xref: /csrg-svn/sys/nfs/nfs_node.c (revision 38884)
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  *
20  *	@(#)nfs_node.c	7.4 (Berkeley) 08/30/89
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"
29 #include "../ufs/dir.h"
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 
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 
56 #define TRUE	1
57 #define	FALSE	0
58 
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;
79 	NFSTOV(np)->v_type = VNON;
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;
85 		NFSTOV(np)->v_type = VNON;
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)];
119 	for (np = nh->nh_chain[0]; np != (struct nfsnode *)nh; np = np->n_forw) {
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;
145 			VREF(vp);
146 			*npp = np;
147 			return(0);
148 		}
149 
150 	}
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,
168 	 * but that doesn't matter)
169 	 */
170 	remque(np);
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;
182 	insque(np, nh);
183 	bcopy((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH);
184 #ifndef notyet
185 	cache_purge(vp);
186 #endif
187 	np->n_attrstamp = 0;
188 	np->n_sillyrename = (struct sillyrename *)0;
189 	np->n_id = ++nextnfsnodeid;
190 	np->n_size = 0;
191 	np->n_mtime = 0;
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 	}
228 	VREF(vp);
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);
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");
252 			/*
253 			 * Remove the silly file that was rename'd earlier
254 			 */
255 			ndp = &sp->s_namei;
256 			if (!nfs_nget(vp->v_mount, &sp->s_fh, &dnp)) {
257 printf("got the dir\n");
258 				ndp->ni_dvp = NFSTOV(dnp);
259 				nfs_removeit(ndp);
260 				nfs_nput(ndp->ni_dvp);
261 			}
262 			crfree(ndp->ni_cred);
263 			free((caddr_t)sp, M_TEMP);
264 		}
265 		nfs_unlock(vp);
266 		np->n_flag = 0;
267 #ifdef notdef
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);
287 #endif
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 }
425