git: 7dc643fe15f9 - stable/14 - vn_copy_file_range(): find write vnodes on which to call the VOP

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Tue, 05 Dec 2023 00:43:59 UTC
The branch stable/14 has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=7dc643fe15f9b18e6821fa17402a0a2005095742

commit 7dc643fe15f9b18e6821fa17402a0a2005095742
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2023-11-18 08:57:44 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2023-12-05 00:43:27 +0000

    vn_copy_file_range(): find write vnodes on which to call the VOP
    
    (cherry picked from commit a9bc8637690ce29496650a41d3c25e225ed22e3d)
---
 sys/kern/vfs_vnops.c | 34 +++++++++++++++++++++++-----------
 1 file changed, 23 insertions(+), 11 deletions(-)

diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c
index 4669296750e4..6e8a6b23eec6 100644
--- a/sys/kern/vfs_vnops.c
+++ b/sys/kern/vfs_vnops.c
@@ -3072,10 +3072,12 @@ vn_copy_file_range(struct vnode *invp, off_t *inoffp, struct vnode *outvp,
     struct ucred *outcred, struct thread *fsize_td)
 {
 	struct mount *inmp, *outmp;
+	struct vnode *invpl, *outvpl;
 	int error;
 	size_t len;
 	uint64_t uval;
 
+	invpl = outvpl = NULL;
 	len = *lenp;
 	*lenp = 0;		/* For error returns. */
 	error = 0;
@@ -3101,17 +3103,22 @@ vn_copy_file_range(struct vnode *invp, off_t *inoffp, struct vnode *outvp,
 	if (len == 0)
 		goto out;
 
-	inmp = invp->v_mount;
-	outmp = outvp->v_mount;
-	if (inmp == NULL || outmp == NULL) {
-		error = EBADF;
+	error = VOP_GETLOWVNODE(invp, &invpl, FREAD);
+	if (error != 0)
 		goto out;
-	}
+	error = VOP_GETLOWVNODE(outvp, &outvpl, FWRITE);
+	if (error != 0)
+		goto out1;
+
+	inmp = invpl->v_mount;
+	outmp = outvpl->v_mount;
+	if (inmp == NULL || outmp == NULL)
+		goto out2;
 
 	for (;;) {
 		error = vfs_busy(inmp, 0);
 		if (error != 0)
-			goto out;
+			goto out2;
 		if (inmp == outmp)
 			break;
 		error = vfs_busy(outmp, MBF_NOWAIT);
@@ -3122,7 +3129,7 @@ vn_copy_file_range(struct vnode *invp, off_t *inoffp, struct vnode *outvp,
 				vfs_unbusy(outmp);
 				continue;
 			}
-			goto out;
+			goto out2;
 		}
 		break;
 	}
@@ -3133,16 +3140,21 @@ vn_copy_file_range(struct vnode *invp, off_t *inoffp, struct vnode *outvp,
 	 * which can handle copies across multiple file system types.
 	 */
 	*lenp = len;
-	if (inmp == outmp || strcmp(inmp->mnt_vfc->vfc_name,
-	    outmp->mnt_vfc->vfc_name) == 0)
-		error = VOP_COPY_FILE_RANGE(invp, inoffp, outvp, outoffp,
+	if (inmp == outmp || inmp->mnt_vfc == outmp->mnt_vfc)
+		error = VOP_COPY_FILE_RANGE(invpl, inoffp, outvpl, outoffp,
 		    lenp, flags, incred, outcred, fsize_td);
 	else
-		error = vn_generic_copy_file_range(invp, inoffp, outvp,
+		error = vn_generic_copy_file_range(invpl, inoffp, outvpl,
 		    outoffp, lenp, flags, incred, outcred, fsize_td);
 	vfs_unbusy(outmp);
 	if (inmp != outmp)
 		vfs_unbusy(inmp);
+out2:
+	if (outvpl != NULL)
+		vrele(outvpl);
+out1:
+	if (invpl != NULL)
+		vrele(invpl);
 out:
 	return (error);
 }