xref: /csrg-svn/sys/nfs/nfs_srvcache.c (revision 39742)
1*39742Smckusick /*
2*39742Smckusick  * Copyright (c) 1989 The Regents of the University of California.
3*39742Smckusick  * All rights reserved.
4*39742Smckusick  *
5*39742Smckusick  * This code is derived from software contributed to Berkeley by
6*39742Smckusick  * Rick Macklem at The University of Guelph.
7*39742Smckusick  *
8*39742Smckusick  * Redistribution and use in source and binary forms are permitted
9*39742Smckusick  * provided that the above copyright notice and this paragraph are
10*39742Smckusick  * duplicated in all such forms and that any documentation,
11*39742Smckusick  * advertising materials, and other materials related to such
12*39742Smckusick  * distribution and use acknowledge that the software was developed
13*39742Smckusick  * by the University of California, Berkeley.  The name of the
14*39742Smckusick  * University may not be used to endorse or promote products derived
15*39742Smckusick  * from this software without specific prior written permission.
16*39742Smckusick  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17*39742Smckusick  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18*39742Smckusick  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19*39742Smckusick  *
20*39742Smckusick  *	@(#)nfs_srvcache.c	7.1 (Berkeley) 12/20/89
21*39742Smckusick  */
22*39742Smckusick 
23*39742Smckusick #include "param.h"
24*39742Smckusick #include "user.h"
25*39742Smckusick #include "vnode.h"
26*39742Smckusick #include "mount.h"
27*39742Smckusick #include "kernel.h"
28*39742Smckusick #include "mbuf.h"
29*39742Smckusick #include "socket.h"
30*39742Smckusick #include "socketvar.h"
31*39742Smckusick #include "netinet/in.h"
32*39742Smckusick #include "nfsm_subs.h"
33*39742Smckusick #include "nfsv2.h"
34*39742Smckusick #include "nfsrvcache.h"
35*39742Smckusick #include "nfs.h"
36*39742Smckusick 
37*39742Smckusick #if	((NFSRCHSZ&(NFSRCHSZ-1)) == 0)
38*39742Smckusick #define	NFSRCHASH(xid)		(((xid)+((xid)>>16))&(NFSRCHSZ-1))
39*39742Smckusick #else
40*39742Smckusick #define	NFSRCHASH(xid)		(((unsigned)((xid)+((xid)>>16)))%NFSRCHSZ)
41*39742Smckusick #endif
42*39742Smckusick 
43*39742Smckusick union rhead {
44*39742Smckusick 	union  rhead *rh_head[2];
45*39742Smckusick 	struct nfsrvcache *rh_chain[2];
46*39742Smckusick } rhead[NFSRCHSZ];
47*39742Smckusick 
48*39742Smckusick static struct nfsrvcache nfsrvcachehead;
49*39742Smckusick static struct nfsrvcache nfsrvcache[NFSRVCACHESIZ];
50*39742Smckusick 
51*39742Smckusick #define TRUE	1
52*39742Smckusick #define	FALSE	0
53*39742Smckusick 
54*39742Smckusick /*
55*39742Smckusick  * Static array that defines which nfs rpc's are nonidempotent
56*39742Smckusick  */
57*39742Smckusick static int nonidempotent[NFS_NPROCS] = {
58*39742Smckusick 	FALSE,
59*39742Smckusick 	FALSE,
60*39742Smckusick 	TRUE,
61*39742Smckusick 	FALSE,
62*39742Smckusick 	FALSE,
63*39742Smckusick 	FALSE,
64*39742Smckusick 	FALSE,
65*39742Smckusick 	FALSE,
66*39742Smckusick 	TRUE,
67*39742Smckusick 	TRUE,
68*39742Smckusick 	TRUE,
69*39742Smckusick 	TRUE,
70*39742Smckusick 	TRUE,
71*39742Smckusick 	TRUE,
72*39742Smckusick 	TRUE,
73*39742Smckusick 	TRUE,
74*39742Smckusick 	FALSE,
75*39742Smckusick 	FALSE,
76*39742Smckusick };
77*39742Smckusick 
78*39742Smckusick /* True iff the rpc reply is an nfs status ONLY! */
79*39742Smckusick static int repliesstatus[NFS_NPROCS] = {
80*39742Smckusick 	FALSE,
81*39742Smckusick 	FALSE,
82*39742Smckusick 	FALSE,
83*39742Smckusick 	FALSE,
84*39742Smckusick 	FALSE,
85*39742Smckusick 	FALSE,
86*39742Smckusick 	FALSE,
87*39742Smckusick 	FALSE,
88*39742Smckusick 	FALSE,
89*39742Smckusick 	FALSE,
90*39742Smckusick 	TRUE,
91*39742Smckusick 	TRUE,
92*39742Smckusick 	TRUE,
93*39742Smckusick 	TRUE,
94*39742Smckusick 	FALSE,
95*39742Smckusick 	TRUE,
96*39742Smckusick 	FALSE,
97*39742Smckusick 	FALSE,
98*39742Smckusick };
99*39742Smckusick 
100*39742Smckusick /*
101*39742Smckusick  * Initialize the server request cache list
102*39742Smckusick  */
103*39742Smckusick nfsrv_initcache()
104*39742Smckusick {
105*39742Smckusick 	register int i;
106*39742Smckusick 	register struct nfsrvcache *rp = nfsrvcache;
107*39742Smckusick 	register struct nfsrvcache *hp = &nfsrvcachehead;
108*39742Smckusick 	register union  rhead *rh = rhead;
109*39742Smckusick 
110*39742Smckusick 	for (i = NFSRCHSZ; --i >= 0; rh++) {
111*39742Smckusick 		rh->rh_head[0] = rh;
112*39742Smckusick 		rh->rh_head[1] = rh;
113*39742Smckusick 	}
114*39742Smckusick 	hp->rc_next = hp->rc_prev = hp;
115*39742Smckusick 	for (i = NFSRVCACHESIZ; i-- > 0; ) {
116*39742Smckusick 		rp->rc_state = RC_UNUSED;
117*39742Smckusick 		rp->rc_flag = 0;
118*39742Smckusick 		rp->rc_forw = rp;
119*39742Smckusick 		rp->rc_back = rp;
120*39742Smckusick 		rp->rc_next = hp->rc_next;
121*39742Smckusick 		hp->rc_next->rc_prev = rp;
122*39742Smckusick 		rp->rc_prev = hp;
123*39742Smckusick 		hp->rc_next = rp;
124*39742Smckusick 		rp++;
125*39742Smckusick 	}
126*39742Smckusick }
127*39742Smckusick 
128*39742Smckusick /*
129*39742Smckusick  * Look for the request in the cache
130*39742Smckusick  * If found then
131*39742Smckusick  *    return action and optionally reply
132*39742Smckusick  * else
133*39742Smckusick  *    insert it in the cache
134*39742Smckusick  *
135*39742Smckusick  * The rules are as follows:
136*39742Smckusick  * - if in progress, return DROP request
137*39742Smckusick  * - if completed within DELAY of the current time, return DROP it
138*39742Smckusick  * - if completed a longer time ago return REPLY if the reply was cached or
139*39742Smckusick  *   return DOIT
140*39742Smckusick  * Update/add new request at end of lru list
141*39742Smckusick  */
142*39742Smckusick nfsrv_getcache(nam, xid, proc, repp)
143*39742Smckusick 	struct mbuf *nam;
144*39742Smckusick 	u_long xid;
145*39742Smckusick 	int proc;
146*39742Smckusick 	struct mbuf **repp;
147*39742Smckusick {
148*39742Smckusick 	register struct nfsrvcache *rp;
149*39742Smckusick 	register union  rhead *rh;
150*39742Smckusick 	register u_long saddr;
151*39742Smckusick 	struct mbuf *mb;
152*39742Smckusick 	caddr_t bpos;
153*39742Smckusick 	int ret;
154*39742Smckusick 
155*39742Smckusick 	rh = &rhead[NFSRCHASH(xid)];
156*39742Smckusick 	saddr = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr;
157*39742Smckusick loop:
158*39742Smckusick 	for (rp = rh->rh_chain[0]; rp != (struct nfsrvcache *)rh; rp = rp->rc_forw) {
159*39742Smckusick 		if (xid == rp->rc_xid && saddr == rp->rc_saddr &&
160*39742Smckusick 		    proc == rp->rc_proc) {
161*39742Smckusick 			if ((rp->rc_flag & RC_LOCKED) != 0) {
162*39742Smckusick 				rp->rc_flag |= RC_WANTED;
163*39742Smckusick 				sleep((caddr_t)rp, PZERO-1);
164*39742Smckusick 				goto loop;
165*39742Smckusick 			}
166*39742Smckusick 			rp->rc_flag |= RC_LOCKED;
167*39742Smckusick 			put_at_head(rp);
168*39742Smckusick 			if (rp->rc_state == RC_UNUSED)
169*39742Smckusick 				panic("nfsrv cache");
170*39742Smckusick 			if (rp->rc_state == RC_INPROG ||
171*39742Smckusick 			   (time.tv_sec - rp->rc_timestamp) < RC_DELAY) {
172*39742Smckusick 				nfsstats.srvcache_inproghits++;
173*39742Smckusick 				ret = RC_DROPIT;
174*39742Smckusick 			} else if (rp->rc_flag & RC_REPSTATUS) {
175*39742Smckusick 				nfsstats.srvcache_idemdonehits++;
176*39742Smckusick 				nfs_rephead(0, xid, rp->rc_status, repp, &mb,
177*39742Smckusick 					&bpos);
178*39742Smckusick 				rp->rc_timestamp = time.tv_sec;
179*39742Smckusick 				ret = RC_REPLY;
180*39742Smckusick 			} else if (rp->rc_flag & RC_REPMBUF) {
181*39742Smckusick 				nfsstats.srvcache_idemdonehits++;
182*39742Smckusick 				*repp = NFSMCOPY(rp->rc_reply, 0, M_COPYALL,
183*39742Smckusick 						M_WAIT);
184*39742Smckusick 				rp->rc_timestamp = time.tv_sec;
185*39742Smckusick 				ret = RC_REPLY;
186*39742Smckusick 			} else {
187*39742Smckusick 				nfsstats.srvcache_nonidemdonehits++;
188*39742Smckusick 				rp->rc_state = RC_INPROG;
189*39742Smckusick 				ret = RC_DOIT;
190*39742Smckusick 			}
191*39742Smckusick 			rp->rc_flag &= ~RC_LOCKED;
192*39742Smckusick 			if (rp->rc_flag & RC_WANTED) {
193*39742Smckusick 				rp->rc_flag &= ~RC_WANTED;
194*39742Smckusick 				wakeup((caddr_t)rp);
195*39742Smckusick 			}
196*39742Smckusick 			return (ret);
197*39742Smckusick 		}
198*39742Smckusick 	}
199*39742Smckusick 	nfsstats.srvcache_misses++;
200*39742Smckusick 	rp = nfsrvcachehead.rc_prev;
201*39742Smckusick 	while ((rp->rc_flag & RC_LOCKED) != 0) {
202*39742Smckusick 		rp->rc_flag |= RC_WANTED;
203*39742Smckusick 		sleep((caddr_t)rp, PZERO-1);
204*39742Smckusick 	}
205*39742Smckusick 	remque(rp);
206*39742Smckusick 	put_at_head(rp);
207*39742Smckusick 	if (rp->rc_flag & RC_REPMBUF)
208*39742Smckusick 		mb = rp->rc_reply;
209*39742Smckusick 	else
210*39742Smckusick 		mb = (struct mbuf *)0;
211*39742Smckusick 	rp->rc_flag = 0;
212*39742Smckusick 	rp->rc_state = RC_INPROG;
213*39742Smckusick 	rp->rc_xid = xid;
214*39742Smckusick 	rp->rc_saddr = saddr;
215*39742Smckusick 	rp->rc_proc = proc;
216*39742Smckusick 	insque(rp, rh);
217*39742Smckusick 	if (mb)
218*39742Smckusick 		m_freem(mb);
219*39742Smckusick 	return (RC_DOIT);
220*39742Smckusick }
221*39742Smckusick 
222*39742Smckusick /*
223*39742Smckusick  * Update a request cache entry after the rpc has been done
224*39742Smckusick  */
225*39742Smckusick nfsrv_updatecache(nam, xid, proc, repstat, repmbuf)
226*39742Smckusick 	struct mbuf *nam;
227*39742Smckusick 	u_long xid;
228*39742Smckusick 	int proc;
229*39742Smckusick 	int repstat;
230*39742Smckusick 	struct mbuf *repmbuf;
231*39742Smckusick {
232*39742Smckusick 	register struct nfsrvcache *rp;
233*39742Smckusick 	register union	rhead *rh;
234*39742Smckusick 	register u_long saddr;
235*39742Smckusick 
236*39742Smckusick 	rh = &rhead[NFSRCHASH(xid)];
237*39742Smckusick 	saddr = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr;
238*39742Smckusick loop:
239*39742Smckusick 	for (rp = rh->rh_chain[0]; rp != (struct nfsrvcache *)rh; rp = rp->rc_forw) {
240*39742Smckusick 		if (xid == rp->rc_xid && saddr == rp->rc_saddr &&
241*39742Smckusick 		    proc == rp->rc_proc) {
242*39742Smckusick 			if ((rp->rc_flag & RC_LOCKED) != 0) {
243*39742Smckusick 				rp->rc_flag |= RC_WANTED;
244*39742Smckusick 				sleep((caddr_t)rp, PZERO-1);
245*39742Smckusick 				goto loop;
246*39742Smckusick 			}
247*39742Smckusick 			rp->rc_flag |= RC_LOCKED;
248*39742Smckusick 			rp->rc_state = RC_DONE;
249*39742Smckusick 			rp->rc_timestamp = time.tv_sec;
250*39742Smckusick 			if (nonidempotent[proc]) {
251*39742Smckusick 				if (repliesstatus[proc]) {
252*39742Smckusick 					rp->rc_status = repstat;
253*39742Smckusick 					rp->rc_flag |= RC_REPSTATUS;
254*39742Smckusick 				} else {
255*39742Smckusick 					rp->rc_reply = NFSMCOPY(repmbuf, 0,
256*39742Smckusick 							M_COPYALL, M_WAIT);
257*39742Smckusick 					rp->rc_flag |= RC_REPMBUF;
258*39742Smckusick 				}
259*39742Smckusick 			}
260*39742Smckusick 			rp->rc_flag &= ~RC_LOCKED;
261*39742Smckusick 			if (rp->rc_flag & RC_WANTED) {
262*39742Smckusick 				rp->rc_flag &= ~RC_WANTED;
263*39742Smckusick 				wakeup((caddr_t)rp);
264*39742Smckusick 			}
265*39742Smckusick 			return;
266*39742Smckusick 		}
267*39742Smckusick 	}
268*39742Smckusick }
269