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