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