Пример #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);
}
Пример #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);
}