|
|
1.1 root 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: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by the University of
19: * California, Berkeley and its contributors.
20: * 4. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: *
36: * @(#)nfs_srvcache.c 7.11 (Berkeley) 4/16/91
37: */
38:
39: /*
40: * Reference: Chet Juszczak, "Improving the Performance and Correctness
41: * of an NFS Server", in Proc. Winter 1989 USENIX Conference,
42: * pages 53-63. San Diego, February 1989.
43: */
44:
45: #include "param.h"
46: #include "namei.h"
47: #include "vnode.h"
48: #include "mount.h"
49: #include "kernel.h"
50: #include "systm.h"
51: #include "mbuf.h"
52: #include "socket.h"
53: #include "socketvar.h"
54:
55: #include "../netinet/in.h"
56:
57: #include "nfsm_subs.h"
58: #include "nfsv2.h"
59: #include "nfsrvcache.h"
60: #include "nfs.h"
61:
62: #if ((NFSRCHSZ&(NFSRCHSZ-1)) == 0)
63: #define NFSRCHASH(xid) (((xid)+((xid)>>16))&(NFSRCHSZ-1))
64: #else
65: #define NFSRCHASH(xid) (((unsigned)((xid)+((xid)>>16)))%NFSRCHSZ)
66: #endif
67:
68: union rhead {
69: union rhead *rh_head[2];
70: struct nfsrvcache *rh_chain[2];
71: } rhead[NFSRCHSZ];
72:
73: static struct nfsrvcache nfsrvcachehead;
74: static struct nfsrvcache nfsrvcache[NFSRVCACHESIZ];
75:
76: #define TRUE 1
77: #define FALSE 0
78:
79: /*
80: * Static array that defines which nfs rpc's are nonidempotent
81: */
82: int nonidempotent[NFS_NPROCS] = {
83: FALSE,
84: FALSE,
85: TRUE,
86: FALSE,
87: FALSE,
88: FALSE,
89: FALSE,
90: FALSE,
91: TRUE,
92: TRUE,
93: TRUE,
94: TRUE,
95: TRUE,
96: TRUE,
97: TRUE,
98: TRUE,
99: FALSE,
100: FALSE,
101: };
102:
103: /* True iff the rpc reply is an nfs status ONLY! */
104: static int repliesstatus[NFS_NPROCS] = {
105: FALSE,
106: FALSE,
107: FALSE,
108: FALSE,
109: FALSE,
110: FALSE,
111: FALSE,
112: FALSE,
113: FALSE,
114: FALSE,
115: TRUE,
116: TRUE,
117: TRUE,
118: TRUE,
119: FALSE,
120: TRUE,
121: FALSE,
122: FALSE,
123: };
124:
125: /*
126: * Initialize the server request cache list
127: */
128: nfsrv_initcache()
129: {
130: register int i;
131: register struct nfsrvcache *rp = nfsrvcache;
132: register struct nfsrvcache *hp = &nfsrvcachehead;
133: register union rhead *rh = rhead;
134:
135: for (i = NFSRCHSZ; --i >= 0; rh++) {
136: rh->rh_head[0] = rh;
137: rh->rh_head[1] = rh;
138: }
139: hp->rc_next = hp->rc_prev = hp;
140: for (i = NFSRVCACHESIZ; i-- > 0; ) {
141: rp->rc_state = RC_UNUSED;
142: rp->rc_flag = 0;
143: rp->rc_forw = rp;
144: rp->rc_back = rp;
145: rp->rc_next = hp->rc_next;
146: hp->rc_next->rc_prev = rp;
147: rp->rc_prev = hp;
148: hp->rc_next = rp;
149: rp++;
150: }
151: }
152:
153: /*
154: * Look for the request in the cache
155: * If found then
156: * return action and optionally reply
157: * else
158: * insert it in the cache
159: *
160: * The rules are as follows:
161: * - if in progress, return DROP request
162: * - if completed within DELAY of the current time, return DROP it
163: * - if completed a longer time ago return REPLY if the reply was cached or
164: * return DOIT
165: * Update/add new request at end of lru list
166: */
167: nfsrv_getcache(nam, xid, proc, repp)
168: struct mbuf *nam;
169: u_long xid;
170: int proc;
171: struct mbuf **repp;
172: {
173: register struct nfsrvcache *rp;
174: register union rhead *rh;
175: struct mbuf *mb;
176: caddr_t bpos;
177: int ret;
178:
179: rh = &rhead[NFSRCHASH(xid)];
180: loop:
181: for (rp = rh->rh_chain[0]; rp != (struct nfsrvcache *)rh; rp = rp->rc_forw) {
182: if (xid == rp->rc_xid && proc == rp->rc_proc &&
183: nfs_netaddr_match(nam, &rp->rc_nam)) {
184: if ((rp->rc_flag & RC_LOCKED) != 0) {
185: rp->rc_flag |= RC_WANTED;
186: (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
187: goto loop;
188: }
189: rp->rc_flag |= RC_LOCKED;
190: put_at_head(rp);
191: if (rp->rc_state == RC_UNUSED)
192: panic("nfsrv cache");
193: if (rp->rc_state == RC_INPROG ||
194: (time.tv_sec - rp->rc_timestamp) < RC_DELAY) {
195: nfsstats.srvcache_inproghits++;
196: ret = RC_DROPIT;
197: } else if (rp->rc_flag & RC_REPSTATUS) {
198: nfsstats.srvcache_idemdonehits++;
199: nfs_rephead(0, xid, rp->rc_status, repp, &mb,
200: &bpos);
201: rp->rc_timestamp = time.tv_sec;
202: ret = RC_REPLY;
203: } else if (rp->rc_flag & RC_REPMBUF) {
204: nfsstats.srvcache_idemdonehits++;
205: *repp = m_copym(rp->rc_reply, 0, M_COPYALL,
206: M_WAIT);
207: rp->rc_timestamp = time.tv_sec;
208: ret = RC_REPLY;
209: } else {
210: nfsstats.srvcache_nonidemdonehits++;
211: rp->rc_state = RC_INPROG;
212: ret = RC_DOIT;
213: }
214: rp->rc_flag &= ~RC_LOCKED;
215: if (rp->rc_flag & RC_WANTED) {
216: rp->rc_flag &= ~RC_WANTED;
217: wakeup((caddr_t)rp);
218: }
219: return (ret);
220: }
221: }
222: nfsstats.srvcache_misses++;
223: rp = nfsrvcachehead.rc_prev;
224: while ((rp->rc_flag & RC_LOCKED) != 0) {
225: rp->rc_flag |= RC_WANTED;
226: (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
227: }
228: remque(rp);
229: put_at_head(rp);
230: if (rp->rc_flag & RC_REPMBUF)
231: mb = rp->rc_reply;
232: else
233: mb = (struct mbuf *)0;
234: rp->rc_flag = 0;
235: rp->rc_state = RC_INPROG;
236: rp->rc_xid = xid;
237: bcopy((caddr_t)nam, (caddr_t)&rp->rc_nam, sizeof (struct mbuf));
238: rp->rc_proc = proc;
239: insque(rp, rh);
240: if (mb)
241: m_freem(mb);
242: return (RC_DOIT);
243: }
244:
245: /*
246: * Update a request cache entry after the rpc has been done
247: */
248: nfsrv_updatecache(nam, xid, proc, repvalid, repstat, repmbuf)
249: struct mbuf *nam;
250: u_long xid;
251: int proc;
252: int repvalid;
253: int repstat;
254: struct mbuf *repmbuf;
255: {
256: register struct nfsrvcache *rp;
257: register union rhead *rh;
258:
259: rh = &rhead[NFSRCHASH(xid)];
260: loop:
261: for (rp = rh->rh_chain[0]; rp != (struct nfsrvcache *)rh; rp = rp->rc_forw) {
262: if (xid == rp->rc_xid && proc == rp->rc_proc &&
263: nfs_netaddr_match(nam, &rp->rc_nam)) {
264: if ((rp->rc_flag & RC_LOCKED) != 0) {
265: rp->rc_flag |= RC_WANTED;
266: (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
267: goto loop;
268: }
269: rp->rc_flag |= RC_LOCKED;
270: rp->rc_state = RC_DONE;
271: /*
272: * If we have a valid reply update status and save
273: * the reply for non-idempotent rpc's.
274: * Otherwise invalidate entry by setting the timestamp
275: * to nil.
276: */
277: if (repvalid) {
278: rp->rc_timestamp = time.tv_sec;
279: if (nonidempotent[proc]) {
280: if (repliesstatus[proc]) {
281: rp->rc_status = repstat;
282: rp->rc_flag |= RC_REPSTATUS;
283: } else {
284: rp->rc_reply = m_copym(repmbuf,
285: 0, M_COPYALL, M_WAIT);
286: rp->rc_flag |= RC_REPMBUF;
287: }
288: }
289: } else {
290: rp->rc_timestamp = 0;
291: }
292: rp->rc_flag &= ~RC_LOCKED;
293: if (rp->rc_flag & RC_WANTED) {
294: rp->rc_flag &= ~RC_WANTED;
295: wakeup((caddr_t)rp);
296: }
297: return;
298: }
299: }
300: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.