xref: /csrg-svn/sys/nfs/nfs_node.c (revision 67708)
1 /*
2  * Copyright (c) 1989, 1993
3  *	The Regents of the University of California.  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  * %sccs.include.redist.c%
9  *
10  *	@(#)nfs_node.c	8.3 (Berkeley) 08/18/94
11  */
12 
13 #include <sys/param.h>
14 #include <sys/systm.h>
15 #include <sys/proc.h>
16 #include <sys/mount.h>
17 #include <sys/namei.h>
18 #include <sys/vnode.h>
19 #include <sys/kernel.h>
20 #include <sys/malloc.h>
21 
22 #include <nfs/rpcv2.h>
23 #include <nfs/nfsv2.h>
24 #include <nfs/nfs.h>
25 #include <nfs/nfsnode.h>
26 #include <nfs/nfsmount.h>
27 #include <nfs/nqnfs.h>
28 
29 #define	NFSNOHASH(fhsum) \
30 	(&nfsnodehashtbl[(fhsum) & nfsnodehash])
31 LIST_HEAD(nfsnodehashhead, nfsnode) *nfsnodehashtbl;
32 u_long nfsnodehash;
33 
34 #define TRUE	1
35 #define	FALSE	0
36 
37 /*
38  * Initialize hash links for nfsnodes
39  * and build nfsnode free list.
40  */
41 nfs_nhinit()
42 {
43 
44 #ifndef lint
45 	if ((sizeof(struct nfsnode) - 1) & sizeof(struct nfsnode))
46 		printf("nfs_nhinit: bad size %d\n", sizeof(struct nfsnode));
47 #endif /* not lint */
48 	nfsnodehashtbl = hashinit(desiredvnodes, M_NFSNODE, &nfsnodehash);
49 }
50 
51 /*
52  * Compute an entry in the NFS hash table structure
53  */
54 struct nfsnodehashhead *
55 nfs_hash(fhp)
56 	register nfsv2fh_t *fhp;
57 {
58 	register u_char *fhpp;
59 	register u_long fhsum;
60 	int i;
61 
62 	fhpp = &fhp->fh_bytes[0];
63 	fhsum = 0;
64 	for (i = 0; i < NFSX_FH; i++)
65 		fhsum += *fhpp++;
66 	return (NFSNOHASH(fhsum));
67 }
68 
69 /*
70  * Look up a vnode/nfsnode by file handle.
71  * Callers must check for mount points!!
72  * In all cases, a pointer to a
73  * nfsnode structure is returned.
74  */
75 nfs_nget(mntp, fhp, npp)
76 	struct mount *mntp;
77 	register nfsv2fh_t *fhp;
78 	struct nfsnode **npp;
79 {
80 	register struct nfsnode *np;
81 	struct nfsnodehashhead *nhpp;
82 	register struct vnode *vp;
83 	extern int (**nfsv2_vnodeop_p)();
84 	struct vnode *nvp;
85 	int error;
86 
87 	nhpp = nfs_hash(fhp);
88 loop:
89 	for (np = nhpp->lh_first; np != 0; np = np->n_hash.le_next) {
90 		if (mntp != NFSTOV(np)->v_mount ||
91 		    bcmp((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH))
92 			continue;
93 		vp = NFSTOV(np);
94 		if (vget(vp, 1))
95 			goto loop;
96 		*npp = np;
97 		return(0);
98 	}
99 	if (error = getnewvnode(VT_NFS, mntp, nfsv2_vnodeop_p, &nvp)) {
100 		*npp = 0;
101 		return (error);
102 	}
103 	vp = nvp;
104 	MALLOC(np, struct nfsnode *, sizeof *np, M_NFSNODE, M_WAITOK);
105 	vp->v_data = np;
106 	np->n_vnode = vp;
107 	/*
108 	 * Insert the nfsnode in the hash queue for its new file handle
109 	 */
110 	np->n_flag = 0;
111 	LIST_INSERT_HEAD(nhpp, np, n_hash);
112 	bcopy((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH);
113 	np->n_attrstamp = 0;
114 	np->n_direofoffset = 0;
115 	np->n_sillyrename = (struct sillyrename *)0;
116 	np->n_size = 0;
117 	np->n_mtime = 0;
118 	if (VFSTONFS(mntp)->nm_flag & NFSMNT_NQNFS) {
119 		np->n_brev = 0;
120 		np->n_lrev = 0;
121 		np->n_expiry = (time_t)0;
122 		np->n_timer.cqe_next = (struct nfsnode *)0;
123 	}
124 	*npp = np;
125 	return (0);
126 }
127 
128 nfs_inactive(ap)
129 	struct vop_inactive_args /* {
130 		struct vnode *a_vp;
131 	} */ *ap;
132 {
133 	register struct nfsnode *np;
134 	register struct sillyrename *sp;
135 	struct proc *p = curproc;	/* XXX */
136 	extern int prtactive;
137 
138 	np = VTONFS(ap->a_vp);
139 	if (prtactive && ap->a_vp->v_usecount != 0)
140 		vprint("nfs_inactive: pushing active", ap->a_vp);
141 	sp = np->n_sillyrename;
142 	np->n_sillyrename = (struct sillyrename *)0;
143 	if (sp) {
144 		/*
145 		 * Remove the silly file that was rename'd earlier
146 		 */
147 		(void) nfs_vinvalbuf(ap->a_vp, 0, sp->s_cred, p, 1);
148 		nfs_removeit(sp);
149 		crfree(sp->s_cred);
150 		vrele(sp->s_dvp);
151 #ifdef SILLYSEPARATE
152 		free((caddr_t)sp, M_NFSREQ);
153 #endif
154 	}
155 	np->n_flag &= (NMODIFIED | NFLUSHINPROG | NFLUSHWANT | NQNFSEVICTED |
156 		NQNFSNONCACHE | NQNFSWRITE);
157 	return (0);
158 }
159 
160 /*
161  * Reclaim an nfsnode so that it can be used for other purposes.
162  */
163 nfs_reclaim(ap)
164 	struct vop_reclaim_args /* {
165 		struct vnode *a_vp;
166 	} */ *ap;
167 {
168 	register struct vnode *vp = ap->a_vp;
169 	register struct nfsnode *np = VTONFS(vp);
170 	register struct nfsmount *nmp = VFSTONFS(vp->v_mount);
171 	extern int prtactive;
172 
173 	if (prtactive && vp->v_usecount != 0)
174 		vprint("nfs_reclaim: pushing active", vp);
175 	LIST_REMOVE(np, n_hash);
176 
177 	/*
178 	 * For nqnfs, take it off the timer queue as required.
179 	 */
180 	if ((nmp->nm_flag & NFSMNT_NQNFS) && np->n_timer.cqe_next != 0)
181 		CIRCLEQ_REMOVE(&nmp->nm_timerhead, np, n_timer);
182 	cache_purge(vp);
183 	FREE(vp->v_data, M_NFSNODE);
184 	vp->v_data = (void *)0;
185 	return (0);
186 }
187 
188 /*
189  * Lock an nfsnode
190  */
191 nfs_lock(ap)
192 	struct vop_lock_args /* {
193 		struct vnode *a_vp;
194 	} */ *ap;
195 {
196 	register struct vnode *vp = ap->a_vp;
197 
198 	/*
199 	 * Ugh, another place where interruptible mounts will get hung.
200 	 * If you make this sleep interruptible, then you have to fix all
201 	 * the VOP_LOCK() calls to expect interruptibility.
202 	 */
203 	while (vp->v_flag & VXLOCK) {
204 		vp->v_flag |= VXWANT;
205 		sleep((caddr_t)vp, PINOD);
206 	}
207 	if (vp->v_tag == VT_NON)
208 		return (ENOENT);
209 	return (0);
210 }
211 
212 /*
213  * Unlock an nfsnode
214  */
215 nfs_unlock(ap)
216 	struct vop_unlock_args /* {
217 		struct vnode *a_vp;
218 	} */ *ap;
219 {
220 
221 	return (0);
222 }
223 
224 /*
225  * Check for a locked nfsnode
226  */
227 nfs_islocked(ap)
228 	struct vop_islocked_args /* {
229 		struct vnode *a_vp;
230 	} */ *ap;
231 {
232 
233 	return (0);
234 }
235 
236 /*
237  * Nfs abort op, called after namei() when a CREATE/DELETE isn't actually
238  * done. Currently nothing to do.
239  */
240 /* ARGSUSED */
241 int
242 nfs_abortop(ap)
243 	struct vop_abortop_args /* {
244 		struct vnode *a_dvp;
245 		struct componentname *a_cnp;
246 	} */ *ap;
247 {
248 
249 	if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
250 		FREE(ap->a_cnp->cn_pnbuf, M_NAMEI);
251 	return (0);
252 }
253