xref: /openbsd-src/sys/nfs/nfs_node.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: nfs_node.c,v 1.44 2008/12/24 02:43:52 thib Exp $	*/
2 /*	$NetBSD: nfs_node.c,v 1.16 1996/02/18 11:53:42 fvdl Exp $	*/
3 
4 /*
5  * Copyright (c) 1989, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Rick Macklem at The University of Guelph.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  *	@(#)nfs_node.c	8.6 (Berkeley) 5/22/95
36  */
37 
38 
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/proc.h>
42 #include <sys/mount.h>
43 #include <sys/namei.h>
44 #include <sys/vnode.h>
45 #include <sys/kernel.h>
46 #include <sys/malloc.h>
47 #include <sys/pool.h>
48 #include <sys/hash.h>
49 #include <sys/rwlock.h>
50 #include <sys/queue.h>
51 
52 #include <nfs/rpcv2.h>
53 #include <nfs/nfsproto.h>
54 #include <nfs/nfs.h>
55 #include <nfs/nfsnode.h>
56 #include <nfs/nfsmount.h>
57 #include <nfs/nfs_var.h>
58 
59 LIST_HEAD(nfsnodehashhead, nfsnode) *nfsnodehashtbl;
60 u_long nfsnodehash;
61 struct rwlock nfs_hashlock = RWLOCK_INITIALIZER("nfshshlk");
62 
63 struct pool nfs_node_pool;
64 
65 extern int prtactive;
66 
67 #define	nfs_hash(x,y)	hash32_buf((x), (y), HASHINIT)
68 
69 /*
70  * Initialize hash links for nfsnodes
71  * and build nfsnode free list.
72  */
73 void
74 nfs_nhinit()
75 {
76 	nfsnodehashtbl = hashinit(desiredvnodes, M_NFSNODE, M_WAITOK, &nfsnodehash);
77 	pool_init(&nfs_node_pool, sizeof(struct nfsnode), 0, 0, 0, "nfsnodepl",
78 	    &pool_allocator_nointr);
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 int
88 nfs_nget(mntp, fhp, fhsize, npp)
89 	struct mount *mntp;
90 	nfsfh_t *fhp;
91 	int fhsize;
92 	struct nfsnode **npp;
93 {
94 	struct nfsmount *nmp;
95 	struct proc *p = curproc;	/* XXX */
96 	struct nfsnode *np;
97 	struct nfsnodehashhead *nhpp;
98 	struct vnode *vp;
99 	extern int (**nfsv2_vnodeop_p)(void *);
100 	struct vnode *nvp;
101 	int error;
102 
103 	nhpp = NFSNOHASH(nfs_hash(fhp, fhsize));
104 loop:
105 	LIST_FOREACH(np, nhpp, n_hash) {
106 		if (mntp != NFSTOV(np)->v_mount || np->n_fhsize != fhsize ||
107 		    bcmp((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize))
108 			continue;
109 		vp = NFSTOV(np);
110 		if (vget(vp, LK_EXCLUSIVE, p))
111 			goto loop;
112 		*npp = np;
113 		return(0);
114 	}
115 	if (rw_enter(&nfs_hashlock, RW_WRITE|RW_SLEEPFAIL))
116 		goto loop;
117 	error = getnewvnode(VT_NFS, mntp, nfsv2_vnodeop_p, &nvp);
118 	if (error) {
119 		*npp = 0;
120 		rw_exit(&nfs_hashlock);
121 		return (error);
122 	}
123 	vp = nvp;
124 	np = pool_get(&nfs_node_pool, PR_WAITOK | PR_ZERO);
125 	vp->v_data = np;
126 	np->n_vnode = vp;
127 
128 	rw_init(&np->n_commitlock, "nfs_commitlk");
129 
130 	/*
131 	 * Are we getting the root? If so, make sure the vnode flags
132 	 * are correct
133 	 */
134 	nmp = VFSTONFS(mntp);
135 	if ((fhsize == nmp->nm_fhsize) &&
136 	    !bcmp(fhp, nmp->nm_fh, fhsize)) {
137 		if (vp->v_type == VNON)
138 			vp->v_type = VDIR;
139 		vp->v_flag |= VROOT;
140 	}
141 
142 	LIST_INSERT_HEAD(nhpp, np, n_hash);
143 	np->n_fhp = &np->n_fh;
144 	bcopy((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize);
145 	np->n_fhsize = fhsize;
146 	np->n_accstamp = -1;
147 	rw_exit(&nfs_hashlock);
148 	*npp = np;
149 	return (0);
150 }
151 
152 int
153 nfs_inactive(v)
154 	void *v;
155 {
156 	struct vop_inactive_args *ap = v;
157 	struct nfsnode *np;
158 	struct sillyrename *sp;
159 	struct proc *p = curproc;	/* XXX */
160 
161 	np = VTONFS(ap->a_vp);
162 
163 #ifdef DIAGNOSTIC
164 	if (prtactive && ap->a_vp->v_usecount != 0)
165 		vprint("nfs_inactive: pushing active", ap->a_vp);
166 #endif
167 
168 	if (ap->a_vp->v_type != VDIR) {
169 		sp = np->n_sillyrename;
170 		np->n_sillyrename = (struct sillyrename *)0;
171 	} else
172 		sp = (struct sillyrename *)0;
173 	if (sp) {
174 		/*
175 		 * Remove the silly file that was rename'd earlier
176 		 */
177 		nfs_vinvalbuf(ap->a_vp, 0, sp->s_cred, p);
178 		nfs_removeit(sp);
179 		crfree(sp->s_cred);
180 		vrele(sp->s_dvp);
181 		free(sp, M_NFSREQ);
182 	}
183 	np->n_flag &= (NMODIFIED | NFLUSHINPROG | NFLUSHWANT);
184 
185 	VOP_UNLOCK(ap->a_vp, 0, ap->a_p);
186 	return (0);
187 }
188 
189 /*
190  * Reclaim an nfsnode so that it can be used for other purposes.
191  */
192 int
193 nfs_reclaim(v)
194 	void *v;
195 {
196 	struct vop_reclaim_args *ap = v;
197 	struct vnode *vp = ap->a_vp;
198 	struct nfsnode *np = VTONFS(vp);
199 
200 #ifdef DIAGNOSTIC
201 	if (prtactive && vp->v_usecount != 0)
202 		vprint("nfs_reclaim: pushing active", vp);
203 #endif
204 
205 	if (np->n_hash.le_prev != NULL)
206 		LIST_REMOVE(np, n_hash);
207 
208 	if (np->n_rcred)
209 		crfree(np->n_rcred);
210 	if (np->n_wcred)
211 		crfree(np->n_wcred);
212 	cache_purge(vp);
213 	pool_put(&nfs_node_pool, vp->v_data);
214 	vp->v_data = NULL;
215 	return (0);
216 }
217