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;
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;