The branch main has been updated by jah:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=5c025978fc3649730329994eecc56ada119e6717

commit 5c025978fc3649730329994eecc56ada119e6717
Author:     Jason A. Harmening <[email protected]>
AuthorDate: 2025-11-28 07:36:24 +0000
Commit:     Jason A. Harmening <[email protected]>
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);

Reply via email to