date and time created 92/07/13 00:43:47 by torek
[unix-history] / usr / src / sys / nfs / nfs_srvcache.c
CommitLineData
95f0eacd
KM
1/*
2 * Copyright (c) 1989 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
7 *
dbf0c423 8 * %sccs.include.redist.c%
95f0eacd 9 *
d615f2fe 10 * @(#)nfs_srvcache.c 7.15 (Berkeley) %G%
b54e05cc
KM
11 */
12
13/*
14 * Reference: Chet Juszczak, "Improving the Performance and Correctness
2c5b44a2
KM
15 * of an NFS Server", in Proc. Winter 1989 USENIX Conference,
16 * pages 53-63. San Diego, February 1989.
95f0eacd 17 */
d615f2fe
KM
18#include <sys/param.h>
19#include <sys/vnode.h>
20#include <sys/mount.h>
21#include <sys/kernel.h>
22#include <sys/systm.h>
23#include <sys/proc.h>
24#include <sys/mbuf.h>
25#include <sys/socket.h>
26#include <sys/socketvar.h>
27#include <netinet/in.h>
2c5b44a2 28#ifdef ISO
d615f2fe 29#include <netiso/iso.h>
2c5b44a2 30#endif
d615f2fe
KM
31#include <nfs/nfsm_subs.h>
32#include <nfs/rpcv2.h>
33#include <nfs/nfsv2.h>
34#include <nfs/nfs.h>
35#include <nfs/nfsrvcache.h>
36#include <nfs/nqnfs.h>
95f0eacd
KM
37
38#if ((NFSRCHSZ&(NFSRCHSZ-1)) == 0)
39#define NFSRCHASH(xid) (((xid)+((xid)>>16))&(NFSRCHSZ-1))
40#else
41#define NFSRCHASH(xid) (((unsigned)((xid)+((xid)>>16)))%NFSRCHSZ)
42#endif
43
44union rhead {
45 union rhead *rh_head[2];
46 struct nfsrvcache *rh_chain[2];
47} rhead[NFSRCHSZ];
48
49static struct nfsrvcache nfsrvcachehead;
50static struct nfsrvcache nfsrvcache[NFSRVCACHESIZ];
51
52#define TRUE 1
53#define FALSE 0
54
2c5b44a2
KM
55#define NETFAMILY(rp) \
56 (((rp)->rc_flag & RC_INETADDR) ? AF_INET : AF_ISO)
57
95f0eacd
KM
58/*
59 * Static array that defines which nfs rpc's are nonidempotent
60 */
cdf8c1c6 61int nonidempotent[NFS_NPROCS] = {
95f0eacd
KM
62 FALSE,
63 FALSE,
64 TRUE,
65 FALSE,
66 FALSE,
67 FALSE,
68 FALSE,
69 FALSE,
70 TRUE,
71 TRUE,
72 TRUE,
73 TRUE,
74 TRUE,
75 TRUE,
76 TRUE,
77 TRUE,
78 FALSE,
79 FALSE,
2c5b44a2
KM
80 FALSE,
81 FALSE,
82 FALSE,
83 FALSE,
95f0eacd
KM
84};
85
86/* True iff the rpc reply is an nfs status ONLY! */
87static int repliesstatus[NFS_NPROCS] = {
88 FALSE,
89 FALSE,
90 FALSE,
91 FALSE,
92 FALSE,
93 FALSE,
94 FALSE,
95 FALSE,
96 FALSE,
97 FALSE,
98 TRUE,
99 TRUE,
100 TRUE,
101 TRUE,
102 FALSE,
103 TRUE,
104 FALSE,
105 FALSE,
2c5b44a2
KM
106 FALSE,
107 FALSE,
108 FALSE,
109 FALSE,
95f0eacd
KM
110};
111
112/*
113 * Initialize the server request cache list
114 */
115nfsrv_initcache()
116{
117 register int i;
118 register struct nfsrvcache *rp = nfsrvcache;
119 register struct nfsrvcache *hp = &nfsrvcachehead;
120 register union rhead *rh = rhead;
121
122 for (i = NFSRCHSZ; --i >= 0; rh++) {
123 rh->rh_head[0] = rh;
124 rh->rh_head[1] = rh;
125 }
126 hp->rc_next = hp->rc_prev = hp;
127 for (i = NFSRVCACHESIZ; i-- > 0; ) {
128 rp->rc_state = RC_UNUSED;
129 rp->rc_flag = 0;
130 rp->rc_forw = rp;
131 rp->rc_back = rp;
132 rp->rc_next = hp->rc_next;
133 hp->rc_next->rc_prev = rp;
134 rp->rc_prev = hp;
135 hp->rc_next = rp;
136 rp++;
137 }
138}
139
140/*
141 * Look for the request in the cache
142 * If found then
143 * return action and optionally reply
144 * else
145 * insert it in the cache
146 *
147 * The rules are as follows:
148 * - if in progress, return DROP request
149 * - if completed within DELAY of the current time, return DROP it
150 * - if completed a longer time ago return REPLY if the reply was cached or
151 * return DOIT
152 * Update/add new request at end of lru list
153 */
2c5b44a2 154nfsrv_getcache(nam, nd, repp)
95f0eacd 155 struct mbuf *nam;
2c5b44a2 156 register struct nfsd *nd;
95f0eacd
KM
157 struct mbuf **repp;
158{
159 register struct nfsrvcache *rp;
160 register union rhead *rh;
95f0eacd 161 struct mbuf *mb;
2c5b44a2 162 struct sockaddr_in *saddr;
95f0eacd
KM
163 caddr_t bpos;
164 int ret;
165
2c5b44a2
KM
166 if (nd->nd_nqlflag != NQL_NOVAL)
167 return (RC_DOIT);
168 rh = &rhead[NFSRCHASH(nd->nd_retxid)];
95f0eacd
KM
169loop:
170 for (rp = rh->rh_chain[0]; rp != (struct nfsrvcache *)rh; rp = rp->rc_forw) {
2c5b44a2 171 if (nd->nd_retxid == rp->rc_xid && nd->nd_procnum == rp->rc_proc &&
4197fd4a 172 netaddr_match(NETFAMILY(rp), &rp->rc_haddr, (union nethostaddr *)0, nam)) {
95f0eacd
KM
173 if ((rp->rc_flag & RC_LOCKED) != 0) {
174 rp->rc_flag |= RC_WANTED;
170bfd05 175 (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
95f0eacd
KM
176 goto loop;
177 }
178 rp->rc_flag |= RC_LOCKED;
2c5b44a2
KM
179 if (rp->rc_prev != &nfsrvcachehead) {
180 rp->rc_next->rc_prev = rp->rc_prev;
181 rp->rc_prev->rc_next = rp->rc_next;
182 rp->rc_next = nfsrvcachehead.rc_next;
183 nfsrvcachehead.rc_next = rp;
184 rp->rc_prev = &nfsrvcachehead;
185 rp->rc_next->rc_prev = rp;
186 }
95f0eacd
KM
187 if (rp->rc_state == RC_UNUSED)
188 panic("nfsrv cache");
189 if (rp->rc_state == RC_INPROG ||
190 (time.tv_sec - rp->rc_timestamp) < RC_DELAY) {
191 nfsstats.srvcache_inproghits++;
192 ret = RC_DROPIT;
193 } else if (rp->rc_flag & RC_REPSTATUS) {
194 nfsstats.srvcache_idemdonehits++;
2c5b44a2
KM
195 nfs_rephead(0, nd, rp->rc_status,
196 0, (u_quad_t *)0, repp, &mb, &bpos);
95f0eacd
KM
197 rp->rc_timestamp = time.tv_sec;
198 ret = RC_REPLY;
199 } else if (rp->rc_flag & RC_REPMBUF) {
200 nfsstats.srvcache_idemdonehits++;
f0f1cbaa 201 *repp = m_copym(rp->rc_reply, 0, M_COPYALL,
95f0eacd
KM
202 M_WAIT);
203 rp->rc_timestamp = time.tv_sec;
204 ret = RC_REPLY;
205 } else {
206 nfsstats.srvcache_nonidemdonehits++;
207 rp->rc_state = RC_INPROG;
208 ret = RC_DOIT;
209 }
210 rp->rc_flag &= ~RC_LOCKED;
211 if (rp->rc_flag & RC_WANTED) {
212 rp->rc_flag &= ~RC_WANTED;
213 wakeup((caddr_t)rp);
214 }
215 return (ret);
216 }
217 }
218 nfsstats.srvcache_misses++;
219 rp = nfsrvcachehead.rc_prev;
220 while ((rp->rc_flag & RC_LOCKED) != 0) {
221 rp->rc_flag |= RC_WANTED;
170bfd05 222 (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
2c5b44a2 223 rp = nfsrvcachehead.rc_prev;
95f0eacd 224 }
2c5b44a2 225 rp->rc_flag |= RC_LOCKED;
95f0eacd 226 remque(rp);
2c5b44a2
KM
227 if (rp->rc_prev != &nfsrvcachehead) {
228 rp->rc_next->rc_prev = rp->rc_prev;
229 rp->rc_prev->rc_next = rp->rc_next;
230 rp->rc_next = nfsrvcachehead.rc_next;
231 nfsrvcachehead.rc_next = rp;
232 rp->rc_prev = &nfsrvcachehead;
233 rp->rc_next->rc_prev = rp;
234 }
95f0eacd 235 if (rp->rc_flag & RC_REPMBUF)
2c5b44a2
KM
236 m_freem(rp->rc_reply);
237 if (rp->rc_flag & RC_NAM)
238 MFREE(rp->rc_nam, mb);
239 rp->rc_flag &= (RC_LOCKED | RC_WANTED);
95f0eacd 240 rp->rc_state = RC_INPROG;
2c5b44a2
KM
241 rp->rc_xid = nd->nd_retxid;
242 saddr = mtod(nam, struct sockaddr_in *);
243 switch (saddr->sin_family) {
244 case AF_INET:
245 rp->rc_flag |= RC_INETADDR;
246 rp->rc_inetaddr = saddr->sin_addr.s_addr;
247 break;
248 case AF_ISO:
249 default:
250 rp->rc_flag |= RC_NAM;
251 rp->rc_nam = m_copym(nam, 0, M_COPYALL, M_WAIT);
252 break;
253 };
254 rp->rc_proc = nd->nd_procnum;
95f0eacd 255 insque(rp, rh);
2c5b44a2
KM
256 rp->rc_flag &= ~RC_LOCKED;
257 if (rp->rc_flag & RC_WANTED) {
258 rp->rc_flag &= ~RC_WANTED;
259 wakeup((caddr_t)rp);
260 }
95f0eacd
KM
261 return (RC_DOIT);
262}
263
264/*
265 * Update a request cache entry after the rpc has been done
266 */
2c5b44a2
KM
267void
268nfsrv_updatecache(nam, nd, repvalid, repmbuf)
95f0eacd 269 struct mbuf *nam;
2c5b44a2 270 register struct nfsd *nd;
f170c5c2 271 int repvalid;
95f0eacd
KM
272 struct mbuf *repmbuf;
273{
274 register struct nfsrvcache *rp;
275 register union rhead *rh;
95f0eacd 276
2c5b44a2
KM
277 if (nd->nd_nqlflag != NQL_NOVAL)
278 return;
279 rh = &rhead[NFSRCHASH(nd->nd_retxid)];
95f0eacd
KM
280loop:
281 for (rp = rh->rh_chain[0]; rp != (struct nfsrvcache *)rh; rp = rp->rc_forw) {
2c5b44a2 282 if (nd->nd_retxid == rp->rc_xid && nd->nd_procnum == rp->rc_proc &&
4197fd4a 283 netaddr_match(NETFAMILY(rp), &rp->rc_haddr, (union nethostaddr *)0, nam)) {
95f0eacd
KM
284 if ((rp->rc_flag & RC_LOCKED) != 0) {
285 rp->rc_flag |= RC_WANTED;
170bfd05 286 (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
95f0eacd
KM
287 goto loop;
288 }
289 rp->rc_flag |= RC_LOCKED;
290 rp->rc_state = RC_DONE;
f170c5c2
KM
291 /*
292 * If we have a valid reply update status and save
f0f1cbaa
KM
293 * the reply for non-idempotent rpc's.
294 * Otherwise invalidate entry by setting the timestamp
295 * to nil.
f170c5c2
KM
296 */
297 if (repvalid) {
298 rp->rc_timestamp = time.tv_sec;
2c5b44a2
KM
299 if (nonidempotent[nd->nd_procnum]) {
300 if (repliesstatus[nd->nd_procnum]) {
301 rp->rc_status = nd->nd_repstat;
f170c5c2
KM
302 rp->rc_flag |= RC_REPSTATUS;
303 } else {
f0f1cbaa 304 rp->rc_reply = m_copym(repmbuf,
f170c5c2
KM
305 0, M_COPYALL, M_WAIT);
306 rp->rc_flag |= RC_REPMBUF;
307 }
95f0eacd 308 }
f170c5c2
KM
309 } else {
310 rp->rc_timestamp = 0;
95f0eacd
KM
311 }
312 rp->rc_flag &= ~RC_LOCKED;
313 if (rp->rc_flag & RC_WANTED) {
314 rp->rc_flag &= ~RC_WANTED;
315 wakeup((caddr_t)rp);
316 }
317 return;
318 }
319 }
320}
2c5b44a2
KM
321
322/*
323 * Clean out the cache. Called when the last nfsd terminates.
324 */
325void
326nfsrv_cleancache()
327{
328 register int i;
329 register struct nfsrvcache *rp = nfsrvcache;
330 register struct nfsrvcache *hp = &nfsrvcachehead;
331 register union rhead *rh = rhead;
332
333 for (i = NFSRCHSZ; --i >= 0; rh++) {
334 rh->rh_head[0] = rh;
335 rh->rh_head[1] = rh;
336 }
337 hp->rc_next = hp->rc_prev = hp;
338 for (i = NFSRVCACHESIZ; i-- > 0; ) {
339 if (rp->rc_flag & RC_REPMBUF)
340 m_freem(rp->rc_reply);
341 if (rp->rc_flag & RC_NAM)
342 m_freem(rp->rc_nam);
343 rp->rc_state = RC_UNUSED;
344 rp->rc_flag = 0;
345 rp->rc_forw = rp;
346 rp->rc_back = rp;
347 rp->rc_next = hp->rc_next;
348 hp->rc_next->rc_prev = rp;
349 rp->rc_prev = hp;
350 hp->rc_next = rp;
351 rp++;
352 }
353}