aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Johnston <markj@FreeBSD.org>2024-04-04 15:18:03 +0000
committerMark Johnston <markj@FreeBSD.org>2024-04-04 21:03:07 +0000
commit08f3d5b60cdfff434e391d96cdffc5a90c550b07 (patch)
tree00ad6f2b1d19a64dc114ae682bdb4b8aa9d4e2b6
parentc1326c01df81dd06739ddf1946e1968ddaba0c8e (diff)
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
-rw-r--r--sys/kern/vfs_vnops.c16
1 files 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;