xref: /csrg-svn/sys/nfs/nfs_node.c (revision 51985)
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.35 (Berkeley) 12/16/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 ((sizeof(struct nfsnode) - 1) & sizeof(struct nfsnode))
56 		printf("nfs_nhinit: bad size %d\n", sizeof(struct nfsnode));
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 	MALLOC(np, struct nfsnode *, sizeof *np, M_NFSNODE, M_WAITOK);
123 	vp->v_data = np;
124 	np->n_vnode = vp;
125 	/*
126 	 * Insert the nfsnode in the hash queue for its new file handle
127 	 */
128 	np->n_flag = 0;
129 	insque(np, nh);
130 	nfs_lock(vp);
131 	bcopy((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH);
132 	np->n_attrstamp = 0;
133 	np->n_direofoffset = 0;
134 	np->n_sillyrename = (struct sillyrename *)0;
135 	np->n_size = 0;
136 	np->n_mtime = 0;
137 	*npp = np;
138 	return (0);
139 }
140 
141 nfs_inactive(vp, p)
142 	struct vnode *vp;
143 	struct proc *p;
144 {
145 	register struct nfsnode *np;
146 	register struct sillyrename *sp;
147 	struct nfsnode *dnp;
148 	extern int prtactive;
149 
150 	np = VTONFS(vp);
151 	if (prtactive && vp->v_usecount != 0)
152 		vprint("nfs_inactive: pushing active", vp);
153 	nfs_lock(vp);
154 	sp = np->n_sillyrename;
155 	np->n_sillyrename = (struct sillyrename *)0;
156 	if (sp) {
157 		/*
158 		 * Remove the silly file that was rename'd earlier
159 		 */
160 		if (!nfs_nget(vp->v_mount, &sp->s_fh, &dnp)) {
161 			sp->s_dvp = NFSTOV(dnp);
162 			nfs_removeit(sp, p);
163 			nfs_nput(sp->s_dvp);
164 		}
165 		crfree(sp->s_cred);
166 		vrele(sp->s_dvp);
167 #ifdef SILLYSEPARATE
168 		free((caddr_t)sp, M_NFSREQ);
169 #endif
170 	}
171 	nfs_unlock(vp);
172 	np->n_flag &= NMODIFIED;
173 #ifdef notdef
174 	/*
175 	 * Scan the request list for any requests left hanging about
176 	 */
177 	s = splnet();
178 	rep = nfsreqh.r_next;
179 	while (rep && rep != &nfsreqh) {
180 		if (rep->r_vp == vp) {
181 			rep->r_prev->r_next = rep2 = rep->r_next;
182 			rep->r_next->r_prev = rep->r_prev;
183 			m_freem(rep->r_mreq);
184 			if (rep->r_mrep != NULL)
185 				m_freem(rep->r_mrep);
186 			free((caddr_t)rep, M_NFSREQ);
187 			rep = rep2;
188 		} else
189 			rep = rep->r_next;
190 	}
191 	splx(s);
192 #endif
193 	return (0);
194 }
195 
196 /*
197  * Reclaim an nfsnode so that it can be used for other purposes.
198  */
199 nfs_reclaim(vp)
200 	register struct vnode *vp;
201 {
202 	register struct nfsnode *np = VTONFS(vp);
203 	extern int prtactive;
204 
205 	if (prtactive && vp->v_usecount != 0)
206 		vprint("nfs_reclaim: pushing active", vp);
207 	/*
208 	 * Remove the nfsnode from its hash chain.
209 	 */
210 	remque(np);
211 	cache_purge(vp);
212 	FREE(vp->v_data, M_NFSNODE);
213 	vp->v_data = NULL;
214 	return (0);
215 }
216 
217 /*
218  * In theory, NFS does not need locking, but we make provision
219  * for doing it just in case it is needed.
220  */
221 int donfslocking = 0;
222 /*
223  * Lock an nfsnode
224  */
225 
226 nfs_lock(vp)
227 	struct vnode *vp;
228 {
229 	register struct nfsnode *np = VTONFS(vp);
230 
231 	if (!donfslocking)
232 		return;
233 	while (np->n_flag & NLOCKED) {
234 		np->n_flag |= NWANT;
235 		if (np->n_lockholder == curproc->p_pid)
236 			panic("locking against myself");
237 		np->n_lockwaiter = curproc->p_pid;
238 		(void) tsleep((caddr_t)np, PINOD, "nfslock", 0);
239 	}
240 	np->n_lockwaiter = 0;
241 	np->n_lockholder = curproc->p_pid;
242 	np->n_flag |= NLOCKED;
243 }
244 
245 /*
246  * Unlock an nfsnode
247  */
248 nfs_unlock(vp)
249 	struct vnode *vp;
250 {
251 	register struct nfsnode *np = VTONFS(vp);
252 
253 	np->n_lockholder = 0;
254 	np->n_flag &= ~NLOCKED;
255 	if (np->n_flag & NWANT) {
256 		np->n_flag &= ~NWANT;
257 		wakeup((caddr_t)np);
258 	}
259 }
260 
261 /*
262  * Check for a locked nfsnode
263  */
264 nfs_islocked(vp)
265 	struct vnode *vp;
266 {
267 
268 	if (VTONFS(vp)->n_flag & NLOCKED)
269 		return (1);
270 	return (0);
271 }
272 
273 /*
274  * Unlock and vrele()
275  * since I can't decide if dirs. should be locked, I will check for
276  * the lock and be flexible
277  */
278 nfs_nput(vp)
279 	struct vnode *vp;
280 {
281 	register struct nfsnode *np = VTONFS(vp);
282 
283 	if (np->n_flag & NLOCKED)
284 		nfs_unlock(vp);
285 	vrele(vp);
286 }
287 
288 /*
289  * Nfs abort op, called after namei() when a CREATE/DELETE isn't actually
290  * done. Currently nothing to do.
291  */
292 /* ARGSUSED */
293 nfs_abortop(ndp)
294 	struct nameidata *ndp;
295 {
296 
297 	if ((ndp->ni_nameiop & (HASBUF | SAVESTART)) == HASBUF)
298 		FREE(ndp->ni_pnbuf, M_NAMEI);
299 	return (0);
300 }
301