Commit | Line | Data |
---|---|---|
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 */ | |
40 | extern 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 | ||
49 | union nhead { /* inode LRU cache, Chris Maltby */ | |
50 | union nhead *nh_head[2]; | |
51 | struct nfsnode *nh_chain[2]; | |
52 | } nhead[NFSNOHSZ]; | |
53 | ||
54 | struct 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 | */ | |
63 | nfs_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 | */ | |
99 | nfs_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++; | |
117 | loop: | |
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 | */ | |
208 | nfs_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 | ||
232 | nfs_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) { | |
251 | printf("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 | 257 | printf("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 | */ | |
310 | nfs_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 | */ | |
342 | nfs_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 | */ | |
360 | nfs_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 | */ | |
386 | nfs_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 | ||
396 | nfs_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 | */ | |
420 | struct nfsmount *vfs_to_nfs(mp) | |
421 | struct mount *mp; | |
422 | { | |
423 | return ((struct nfsmount *)mp->m_data); | |
424 | } |