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