xref: /csrg-svn/sys/nfs/nfs_node.c (revision 48052)
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.31 (Berkeley) 04/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 (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 nameidata *ndp;
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 		ndp = &sp->s_namei;
161 		if (!nfs_nget(vp->v_mount, &sp->s_fh, &dnp)) {
162 			ndp->ni_dvp = NFSTOV(dnp);
163 			nfs_removeit(ndp, p);
164 			nfs_nput(ndp->ni_dvp);
165 		}
166 		crfree(ndp->ni_cred);
167 		free((caddr_t)sp, M_TEMP);
168 	}
169 	nfs_unlock(vp);
170 	np->n_flag &= NMODIFIED;
171 #ifdef notdef
172 	/*
173 	 * Scan the request list for any requests left hanging about
174 	 */
175 	s = splnet();
176 	rep = nfsreqh.r_next;
177 	while (rep && rep != &nfsreqh) {
178 		if (rep->r_vp == vp) {
179 			rep->r_prev->r_next = rep2 = rep->r_next;
180 			rep->r_next->r_prev = rep->r_prev;
181 			m_freem(rep->r_mreq);
182 			if (rep->r_mrep != NULL)
183 				m_freem(rep->r_mrep);
184 			free((caddr_t)rep, M_NFSREQ);
185 			rep = rep2;
186 		} else
187 			rep = rep->r_next;
188 	}
189 	splx(s);
190 #endif
191 	return (0);
192 }
193 
194 /*
195  * Reclaim an nfsnode so that it can be used for other purposes.
196  */
197 nfs_reclaim(vp)
198 	register struct vnode *vp;
199 {
200 	register struct nfsnode *np = VTONFS(vp);
201 	extern int prtactive;
202 
203 	if (prtactive && vp->v_usecount != 0)
204 		vprint("nfs_reclaim: pushing active", vp);
205 	/*
206 	 * Remove the nfsnode from its hash chain.
207 	 */
208 	remque(np);
209 	np->n_forw = np;
210 	np->n_back = np;
211 	cache_purge(vp);
212 	np->n_flag = 0;
213 	np->n_direofoffset = 0;
214 	return (0);
215 }
216 
217 /*
218  * Lock an nfsnode
219  */
220 nfs_lock(vp)
221 	struct vnode *vp;
222 {
223 	register struct nfsnode *np = VTONFS(vp);
224 
225 	while (np->n_flag & NLOCKED) {
226 		np->n_flag |= NWANT;
227 		if (np->n_lockholder == curproc->p_pid)
228 			panic("locking against myself");
229 		np->n_lockwaiter = curproc->p_pid;
230 		(void) tsleep((caddr_t)np, PINOD, "nfslock", 0);
231 	}
232 	np->n_lockwaiter = 0;
233 	np->n_lockholder = curproc->p_pid;
234 	np->n_flag |= NLOCKED;
235 }
236 
237 /*
238  * Unlock an nfsnode
239  */
240 nfs_unlock(vp)
241 	struct vnode *vp;
242 {
243 	register struct nfsnode *np = VTONFS(vp);
244 
245 	if ((np->n_flag & NLOCKED) == 0)
246 		vprint("nfs_unlock: unlocked nfsnode", vp);
247 	np->n_lockholder = 0;
248 	np->n_flag &= ~NLOCKED;
249 	if (np->n_flag & NWANT) {
250 		np->n_flag &= ~NWANT;
251 		wakeup((caddr_t)np);
252 	}
253 }
254 
255 /*
256  * Check for a locked nfsnode
257  */
258 nfs_islocked(vp)
259 	struct vnode *vp;
260 {
261 
262 	if (VTONFS(vp)->n_flag & NLOCKED)
263 		return (1);
264 	return (0);
265 }
266 
267 /*
268  * Unlock and vrele()
269  * since I can't decide if dirs. should be locked, I will check for
270  * the lock and be flexible
271  */
272 nfs_nput(vp)
273 	struct vnode *vp;
274 {
275 	register struct nfsnode *np = VTONFS(vp);
276 
277 	if (np->n_flag & NLOCKED)
278 		nfs_unlock(vp);
279 	vrele(vp);
280 }
281 
282 /*
283  * Nfs abort op, called after namei() when a CREATE/DELETE isn't actually
284  * done. Currently nothing to do.
285  */
286 /* ARGSUSED */
287 nfs_abortop(ndp)
288 	struct nameidata *ndp;
289 {
290 
291 	return (0);
292 }
293