first buffer cache implementation; name cache usage; code cleanups
[unix-history] / usr / src / sys / nfs / nfs_node.c
CommitLineData
a2907882
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 *
8 * Redistribution and use in source and binary forms are permitted
9 * provided that the above copyright notice and this paragraph are
10 * duplicated in all such forms and that any documentation,
11 * advertising materials, and other materials related to such
12 * distribution and use acknowledge that the software was developed
13 * by the University of California, Berkeley. The name of the
14 * University may not be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 *
9238aa59 20 * @(#)nfs_node.c 7.4 (Berkeley) %G%
a2907882
KM
21 */
22
23#include "param.h"
24#include "systm.h"
25#include "user.h"
26#include "proc.h"
27#include "mount.h"
28#include "vnode.h"
36c3043b 29#include "../ufs/dir.h"
a2907882
KM
30#include "namei.h"
31#include "errno.h"
32#include "nfsv2.h"
33#include "nfs.h"
34#include "nfsnode.h"
35#include "nfsmount.h"
36#include "kernel.h"
37#include "malloc.h"
38
39/* The request list head */
40extern struct nfsreq nfsreqh;
41
a2907882
KM
42#define NFSNOHSZ 512
43#if ((NFSNOHSZ&(NFSNOHSZ-1)) == 0)
44#define NFSNOHASH(fhsum) ((fhsum)&(NFSNOHSZ-1))
45#else
46#define NFSNOHASH(fhsum) (((unsigned)(fhsum))%NFSNOHSZ)
47#endif
48
49union nhead { /* inode LRU cache, Chris Maltby */
50 union nhead *nh_head[2];
51 struct nfsnode *nh_chain[2];
52} nhead[NFSNOHSZ];
53
54struct nfsnode *nfreeh, **nfreet;
55
9238aa59
RM
56#define TRUE 1
57#define FALSE 0
58
a2907882
KM
59/*
60 * Initialize hash links for nfsnodes
61 * and build nfsnode free list.
62 */
63nfs_nhinit()
64{
65 register int i;
66 register struct nfsnode *np = nfsnode;
67 register union nhead *nh = nhead;
68
69 for (i = NFSNOHSZ; --i >= 0; nh++) {
70 nh->nh_head[0] = nh;
71 nh->nh_head[1] = nh;
72 }
73 nfreeh = np;
74 nfreet = &np->n_freef;
75 np->n_freeb = &nfreeh;
76 np->n_forw = np;
77 np->n_back = np;
78 NFSTOV(np)->v_data = (qaddr_t)np;
9238aa59 79 NFSTOV(np)->v_type = VNON;
a2907882
KM
80 for (i = nnfsnode; --i > 0; ) {
81 ++np;
82 np->n_forw = np;
83 np->n_back = np;
84 NFSTOV(np)->v_data = (qaddr_t)np;
9238aa59 85 NFSTOV(np)->v_type = VNON;
a2907882
KM
86 *nfreet = np;
87 np->n_freeb = nfreet;
88 nfreet = &np->n_freef;
89 }
90 np->n_freef = NULL;
91}
92
93/*
94 * Look up an vnode/nfsnode by file handle.
95 * Callers must check for mount points!!
96 * In all cases, a pointer to a
97 * nfsnode structure is returned.
98 */
99nfs_nget(mntp, fhp, npp)
100 struct mount *mntp;
101 register nfsv2fh_t *fhp;
102 struct nfsnode **npp;
103{
104 register struct nfsnode *np;
105 register struct vnode *vp;
106 register struct nfsnode *nq;
107 register u_char *fhpp;
108 register u_long fhsum;
109 register int i;
110 union nhead *nh;
111 int error;
112
113 fhpp = &fhp->fh_bytes[0];
114 fhsum = 0;
115 for (i = 0; i < NFSX_FH; i++)
116 fhsum += *fhpp++;
117loop:
118 nh = &nhead[NFSNOHASH(fhsum)];
9238aa59 119 for (np = nh->nh_chain[0]; np != (struct nfsnode *)nh; np = np->n_forw) {
a2907882
KM
120 if (mntp == NFSTOV(np)->v_mount &&
121 !bcmp((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH)) {
122 /*
123 * Following is essentially an inline expanded
124 * copy of ngrab(), expanded inline for speed,
125 * and so that the test for a mounted on nfsnode
126 * can be deferred until after we are sure that
127 * the nfsnode isn't busy.
128 */
129 if ((np->n_flag & NLOCKED) != 0) {
130 np->n_flag |= NWANT;
131 sleep((caddr_t)np, PINOD);
132 goto loop;
133 }
134 vp = NFSTOV(np);
135 if (vp->v_count == 0) { /* nfsno on free list */
136 if (nq = np->n_freef)
137 nq->n_freeb = np->n_freeb;
138 else
139 nfreet = np->n_freeb;
140 *np->n_freeb = nq;
141 np->n_freef = NULL;
142 np->n_freeb = NULL;
143 }
144 np->n_flag |= NLOCKED;
36c3043b 145 VREF(vp);
a2907882
KM
146 *npp = np;
147 return(0);
148 }
149
9238aa59 150 }
a2907882
KM
151 if ((np = nfreeh) == NULL) {
152 tablefull("nfsnode");
153 *npp = 0;
154 return(ENFILE);
155 }
156 vp = NFSTOV(np);
157 if (vp->v_count)
158 panic("free nfsnode isn't");
159 if (nq = np->n_freef)
160 nq->n_freeb = &nfreeh;
161 nfreeh = nq;
162 np->n_freef = NULL;
163 np->n_freeb = NULL;
164 /*
165 * Now to take nfsnode off the hash chain it was on
166 * (initially, or after an nflush, it is on a "hash chain"
167 * consisting entirely of itself, and pointed to by no-one,
9238aa59 168 * but that doesn't matter)
a2907882
KM
169 */
170 remque(np);
9238aa59
RM
171 /*
172 * Flush out any associated bio buffers that might be lying about
173 */
174 if (vp->v_type == VREG && (np->n_flag & NMODIFIED) == 0) {
175 np->n_flag |= NLOCKED;
176 nfs_blkflush(vp, (daddr_t)0, np->n_size, TRUE);
177 }
178 /*
179 * Insert the nfsnode in the hash queue for its new file handle
180 */
181 np->n_flag = NLOCKED;
a2907882
KM
182 insque(np, nh);
183 bcopy((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH);
9238aa59 184#ifndef notyet
a2907882
KM
185 cache_purge(vp);
186#endif
a2907882
KM
187 np->n_attrstamp = 0;
188 np->n_sillyrename = (struct sillyrename *)0;
189 np->n_id = ++nextnfsnodeid;
9238aa59
RM
190 np->n_size = 0;
191 np->n_mtime = 0;
a2907882
KM
192 /*
193 * Initialize the associated vnode
194 */
195 vinit(vp, mntp, VNON, &nfsv2_vnodeops);
196 *npp = np;
197 return (0);
198}
199
200/*
201 * Convert a pointer to an nfsnode into a reference to an nfsnode.
202 *
203 * This is basically the internal piece of nget (after the
204 * nfsnode pointer is located) but without the test for mounted
205 * filesystems. It is caller's responsibility to check that
206 * the nfsnode pointer is valid.
207 */
208nfs_ngrab(np)
209 register struct nfsnode *np;
210{
211 register struct vnode *vp = NFSTOV(np);
212
213 while ((np->n_flag & NLOCKED) != 0) {
214 np->n_flag |= NWANT;
215 sleep((caddr_t)np, PINOD);
216 }
217 if (vp->v_count == 0) { /* ino on free list */
218 register struct nfsnode *nq;
219
220 if (nq = np->n_freef)
221 nq->n_freeb = np->n_freeb;
222 else
223 nfreet = np->n_freeb;
224 *np->n_freeb = nq;
225 np->n_freef = NULL;
226 np->n_freeb = NULL;
227 }
36c3043b 228 VREF(vp);
a2907882
KM
229 np->n_flag |= NLOCKED;
230}
231
232nfs_inactive(vp)
233 struct vnode *vp;
234{
235 register struct nfsnode *np;
236 register struct nameidata *ndp;
237 register struct sillyrename *sp;
238 register struct nfsreq *rep;
239 struct nfsreq *rep2;
240 struct nfsnode *dnp;
241 int s;
242
243 if (vp == NULL)
244 panic("nfs_inactive NULL vp");
245 if (vp->v_count == 0) {
246 np = VTONFS(vp);
9238aa59
RM
247 sp = np->n_sillyrename;
248 np->n_sillyrename = (struct sillyrename *)0;
249 nfs_lock(vp);
250 if (sp) {
251printf("in silltren inact\n");
a2907882
KM
252 /*
253 * Remove the silly file that was rename'd earlier
254 */
a2907882
KM
255 ndp = &sp->s_namei;
256 if (!nfs_nget(vp->v_mount, &sp->s_fh, &dnp)) {
9238aa59 257printf("got the dir\n");
a2907882 258 ndp->ni_dvp = NFSTOV(dnp);
9238aa59 259 nfs_removeit(ndp);
a2907882
KM
260 nfs_nput(ndp->ni_dvp);
261 }
262 crfree(ndp->ni_cred);
263 free((caddr_t)sp, M_TEMP);
a2907882
KM
264 }
265 nfs_unlock(vp);
266 np->n_flag = 0;
9238aa59 267#ifdef notdef
a2907882
KM
268 /*
269 * Scan the request list for any requests left hanging about
270 */
271 s = splnet();
272 rep = nfsreqh.r_next;
273 while (rep) {
274 if (rep->r_vp == vp) {
275 rep->r_prev->r_next = rep2 = rep->r_next;
276 if (rep->r_next != NULL)
277 rep->r_next->r_prev = rep->r_prev;
278 m_freem(rep->r_mreq);
279 if (rep->r_mrep != NULL)
280 m_freem(rep->r_mrep);
281 free((caddr_t)rep, M_NFSREQ);
282 rep = rep2;
283 } else
284 rep = rep->r_next;
285 }
286 splx(s);
9238aa59 287#endif
a2907882
KM
288 /*
289 * Put the nfsnode on the end of the free list.
290 */
291 if (nfreeh) {
292 *nfreet = np;
293 np->n_freeb = nfreet;
294 } else {
295 nfreeh = np;
296 np->n_freeb = &nfreeh;
297 }
298 np->n_freef = NULL;
299 nfreet = &np->n_freef;
300 }
301 return (0);
302}
303
304/*
305 * Remove any nfsnodes in the nfsnode cache belonging to mount.
306 *
307 * There should not be any active ones, return error if any are found
308 * (nb: this is a user error, not a system err).
309 */
310nfs_nflush(mntp)
311 struct mount *mntp;
312{
313 register struct nfsnode *np;
314 register struct vnode *vp;
315
316 for (np = nfsnode; np < nfsnodeNNFSNODE; np++) {
317 vp = NFSTOV(np);
318 if (vp->v_mount == mntp)
319 if (vp->v_count)
320 return (EBUSY);
321 else {
322 remque(np);
323 np->n_forw = np;
324 np->n_back = np;
325 /*
326 * as v_count == 0, the inode was on the free
327 * list already, just leave it there, it will
328 * fall off the bottom eventually. We could
329 * perhaps move it to the head of the free
330 * list, but as umounts are done so
331 * infrequently, we would gain very little,
332 * while making the code bigger.
333 */
334 }
335 }
336 return (0);
337}
338
339/*
340 * Lock an nfsnode
341 */
342nfs_lock(vp)
343 struct vnode *vp;
344{
345 register struct nfsnode *np = VTONFS(vp);
346
347 if (np->n_flag & NLOCKED)
348 printf("pid %d hit locked nfsnode=0x%x\n",
349 u.u_procp->p_pid, np);
350 while (np->n_flag & NLOCKED) {
351 np->n_flag |= NWANT;
352 sleep((caddr_t)np, PINOD);
353 }
354 np->n_flag |= NLOCKED;
355}
356
357/*
358 * Unlock an nfsnode
359 */
360nfs_unlock(vp)
361 struct vnode *vp;
362{
363 register struct nfsnode *np = VTONFS(vp);
364
365 if ((np->n_flag & NLOCKED) == 0) {
366 printf("pid %d unlocking unlocked nfsnode=0x%x ",
367 u.u_procp->p_pid, np);
368 printf("fh0=0x%x fh1=0x%x fh2=0x%x fh3=0x%x fh4=0x%x fh5=0x%x fh6=0x%x fh7=0x%x\n",
369 np->n_fh.fh_bytes[0],np->n_fh.fh_bytes[1],
370 np->n_fh.fh_bytes[2],np->n_fh.fh_bytes[3],
371 np->n_fh.fh_bytes[4],np->n_fh.fh_bytes[5],
372 np->n_fh.fh_bytes[6],np->n_fh.fh_bytes[7]);
373 }
374 np->n_flag &= ~NLOCKED;
375 if (np->n_flag & NWANT) {
376 np->n_flag &= ~NWANT;
377 wakeup((caddr_t)np);
378 }
379}
380
381/*
382 * Unlock and vrele()
383 * since I can't decide if dirs. should be locked, I will check for
384 * the lock and be flexible
385 */
386nfs_nput(vp)
387 struct vnode *vp;
388{
389 register struct nfsnode *np = VTONFS(vp);
390
391 if (np->n_flag & NLOCKED)
392 nfs_unlock(vp);
393 vrele(vp);
394}
395
396nfs_abortop(ndp)
397 register struct nameidata *ndp;
398{
399 register struct nfsnode *np;
400
401 if (ndp->ni_vp != NULL) {
402 np = VTONFS(ndp->ni_vp);
403 if (np->n_flag & NLOCKED)
404 nfs_unlock(ndp->ni_vp);
405 vrele(ndp->ni_vp);
406 }
407 if (ndp->ni_dvp != NULL) {
408 np = VTONFS(ndp->ni_dvp);
409 if (np->n_flag & NLOCKED)
410 nfs_unlock(ndp->ni_dvp);
411 vrele(ndp->ni_dvp);
412 }
413}
414
415/*
416 * This is silly, but if you use a macro and try and use it in a file
417 * that has mbuf.h included, m_data --> m_hdr.mh_data and this is not
418 * a good thing
419 */
420struct nfsmount *vfs_to_nfs(mp)
421 struct mount *mp;
422{
423 return ((struct nfsmount *)mp->m_data);
424}