diff --git a/lib/libc/gen/getvfsbyname.3 b/lib/libc/gen/getvfsbyname.3 --- a/lib/libc/gen/getvfsbyname.3 +++ b/lib/libc/gen/getvfsbyname.3 @@ -28,7 +28,7 @@ .\" @(#)kvm_getvfsbyname.3 8.3 (Berkeley) 5/4/95 .\" $FreeBSD$ .\" -.Dd August 16, 2018 +.Dd February 26, 2023 .Dt GETVFSBYNAME 3 .Os .Sh NAME @@ -92,6 +92,10 @@ .Va vfs.usermount sysctl is set to .Dv 1 +.It Dv VFCF_CROSS_COPY_FILE_RANGE +supports file system specific +.Xr copy_file_range 2 +across mount points. .El .Sh RETURN VALUES .Rv -std getvfsbyname @@ -105,6 +109,7 @@ specifies a file system that is unknown or not configured in the kernel. .El .Sh SEE ALSO +.Xr copy_file_range 2 , .Xr jail 2 , .Xr mount 2 , .Xr sysctl 3 , diff --git a/share/man/man9/VFS_SET.9 b/share/man/man9/VFS_SET.9 --- a/share/man/man9/VFS_SET.9 +++ b/share/man/man9/VFS_SET.9 @@ -26,7 +26,7 @@ .\" .\" $FreeBSD$ .\" -.Dd August 16, 2018 +.Dd February 26, 2023 .Dt VFS_SET 9 .Os .Sh NAME @@ -57,7 +57,7 @@ Possible values for the .Fa flags argument are: -.Bl -hang -width ".Dv VFCF_DELEGADMIN" +.Bl -tag -width ".Dv VFCF_DELEGADMIN" .It Dv VFCF_STATIC File system should be statically available in the kernel. .It Dv VFCF_NETWORK @@ -84,6 +84,11 @@ .It Dv VFCF_SBDRY When in VFS method, the thread suspension is deferred to the user boundary upon arrival of stop action. +.It Dv VFCF_CROSS_COPY_FILE_RANGE +Allow +.Xr copy_file_range 2 +to call file system specific VOP even for different mount points, +but the same file system type. .El .Sh PSEUDOCODE .Bd -literal @@ -102,6 +107,7 @@ VFS_SET(myfs_vfsops, myfs, 0); .Ed .Sh SEE ALSO +.Xr copy_file_range 2 , .Xr jail 2 , .Xr jail 8 , .Xr DECLARE_MODULE 9 , diff --git a/share/man/man9/VOP_COPY_FILE_RANGE.9 b/share/man/man9/VOP_COPY_FILE_RANGE.9 --- a/share/man/man9/VOP_COPY_FILE_RANGE.9 +++ b/share/man/man9/VOP_COPY_FILE_RANGE.9 @@ -25,13 +25,12 @@ .\" .\" $FreeBSD$ .\" -.Dd March 30, 2020 +.Dd February 26, 2023 .Dt VOP_COPY_FILE_RANGE 9 .Os .Sh NAME .Nm VOP_COPY_FILE_RANGE .Nd copy a byte range from one file to another or within one file -in a single file system .Sh SYNOPSIS .In sys/param.h .In sys/vnode.h @@ -50,6 +49,15 @@ .Sh DESCRIPTION This entry point copies a byte range from one regular file to another or within one file in a single file system. +If the file system type is declared with the +.Dv VFCF_CROSS_COPY_FILE_RANGE +flag, +.Nm VOP_COPY_FILE_RANGE +will also be called if both +.Fa invp +and +.Fa outvp +reside under different mount points of the same file system type. .Fa invp and .Fa outvp @@ -138,7 +146,12 @@ Corrupted data was detected while reading/writing the files. .It Bq Er ENOSPC The file system is full. +.It Bq Er EXDEV +The file system was not able to perform the operation, but it should be still +possible to perform generic copy. .El .Sh SEE ALSO +.Xr copy_file_range 2 , +.Xr VFS_SET 9 , .Xr vn_rdwr 9 , .Xr vnode 9 diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -3039,7 +3039,8 @@ off_t *outoffp, size_t *lenp, unsigned int flags, struct ucred *incred, struct ucred *outcred, struct thread *fsize_td) { - int error; + struct vfsconf *invfc, *outvfc; + int error, crosscopy; size_t len; uint64_t uval; @@ -3068,18 +3069,29 @@ if (len == 0) goto out; + *lenp = len; + /* - * If the two vnode are for the same file system, call - * VOP_COPY_FILE_RANGE(), otherwise call vn_generic_copy_file_range() - * which can handle copies across multiple file systems. + * If the two vnode are for the same file system or this is the same + * file system type and it supports cross-mount-point copy_file_range() + * (like ZFS), call VOP_COPY_FILE_RANGE(), otherwise call + * vn_generic_copy_file_range() which can handle copies across multiple + * file systems. */ - *lenp = len; - if (invp->v_mount == outvp->v_mount) + invfc = invp->v_mount->mnt_vfc; + outvfc = outvp->v_mount->mnt_vfc; + crosscopy = (invfc == outvfc && + (outvfc->vfc_flags & VFCF_CROSS_COPY_FILE_RANGE) != 0); + + if (invp->v_mount == outvp->v_mount || crosscopy) { error = VOP_COPY_FILE_RANGE(invp, inoffp, outvp, outoffp, lenp, flags, incred, outcred, fsize_td); - else - error = vn_generic_copy_file_range(invp, inoffp, outvp, - outoffp, lenp, flags, incred, outcred, fsize_td); + /* EXDEV means that we should try generic copy. */ + if (error != EXDEV) + goto out; + } + error = vn_generic_copy_file_range(invp, inoffp, outvp, outoffp, lenp, + flags, incred, outcred, fsize_td); out: return (error); } diff --git a/sys/sys/mount.h b/sys/sys/mount.h --- a/sys/sys/mount.h +++ b/sys/sys/mount.h @@ -681,6 +681,10 @@ #define VFCF_SBDRY 0x01000000 /* Stop at Boundary: defer stop requests to kernel->user (AST) transition */ #define VFCF_FILEMOUNT 0x02000000 /* allow mounting files */ +#define VFCF_CROSS_COPY_FILE_RANGE \ + 0x04000000 /* allow copy_file_range(2) between + different mount points of the same + file system type */ typedef uint32_t fsctlop_t; diff --git a/usr.bin/lsvfs/lsvfs.c b/usr.bin/lsvfs/lsvfs.c --- a/usr.bin/lsvfs/lsvfs.c +++ b/usr.bin/lsvfs/lsvfs.c @@ -34,6 +34,7 @@ { .flag = VFCF_UNICODE, .str = "unicode", }, { .flag = VFCF_JAIL, .str = "jail", }, { .flag = VFCF_DELEGADMIN, .str = "delegated-administration", }, + { .flag = VFCF_CROSS_COPY_FILE_RANGE, .str = "cross-copy_file_range", }, }; static const char *fmt_flags(int);