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