git: a9bc8637690c - main - vn_copy_file_range(): find write vnodes on which to call the VOP

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Tue, 28 Nov 2023 17:33:23 UTC
The branch main has been updated by kib:

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

commit a9bc8637690ce29496650a41d3c25e225ed22e3d
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2023-11-18 08:57:44 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2023-11-28 17:32:53 +0000

    vn_copy_file_range(): find write vnodes on which to call the VOP
    
    Reviewed by:    markj, Olivier Certner <olce.freebsd@certner.fr>
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D42603
---
 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 e90330b08cbc..29114f795f5e 100644
--- a/sys/kern/vfs_vnops.c
+++ b/sys/kern/vfs_vnops.c
@@ -3070,10 +3070,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;
@@ -3099,17 +3101,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);
@@ -3120,7 +3127,7 @@ vn_copy_file_range(struct vnode *invp, off_t *inoffp, struct vnode *outvp,
 				vfs_unbusy(outmp);
 				continue;
 			}
-			goto out;
+			goto out2;
 		}
 		break;
 	}
@@ -3131,16 +3138,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);
 }