git: 969071be938c - main - vfs: copy_file_range() between multiple mountpoints of the same fs type

From: Martin Matuska <mm_at_FreeBSD.org>
Date: Wed, 06 Sep 2023 12:28:50 UTC
The branch main has been updated by mm:

URL: https://cgit.FreeBSD.org/src/commit/?id=969071be938ca9b96f8dff003c7b43d6308849f1

commit 969071be938ca9b96f8dff003c7b43d6308849f1
Author:     Martin Matuska <mm@FreeBSD.org>
AuthorDate: 2023-09-06 11:58:10 +0000
Commit:     Martin Matuska <mm@FreeBSD.org>
CommitDate: 2023-09-06 12:28:23 +0000

    vfs: copy_file_range() between multiple mountpoints of the same fs type
    
    VOP_COPY_FILE_RANGE(9) is now caled when source and target vnodes
    reside on the same filesystem type (not just on the same mountpoint).
    The check if vnodes are on the same mountpoint must be done in the
    filesystem code. There are currently only three users - fusefs(5) already
    has this check, ZFS can handle multiple mountpoints and a check has been
    added to NFS client.
    
    ZFS block cloning is now possible between all snapshots and datasets
    of the same ZFS pool.
    
    MFC after:      1 week
    Reviewed by:    rmacklem
    Differential Revision:  https://reviews.freebsd.org/D41721
---
 share/man/man9/VOP_COPY_FILE_RANGE.9 | 4 ++--
 sys/fs/nfsclient/nfs_clvnops.c       | 7 +++++--
 sys/kern/vfs_vnops.c                 | 8 +++++---
 3 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/share/man/man9/VOP_COPY_FILE_RANGE.9 b/share/man/man9/VOP_COPY_FILE_RANGE.9
index 9243210cb265..aa17670954f4 100644
--- a/share/man/man9/VOP_COPY_FILE_RANGE.9
+++ b/share/man/man9/VOP_COPY_FILE_RANGE.9
@@ -28,8 +28,8 @@
 .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
+.Nd copy a byte range within a file or from one file to another in a single
+file system or between multiple file systems
 .Sh SYNOPSIS
 .In sys/param.h
 .In sys/vnode.h
diff --git a/sys/fs/nfsclient/nfs_clvnops.c b/sys/fs/nfsclient/nfs_clvnops.c
index 1fa287a79a84..383d45ba260b 100644
--- a/sys/fs/nfsclient/nfs_clvnops.c
+++ b/sys/fs/nfsclient/nfs_clvnops.c
@@ -3898,8 +3898,11 @@ nfs_copy_file_range(struct vop_copy_file_range_args *ap)
 	off_t inoff, outoff;
 	bool consecutive, must_commit, tryoutcred;
 
-	/* NFSv4.2 Copy is not permitted for infile == outfile. */
-	if (invp == outvp) {
+	/*
+	 * NFSv4.2 Copy is not permitted for infile == outfile.
+	 * TODO: copy_file_range() between multiple NFS mountpoints
+	 */
+	if (invp == outvp || invp->v_mount != outvp->v_mount) {
 generic_copy:
 		return (vn_generic_copy_file_range(invp, ap->a_inoffp,
 		    outvp, ap->a_outoffp, ap->a_lenp, ap->a_flags,
diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c
index 9fb5aee6a023..4e4161ef1a7f 100644
--- a/sys/kern/vfs_vnops.c
+++ b/sys/kern/vfs_vnops.c
@@ -3076,12 +3076,14 @@ vn_copy_file_range(struct vnode *invp, off_t *inoffp, struct vnode *outvp,
 		goto out;
 
 	/*
-	 * If the two vnode are for the same file system, call
+	 * If the two vnodes are for the same file system type, call
 	 * VOP_COPY_FILE_RANGE(), otherwise call vn_generic_copy_file_range()
-	 * which can handle copies across multiple file systems.
+	 * which can handle copies across multiple file system types.
 	 */
 	*lenp = len;
-	if (invp->v_mount == outvp->v_mount)
+	if (invp->v_mount == outvp->v_mount ||
+	    strcmp(invp->v_mount->mnt_vfc->vfc_name,
+	    outvp->v_mount->mnt_vfc->vfc_name) == 0)
 		error = VOP_COPY_FILE_RANGE(invp, inoffp, outvp, outoffp,
 		    lenp, flags, incred, outcred, fsize_td);
 	else