Line data Source code
1 : /* $OpenBSD: nfs_node.c,v 1.70 2018/05/27 06:02:15 visa 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/timeout.h>
42 : #include <sys/mount.h>
43 : #include <sys/namei.h>
44 : #include <sys/vnode.h>
45 : #include <sys/lock.h>
46 : #include <sys/kernel.h>
47 : #include <sys/malloc.h>
48 : #include <sys/pool.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/nfsnode.h>
55 : #include <nfs/nfsmount.h>
56 : #include <nfs/nfs_var.h>
57 :
58 : struct pool nfs_node_pool;
59 : extern int prtactive;
60 :
61 : /* XXX */
62 : extern struct vops nfs_vops;
63 :
64 : /* filehandle to node lookup. */
65 : static __inline int
66 0 : nfsnode_cmp(const struct nfsnode *a, const struct nfsnode *b)
67 : {
68 0 : if (a->n_fhsize != b->n_fhsize)
69 0 : return (a->n_fhsize - b->n_fhsize);
70 0 : return (memcmp(a->n_fhp, b->n_fhp, a->n_fhsize));
71 0 : }
72 :
73 0 : RBT_PROTOTYPE(nfs_nodetree, nfsnode, n_entry, nfsnode_cmp);
74 0 : RBT_GENERATE(nfs_nodetree, nfsnode, n_entry, nfsnode_cmp);
75 :
76 : void
77 0 : nfs_ninit(struct nfsmount *nmp)
78 : {
79 0 : RBT_INIT(nfs_nodetree, &nmp->nm_ntree);
80 0 : }
81 :
82 : /*
83 : * Look up a vnode/nfsnode by file handle and store the pointer in *npp.
84 : * Callers must check for mount points!!
85 : * An error number is returned.
86 : */
87 : int
88 0 : nfs_nget(struct mount *mnt, nfsfh_t *fh, int fhsize, struct nfsnode **npp)
89 : {
90 : struct nfsmount *nmp;
91 0 : struct nfsnode *np, find, *np2;
92 0 : struct vnode *vp, *nvp;
93 : int error;
94 :
95 0 : nmp = VFSTONFS(mnt);
96 :
97 : loop:
98 0 : find.n_fhp = fh;
99 0 : find.n_fhsize = fhsize;
100 0 : np = RBT_FIND(nfs_nodetree, &nmp->nm_ntree, &find);
101 0 : if (np != NULL) {
102 0 : vp = NFSTOV(np);
103 0 : error = vget(vp, LK_EXCLUSIVE);
104 0 : if (error)
105 0 : goto loop;
106 0 : *npp = np;
107 0 : return (0);
108 : }
109 :
110 : /*
111 : * getnewvnode() could recycle a vnode, potentially formerly
112 : * owned by NFS. This will cause a VOP_RECLAIM() to happen,
113 : * which will cause recursive locking, so we unlock before
114 : * calling getnewvnode() lock again afterwards, but must check
115 : * to see if this nfsnode has been added while we did not hold
116 : * the lock.
117 : */
118 0 : error = getnewvnode(VT_NFS, mnt, &nfs_vops, &nvp);
119 : /* note that we don't have this vnode set up completely yet */
120 0 : if (error) {
121 0 : *npp = NULL;
122 0 : return (error);
123 : }
124 0 : nvp->v_flag |= VLARVAL;
125 0 : np = pool_get(&nfs_node_pool, PR_WAITOK | PR_ZERO);
126 : /*
127 : * getnewvnode() and pool_get() can sleep, check for race.
128 : */
129 0 : if (RBT_FIND(nfs_nodetree, &nmp->nm_ntree, &find) != NULL) {
130 0 : pool_put(&nfs_node_pool, np);
131 0 : vgone(nvp);
132 0 : goto loop;
133 : }
134 :
135 0 : vp = nvp;
136 : #ifdef VFSLCKDEBUG
137 : vp->v_flag |= VLOCKSWORK;
138 : #endif
139 0 : rrw_init_flags(&np->n_lock, "nfsnode", RWL_DUPOK | RWL_IS_VNODE);
140 0 : vp->v_data = np;
141 : /* we now have an nfsnode on this vnode */
142 0 : vp->v_flag &= ~VLARVAL;
143 0 : np->n_vnode = vp;
144 0 : rw_init(&np->n_commitlock, "nfs_commitlk");
145 0 : np->n_fhp = &np->n_fh;
146 0 : bcopy(fh, np->n_fhp, fhsize);
147 0 : np->n_fhsize = fhsize;
148 : /* lock the nfsnode, then put it on the rbtree */
149 0 : rrw_enter(&np->n_lock, RW_WRITE);
150 0 : np2 = RBT_INSERT(nfs_nodetree, &nmp->nm_ntree, np);
151 0 : KASSERT(np2 == NULL);
152 0 : np->n_accstamp = -1;
153 0 : *npp = np;
154 :
155 0 : return (0);
156 0 : }
157 :
158 : int
159 0 : nfs_inactive(void *v)
160 : {
161 0 : struct vop_inactive_args *ap = v;
162 : struct nfsnode *np;
163 : struct sillyrename *sp;
164 :
165 : #ifdef DIAGNOSTIC
166 0 : if (prtactive && ap->a_vp->v_usecount != 0)
167 0 : vprint("nfs_inactive: pushing active", ap->a_vp);
168 : #endif
169 0 : if (ap->a_vp->v_flag & VLARVAL)
170 : /*
171 : * vnode was incompletely set up, just return
172 : * as we are throwing it away.
173 : */
174 0 : return(0);
175 : #ifdef DIAGNOSTIC
176 0 : if (ap->a_vp->v_data == NULL)
177 0 : panic("NULL v_data (no nfsnode set up?) in vnode %p",
178 : ap->a_vp);
179 : #endif
180 0 : np = VTONFS(ap->a_vp);
181 0 : if (ap->a_vp->v_type != VDIR) {
182 0 : sp = np->n_sillyrename;
183 0 : np->n_sillyrename = NULL;
184 0 : } else
185 : sp = NULL;
186 0 : if (sp) {
187 : /*
188 : * Remove the silly file that was rename'd earlier
189 : */
190 0 : nfs_vinvalbuf(ap->a_vp, 0, sp->s_cred, curproc);
191 0 : vn_lock(sp->s_dvp, LK_EXCLUSIVE | LK_RETRY);
192 0 : nfs_removeit(sp);
193 0 : crfree(sp->s_cred);
194 0 : vput(sp->s_dvp);
195 0 : free(sp, M_NFSREQ, sizeof(*sp));
196 0 : }
197 0 : np->n_flag &= (NMODIFIED | NFLUSHINPROG | NFLUSHWANT);
198 :
199 0 : VOP_UNLOCK(ap->a_vp);
200 0 : return (0);
201 0 : }
202 :
203 : /*
204 : * Reclaim an nfsnode so that it can be used for other purposes.
205 : */
206 : int
207 0 : nfs_reclaim(void *v)
208 : {
209 0 : struct vop_reclaim_args *ap = v;
210 0 : struct vnode *vp = ap->a_vp;
211 : struct nfsmount *nmp;
212 0 : struct nfsnode *np = VTONFS(vp);
213 :
214 : #ifdef DIAGNOSTIC
215 0 : if (prtactive && vp->v_usecount != 0)
216 0 : vprint("nfs_reclaim: pushing active", vp);
217 : #endif
218 0 : if (ap->a_vp->v_flag & VLARVAL)
219 : /*
220 : * vnode was incompletely set up, just return
221 : * as we are throwing it away.
222 : */
223 0 : return(0);
224 : #ifdef DIAGNOSTIC
225 0 : if (ap->a_vp->v_data == NULL)
226 0 : panic("NULL v_data (no nfsnode set up?) in vnode %p",
227 : ap->a_vp);
228 : #endif
229 0 : nmp = VFSTONFS(vp->v_mount);
230 0 : RBT_REMOVE(nfs_nodetree, &nmp->nm_ntree, np);
231 :
232 0 : if (np->n_rcred)
233 0 : crfree(np->n_rcred);
234 0 : if (np->n_wcred)
235 0 : crfree(np->n_wcred);
236 :
237 0 : cache_purge(vp);
238 0 : pool_put(&nfs_node_pool, vp->v_data);
239 0 : vp->v_data = NULL;
240 :
241 0 : return (0);
242 0 : }
|