|
|
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:
1.1.1.2 ! root 68: extern int nonidempotent[NFS_NPROCS];
! 69:
1.1 root 70: union rhead {
71: union rhead *rh_head[2];
72: struct nfsrvcache *rh_chain[2];
73: } rhead[NFSRCHSZ];
74:
75: static struct nfsrvcache nfsrvcachehead;
76: static struct nfsrvcache nfsrvcache[NFSRVCACHESIZ];
77:
78: #define TRUE 1
79: #define FALSE 0
80:
81:
82: /* True iff the rpc reply is an nfs status ONLY! */
83: static int repliesstatus[NFS_NPROCS] = {
84: FALSE,
85: FALSE,
86: FALSE,
87: FALSE,
88: FALSE,
89: FALSE,
90: FALSE,
91: FALSE,
92: FALSE,
93: FALSE,
94: TRUE,
95: TRUE,
96: TRUE,
97: TRUE,
98: FALSE,
99: TRUE,
100: FALSE,
101: FALSE,
102: };
103:
104: /*
105: * Initialize the server request cache list
106: */
107: nfsrv_initcache()
108: {
109: register int i;
110: register struct nfsrvcache *rp = nfsrvcache;
111: register struct nfsrvcache *hp = &nfsrvcachehead;
112: register union rhead *rh = rhead;
113:
114: for (i = NFSRCHSZ; --i >= 0; rh++) {
115: rh->rh_head[0] = rh;
116: rh->rh_head[1] = rh;
117: }
118: hp->rc_next = hp->rc_prev = hp;
119: for (i = NFSRVCACHESIZ; i-- > 0; ) {
120: rp->rc_state = RC_UNUSED;
121: rp->rc_flag = 0;
122: rp->rc_forw = rp;
123: rp->rc_back = rp;
124: rp->rc_next = hp->rc_next;
125: hp->rc_next->rc_prev = rp;
126: rp->rc_prev = hp;
127: hp->rc_next = rp;
128: rp++;
129: }
130: }
131:
132: /*
133: * Look for the request in the cache
134: * If found then
135: * return action and optionally reply
136: * else
137: * insert it in the cache
138: *
139: * The rules are as follows:
140: * - if in progress, return DROP request
141: * - if completed within DELAY of the current time, return DROP it
142: * - if completed a longer time ago return REPLY if the reply was cached or
143: * return DOIT
144: * Update/add new request at end of lru list
145: */
146: nfsrv_getcache(nam, xid, proc, repp)
147: struct mbuf *nam;
148: u_long xid;
149: int proc;
150: struct mbuf **repp;
151: {
152: register struct nfsrvcache *rp;
153: register union rhead *rh;
154: struct mbuf *mb;
155: caddr_t bpos;
156: int ret;
157:
158: rh = &rhead[NFSRCHASH(xid)];
159: loop:
160: for (rp = rh->rh_chain[0]; rp != (struct nfsrvcache *)rh; rp = rp->rc_forw) {
161: if (xid == rp->rc_xid && proc == rp->rc_proc &&
162: nfs_netaddr_match(nam, &rp->rc_nam)) {
163: if ((rp->rc_flag & RC_LOCKED) != 0) {
164: rp->rc_flag |= RC_WANTED;
165: (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
166: goto loop;
167: }
168: rp->rc_flag |= RC_LOCKED;
169: put_at_head(rp);
170: if (rp->rc_state == RC_UNUSED)
171: panic("nfsrv cache");
172: if (rp->rc_state == RC_INPROG ||
173: (time.tv_sec - rp->rc_timestamp) < RC_DELAY) {
174: nfsstats.srvcache_inproghits++;
175: ret = RC_DROPIT;
176: } else if (rp->rc_flag & RC_REPSTATUS) {
177: nfsstats.srvcache_idemdonehits++;
178: nfs_rephead(0, xid, rp->rc_status, repp, &mb,
179: &bpos);
180: rp->rc_timestamp = time.tv_sec;
181: ret = RC_REPLY;
182: } else if (rp->rc_flag & RC_REPMBUF) {
183: nfsstats.srvcache_idemdonehits++;
184: *repp = m_copym(rp->rc_reply, 0, M_COPYALL,
185: M_WAIT);
186: rp->rc_timestamp = time.tv_sec;
187: ret = RC_REPLY;
188: } else {
189: nfsstats.srvcache_nonidemdonehits++;
190: rp->rc_state = RC_INPROG;
191: ret = RC_DOIT;
192: }
193: rp->rc_flag &= ~RC_LOCKED;
194: if (rp->rc_flag & RC_WANTED) {
195: rp->rc_flag &= ~RC_WANTED;
196: wakeup((caddr_t)rp);
197: }
198: return (ret);
199: }
200: }
201: nfsstats.srvcache_misses++;
202: rp = nfsrvcachehead.rc_prev;
203: while ((rp->rc_flag & RC_LOCKED) != 0) {
204: rp->rc_flag |= RC_WANTED;
205: (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
206: }
207: remque(rp);
208: put_at_head(rp);
209: if (rp->rc_flag & RC_REPMBUF)
210: mb = rp->rc_reply;
211: else
212: mb = (struct mbuf *)0;
213: rp->rc_flag = 0;
214: rp->rc_state = RC_INPROG;
215: rp->rc_xid = xid;
216: bcopy((caddr_t)nam, (caddr_t)&rp->rc_nam, sizeof (struct mbuf));
217: rp->rc_proc = proc;
218: insque(rp, rh);
219: if (mb)
220: m_freem(mb);
221: return (RC_DOIT);
222: }
223:
224: /*
225: * Update a request cache entry after the rpc has been done
226: */
227: nfsrv_updatecache(nam, xid, proc, repvalid, repstat, repmbuf)
228: struct mbuf *nam;
229: u_long xid;
230: int proc;
231: int repvalid;
232: int repstat;
233: struct mbuf *repmbuf;
234: {
235: register struct nfsrvcache *rp;
236: register union rhead *rh;
237:
238: rh = &rhead[NFSRCHASH(xid)];
239: loop:
240: for (rp = rh->rh_chain[0]; rp != (struct nfsrvcache *)rh; rp = rp->rc_forw) {
241: if (xid == rp->rc_xid && proc == rp->rc_proc &&
242: nfs_netaddr_match(nam, &rp->rc_nam)) {
243: if ((rp->rc_flag & RC_LOCKED) != 0) {
244: rp->rc_flag |= RC_WANTED;
245: (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
246: goto loop;
247: }
248: rp->rc_flag |= RC_LOCKED;
249: rp->rc_state = RC_DONE;
250: /*
251: * If we have a valid reply update status and save
252: * the reply for non-idempotent rpc's.
253: * Otherwise invalidate entry by setting the timestamp
254: * to nil.
255: */
256: if (repvalid) {
257: rp->rc_timestamp = time.tv_sec;
258: if (nonidempotent[proc]) {
259: if (repliesstatus[proc]) {
260: rp->rc_status = repstat;
261: rp->rc_flag |= RC_REPSTATUS;
262: } else {
263: rp->rc_reply = m_copym(repmbuf,
264: 0, M_COPYALL, M_WAIT);
265: rp->rc_flag |= RC_REPMBUF;
266: }
267: }
268: } else {
269: rp->rc_timestamp = 0;
270: }
271: rp->rc_flag &= ~RC_LOCKED;
272: if (rp->rc_flag & RC_WANTED) {
273: rp->rc_flag &= ~RC_WANTED;
274: wakeup((caddr_t)rp);
275: }
276: return;
277: }
278: }
279: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.