aboutsummaryrefslogtreecommitdiff
path: root/sys/fs/nfsclient/nfs_clvnops.c
diff options
context:
space:
mode:
authorRick Macklem <rmacklem@FreeBSD.org>2021-09-18 21:38:43 +0000
committerRick Macklem <rmacklem@FreeBSD.org>2021-09-18 21:38:43 +0000
commitad6dc365202390edffb14d725155e230b96f59ae (patch)
tree7d7f3093f1c1d51283e456f4c15ad0aa996c7e57 /sys/fs/nfsclient/nfs_clvnops.c
parent7b2ac8eb9be76c96356b6e9a7c06a8080ea841ae (diff)
downloadsrc-ad6dc365202390edffb14d725155e230b96f59ae.tar.gz
src-ad6dc365202390edffb14d725155e230b96f59ae.zip
nfscl: Use vfs.nfs.maxalloclen to limit Deallocate RPC RTT
Unlike Copy, the NFSv4.2 Allocate and Deallocate operations do not allow a reply with partial completion. As such, the only way to limit the time the operation takes to provide a reasonable RPC RTT is to limit the size of the allocation/deallocation in the NFSv4.2 client. This patch uses the sysctl vfs.nfs.maxalloclen to set the limit on the size of the Deallocate operation. There is no way to know how long a server will take to do an deallocate operation, but 64Mbytes results in a reasonable RPC RTT for the slow hardware I test on. For an 8Gbyte deallocation, the elapsed time for doing it in 64Mbyte chunks was the same (within margin of variability) as the elapsed time taken for a single large deallocation operation for a FreeBSD server with a UFS file system.
Diffstat (limited to 'sys/fs/nfsclient/nfs_clvnops.c')
-rw-r--r--sys/fs/nfsclient/nfs_clvnops.c20
1 files changed, 18 insertions, 2 deletions
diff --git a/sys/fs/nfsclient/nfs_clvnops.c b/sys/fs/nfsclient/nfs_clvnops.c
index 85b5dd9cfbb1..0b60100d1fc9 100644
--- a/sys/fs/nfsclient/nfs_clvnops.c
+++ b/sys/fs/nfsclient/nfs_clvnops.c
@@ -3702,12 +3702,15 @@ nfs_deallocate(struct vop_deallocate_args *ap)
struct thread *td = curthread;
struct nfsvattr nfsva;
struct nfsmount *nmp;
- off_t tlen;
+ struct nfsnode *np;
+ off_t tlen, mlen;
int attrflag, error, ret;
+ bool clipped;
error = 0;
attrflag = 0;
nmp = VFSTONFS(vp->v_mount);
+ np = VTONFS(vp);
mtx_lock(&nmp->nm_mtx);
if (NFSHASNFSV4(nmp) && nmp->nm_minorvers >= NFSV42_MINORVERSION &&
(nmp->nm_privflag & NFSMNTP_NODEALLOCATE) == 0) {
@@ -3721,8 +3724,18 @@ nfs_deallocate(struct vop_deallocate_args *ap)
*ap->a_len = 0;
return (0);
}
+ clipped = false;
if ((uint64_t)*ap->a_offset + tlen > nmp->nm_maxfilesize)
tlen = nmp->nm_maxfilesize - *ap->a_offset;
+ if ((uint64_t)*ap->a_offset < np->n_size) {
+ /* Limit the len to nfs_maxalloclen before EOF. */
+ mlen = omin((off_t)np->n_size - *ap->a_offset, tlen);
+ if ((uint64_t)mlen > nfs_maxalloclen) {
+ NFSCL_DEBUG(4, "dealloc: tlen maxalloclen\n");
+ tlen = nfs_maxalloclen;
+ clipped = true;
+ }
+ }
if (error == 0)
error = ncl_vinvalbuf(vp, V_SAVE, td, 1);
if (error == 0) {
@@ -3741,7 +3754,10 @@ nfs_deallocate(struct vop_deallocate_args *ap)
nfsva.na_size - *ap->a_offset,
tlen);
}
- *ap->a_len = 0;
+ if (clipped && tlen < *ap->a_len)
+ *ap->a_len -= tlen;
+ else
+ *ap->a_len = 0;
} else if (error == NFSERR_NOTSUPP) {
mtx_lock(&nmp->nm_mtx);
nmp->nm_privflag |= NFSMNTP_NODEALLOCATE;