Date: Thu, 12 Aug 2021 01:53:14 GMT From: Rick Macklem <rmacklem@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: 3ad1e1c1ce20 - main - nfscl: Add a Lookup+Open RPC for NFSv4.1/4.2 Message-ID: <202108120153.17C1rEAl004772@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch main has been updated by rmacklem: URL: https://cgit.FreeBSD.org/src/commit/?id=3ad1e1c1ce2042bb45a518e28c881e5bc4491117 commit 3ad1e1c1ce2042bb45a518e28c881e5bc4491117 Author: Rick Macklem <rmacklem@FreeBSD.org> AuthorDate: 2021-08-12 01:49:26 +0000 Commit: Rick Macklem <rmacklem@FreeBSD.org> CommitDate: 2021-08-12 01:49:26 +0000 nfscl: Add a Lookup+Open RPC for NFSv4.1/4.2 This patch adds a Lookup+Open compound RPC to the NFSv4.1/4.2 NFS client, which can be used by nfs_lookup() so that a subsequent Open RPC is not required. It uses the cn_flags OPENREAD, OPENWRITE added by commit c18c74a87c15. This reduced the number of RPCs by about 15% for a kernel build over NFS. For now, use of Lookup+Open is only done when the "oneopenown" mount option is used. It may be possible for Lookup+Open to be used for non-oneopenown NFSv4.1/4.2 mounts, but that will require extensive further testing to determine if it works. While here, I've added the changes to the nfscommon module that are needed to implement the Deallocate NFSv4.2 operation. This avoids needing another cycle of changes to the internal KAPI between the NFS modules. This commit has changed the internal KAPI between the NFS modules and, as such, all need to be rebuilt from sources. I have not bumped __FreeBSD_version, since it was bumped a few days ago. --- sys/fs/nfs/nfs_commonsubs.c | 11 ++-- sys/fs/nfs/nfs_var.h | 4 +- sys/fs/nfs/nfsport.h | 12 +++- sys/fs/nfs/nfsproto.h | 8 ++- sys/fs/nfsclient/nfs_clrpcops.c | 140 +++++++++++++++++++++++++++++++++++++++- sys/fs/nfsclient/nfs_clstate.c | 4 +- sys/fs/nfsclient/nfs_clvnops.c | 28 ++++++-- 7 files changed, 188 insertions(+), 19 deletions(-) diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c index 817d89284091..20f5618c202c 100644 --- a/sys/fs/nfs/nfs_commonsubs.c +++ b/sys/fs/nfs/nfs_commonsubs.c @@ -179,7 +179,7 @@ struct nfsv4_opflag nfsv4_opflag[NFSV42_NOPS] = { { 0, 1, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Allocate */ { 2, 1, 1, 0, LK_SHARED, 1, 0 }, /* Copy */ { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Copy Notify */ - { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Deallocate */ + { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Deallocate */ { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* IO Advise */ { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Layout Error */ { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Layout Stats */ @@ -219,7 +219,7 @@ static struct nfsrv_lughash *nfsgroupnamehash; static int nfs_bigreply[NFSV42_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 0, 0, 1, 0 }; + 1, 0, 0, 1, 0, 0, 0 }; /* local functions */ static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep); @@ -303,6 +303,8 @@ static struct { { NFSV4OP_REMOVEXATTR, 2, "Rmxattr", 7, }, { NFSV4OP_LISTXATTRS, 2, "Listxattr", 9, }, { NFSV4OP_BINDCONNTOSESS, 1, "BindConSess", 11, }, + { NFSV4OP_LOOKUP, 5, "LookupOpen", 10, }, + { NFSV4OP_DEALLOCATE, 2, "Deallocate", 10, }, }; /* @@ -311,7 +313,7 @@ static struct { static int nfs_bigrequest[NFSV42_NPROCS] = { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }; /* @@ -434,7 +436,8 @@ nfscl_reqstart(struct nfsrv_descript *nd, int procnum, struct nfsmount *nmp, * attributes, so we can load the name cache. */ if (procnum == NFSPROC_LOOKUP || - procnum == NFSPROC_LOOKUPP) + procnum == NFSPROC_LOOKUPP || + procnum == NFSPROC_LOOKUPOPEN) NFSGETATTR_ATTRBIT(&attrbits); else { NFSWCCATTR_ATTRBIT(&attrbits); diff --git a/sys/fs/nfs/nfs_var.h b/sys/fs/nfs/nfs_var.h index 9cbaeae361a6..b4c21c6f7029 100644 --- a/sys/fs/nfs/nfs_var.h +++ b/sys/fs/nfs/nfs_var.h @@ -465,7 +465,7 @@ int nfsrpc_setattr(vnode_t, struct vattr *, NFSACL_T *, struct ucred *, NFSPROC_T *, struct nfsvattr *, int *, void *); int nfsrpc_lookup(vnode_t, char *, int, struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, struct nfsfh **, int *, int *, - void *); + void *, uint32_t); int nfsrpc_readlink(vnode_t, struct uio *, struct ucred *, NFSPROC_T *, struct nfsvattr *, int *, void *); int nfsrpc_read(vnode_t, struct uio *, struct ucred *, NFSPROC_T *, @@ -624,6 +624,8 @@ void nfscl_reclaimnode(vnode_t); void nfscl_newnode(vnode_t); void nfscl_delegmodtime(vnode_t); void nfscl_deleggetmodtime(vnode_t, struct timespec *); +int nfscl_trydelegreturn(struct nfscldeleg *, struct ucred *, + struct nfsmount *, NFSPROC_T *); int nfscl_tryclose(struct nfsclopen *, struct ucred *, struct nfsmount *, NFSPROC_T *); void nfscl_cleanup(NFSPROC_T *); diff --git a/sys/fs/nfs/nfsport.h b/sys/fs/nfs/nfsport.h index cb82666ab397..64ba4d48b3f1 100644 --- a/sys/fs/nfs/nfsport.h +++ b/sys/fs/nfs/nfsport.h @@ -415,10 +415,16 @@ /* BindConnectionToSession, done by the krpc for a new connection. */ #define NFSPROC_BINDCONNTOSESS 65 +/* Do a Lookup+Open for "oneopenown". */ +#define NFSPROC_LOOKUPOPEN 66 + +/* Do an NFSv4.2 Deallocate. */ +#define NFSPROC_DEALLOCATE 67 + /* * Must be defined as one higher than the last NFSv4.2 Proc# above. */ -#define NFSV42_NPROCS 66 +#define NFSV42_NPROCS 68 #endif /* NFS_V3NPROCS */ @@ -447,7 +453,7 @@ struct nfsstatsv1 { uint64_t readlink_bios; uint64_t biocache_readdirs; uint64_t readdir_bios; - uint64_t rpccnt[NFSV42_NPROCS + 14]; + uint64_t rpccnt[NFSV42_NPROCS + 12]; uint64_t rpcretries; uint64_t srvrpccnt[NFSV42_NOPS + NFSV4OP_FAKENOPS + 15]; uint64_t reserved_0; @@ -512,7 +518,7 @@ struct nfsstatsov1 { uint64_t readlink_bios; uint64_t biocache_readdirs; uint64_t readdir_bios; - uint64_t rpccnt[NFSV42_NPROCS + 3]; + uint64_t rpccnt[NFSV42_NPROCS + 1]; uint64_t rpcretries; uint64_t srvrpccnt[NFSV42_PURENOPS + NFSV4OP_FAKENOPS]; uint64_t reserved_0; diff --git a/sys/fs/nfs/nfsproto.h b/sys/fs/nfs/nfsproto.h index 13e146154805..7ac7cdc3bacf 100644 --- a/sys/fs/nfs/nfsproto.h +++ b/sys/fs/nfs/nfsproto.h @@ -396,10 +396,16 @@ /* BindConnectionToSession, done by the krpc for a new connection. */ #define NFSPROC_BINDCONNTOSESS 65 +/* Do a Lookup+Open for "oneopenown". */ +#define NFSPROC_LOOKUPOPEN 66 + +/* Do an NFSv4.2 Deallocate. */ +#define NFSPROC_DEALLOCATE 67 + /* * Must be defined as one higher than the last NFSv4.2 Proc# above. */ -#define NFSV42_NPROCS 66 +#define NFSV42_NPROCS 68 #endif /* NFS_V3NPROCS */ diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c index 74803e255aae..de4030876bfe 100644 --- a/sys/fs/nfsclient/nfs_clrpcops.c +++ b/sys/fs/nfsclient/nfs_clrpcops.c @@ -1382,15 +1382,20 @@ nfsrpc_setattrrpc(vnode_t vp, struct vattr *vap, int nfsrpc_lookup(vnode_t dvp, char *name, int len, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, struct nfsvattr *nap, - struct nfsfh **nfhpp, int *attrflagp, int *dattrflagp, void *stuff) + struct nfsfh **nfhpp, int *attrflagp, int *dattrflagp, void *stuff, + uint32_t openmode) { - u_int32_t *tl; + uint32_t deleg, rflags, *tl; struct nfsrv_descript nfsd, *nd = &nfsd; struct nfsmount *nmp; struct nfsnode *np; struct nfsfh *nfhp; nfsattrbit_t attrbits; - int error = 0, lookupp = 0; + int error = 0, lookupp = 0, newone, ret, retop; + uint8_t own[NFSV4CL_LOCKNAMELEN]; + struct nfsclopen *op; + struct nfscldeleg *ndp; + nfsv4stateid_t stateid; *attrflagp = 0; *dattrflagp = 0; @@ -1415,7 +1420,11 @@ nfsrpc_lookup(vnode_t dvp, char *name, int len, struct ucred *cred, if (NFSHASNFSV4(nmp) && len == 2 && name[0] == '.' && name[1] == '.') { lookupp = 1; + openmode = 0; NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, dvp); + } else if (openmode != 0) { + NFSCL_REQSTART(nd, NFSPROC_LOOKUPOPEN, dvp); + nfsm_strtom(nd, name, len); } else { NFSCL_REQSTART(nd, NFSPROC_LOOKUP, dvp); (void) nfsm_strtom(nd, name, len); @@ -1426,10 +1435,36 @@ nfsrpc_lookup(vnode_t dvp, char *name, int len, struct ucred *cred, *tl++ = txdr_unsigned(NFSV4OP_GETFH); *tl = txdr_unsigned(NFSV4OP_GETATTR); (void) nfsrv_putattrbit(nd, &attrbits); + if (openmode != 0) { + /* Test for a VREG file. */ + NFSZERO_ATTRBIT(&attrbits); + NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TYPE); + NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); + *tl = txdr_unsigned(NFSV4OP_VERIFY); + nfsrv_putattrbit(nd, &attrbits); + NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); + *tl++ = txdr_unsigned(NFSX_UNSIGNED); + *tl = vtonfsv34_type(VREG); + + /* Attempt the Open for VREG. */ + nfscl_filllockowner(NULL, own, F_POSIX); + NFSM_BUILD(tl, uint32_t *, 6 * NFSX_UNSIGNED); + *tl++ = txdr_unsigned(NFSV4OP_OPEN); + *tl++ = 0; /* seqid, ignored. */ + *tl++ = txdr_unsigned(openmode); + *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE); + *tl++ = 0; /* ClientID, ignored. */ + *tl = 0; + nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN); + NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); + *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE); + *tl = txdr_unsigned(NFSV4OPEN_CLAIMFH); + } } error = nfscl_request(nd, dvp, p, cred, stuff); if (error) return (error); + ndp = NULL; if (nd->nd_repstat) { /* * When an NFSv4 Lookupp returns ENOENT, it means that @@ -1453,6 +1488,33 @@ nfsrpc_lookup(vnode_t dvp, char *name, int len, struct ucred *cred, error = nfsm_loadattr(nd, dnap); if (error == 0) *dattrflagp = 1; + else + goto nfsmout; + } + /* Check Lookup operation reply status. */ + if (openmode != 0 && (nd->nd_flag & ND_NOMOREDATA) == 0) { + NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); + if (*++tl != 0) + goto nfsmout; + } + /* Look for GetFH reply. */ + if (openmode != 0 && (nd->nd_flag & ND_NOMOREDATA) == 0) { + NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); + if (*++tl != 0) + goto nfsmout; + error = nfsm_getfh(nd, nfhpp); + if (error) + goto nfsmout; + } + /* Look for Getattr reply. */ + if (openmode != 0 && (nd->nd_flag & ND_NOMOREDATA) == 0) { + NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); + if (*++tl != 0) + goto nfsmout; + error = nfscl_postop_attr(nd, nap, attrflagp, stuff); + if (error == 0) + /* Successfully got Lookup done. */ + nd->nd_repstat = 0; } goto nfsmout; } @@ -1470,12 +1532,84 @@ nfsrpc_lookup(vnode_t dvp, char *name, int len, struct ucred *cred, goto nfsmout; error = nfscl_postop_attr(nd, nap, attrflagp, stuff); + if (openmode != 0 && error == 0) { + NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + + 10 * NFSX_UNSIGNED); + tl += 4; /* Skip over Verify+Open status. */ + stateid.seqid = *tl++; + stateid.other[0] = *tl++; + stateid.other[1] = *tl++; + stateid.other[2] = *tl; + rflags = fxdr_unsigned(uint32_t, *(tl + 6)); + error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); + if (error != 0) + goto nfsmout; + NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); + deleg = fxdr_unsigned(uint32_t, *tl); + if (deleg == NFSV4OPEN_DELEGATEREAD || + deleg == NFSV4OPEN_DELEGATEWRITE) { + /* + * Just need to fill in the fields used by + * nfscl_trydelegreturn(). + * Mark the mount point as acquiring + * delegations, so NFSPROC_LOOKUPOPEN will + * no longer be done. + */ + NFSLOCKMNT(nmp); + nmp->nm_privflag |= NFSMNTP_DELEGISSUED; + NFSUNLOCKMNT(nmp); + ndp = malloc(sizeof(struct nfscldeleg) + + (*nfhpp)->nfh_len, M_NFSCLDELEG, M_WAITOK); + ndp->nfsdl_fhlen = (*nfhpp)->nfh_len; + NFSBCOPY((*nfhpp)->nfh_fh, ndp->nfsdl_fh, + ndp->nfsdl_fhlen); + newnfs_copyincred(cred, &ndp->nfsdl_cred); + NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); + ndp->nfsdl_stateid.seqid = *tl++; + ndp->nfsdl_stateid.other[0] = *tl++; + ndp->nfsdl_stateid.other[1] = *tl++; + ndp->nfsdl_stateid.other[2] = *tl++; + } else if (deleg != NFSV4OPEN_DELEGATENONE) { + error = NFSERR_BADXDR; + goto nfsmout; + } + ret = nfscl_open(dvp, (*nfhpp)->nfh_fh, (*nfhpp)->nfh_len, + openmode, 0, cred, p, NULL, &op, &newone, &retop, 1); + if (ret != 0) + goto nfsmout; + if (newone != 0) { + op->nfso_stateid.seqid = stateid.seqid; + op->nfso_stateid.other[0] = stateid.other[0]; + op->nfso_stateid.other[1] = stateid.other[1]; + op->nfso_stateid.other[2] = stateid.other[2]; + op->nfso_mode = openmode; + } else { + op->nfso_stateid.seqid = stateid.seqid; + if (retop == NFSCLOPEN_DOOPEN) + op->nfso_mode |= openmode; + } + if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) != 0 || + nfscl_assumeposixlocks) + op->nfso_posixlock = 1; + else + op->nfso_posixlock = 0; + nfscl_openrelease(nmp, op, 0, 0); + if (ndp != NULL) { + /* + * Since we do not have the vnode, we + * cannot invalidate cached attributes. + * Just return the delegation. + */ + nfscl_trydelegreturn(ndp, cred, nmp, p); + } + } if ((nd->nd_flag & ND_NFSV3) && !error) error = nfscl_postop_attr(nd, dnap, dattrflagp, stuff); nfsmout: m_freem(nd->nd_mrep); if (!error && nd->nd_repstat) error = nd->nd_repstat; + free(ndp, M_NFSCLDELEG); return (error); } diff --git a/sys/fs/nfsclient/nfs_clstate.c b/sys/fs/nfsclient/nfs_clstate.c index bb2c78a72ed9..8ec5b80489f9 100644 --- a/sys/fs/nfsclient/nfs_clstate.c +++ b/sys/fs/nfsclient/nfs_clstate.c @@ -162,8 +162,6 @@ static int nfscl_recalldeleg(struct nfsclclient *, struct nfsmount *, vnode_t *); static void nfscl_freeopenowner(struct nfsclowner *, int); static void nfscl_cleandeleg(struct nfscldeleg *); -static int nfscl_trydelegreturn(struct nfscldeleg *, struct ucred *, - struct nfsmount *, NFSPROC_T *); static void nfscl_emptylockowner(struct nfscllockowner *, struct nfscllockownerfhhead *); static void nfscl_mergeflayouts(struct nfsclflayouthead *, @@ -4463,7 +4461,7 @@ nfscl_trylock(struct nfsmount *nmp, vnode_t vp, u_int8_t *fhp, * retrying while NFSERR_DELAY. Also, try system credentials, if the passed in * credentials fail. */ -static int +int nfscl_trydelegreturn(struct nfscldeleg *dp, struct ucred *cred, struct nfsmount *nmp, NFSPROC_T *p) { diff --git a/sys/fs/nfsclient/nfs_clvnops.c b/sys/fs/nfsclient/nfs_clvnops.c index 72d9eac8e962..39340692563f 100644 --- a/sys/fs/nfsclient/nfs_clvnops.c +++ b/sys/fs/nfsclient/nfs_clvnops.c @@ -1164,6 +1164,7 @@ nfs_lookup(struct vop_lookup_args *ap) struct nfsvattr dnfsva, nfsva; struct vattr vattr; struct timespec nctime; + uint32_t openmode; *vpp = NULLVP; if ((flags & ISLASTCN) && (mp->mnt_flag & MNT_RDONLY) && @@ -1265,11 +1266,30 @@ nfs_lookup(struct vop_lookup_args *ap) cache_purge_negative(dvp); } + /* + * If this an NFSv4.1/4.2 mount using the "oneopenown" mount + * option, it is possible to do the Open operation in the same + * compound as Lookup, so long as delegations are not being + * issued. This saves doing a separate RPC for Open. + */ + openmode = 0; + NFSLOCKMNT(nmp); + if (NFSHASNFSV4N(nmp) && NFSHASONEOPENOWN(nmp) && + (nmp->nm_privflag & NFSMNTP_DELEGISSUED) == 0 && + (!NFSMNT_RDONLY(mp) || (flags & OPENWRITE) == 0) && + (flags & (ISLASTCN | ISOPEN)) == (ISLASTCN | ISOPEN)) { + if ((flags & OPENREAD) != 0) + openmode |= NFSV4OPEN_ACCESSREAD; + if ((flags & OPENWRITE) != 0) + openmode |= NFSV4OPEN_ACCESSWRITE; + } + NFSUNLOCKMNT(nmp); + newvp = NULLVP; NFSINCRGLOBAL(nfsstatsv1.lookupcache_misses); error = nfsrpc_lookup(dvp, cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_cred, td, &dnfsva, &nfsva, &nfhp, &attrflag, &dattrflag, - NULL); + NULL, openmode); if (dattrflag) (void) nfscl_loadattrcache(&dvp, &dnfsva, NULL, NULL, 0, 1); if (error) { @@ -1577,7 +1597,7 @@ nfs_mknodrpc(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, (void) nfsrpc_lookup(dvp, cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_cred, cnp->cn_thread, &dnfsva, &nfsva, &nfhp, &attrflag, &dattrflag, - NULL); + NULL, 0); if (nfhp) error = nfscl_nget(dvp->v_mount, dvp, nfhp, cnp, cnp->cn_thread, &np, NULL, LK_EXCLUSIVE); @@ -1693,7 +1713,7 @@ again: (void) nfsrpc_lookup(dvp, cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_cred, cnp->cn_thread, &dnfsva, &nfsva, &nfhp, &attrflag, &dattrflag, - NULL); + NULL, 0); if (nfhp != NULL) error = nfscl_nget(dvp->v_mount, dvp, nfhp, cnp, cnp->cn_thread, &np, NULL, LK_EXCLUSIVE); @@ -2611,7 +2631,7 @@ nfs_lookitup(struct vnode *dvp, char *name, int len, struct ucred *cred, u_int hash; error = nfsrpc_lookup(dvp, name, len, cred, td, &dnfsva, &nfsva, - &nfhp, &attrflag, &dattrflag, NULL); + &nfhp, &attrflag, &dattrflag, NULL, 0); if (dattrflag) (void) nfscl_loadattrcache(&dvp, &dnfsva, NULL, NULL, 0, 1); if (npp && !error) {
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202108120153.17C1rEAl004772>