xref: /original-bsd/sys/nfs/nfs_node.c (revision ba762ddc)
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.32 (Berkeley) 04/19/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  * Lock an nfsnode
218  */
219 nfs_lock(vp)
220 	struct vnode *vp;
221 {
222 	register struct nfsnode *np = VTONFS(vp);
223 
224 	while (np->n_flag & NLOCKED) {
225 		np->n_flag |= NWANT;
226 		if (np->n_lockholder == curproc->p_pid)
227 			panic("locking against myself");
228 		np->n_lockwaiter = curproc->p_pid;
229 		(void) tsleep((caddr_t)np, PINOD, "nfslock", 0);
230 	}
231 	np->n_lockwaiter = 0;
232 	np->n_lockholder = curproc->p_pid;
233 	np->n_flag |= NLOCKED;
234 }
235 
236 /*
237  * Unlock an nfsnode
238  */
239 nfs_unlock(vp)
240 	struct vnode *vp;
241 {
242 	register struct nfsnode *np = VTONFS(vp);
243 
244 	if ((np->n_flag & NLOCKED) == 0)
245 		vprint("nfs_unlock: unlocked nfsnode", vp);
246 	np->n_lockholder = 0;
247 	np->n_flag &= ~NLOCKED;
248 	if (np->n_flag & NWANT) {
249 		np->n_flag &= ~NWANT;
250 		wakeup((caddr_t)np);
251 	}
252 }
253 
254 /*
255  * Check for a locked nfsnode
256  */
257 nfs_islocked(vp)
258 	struct vnode *vp;
259 {
260 
261 	if (VTONFS(vp)->n_flag & NLOCKED)
262 		return (1);
263 	return (0);
264 }
265 
266 /*
267  * Unlock and vrele()
268  * since I can't decide if dirs. should be locked, I will check for
269  * the lock and be flexible
270  */
271 nfs_nput(vp)
272 	struct vnode *vp;
273 {
274 	register struct nfsnode *np = VTONFS(vp);
275 
276 	if (np->n_flag & NLOCKED)
277 		nfs_unlock(vp);
278 	vrele(vp);
279 }
280 
281 /*
282  * Nfs abort op, called after namei() when a CREATE/DELETE isn't actually
283  * done. Currently nothing to do.
284  */
285 /* ARGSUSED */
286 nfs_abortop(ndp)
287 	struct nameidata *ndp;
288 {
289 
290 	return (0);
291 }
292