summaryrefslogtreecommitdiffstats
path: root/sys/fs/nfs/nfs_commonkrpc.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/fs/nfs/nfs_commonkrpc.c')
-rw-r--r--sys/fs/nfs/nfs_commonkrpc.c155
1 files changed, 117 insertions, 38 deletions
diff --git a/sys/fs/nfs/nfs_commonkrpc.c b/sys/fs/nfs/nfs_commonkrpc.c
index 7b72ced..6640c1f 100644
--- a/sys/fs/nfs/nfs_commonkrpc.c
+++ b/sys/fs/nfs/nfs_commonkrpc.c
@@ -76,23 +76,27 @@ dtrace_nfsclient_nfs23_done_probe_func_t
/*
* Registered probes by RPC type.
*/
-uint32_t nfscl_nfs2_start_probes[NFS_NPROCS + 1];
-uint32_t nfscl_nfs2_done_probes[NFS_NPROCS + 1];
+uint32_t nfscl_nfs2_start_probes[NFSV41_NPROCS + 1];
+uint32_t nfscl_nfs2_done_probes[NFSV41_NPROCS + 1];
-uint32_t nfscl_nfs3_start_probes[NFS_NPROCS + 1];
-uint32_t nfscl_nfs3_done_probes[NFS_NPROCS + 1];
+uint32_t nfscl_nfs3_start_probes[NFSV41_NPROCS + 1];
+uint32_t nfscl_nfs3_done_probes[NFSV41_NPROCS + 1];
-uint32_t nfscl_nfs4_start_probes[NFS_NPROCS + 1];
-uint32_t nfscl_nfs4_done_probes[NFS_NPROCS + 1];
+uint32_t nfscl_nfs4_start_probes[NFSV41_NPROCS + 1];
+uint32_t nfscl_nfs4_done_probes[NFSV41_NPROCS + 1];
#endif
NFSSTATESPINLOCK;
NFSREQSPINLOCK;
+NFSDLOCKMUTEX;
extern struct nfsstats newnfsstats;
extern struct nfsreqhead nfsd_reqq;
extern int nfscl_ticks;
extern void (*ncl_call_invalcaches)(struct vnode *);
+extern int nfs_numnfscbd;
+extern int nfscl_debuglevel;
+SVCPOOL *nfscbd_pool;
static int nfsrv_gsscallbackson = 0;
static int nfs_bufpackets = 4;
static int nfs_reconnects;
@@ -167,6 +171,7 @@ newnfs_connect(struct nfsmount *nmp, struct nfssockreq *nrp,
struct socket *so;
int one = 1, retries, error = 0;
struct thread *td = curthread;
+ SVCXPRT *xprt;
struct timeval timo;
/*
@@ -277,6 +282,24 @@ newnfs_connect(struct nfsmount *nmp, struct nfssockreq *nrp,
retries = nmp->nm_retry;
} else
retries = INT_MAX;
+ if (NFSHASNFSV4N(nmp)) {
+ /*
+ * Make sure the nfscbd_pool doesn't get destroyed
+ * while doing this.
+ */
+ NFSD_LOCK();
+ if (nfs_numnfscbd > 0) {
+ nfs_numnfscbd++;
+ NFSD_UNLOCK();
+ xprt = svc_vc_create_backchannel(nfscbd_pool);
+ CLNT_CONTROL(client, CLSET_BACKCHANNEL, xprt);
+ NFSD_LOCK();
+ nfs_numnfscbd--;
+ if (nfs_numnfscbd == 0)
+ wakeup(&nfs_numnfscbd);
+ }
+ NFSD_UNLOCK();
+ }
} else {
/*
* Three cases:
@@ -468,12 +491,13 @@ int
newnfs_request(struct nfsrv_descript *nd, struct nfsmount *nmp,
struct nfsclient *clp, struct nfssockreq *nrp, vnode_t vp,
struct thread *td, struct ucred *cred, u_int32_t prog, u_int32_t vers,
- u_char *retsum, int toplevel, u_int64_t *xidp)
+ u_char *retsum, int toplevel, u_int64_t *xidp, struct nfsclsession *sep)
{
- u_int32_t *tl;
+ u_int32_t retseq, retval, *tl;
time_t waituntil;
- int i, j, set_sigset = 0, timeo;
+ int i = 0, j = 0, opcnt, set_sigset = 0, slot;
int trycnt, error = 0, usegssname = 0, secflavour = AUTH_SYS;
+ int freeslot, timeo;
u_int16_t procnum;
u_int trylater_delay = 1;
struct nfs_feedback_arg nf;
@@ -670,7 +694,9 @@ newnfs_request(struct nfsrv_descript *nd, struct nfsmount *nmp,
#endif
}
trycnt = 0;
+ freeslot = -1; /* Set to slot that needs to be free'd */
tryagain:
+ slot = -1; /* Slot that needs a sequence# increment. */
/*
* This timeout specifies when a new socket should be created,
* along with new xid values. For UDP, this should be done
@@ -772,11 +798,66 @@ tryagain:
nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
nd->nd_repstat = 0;
if (nd->nd_procnum != NFSPROC_NULL) {
+ /* If sep == NULL, set it to the default in nmp. */
+ if (sep == NULL && nmp != NULL)
+ sep = NFSMNT_MDSSESSION(nmp);
/*
* and now the actual NFS xdr.
*/
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
nd->nd_repstat = fxdr_unsigned(u_int32_t, *tl);
+ if (nd->nd_repstat >= 10000)
+ NFSCL_DEBUG(1, "proc=%d reps=%d\n", (int)nd->nd_procnum,
+ (int)nd->nd_repstat);
+
+ /*
+ * Get rid of the tag, return count and SEQUENCE result for
+ * NFSv4.
+ */
+ if ((nd->nd_flag & ND_NFSV4) != 0) {
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ i = fxdr_unsigned(int, *tl);
+ error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
+ if (error)
+ goto nfsmout;
+ NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
+ opcnt = fxdr_unsigned(int, *tl++);
+ i = fxdr_unsigned(int, *tl++);
+ j = fxdr_unsigned(int, *tl);
+ if (j >= 10000)
+ NFSCL_DEBUG(1, "fop=%d fst=%d\n", i, j);
+ /*
+ * If the first op is Sequence, free up the slot.
+ */
+ if (nmp != NULL && i == NFSV4OP_SEQUENCE && j != 0)
+ NFSCL_DEBUG(1, "failed seq=%d\n", j);
+ if (nmp != NULL && i == NFSV4OP_SEQUENCE && j == 0) {
+ NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID +
+ 5 * NFSX_UNSIGNED);
+ mtx_lock(&sep->nfsess_mtx);
+ tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
+ retseq = fxdr_unsigned(uint32_t, *tl++);
+ slot = fxdr_unsigned(int, *tl++);
+ freeslot = slot;
+ if (retseq != sep->nfsess_slotseq[slot])
+ printf("retseq diff 0x%x\n", retseq);
+ retval = fxdr_unsigned(uint32_t, *++tl);
+ if ((retval + 1) < sep->nfsess_foreslots)
+ sep->nfsess_foreslots = (retval + 1);
+ else if ((retval + 1) > sep->nfsess_foreslots)
+ sep->nfsess_foreslots = (retval < 64) ?
+ (retval + 1) : 64;
+ mtx_unlock(&sep->nfsess_mtx);
+
+ /* Grab the op and status for the next one. */
+ if (opcnt > 1) {
+ NFSM_DISSECT(tl, uint32_t *,
+ 2 * NFSX_UNSIGNED);
+ i = fxdr_unsigned(int, *tl++);
+ j = fxdr_unsigned(int, *tl);
+ }
+ }
+ }
if (nd->nd_repstat != 0) {
if (((nd->nd_repstat == NFSERR_DELAY ||
nd->nd_repstat == NFSERR_GRACE) &&
@@ -784,7 +865,9 @@ tryagain:
nd->nd_procnum != NFSPROC_DELEGRETURN &&
nd->nd_procnum != NFSPROC_SETATTR &&
nd->nd_procnum != NFSPROC_READ &&
+ nd->nd_procnum != NFSPROC_READDS &&
nd->nd_procnum != NFSPROC_WRITE &&
+ nd->nd_procnum != NFSPROC_WRITEDS &&
nd->nd_procnum != NFSPROC_OPEN &&
nd->nd_procnum != NFSPROC_CREATE &&
nd->nd_procnum != NFSPROC_OPENCONFIRM &&
@@ -801,6 +884,13 @@ tryagain:
while (NFSD_MONOSEC < waituntil)
(void) nfs_catnap(PZERO, 0, "nfstry");
trylater_delay *= 2;
+ if (slot != -1) {
+ mtx_lock(&sep->nfsess_mtx);
+ sep->nfsess_slotseq[slot]++;
+ *nd->nd_slotseq = txdr_unsigned(
+ sep->nfsess_slotseq[slot]);
+ mtx_unlock(&sep->nfsess_mtx);
+ }
m_freem(nd->nd_mrep);
nd->nd_mrep = NULL;
goto tryagain;
@@ -817,34 +907,22 @@ tryagain:
(*ncl_call_invalcaches)(vp);
}
}
-
- /*
- * Get rid of the tag, return count, and PUTFH result for V4.
- */
- if (nd->nd_flag & ND_NFSV4) {
- NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
- i = fxdr_unsigned(int, *tl);
- error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
- if (error)
- goto nfsmout;
- NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
- i = fxdr_unsigned(int, *++tl);
-
+ if ((nd->nd_flag & ND_NFSV4) != 0) {
+ /* Free the slot, as required. */
+ if (freeslot != -1)
+ nfsv4_freeslot(sep, freeslot);
/*
- * If the first op's status is non-zero, mark that
- * there is no more data to process.
+ * If this op is Putfh, throw its results away.
*/
- if (*++tl)
- nd->nd_flag |= ND_NOMOREDATA;
-
- /*
- * If the first op is Putfh, throw its results away
- * and toss the op# and status for the first op.
- */
- if (nmp != NULL && i == NFSV4OP_PUTFH && *tl == 0) {
+ if (j >= 10000)
+ NFSCL_DEBUG(1, "nop=%d nst=%d\n", i, j);
+ if (nmp != NULL && i == NFSV4OP_PUTFH && j == 0) {
NFSM_DISSECT(tl,u_int32_t *,2 * NFSX_UNSIGNED);
i = fxdr_unsigned(int, *tl++);
j = fxdr_unsigned(int, *tl);
+ if (j >= 10000)
+ NFSCL_DEBUG(1, "n2op=%d n2st=%d\n", i,
+ j);
/*
* All Compounds that do an Op that must
* be in sequence consist of NFSV4OP_PUTFH
@@ -867,19 +945,20 @@ tryagain:
j != NFSERR_RESOURCE &&
j != NFSERR_NOFILEHANDLE)))
nd->nd_flag |= ND_INCRSEQID;
- /*
- * If the first op's status is non-zero, mark
- * that there is no more data to process.
- */
- if (j)
- nd->nd_flag |= ND_NOMOREDATA;
}
+ /*
+ * If this op's status is non-zero, mark
+ * that there is no more data to process.
+ */
+ if (j)
+ nd->nd_flag |= ND_NOMOREDATA;
/*
* If R_DONTRECOVER is set, replace the stale error
* reply, so that recovery isn't initiated.
*/
if ((nd->nd_repstat == NFSERR_STALECLIENTID ||
+ nd->nd_repstat == NFSERR_BADSESSION ||
nd->nd_repstat == NFSERR_STALESTATEID) &&
rep != NULL && (rep->r_flags & R_DONTRECOVER))
nd->nd_repstat = NFSERR_STALEDONTRECOVER;
OpenPOWER on IntegriCloud