]> git.saurik.com Git - apple/xnu.git/blame - bsd/nfs/nfs_node.c
xnu-792.25.20.tar.gz
[apple/xnu.git] / bsd / nfs / nfs_node.c
CommitLineData
1c79356b 1/*
5d5c5d0d
A
2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
3 *
6601e61a 4 * @APPLE_LICENSE_HEADER_START@
1c79356b 5 *
6601e61a
A
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
8f6c56a5 11 *
6601e61a
A
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
6601e61a
A
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
8f6c56a5 19 *
6601e61a 20 * @APPLE_LICENSE_HEADER_END@
1c79356b
A
21 */
22/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
23/*
24 * Copyright (c) 1989, 1993
25 * The Regents of the University of California. All rights reserved.
26 *
27 * This code is derived from software contributed to Berkeley by
28 * Rick Macklem at The University of Guelph.
29 *
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
32 * are met:
33 * 1. Redistributions of source code must retain the above copyright
34 * notice, this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above copyright
36 * notice, this list of conditions and the following disclaimer in the
37 * documentation and/or other materials provided with the distribution.
38 * 3. All advertising materials mentioning features or use of this software
39 * must display the following acknowledgement:
40 * This product includes software developed by the University of
41 * California, Berkeley and its contributors.
42 * 4. Neither the name of the University nor the names of its contributors
43 * may be used to endorse or promote products derived from this software
44 * without specific prior written permission.
45 *
46 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56 * SUCH DAMAGE.
57 *
58 * @(#)nfs_node.c 8.6 (Berkeley) 5/22/95
59 * FreeBSD-Id: nfs_node.c,v 1.22 1997/10/28 14:06:20 bde Exp $
60 */
61
62
63#include <sys/param.h>
64#include <sys/systm.h>
65#include <sys/proc.h>
91447636
A
66#include <sys/kauth.h>
67#include <sys/mount_internal.h>
1c79356b 68#include <sys/vnode.h>
91447636 69#include <sys/ubc.h>
1c79356b
A
70#include <sys/malloc.h>
71
72#include <nfs/rpcv2.h>
73#include <nfs/nfsproto.h>
74#include <nfs/nfs.h>
75#include <nfs/nfsnode.h>
76#include <nfs/nfsmount.h>
77
1c79356b
A
78LIST_HEAD(nfsnodehashhead, nfsnode) *nfsnodehashtbl;
79u_long nfsnodehash;
80
91447636
A
81lck_grp_t * nfs_node_hash_lck_grp;
82lck_grp_attr_t * nfs_node_hash_lck_grp_attr;
83lck_attr_t * nfs_node_hash_lck_attr;
84lck_mtx_t *nfs_node_hash_mutex;
1c79356b
A
85
86/*
87 * Initialize hash links for nfsnodes
88 * and build nfsnode free list.
89 */
90void
e5568f75 91nfs_nhinit(void)
1c79356b
A
92{
93 nfsnodehashtbl = hashinit(desiredvnodes, M_NFSNODE, &nfsnodehash);
91447636
A
94
95 nfs_node_hash_lck_grp_attr = lck_grp_attr_alloc_init();
91447636
A
96 nfs_node_hash_lck_grp = lck_grp_alloc_init("nfs_node_hash", nfs_node_hash_lck_grp_attr);
97
98 nfs_node_hash_lck_attr = lck_attr_alloc_init();
99
100 nfs_node_hash_mutex = lck_mtx_alloc_init(nfs_node_hash_lck_grp, nfs_node_hash_lck_attr);
1c79356b
A
101}
102
103/*
104 * Compute an entry in the NFS hash table structure
105 */
106u_long
91447636 107nfs_hash(u_char *fhp, int fhsize)
1c79356b 108{
91447636
A
109 u_long fhsum;
110 int i;
1c79356b 111
1c79356b
A
112 fhsum = 0;
113 for (i = 0; i < fhsize; i++)
91447636 114 fhsum += *fhp++;
1c79356b
A
115 return (fhsum);
116}
117
118/*
119 * Look up a vnode/nfsnode by file handle.
120 * Callers must check for mount points!!
121 * In all cases, a pointer to a
122 * nfsnode structure is returned.
123 */
1c79356b 124int
91447636
A
125nfs_nget(
126 mount_t mntp,
127 vnode_t dvp,
128 struct componentname *cnp,
129 u_char *fhp,
130 int fhsize,
131 struct nfs_vattr *nvap,
132 u_int64_t *xidp,
133 int flags,
134 struct nfsnode **npp)
1c79356b 135{
1c79356b
A
136 struct nfsnode *np;
137 struct nfsnodehashhead *nhpp;
91447636 138 vnode_t vp, nvp;
1c79356b 139 int error;
91447636
A
140 mount_t mp;
141 struct vnode_fsparam vfsp;
142 uint32_t vid;
1c79356b
A
143
144 /* Check for unmount in progress */
55e303ae 145 if (!mntp || (mntp->mnt_kern_flag & MNTK_UNMOUNT)) {
1c79356b 146 *npp = 0;
55e303ae 147 return (!mntp ? ENXIO : EPERM);
1c79356b
A
148 }
149
150 nhpp = NFSNOHASH(nfs_hash(fhp, fhsize));
151loop:
91447636 152 lck_mtx_lock(nfs_node_hash_mutex);
1c79356b 153 for (np = nhpp->lh_first; np != 0; np = np->n_hash.le_next) {
91447636 154 mp = (np->n_flag & NINIT) ? np->n_mount : vnode_mount(NFSTOV(np));
55e303ae 155 if (mntp != mp || np->n_fhsize != fhsize ||
91447636 156 bcmp(fhp, np->n_fhp, fhsize))
1c79356b 157 continue;
55e303ae
A
158 /* if the node is still being initialized, sleep on it */
159 if (np->n_flag & NINIT) {
160 np->n_flag |= NWINIT;
91447636 161 msleep(np, nfs_node_hash_mutex, PDROP | PINOD, "nfs_nget", 0);
55e303ae
A
162 goto loop;
163 }
1c79356b 164 vp = NFSTOV(np);
91447636
A
165 vid = vnode_vid(vp);
166 lck_mtx_unlock(nfs_node_hash_mutex);
167 if ((error = vnode_getwithvid(vp, vid))) {
168 /*
169 * If vnode is being reclaimed or has already
170 * changed identity, no need to wait.
171 */
172 return (error);
173 }
174 /* update attributes */
175 error = nfs_loadattrcache(np, nvap, xidp, 0);
176 if (error) {
177 vnode_put(vp);
178 } else {
179 if (dvp && cnp && (flags & NG_MAKEENTRY))
180 cache_enter(dvp, vp, cnp);
181 *npp = np;
1c79356b 182 }
91447636 183 return(error);
1c79356b 184 }
1c79356b
A
185
186 /*
55e303ae
A
187 * allocate and initialize nfsnode and stick it in the hash
188 * before calling getnewvnode(). Anyone finding it in the
189 * hash before initialization is complete will wait for it.
1c79356b
A
190 */
191 MALLOC_ZONE(np, struct nfsnode *, sizeof *np, M_NFSNODE, M_WAITOK);
91447636
A
192 if (!np) {
193 lck_mtx_unlock(nfs_node_hash_mutex);
194 *npp = 0;
195 return (ENOMEM);
196 }
1c79356b 197 bzero((caddr_t)np, sizeof *np);
55e303ae
A
198 np->n_flag |= NINIT;
199 np->n_mount = mntp;
55e303ae 200
91447636 201 /* setup node's file handle */
1c79356b 202 if (fhsize > NFS_SMALLFH) {
91447636 203 MALLOC_ZONE(np->n_fhp, u_char *,
1c79356b 204 fhsize, M_NFSBIGFH, M_WAITOK);
91447636
A
205 if (!np->n_fhp) {
206 lck_mtx_unlock(nfs_node_hash_mutex);
207 FREE_ZONE(np, sizeof *np, M_NFSNODE);
208 *npp = 0;
209 return (ENOMEM);
210 }
211 } else {
212 np->n_fhp = &np->n_fh[0];
213 }
214 bcopy(fhp, np->n_fhp, fhsize);
1c79356b 215 np->n_fhsize = fhsize;
91447636
A
216
217 /* Insert the nfsnode in the hash queue for its new file handle */
55e303ae 218 np->n_flag |= NHASHED;
91447636 219 LIST_INSERT_HEAD(nhpp, np, n_hash);
1c79356b 220
55e303ae 221 /* release lock on hash table */
91447636
A
222 lck_mtx_unlock(nfs_node_hash_mutex);
223
224 /* do initial loading of attributes */
225 error = nfs_loadattrcache(np, nvap, xidp, 1);
226 if (error) {
227 lck_mtx_lock(nfs_node_hash_mutex);
228 LIST_REMOVE(np, n_hash);
229 np->n_flag &= ~(NHASHED|NINIT);
230 if (np->n_flag & NWINIT) {
231 np->n_flag &= ~NWINIT;
232 wakeup((caddr_t)np);
233 }
234 lck_mtx_unlock(nfs_node_hash_mutex);
235 if (np->n_fhsize > NFS_SMALLFH)
236 FREE_ZONE(np->n_fhp, np->n_fhsize, M_NFSBIGFH);
237 FREE_ZONE(np, sizeof *np, M_NFSNODE);
238 *npp = 0;
239 return (error);
240 }
241 np->n_mtime = nvap->nva_mtime;
242 if (nvap->nva_type == VDIR)
243 np->n_ncmtime = nvap->nva_mtime;
244 NMODEINVALIDATE(np);
1c79356b 245
55e303ae 246 /* now, attempt to get a new vnode */
91447636
A
247 vfsp.vnfs_mp = mntp;
248 vfsp.vnfs_vtype = nvap->nva_type;
249 vfsp.vnfs_str = "nfs";
250 vfsp.vnfs_dvp = dvp;
251 vfsp.vnfs_fsnode = np;
252 if (nvap->nva_type == VFIFO)
253 vfsp.vnfs_vops = fifo_nfsv2nodeop_p;
254 else if (nvap->nva_type == VBLK || nvap->nva_type == VCHR)
255 vfsp.vnfs_vops = spec_nfsv2nodeop_p;
256 else
257 vfsp.vnfs_vops = nfsv2_vnodeop_p;
258 vfsp.vnfs_markroot = (flags & NG_MARKROOT) ? 1 : 0;
259 vfsp.vnfs_marksystem = 0;
260 vfsp.vnfs_rdev = 0;
261 vfsp.vnfs_filesize = nvap->nva_size;
262 vfsp.vnfs_cnp = cnp;
263 if (dvp && cnp && (flags & NG_MAKEENTRY))
264 vfsp.vnfs_flags = 0;
265 else
266 vfsp.vnfs_flags = VNFS_NOCACHE;
267 error = vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &vfsp, &nvp);
55e303ae 268 if (error) {
91447636 269 lck_mtx_lock(nfs_node_hash_mutex);
55e303ae 270 LIST_REMOVE(np, n_hash);
91447636
A
271 np->n_flag &= ~(NHASHED|NINIT);
272 if (np->n_flag & NWINIT) {
273 np->n_flag &= ~NWINIT;
274 wakeup((caddr_t)np);
275 }
276 lck_mtx_unlock(nfs_node_hash_mutex);
55e303ae 277 if (np->n_fhsize > NFS_SMALLFH)
91447636 278 FREE_ZONE(np->n_fhp, np->n_fhsize, M_NFSBIGFH);
55e303ae
A
279 FREE_ZONE(np, sizeof *np, M_NFSNODE);
280 *npp = 0;
281 return (error);
282 }
283 vp = nvp;
55e303ae 284 np->n_vnode = vp;
91447636
A
285 vnode_addfsref(vp);
286 vnode_settag(vp, VT_NFS); // XXX shouldn't this be a vnode_create() parameter?
55e303ae 287 *npp = np;
91447636 288 /* node is now initialized */
55e303ae 289
91447636
A
290 /* check if anyone's waiting on this node */
291 lck_mtx_lock(nfs_node_hash_mutex);
55e303ae
A
292 np->n_flag &= ~NINIT;
293 if (np->n_flag & NWINIT) {
294 np->n_flag &= ~NWINIT;
295 wakeup((caddr_t)np);
296 }
91447636 297 lck_mtx_unlock(nfs_node_hash_mutex);
1c79356b 298
fa4905b1 299 return (error);
1c79356b
A
300}
301
91447636 302
1c79356b
A
303int
304nfs_inactive(ap)
91447636
A
305 struct vnop_inactive_args /* {
306 struct vnodeop_desc *a_desc;
307 vnode_t a_vp;
308 vfs_context_t a_context;
1c79356b
A
309 } */ *ap;
310{
311 register struct nfsnode *np;
312 register struct sillyrename *sp;
1c79356b
A
313
314 np = VTONFS(ap->a_vp);
91447636 315 if (vnode_vtype(ap->a_vp) != VDIR) {
1c79356b
A
316 sp = np->n_sillyrename;
317 np->n_sillyrename = (struct sillyrename *)0;
318 } else
319 sp = (struct sillyrename *)0;
320
321 if (sp) {
322 /*
323 * Remove the silly file that was rename'd earlier
324 */
325#if DIAGNOSTIC
91447636
A
326 kprintf("nfs_inactive removing %s, dvp=%x, a_vp=%x, ap=%x, np=%x, sp=%x\n",
327 &sp->s_name[0], (unsigned)sp->s_dvp, (unsigned)ap->a_vp, (unsigned)ap,
328 (unsigned)np, (unsigned)sp);
1c79356b 329#endif
91447636 330 nfs_vinvalbuf(ap->a_vp, 0, sp->s_cred, vfs_context_proc(ap->a_context), 1);
fa4905b1 331 np->n_size = 0;
1c79356b 332 ubc_setsize(ap->a_vp, (off_t)0);
55e303ae
A
333 nfs_removeit(sp);
334 /*
335 * remove nfsnode from hash now so we can't accidentally find it
336 * again if another object gets created with the same filehandle
337 * before this vnode gets reclaimed
338 */
91447636 339 lck_mtx_lock(nfs_node_hash_mutex);
55e303ae
A
340 LIST_REMOVE(np, n_hash);
341 np->n_flag &= ~NHASHED;
91447636 342 lck_mtx_unlock(nfs_node_hash_mutex);
0c530ab8
A
343 if (IS_VALID_CRED(sp->s_cred)) {
344 kauth_cred_unref(&sp->s_cred);
1c79356b 345 }
91447636 346 vnode_rele(sp->s_dvp);
1c79356b 347 FREE_ZONE((caddr_t)sp, sizeof (struct sillyrename), M_NFSREQ);
91447636 348 vnode_recycle(ap->a_vp);
1c79356b 349 }
91447636
A
350 /* clear all flags other than these */
351 np->n_flag &= (NMODIFIED | NFLUSHINPROG | NFLUSHWANT | NHASHED);
1c79356b
A
352 return (0);
353}
354
355/*
356 * Reclaim an nfsnode so that it can be used for other purposes.
357 */
358int
359nfs_reclaim(ap)
91447636
A
360 struct vnop_reclaim_args /* {
361 struct vnodeop_desc *a_desc;
362 vnode_t a_vp;
363 vfs_context_t a_context;
1c79356b
A
364 } */ *ap;
365{
91447636
A
366 vnode_t vp = ap->a_vp;
367 struct nfsnode *np = VTONFS(vp);
368 struct nfsdmap *dp, *dp2;
1c79356b 369
91447636 370 vnode_removefsref(vp);
1c79356b 371
55e303ae 372 if (np->n_flag & NHASHED) {
91447636 373 lck_mtx_lock(nfs_node_hash_mutex);
55e303ae
A
374 LIST_REMOVE(np, n_hash);
375 np->n_flag &= ~NHASHED;
91447636 376 lck_mtx_unlock(nfs_node_hash_mutex);
1c79356b
A
377 }
378
379 /*
380 * Free up any directory cookie structures and
381 * large file handle structures that might be associated with
382 * this nfs node.
383 */
91447636 384 if (vnode_vtype(vp) == VDIR) {
1c79356b
A
385 dp = np->n_cookies.lh_first;
386 while (dp) {
387 dp2 = dp;
388 dp = dp->ndm_list.le_next;
389 FREE_ZONE((caddr_t)dp2,
390 sizeof (struct nfsdmap), M_NFSDIROFF);
391 }
392 }
393 if (np->n_fhsize > NFS_SMALLFH) {
91447636 394 FREE_ZONE(np->n_fhp, np->n_fhsize, M_NFSBIGFH);
1c79356b 395 }
91447636 396 vnode_clearfsnode(vp);
1c79356b 397
91447636 398 FREE_ZONE(np, sizeof(struct nfsnode), M_NFSNODE);
1c79356b
A
399 return (0);
400}
401