VOP_COPY_FILE_RANGE: Add a COPY_FILE_RANGE_TIMEO1SEC flag

Although it is not specified in the RFCs, the concept that
the NFSv4 server should reply to an RPC request within a
reasonable time is accepted practice within the NFSv4 community.

Without this patch, the NFSv4.2 server attempts to reply to
a Copy operation within 1second by limiting the copy to
vfs.nfs.maxcopyrange bytes (default 10Mbytes). This is crude at
best, given the large variation in I/O subsystem performance.

This patch adds a kernel only flag COPY_FILE_RANGE_TIMEO1SEC
that the NFSv4.2 can specify, which tells VOP_COPY_FILE_RANGE()
to return after approximately 1 second with a partial result and
implements this in vn_generic_copy_file_range(), used by
vop_stdcopyfilerange().

Modifying the NFSv4.2 server to set this flag will be done in
a separate patch.  Also under consideration is exposing the
COPY_FILE_RANGE_TIMEO1SEC to userland for use on the FreeBSD
copy_file_range(2) syscall.

Although this technically does change the VFS/VOP KAPI, I do not
think the MFC will cause problems.

(cherry picked from commit c5128c48df)
This commit is contained in:
Rick Macklem 2021-09-07 17:35:26 -07:00
parent 9faebc1e66
commit ed03973908
2 changed files with 33 additions and 2 deletions

View File

@ -3142,6 +3142,7 @@ vn_generic_copy_file_range(struct vnode *invp, off_t *inoffp,
size_t copylen, len, rem, savlen;
char *dat;
long holein, holeout;
struct timespec curts, endts;
holein = holeout = 0;
savlen = len = *lenp;
@ -3238,7 +3239,15 @@ vn_generic_copy_file_range(struct vnode *invp, off_t *inoffp,
* in the inner loop where the data copying is done.
* Note that some file systems such as NFSv3, NFSv4.0 and NFSv4.1 may
* support holes on the server, but do not support FIOSEEKHOLE.
* The kernel flag COPY_FILE_RANGE_TIMEO1SEC is used to indicate
* that this function should return after 1second with a partial
* completion.
*/
if ((flags & COPY_FILE_RANGE_TIMEO1SEC) != 0) {
getnanouptime(&endts);
endts.tv_sec++;
} else
timespecclear(&endts);
holetoeof = eof = false;
while (len > 0 && error == 0 && !eof && interrupted == 0) {
endoff = 0; /* To shut up compilers. */
@ -3307,8 +3316,17 @@ vn_generic_copy_file_range(struct vnode *invp, off_t *inoffp,
*inoffp += xfer;
*outoffp += xfer;
len -= xfer;
if (len < savlen)
if (len < savlen) {
interrupted = sig_intr();
if (timespecisset(&endts) &&
interrupted == 0) {
getnanouptime(&curts);
if (timespeccmp(&curts,
&endts, >=))
interrupted =
EINTR;
}
}
}
}
copylen = MIN(len, endoff - startoff);
@ -3371,8 +3389,17 @@ vn_generic_copy_file_range(struct vnode *invp, off_t *inoffp,
*outoffp += xfer;
copylen -= xfer;
len -= xfer;
if (len < savlen)
if (len < savlen) {
interrupted = sig_intr();
if (timespecisset(&endts) &&
interrupted == 0) {
getnanouptime(&curts);
if (timespeccmp(&curts,
&endts, >=))
interrupted =
EINTR;
}
}
}
}
xfer = blksize;

View File

@ -613,6 +613,10 @@ typedef void vop_getpages_iodone_t(void *, vm_page_t *, int, int);
#define VN_OPEN_NAMECACHE 0x00000004
#define VN_OPEN_INVFS 0x00000008
/* copy_file_range kernel flags */
#define COPY_FILE_RANGE_KFLAGS 0xff000000
#define COPY_FILE_RANGE_TIMEO1SEC 0x01000000 /* Return after 1sec. */
/*
* Public vnode manipulation functions.
*/