Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 18 Feb 2024 15:18:20 GMT
From:      "Jason A. Harmening" <jah@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 2656fc29be8b - main - unionfs: upgrade the vnode lock during fsync() if necessary
Message-ID:  <202402181518.41IFIKf4009294@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by jah:

URL: https://cgit.FreeBSD.org/src/commit/?id=2656fc29be8b0fc1cd9e64ed52aa0a61fe87744c

commit 2656fc29be8b0fc1cd9e64ed52aa0a61fe87744c
Author:     Jason A. Harmening <jah@FreeBSD.org>
AuthorDate: 2023-12-24 04:42:28 +0000
Commit:     Jason A. Harmening <jah@FreeBSD.org>
CommitDate: 2024-02-18 15:18:07 +0000

    unionfs: upgrade the vnode lock during fsync() if necessary
    
    If the underlying upper FS supports shared locking for write ops,
    as is the case with ZFS, VOP_FSYNC() may only be called with the vnode
    lock held shared.  In this case, temporarily upgrade the lock for
    those unionfs maintenance operations which require exclusive locking.
    
    While here, make unionfs inherit the upper FS' support for shared
    write locking.  Since the upper FS is the target of VOP_GETWRITEMOUNT()
    this is what will dictate the locking behavior of any unionfs caller
    that uses vn_start_write() + vn_lktype_write(), so unionfs must be
    prepared for the caller to only hold a shared vnode lock in these
    cases.
    
    Found in local testing of unionfs atop ZFS with DEBUG_VFS_LOCKS.
    
    MFC after:      2 weeks
    Reviewed by:    kib, olce
    Differential Revision: https://reviews.freebsd.org/D43817
---
 sys/fs/unionfs/union_vfsops.c | 3 ++-
 sys/fs/unionfs/union_vnops.c  | 8 ++++++++
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/sys/fs/unionfs/union_vfsops.c b/sys/fs/unionfs/union_vfsops.c
index 8635600549b1..cb55c2dd6474 100644
--- a/sys/fs/unionfs/union_vfsops.c
+++ b/sys/fs/unionfs/union_vfsops.c
@@ -348,7 +348,8 @@ unionfs_domount(struct mount *mp)
 	if ((ump->um_lowermp->mnt_flag & MNT_LOCAL) != 0 &&
 	    (ump->um_uppermp->mnt_flag & MNT_LOCAL) != 0)
 		mp->mnt_flag |= MNT_LOCAL;
-	mp->mnt_kern_flag |= MNTK_NOMSYNC | MNTK_UNIONFS;
+	mp->mnt_kern_flag |= MNTK_NOMSYNC | MNTK_UNIONFS |
+	    (ump->um_uppermp->mnt_kern_flag & MNTK_SHARED_WRITES);
 	MNT_IUNLOCK(mp);
 
 	/*
diff --git a/sys/fs/unionfs/union_vnops.c b/sys/fs/unionfs/union_vnops.c
index cb2bed925399..3ea427b5b53c 100644
--- a/sys/fs/unionfs/union_vnops.c
+++ b/sys/fs/unionfs/union_vnops.c
@@ -998,14 +998,22 @@ unionfs_fsync(struct vop_fsync_args *ap)
 	struct unionfs_node *unp;
 	struct unionfs_node_status *unsp;
 	struct vnode *ovp;
+	enum unionfs_lkupgrade lkstatus;
 
 	KASSERT_UNIONFS_VNODE(ap->a_vp);
 
 	unp = VTOUNIONFS(ap->a_vp);
+	lkstatus = unionfs_upgrade_lock(ap->a_vp);
+	if (lkstatus == UNIONFS_LKUPGRADE_DOOMED) {
+		unionfs_downgrade_lock(ap->a_vp, lkstatus);
+		return (ENOENT);
+	}
 	unionfs_get_node_status(unp, ap->a_td, &unsp);
 	ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp);
 	unionfs_tryrem_node_status(unp, unsp);
 
+	unionfs_downgrade_lock(ap->a_vp, lkstatus);
+
 	if (ovp == NULLVP)
 		return (EBADF);
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202402181518.41IFIKf4009294>