/* * Check the cache and, optionally, do the RPC. * Return the appropriate cache response. */ static int nfs_proc(struct nfsrv_descript *nd, u_int32_t xid, struct socket *so, u_int64_t sockref, struct nfsrvcache **rpp) { struct thread *td = curthread; int cacherep = RC_DOIT, isdgram; *rpp = NULL; if (nd->nd_nam2 == NULL) { nd->nd_flag |= ND_STREAMSOCK; isdgram = 0; } else { isdgram = 1; } NFSGETTIME(&nd->nd_starttime); /* * Two cases: * 1 - For NFSv2 over UDP, if we are near our malloc/mget * limit, just drop the request. There is no * NFSERR_RESOURCE or NFSERR_DELAY for NFSv2 and the * client will timeout/retry over UDP in a little while. * 2 - nd_repstat == 0 && nd_mreq == NULL, which * means a normal nfs rpc, so check the cache */ if ((nd->nd_flag & ND_NFSV2) && nd->nd_nam2 != NULL && nfsrv_mallocmget_limit()) { cacherep = RC_DROPIT; } else { /* * For NFSv3, play it safe and assume that the client is * doing retries on the same TCP connection. */ if ((nd->nd_flag & (ND_NFSV4 | ND_STREAMSOCK)) == ND_STREAMSOCK) nd->nd_flag |= ND_SAMETCPCONN; nd->nd_retxid = xid; nd->nd_tcpconntime = NFSD_MONOSEC; nd->nd_sockref = sockref; cacherep = nfsrvd_getcache(nd, so); } /* * Handle the request. There are three cases. * RC_DOIT - do the RPC * RC_REPLY - return the reply already created * RC_DROPIT - just throw the request away */ if (cacherep == RC_DOIT) { nfsrvd_dorpc(nd, isdgram, td); if (nd->nd_repstat == NFSERR_DONTREPLY) cacherep = RC_DROPIT; else cacherep = RC_REPLY; *rpp = nfsrvd_updatecache(nd, so); } NFSEXITCODE2(0, nd); return (cacherep); }
/* * Check the cache and, optionally, do the RPC. * Return the appropriate cache response. */ static int nfs_proc(struct nfsrv_descript *nd, u_int32_t xid, SVCXPRT *xprt, struct nfsrvcache **rpp) { struct thread *td = curthread; int cacherep = RC_DOIT, isdgram, taglen = -1; struct mbuf *m; u_char tag[NFSV4_SMALLSTR + 1], *tagstr = NULL; u_int32_t minorvers = 0; uint32_t ack; *rpp = NULL; if (nd->nd_nam2 == NULL) { nd->nd_flag |= ND_STREAMSOCK; isdgram = 0; } else { isdgram = 1; } /* * Two cases: * 1 - For NFSv2 over UDP, if we are near our malloc/mget * limit, just drop the request. There is no * NFSERR_RESOURCE or NFSERR_DELAY for NFSv2 and the * client will timeout/retry over UDP in a little while. * 2 - nd_repstat == 0 && nd_mreq == NULL, which * means a normal nfs rpc, so check the cache */ if ((nd->nd_flag & ND_NFSV2) && nd->nd_nam2 != NULL && nfsrv_mallocmget_limit()) { cacherep = RC_DROPIT; } else { /* * For NFSv3, play it safe and assume that the client is * doing retries on the same TCP connection. */ if ((nd->nd_flag & (ND_NFSV4 | ND_STREAMSOCK)) == ND_STREAMSOCK) nd->nd_flag |= ND_SAMETCPCONN; nd->nd_retxid = xid; nd->nd_tcpconntime = NFSD_MONOSEC; nd->nd_sockref = xprt->xp_sockref; if ((nd->nd_flag & ND_NFSV4) != 0) nfsd_getminorvers(nd, tag, &tagstr, &taglen, &minorvers); if ((nd->nd_flag & ND_NFSV41) != 0) /* NFSv4.1 caches replies in the session slots. */ cacherep = RC_DOIT; else { cacherep = nfsrvd_getcache(nd); ack = 0; SVC_ACK(xprt, &ack); nfsrc_trimcache(xprt->xp_sockref, ack, 0); } } /* * Handle the request. There are three cases. * RC_DOIT - do the RPC * RC_REPLY - return the reply already created * RC_DROPIT - just throw the request away */ if (cacherep == RC_DOIT) { if ((nd->nd_flag & ND_NFSV41) != 0) nd->nd_xprt = xprt; nfsrvd_dorpc(nd, isdgram, tagstr, taglen, minorvers, td); if ((nd->nd_flag & ND_NFSV41) != 0) { if (nd->nd_repstat != NFSERR_REPLYFROMCACHE && (nd->nd_flag & ND_SAVEREPLY) != 0) { /* Cache a copy of the reply. */ m = m_copym(nd->nd_mreq, 0, M_COPYALL, M_WAITOK); } else m = NULL; if ((nd->nd_flag & ND_HASSEQUENCE) != 0) nfsrv_cache_session(nd->nd_sessionid, nd->nd_slotid, nd->nd_repstat, &m); if (nd->nd_repstat == NFSERR_REPLYFROMCACHE) nd->nd_repstat = 0; cacherep = RC_REPLY; } else { if (nd->nd_repstat == NFSERR_DONTREPLY) cacherep = RC_DROPIT; else cacherep = RC_REPLY; *rpp = nfsrvd_updatecache(nd); } } if (tagstr != NULL && taglen > NFSV4_SMALLSTR) free(tagstr, M_TEMP); NFSEXITCODE2(0, nd); return (cacherep); }
/* * copies mbuf chain to the uio scatter/gather list */ int nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz) { char *mbufcp, *uiocp; int xfer, left, len; mbuf_t mp; long uiosiz, rem; int error = 0; mp = nd->nd_md; mbufcp = nd->nd_dpos; len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp; rem = NFSM_RNDUP(siz) - siz; while (siz > 0) { if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) { error = EBADRPC; goto out; } left = uiop->uio_iov->iov_len; uiocp = uiop->uio_iov->iov_base; if (left > siz) left = siz; uiosiz = left; while (left > 0) { while (len == 0) { mp = mbuf_next(mp); if (mp == NULL) { error = EBADRPC; goto out; } mbufcp = NFSMTOD(mp, caddr_t); len = mbuf_len(mp); KASSERT(len >= 0, ("len %d, corrupted mbuf?", len)); } xfer = (left > len) ? len : left; #ifdef notdef /* Not Yet.. */ if (uiop->uio_iov->iov_op != NULL) (*(uiop->uio_iov->iov_op)) (mbufcp, uiocp, xfer); else #endif if (uiop->uio_segflg == UIO_SYSSPACE) NFSBCOPY(mbufcp, uiocp, xfer); else copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer); left -= xfer; len -= xfer; mbufcp += xfer; uiocp += xfer; uiop->uio_offset += xfer; uiop->uio_resid -= xfer; } if (uiop->uio_iov->iov_len <= siz) { uiop->uio_iovcnt--; uiop->uio_iov++; } else { uiop->uio_iov->iov_base = (void *) ((char *)uiop->uio_iov->iov_base + uiosiz); uiop->uio_iov->iov_len -= uiosiz; } siz -= uiosiz; } nd->nd_dpos = mbufcp; nd->nd_md = mp; if (rem > 0) { if (len < rem) error = nfsm_advance(nd, rem, len); else nd->nd_dpos += rem; } out: NFSEXITCODE2(error, nd); return (error); }