xref: /csrg-svn/sys/nfs/nfs_node.c (revision 39395)
138415Smckusick /*
238415Smckusick  * Copyright (c) 1989 The Regents of the University of California.
338415Smckusick  * All rights reserved.
438415Smckusick  *
538415Smckusick  * This code is derived from software contributed to Berkeley by
638415Smckusick  * Rick Macklem at The University of Guelph.
738415Smckusick  *
838415Smckusick  * Redistribution and use in source and binary forms are permitted
938415Smckusick  * provided that the above copyright notice and this paragraph are
1038415Smckusick  * duplicated in all such forms and that any documentation,
1138415Smckusick  * advertising materials, and other materials related to such
1238415Smckusick  * distribution and use acknowledge that the software was developed
1338415Smckusick  * by the University of California, Berkeley.  The name of the
1438415Smckusick  * University may not be used to endorse or promote products derived
1538415Smckusick  * from this software without specific prior written permission.
1638415Smckusick  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1738415Smckusick  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1838415Smckusick  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1938415Smckusick  *
20*39395Smckusick  *	@(#)nfs_node.c	7.7 (Berkeley) 10/24/89
2138415Smckusick  */
2238415Smckusick 
2338415Smckusick #include "param.h"
2438415Smckusick #include "systm.h"
2538415Smckusick #include "user.h"
2638415Smckusick #include "proc.h"
2738415Smckusick #include "mount.h"
2838415Smckusick #include "vnode.h"
2938425Smckusick #include "../ufs/dir.h"
3038415Smckusick #include "namei.h"
3138415Smckusick #include "errno.h"
3238415Smckusick #include "nfsv2.h"
3338415Smckusick #include "nfs.h"
3438415Smckusick #include "nfsnode.h"
3538415Smckusick #include "nfsmount.h"
3638415Smckusick #include "kernel.h"
3738415Smckusick #include "malloc.h"
3838415Smckusick 
3938415Smckusick /* The request list head */
4038415Smckusick extern struct nfsreq nfsreqh;
4138415Smckusick 
4238415Smckusick #define	NFSNOHSZ	512
4338415Smckusick #if	((NFSNOHSZ&(NFSNOHSZ-1)) == 0)
4438415Smckusick #define	NFSNOHASH(fhsum)	((fhsum)&(NFSNOHSZ-1))
4538415Smckusick #else
4638415Smckusick #define	NFSNOHASH(fhsum)	(((unsigned)(fhsum))%NFSNOHSZ)
4738415Smckusick #endif
4838415Smckusick 
49*39395Smckusick union nhead {
5038415Smckusick 	union  nhead *nh_head[2];
5138415Smckusick 	struct nfsnode *nh_chain[2];
5238415Smckusick } nhead[NFSNOHSZ];
5338415Smckusick 
5438884Smacklem #define TRUE	1
5538884Smacklem #define	FALSE	0
5638884Smacklem 
5738415Smckusick /*
5838415Smckusick  * Initialize hash links for nfsnodes
5938415Smckusick  * and build nfsnode free list.
6038415Smckusick  */
6138415Smckusick nfs_nhinit()
6238415Smckusick {
6338415Smckusick 	register int i;
6438415Smckusick 	register union  nhead *nh = nhead;
6538415Smckusick 
66*39395Smckusick 	if (VN_MAXPRIVATE < sizeof(struct nfsnode))
67*39395Smckusick 		panic("nfs_nhinit: too small");
6838415Smckusick 	for (i = NFSNOHSZ; --i >= 0; nh++) {
6938415Smckusick 		nh->nh_head[0] = nh;
7038415Smckusick 		nh->nh_head[1] = nh;
7138415Smckusick 	}
7238415Smckusick }
7338415Smckusick 
7438415Smckusick /*
75*39395Smckusick  * Look up a vnode/nfsnode by file handle.
7638415Smckusick  * Callers must check for mount points!!
7738415Smckusick  * In all cases, a pointer to a
7838415Smckusick  * nfsnode structure is returned.
7938415Smckusick  */
8038415Smckusick nfs_nget(mntp, fhp, npp)
8138415Smckusick 	struct mount *mntp;
8238415Smckusick 	register nfsv2fh_t *fhp;
8338415Smckusick 	struct nfsnode **npp;
8438415Smckusick {
8538415Smckusick 	register struct nfsnode *np;
8638415Smckusick 	register struct vnode *vp;
8738415Smckusick 	register u_char *fhpp;
8838415Smckusick 	register u_long fhsum;
89*39395Smckusick 	struct vnode *nvp;
90*39395Smckusick 	union nhead *nh;
91*39395Smckusick 	int i, error;
9238415Smckusick 
9338415Smckusick 	fhpp = &fhp->fh_bytes[0];
9438415Smckusick 	fhsum = 0;
9538415Smckusick 	for (i = 0; i < NFSX_FH; i++)
9638415Smckusick 		fhsum += *fhpp++;
9738415Smckusick loop:
9838415Smckusick 	nh = &nhead[NFSNOHASH(fhsum)];
9938884Smacklem 	for (np = nh->nh_chain[0]; np != (struct nfsnode *)nh; np = np->n_forw) {
100*39395Smckusick 		if (mntp != NFSTOV(np)->v_mount ||
101*39395Smckusick 		    bcmp((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH))
102*39395Smckusick 			continue;
103*39395Smckusick 		/*
104*39395Smckusick 		 * Following is essentially an inline expanded
105*39395Smckusick 		 * copy of ngrab(), expanded inline for speed,
106*39395Smckusick 		 * and so that the test for a mounted on nfsnode
107*39395Smckusick 		 * can be deferred until after we are sure that
108*39395Smckusick 		 * the nfsnode isn't busy.
109*39395Smckusick 		 */
110*39395Smckusick 		if ((np->n_flag & NLOCKED) != 0) {
111*39395Smckusick 			np->n_flag |= NWANT;
112*39395Smckusick 			sleep((caddr_t)np, PINOD);
113*39395Smckusick 			goto loop;
114*39395Smckusick 		}
115*39395Smckusick 		vp = NFSTOV(np);
116*39395Smckusick 		if (vp->v_count == 0)	/* nfsnode on free list */
117*39395Smckusick 			vget(vp);
118*39395Smckusick 		else
11938425Smckusick 			VREF(vp);
120*39395Smckusick 		np->n_flag |= NLOCKED;
121*39395Smckusick 		*npp = np;
122*39395Smckusick 		return(0);
12338884Smacklem 	}
124*39395Smckusick 	if (error = getnewvnode(VT_NFS, mntp, &nfsv2_vnodeops, &nvp)) {
12538415Smckusick 		*npp = 0;
126*39395Smckusick 		return (error);
12738415Smckusick 	}
128*39395Smckusick 	vp = nvp;
129*39395Smckusick 	np = VTONFS(vp);
130*39395Smckusick 	np->n_vnode = vp;
13138415Smckusick 	/*
13238884Smacklem 	 * Insert the nfsnode in the hash queue for its new file handle
13338884Smacklem 	 */
13438884Smacklem 	np->n_flag = NLOCKED;
13538415Smckusick 	insque(np, nh);
13638415Smckusick 	bcopy((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH);
13738415Smckusick 	np->n_attrstamp = 0;
13838415Smckusick 	np->n_sillyrename = (struct sillyrename *)0;
13938884Smacklem 	np->n_size = 0;
14038884Smacklem 	np->n_mtime = 0;
14138415Smckusick 	/*
14238415Smckusick 	 * Initialize the associated vnode
14338415Smckusick 	 */
14438415Smckusick 	*npp = np;
14538415Smckusick 	return (0);
14638415Smckusick }
14738415Smckusick 
14838415Smckusick /*
14938415Smckusick  * Convert a pointer to an nfsnode into a reference to an nfsnode.
15038415Smckusick  *
15138415Smckusick  * This is basically the internal piece of nget (after the
15238415Smckusick  * nfsnode pointer is located) but without the test for mounted
15338415Smckusick  * filesystems.  It is caller's responsibility to check that
15438415Smckusick  * the nfsnode pointer is valid.
15538415Smckusick  */
15638415Smckusick nfs_ngrab(np)
15738415Smckusick 	register struct nfsnode *np;
15838415Smckusick {
15938415Smckusick 	register struct vnode *vp = NFSTOV(np);
16038415Smckusick 
16138415Smckusick 	while ((np->n_flag & NLOCKED) != 0) {
16238415Smckusick 		np->n_flag |= NWANT;
16338415Smckusick 		sleep((caddr_t)np, PINOD);
16438415Smckusick 	}
165*39395Smckusick 	if (vp->v_count == 0)		/* ino on free list */
166*39395Smckusick 		vget(vp);
167*39395Smckusick 	else
168*39395Smckusick 		VREF(vp);
16938415Smckusick 	np->n_flag |= NLOCKED;
17038415Smckusick }
17138415Smckusick 
17238415Smckusick nfs_inactive(vp)
17338415Smckusick 	struct vnode *vp;
17438415Smckusick {
17538415Smckusick 	register struct nfsnode *np;
17638415Smckusick 	register struct nameidata *ndp;
17738415Smckusick 	register struct sillyrename *sp;
17838415Smckusick 	struct nfsnode *dnp;
17938415Smckusick 
180*39395Smckusick 	if (vp == NULL || vp->v_count != 0)
181*39395Smckusick 		panic("nfs_inactive: NULL or active vp");
182*39395Smckusick 	np = VTONFS(vp);
183*39395Smckusick 	nfs_lock(vp);
184*39395Smckusick 	sp = np->n_sillyrename;
185*39395Smckusick 	np->n_sillyrename = (struct sillyrename *)0;
186*39395Smckusick 	if (sp) {
18738415Smckusick 		/*
188*39395Smckusick 		 * Remove the silly file that was rename'd earlier
18938415Smckusick 		 */
190*39395Smckusick 		ndp = &sp->s_namei;
191*39395Smckusick 		if (!nfs_nget(vp->v_mount, &sp->s_fh, &dnp)) {
192*39395Smckusick 			ndp->ni_dvp = NFSTOV(dnp);
193*39395Smckusick 			nfs_removeit(ndp);
194*39395Smckusick 			nfs_nput(ndp->ni_dvp);
19538415Smckusick 		}
196*39395Smckusick 		crfree(ndp->ni_cred);
197*39395Smckusick 		free((caddr_t)sp, M_TEMP);
198*39395Smckusick 	}
199*39395Smckusick 	nfs_unlock(vp);
200*39395Smckusick 	np->n_flag = 0;
201*39395Smckusick #ifdef notdef
202*39395Smckusick 	/*
203*39395Smckusick 	 * Scan the request list for any requests left hanging about
204*39395Smckusick 	 */
205*39395Smckusick 	s = splnet();
206*39395Smckusick 	rep = nfsreqh.r_next;
207*39395Smckusick 	while (rep && rep != &nfsreqh) {
208*39395Smckusick 		if (rep->r_vp == vp) {
209*39395Smckusick 			rep->r_prev->r_next = rep2 = rep->r_next;
210*39395Smckusick 			rep->r_next->r_prev = rep->r_prev;
211*39395Smckusick 			m_freem(rep->r_mreq);
212*39395Smckusick 			if (rep->r_mrep != NULL)
213*39395Smckusick 				m_freem(rep->r_mrep);
214*39395Smckusick 			free((caddr_t)rep, M_NFSREQ);
215*39395Smckusick 			rep = rep2;
216*39395Smckusick 		} else
217*39395Smckusick 			rep = rep->r_next;
218*39395Smckusick 	}
219*39395Smckusick 	splx(s);
22038884Smacklem #endif
221*39395Smckusick 	return (0);
222*39395Smckusick }
223*39395Smckusick 
224*39395Smckusick /*
225*39395Smckusick  * Reclaim an nfsnode so that it can be used for other purposes.
226*39395Smckusick  */
227*39395Smckusick nfs_reclaim(vp)
228*39395Smckusick 	register struct vnode *vp;
229*39395Smckusick {
230*39395Smckusick 	register struct nfsnode *np = VTONFS(vp);
231*39395Smckusick 
232*39395Smckusick 	if (vp->v_count != 0)
233*39395Smckusick 		panic("nfs_reclaim: active inode");
234*39395Smckusick 	/*
235*39395Smckusick 	 * Remove the nfsnode from its hash chain.
236*39395Smckusick 	 */
237*39395Smckusick 	remque(np);
238*39395Smckusick 	np->n_forw = np;
239*39395Smckusick 	np->n_back = np;
240*39395Smckusick 	cache_purge(vp);
241*39395Smckusick 	/*
242*39395Smckusick 	 * Flush out any associated bio buffers that might be lying about
243*39395Smckusick 	 * XXX n_flags are set to zero by nfs_inactive.
244*39395Smckusick 	 */
245*39395Smckusick 	if (vp->v_type == VREG && (np->n_flag & NBUFFERED)) {
246*39395Smckusick 		np->n_flag |= NLOCKED;
247*39395Smckusick 		nfs_blkflush(vp, (daddr_t)0, np->n_size, TRUE);
24838415Smckusick 	}
249*39395Smckusick 	vp->v_type = VNON;
25038415Smckusick 	return (0);
25138415Smckusick }
25238415Smckusick 
25338415Smckusick /*
25438415Smckusick  * Remove any nfsnodes in the nfsnode cache belonging to mount.
25538415Smckusick  *
25638415Smckusick  * There should not be any active ones, return error if any are found
25738415Smckusick  * (nb: this is a user error, not a system err).
25838415Smckusick  */
25938415Smckusick nfs_nflush(mntp)
26038415Smckusick 	struct mount *mntp;
26138415Smckusick {
26238415Smckusick 	register struct vnode *vp;
263*39395Smckusick 	int busy = 0;
26438415Smckusick 
265*39395Smckusick 	for (vp = mntp->m_mounth; vp; vp = vp->v_mountf) {
266*39395Smckusick 		if (vp->v_count) {
267*39395Smckusick 			busy++;
268*39395Smckusick 			continue;
269*39395Smckusick 		}
270*39395Smckusick 		/*
271*39395Smckusick 		 * As v_count == 0, the nfsnode was on the free list already,
272*39395Smckusick 		 * so it will fall off the bottom eventually.
273*39395Smckusick 		 * We could perhaps move it to the head of the free list,
274*39395Smckusick 		 * but as umounts are done so infrequently, we would gain
275*39395Smckusick 		 * very little, while making the code bigger.
276*39395Smckusick 		 */
277*39395Smckusick 		nfs_reclaim(vp);
27838415Smckusick 	}
279*39395Smckusick 	if (busy)
280*39395Smckusick 		return (EBUSY);
28138415Smckusick 	return (0);
28238415Smckusick }
28338415Smckusick 
28438415Smckusick /*
28538415Smckusick  * Lock an nfsnode
28638415Smckusick  */
28738415Smckusick nfs_lock(vp)
28838415Smckusick 	struct vnode *vp;
28938415Smckusick {
29038415Smckusick 	register struct nfsnode *np = VTONFS(vp);
29138415Smckusick 
29238415Smckusick 	while (np->n_flag & NLOCKED) {
29338415Smckusick 		np->n_flag |= NWANT;
29438415Smckusick 		sleep((caddr_t)np, PINOD);
29538415Smckusick 	}
29638415Smckusick 	np->n_flag |= NLOCKED;
29738415Smckusick }
29838415Smckusick 
29938415Smckusick /*
30038415Smckusick  * Unlock an nfsnode
30138415Smckusick  */
30238415Smckusick nfs_unlock(vp)
30338415Smckusick 	struct vnode *vp;
30438415Smckusick {
30538415Smckusick 	register struct nfsnode *np = VTONFS(vp);
30638415Smckusick 
30738415Smckusick 	np->n_flag &= ~NLOCKED;
30838415Smckusick 	if (np->n_flag & NWANT) {
30938415Smckusick 		np->n_flag &= ~NWANT;
31038415Smckusick 		wakeup((caddr_t)np);
31138415Smckusick 	}
31238415Smckusick }
31338415Smckusick 
31438415Smckusick /*
31538415Smckusick  * Unlock and vrele()
31638415Smckusick  * since I can't decide if dirs. should be locked, I will check for
31738415Smckusick  * the lock and be flexible
31838415Smckusick  */
31938415Smckusick nfs_nput(vp)
32038415Smckusick 	struct vnode *vp;
32138415Smckusick {
32238415Smckusick 	register struct nfsnode *np = VTONFS(vp);
32338415Smckusick 
32438415Smckusick 	if (np->n_flag & NLOCKED)
32538415Smckusick 		nfs_unlock(vp);
32638415Smckusick 	vrele(vp);
32738415Smckusick }
32838415Smckusick 
32938415Smckusick nfs_abortop(ndp)
33038415Smckusick 	register struct nameidata *ndp;
33138415Smckusick {
33238415Smckusick 	register struct nfsnode *np;
33338415Smckusick 
33438415Smckusick 	if (ndp->ni_vp != NULL) {
33538415Smckusick 		np = VTONFS(ndp->ni_vp);
33638415Smckusick 		if (np->n_flag & NLOCKED)
33738415Smckusick 			nfs_unlock(ndp->ni_vp);
33838415Smckusick 		vrele(ndp->ni_vp);
33938415Smckusick 	}
34038415Smckusick 	if (ndp->ni_dvp != NULL) {
34138415Smckusick 		np = VTONFS(ndp->ni_dvp);
34238415Smckusick 		if (np->n_flag & NLOCKED)
34338415Smckusick 			nfs_unlock(ndp->ni_dvp);
34438415Smckusick 		vrele(ndp->ni_dvp);
34538415Smckusick 	}
34638415Smckusick }
34738415Smckusick 
34838415Smckusick /*
34938415Smckusick  * This is silly, but if you use a macro and try and use it in a file
35038415Smckusick  * that has mbuf.h included, m_data --> m_hdr.mh_data and this is not
35138415Smckusick  * a good thing
35238415Smckusick  */
35338415Smckusick struct nfsmount *vfs_to_nfs(mp)
35438415Smckusick 	struct mount *mp;
35538415Smckusick {
35638415Smckusick 	return ((struct nfsmount *)mp->m_data);
35738415Smckusick }
358