FreeBSD/sys/fs/nfsserver/nfs_nfsdcache.c
/*
 * Get a cache entry for TCP
 * - key on <xid, nfs version>
 *   (allow multiple entries for a given key)
 */
Get a cache entry for TCP
- key on 
(allow multiple entries for a given key)
Get a cache entry for TCP - key on ( allow multiple entries for a given key )
static int
nfsrc_gettcp(struct nfsrv_descript *nd, struct nfsrvcache *newrp)
{
	struct nfsrvcache *rp, *nextrp;
	int i;
	struct nfsrvcache *hitrp;
	struct nfsrvhashhead *hp, nfsrc_templist;
	int hit, ret = 0;
	struct mtx *mutex;
	mutex = nfsrc_cachemutex(newrp);
	hp = NFSRCHASH(newrp->rc_xid);
	newrp->rc_reqlen = nfsrc_getlenandcksum(nd->nd_mrep, &newrp->rc_cksum);
tryagain:
	mtx_lock(mutex);
	hit = 1;
	LIST_INIT(&nfsrc_templist);
	rp = LIST_FIRST(hp);
	while (rp != LIST_END(hp)) {
		nextrp = LIST_NEXT(rp, rc_hash);
		if (newrp->rc_xid == rp->rc_xid &&
		    (!(rp->rc_flag & RC_INPROG) ||
		     ((newrp->rc_flag & RC_SAMETCPCONN) &&
		      newrp->rc_sockref == rp->rc_sockref)) &&
		    (newrp->rc_flag & rp->rc_flag & RC_NFSVERS) &&
		    newrp->rc_proc == rp->rc_proc &&
		    ((newrp->rc_flag & RC_NFSV4) &&
		     newrp->rc_sockref != rp->rc_sockref &&
		     newrp->rc_cachetime >= rp->rc_cachetime)
		    && newrp->rc_reqlen == rp->rc_reqlen &&
		    newrp->rc_cksum == rp->rc_cksum) {
			LIST_REMOVE(rp, rc_hash);
			LIST_INSERT_HEAD(&nfsrc_templist, rp, rc_hash);
		}
		rp = nextrp;
	}
	i = 0;
	LIST_FOREACH(rp, &nfsrc_templist, rc_hash) {
		i++;
		if (rp->rc_refcnt > 0) {
			hit = 0;
			break;
		}
	}
	if (i != 1)
		hit = 0;
	hitrp = rp = LIST_FIRST(&nfsrc_templist);
	while (rp != LIST_END(&nfsrc_templist)) {
		nextrp = LIST_NEXT(rp, rc_hash);
		LIST_REMOVE(rp, rc_hash);
		LIST_INSERT_HEAD(hp, rp, rc_hash);
		rp = nextrp;
	}
	if (LIST_FIRST(&nfsrc_templist) != LIST_END(&nfsrc_templist))
		panic("nfs gettcp cache templist");
	if (hit) {
		rp = hitrp;
		if ((rp->rc_flag & RC_LOCKED) != 0) {
			rp->rc_flag |= RC_WANTED;
			(void)mtx_sleep(rp, mutex, (PZERO - 1) | PDROP,
			    "nfsrc", 10 * hz);
			goto tryagain;
		}
		if (rp->rc_flag == 0)
			panic("nfs tcp cache0");
		rp->rc_flag |= RC_LOCKED;
		if (rp->rc_flag & RC_INPROG) {
			newnfsstats.srvcache_inproghits++;
			mtx_unlock(mutex);
			if (newrp->rc_sockref == rp->rc_sockref)
				nfsrc_marksametcpconn(rp->rc_sockref);
			ret = RC_DROPIT;
		} else if (rp->rc_flag & RC_REPSTATUS) {
			newnfsstats.srvcache_nonidemdonehits++;
			mtx_unlock(mutex);
			if (newrp->rc_sockref == rp->rc_sockref)
				nfsrc_marksametcpconn(rp->rc_sockref);
			ret = RC_REPLY;
			nfsrvd_rephead(nd);
			*(nd->nd_errp) = rp->rc_status;
			rp->rc_timestamp = NFSD_MONOSEC + nfsrc_tcptimeout;
		} else if (rp->rc_flag & RC_REPMBUF) {
			newnfsstats.srvcache_nonidemdonehits++;
			mtx_unlock(mutex);
			if (newrp->rc_sockref == rp->rc_sockref)
				nfsrc_marksametcpconn(rp->rc_sockref);
			ret = RC_REPLY;
			nd->nd_mreq = m_copym(rp->rc_reply, 0,
				M_COPYALL, M_WAITOK);
			rp->rc_timestamp = NFSD_MONOSEC + nfsrc_tcptimeout;
		} else {
			panic("nfs tcp cache1");
		}
		nfsrc_unlock(rp);
		free((caddr_t)newrp, M_NFSRVCACHE);
		goto out;
	}
	newnfsstats.srvcache_misses++;
	atomic_add_int(&newnfsstats.srvcache_size, 1);
	newrp->rc_cachetime = NFSD_MONOSEC;
	newrp->rc_flag |= RC_INPROG;
	LIST_INSERT_HEAD(hp, newrp, rc_hash);
	mtx_unlock(mutex);
	nd->nd_rp = newrp;
	ret = RC_DOIT;
out:
	NFSEXITCODE2(0, nd);
	return (ret);
}
static int nfsrc_gettcp ( struct nfsrv_descript * nd , struct nfsrvcache * newrp ) { struct nfsrvcache * rp , * nextrp ; int i ; struct nfsrvcache * hitrp ; struct nfsrvhashhead * hp , nfsrc_templist ; int hit , ret = 0 ; struct mtx * mutex ; mutex = nfsrc_cachemutex ( newrp ) ; hp = NFSRCHASH ( newrp -> rc_xid ) ; newrp -> rc_reqlen = nfsrc_getlenandcksum ( nd -> nd_mrep , & newrp -> rc_cksum ) ; tryagain : mtx_lock ( mutex ) ; hit = 1 ; LIST_INIT ( & nfsrc_templist ) ; rp = LIST_FIRST ( hp ) ; while ( rp != LIST_END ( hp ) ) { nextrp = LIST_NEXT ( rp , rc_hash ) ; if ( newrp -> rc_xid == rp -> rc_xid && ( ! ( rp -> rc_flag & RC_INPROG ) || ( ( newrp -> rc_flag & RC_SAMETCPCONN ) && newrp -> rc_sockref == rp -> rc_sockref ) ) && ( newrp -> rc_flag & rp -> rc_flag & RC_NFSVERS ) && newrp -> rc_proc == rp -> rc_proc && ( ( newrp -> rc_flag & RC_NFSV4 ) && newrp -> rc_sockref != rp -> rc_sockref && newrp -> rc_cachetime >= rp -> rc_cachetime ) && newrp -> rc_reqlen == rp -> rc_reqlen && newrp -> rc_cksum == rp -> rc_cksum ) { LIST_REMOVE ( rp , rc_hash ) ; LIST_INSERT_HEAD ( & nfsrc_templist , rp , rc_hash ) ; } rp = nextrp ; } i = 0 ; LIST_FOREACH ( rp , & nfsrc_templist , rc_hash ) { i ++ ; if ( rp -> rc_refcnt > 0 ) { hit = 0 ; break ; } } if ( i != 1 ) hit = 0 ; hitrp = rp = LIST_FIRST ( & nfsrc_templist ) ; while ( rp != LIST_END ( & nfsrc_templist ) ) { nextrp = LIST_NEXT ( rp , rc_hash ) ; LIST_REMOVE ( rp , rc_hash ) ; LIST_INSERT_HEAD ( hp , rp , rc_hash ) ; rp = nextrp ; } if ( LIST_FIRST ( & nfsrc_templist ) != LIST_END ( & nfsrc_templist ) ) panic ( " " ) ; if ( hit ) { rp = hitrp ; if ( ( rp -> rc_flag & RC_LOCKED ) != 0 ) { rp -> rc_flag |= RC_WANTED ; ( void ) mtx_sleep ( rp , mutex , ( PZERO - 1 ) | PDROP , " " , 10 * hz ) ; goto tryagain ; } if ( rp -> rc_flag == 0 ) panic ( " " ) ; rp -> rc_flag |= RC_LOCKED ; if ( rp -> rc_flag & RC_INPROG ) { newnfsstats . srvcache_inproghits ++ ; mtx_unlock ( mutex ) ; if ( newrp -> rc_sockref == rp -> rc_sockref ) nfsrc_marksametcpconn ( rp -> rc_sockref ) ; ret = RC_DROPIT ; } else if ( rp -> rc_flag & RC_REPSTATUS ) { newnfsstats . srvcache_nonidemdonehits ++ ; mtx_unlock ( mutex ) ; if ( newrp -> rc_sockref == rp -> rc_sockref ) nfsrc_marksametcpconn ( rp -> rc_sockref ) ; ret = RC_REPLY ; nfsrvd_rephead ( nd ) ; * ( nd -> nd_errp ) = rp -> rc_status ; rp -> rc_timestamp = NFSD_MONOSEC + nfsrc_tcptimeout ; } else if ( rp -> rc_flag & RC_REPMBUF ) { newnfsstats . srvcache_nonidemdonehits ++ ; mtx_unlock ( mutex ) ; if ( newrp -> rc_sockref == rp -> rc_sockref ) nfsrc_marksametcpconn ( rp -> rc_sockref ) ; ret = RC_REPLY ; nd -> nd_mreq = m_copym ( rp -> rc_reply , 0 , M_COPYALL , M_WAITOK ) ; rp -> rc_timestamp = NFSD_MONOSEC + nfsrc_tcptimeout ; } else { panic ( " " ) ; } nfsrc_unlock ( rp ) ; free ( ( caddr_t ) newrp , M_NFSRVCACHE ) ; goto out ; } newnfsstats . srvcache_misses ++ ; atomic_add_int ( & newnfsstats . srvcache_size , 1 ) ; newrp -> rc_cachetime = NFSD_MONOSEC ; newrp -> rc_flag |= RC_INPROG ; LIST_INSERT_HEAD ( hp , newrp , rc_hash ) ; mtx_unlock ( mutex ) ; nd -> nd_rp = newrp ; ret = RC_DOIT ; out : NFSEXITCODE2 ( 0 , nd ) ; return ( ret ) ; }
Get a cache entry for TCP
 - key on <xid, nfs version>
   (allow multiple entries for a given key)
Get a cache entry for TCP - key on <xid nfs version > ( allow multiple entries for a given key )
/*
	 * Get all the matches and put them on the temp list.
	 */ /*
	 * Now, use nfsrc_templist to decide if there is a match.
	 */ /*
	 * Can be a hit only if one entry left.
	 * Note possible hit entry and put nfsrc_templist back on hash
	 * list.
	 */ /*
			 * V2 only.
			 */ /*
	 * For TCP, multiple entries for a key are allowed, so don't
	 * chain it into the hash table until done.
	 */