xref: /xnu-10002.61.3/bsd/nfs/nfs_srvcache.c (revision 0f4c859e951fba394238ab619495c4e1d54d0f34)
1*0f4c859eSApple OSS Distributions /*
2*0f4c859eSApple OSS Distributions  * Copyright (c) 2000-2010 Apple Inc. All rights reserved.
3*0f4c859eSApple OSS Distributions  *
4*0f4c859eSApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*0f4c859eSApple OSS Distributions  *
6*0f4c859eSApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*0f4c859eSApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*0f4c859eSApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*0f4c859eSApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10*0f4c859eSApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11*0f4c859eSApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12*0f4c859eSApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13*0f4c859eSApple OSS Distributions  * terms of an Apple operating system software license agreement.
14*0f4c859eSApple OSS Distributions  *
15*0f4c859eSApple OSS Distributions  * Please obtain a copy of the License at
16*0f4c859eSApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*0f4c859eSApple OSS Distributions  *
18*0f4c859eSApple OSS Distributions  * The Original Code and all software distributed under the License are
19*0f4c859eSApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*0f4c859eSApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*0f4c859eSApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*0f4c859eSApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*0f4c859eSApple OSS Distributions  * Please see the License for the specific language governing rights and
24*0f4c859eSApple OSS Distributions  * limitations under the License.
25*0f4c859eSApple OSS Distributions  *
26*0f4c859eSApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*0f4c859eSApple OSS Distributions  */
28*0f4c859eSApple OSS Distributions /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
29*0f4c859eSApple OSS Distributions /*
30*0f4c859eSApple OSS Distributions  * Copyright (c) 1989, 1993
31*0f4c859eSApple OSS Distributions  *	The Regents of the University of California.  All rights reserved.
32*0f4c859eSApple OSS Distributions  *
33*0f4c859eSApple OSS Distributions  * This code is derived from software contributed to Berkeley by
34*0f4c859eSApple OSS Distributions  * Rick Macklem at The University of Guelph.
35*0f4c859eSApple OSS Distributions  *
36*0f4c859eSApple OSS Distributions  * Redistribution and use in source and binary forms, with or without
37*0f4c859eSApple OSS Distributions  * modification, are permitted provided that the following conditions
38*0f4c859eSApple OSS Distributions  * are met:
39*0f4c859eSApple OSS Distributions  * 1. Redistributions of source code must retain the above copyright
40*0f4c859eSApple OSS Distributions  *    notice, this list of conditions and the following disclaimer.
41*0f4c859eSApple OSS Distributions  * 2. Redistributions in binary form must reproduce the above copyright
42*0f4c859eSApple OSS Distributions  *    notice, this list of conditions and the following disclaimer in the
43*0f4c859eSApple OSS Distributions  *    documentation and/or other materials provided with the distribution.
44*0f4c859eSApple OSS Distributions  * 3. All advertising materials mentioning features or use of this software
45*0f4c859eSApple OSS Distributions  *    must display the following acknowledgement:
46*0f4c859eSApple OSS Distributions  *	This product includes software developed by the University of
47*0f4c859eSApple OSS Distributions  *	California, Berkeley and its contributors.
48*0f4c859eSApple OSS Distributions  * 4. Neither the name of the University nor the names of its contributors
49*0f4c859eSApple OSS Distributions  *    may be used to endorse or promote products derived from this software
50*0f4c859eSApple OSS Distributions  *    without specific prior written permission.
51*0f4c859eSApple OSS Distributions  *
52*0f4c859eSApple OSS Distributions  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53*0f4c859eSApple OSS Distributions  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54*0f4c859eSApple OSS Distributions  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55*0f4c859eSApple OSS Distributions  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56*0f4c859eSApple OSS Distributions  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57*0f4c859eSApple OSS Distributions  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58*0f4c859eSApple OSS Distributions  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59*0f4c859eSApple OSS Distributions  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60*0f4c859eSApple OSS Distributions  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61*0f4c859eSApple OSS Distributions  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62*0f4c859eSApple OSS Distributions  * SUCH DAMAGE.
63*0f4c859eSApple OSS Distributions  *
64*0f4c859eSApple OSS Distributions  *	@(#)nfs_srvcache.c	8.3 (Berkeley) 3/30/95
65*0f4c859eSApple OSS Distributions  * FreeBSD-Id: nfs_srvcache.c,v 1.15 1997/10/12 20:25:46 phk Exp $
66*0f4c859eSApple OSS Distributions  */
67*0f4c859eSApple OSS Distributions 
68*0f4c859eSApple OSS Distributions #include <nfs/nfs_conf.h>
69*0f4c859eSApple OSS Distributions #if CONFIG_NFS_SERVER
70*0f4c859eSApple OSS Distributions 
71*0f4c859eSApple OSS Distributions /*
72*0f4c859eSApple OSS Distributions  * Reference: Chet Juszczak, "Improving the Performance and Correctness
73*0f4c859eSApple OSS Distributions  *		of an NFS Server", in Proc. Winter 1989 USENIX Conference,
74*0f4c859eSApple OSS Distributions  *		pages 53-63. San Diego, February 1989.
75*0f4c859eSApple OSS Distributions  */
76*0f4c859eSApple OSS Distributions #include <sys/param.h>
77*0f4c859eSApple OSS Distributions #include <sys/vnode.h>
78*0f4c859eSApple OSS Distributions #include <sys/mount_internal.h>
79*0f4c859eSApple OSS Distributions #include <sys/kernel.h>
80*0f4c859eSApple OSS Distributions #include <sys/systm.h>
81*0f4c859eSApple OSS Distributions #include <sys/proc.h>
82*0f4c859eSApple OSS Distributions #include <sys/kpi_mbuf.h>
83*0f4c859eSApple OSS Distributions #include <sys/malloc.h>
84*0f4c859eSApple OSS Distributions #include <sys/socket.h>
85*0f4c859eSApple OSS Distributions #include <libkern/OSAtomic.h>
86*0f4c859eSApple OSS Distributions 
87*0f4c859eSApple OSS Distributions #include <netinet/in.h>
88*0f4c859eSApple OSS Distributions #include <nfs/rpcv2.h>
89*0f4c859eSApple OSS Distributions #include <nfs/nfsproto.h>
90*0f4c859eSApple OSS Distributions #include <nfs/nfs.h>
91*0f4c859eSApple OSS Distributions #include <nfs/nfsrvcache.h>
92*0f4c859eSApple OSS Distributions 
93*0f4c859eSApple OSS Distributions extern int nfsv2_procid[NFS_NPROCS];
94*0f4c859eSApple OSS Distributions static int nfsrv_reqcache_count;
95*0f4c859eSApple OSS Distributions int nfsrv_reqcache_size = NFSRVCACHESIZ;
96*0f4c859eSApple OSS Distributions 
97*0f4c859eSApple OSS Distributions #define NFSRCHASH(xid) \
98*0f4c859eSApple OSS Distributions 	(&nfsrv_reqcache_hashtbl[((xid) + ((xid) >> 24)) & nfsrv_reqcache_hash])
99*0f4c859eSApple OSS Distributions static LIST_HEAD(nfsrv_reqcache_hash, nfsrvcache) * nfsrv_reqcache_hashtbl;
100*0f4c859eSApple OSS Distributions static TAILQ_HEAD(nfsrv_reqcache_lru, nfsrvcache) nfsrv_reqcache_lruhead;
101*0f4c859eSApple OSS Distributions static u_long nfsrv_reqcache_hash;
102*0f4c859eSApple OSS Distributions 
103*0f4c859eSApple OSS Distributions static LCK_GRP_DECLARE(nfsrv_reqcache_lck_grp, "nfsrv_reqcache");
104*0f4c859eSApple OSS Distributions static LCK_MTX_DECLARE(nfsrv_reqcache_mutex, &nfsrv_reqcache_lck_grp);
105*0f4c859eSApple OSS Distributions 
106*0f4c859eSApple OSS Distributions /*
107*0f4c859eSApple OSS Distributions  * Static array that defines which nfs rpc's are nonidempotent
108*0f4c859eSApple OSS Distributions  */
109*0f4c859eSApple OSS Distributions static int nonidempotent[NFS_NPROCS] = {
110*0f4c859eSApple OSS Distributions 	FALSE,
111*0f4c859eSApple OSS Distributions 	FALSE,
112*0f4c859eSApple OSS Distributions 	TRUE,
113*0f4c859eSApple OSS Distributions 	FALSE,
114*0f4c859eSApple OSS Distributions 	FALSE,
115*0f4c859eSApple OSS Distributions 	FALSE,
116*0f4c859eSApple OSS Distributions 	FALSE,
117*0f4c859eSApple OSS Distributions 	TRUE,
118*0f4c859eSApple OSS Distributions 	TRUE,
119*0f4c859eSApple OSS Distributions 	TRUE,
120*0f4c859eSApple OSS Distributions 	TRUE,
121*0f4c859eSApple OSS Distributions 	TRUE,
122*0f4c859eSApple OSS Distributions 	TRUE,
123*0f4c859eSApple OSS Distributions 	TRUE,
124*0f4c859eSApple OSS Distributions 	TRUE,
125*0f4c859eSApple OSS Distributions 	TRUE,
126*0f4c859eSApple OSS Distributions 	FALSE,
127*0f4c859eSApple OSS Distributions 	FALSE,
128*0f4c859eSApple OSS Distributions 	FALSE,
129*0f4c859eSApple OSS Distributions 	FALSE,
130*0f4c859eSApple OSS Distributions 	FALSE,
131*0f4c859eSApple OSS Distributions 	FALSE,
132*0f4c859eSApple OSS Distributions 	FALSE,
133*0f4c859eSApple OSS Distributions };
134*0f4c859eSApple OSS Distributions 
135*0f4c859eSApple OSS Distributions /* True iff the rpc reply is an nfs status ONLY! */
136*0f4c859eSApple OSS Distributions static int nfsv2_repstat[NFS_NPROCS] = {
137*0f4c859eSApple OSS Distributions 	FALSE,
138*0f4c859eSApple OSS Distributions 	FALSE,
139*0f4c859eSApple OSS Distributions 	FALSE,
140*0f4c859eSApple OSS Distributions 	FALSE,
141*0f4c859eSApple OSS Distributions 	FALSE,
142*0f4c859eSApple OSS Distributions 	FALSE,
143*0f4c859eSApple OSS Distributions 	FALSE,
144*0f4c859eSApple OSS Distributions 	FALSE,
145*0f4c859eSApple OSS Distributions 	FALSE,
146*0f4c859eSApple OSS Distributions 	FALSE,
147*0f4c859eSApple OSS Distributions 	TRUE,
148*0f4c859eSApple OSS Distributions 	TRUE,
149*0f4c859eSApple OSS Distributions 	TRUE,
150*0f4c859eSApple OSS Distributions 	TRUE,
151*0f4c859eSApple OSS Distributions 	FALSE,
152*0f4c859eSApple OSS Distributions 	TRUE,
153*0f4c859eSApple OSS Distributions 	FALSE,
154*0f4c859eSApple OSS Distributions 	FALSE,
155*0f4c859eSApple OSS Distributions };
156*0f4c859eSApple OSS Distributions 
157*0f4c859eSApple OSS Distributions /*
158*0f4c859eSApple OSS Distributions  * Initialize the server request cache list
159*0f4c859eSApple OSS Distributions  */
160*0f4c859eSApple OSS Distributions void
nfsrv_initcache(void)161*0f4c859eSApple OSS Distributions nfsrv_initcache(void)
162*0f4c859eSApple OSS Distributions {
163*0f4c859eSApple OSS Distributions 	if (nfsrv_reqcache_size <= 0) {
164*0f4c859eSApple OSS Distributions 		return;
165*0f4c859eSApple OSS Distributions 	}
166*0f4c859eSApple OSS Distributions 
167*0f4c859eSApple OSS Distributions 	lck_mtx_lock(&nfsrv_reqcache_mutex);
168*0f4c859eSApple OSS Distributions 	/* init nfs server request cache hash table */
169*0f4c859eSApple OSS Distributions 	nfsrv_reqcache_hashtbl = hashinit(nfsrv_reqcache_size, M_NFSD, &nfsrv_reqcache_hash);
170*0f4c859eSApple OSS Distributions 	TAILQ_INIT(&nfsrv_reqcache_lruhead);
171*0f4c859eSApple OSS Distributions 	lck_mtx_unlock(&nfsrv_reqcache_mutex);
172*0f4c859eSApple OSS Distributions }
173*0f4c859eSApple OSS Distributions 
174*0f4c859eSApple OSS Distributions /*
175*0f4c859eSApple OSS Distributions  * This function compares two net addresses by family and returns TRUE
176*0f4c859eSApple OSS Distributions  * if they are the same host.
177*0f4c859eSApple OSS Distributions  * If there is any doubt, return FALSE.
178*0f4c859eSApple OSS Distributions  * The AF_INET family is handled as a special case so that address mbufs
179*0f4c859eSApple OSS Distributions  * don't need to be saved to store "struct in_addr", which is only 4 bytes.
180*0f4c859eSApple OSS Distributions  * Ditto for AF_INET6 which is only 16 bytes.
181*0f4c859eSApple OSS Distributions  */
182*0f4c859eSApple OSS Distributions static int
netaddr_match(int family,union nethostaddr * haddr,mbuf_t nam)183*0f4c859eSApple OSS Distributions netaddr_match(
184*0f4c859eSApple OSS Distributions 	int family,
185*0f4c859eSApple OSS Distributions 	union nethostaddr *haddr,
186*0f4c859eSApple OSS Distributions 	mbuf_t nam)
187*0f4c859eSApple OSS Distributions {
188*0f4c859eSApple OSS Distributions 	struct sockaddr_in *inetaddr;
189*0f4c859eSApple OSS Distributions 	struct sockaddr_in6 *inet6addr;
190*0f4c859eSApple OSS Distributions 
191*0f4c859eSApple OSS Distributions 	switch (family) {
192*0f4c859eSApple OSS Distributions 	case AF_INET:
193*0f4c859eSApple OSS Distributions 		inetaddr = mbuf_data(nam);
194*0f4c859eSApple OSS Distributions 		if ((inetaddr->sin_family == AF_INET) &&
195*0f4c859eSApple OSS Distributions 		    (inetaddr->sin_addr.s_addr == haddr->had_inetaddr)) {
196*0f4c859eSApple OSS Distributions 			return 1;
197*0f4c859eSApple OSS Distributions 		}
198*0f4c859eSApple OSS Distributions 		break;
199*0f4c859eSApple OSS Distributions 	case AF_INET6:
200*0f4c859eSApple OSS Distributions 		inet6addr = mbuf_data(nam);
201*0f4c859eSApple OSS Distributions 		if ((inet6addr->sin6_family == AF_INET6) &&
202*0f4c859eSApple OSS Distributions 		    !bcmp(&inet6addr->sin6_addr, &haddr->had_inet6addr, sizeof(inet6addr->sin6_addr))) {
203*0f4c859eSApple OSS Distributions 			return 1;
204*0f4c859eSApple OSS Distributions 		}
205*0f4c859eSApple OSS Distributions 		break;
206*0f4c859eSApple OSS Distributions 	}
207*0f4c859eSApple OSS Distributions 	return 0;
208*0f4c859eSApple OSS Distributions }
209*0f4c859eSApple OSS Distributions 
210*0f4c859eSApple OSS Distributions /*
211*0f4c859eSApple OSS Distributions  * Look for the request in the cache
212*0f4c859eSApple OSS Distributions  * If found then
213*0f4c859eSApple OSS Distributions  *    return action and optionally reply
214*0f4c859eSApple OSS Distributions  * else
215*0f4c859eSApple OSS Distributions  *    insert it in the cache
216*0f4c859eSApple OSS Distributions  *
217*0f4c859eSApple OSS Distributions  * The rules are as follows:
218*0f4c859eSApple OSS Distributions  * - if in progress, return DROP request
219*0f4c859eSApple OSS Distributions  * - if completed within DELAY of the current time, return DROP it
220*0f4c859eSApple OSS Distributions  * - if completed a longer time ago return REPLY if the reply was cached or
221*0f4c859eSApple OSS Distributions  *   return DOIT
222*0f4c859eSApple OSS Distributions  * Update/add new request at end of lru list
223*0f4c859eSApple OSS Distributions  */
224*0f4c859eSApple OSS Distributions int
nfsrv_getcache(struct nfsrv_descript * nd,struct nfsrv_sock * slp,mbuf_t * mrepp)225*0f4c859eSApple OSS Distributions nfsrv_getcache(
226*0f4c859eSApple OSS Distributions 	struct nfsrv_descript *nd,
227*0f4c859eSApple OSS Distributions 	struct nfsrv_sock *slp,
228*0f4c859eSApple OSS Distributions 	mbuf_t *mrepp)
229*0f4c859eSApple OSS Distributions {
230*0f4c859eSApple OSS Distributions 	struct nfsrvcache *rp;
231*0f4c859eSApple OSS Distributions 	struct nfsm_chain nmrep;
232*0f4c859eSApple OSS Distributions 	struct sockaddr *saddr;
233*0f4c859eSApple OSS Distributions 	int ret, error;
234*0f4c859eSApple OSS Distributions 
235*0f4c859eSApple OSS Distributions 	/*
236*0f4c859eSApple OSS Distributions 	 * Don't cache recent requests for reliable transport protocols.
237*0f4c859eSApple OSS Distributions 	 * (Maybe we should for the case of a reconnect, but..)
238*0f4c859eSApple OSS Distributions 	 */
239*0f4c859eSApple OSS Distributions 	if (!nd->nd_nam2) {
240*0f4c859eSApple OSS Distributions 		return RC_DOIT;
241*0f4c859eSApple OSS Distributions 	}
242*0f4c859eSApple OSS Distributions 	lck_mtx_lock(&nfsrv_reqcache_mutex);
243*0f4c859eSApple OSS Distributions loop:
244*0f4c859eSApple OSS Distributions 	for (rp = NFSRCHASH(nd->nd_retxid)->lh_first; rp != 0;
245*0f4c859eSApple OSS Distributions 	    rp = rp->rc_hash.le_next) {
246*0f4c859eSApple OSS Distributions 		if (nd->nd_retxid == rp->rc_xid && nd->nd_procnum == rp->rc_proc &&
247*0f4c859eSApple OSS Distributions 		    netaddr_match(rp->rc_family, &rp->rc_haddr, nd->nd_nam)) {
248*0f4c859eSApple OSS Distributions 			if ((rp->rc_flag & RC_LOCKED) != 0) {
249*0f4c859eSApple OSS Distributions 				rp->rc_flag |= RC_WANTED;
250*0f4c859eSApple OSS Distributions 				msleep(rp, &nfsrv_reqcache_mutex, PZERO - 1, "nfsrc", NULL);
251*0f4c859eSApple OSS Distributions 				goto loop;
252*0f4c859eSApple OSS Distributions 			}
253*0f4c859eSApple OSS Distributions 			rp->rc_flag |= RC_LOCKED;
254*0f4c859eSApple OSS Distributions 			/* If not at end of LRU chain, move it there */
255*0f4c859eSApple OSS Distributions 			if (rp->rc_lru.tqe_next) {
256*0f4c859eSApple OSS Distributions 				TAILQ_REMOVE(&nfsrv_reqcache_lruhead, rp, rc_lru);
257*0f4c859eSApple OSS Distributions 				TAILQ_INSERT_TAIL(&nfsrv_reqcache_lruhead, rp, rc_lru);
258*0f4c859eSApple OSS Distributions 			}
259*0f4c859eSApple OSS Distributions 			if (rp->rc_state == RC_UNUSED) {
260*0f4c859eSApple OSS Distributions 				panic("nfsrv cache");
261*0f4c859eSApple OSS Distributions 			}
262*0f4c859eSApple OSS Distributions 			if (rp->rc_state == RC_INPROG) {
263*0f4c859eSApple OSS Distributions 				OSAddAtomic64(1, &nfsrvstats.srvcache_inproghits);
264*0f4c859eSApple OSS Distributions 				ret = RC_DROPIT;
265*0f4c859eSApple OSS Distributions 			} else if (rp->rc_flag & RC_REPSTATUS) {
266*0f4c859eSApple OSS Distributions 				OSAddAtomic64(1, &nfsrvstats.srvcache_nonidemdonehits);
267*0f4c859eSApple OSS Distributions 				nd->nd_repstat = rp->rc_status;
268*0f4c859eSApple OSS Distributions 				error = nfsrv_rephead(nd, slp, &nmrep, 0);
269*0f4c859eSApple OSS Distributions 				if (error) {
270*0f4c859eSApple OSS Distributions 					printf("nfsrv cache: reply alloc failed for nonidem request hit\n");
271*0f4c859eSApple OSS Distributions 					ret = RC_DROPIT;
272*0f4c859eSApple OSS Distributions 					*mrepp = NULL;
273*0f4c859eSApple OSS Distributions 				} else {
274*0f4c859eSApple OSS Distributions 					ret = RC_REPLY;
275*0f4c859eSApple OSS Distributions 					*mrepp = nmrep.nmc_mhead;
276*0f4c859eSApple OSS Distributions 				}
277*0f4c859eSApple OSS Distributions 			} else if (rp->rc_flag & RC_REPMBUF) {
278*0f4c859eSApple OSS Distributions 				OSAddAtomic64(1, &nfsrvstats.srvcache_nonidemdonehits);
279*0f4c859eSApple OSS Distributions 				error = mbuf_copym(rp->rc_reply, 0, MBUF_COPYALL, MBUF_WAITOK, mrepp);
280*0f4c859eSApple OSS Distributions 				if (error) {
281*0f4c859eSApple OSS Distributions 					printf("nfsrv cache: reply copym failed for nonidem request hit\n");
282*0f4c859eSApple OSS Distributions 					ret = RC_DROPIT;
283*0f4c859eSApple OSS Distributions 				} else {
284*0f4c859eSApple OSS Distributions 					ret = RC_REPLY;
285*0f4c859eSApple OSS Distributions 				}
286*0f4c859eSApple OSS Distributions 			} else {
287*0f4c859eSApple OSS Distributions 				OSAddAtomic64(1, &nfsrvstats.srvcache_idemdonehits);
288*0f4c859eSApple OSS Distributions 				rp->rc_state = RC_INPROG;
289*0f4c859eSApple OSS Distributions 				ret = RC_DOIT;
290*0f4c859eSApple OSS Distributions 			}
291*0f4c859eSApple OSS Distributions 			rp->rc_flag &= ~RC_LOCKED;
292*0f4c859eSApple OSS Distributions 			if (rp->rc_flag & RC_WANTED) {
293*0f4c859eSApple OSS Distributions 				rp->rc_flag &= ~RC_WANTED;
294*0f4c859eSApple OSS Distributions 				wakeup(rp);
295*0f4c859eSApple OSS Distributions 			}
296*0f4c859eSApple OSS Distributions 			lck_mtx_unlock(&nfsrv_reqcache_mutex);
297*0f4c859eSApple OSS Distributions 			return ret;
298*0f4c859eSApple OSS Distributions 		}
299*0f4c859eSApple OSS Distributions 	}
300*0f4c859eSApple OSS Distributions 	OSAddAtomic64(1, &nfsrvstats.srvcache_misses);
301*0f4c859eSApple OSS Distributions 	if (nfsrv_reqcache_count < nfsrv_reqcache_size) {
302*0f4c859eSApple OSS Distributions 		/* try to allocate a new entry */
303*0f4c859eSApple OSS Distributions 		rp = kalloc_type(struct nfsrvcache, Z_WAITOK | Z_ZERO | Z_NOFAIL);
304*0f4c859eSApple OSS Distributions 		rp->rc_flag = RC_LOCKED;
305*0f4c859eSApple OSS Distributions 		nfsrv_reqcache_count++;
306*0f4c859eSApple OSS Distributions 	} else {
307*0f4c859eSApple OSS Distributions 		rp = NULL;
308*0f4c859eSApple OSS Distributions 	}
309*0f4c859eSApple OSS Distributions 	if (!rp) {
310*0f4c859eSApple OSS Distributions 		/* try to reuse the least recently used entry */
311*0f4c859eSApple OSS Distributions 		rp = nfsrv_reqcache_lruhead.tqh_first;
312*0f4c859eSApple OSS Distributions 		if (!rp) {
313*0f4c859eSApple OSS Distributions 			/* no entry to reuse? */
314*0f4c859eSApple OSS Distributions 			/* OK, we just won't be able to cache this request */
315*0f4c859eSApple OSS Distributions 			lck_mtx_unlock(&nfsrv_reqcache_mutex);
316*0f4c859eSApple OSS Distributions 			return RC_DOIT;
317*0f4c859eSApple OSS Distributions 		}
318*0f4c859eSApple OSS Distributions 		while ((rp->rc_flag & RC_LOCKED) != 0) {
319*0f4c859eSApple OSS Distributions 			rp->rc_flag |= RC_WANTED;
320*0f4c859eSApple OSS Distributions 			msleep(rp, &nfsrv_reqcache_mutex, PZERO - 1, "nfsrc", NULL);
321*0f4c859eSApple OSS Distributions 			rp = nfsrv_reqcache_lruhead.tqh_first;
322*0f4c859eSApple OSS Distributions 		}
323*0f4c859eSApple OSS Distributions 		rp->rc_flag |= RC_LOCKED;
324*0f4c859eSApple OSS Distributions 		LIST_REMOVE(rp, rc_hash);
325*0f4c859eSApple OSS Distributions 		TAILQ_REMOVE(&nfsrv_reqcache_lruhead, rp, rc_lru);
326*0f4c859eSApple OSS Distributions 		if (rp->rc_flag & RC_REPMBUF) {
327*0f4c859eSApple OSS Distributions 			mbuf_freem(rp->rc_reply);
328*0f4c859eSApple OSS Distributions 		}
329*0f4c859eSApple OSS Distributions 		if (rp->rc_flag & RC_NAM) {
330*0f4c859eSApple OSS Distributions 			mbuf_freem(rp->rc_nam);
331*0f4c859eSApple OSS Distributions 		}
332*0f4c859eSApple OSS Distributions 		rp->rc_flag &= (RC_LOCKED | RC_WANTED);
333*0f4c859eSApple OSS Distributions 	}
334*0f4c859eSApple OSS Distributions 	TAILQ_INSERT_TAIL(&nfsrv_reqcache_lruhead, rp, rc_lru);
335*0f4c859eSApple OSS Distributions 	rp->rc_state = RC_INPROG;
336*0f4c859eSApple OSS Distributions 	rp->rc_xid = nd->nd_retxid;
337*0f4c859eSApple OSS Distributions 	saddr = mbuf_data(nd->nd_nam);
338*0f4c859eSApple OSS Distributions 	rp->rc_family = saddr->sa_family;
339*0f4c859eSApple OSS Distributions 	switch (saddr->sa_family) {
340*0f4c859eSApple OSS Distributions 	case AF_INET:
341*0f4c859eSApple OSS Distributions 		rp->rc_flag |= RC_INETADDR;
342*0f4c859eSApple OSS Distributions 		rp->rc_inetaddr = ((struct sockaddr_in*)saddr)->sin_addr.s_addr;
343*0f4c859eSApple OSS Distributions 		break;
344*0f4c859eSApple OSS Distributions 	case AF_INET6:
345*0f4c859eSApple OSS Distributions 		rp->rc_flag |= RC_INETADDR;
346*0f4c859eSApple OSS Distributions 		rp->rc_inet6addr = ((struct sockaddr_in6*)saddr)->sin6_addr;
347*0f4c859eSApple OSS Distributions 		break;
348*0f4c859eSApple OSS Distributions 	default:
349*0f4c859eSApple OSS Distributions 		error = mbuf_copym(nd->nd_nam, 0, MBUF_COPYALL, MBUF_WAITOK, &rp->rc_nam);
350*0f4c859eSApple OSS Distributions 		if (error) {
351*0f4c859eSApple OSS Distributions 			printf("nfsrv cache: nam copym failed\n");
352*0f4c859eSApple OSS Distributions 		} else {
353*0f4c859eSApple OSS Distributions 			rp->rc_flag |= RC_NAM;
354*0f4c859eSApple OSS Distributions 		}
355*0f4c859eSApple OSS Distributions 		break;
356*0f4c859eSApple OSS Distributions 	}
357*0f4c859eSApple OSS Distributions 	;
358*0f4c859eSApple OSS Distributions 	rp->rc_proc = nd->nd_procnum;
359*0f4c859eSApple OSS Distributions 	LIST_INSERT_HEAD(NFSRCHASH(nd->nd_retxid), rp, rc_hash);
360*0f4c859eSApple OSS Distributions 	rp->rc_flag &= ~RC_LOCKED;
361*0f4c859eSApple OSS Distributions 	if (rp->rc_flag & RC_WANTED) {
362*0f4c859eSApple OSS Distributions 		rp->rc_flag &= ~RC_WANTED;
363*0f4c859eSApple OSS Distributions 		wakeup(rp);
364*0f4c859eSApple OSS Distributions 	}
365*0f4c859eSApple OSS Distributions 	lck_mtx_unlock(&nfsrv_reqcache_mutex);
366*0f4c859eSApple OSS Distributions 	return RC_DOIT;
367*0f4c859eSApple OSS Distributions }
368*0f4c859eSApple OSS Distributions 
369*0f4c859eSApple OSS Distributions /*
370*0f4c859eSApple OSS Distributions  * Update a request cache entry after the rpc has been done
371*0f4c859eSApple OSS Distributions  */
372*0f4c859eSApple OSS Distributions void
nfsrv_updatecache(struct nfsrv_descript * nd,int repvalid,mbuf_t repmbuf)373*0f4c859eSApple OSS Distributions nfsrv_updatecache(
374*0f4c859eSApple OSS Distributions 	struct nfsrv_descript *nd,
375*0f4c859eSApple OSS Distributions 	int repvalid,
376*0f4c859eSApple OSS Distributions 	mbuf_t repmbuf)
377*0f4c859eSApple OSS Distributions {
378*0f4c859eSApple OSS Distributions 	struct nfsrvcache *rp;
379*0f4c859eSApple OSS Distributions 	int error;
380*0f4c859eSApple OSS Distributions 
381*0f4c859eSApple OSS Distributions 	if (!nd->nd_nam2) {
382*0f4c859eSApple OSS Distributions 		return;
383*0f4c859eSApple OSS Distributions 	}
384*0f4c859eSApple OSS Distributions 	lck_mtx_lock(&nfsrv_reqcache_mutex);
385*0f4c859eSApple OSS Distributions loop:
386*0f4c859eSApple OSS Distributions 	for (rp = NFSRCHASH(nd->nd_retxid)->lh_first; rp != 0;
387*0f4c859eSApple OSS Distributions 	    rp = rp->rc_hash.le_next) {
388*0f4c859eSApple OSS Distributions 		if (nd->nd_retxid == rp->rc_xid && nd->nd_procnum == rp->rc_proc &&
389*0f4c859eSApple OSS Distributions 		    netaddr_match(rp->rc_family, &rp->rc_haddr, nd->nd_nam)) {
390*0f4c859eSApple OSS Distributions 			if ((rp->rc_flag & RC_LOCKED) != 0) {
391*0f4c859eSApple OSS Distributions 				rp->rc_flag |= RC_WANTED;
392*0f4c859eSApple OSS Distributions 				msleep(rp, &nfsrv_reqcache_mutex, PZERO - 1, "nfsrc", NULL);
393*0f4c859eSApple OSS Distributions 				goto loop;
394*0f4c859eSApple OSS Distributions 			}
395*0f4c859eSApple OSS Distributions 			rp->rc_flag |= RC_LOCKED;
396*0f4c859eSApple OSS Distributions 			if (rp->rc_state == RC_DONE) {
397*0f4c859eSApple OSS Distributions 				/*
398*0f4c859eSApple OSS Distributions 				 * This can occur if the cache is too small.
399*0f4c859eSApple OSS Distributions 				 * Retransmits of the same request aren't
400*0f4c859eSApple OSS Distributions 				 * dropped so we may see the operation
401*0f4c859eSApple OSS Distributions 				 * complete more then once.
402*0f4c859eSApple OSS Distributions 				 */
403*0f4c859eSApple OSS Distributions 				if (rp->rc_flag & RC_REPMBUF) {
404*0f4c859eSApple OSS Distributions 					mbuf_freem(rp->rc_reply);
405*0f4c859eSApple OSS Distributions 					rp->rc_flag &= ~RC_REPMBUF;
406*0f4c859eSApple OSS Distributions 				}
407*0f4c859eSApple OSS Distributions 			}
408*0f4c859eSApple OSS Distributions 			rp->rc_state = RC_DONE;
409*0f4c859eSApple OSS Distributions 			/*
410*0f4c859eSApple OSS Distributions 			 * If we have a valid reply update status and save
411*0f4c859eSApple OSS Distributions 			 * the reply for non-idempotent rpc's.
412*0f4c859eSApple OSS Distributions 			 */
413*0f4c859eSApple OSS Distributions 			if (repvalid && nonidempotent[nd->nd_procnum]) {
414*0f4c859eSApple OSS Distributions 				if ((nd->nd_vers == NFS_VER2) &&
415*0f4c859eSApple OSS Distributions 				    nfsv2_repstat[nfsv2_procid[nd->nd_procnum]]) {
416*0f4c859eSApple OSS Distributions 					rp->rc_status = nd->nd_repstat;
417*0f4c859eSApple OSS Distributions 					rp->rc_flag |= RC_REPSTATUS;
418*0f4c859eSApple OSS Distributions 				} else {
419*0f4c859eSApple OSS Distributions 					error = mbuf_copym(repmbuf, 0, MBUF_COPYALL, MBUF_WAITOK, &rp->rc_reply);
420*0f4c859eSApple OSS Distributions 					if (!error) {
421*0f4c859eSApple OSS Distributions 						rp->rc_flag |= RC_REPMBUF;
422*0f4c859eSApple OSS Distributions 					}
423*0f4c859eSApple OSS Distributions 				}
424*0f4c859eSApple OSS Distributions 			}
425*0f4c859eSApple OSS Distributions 			rp->rc_flag &= ~RC_LOCKED;
426*0f4c859eSApple OSS Distributions 			if (rp->rc_flag & RC_WANTED) {
427*0f4c859eSApple OSS Distributions 				rp->rc_flag &= ~RC_WANTED;
428*0f4c859eSApple OSS Distributions 				wakeup(rp);
429*0f4c859eSApple OSS Distributions 			}
430*0f4c859eSApple OSS Distributions 			lck_mtx_unlock(&nfsrv_reqcache_mutex);
431*0f4c859eSApple OSS Distributions 			return;
432*0f4c859eSApple OSS Distributions 		}
433*0f4c859eSApple OSS Distributions 	}
434*0f4c859eSApple OSS Distributions 	lck_mtx_unlock(&nfsrv_reqcache_mutex);
435*0f4c859eSApple OSS Distributions }
436*0f4c859eSApple OSS Distributions 
437*0f4c859eSApple OSS Distributions /*
438*0f4c859eSApple OSS Distributions  * Clean out the cache. Called when the last nfsd terminates.
439*0f4c859eSApple OSS Distributions  */
440*0f4c859eSApple OSS Distributions void
nfsrv_cleancache(void)441*0f4c859eSApple OSS Distributions nfsrv_cleancache(void)
442*0f4c859eSApple OSS Distributions {
443*0f4c859eSApple OSS Distributions 	struct nfsrvcache *rp, *nextrp;
444*0f4c859eSApple OSS Distributions 
445*0f4c859eSApple OSS Distributions 	lck_mtx_lock(&nfsrv_reqcache_mutex);
446*0f4c859eSApple OSS Distributions 	TAILQ_FOREACH_SAFE(rp, &nfsrv_reqcache_lruhead, rc_lru, nextrp) {
447*0f4c859eSApple OSS Distributions 		kfree_type(struct nfsrvcache, rp);
448*0f4c859eSApple OSS Distributions 	}
449*0f4c859eSApple OSS Distributions 	hashdestroy(nfsrv_reqcache_hashtbl, M_NFSD, nfsrv_reqcache_hash);
450*0f4c859eSApple OSS Distributions 	nfsrv_reqcache_hash = 0;
451*0f4c859eSApple OSS Distributions 	nfsrv_reqcache_count = 0;
452*0f4c859eSApple OSS Distributions 	TAILQ_INIT(&nfsrv_reqcache_lruhead);
453*0f4c859eSApple OSS Distributions 	lck_mtx_unlock(&nfsrv_reqcache_mutex);
454*0f4c859eSApple OSS Distributions }
455*0f4c859eSApple OSS Distributions 
456*0f4c859eSApple OSS Distributions #endif /* CONFIG_NFS_SERVER */
457