From 5d4835e4b762eb48c1dc11c85f6fe2c71bd18c8f Mon Sep 17 00:00:00 2001 From: Rick Macklem Date: Fri, 11 May 2018 22:16:23 +0000 Subject: [PATCH] Add support for the TestStateID operation to the NFSv4.1 server. The Linux client now uses the TestStateID operation, so this patch adds support for it to the NFSv4.1 server. The FreeBSD client never uses this operation, so it should not be affected. MFC after: 2 months --- sys/fs/nfs/nfs_var.h | 3 +++ sys/fs/nfsserver/nfs_nfsdserv.c | 44 +++++++++++++++++++++++++++++++ sys/fs/nfsserver/nfs_nfsdsocket.c | 2 +- sys/fs/nfsserver/nfs_nfsdstate.c | 26 ++++++++++++++++++ 4 files changed, 74 insertions(+), 1 deletion(-) diff --git a/sys/fs/nfs/nfs_var.h b/sys/fs/nfs/nfs_var.h index f1f3efe3958d..151a32b37df8 100644 --- a/sys/fs/nfs/nfs_var.h +++ b/sys/fs/nfs/nfs_var.h @@ -98,6 +98,7 @@ int nfsrv_getclient(nfsquad_t, int, struct nfsclient **, struct nfsdsession *, int nfsrv_destroyclient(nfsquad_t, NFSPROC_T *); int nfsrv_destroysession(struct nfsrv_descript *, uint8_t *); int nfsrv_freestateid(struct nfsrv_descript *, nfsv4stateid_t *, NFSPROC_T *); +int nfsrv_teststateid(struct nfsrv_descript *, nfsv4stateid_t *, NFSPROC_T *); int nfsrv_adminrevoke(struct nfsd_clid *, NFSPROC_T *); void nfsrv_dumpclients(struct nfsd_dumpclients *, int); void nfsrv_dumplocks(vnode_t, struct nfsd_dumplocks *, int, NFSPROC_T *); @@ -236,6 +237,8 @@ int nfsrvd_destroysession(struct nfsrv_descript *, int, vnode_t, NFSPROC_T *, struct nfsexstuff *); int nfsrvd_freestateid(struct nfsrv_descript *, int, vnode_t, NFSPROC_T *, struct nfsexstuff *); +int nfsrvd_teststateid(struct nfsrv_descript *, int, + vnode_t, NFSPROC_T *, struct nfsexstuff *); int nfsrvd_notsupp(struct nfsrv_descript *, int, vnode_t, NFSPROC_T *, struct nfsexstuff *); diff --git a/sys/fs/nfsserver/nfs_nfsdserv.c b/sys/fs/nfsserver/nfs_nfsdserv.c index c1dacca937b5..5ea20b7a8a20 100644 --- a/sys/fs/nfsserver/nfs_nfsdserv.c +++ b/sys/fs/nfsserver/nfs_nfsdserv.c @@ -4100,6 +4100,50 @@ nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram, return (error); } +/* + * nfsv4 test stateid service + */ +APPLESTATIC int +nfsrvd_teststateid(struct nfsrv_descript *nd, __unused int isdgram, + __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) +{ + uint32_t *tl; + nfsv4stateid_t *stateidp = NULL, *tstateidp; + int cnt, error = 0, i, ret; + + if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { + nd->nd_repstat = NFSERR_WRONGSEC; + goto nfsmout; + } + NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); + cnt = fxdr_unsigned(int, *tl); + if (cnt <= 0 || cnt > 1024) { + nd->nd_repstat = NFSERR_BADXDR; + goto nfsmout; + } + stateidp = mallocarray(cnt, sizeof(nfsv4stateid_t), M_TEMP, M_WAITOK); + tstateidp = stateidp; + for (i = 0; i < cnt; i++) { + NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); + tstateidp->seqid = fxdr_unsigned(uint32_t, *tl++); + NFSBCOPY(tl, tstateidp->other, NFSX_STATEIDOTHER); + tstateidp++; + } + NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); + *tl = txdr_unsigned(cnt); + tstateidp = stateidp; + for (i = 0; i < cnt; i++) { + ret = nfsrv_teststateid(nd, tstateidp, p); + NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); + *tl = txdr_unsigned(ret); + tstateidp++; + } +nfsmout: + free(stateidp, M_TEMP); + NFSEXITCODE2(error, nd); + return (error); +} + /* * nfsv4 service not supported */ diff --git a/sys/fs/nfsserver/nfs_nfsdsocket.c b/sys/fs/nfsserver/nfs_nfsdsocket.c index 633b712a8349..64b84835efe9 100644 --- a/sys/fs/nfsserver/nfs_nfsdsocket.c +++ b/sys/fs/nfsserver/nfs_nfsdsocket.c @@ -192,7 +192,7 @@ int (*nfsrv4_ops0[NFSV41_NOPS])(struct nfsrv_descript *, nfsrvd_notsupp, nfsrvd_sequence, nfsrvd_notsupp, - nfsrvd_notsupp, + nfsrvd_teststateid, nfsrvd_notsupp, nfsrvd_destroyclientid, nfsrvd_reclaimcomplete, diff --git a/sys/fs/nfsserver/nfs_nfsdstate.c b/sys/fs/nfsserver/nfs_nfsdstate.c index dfead5834c55..33c529a9f617 100644 --- a/sys/fs/nfsserver/nfs_nfsdstate.c +++ b/sys/fs/nfsserver/nfs_nfsdstate.c @@ -6049,6 +6049,32 @@ nfsrv_freestateid(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, return (error); } +/* + * Test a stateid. + */ +int +nfsrv_teststateid(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, + NFSPROC_T *p) +{ + struct nfsclient *clp; + struct nfsstate *stp; + int error; + + NFSLOCKSTATE(); + /* + * Look up the stateid + */ + error = nfsrv_getclient((nfsquad_t)((u_quad_t)0), CLOPS_RENEW, &clp, + NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p); + if (error == 0) + error = nfsrv_getstate(clp, stateidp, 0, &stp); + if (error == 0 && stateidp->seqid != 0 && + SEQ_LT(stateidp->seqid, stp->ls_stateid.seqid)) + error = NFSERR_OLDSTATEID; + NFSUNLOCKSTATE(); + return (error); +} + /* * Generate the xdr for an NFSv4.1 CBSequence Operation. */