1*b8817e4aScegger /* $NetBSD: nfs_srvcache.c,v 1.45 2009/03/15 17:20:10 cegger Exp $ */
2fccfa11aScgd
361f28255Scgd /*
4cde1d475Smycroft * Copyright (c) 1989, 1993
5cde1d475Smycroft * The Regents of the University of California. All rights reserved.
661f28255Scgd *
761f28255Scgd * This code is derived from software contributed to Berkeley by
861f28255Scgd * Rick Macklem at The University of Guelph.
961f28255Scgd *
1061f28255Scgd * Redistribution and use in source and binary forms, with or without
1161f28255Scgd * modification, are permitted provided that the following conditions
1261f28255Scgd * are met:
1361f28255Scgd * 1. Redistributions of source code must retain the above copyright
1461f28255Scgd * notice, this list of conditions and the following disclaimer.
1561f28255Scgd * 2. Redistributions in binary form must reproduce the above copyright
1661f28255Scgd * notice, this list of conditions and the following disclaimer in the
1761f28255Scgd * documentation and/or other materials provided with the distribution.
18aad01611Sagc * 3. Neither the name of the University nor the names of its contributors
1961f28255Scgd * may be used to endorse or promote products derived from this software
2061f28255Scgd * without specific prior written permission.
2161f28255Scgd *
2261f28255Scgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2361f28255Scgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2461f28255Scgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2561f28255Scgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2661f28255Scgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2761f28255Scgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2861f28255Scgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2961f28255Scgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3061f28255Scgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3161f28255Scgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3261f28255Scgd * SUCH DAMAGE.
3361f28255Scgd *
345ac7df1cSfvdl * @(#)nfs_srvcache.c 8.3 (Berkeley) 3/30/95
3561f28255Scgd */
3661f28255Scgd
3761f28255Scgd /*
3861f28255Scgd * Reference: Chet Juszczak, "Improving the Performance and Correctness
3961f28255Scgd * of an NFS Server", in Proc. Winter 1989 USENIX Conference,
4061f28255Scgd * pages 53-63. San Diego, February 1989.
4161f28255Scgd */
420ffad693Slukem
430ffad693Slukem #include <sys/cdefs.h>
44*b8817e4aScegger __KERNEL_RCSID(0, "$NetBSD: nfs_srvcache.c,v 1.45 2009/03/15 17:20:10 cegger Exp $");
455c0c5dd0Sjonathan
4695b048b5Smycroft #include <sys/param.h>
4795b048b5Smycroft #include <sys/vnode.h>
4805aaff39Syamt #include <sys/condvar.h>
4995b048b5Smycroft #include <sys/mount.h>
5095b048b5Smycroft #include <sys/kernel.h>
5195b048b5Smycroft #include <sys/systm.h>
5213278252Syamt #include <sys/lock.h>
53cde1d475Smycroft #include <sys/proc.h>
548ee3b648Syamt #include <sys/pool.h>
5595b048b5Smycroft #include <sys/mbuf.h>
5605aaff39Syamt #include <sys/mutex.h>
5795b048b5Smycroft #include <sys/socket.h>
5895b048b5Smycroft #include <sys/socketvar.h>
5961f28255Scgd
6095b048b5Smycroft #include <netinet/in.h>
61cde1d475Smycroft #include <nfs/nfsm_subs.h>
62cde1d475Smycroft #include <nfs/rpcv2.h>
635ac7df1cSfvdl #include <nfs/nfsproto.h>
64cde1d475Smycroft #include <nfs/nfs.h>
65cde1d475Smycroft #include <nfs/nfsrvcache.h>
66e4c93ec8Schristos #include <nfs/nfs_var.h>
6761f28255Scgd
685ac7df1cSfvdl extern struct nfsstats nfsstats;
699bd0cc2bSmatt extern const int nfsv2_procid[NFS_NPROCS];
70cde1d475Smycroft long numnfsrvcache, desirednfsrvcache = NFSRVCACHESIZ;
718ee3b648Syamt struct pool nfs_reqcache_pool;
7224e91b07Sglass
737b8734f3Smycroft #define NFSRCHASH(xid) \
747b8734f3Smycroft (&nfsrvhashtbl[((xid) + ((xid) >> 24)) & nfsrvhash])
757b8734f3Smycroft LIST_HEAD(nfsrvhash, nfsrvcache) *nfsrvhashtbl;
767b8734f3Smycroft TAILQ_HEAD(nfsrvlru, nfsrvcache) nfsrvlruhead;
7705aaff39Syamt kmutex_t nfsrv_reqcache_lock;
787b8734f3Smycroft u_long nfsrvhash;
7961f28255Scgd
80cb2e7bafSyamt #if defined(MBUFTRACE)
81cb2e7bafSyamt static struct mowner nfsd_cache_mowner = MOWNER_INIT("nfsd", "cache");
82cb2e7bafSyamt #endif /* defined(MBUFTRACE) */
83cb2e7bafSyamt
84cde1d475Smycroft #define NETFAMILY(rp) \
8592ce8c6aSad (((rp)->rc_flags & RC_INETADDR) ? AF_INET : -1)
86cde1d475Smycroft
8713278252Syamt static struct nfsrvcache *nfsrv_lookupcache(struct nfsrv_descript *nd);
8813278252Syamt static void nfsrv_unlockcache(struct nfsrvcache *rp);
8913278252Syamt
90cde1d475Smycroft /*
91cde1d475Smycroft * Static array that defines which nfs rpc's are nonidempotent
92cde1d475Smycroft */
93522f5698Sjdolecek const int nonidempotent[NFS_NPROCS] = {
94b3667adaSthorpej false, /* NULL */
95b3667adaSthorpej false, /* GETATTR */
96b3667adaSthorpej true, /* SETATTR */
97b3667adaSthorpej false, /* LOOKUP */
98b3667adaSthorpej false, /* ACCESS */
99b3667adaSthorpej false, /* READLINK */
100b3667adaSthorpej false, /* READ */
101b3667adaSthorpej true, /* WRITE */
102b3667adaSthorpej true, /* CREATE */
103b3667adaSthorpej true, /* MKDIR */
104b3667adaSthorpej true, /* SYMLINK */
105b3667adaSthorpej true, /* MKNOD */
106b3667adaSthorpej true, /* REMOVE */
107b3667adaSthorpej true, /* RMDIR */
108b3667adaSthorpej true, /* RENAME */
109b3667adaSthorpej true, /* LINK */
110b3667adaSthorpej false, /* READDIR */
111b3667adaSthorpej false, /* READDIRPLUS */
112b3667adaSthorpej false, /* FSSTAT */
113b3667adaSthorpej false, /* FSINFO */
114b3667adaSthorpej false, /* PATHCONF */
115b3667adaSthorpej false, /* COMMIT */
116b3667adaSthorpej false, /* NOOP */
117cde1d475Smycroft };
11861f28255Scgd
11961f28255Scgd /* True iff the rpc reply is an nfs status ONLY! */
120522f5698Sjdolecek static const int nfsv2_repstat[NFS_NPROCS] = {
121b3667adaSthorpej false, /* NULL */
122b3667adaSthorpej false, /* GETATTR */
123b3667adaSthorpej false, /* SETATTR */
124b3667adaSthorpej false, /* NOOP */
125b3667adaSthorpej false, /* LOOKUP */
126b3667adaSthorpej false, /* READLINK */
127b3667adaSthorpej false, /* READ */
128b3667adaSthorpej false, /* Obsolete WRITECACHE */
129b3667adaSthorpej false, /* WRITE */
130b3667adaSthorpej false, /* CREATE */
131b3667adaSthorpej true, /* REMOVE */
132b3667adaSthorpej true, /* RENAME */
133b3667adaSthorpej true, /* LINK */
134b3667adaSthorpej true, /* SYMLINK */
135b3667adaSthorpej false, /* MKDIR */
136b3667adaSthorpej true, /* RMDIR */
137b3667adaSthorpej false, /* READDIR */
138b3667adaSthorpej false, /* STATFS */
13961f28255Scgd };
14061f28255Scgd
1413be095f6Syamt static void
cleanentry(struct nfsrvcache * rp)1423be095f6Syamt cleanentry(struct nfsrvcache *rp)
1433be095f6Syamt {
1443be095f6Syamt
1451ed3981cSyamt if ((rp->rc_flags & RC_REPMBUF) != 0) {
1463be095f6Syamt m_freem(rp->rc_reply);
1473be095f6Syamt }
1481ed3981cSyamt if ((rp->rc_flags & RC_NAM) != 0) {
1493be095f6Syamt m_free(rp->rc_nam);
1503be095f6Syamt }
1511ed3981cSyamt rp->rc_flags &= ~(RC_REPSTATUS|RC_REPMBUF);
1523be095f6Syamt }
1533be095f6Syamt
15461f28255Scgd /*
15561f28255Scgd * Initialize the server request cache list
15661f28255Scgd */
157e4c93ec8Schristos void
nfsrv_initcache(void)158*b8817e4aScegger nfsrv_initcache(void)
15961f28255Scgd {
16061f28255Scgd
1611ed3981cSyamt mutex_init(&nfsrv_reqcache_lock, MUTEX_DEFAULT, IPL_NONE);
162e071d39cSad nfsrvhashtbl = hashinit(desirednfsrvcache, HASH_LIST, true,
163e071d39cSad &nfsrvhash);
1647b8734f3Smycroft TAILQ_INIT(&nfsrvlruhead);
1658ee3b648Syamt pool_init(&nfs_reqcache_pool, sizeof(struct nfsrvcache), 0, 0, 0,
16659d979c5Sad "nfsreqcachepl", &pool_allocator_nointr, IPL_NONE);
167cb2e7bafSyamt MOWNER_ATTACH(&nfsd_cache_mowner);
16861f28255Scgd }
16961f28255Scgd
17092ce8c6aSad void
nfsrv_finicache(void)171*b8817e4aScegger nfsrv_finicache(void)
17292ce8c6aSad {
17392ce8c6aSad
17492ce8c6aSad nfsrv_cleancache();
17592ce8c6aSad KASSERT(TAILQ_EMPTY(&nfsrvlruhead));
17692ce8c6aSad pool_destroy(&nfs_reqcache_pool);
17792ce8c6aSad hashdone(nfsrvhashtbl, HASH_LIST, nfsrvhash);
17892ce8c6aSad MOWNER_DETACH(&nfsd_cache_mowner);
17992ce8c6aSad mutex_destroy(&nfsrv_reqcache_lock);
18092ce8c6aSad }
18192ce8c6aSad
18261f28255Scgd /*
18313278252Syamt * Lookup a cache and lock it
18413278252Syamt */
18513278252Syamt static struct nfsrvcache *
nfsrv_lookupcache(struct nfsrv_descript * nd)186454af1c0Sdsl nfsrv_lookupcache(struct nfsrv_descript *nd)
18713278252Syamt {
18813278252Syamt struct nfsrvcache *rp;
18913278252Syamt
19005aaff39Syamt KASSERT(mutex_owned(&nfsrv_reqcache_lock));
19113278252Syamt
19213278252Syamt loop:
19313278252Syamt LIST_FOREACH(rp, NFSRCHASH(nd->nd_retxid), rc_hash) {
19413278252Syamt if (nd->nd_retxid == rp->rc_xid &&
19513278252Syamt nd->nd_procnum == rp->rc_proc &&
19613278252Syamt netaddr_match(NETFAMILY(rp), &rp->rc_haddr, nd->nd_nam)) {
1971ed3981cSyamt if ((rp->rc_gflags & RC_G_LOCKED) != 0) {
19805aaff39Syamt cv_wait(&rp->rc_cv, &nfsrv_reqcache_lock);
19913278252Syamt goto loop;
20013278252Syamt }
2011ed3981cSyamt rp->rc_gflags |= RC_G_LOCKED;
20213278252Syamt break;
20313278252Syamt }
20413278252Syamt }
20513278252Syamt
20613278252Syamt return rp;
20713278252Syamt }
20813278252Syamt
20913278252Syamt /*
21013278252Syamt * Unlock a cache
21113278252Syamt */
21213278252Syamt static void
nfsrv_unlockcache(struct nfsrvcache * rp)213454af1c0Sdsl nfsrv_unlockcache(struct nfsrvcache *rp)
21413278252Syamt {
21513278252Syamt
21605aaff39Syamt KASSERT(mutex_owned(&nfsrv_reqcache_lock));
21713278252Syamt
2181ed3981cSyamt KASSERT((rp->rc_gflags & RC_G_LOCKED) != 0);
2191ed3981cSyamt rp->rc_gflags &= ~RC_G_LOCKED;
22005aaff39Syamt cv_broadcast(&rp->rc_cv);
22113278252Syamt }
22213278252Syamt
22313278252Syamt /*
22461f28255Scgd * Look for the request in the cache
22561f28255Scgd * If found then
22661f28255Scgd * return action and optionally reply
22761f28255Scgd * else
22861f28255Scgd * insert it in the cache
22961f28255Scgd *
23061f28255Scgd * The rules are as follows:
23161f28255Scgd * - if in progress, return DROP request
23261f28255Scgd * - if completed within DELAY of the current time, return DROP it
23361f28255Scgd * - if completed a longer time ago return REPLY if the reply was cached or
23461f28255Scgd * return DOIT
23561f28255Scgd * Update/add new request at end of lru list
23661f28255Scgd */
237e4c93ec8Schristos int
nfsrv_getcache(struct nfsrv_descript * nd,struct nfssvc_sock * slp,struct mbuf ** repp)238454af1c0Sdsl nfsrv_getcache(struct nfsrv_descript *nd, struct nfssvc_sock *slp, struct mbuf **repp)
23961f28255Scgd {
2400b47e1b2Syamt struct nfsrvcache *rp, *rpdup;
24161f28255Scgd struct mbuf *mb;
242cde1d475Smycroft struct sockaddr_in *saddr;
24353524e44Schristos char *bpos;
24461f28255Scgd int ret;
24561f28255Scgd
24605aaff39Syamt mutex_enter(&nfsrv_reqcache_lock);
24713278252Syamt rp = nfsrv_lookupcache(nd);
24813278252Syamt if (rp) {
24905aaff39Syamt mutex_exit(&nfsrv_reqcache_lock);
25013278252Syamt found:
251cde1d475Smycroft /* If not at end of LRU chain, move it there */
25213278252Syamt if (TAILQ_NEXT(rp, rc_lru)) { /* racy but ok */
25305aaff39Syamt mutex_enter(&nfsrv_reqcache_lock);
2547b8734f3Smycroft TAILQ_REMOVE(&nfsrvlruhead, rp, rc_lru);
2557b8734f3Smycroft TAILQ_INSERT_TAIL(&nfsrvlruhead, rp, rc_lru);
25605aaff39Syamt mutex_exit(&nfsrv_reqcache_lock);
257cde1d475Smycroft }
25861f28255Scgd if (rp->rc_state == RC_UNUSED)
25961f28255Scgd panic("nfsrv cache");
260cde1d475Smycroft if (rp->rc_state == RC_INPROG) {
26161f28255Scgd nfsstats.srvcache_inproghits++;
26261f28255Scgd ret = RC_DROPIT;
2631ed3981cSyamt } else if (rp->rc_flags & RC_REPSTATUS) {
264cde1d475Smycroft nfsstats.srvcache_nonidemdonehits++;
2655ac7df1cSfvdl nfs_rephead(0, nd, slp, rp->rc_status,
266cde1d475Smycroft 0, (u_quad_t *)0, repp, &mb, &bpos);
26761f28255Scgd ret = RC_REPLY;
2681ed3981cSyamt } else if (rp->rc_flags & RC_REPMBUF) {
269cde1d475Smycroft nfsstats.srvcache_nonidemdonehits++;
27061f28255Scgd *repp = m_copym(rp->rc_reply, 0, M_COPYALL,
27161f28255Scgd M_WAIT);
27261f28255Scgd ret = RC_REPLY;
27361f28255Scgd } else {
274cde1d475Smycroft nfsstats.srvcache_idemdonehits++;
27561f28255Scgd rp->rc_state = RC_INPROG;
27661f28255Scgd ret = RC_DOIT;
27761f28255Scgd }
27805aaff39Syamt mutex_enter(&nfsrv_reqcache_lock);
27913278252Syamt nfsrv_unlockcache(rp);
28005aaff39Syamt mutex_exit(&nfsrv_reqcache_lock);
281a055ad0fSyamt return ret;
28261f28255Scgd }
28361f28255Scgd nfsstats.srvcache_misses++;
284cde1d475Smycroft if (numnfsrvcache < desirednfsrvcache) {
285cde1d475Smycroft numnfsrvcache++;
28605aaff39Syamt mutex_exit(&nfsrv_reqcache_lock);
28713278252Syamt rp = pool_get(&nfs_reqcache_pool, PR_WAITOK);
28813278252Syamt memset(rp, 0, sizeof *rp);
28905aaff39Syamt cv_init(&rp->rc_cv, "nfsdrc");
2901ed3981cSyamt rp->rc_gflags = RC_G_LOCKED;
291cde1d475Smycroft } else {
292a14f4443Syamt rp = TAILQ_FIRST(&nfsrvlruhead);
2931ed3981cSyamt while ((rp->rc_gflags & RC_G_LOCKED) != 0) {
29405aaff39Syamt cv_wait(&rp->rc_cv, &nfsrv_reqcache_lock);
295a14f4443Syamt rp = TAILQ_FIRST(&nfsrvlruhead);
29661f28255Scgd }
2971ed3981cSyamt rp->rc_gflags |= RC_G_LOCKED;
2987b8734f3Smycroft LIST_REMOVE(rp, rc_hash);
2997b8734f3Smycroft TAILQ_REMOVE(&nfsrvlruhead, rp, rc_lru);
30005aaff39Syamt mutex_exit(&nfsrv_reqcache_lock);
3013be095f6Syamt cleanentry(rp);
3021ed3981cSyamt rp->rc_flags = 0;
303cde1d475Smycroft }
30461f28255Scgd rp->rc_state = RC_INPROG;
305cde1d475Smycroft rp->rc_xid = nd->nd_retxid;
3065ac7df1cSfvdl saddr = mtod(nd->nd_nam, struct sockaddr_in *);
307cde1d475Smycroft switch (saddr->sin_family) {
308cde1d475Smycroft case AF_INET:
3091ed3981cSyamt rp->rc_flags |= RC_INETADDR;
310cde1d475Smycroft rp->rc_inetaddr = saddr->sin_addr.s_addr;
311cde1d475Smycroft break;
312cde1d475Smycroft default:
3131ed3981cSyamt rp->rc_flags |= RC_NAM;
3145ac7df1cSfvdl rp->rc_nam = m_copym(nd->nd_nam, 0, M_COPYALL, M_WAIT);
315cb2e7bafSyamt m_claimm(rp->rc_nam, &nfsd_cache_mowner);
316cde1d475Smycroft break;
317cde1d475Smycroft };
318cde1d475Smycroft rp->rc_proc = nd->nd_procnum;
31905aaff39Syamt mutex_enter(&nfsrv_reqcache_lock);
3200b47e1b2Syamt rpdup = nfsrv_lookupcache(nd);
3210b47e1b2Syamt if (rpdup != NULL) {
32213278252Syamt /*
32313278252Syamt * other thread made duplicate cache entry.
32413278252Syamt */
3251ed3981cSyamt KASSERT(numnfsrvcache > 0);
3261ed3981cSyamt numnfsrvcache--;
32705aaff39Syamt mutex_exit(&nfsrv_reqcache_lock);
3281ed3981cSyamt cleanentry(rp);
32905aaff39Syamt cv_destroy(&rp->rc_cv);
33013278252Syamt pool_put(&nfs_reqcache_pool, rp);
3310b47e1b2Syamt rp = rpdup;
33213278252Syamt goto found;
333cde1d475Smycroft }
33413278252Syamt TAILQ_INSERT_TAIL(&nfsrvlruhead, rp, rc_lru);
33513278252Syamt LIST_INSERT_HEAD(NFSRCHASH(nd->nd_retxid), rp, rc_hash);
33613278252Syamt nfsrv_unlockcache(rp);
33705aaff39Syamt mutex_exit(&nfsrv_reqcache_lock);
338a055ad0fSyamt return RC_DOIT;
33961f28255Scgd }
34061f28255Scgd
34161f28255Scgd /*
34261f28255Scgd * Update a request cache entry after the rpc has been done
34361f28255Scgd */
344cde1d475Smycroft void
nfsrv_updatecache(struct nfsrv_descript * nd,int repvalid,struct mbuf * repmbuf)345454af1c0Sdsl nfsrv_updatecache(struct nfsrv_descript *nd, int repvalid, struct mbuf *repmbuf)
34661f28255Scgd {
3478529438fSaugustss struct nfsrvcache *rp;
34861f28255Scgd
34905aaff39Syamt mutex_enter(&nfsrv_reqcache_lock);
35013278252Syamt rp = nfsrv_lookupcache(nd);
35105aaff39Syamt mutex_exit(&nfsrv_reqcache_lock);
35213278252Syamt if (rp) {
3533be095f6Syamt cleanentry(rp);
35461f28255Scgd rp->rc_state = RC_DONE;
35561f28255Scgd /*
35661f28255Scgd * If we have a valid reply update status and save
35761f28255Scgd * the reply for non-idempotent rpc's.
35861f28255Scgd */
359cde1d475Smycroft if (repvalid && nonidempotent[nd->nd_procnum]) {
3605ac7df1cSfvdl if ((nd->nd_flag & ND_NFSV3) == 0 &&
3615ac7df1cSfvdl nfsv2_repstat[nfsv2_procid[nd->nd_procnum]]) {
362cde1d475Smycroft rp->rc_status = nd->nd_repstat;
3631ed3981cSyamt rp->rc_flags |= RC_REPSTATUS;
36461f28255Scgd } else {
36561f28255Scgd rp->rc_reply = m_copym(repmbuf,
36661f28255Scgd 0, M_COPYALL, M_WAIT);
367cb2e7bafSyamt m_claimm(rp->rc_reply, &nfsd_cache_mowner);
3681ed3981cSyamt rp->rc_flags |= RC_REPMBUF;
36961f28255Scgd }
37061f28255Scgd }
37105aaff39Syamt mutex_enter(&nfsrv_reqcache_lock);
37213278252Syamt nfsrv_unlockcache(rp);
37305aaff39Syamt mutex_exit(&nfsrv_reqcache_lock);
37461f28255Scgd }
37561f28255Scgd }
376cde1d475Smycroft
377cde1d475Smycroft /*
378cde1d475Smycroft * Clean out the cache. Called when the last nfsd terminates.
379cde1d475Smycroft */
380cde1d475Smycroft void
nfsrv_cleancache(void)381*b8817e4aScegger nfsrv_cleancache(void)
382cde1d475Smycroft {
3831ed3981cSyamt struct nfsrvcache *rp;
384cde1d475Smycroft
38505aaff39Syamt mutex_enter(&nfsrv_reqcache_lock);
3861ed3981cSyamt while ((rp = TAILQ_FIRST(&nfsrvlruhead)) != NULL) {
3871ed3981cSyamt KASSERT((rp->rc_gflags & RC_G_LOCKED) == 0);
3887b8734f3Smycroft LIST_REMOVE(rp, rc_hash);
3897b8734f3Smycroft TAILQ_REMOVE(&nfsrvlruhead, rp, rc_lru);
3901ed3981cSyamt KASSERT(numnfsrvcache > 0);
3911ed3981cSyamt numnfsrvcache--;
3921ed3981cSyamt mutex_exit(&nfsrv_reqcache_lock);
3933be095f6Syamt cleanentry(rp);
39405aaff39Syamt cv_destroy(&rp->rc_cv);
3958ee3b648Syamt pool_put(&nfs_reqcache_pool, rp);
3961ed3981cSyamt mutex_enter(&nfsrv_reqcache_lock);
397cde1d475Smycroft }
3981ed3981cSyamt KASSERT(numnfsrvcache == 0);
39905aaff39Syamt mutex_exit(&nfsrv_reqcache_lock);
400cde1d475Smycroft }
401