Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 12 Dec 2025 06:32:55 +0000
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: 5c025978fc36 - main - unionfs: Implement VOP_GETLOWVNODE
Message-ID:  <693bb717.2542b.2fc8a436@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=5c025978fc3649730329994eecc56ada119e6717

commit 5c025978fc3649730329994eecc56ada119e6717
Author:     Jason A. Harmening <jah@FreeBSD.org>
AuthorDate: 2025-11-28 07:36:24 +0000
Commit:     Jason A. Harmening <jah@FreeBSD.org>
CommitDate: 2025-12-12 06:32:05 +0000

    unionfs: Implement VOP_GETLOWVNODE
    
    This function returns the vnode that will be used to resolve the
    access type specified in the 'flags' argument, and is useful for
    optimal behavior of vn_copy_file_range(). While most filesystems
    can simply use the default implementation which returns the passed-
    in vnode, unionfs (like nullfs) ideally should resolve the access
    request to whichever base layer vnode will be used for the I/O.
    
    For unionfs, write accesses must be resolved through the upper vnode,
    while read accesses will be resolved through the upper vnode if
    present or the lower vnode otherwise.  Provide a simple
    unionfs_getlowvnode() implementation that reflects this policy.
    
    Reviewed by:    kib, olce
    Tested by:      pho
    MFC after:      1 week
    Differential Revision:  https://reviews.freebsd.org/D53988
---
 sys/fs/unionfs/union_vnops.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
 sys/kern/vfs_default.c       |  3 +--
 sys/sys/vnode.h              |  1 +
 3 files changed, 47 insertions(+), 2 deletions(-)

diff --git a/sys/fs/unionfs/union_vnops.c b/sys/fs/unionfs/union_vnops.c
index 66fee97a07d5..060863866fcf 100644
--- a/sys/fs/unionfs/union_vnops.c
+++ b/sys/fs/unionfs/union_vnops.c
@@ -2105,6 +2105,49 @@ unionfs_getwritemount(struct vop_getwritemount_args *ap)
 	return (error);
 }
 
+static int
+unionfs_getlowvnode(struct vop_getlowvnode_args *ap)
+{
+	struct unionfs_node *unp;
+	struct vnode *vp, *basevp;
+
+	vp = ap->a_vp;
+	VI_LOCK(vp);
+	unp = VTOUNIONFS(vp);
+	if (unp == NULL) {
+		VI_UNLOCK(vp);
+		return (EBADF);
+	}
+
+	if (ap->a_flags & FWRITE) {
+		basevp = unp->un_uppervp;
+		/*
+		 * If write access is being requested, we expect the unionfs
+		 * vnode has already been opened for write access and thus any
+		 * necessary copy-up has already been performed.  Return an
+		 * error if that expectation is not met and an upper vnode has
+		 * not been instantiated.  We could proactively do a copy-up
+		 * here, but that would require additional locking as well as
+		 * the addition of a 'cred' argument to VOP_GETLOWVNODE().
+		 */
+		if (basevp == NULL) {
+			VI_UNLOCK(vp);
+			return (EACCES);
+		}
+	} else {
+		basevp = (unp->un_uppervp != NULL) ?
+		    unp->un_uppervp : unp->un_lowervp;
+	}
+
+	VNASSERT(basevp != NULL, vp, ("%s: no upper/lower vnode", __func__));
+
+	vholdnz(basevp);
+	VI_UNLOCK(vp);
+	VOP_GETLOWVNODE(basevp, ap->a_vplp, ap->a_flags);
+	vdrop(basevp);
+	return (0);
+}
+
 static int
 unionfs_inactive(struct vop_inactive_args *ap)
 {
@@ -3000,6 +3043,7 @@ struct vop_vector unionfs_vnodeops = {
 	.vop_getattr =		unionfs_getattr,
 	.vop_getextattr =	unionfs_getextattr,
 	.vop_getwritemount =	unionfs_getwritemount,
+	.vop_getlowvnode =	unionfs_getlowvnode,
 	.vop_inactive =		unionfs_inactive,
 	.vop_need_inactive =	vop_stdneed_inactive,
 	.vop_islocked =		vop_stdislocked,
@@ -3039,5 +3083,6 @@ struct vop_vector unionfs_vnodeops = {
 	.vop_unp_bind =		unionfs_unp_bind,
 	.vop_unp_connect =	unionfs_unp_connect,
 	.vop_unp_detach =	unionfs_unp_detach,
+	.vop_copy_file_range =	vop_stdcopy_file_range,
 };
 VFS_VOP_VECTOR_REGISTER(unionfs_vnodeops);
diff --git a/sys/kern/vfs_default.c b/sys/kern/vfs_default.c
index 4eca09aef145..468d5d18b02b 100644
--- a/sys/kern/vfs_default.c
+++ b/sys/kern/vfs_default.c
@@ -77,7 +77,6 @@ static int	dirent_exists(struct vnode *vp, const char *dirname,
 static int vop_stdis_text(struct vop_is_text_args *ap);
 static int vop_stdunset_text(struct vop_unset_text_args *ap);
 static int vop_stdadd_writecount(struct vop_add_writecount_args *ap);
-static int vop_stdcopy_file_range(struct vop_copy_file_range_args *ap);
 static int vop_stdfdatasync(struct vop_fdatasync_args *ap);
 static int vop_stdgetpages_async(struct vop_getpages_async_args *ap);
 static int vop_stdread_pgcache(struct vop_read_pgcache_args *ap);
@@ -1426,7 +1425,7 @@ vfs_stdnosync(struct mount *mp, int waitfor)
 	return (0);
 }
 
-static int
+int
 vop_stdcopy_file_range(struct vop_copy_file_range_args *ap)
 {
 	int error;
diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h
index 0bf438a1b821..1a267e0e272c 100644
--- a/sys/sys/vnode.h
+++ b/sys/sys/vnode.h
@@ -906,6 +906,7 @@ int	vop_stdunp_bind(struct vop_unp_bind_args *ap);
 int	vop_stdunp_connect(struct vop_unp_connect_args *ap);
 int	vop_stdunp_detach(struct vop_unp_detach_args *ap);
 int	vop_stdadd_writecount_nomsync(struct vop_add_writecount_args *ap);
+int	vop_stdcopy_file_range(struct vop_copy_file_range_args *ap);
 int	vop_eopnotsupp(struct vop_generic_args *ap);
 int	vop_ebadf(struct vop_generic_args *ap);
 int	vop_einval(struct vop_generic_args *ap);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?693bb717.2542b.2fc8a436>