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