xref: /csrg-svn/sys/nfs/nfs_node.c (revision 51985)
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  *
844509Sbostic  * %sccs.include.redist.c%
938415Smckusick  *
10*51985Smckusick  *	@(#)nfs_node.c	7.35 (Berkeley) 12/16/91
1138415Smckusick  */
1238415Smckusick 
1338415Smckusick #include "param.h"
1438415Smckusick #include "systm.h"
1538415Smckusick #include "proc.h"
1638415Smckusick #include "mount.h"
1748052Smckusick #include "namei.h"
1838415Smckusick #include "vnode.h"
1947573Skarels #include "kernel.h"
2047573Skarels #include "malloc.h"
2147573Skarels 
2238415Smckusick #include "nfsv2.h"
2338415Smckusick #include "nfs.h"
2438415Smckusick #include "nfsnode.h"
2538415Smckusick #include "nfsmount.h"
2638415Smckusick 
2738415Smckusick /* The request list head */
2838415Smckusick extern struct nfsreq nfsreqh;
2938415Smckusick 
3038415Smckusick #define	NFSNOHSZ	512
3138415Smckusick #if	((NFSNOHSZ&(NFSNOHSZ-1)) == 0)
3238415Smckusick #define	NFSNOHASH(fhsum)	((fhsum)&(NFSNOHSZ-1))
3338415Smckusick #else
3438415Smckusick #define	NFSNOHASH(fhsum)	(((unsigned)(fhsum))%NFSNOHSZ)
3538415Smckusick #endif
3638415Smckusick 
3739395Smckusick union nhead {
3838415Smckusick 	union  nhead *nh_head[2];
3938415Smckusick 	struct nfsnode *nh_chain[2];
4038415Smckusick } nhead[NFSNOHSZ];
4138415Smckusick 
4238884Smacklem #define TRUE	1
4338884Smacklem #define	FALSE	0
4438884Smacklem 
4538415Smckusick /*
4638415Smckusick  * Initialize hash links for nfsnodes
4738415Smckusick  * and build nfsnode free list.
4838415Smckusick  */
4938415Smckusick nfs_nhinit()
5038415Smckusick {
5138415Smckusick 	register int i;
5238415Smckusick 	register union  nhead *nh = nhead;
5338415Smckusick 
5439494Smckusick #ifndef lint
55*51985Smckusick 	if ((sizeof(struct nfsnode) - 1) & sizeof(struct nfsnode))
56*51985Smckusick 		printf("nfs_nhinit: bad size %d\n", sizeof(struct nfsnode));
5739494Smckusick #endif /* not lint */
5838415Smckusick 	for (i = NFSNOHSZ; --i >= 0; nh++) {
5938415Smckusick 		nh->nh_head[0] = nh;
6038415Smckusick 		nh->nh_head[1] = nh;
6138415Smckusick 	}
6238415Smckusick }
6338415Smckusick 
6438415Smckusick /*
6539445Smckusick  * Compute an entry in the NFS hash table structure
6639445Smckusick  */
6739445Smckusick union nhead *
6839445Smckusick nfs_hash(fhp)
6939445Smckusick 	register nfsv2fh_t *fhp;
7039445Smckusick {
7139445Smckusick 	register u_char *fhpp;
7239445Smckusick 	register u_long fhsum;
7339445Smckusick 	int i;
7439445Smckusick 
7539445Smckusick 	fhpp = &fhp->fh_bytes[0];
7639445Smckusick 	fhsum = 0;
7739445Smckusick 	for (i = 0; i < NFSX_FH; i++)
7839445Smckusick 		fhsum += *fhpp++;
7939445Smckusick 	return (&nhead[NFSNOHASH(fhsum)]);
8039445Smckusick }
8139445Smckusick 
8239445Smckusick /*
8339395Smckusick  * Look up a vnode/nfsnode by file handle.
8438415Smckusick  * Callers must check for mount points!!
8538415Smckusick  * In all cases, a pointer to a
8638415Smckusick  * nfsnode structure is returned.
8738415Smckusick  */
8838415Smckusick nfs_nget(mntp, fhp, npp)
8938415Smckusick 	struct mount *mntp;
9038415Smckusick 	register nfsv2fh_t *fhp;
9138415Smckusick 	struct nfsnode **npp;
9238415Smckusick {
9338415Smckusick 	register struct nfsnode *np;
9438415Smckusick 	register struct vnode *vp;
9539445Smckusick 	extern struct vnodeops nfsv2_vnodeops;
9639395Smckusick 	struct vnode *nvp;
9739395Smckusick 	union nhead *nh;
9839445Smckusick 	int error;
9938415Smckusick 
10039445Smckusick 	nh = nfs_hash(fhp);
10138415Smckusick loop:
10238884Smacklem 	for (np = nh->nh_chain[0]; np != (struct nfsnode *)nh; np = np->n_forw) {
10339395Smckusick 		if (mntp != NFSTOV(np)->v_mount ||
10439395Smckusick 		    bcmp((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH))
10539395Smckusick 			continue;
10639395Smckusick 		if ((np->n_flag & NLOCKED) != 0) {
10739395Smckusick 			np->n_flag |= NWANT;
10843349Smckusick 			(void) tsleep((caddr_t)np, PINOD, "nfsnode", 0);
10939395Smckusick 			goto loop;
11039395Smckusick 		}
11139395Smckusick 		vp = NFSTOV(np);
11239445Smckusick 		if (vget(vp))
11339445Smckusick 			goto loop;
11439395Smckusick 		*npp = np;
11539395Smckusick 		return(0);
11638884Smacklem 	}
11739395Smckusick 	if (error = getnewvnode(VT_NFS, mntp, &nfsv2_vnodeops, &nvp)) {
11838415Smckusick 		*npp = 0;
11939395Smckusick 		return (error);
12038415Smckusick 	}
12139395Smckusick 	vp = nvp;
122*51985Smckusick 	MALLOC(np, struct nfsnode *, sizeof *np, M_NFSNODE, M_WAITOK);
123*51985Smckusick 	vp->v_data = np;
12439395Smckusick 	np->n_vnode = vp;
12538415Smckusick 	/*
12638884Smacklem 	 * Insert the nfsnode in the hash queue for its new file handle
12738884Smacklem 	 */
12839908Smckusick 	np->n_flag = 0;
12938415Smckusick 	insque(np, nh);
13039908Smckusick 	nfs_lock(vp);
13138415Smckusick 	bcopy((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH);
13238415Smckusick 	np->n_attrstamp = 0;
13341898Smckusick 	np->n_direofoffset = 0;
13438415Smckusick 	np->n_sillyrename = (struct sillyrename *)0;
13538884Smacklem 	np->n_size = 0;
13638884Smacklem 	np->n_mtime = 0;
13738415Smckusick 	*npp = np;
13838415Smckusick 	return (0);
13938415Smckusick }
14038415Smckusick 
14148052Smckusick nfs_inactive(vp, p)
14238415Smckusick 	struct vnode *vp;
14348052Smckusick 	struct proc *p;
14438415Smckusick {
14538415Smckusick 	register struct nfsnode *np;
14638415Smckusick 	register struct sillyrename *sp;
14738415Smckusick 	struct nfsnode *dnp;
14839575Smckusick 	extern int prtactive;
14938415Smckusick 
15039395Smckusick 	np = VTONFS(vp);
15139810Smckusick 	if (prtactive && vp->v_usecount != 0)
15239671Smckusick 		vprint("nfs_inactive: pushing active", vp);
15339395Smckusick 	nfs_lock(vp);
15439395Smckusick 	sp = np->n_sillyrename;
15539395Smckusick 	np->n_sillyrename = (struct sillyrename *)0;
15639395Smckusick 	if (sp) {
15738415Smckusick 		/*
15839395Smckusick 		 * Remove the silly file that was rename'd earlier
15938415Smckusick 		 */
16039395Smckusick 		if (!nfs_nget(vp->v_mount, &sp->s_fh, &dnp)) {
16148364Smckusick 			sp->s_dvp = NFSTOV(dnp);
16248364Smckusick 			nfs_removeit(sp, p);
16348364Smckusick 			nfs_nput(sp->s_dvp);
16438415Smckusick 		}
16548364Smckusick 		crfree(sp->s_cred);
16648364Smckusick 		vrele(sp->s_dvp);
167*51985Smckusick #ifdef SILLYSEPARATE
16848364Smckusick 		free((caddr_t)sp, M_NFSREQ);
169*51985Smckusick #endif
17039395Smckusick 	}
17139395Smckusick 	nfs_unlock(vp);
17241898Smckusick 	np->n_flag &= NMODIFIED;
17339395Smckusick #ifdef notdef
17439395Smckusick 	/*
17539395Smckusick 	 * Scan the request list for any requests left hanging about
17639395Smckusick 	 */
17739395Smckusick 	s = splnet();
17839395Smckusick 	rep = nfsreqh.r_next;
17939395Smckusick 	while (rep && rep != &nfsreqh) {
18039395Smckusick 		if (rep->r_vp == vp) {
18139395Smckusick 			rep->r_prev->r_next = rep2 = rep->r_next;
18239395Smckusick 			rep->r_next->r_prev = rep->r_prev;
18339395Smckusick 			m_freem(rep->r_mreq);
18439395Smckusick 			if (rep->r_mrep != NULL)
18539395Smckusick 				m_freem(rep->r_mrep);
18639395Smckusick 			free((caddr_t)rep, M_NFSREQ);
18739395Smckusick 			rep = rep2;
18839395Smckusick 		} else
18939395Smckusick 			rep = rep->r_next;
19039395Smckusick 	}
19139395Smckusick 	splx(s);
19238884Smacklem #endif
19339395Smckusick 	return (0);
19439395Smckusick }
19539395Smckusick 
19639395Smckusick /*
19739395Smckusick  * Reclaim an nfsnode so that it can be used for other purposes.
19839395Smckusick  */
19939395Smckusick nfs_reclaim(vp)
20039395Smckusick 	register struct vnode *vp;
20139395Smckusick {
20239395Smckusick 	register struct nfsnode *np = VTONFS(vp);
20339575Smckusick 	extern int prtactive;
20439395Smckusick 
20539810Smckusick 	if (prtactive && vp->v_usecount != 0)
20639671Smckusick 		vprint("nfs_reclaim: pushing active", vp);
20739395Smckusick 	/*
20839395Smckusick 	 * Remove the nfsnode from its hash chain.
20939395Smckusick 	 */
21039395Smckusick 	remque(np);
21139395Smckusick 	cache_purge(vp);
212*51985Smckusick 	FREE(vp->v_data, M_NFSNODE);
213*51985Smckusick 	vp->v_data = NULL;
21438415Smckusick 	return (0);
21538415Smckusick }
21638415Smckusick 
21738415Smckusick /*
21849462Smckusick  * In theory, NFS does not need locking, but we make provision
21949462Smckusick  * for doing it just in case it is needed.
22049462Smckusick  */
22149462Smckusick int donfslocking = 0;
22249462Smckusick /*
22338415Smckusick  * Lock an nfsnode
22438415Smckusick  */
22549462Smckusick 
22638415Smckusick nfs_lock(vp)
22738415Smckusick 	struct vnode *vp;
22838415Smckusick {
22938415Smckusick 	register struct nfsnode *np = VTONFS(vp);
23038415Smckusick 
23149462Smckusick 	if (!donfslocking)
23249462Smckusick 		return;
23338415Smckusick 	while (np->n_flag & NLOCKED) {
23438415Smckusick 		np->n_flag |= NWANT;
23547573Skarels 		if (np->n_lockholder == curproc->p_pid)
23639904Smckusick 			panic("locking against myself");
23747573Skarels 		np->n_lockwaiter = curproc->p_pid;
23843349Smckusick 		(void) tsleep((caddr_t)np, PINOD, "nfslock", 0);
23938415Smckusick 	}
24039904Smckusick 	np->n_lockwaiter = 0;
24147573Skarels 	np->n_lockholder = curproc->p_pid;
24238415Smckusick 	np->n_flag |= NLOCKED;
24338415Smckusick }
24438415Smckusick 
24538415Smckusick /*
24638415Smckusick  * Unlock an nfsnode
24738415Smckusick  */
24838415Smckusick nfs_unlock(vp)
24938415Smckusick 	struct vnode *vp;
25038415Smckusick {
25138415Smckusick 	register struct nfsnode *np = VTONFS(vp);
25238415Smckusick 
25339904Smckusick 	np->n_lockholder = 0;
25438415Smckusick 	np->n_flag &= ~NLOCKED;
25538415Smckusick 	if (np->n_flag & NWANT) {
25638415Smckusick 		np->n_flag &= ~NWANT;
25738415Smckusick 		wakeup((caddr_t)np);
25838415Smckusick 	}
25938415Smckusick }
26038415Smckusick 
26138415Smckusick /*
26239908Smckusick  * Check for a locked nfsnode
26339908Smckusick  */
26439908Smckusick nfs_islocked(vp)
26539908Smckusick 	struct vnode *vp;
26639908Smckusick {
26739908Smckusick 
26839908Smckusick 	if (VTONFS(vp)->n_flag & NLOCKED)
26939908Smckusick 		return (1);
27039908Smckusick 	return (0);
27139908Smckusick }
27239908Smckusick 
27339908Smckusick /*
27438415Smckusick  * Unlock and vrele()
27538415Smckusick  * since I can't decide if dirs. should be locked, I will check for
27638415Smckusick  * the lock and be flexible
27738415Smckusick  */
27838415Smckusick nfs_nput(vp)
27938415Smckusick 	struct vnode *vp;
28038415Smckusick {
28138415Smckusick 	register struct nfsnode *np = VTONFS(vp);
28238415Smckusick 
28338415Smckusick 	if (np->n_flag & NLOCKED)
28438415Smckusick 		nfs_unlock(vp);
28538415Smckusick 	vrele(vp);
28638415Smckusick }
28738415Smckusick 
28842467Smckusick /*
28942467Smckusick  * Nfs abort op, called after namei() when a CREATE/DELETE isn't actually
29042467Smckusick  * done. Currently nothing to do.
29142467Smckusick  */
29242467Smckusick /* ARGSUSED */
29338415Smckusick nfs_abortop(ndp)
29442467Smckusick 	struct nameidata *ndp;
29538415Smckusick {
29638415Smckusick 
29749740Smckusick 	if ((ndp->ni_nameiop & (HASBUF | SAVESTART)) == HASBUF)
29849740Smckusick 		FREE(ndp->ni_pnbuf, M_NAMEI);
29942467Smckusick 	return (0);
30038415Smckusick }
301