xref: /netbsd-src/sys/nfs/nfs_node.c (revision 0b9f50897e9a9c6709320fafb4c3787fddcc0a45)
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * 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  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  *	from: @(#)nfs_node.c	7.34 (Berkeley) 5/15/91
37  *	$Id: nfs_node.c,v 1.3 1993/07/28 02:22:25 cgd Exp $
38  */
39 
40 #include "param.h"
41 #include "systm.h"
42 #include "proc.h"
43 #include "mount.h"
44 #include "namei.h"
45 #include "vnode.h"
46 #include "kernel.h"
47 #include "malloc.h"
48 
49 #include "nfsv2.h"
50 #include "nfs.h"
51 #include "nfsnode.h"
52 #include "nfsmount.h"
53 
54 /* The request list head */
55 extern struct nfsreq nfsreqh;
56 
57 #define	NFSNOHSZ	512
58 #if	((NFSNOHSZ&(NFSNOHSZ-1)) == 0)
59 #define	NFSNOHASH(fhsum)	((fhsum)&(NFSNOHSZ-1))
60 #else
61 #define	NFSNOHASH(fhsum)	(((unsigned)(fhsum))%NFSNOHSZ)
62 #endif
63 
64 union nhead {
65 	union  nhead *nh_head[2];
66 	struct nfsnode *nh_chain[2];
67 } nhead[NFSNOHSZ];
68 
69 #define TRUE	1
70 #define	FALSE	0
71 
72 /*
73  * Initialize hash links for nfsnodes
74  * and build nfsnode free list.
75  */
76 nfs_nhinit()
77 {
78 	register int i;
79 	register union  nhead *nh = nhead;
80 
81 #ifndef lint
82 	if (VN_MAXPRIVATE < sizeof(struct nfsnode))
83 		panic("nfs_nhinit: too small");
84 #endif /* not lint */
85 	for (i = NFSNOHSZ; --i >= 0; nh++) {
86 		nh->nh_head[0] = nh;
87 		nh->nh_head[1] = nh;
88 	}
89 }
90 
91 /*
92  * Compute an entry in the NFS hash table structure
93  */
94 union nhead *
95 nfs_hash(fhp)
96 	register nfsv2fh_t *fhp;
97 {
98 	register u_char *fhpp;
99 	register u_long fhsum;
100 	int i;
101 
102 	fhpp = &fhp->fh_bytes[0];
103 	fhsum = 0;
104 	for (i = 0; i < NFSX_FH; i++)
105 		fhsum += *fhpp++;
106 	return (&nhead[NFSNOHASH(fhsum)]);
107 }
108 
109 /*
110  * Look up a vnode/nfsnode by file handle.
111  * Callers must check for mount points!!
112  * In all cases, a pointer to a
113  * nfsnode structure is returned.
114  */
115 nfs_nget(mntp, fhp, npp)
116 	struct mount *mntp;
117 	register nfsv2fh_t *fhp;
118 	struct nfsnode **npp;
119 {
120 	register struct nfsnode *np;
121 	register struct vnode *vp;
122 	extern struct vnodeops nfsv2_vnodeops;
123 	struct vnode *nvp;
124 	union nhead *nh;
125 	int error;
126 
127 	nh = nfs_hash(fhp);
128 loop:
129 	for (np = nh->nh_chain[0]; np != (struct nfsnode *)nh; np = np->n_forw) {
130 		if (mntp != NFSTOV(np)->v_mount ||
131 		    bcmp((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH))
132 			continue;
133 		if ((np->n_flag & NLOCKED) != 0) {
134 			np->n_flag |= NWANT;
135 			(void) tsleep((caddr_t)np, PINOD, "nfsnode", 0);
136 			goto loop;
137 		}
138 		vp = NFSTOV(np);
139 		if (vget(vp))
140 			goto loop;
141 		*npp = np;
142 		return(0);
143 	}
144 	if (error = getnewvnode(VT_NFS, mntp, &nfsv2_vnodeops, &nvp)) {
145 		*npp = 0;
146 		return (error);
147 	}
148 	vp = nvp;
149 	np = VTONFS(vp);
150 	np->n_vnode = vp;
151 	/*
152 	 * Insert the nfsnode in the hash queue for its new file handle
153 	 */
154 	np->n_flag = 0;
155 	insque(np, nh);
156 	nfs_lock(vp);
157 	bcopy((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH);
158 	np->n_attrstamp = 0;
159 	np->n_direofoffset = 0;
160 	np->n_sillyrename = (struct sillyrename *)0;
161 	np->n_size = 0;
162 	np->n_mtime = 0;
163 	np->n_lockf = 0;
164 	*npp = np;
165 	return (0);
166 }
167 
168 nfs_inactive(vp, p)
169 	struct vnode *vp;
170 	struct proc *p;
171 {
172 	register struct nfsnode *np;
173 	register struct sillyrename *sp;
174 	struct nfsnode *dnp;
175 	extern int prtactive;
176 
177 	np = VTONFS(vp);
178 	if (prtactive && vp->v_usecount != 0)
179 		vprint("nfs_inactive: pushing active", vp);
180 	nfs_lock(vp);
181 	sp = np->n_sillyrename;
182 	np->n_sillyrename = (struct sillyrename *)0;
183 	if (sp) {
184 		/*
185 		 * Remove the silly file that was rename'd earlier
186 		 */
187 		if (!nfs_nget(vp->v_mount, &sp->s_fh, &dnp)) {
188 			sp->s_dvp = NFSTOV(dnp);
189 			nfs_removeit(sp, p);
190 			nfs_nput(sp->s_dvp);
191 		}
192 		crfree(sp->s_cred);
193 		vrele(sp->s_dvp);
194 		free((caddr_t)sp, M_NFSREQ);
195 	}
196 	nfs_unlock(vp);
197 	np->n_flag &= NMODIFIED;
198 #ifdef notdef
199 	/*
200 	 * Scan the request list for any requests left hanging about
201 	 */
202 	s = splnet();
203 	rep = nfsreqh.r_next;
204 	while (rep && rep != &nfsreqh) {
205 		if (rep->r_vp == vp) {
206 			rep->r_prev->r_next = rep2 = rep->r_next;
207 			rep->r_next->r_prev = rep->r_prev;
208 			m_freem(rep->r_mreq);
209 			if (rep->r_mrep != NULL)
210 				m_freem(rep->r_mrep);
211 			free((caddr_t)rep, M_NFSREQ);
212 			rep = rep2;
213 		} else
214 			rep = rep->r_next;
215 	}
216 	splx(s);
217 #endif
218 	return (0);
219 }
220 
221 /*
222  * Reclaim an nfsnode so that it can be used for other purposes.
223  */
224 nfs_reclaim(vp)
225 	register struct vnode *vp;
226 {
227 	register struct nfsnode *np = VTONFS(vp);
228 	extern int prtactive;
229 
230 	if (prtactive && vp->v_usecount != 0)
231 		vprint("nfs_reclaim: pushing active", vp);
232 	/*
233 	 * Remove the nfsnode from its hash chain.
234 	 */
235 	remque(np);
236 	np->n_forw = np;
237 	np->n_back = np;
238 	cache_purge(vp);
239 	np->n_flag = 0;
240 	np->n_direofoffset = 0;
241 	return (0);
242 }
243 
244 /*
245  * In theory, NFS does not need locking, but we make provision
246  * for doing it just in case it is needed.
247  */
248 int donfslocking = 0;
249 /*
250  * Lock an nfsnode
251  */
252 
253 nfs_lock(vp)
254 	struct vnode *vp;
255 {
256 	register struct nfsnode *np = VTONFS(vp);
257 
258 	if (!donfslocking)
259 		return;
260 	while (np->n_flag & NLOCKED) {
261 		np->n_flag |= NWANT;
262 		if (np->n_lockholder == curproc->p_pid)
263 			panic("locking against myself");
264 		np->n_lockwaiter = curproc->p_pid;
265 		(void) tsleep((caddr_t)np, PINOD, "nfslock", 0);
266 	}
267 	np->n_lockwaiter = 0;
268 	np->n_lockholder = curproc->p_pid;
269 	np->n_flag |= NLOCKED;
270 }
271 
272 /*
273  * Unlock an nfsnode
274  */
275 nfs_unlock(vp)
276 	struct vnode *vp;
277 {
278 	register struct nfsnode *np = VTONFS(vp);
279 
280 	np->n_lockholder = 0;
281 	np->n_flag &= ~NLOCKED;
282 	if (np->n_flag & NWANT) {
283 		np->n_flag &= ~NWANT;
284 		wakeup((caddr_t)np);
285 	}
286 }
287 
288 /*
289  * Check for a locked nfsnode
290  */
291 nfs_islocked(vp)
292 	struct vnode *vp;
293 {
294 
295 	if (VTONFS(vp)->n_flag & NLOCKED)
296 		return (1);
297 	return (0);
298 }
299 
300 /*
301  * Unlock and vrele()
302  * since I can't decide if dirs. should be locked, I will check for
303  * the lock and be flexible
304  */
305 nfs_nput(vp)
306 	struct vnode *vp;
307 {
308 	register struct nfsnode *np = VTONFS(vp);
309 
310 	if (np->n_flag & NLOCKED)
311 		nfs_unlock(vp);
312 	vrele(vp);
313 }
314 
315 /*
316  * Nfs abort op, called after namei() when a CREATE/DELETE isn't actually
317  * done. Currently nothing to do.
318  */
319 /* ARGSUSED */
320 nfs_abortop(ndp)
321 	struct nameidata *ndp;
322 {
323 
324 	if ((ndp->ni_nameiop & (HASBUF | SAVESTART)) == HASBUF)
325 		FREE(ndp->ni_pnbuf, M_NAMEI);
326 	return (0);
327 }
328