git: 08f3d5b60cdf - main - copy_file_range: Call vn_rdwr() at least once

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Thu, 04 Apr 2024 21:16:47 UTC
The branch main has been updated by markj:

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

commit 08f3d5b60cdfff434e391d96cdffc5a90c550b07
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2024-04-04 15:18:03 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2024-04-04 21:03:07 +0000

    copy_file_range: Call vn_rdwr() at least once
    
    This ensures that we invoke VOP_READ on the input file even if it's
    empty, which in turn helps ensure that filesystems update the atime of
    the file.
    
    PR:             274615
    Reviewed by:    olce, rmacklem, kib
    MFC after:      1 month
    Differential Revision:  https://reviews.freebsd.org/D43524
---
 sys/kern/vfs_vnops.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c
index d79707555ac1..0e864f959e36 100644
--- a/sys/kern/vfs_vnops.c
+++ b/sys/kern/vfs_vnops.c
@@ -3339,7 +3339,7 @@ vn_generic_copy_file_range(struct vnode *invp, off_t *inoffp,
 	off_t startoff, endoff, xfer, xfer2;
 	u_long blksize;
 	int error, interrupted;
-	bool cantseek, readzeros, eof, lastblock, holetoeof, sparse;
+	bool cantseek, readzeros, eof, first, lastblock, holetoeof, sparse;
 	ssize_t aresid, r = 0;
 	size_t copylen, len, savlen;
 	off_t outsize;
@@ -3480,6 +3480,7 @@ vn_generic_copy_file_range(struct vnode *invp, off_t *inoffp,
 		endts.tv_sec++;
 	} else
 		timespecclear(&endts);
+	first = true;
 	holetoeof = eof = false;
 	while (len > 0 && error == 0 && !eof && interrupted == 0) {
 		endoff = 0;			/* To shut up compilers. */
@@ -3581,10 +3582,17 @@ vn_generic_copy_file_range(struct vnode *invp, off_t *inoffp,
 			 */
 			xfer -= (*inoffp % blksize);
 		}
-		/* Loop copying the data block. */
-		while (copylen > 0 && error == 0 && !eof && interrupted == 0) {
+
+		/*
+		 * Loop copying the data block.  If this was our first attempt
+		 * to copy anything, allow a zero-length block so that the VOPs
+		 * get a chance to update metadata, specifically the atime.
+		 */
+		while (error == 0 && ((copylen > 0 && !eof) || first) &&
+		    interrupted == 0) {
 			if (copylen < xfer)
 				xfer = copylen;
+			first = false;
 			error = vn_lock(invp, LK_SHARED);
 			if (error != 0)
 				goto out;
@@ -3594,7 +3602,7 @@ vn_generic_copy_file_range(struct vnode *invp, off_t *inoffp,
 			    curthread);
 			VOP_UNLOCK(invp);
 			lastblock = false;
-			if (error == 0 && aresid > 0) {
+			if (error == 0 && (xfer == 0 || aresid > 0)) {
 				/* Stop the copy at EOF on the input file. */
 				xfer -= aresid;
 				eof = true;