From nobody Sun Dec 05 18:38:52 2021 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 7206E18BC134; Sun, 5 Dec 2021 18:38:53 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4J6b1T1Vcmz4hfb; Sun, 5 Dec 2021 18:38:53 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 1390F1C97F; Sun, 5 Dec 2021 18:38:53 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 1B5Icqrb017381; Sun, 5 Dec 2021 18:38:52 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 1B5IcqRK017380; Sun, 5 Dec 2021 18:38:52 GMT (envelope-from git) Date: Sun, 5 Dec 2021 18:38:52 GMT Message-Id: <202112051838.1B5IcqRK017380@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Mark Johnston Subject: git: 0c5f290ed909 - stable/13 - zfs: Fix a deadlock between page busy and the teardown lock List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-all@freebsd.org X-BeenThere: dev-commits-src-all@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: markj X-Git-Repository: src X-Git-Refname: refs/heads/stable/13 X-Git-Reftype: branch X-Git-Commit: 0c5f290ed90963b64b05a2098e0b11c3d9f6471f Auto-Submitted: auto-generated ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1638729533; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=1q61F4Vu8Sw1vWdhKo3wL4Uwhk1ely77u/HGDJXFgnw=; b=aTxyRVwuXL9jT0zr83FjUnsD+7hKiyg5ih3Vk9Vpr0WMl2V/e3jgug7yeAaj4LZlS65Xrp sHJ/ZIpqujXKhSUcLre7ms7VWijP6Kclez5HaYT7An+Lizin3RSEa98ikaCXw4/1GqXywW xXH8p9Jrzii0cGTD1XD6SdFYbzZK4eWu4qyQ2smDpCjK8AWpZ8HeFvkl83JR7Ec6nz+Hh3 dHYx8IxsFnNbVTzTVd4ZFVuPZrwIUp4SMVeFOH73+sDOxH7b78onHzPmno3GgElu7YrPpT +xLa7sCWwbSerHuw+NzUZm2qZXupvY8UTL2aAKtZjTopdZItybKJag9mVPx6Cg== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1638729533; a=rsa-sha256; cv=none; b=tZiTxJT4hQvJCXBDOZIm7fECa1V3bJpq+d/zaaQ+ErzFO+pcCyll6s/DOs2WTAPabtiMAd qypL5OWAsGBT6J1TYIQtCyqJq5IYg1bbVFUCz/t+b8R2qhGBEl5YvLeqN468LWq+fzy8/q 1LEqz690Txx2kQuzI7yfm7cYABmFgNDx/LJvOkyio5QkOCggMCsBJ8uOfj8RKkdHTHbCIC 7avp905qXvRY/Ewpp+bXqDwWEK9w7ofX/0G82TNEjaNH0yiZJ3FXWfUy3OdcdxwWo0jNJj j2dqZ7zrhnuAOPAsZ9pYB3C9U143ezuuS/bMWYr0uA42PUkxDtms91TW3Blqcw== ARC-Authentication-Results: i=1; mx1.freebsd.org; none X-ThisMailContainsUnwantedMimeParts: N The branch stable/13 has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=0c5f290ed90963b64b05a2098e0b11c3d9f6471f commit 0c5f290ed90963b64b05a2098e0b11c3d9f6471f Author: Mark Johnston AuthorDate: 2021-11-20 16:21:25 +0000 Commit: Mark Johnston CommitDate: 2021-12-05 18:38:35 +0000 zfs: Fix a deadlock between page busy and the teardown lock When rolling back a dataset, ZFS has to purge file data resident in the system page cache. To do this, it loops over all vnodes for the mountpoint and calls vn_pages_remove() to purge pages associated with the vnode's VM object. Each page is thus exclusively busied while the dataset's teardown write lock is held. When handling a page fault on a mapped ZFS file, FreeBSD's page fault handler busies newly allocated pages and then uses VOP_GETPAGES to fill them. The ZFS getpages VOP acquires the teardown read lock with vnode pages already busied. This represents a lock order reversal which can lead to deadlock. To break the deadlock, observe that zfs_rezget() need only purge those pages marked valid, and that pages busied by the page fault handler are, by definition, invalid. Furthermore, ZFS pages always transition from invalid to valid with the teardown lock held, and ZFS never creates partially valid pages. Thus, zfs_rezget() can use the new vn_pages_remove_valid() to skip over pages busied by the fault handler. PR: 258208 Tested by: pho Reviewed by: avg, sef, kib Sponsored by: The FreeBSD Foundation (cherry picked from commit 705a6ee2b6112c3a653b2bd68f961a8b5b8071a4) --- sys/contrib/openzfs/module/os/freebsd/zfs/zfs_znode.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_znode.c b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_znode.c index 7b6f77e2c669..d14df9d88a35 100644 --- a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_znode.c +++ b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_znode.c @@ -1083,9 +1083,18 @@ zfs_rezget(znode_t *zp) * the vnode in case of error, but currently we cannot do that * because of the LOR between the vnode lock and z_teardown_lock. * So, instead, we have to "doom" the znode in the illumos style. + * + * Ignore invalid pages during the scan. This is to avoid deadlocks + * between page busying and the teardown lock, as pages are busied prior + * to a VOP_GETPAGES operation, which acquires the teardown read lock. + * Such pages will be invalid and can safely be skipped here. */ vp = ZTOV(zp); +#if __FreeBSD_version >= 1300522 + vn_pages_remove_valid(vp, 0, 0); +#else vn_pages_remove(vp, 0, 0); +#endif ZFS_OBJ_HOLD_ENTER(zfsvfs, obj_num);