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