386BSD 0.1 development
[unix-history] / usr / src / sys.386bsd / nfs / nfs_node.c
CommitLineData
b688fc87
WJ
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 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * @(#)nfs_node.c 7.34 (Berkeley) 5/15/91
37 */
38
39#include "param.h"
40#include "systm.h"
41#include "proc.h"
42#include "mount.h"
43#include "namei.h"
44#include "vnode.h"
45#include "kernel.h"
46#include "malloc.h"
47
48#include "nfsv2.h"
49#include "nfs.h"
50#include "nfsnode.h"
51#include "nfsmount.h"
52
53/* The request list head */
54extern struct nfsreq nfsreqh;
55
56#define NFSNOHSZ 512
57#if ((NFSNOHSZ&(NFSNOHSZ-1)) == 0)
58#define NFSNOHASH(fhsum) ((fhsum)&(NFSNOHSZ-1))
59#else
60#define NFSNOHASH(fhsum) (((unsigned)(fhsum))%NFSNOHSZ)
61#endif
62
63union nhead {
64 union nhead *nh_head[2];
65 struct nfsnode *nh_chain[2];
66} nhead[NFSNOHSZ];
67
68#define TRUE 1
69#define FALSE 0
70
71/*
72 * Initialize hash links for nfsnodes
73 * and build nfsnode free list.
74 */
75nfs_nhinit()
76{
77 register int i;
78 register union nhead *nh = nhead;
79
80#ifndef lint
81 if (VN_MAXPRIVATE < sizeof(struct nfsnode))
82 panic("nfs_nhinit: too small");
83#endif /* not lint */
84 for (i = NFSNOHSZ; --i >= 0; nh++) {
85 nh->nh_head[0] = nh;
86 nh->nh_head[1] = nh;
87 }
88}
89
90/*
91 * Compute an entry in the NFS hash table structure
92 */
93union nhead *
94nfs_hash(fhp)
95 register nfsv2fh_t *fhp;
96{
97 register u_char *fhpp;
98 register u_long fhsum;
99 int i;
100
101 fhpp = &fhp->fh_bytes[0];
102 fhsum = 0;
103 for (i = 0; i < NFSX_FH; i++)
104 fhsum += *fhpp++;
105 return (&nhead[NFSNOHASH(fhsum)]);
106}
107
108/*
109 * Look up a vnode/nfsnode by file handle.
110 * Callers must check for mount points!!
111 * In all cases, a pointer to a
112 * nfsnode structure is returned.
113 */
114nfs_nget(mntp, fhp, npp)
115 struct mount *mntp;
116 register nfsv2fh_t *fhp;
117 struct nfsnode **npp;
118{
119 register struct nfsnode *np;
120 register struct vnode *vp;
121 extern struct vnodeops nfsv2_vnodeops;
122 struct vnode *nvp;
123 union nhead *nh;
124 int error;
125
126 nh = nfs_hash(fhp);
127loop:
128 for (np = nh->nh_chain[0]; np != (struct nfsnode *)nh; np = np->n_forw) {
129 if (mntp != NFSTOV(np)->v_mount ||
130 bcmp((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH))
131 continue;
132 if ((np->n_flag & NLOCKED) != 0) {
133 np->n_flag |= NWANT;
134 (void) tsleep((caddr_t)np, PINOD, "nfsnode", 0);
135 goto loop;
136 }
137 vp = NFSTOV(np);
138 if (vget(vp))
139 goto loop;
140 *npp = np;
141 return(0);
142 }
143 if (error = getnewvnode(VT_NFS, mntp, &nfsv2_vnodeops, &nvp)) {
144 *npp = 0;
145 return (error);
146 }
147 vp = nvp;
148 np = VTONFS(vp);
149 np->n_vnode = vp;
150 /*
151 * Insert the nfsnode in the hash queue for its new file handle
152 */
153 np->n_flag = 0;
154 insque(np, nh);
155 nfs_lock(vp);
156 bcopy((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH);
157 np->n_attrstamp = 0;
158 np->n_direofoffset = 0;
159 np->n_sillyrename = (struct sillyrename *)0;
160 np->n_size = 0;
161 np->n_mtime = 0;
162 *npp = np;
163 return (0);
164}
165
166nfs_inactive(vp, p)
167 struct vnode *vp;
168 struct proc *p;
169{
170 register struct nfsnode *np;
171 register struct sillyrename *sp;
172 struct nfsnode *dnp;
173 extern int prtactive;
174
175 np = VTONFS(vp);
176 if (prtactive && vp->v_usecount != 0)
177 vprint("nfs_inactive: pushing active", vp);
178 nfs_lock(vp);
179 sp = np->n_sillyrename;
180 np->n_sillyrename = (struct sillyrename *)0;
181 if (sp) {
182 /*
183 * Remove the silly file that was rename'd earlier
184 */
185 if (!nfs_nget(vp->v_mount, &sp->s_fh, &dnp)) {
186 sp->s_dvp = NFSTOV(dnp);
187 nfs_removeit(sp, p);
188 nfs_nput(sp->s_dvp);
189 }
190 crfree(sp->s_cred);
191 vrele(sp->s_dvp);
192 free((caddr_t)sp, M_NFSREQ);
193 }
194 nfs_unlock(vp);
195 np->n_flag &= NMODIFIED;
196#ifdef notdef
197 /*
198 * Scan the request list for any requests left hanging about
199 */
200 s = splnet();
201 rep = nfsreqh.r_next;
202 while (rep && rep != &nfsreqh) {
203 if (rep->r_vp == vp) {
204 rep->r_prev->r_next = rep2 = rep->r_next;
205 rep->r_next->r_prev = rep->r_prev;
206 m_freem(rep->r_mreq);
207 if (rep->r_mrep != NULL)
208 m_freem(rep->r_mrep);
209 free((caddr_t)rep, M_NFSREQ);
210 rep = rep2;
211 } else
212 rep = rep->r_next;
213 }
214 splx(s);
215#endif
216 return (0);
217}
218
219/*
220 * Reclaim an nfsnode so that it can be used for other purposes.
221 */
222nfs_reclaim(vp)
223 register struct vnode *vp;
224{
225 register struct nfsnode *np = VTONFS(vp);
226 extern int prtactive;
227
228 if (prtactive && vp->v_usecount != 0)
229 vprint("nfs_reclaim: pushing active", vp);
230 /*
231 * Remove the nfsnode from its hash chain.
232 */
233 remque(np);
234 np->n_forw = np;
235 np->n_back = np;
236 cache_purge(vp);
237 np->n_flag = 0;
238 np->n_direofoffset = 0;
239 return (0);
240}
241
242/*
243 * In theory, NFS does not need locking, but we make provision
244 * for doing it just in case it is needed.
245 */
246int donfslocking = 0;
247/*
248 * Lock an nfsnode
249 */
250
251nfs_lock(vp)
252 struct vnode *vp;
253{
254 register struct nfsnode *np = VTONFS(vp);
255
256 if (!donfslocking)
257 return;
258 while (np->n_flag & NLOCKED) {
259 np->n_flag |= NWANT;
260 if (np->n_lockholder == curproc->p_pid)
261 panic("locking against myself");
262 np->n_lockwaiter = curproc->p_pid;
263 (void) tsleep((caddr_t)np, PINOD, "nfslock", 0);
264 }
265 np->n_lockwaiter = 0;
266 np->n_lockholder = curproc->p_pid;
267 np->n_flag |= NLOCKED;
268}
269
270/*
271 * Unlock an nfsnode
272 */
273nfs_unlock(vp)
274 struct vnode *vp;
275{
276 register struct nfsnode *np = VTONFS(vp);
277
278 np->n_lockholder = 0;
279 np->n_flag &= ~NLOCKED;
280 if (np->n_flag & NWANT) {
281 np->n_flag &= ~NWANT;
282 wakeup((caddr_t)np);
283 }
284}
285
286/*
287 * Check for a locked nfsnode
288 */
289nfs_islocked(vp)
290 struct vnode *vp;
291{
292
293 if (VTONFS(vp)->n_flag & NLOCKED)
294 return (1);
295 return (0);
296}
297
298/*
299 * Unlock and vrele()
300 * since I can't decide if dirs. should be locked, I will check for
301 * the lock and be flexible
302 */
303nfs_nput(vp)
304 struct vnode *vp;
305{
306 register struct nfsnode *np = VTONFS(vp);
307
308 if (np->n_flag & NLOCKED)
309 nfs_unlock(vp);
310 vrele(vp);
311}
312
313/*
314 * Nfs abort op, called after namei() when a CREATE/DELETE isn't actually
315 * done. Currently nothing to do.
316 */
317/* ARGSUSED */
318nfs_abortop(ndp)
319 struct nameidata *ndp;
320{
321
322 if ((ndp->ni_nameiop & (HASBUF | SAVESTART)) == HASBUF)
323 FREE(ndp->ni_pnbuf, M_NAMEI);
324 return (0);
325}