git: 9c530578757b - stable/14 - unionfs: upgrade the vnode lock during fsync() if necessary
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 04 Mar 2024 18:51:47 UTC
The branch stable/14 has been updated by jah: URL: https://cgit.FreeBSD.org/src/commit/?id=9c530578757b9e39eeae8e1e03a14652faa7f458 commit 9c530578757b9e39eeae8e1e03a14652faa7f458 Author: Jason A. Harmening <jah@FreeBSD.org> AuthorDate: 2023-12-24 04:42:28 +0000 Commit: Jason A. Harmening <jah@FreeBSD.org> CommitDate: 2024-03-04 18:31:44 +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. Reviewed by: kib, olce Differential Revision: https://reviews.freebsd.org/D43817 (cherry picked from commit 2656fc29be8b0fc1cd9e64ed52aa0a61fe87744c) --- 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 c6d459622670..c717b048c6ab 100644 --- a/sys/fs/unionfs/union_vfsops.c +++ b/sys/fs/unionfs/union_vfsops.c @@ -351,7 +351,8 @@ unionfs_domount(struct mount *mp) if ((lowermp->mnt_flag & MNT_LOCAL) != 0 && (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 ab277c685e41..ba20bef199e6 100644 --- a/sys/fs/unionfs/union_vnops.c +++ b/sys/fs/unionfs/union_vnops.c @@ -1000,14 +1000,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);