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