xref: /csrg-svn/sys/nfs/nfs_node.c (revision 38884)
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*38884Smacklem  *	@(#)nfs_node.c	7.4 (Berkeley) 08/30/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 
4938415Smckusick union nhead {				/* inode LRU cache, Chris Maltby */
5038415Smckusick 	union  nhead *nh_head[2];
5138415Smckusick 	struct nfsnode *nh_chain[2];
5238415Smckusick } nhead[NFSNOHSZ];
5338415Smckusick 
5438415Smckusick struct nfsnode *nfreeh, **nfreet;
5538415Smckusick 
56*38884Smacklem #define TRUE	1
57*38884Smacklem #define	FALSE	0
58*38884Smacklem 
5938415Smckusick /*
6038415Smckusick  * Initialize hash links for nfsnodes
6138415Smckusick  * and build nfsnode free list.
6238415Smckusick  */
6338415Smckusick nfs_nhinit()
6438415Smckusick {
6538415Smckusick 	register int i;
6638415Smckusick 	register struct nfsnode *np = nfsnode;
6738415Smckusick 	register union  nhead *nh = nhead;
6838415Smckusick 
6938415Smckusick 	for (i = NFSNOHSZ; --i >= 0; nh++) {
7038415Smckusick 		nh->nh_head[0] = nh;
7138415Smckusick 		nh->nh_head[1] = nh;
7238415Smckusick 	}
7338415Smckusick 	nfreeh = np;
7438415Smckusick 	nfreet = &np->n_freef;
7538415Smckusick 	np->n_freeb = &nfreeh;
7638415Smckusick 	np->n_forw = np;
7738415Smckusick 	np->n_back = np;
7838415Smckusick 	NFSTOV(np)->v_data = (qaddr_t)np;
79*38884Smacklem 	NFSTOV(np)->v_type = VNON;
8038415Smckusick 	for (i = nnfsnode; --i > 0; ) {
8138415Smckusick 		++np;
8238415Smckusick 		np->n_forw = np;
8338415Smckusick 		np->n_back = np;
8438415Smckusick 		NFSTOV(np)->v_data = (qaddr_t)np;
85*38884Smacklem 		NFSTOV(np)->v_type = VNON;
8638415Smckusick 		*nfreet = np;
8738415Smckusick 		np->n_freeb = nfreet;
8838415Smckusick 		nfreet = &np->n_freef;
8938415Smckusick 	}
9038415Smckusick 	np->n_freef = NULL;
9138415Smckusick }
9238415Smckusick 
9338415Smckusick /*
9438415Smckusick  * Look up an vnode/nfsnode by file handle.
9538415Smckusick  * Callers must check for mount points!!
9638415Smckusick  * In all cases, a pointer to a
9738415Smckusick  * nfsnode structure is returned.
9838415Smckusick  */
9938415Smckusick nfs_nget(mntp, fhp, npp)
10038415Smckusick 	struct mount *mntp;
10138415Smckusick 	register nfsv2fh_t *fhp;
10238415Smckusick 	struct nfsnode **npp;
10338415Smckusick {
10438415Smckusick 	register struct nfsnode *np;
10538415Smckusick 	register struct vnode *vp;
10638415Smckusick 	register struct nfsnode *nq;
10738415Smckusick 	register u_char *fhpp;
10838415Smckusick 	register u_long fhsum;
10938415Smckusick 	register int i;
11038415Smckusick 	union  nhead *nh;
11138415Smckusick 	int error;
11238415Smckusick 
11338415Smckusick 	fhpp = &fhp->fh_bytes[0];
11438415Smckusick 	fhsum = 0;
11538415Smckusick 	for (i = 0; i < NFSX_FH; i++)
11638415Smckusick 		fhsum += *fhpp++;
11738415Smckusick loop:
11838415Smckusick 	nh = &nhead[NFSNOHASH(fhsum)];
119*38884Smacklem 	for (np = nh->nh_chain[0]; np != (struct nfsnode *)nh; np = np->n_forw) {
12038415Smckusick 		if (mntp == NFSTOV(np)->v_mount &&
12138415Smckusick 		    !bcmp((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH)) {
12238415Smckusick 			/*
12338415Smckusick 			 * Following is essentially an inline expanded
12438415Smckusick 			 * copy of ngrab(), expanded inline for speed,
12538415Smckusick 			 * and so that the test for a mounted on nfsnode
12638415Smckusick 			 * can be deferred until after we are sure that
12738415Smckusick 			 * the nfsnode isn't busy.
12838415Smckusick 			 */
12938415Smckusick 			if ((np->n_flag & NLOCKED) != 0) {
13038415Smckusick 				np->n_flag |= NWANT;
13138415Smckusick 				sleep((caddr_t)np, PINOD);
13238415Smckusick 				goto loop;
13338415Smckusick 			}
13438415Smckusick 			vp = NFSTOV(np);
13538415Smckusick 			if (vp->v_count == 0) {		/* nfsno on free list */
13638415Smckusick 				if (nq = np->n_freef)
13738415Smckusick 					nq->n_freeb = np->n_freeb;
13838415Smckusick 				else
13938415Smckusick 					nfreet = np->n_freeb;
14038415Smckusick 				*np->n_freeb = nq;
14138415Smckusick 				np->n_freef = NULL;
14238415Smckusick 				np->n_freeb = NULL;
14338415Smckusick 			}
14438415Smckusick 			np->n_flag |= NLOCKED;
14538425Smckusick 			VREF(vp);
14638415Smckusick 			*npp = np;
14738415Smckusick 			return(0);
14838415Smckusick 		}
14938415Smckusick 
150*38884Smacklem 	}
15138415Smckusick 	if ((np = nfreeh) == NULL) {
15238415Smckusick 		tablefull("nfsnode");
15338415Smckusick 		*npp = 0;
15438415Smckusick 		return(ENFILE);
15538415Smckusick 	}
15638415Smckusick 	vp = NFSTOV(np);
15738415Smckusick 	if (vp->v_count)
15838415Smckusick 		panic("free nfsnode isn't");
15938415Smckusick 	if (nq = np->n_freef)
16038415Smckusick 		nq->n_freeb = &nfreeh;
16138415Smckusick 	nfreeh = nq;
16238415Smckusick 	np->n_freef = NULL;
16338415Smckusick 	np->n_freeb = NULL;
16438415Smckusick 	/*
16538415Smckusick 	 * Now to take nfsnode off the hash chain it was on
16638415Smckusick 	 * (initially, or after an nflush, it is on a "hash chain"
16738415Smckusick 	 * consisting entirely of itself, and pointed to by no-one,
168*38884Smacklem 	 * but that doesn't matter)
16938415Smckusick 	 */
17038415Smckusick 	remque(np);
171*38884Smacklem 	/*
172*38884Smacklem 	 * Flush out any associated bio buffers that might be lying about
173*38884Smacklem 	 */
174*38884Smacklem 	if (vp->v_type == VREG && (np->n_flag & NMODIFIED) == 0) {
175*38884Smacklem 		np->n_flag |= NLOCKED;
176*38884Smacklem 		nfs_blkflush(vp, (daddr_t)0, np->n_size, TRUE);
177*38884Smacklem 	}
178*38884Smacklem 	/*
179*38884Smacklem 	 * Insert the nfsnode in the hash queue for its new file handle
180*38884Smacklem 	 */
181*38884Smacklem 	np->n_flag = NLOCKED;
18238415Smckusick 	insque(np, nh);
18338415Smckusick 	bcopy((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH);
184*38884Smacklem #ifndef notyet
18538415Smckusick 	cache_purge(vp);
18638415Smckusick #endif
18738415Smckusick 	np->n_attrstamp = 0;
18838415Smckusick 	np->n_sillyrename = (struct sillyrename *)0;
18938415Smckusick 	np->n_id = ++nextnfsnodeid;
190*38884Smacklem 	np->n_size = 0;
191*38884Smacklem 	np->n_mtime = 0;
19238415Smckusick 	/*
19338415Smckusick 	 * Initialize the associated vnode
19438415Smckusick 	 */
19538415Smckusick 	vinit(vp, mntp, VNON, &nfsv2_vnodeops);
19638415Smckusick 	*npp = np;
19738415Smckusick 	return (0);
19838415Smckusick }
19938415Smckusick 
20038415Smckusick /*
20138415Smckusick  * Convert a pointer to an nfsnode into a reference to an nfsnode.
20238415Smckusick  *
20338415Smckusick  * This is basically the internal piece of nget (after the
20438415Smckusick  * nfsnode pointer is located) but without the test for mounted
20538415Smckusick  * filesystems.  It is caller's responsibility to check that
20638415Smckusick  * the nfsnode pointer is valid.
20738415Smckusick  */
20838415Smckusick nfs_ngrab(np)
20938415Smckusick 	register struct nfsnode *np;
21038415Smckusick {
21138415Smckusick 	register struct vnode *vp = NFSTOV(np);
21238415Smckusick 
21338415Smckusick 	while ((np->n_flag & NLOCKED) != 0) {
21438415Smckusick 		np->n_flag |= NWANT;
21538415Smckusick 		sleep((caddr_t)np, PINOD);
21638415Smckusick 	}
21738415Smckusick 	if (vp->v_count == 0) {		/* ino on free list */
21838415Smckusick 		register struct nfsnode *nq;
21938415Smckusick 
22038415Smckusick 		if (nq = np->n_freef)
22138415Smckusick 			nq->n_freeb = np->n_freeb;
22238415Smckusick 		else
22338415Smckusick 			nfreet = np->n_freeb;
22438415Smckusick 		*np->n_freeb = nq;
22538415Smckusick 		np->n_freef = NULL;
22638415Smckusick 		np->n_freeb = NULL;
22738415Smckusick 	}
22838425Smckusick 	VREF(vp);
22938415Smckusick 	np->n_flag |= NLOCKED;
23038415Smckusick }
23138415Smckusick 
23238415Smckusick nfs_inactive(vp)
23338415Smckusick 	struct vnode *vp;
23438415Smckusick {
23538415Smckusick 	register struct nfsnode *np;
23638415Smckusick 	register struct nameidata *ndp;
23738415Smckusick 	register struct sillyrename *sp;
23838415Smckusick 	register struct nfsreq *rep;
23938415Smckusick 	struct nfsreq *rep2;
24038415Smckusick 	struct nfsnode *dnp;
24138415Smckusick 	int s;
24238415Smckusick 
24338415Smckusick 	if (vp == NULL)
24438415Smckusick 		panic("nfs_inactive NULL vp");
24538415Smckusick 	if (vp->v_count == 0) {
24638415Smckusick 		np = VTONFS(vp);
247*38884Smacklem 		sp = np->n_sillyrename;
248*38884Smacklem 		np->n_sillyrename = (struct sillyrename *)0;
249*38884Smacklem 		nfs_lock(vp);
250*38884Smacklem 		if (sp) {
251*38884Smacklem printf("in silltren inact\n");
25238415Smckusick 			/*
25338415Smckusick 			 * Remove the silly file that was rename'd earlier
25438415Smckusick 			 */
25538415Smckusick 			ndp = &sp->s_namei;
25638415Smckusick 			if (!nfs_nget(vp->v_mount, &sp->s_fh, &dnp)) {
257*38884Smacklem printf("got the dir\n");
25838415Smckusick 				ndp->ni_dvp = NFSTOV(dnp);
259*38884Smacklem 				nfs_removeit(ndp);
26038415Smckusick 				nfs_nput(ndp->ni_dvp);
26138415Smckusick 			}
26238415Smckusick 			crfree(ndp->ni_cred);
26338415Smckusick 			free((caddr_t)sp, M_TEMP);
26438415Smckusick 		}
26538415Smckusick 		nfs_unlock(vp);
26638415Smckusick 		np->n_flag = 0;
267*38884Smacklem #ifdef notdef
26838415Smckusick 		/*
26938415Smckusick 		 * Scan the request list for any requests left hanging about
27038415Smckusick 		 */
27138415Smckusick 		s = splnet();
27238415Smckusick 		rep = nfsreqh.r_next;
27338415Smckusick 		while (rep) {
27438415Smckusick 			if (rep->r_vp == vp) {
27538415Smckusick 				rep->r_prev->r_next = rep2 = rep->r_next;
27638415Smckusick 				if (rep->r_next != NULL)
27738415Smckusick 					rep->r_next->r_prev = rep->r_prev;
27838415Smckusick 				m_freem(rep->r_mreq);
27938415Smckusick 				if (rep->r_mrep != NULL)
28038415Smckusick 					m_freem(rep->r_mrep);
28138415Smckusick 				free((caddr_t)rep, M_NFSREQ);
28238415Smckusick 				rep = rep2;
28338415Smckusick 			} else
28438415Smckusick 				rep = rep->r_next;
28538415Smckusick 		}
28638415Smckusick 		splx(s);
287*38884Smacklem #endif
28838415Smckusick 		/*
28938415Smckusick 		 * Put the nfsnode on the end of the free list.
29038415Smckusick 		 */
29138415Smckusick 		if (nfreeh) {
29238415Smckusick 			*nfreet = np;
29338415Smckusick 			np->n_freeb = nfreet;
29438415Smckusick 		} else {
29538415Smckusick 			nfreeh = np;
29638415Smckusick 			np->n_freeb = &nfreeh;
29738415Smckusick 		}
29838415Smckusick 		np->n_freef = NULL;
29938415Smckusick 		nfreet = &np->n_freef;
30038415Smckusick 	}
30138415Smckusick 	return (0);
30238415Smckusick }
30338415Smckusick 
30438415Smckusick /*
30538415Smckusick  * Remove any nfsnodes in the nfsnode cache belonging to mount.
30638415Smckusick  *
30738415Smckusick  * There should not be any active ones, return error if any are found
30838415Smckusick  * (nb: this is a user error, not a system err).
30938415Smckusick  */
31038415Smckusick nfs_nflush(mntp)
31138415Smckusick 	struct mount *mntp;
31238415Smckusick {
31338415Smckusick 	register struct nfsnode *np;
31438415Smckusick 	register struct vnode *vp;
31538415Smckusick 
31638415Smckusick 	for (np = nfsnode; np < nfsnodeNNFSNODE; np++) {
31738415Smckusick 		vp = NFSTOV(np);
31838415Smckusick 		if (vp->v_mount == mntp)
31938415Smckusick 			if (vp->v_count)
32038415Smckusick 				return (EBUSY);
32138415Smckusick 			else {
32238415Smckusick 				remque(np);
32338415Smckusick 				np->n_forw = np;
32438415Smckusick 				np->n_back = np;
32538415Smckusick 				/*
32638415Smckusick 				 * as v_count == 0, the inode was on the free
32738415Smckusick 				 * list already, just leave it there, it will
32838415Smckusick 				 * fall off the bottom eventually. We could
32938415Smckusick 				 * perhaps move it to the head of the free
33038415Smckusick 				 * list, but as umounts are done so
33138415Smckusick 				 * infrequently, we would gain very little,
33238415Smckusick 				 * while making the code bigger.
33338415Smckusick 				 */
33438415Smckusick 			}
33538415Smckusick 	}
33638415Smckusick 	return (0);
33738415Smckusick }
33838415Smckusick 
33938415Smckusick /*
34038415Smckusick  * Lock an nfsnode
34138415Smckusick  */
34238415Smckusick nfs_lock(vp)
34338415Smckusick 	struct vnode *vp;
34438415Smckusick {
34538415Smckusick 	register struct nfsnode *np = VTONFS(vp);
34638415Smckusick 
34738415Smckusick 	if (np->n_flag & NLOCKED)
34838415Smckusick 		printf("pid %d hit locked nfsnode=0x%x\n",
34938415Smckusick 		    u.u_procp->p_pid, np);
35038415Smckusick 	while (np->n_flag & NLOCKED) {
35138415Smckusick 		np->n_flag |= NWANT;
35238415Smckusick 		sleep((caddr_t)np, PINOD);
35338415Smckusick 	}
35438415Smckusick 	np->n_flag |= NLOCKED;
35538415Smckusick }
35638415Smckusick 
35738415Smckusick /*
35838415Smckusick  * Unlock an nfsnode
35938415Smckusick  */
36038415Smckusick nfs_unlock(vp)
36138415Smckusick 	struct vnode *vp;
36238415Smckusick {
36338415Smckusick 	register struct nfsnode *np = VTONFS(vp);
36438415Smckusick 
36538415Smckusick 	if ((np->n_flag & NLOCKED) == 0) {
36638415Smckusick 		printf("pid %d unlocking unlocked nfsnode=0x%x ",
36738415Smckusick 		    u.u_procp->p_pid, np);
36838415Smckusick 		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",
36938415Smckusick 			np->n_fh.fh_bytes[0],np->n_fh.fh_bytes[1],
37038415Smckusick 			np->n_fh.fh_bytes[2],np->n_fh.fh_bytes[3],
37138415Smckusick 			np->n_fh.fh_bytes[4],np->n_fh.fh_bytes[5],
37238415Smckusick 			np->n_fh.fh_bytes[6],np->n_fh.fh_bytes[7]);
37338415Smckusick 	}
37438415Smckusick 	np->n_flag &= ~NLOCKED;
37538415Smckusick 	if (np->n_flag & NWANT) {
37638415Smckusick 		np->n_flag &= ~NWANT;
37738415Smckusick 		wakeup((caddr_t)np);
37838415Smckusick 	}
37938415Smckusick }
38038415Smckusick 
38138415Smckusick /*
38238415Smckusick  * Unlock and vrele()
38338415Smckusick  * since I can't decide if dirs. should be locked, I will check for
38438415Smckusick  * the lock and be flexible
38538415Smckusick  */
38638415Smckusick nfs_nput(vp)
38738415Smckusick 	struct vnode *vp;
38838415Smckusick {
38938415Smckusick 	register struct nfsnode *np = VTONFS(vp);
39038415Smckusick 
39138415Smckusick 	if (np->n_flag & NLOCKED)
39238415Smckusick 		nfs_unlock(vp);
39338415Smckusick 	vrele(vp);
39438415Smckusick }
39538415Smckusick 
39638415Smckusick nfs_abortop(ndp)
39738415Smckusick 	register struct nameidata *ndp;
39838415Smckusick {
39938415Smckusick 	register struct nfsnode *np;
40038415Smckusick 
40138415Smckusick 	if (ndp->ni_vp != NULL) {
40238415Smckusick 		np = VTONFS(ndp->ni_vp);
40338415Smckusick 		if (np->n_flag & NLOCKED)
40438415Smckusick 			nfs_unlock(ndp->ni_vp);
40538415Smckusick 		vrele(ndp->ni_vp);
40638415Smckusick 	}
40738415Smckusick 	if (ndp->ni_dvp != NULL) {
40838415Smckusick 		np = VTONFS(ndp->ni_dvp);
40938415Smckusick 		if (np->n_flag & NLOCKED)
41038415Smckusick 			nfs_unlock(ndp->ni_dvp);
41138415Smckusick 		vrele(ndp->ni_dvp);
41238415Smckusick 	}
41338415Smckusick }
41438415Smckusick 
41538415Smckusick /*
41638415Smckusick  * This is silly, but if you use a macro and try and use it in a file
41738415Smckusick  * that has mbuf.h included, m_data --> m_hdr.mh_data and this is not
41838415Smckusick  * a good thing
41938415Smckusick  */
42038415Smckusick struct nfsmount *vfs_to_nfs(mp)
42138415Smckusick 	struct mount *mp;
42238415Smckusick {
42338415Smckusick 	return ((struct nfsmount *)mp->m_data);
42438415Smckusick }
425