diff options
Diffstat (limited to 'sys/fs/nfs/nfs_commonkrpc.c')
-rw-r--r-- | sys/fs/nfs/nfs_commonkrpc.c | 155 |
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; |