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