diff options
author | Rick Macklem <rmacklem@FreeBSD.org> | 2023-10-17 20:55:48 +0000 |
---|---|---|
committer | Rick Macklem <rmacklem@FreeBSD.org> | 2023-11-16 23:54:20 +0000 |
commit | 0948d2a9cfea5a469a9505fb314a6f9af38bb6fa (patch) | |
tree | 2bb57b64d6ee318633e94188a8c8c4f7abee4143 | |
parent | d9e3f1a5da21b905c3e904643dc45e794eb842e6 (diff) | |
download | src-0948d2a9cfea5a469a9505fb314a6f9af38bb6fa.tar.gz src-0948d2a9cfea5a469a9505fb314a6f9af38bb6fa.zip |
nfsd: Avoid acquiring a vnode for some NFSv4 Readdir operations
Without this patch, a NFSv4 Readdir operation acquires the vnode for
each entry in the directory. If only the Type, Fileid, Mounted_on_fileid
and ReaddirError attributes are requested by a client, acquiring the vnode
is not necessary for non-directories. Directory vnodes must be acquired
to check for server file system mount points.
This patch avoids acquiring the vnode, as above, resulting in a 3-8%
improvement in Readdir RPC RTT for some simple tests I did.
Note that only non-rdirplus NFSv4 mounts will benefit from this change.
Tested during a recent IETF NFSv4 Bakeathon testing event.
(cherry picked from commit cd5edc7db261fb228be4044e6fdd38850eb4e9c4)
-rw-r--r-- | sys/fs/nfsserver/nfs_nfsdport.c | 30 |
1 files changed, 27 insertions, 3 deletions
diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c index e2a3ff7e3b93..05cebdd13f7d 100644 --- a/sys/fs/nfsserver/nfs_nfsdport.c +++ b/sys/fs/nfsserver/nfs_nfsdport.c @@ -117,6 +117,11 @@ extern int nfsrv_issuedelegs; extern int nfsrv_dolocallocks; extern struct nfsdevicehead nfsrv_devidhead; +/* Map d_type to vnode type. */ +static uint8_t dtype_to_vnode[DT_WHT + 1] = { VNON, VFIFO, VCHR, VNON, VDIR, + VNON, VBLK, VNON, VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON }; +#define NFS_DTYPETOVTYPE(t) ((t) <= DT_WHT ? dtype_to_vnode[(t)] : VNON) + static int nfsrv_createiovec(int, struct mbuf **, struct mbuf **, struct iovec **); static int nfsrv_createiovec_extpgs(int, int, struct mbuf **, @@ -2319,7 +2324,7 @@ nfsrvd_readdirplus(struct nfsrv_descript *nd, int isdgram, caddr_t bpos0, bpos1; u_int64_t off, toff, verf; u_long *cookies = NULL, *cookiep; - nfsattrbit_t attrbits, rderrbits, savbits; + nfsattrbit_t attrbits, rderrbits, savbits, refbits; struct uio io; struct iovec iv; struct componentname cn; @@ -2370,9 +2375,20 @@ nfsrvd_readdirplus(struct nfsrv_descript *nd, int isdgram, if (error) goto nfsmout; NFSSET_ATTRBIT(&savbits, &attrbits); + NFSSET_ATTRBIT(&refbits, &attrbits); NFSCLRNOTFILLABLE_ATTRBIT(&attrbits, nd); NFSZERO_ATTRBIT(&rderrbits); NFSSETBIT_ATTRBIT(&rderrbits, NFSATTRBIT_RDATTRERROR); + /* + * If these 4 bits are the only attributes requested by the + * client, they can be satisfied without acquiring the vnode + * for the file object unless it is a directory. + * This will be indicated by savbits being all 0s. + */ + NFSCLRBIT_ATTRBIT(&savbits, NFSATTRBIT_TYPE); + NFSCLRBIT_ATTRBIT(&savbits, NFSATTRBIT_FILEID); + NFSCLRBIT_ATTRBIT(&savbits, NFSATTRBIT_MOUNTEDONFILEID); + NFSCLRBIT_ATTRBIT(&savbits, NFSATTRBIT_RDATTRERROR); } else { NFSZERO_ATTRBIT(&attrbits); } @@ -2616,7 +2632,10 @@ again: new_mp = mp; mounted_on_fileno = (uint64_t)dp->d_fileno; if ((nd->nd_flag & ND_NFSV3) || - NFSNONZERO_ATTRBIT(&savbits)) { + NFSNONZERO_ATTRBIT(&savbits) || + dp->d_type == DT_UNKNOWN || + (dp->d_type == DT_DIR && + nfsrv_enable_crossmntpt != 0)) { if (nd->nd_flag & ND_NFSV4) refp = nfsv4root_getreferral(NULL, vp, dp->d_fileno); @@ -2754,6 +2773,11 @@ again: break; } } + } else if (NFSNONZERO_ATTRBIT(&attrbits)) { + /* Only need Type and/or Fileid. */ + VATTR_NULL(&nvap->na_vattr); + nvap->na_fileid = dp->d_fileno; + nvap->na_type = NFS_DTYPETOVTYPE(dp->d_type); } /* @@ -2785,7 +2809,7 @@ again: supports_nfsv4acls = 0; if (refp != NULL) { dirlen += nfsrv_putreferralattr(nd, - &savbits, refp, 0, + &refbits, refp, 0, &nd->nd_repstat); if (nd->nd_repstat) { if (nvp != NULL) |