Esempio n. 1
0
/*
 * 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);
}
Esempio n. 2
0
/*
 * 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);
}
Esempio n. 3
0
/*
 * 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);
}