xref: /original-bsd/sys/nfs/nfs_node.c (revision b7261a4b)
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 are permitted
9  * provided that the above copyright notice and this paragraph are
10  * duplicated in all such forms and that any documentation,
11  * advertising materials, and other materials related to such
12  * distribution and use acknowledge that the software was developed
13  * by the University of California, Berkeley.  The name of the
14  * University may not be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19  *
20  *	@(#)nfs_node.c	7.28 (Berkeley) 06/21/90
21  */
22 
23 #include "param.h"
24 #include "systm.h"
25 #include "user.h"
26 #include "proc.h"
27 #include "mount.h"
28 #include "vnode.h"
29 #include "errno.h"
30 #include "nfsv2.h"
31 #include "nfs.h"
32 #include "nfsnode.h"
33 #include "nfsmount.h"
34 #include "kernel.h"
35 #include "malloc.h"
36 
37 /* The request list head */
38 extern struct nfsreq nfsreqh;
39 
40 #define	NFSNOHSZ	512
41 #if	((NFSNOHSZ&(NFSNOHSZ-1)) == 0)
42 #define	NFSNOHASH(fhsum)	((fhsum)&(NFSNOHSZ-1))
43 #else
44 #define	NFSNOHASH(fhsum)	(((unsigned)(fhsum))%NFSNOHSZ)
45 #endif
46 
47 union nhead {
48 	union  nhead *nh_head[2];
49 	struct nfsnode *nh_chain[2];
50 } nhead[NFSNOHSZ];
51 
52 #define TRUE	1
53 #define	FALSE	0
54 
55 /*
56  * Initialize hash links for nfsnodes
57  * and build nfsnode free list.
58  */
59 nfs_nhinit()
60 {
61 	register int i;
62 	register union  nhead *nh = nhead;
63 
64 #ifndef lint
65 	if (VN_MAXPRIVATE < sizeof(struct nfsnode))
66 		panic("nfs_nhinit: too small");
67 #endif /* not lint */
68 	for (i = NFSNOHSZ; --i >= 0; nh++) {
69 		nh->nh_head[0] = nh;
70 		nh->nh_head[1] = nh;
71 	}
72 }
73 
74 /*
75  * Compute an entry in the NFS hash table structure
76  */
77 union nhead *
78 nfs_hash(fhp)
79 	register nfsv2fh_t *fhp;
80 {
81 	register u_char *fhpp;
82 	register u_long fhsum;
83 	int i;
84 
85 	fhpp = &fhp->fh_bytes[0];
86 	fhsum = 0;
87 	for (i = 0; i < NFSX_FH; i++)
88 		fhsum += *fhpp++;
89 	return (&nhead[NFSNOHASH(fhsum)]);
90 }
91 
92 /*
93  * Look up a vnode/nfsnode by file handle.
94  * Callers must check for mount points!!
95  * In all cases, a pointer to a
96  * nfsnode structure is returned.
97  */
98 nfs_nget(mntp, fhp, npp)
99 	struct mount *mntp;
100 	register nfsv2fh_t *fhp;
101 	struct nfsnode **npp;
102 {
103 	register struct nfsnode *np;
104 	register struct vnode *vp;
105 	extern struct vnodeops nfsv2_vnodeops;
106 	struct vnode *nvp;
107 	union nhead *nh;
108 	int error;
109 
110 	nh = nfs_hash(fhp);
111 loop:
112 	for (np = nh->nh_chain[0]; np != (struct nfsnode *)nh; np = np->n_forw) {
113 		if (mntp != NFSTOV(np)->v_mount ||
114 		    bcmp((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH))
115 			continue;
116 		if ((np->n_flag & NLOCKED) != 0) {
117 			np->n_flag |= NWANT;
118 			(void) tsleep((caddr_t)np, PINOD, "nfsnode", 0);
119 			goto loop;
120 		}
121 		vp = NFSTOV(np);
122 		if (vget(vp))
123 			goto loop;
124 		*npp = np;
125 		return(0);
126 	}
127 	if (error = getnewvnode(VT_NFS, mntp, &nfsv2_vnodeops, &nvp)) {
128 		*npp = 0;
129 		return (error);
130 	}
131 	vp = nvp;
132 	np = VTONFS(vp);
133 	np->n_vnode = vp;
134 	/*
135 	 * Insert the nfsnode in the hash queue for its new file handle
136 	 */
137 	np->n_flag = 0;
138 	insque(np, nh);
139 	nfs_lock(vp);
140 	bcopy((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH);
141 	np->n_attrstamp = 0;
142 	np->n_direofoffset = 0;
143 	np->n_sillyrename = (struct sillyrename *)0;
144 	np->n_size = 0;
145 	np->n_mtime = 0;
146 	*npp = np;
147 	return (0);
148 }
149 
150 nfs_inactive(vp)
151 	struct vnode *vp;
152 {
153 	register struct nfsnode *np;
154 	register struct nameidata *ndp;
155 	register struct sillyrename *sp;
156 	struct nfsnode *dnp;
157 	extern int prtactive;
158 
159 	np = VTONFS(vp);
160 	if (prtactive && vp->v_usecount != 0)
161 		vprint("nfs_inactive: pushing active", vp);
162 	nfs_lock(vp);
163 	sp = np->n_sillyrename;
164 	np->n_sillyrename = (struct sillyrename *)0;
165 	if (sp) {
166 		/*
167 		 * Remove the silly file that was rename'd earlier
168 		 */
169 		ndp = &sp->s_namei;
170 		if (!nfs_nget(vp->v_mount, &sp->s_fh, &dnp)) {
171 			ndp->ni_dvp = NFSTOV(dnp);
172 			nfs_removeit(ndp);
173 			nfs_nput(ndp->ni_dvp);
174 		}
175 		crfree(ndp->ni_cred);
176 		free((caddr_t)sp, M_TEMP);
177 	}
178 	nfs_unlock(vp);
179 	np->n_flag &= NMODIFIED;
180 #ifdef notdef
181 	/*
182 	 * Scan the request list for any requests left hanging about
183 	 */
184 	s = splnet();
185 	rep = nfsreqh.r_next;
186 	while (rep && rep != &nfsreqh) {
187 		if (rep->r_vp == vp) {
188 			rep->r_prev->r_next = rep2 = rep->r_next;
189 			rep->r_next->r_prev = rep->r_prev;
190 			m_freem(rep->r_mreq);
191 			if (rep->r_mrep != NULL)
192 				m_freem(rep->r_mrep);
193 			free((caddr_t)rep, M_NFSREQ);
194 			rep = rep2;
195 		} else
196 			rep = rep->r_next;
197 	}
198 	splx(s);
199 #endif
200 	return (0);
201 }
202 
203 /*
204  * Reclaim an nfsnode so that it can be used for other purposes.
205  */
206 nfs_reclaim(vp)
207 	register struct vnode *vp;
208 {
209 	register struct nfsnode *np = VTONFS(vp);
210 	extern int prtactive;
211 
212 	if (prtactive && vp->v_usecount != 0)
213 		vprint("nfs_reclaim: pushing active", vp);
214 	/*
215 	 * Remove the nfsnode from its hash chain.
216 	 */
217 	remque(np);
218 	np->n_forw = np;
219 	np->n_back = np;
220 	cache_purge(vp);
221 	np->n_flag = 0;
222 	np->n_direofoffset = 0;
223 	return (0);
224 }
225 
226 /*
227  * Lock an nfsnode
228  */
229 nfs_lock(vp)
230 	struct vnode *vp;
231 {
232 	register struct nfsnode *np = VTONFS(vp);
233 
234 	while (np->n_flag & NLOCKED) {
235 		np->n_flag |= NWANT;
236 		if (np->n_lockholder == u.u_procp->p_pid)
237 			panic("locking against myself");
238 		np->n_lockwaiter = u.u_procp->p_pid;
239 		(void) tsleep((caddr_t)np, PINOD, "nfslock", 0);
240 	}
241 	np->n_lockwaiter = 0;
242 	np->n_lockholder = u.u_procp->p_pid;
243 	u.u_spare[0]++;
244 	np->n_flag |= NLOCKED;
245 }
246 
247 /*
248  * Unlock an nfsnode
249  */
250 nfs_unlock(vp)
251 	struct vnode *vp;
252 {
253 	register struct nfsnode *np = VTONFS(vp);
254 
255 	if ((np->n_flag & NLOCKED) == 0)
256 		vprint("nfs_unlock: unlocked nfsnode", vp);
257 	np->n_lockholder = 0;
258 	u.u_spare[0]--;
259 	np->n_flag &= ~NLOCKED;
260 	if (np->n_flag & NWANT) {
261 		np->n_flag &= ~NWANT;
262 		wakeup((caddr_t)np);
263 	}
264 }
265 
266 /*
267  * Check for a locked nfsnode
268  */
269 nfs_islocked(vp)
270 	struct vnode *vp;
271 {
272 
273 	if (VTONFS(vp)->n_flag & NLOCKED)
274 		return (1);
275 	return (0);
276 }
277 
278 /*
279  * Unlock and vrele()
280  * since I can't decide if dirs. should be locked, I will check for
281  * the lock and be flexible
282  */
283 nfs_nput(vp)
284 	struct vnode *vp;
285 {
286 	register struct nfsnode *np = VTONFS(vp);
287 
288 	if (np->n_flag & NLOCKED)
289 		nfs_unlock(vp);
290 	vrele(vp);
291 }
292 
293 /*
294  * Nfs abort op, called after namei() when a CREATE/DELETE isn't actually
295  * done. Currently nothing to do.
296  */
297 /* ARGSUSED */
298 nfs_abortop(ndp)
299 	struct nameidata *ndp;
300 {
301 
302 	return (0);
303 }
304