aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRick Macklem <rmacklem@FreeBSD.org>2023-10-17 20:55:48 +0000
committerRick Macklem <rmacklem@FreeBSD.org>2023-11-16 23:54:20 +0000
commit0948d2a9cfea5a469a9505fb314a6f9af38bb6fa (patch)
tree2bb57b64d6ee318633e94188a8c8c4f7abee4143
parentd9e3f1a5da21b905c3e904643dc45e794eb842e6 (diff)
downloadsrc-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.c30
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)