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
This commit is contained in:
Mark Johnston 2024-04-04 11:18:03 -04:00
parent c1326c01df
commit 08f3d5b60c

View file

@ -3339,7 +3339,7 @@ vn_generic_copy_file_range(struct vnode *invp, off_t *inoffp,
off_t startoff, endoff, xfer, xfer2; off_t startoff, endoff, xfer, xfer2;
u_long blksize; u_long blksize;
int error, interrupted; int error, interrupted;
bool cantseek, readzeros, eof, lastblock, holetoeof, sparse; bool cantseek, readzeros, eof, first, lastblock, holetoeof, sparse;
ssize_t aresid, r = 0; ssize_t aresid, r = 0;
size_t copylen, len, savlen; size_t copylen, len, savlen;
off_t outsize; off_t outsize;
@ -3480,6 +3480,7 @@ vn_generic_copy_file_range(struct vnode *invp, off_t *inoffp,
endts.tv_sec++; endts.tv_sec++;
} else } else
timespecclear(&endts); timespecclear(&endts);
first = true;
holetoeof = eof = false; holetoeof = eof = false;
while (len > 0 && error == 0 && !eof && interrupted == 0) { while (len > 0 && error == 0 && !eof && interrupted == 0) {
endoff = 0; /* To shut up compilers. */ endoff = 0; /* To shut up compilers. */
@ -3581,10 +3582,17 @@ vn_generic_copy_file_range(struct vnode *invp, off_t *inoffp,
*/ */
xfer -= (*inoffp % blksize); 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) if (copylen < xfer)
xfer = copylen; xfer = copylen;
first = false;
error = vn_lock(invp, LK_SHARED); error = vn_lock(invp, LK_SHARED);
if (error != 0) if (error != 0)
goto out; goto out;
@ -3594,7 +3602,7 @@ vn_generic_copy_file_range(struct vnode *invp, off_t *inoffp,
curthread); curthread);
VOP_UNLOCK(invp); VOP_UNLOCK(invp);
lastblock = false; lastblock = false;
if (error == 0 && aresid > 0) { if (error == 0 && (xfer == 0 || aresid > 0)) {
/* Stop the copy at EOF on the input file. */ /* Stop the copy at EOF on the input file. */
xfer -= aresid; xfer -= aresid;
eof = true; eof = true;