]> git.saurik.com Git - apple/xnu.git/blame - bsd/nfs/nfs_node.c
xnu-1228.tar.gz
[apple/xnu.git] / bsd / nfs / nfs_node.c
CommitLineData
1c79356b 1/*
2d21ac55 2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
8f6c56a5 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
29/*
30 * Copyright (c) 1989, 1993
31 * The Regents of the University of California. All rights reserved.
32 *
33 * This code is derived from software contributed to Berkeley by
34 * Rick Macklem at The University of Guelph.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. All advertising materials mentioning features or use of this software
45 * must display the following acknowledgement:
46 * This product includes software developed by the University of
47 * California, Berkeley and its contributors.
48 * 4. Neither the name of the University nor the names of its contributors
49 * may be used to endorse or promote products derived from this software
50 * without specific prior written permission.
51 *
52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * SUCH DAMAGE.
63 *
64 * @(#)nfs_node.c 8.6 (Berkeley) 5/22/95
65 * FreeBSD-Id: nfs_node.c,v 1.22 1997/10/28 14:06:20 bde Exp $
66 */
67
68
69#include <sys/param.h>
70#include <sys/systm.h>
71#include <sys/proc.h>
91447636
A
72#include <sys/kauth.h>
73#include <sys/mount_internal.h>
1c79356b 74#include <sys/vnode.h>
91447636 75#include <sys/ubc.h>
1c79356b
A
76#include <sys/malloc.h>
77
78#include <nfs/rpcv2.h>
79#include <nfs/nfsproto.h>
80#include <nfs/nfs.h>
81#include <nfs/nfsnode.h>
2d21ac55 82#include <nfs/nfs_gss.h>
1c79356b
A
83#include <nfs/nfsmount.h>
84
2d21ac55
A
85#define NFSNOHASH(fhsum) \
86 (&nfsnodehashtbl[(fhsum) & nfsnodehash])
87static LIST_HEAD(nfsnodehashhead, nfsnode) *nfsnodehashtbl;
88static u_long nfsnodehash;
1c79356b 89
2d21ac55
A
90static lck_grp_t *nfs_node_hash_lck_grp;
91static lck_grp_t *nfs_node_lck_grp;
91447636 92lck_mtx_t *nfs_node_hash_mutex;
1c79356b
A
93
94/*
95 * Initialize hash links for nfsnodes
96 * and build nfsnode free list.
97 */
98void
e5568f75 99nfs_nhinit(void)
1c79356b 100{
2d21ac55
A
101 nfs_node_hash_lck_grp = lck_grp_alloc_init("nfs_node_hash", LCK_GRP_ATTR_NULL);
102 nfs_node_hash_mutex = lck_mtx_alloc_init(nfs_node_hash_lck_grp, LCK_ATTR_NULL);
103 nfs_node_lck_grp = lck_grp_alloc_init("nfs_node", LCK_GRP_ATTR_NULL);
104}
91447636 105
2d21ac55
A
106void
107nfs_nhinit_finish(void)
108{
109 lck_mtx_lock(nfs_node_hash_mutex);
110 if (!nfsnodehashtbl)
111 nfsnodehashtbl = hashinit(desiredvnodes, M_NFSNODE, &nfsnodehash);
112 lck_mtx_unlock(nfs_node_hash_mutex);
1c79356b
A
113}
114
115/*
116 * Compute an entry in the NFS hash table structure
117 */
118u_long
91447636 119nfs_hash(u_char *fhp, int fhsize)
1c79356b 120{
91447636
A
121 u_long fhsum;
122 int i;
1c79356b 123
1c79356b
A
124 fhsum = 0;
125 for (i = 0; i < fhsize; i++)
91447636 126 fhsum += *fhp++;
1c79356b
A
127 return (fhsum);
128}
129
130/*
131 * Look up a vnode/nfsnode by file handle.
132 * Callers must check for mount points!!
133 * In all cases, a pointer to a
134 * nfsnode structure is returned.
135 */
1c79356b 136int
91447636 137nfs_nget(
2d21ac55
A
138 mount_t mp,
139 nfsnode_t dnp,
91447636
A
140 struct componentname *cnp,
141 u_char *fhp,
142 int fhsize,
143 struct nfs_vattr *nvap,
144 u_int64_t *xidp,
145 int flags,
2d21ac55 146 nfsnode_t *npp)
1c79356b 147{
2d21ac55 148 nfsnode_t np;
1c79356b 149 struct nfsnodehashhead *nhpp;
2d21ac55
A
150 vnode_t vp;
151 int error, nfsvers;
152 mount_t mp2;
91447636
A
153 struct vnode_fsparam vfsp;
154 uint32_t vid;
1c79356b 155
2d21ac55
A
156 FSDBG_TOP(263, mp, dnp, flags, npp);
157
1c79356b 158 /* Check for unmount in progress */
2d21ac55
A
159 if (!mp || (mp->mnt_kern_flag & MNTK_FRCUNMOUNT)) {
160 *npp = NULL;
161 error = ENXIO;
162 FSDBG_BOT(263, mp, dnp, 0xd1e, error);
163 return (error);
1c79356b 164 }
2d21ac55 165 nfsvers = VFSTONFS(mp)->nm_vers;
1c79356b
A
166
167 nhpp = NFSNOHASH(nfs_hash(fhp, fhsize));
168loop:
91447636 169 lck_mtx_lock(nfs_node_hash_mutex);
1c79356b 170 for (np = nhpp->lh_first; np != 0; np = np->n_hash.le_next) {
2d21ac55
A
171 mp2 = (np->n_hflag & NHINIT) ? np->n_mount : NFSTOMP(np);
172 if (mp != mp2 || np->n_fhsize != fhsize ||
91447636 173 bcmp(fhp, np->n_fhp, fhsize))
1c79356b 174 continue;
2d21ac55
A
175 FSDBG(263, dnp, np, np->n_flag, 0xcace0000);
176 /* if the node is locked, sleep on it */
177 if (np->n_hflag & NHLOCKED) {
178 np->n_hflag |= NHLOCKWANT;
179 FSDBG(263, dnp, np, np->n_flag, 0xcace2222);
180 msleep(np, nfs_node_hash_mutex, PDROP | PINOD, "nfs_nget", NULL);
181 FSDBG(263, dnp, np, np->n_flag, 0xcace3333);
55e303ae
A
182 goto loop;
183 }
1c79356b 184 vp = NFSTOV(np);
91447636
A
185 vid = vnode_vid(vp);
186 lck_mtx_unlock(nfs_node_hash_mutex);
187 if ((error = vnode_getwithvid(vp, vid))) {
188 /*
189 * If vnode is being reclaimed or has already
190 * changed identity, no need to wait.
191 */
2d21ac55 192 FSDBG_BOT(263, dnp, *npp, 0xcace0d1e, error);
91447636 193 return (error);
2d21ac55
A
194 }
195 if ((error = nfs_lock(np, NFS_NODE_LOCK_EXCLUSIVE))) {
196 /* this only fails if the node is now unhashed */
197 /* so let's see if we can find/create it again */
198 FSDBG(263, dnp, *npp, 0xcaced1e2, error);
199 vnode_put(vp);
200 goto loop;
201 }
91447636
A
202 /* update attributes */
203 error = nfs_loadattrcache(np, nvap, xidp, 0);
204 if (error) {
2d21ac55 205 nfs_unlock(np);
91447636
A
206 vnode_put(vp);
207 } else {
2d21ac55
A
208 if (dnp && cnp && (flags & NG_MAKEENTRY))
209 cache_enter(NFSTOV(dnp), vp, cnp);
91447636 210 *npp = np;
1c79356b 211 }
2d21ac55 212 FSDBG_BOT(263, dnp, *npp, 0xcace0000, error);
91447636 213 return(error);
1c79356b 214 }
1c79356b 215
2d21ac55
A
216 FSDBG(263, mp, dnp, npp, 0xaaaaaaaa);
217
1c79356b 218 /*
55e303ae
A
219 * allocate and initialize nfsnode and stick it in the hash
220 * before calling getnewvnode(). Anyone finding it in the
221 * hash before initialization is complete will wait for it.
1c79356b 222 */
2d21ac55 223 MALLOC_ZONE(np, nfsnode_t, sizeof *np, M_NFSNODE, M_WAITOK);
91447636
A
224 if (!np) {
225 lck_mtx_unlock(nfs_node_hash_mutex);
226 *npp = 0;
2d21ac55 227 FSDBG_BOT(263, dnp, *npp, 0x80000001, ENOMEM);
91447636
A
228 return (ENOMEM);
229 }
2d21ac55
A
230 bzero(np, sizeof *np);
231 np->n_hflag |= (NHINIT | NHLOCKED);
232 np->n_mount = mp;
233
234 if (dnp && cnp && ((cnp->cn_namelen != 2) ||
235 (cnp->cn_nameptr[0] != '.') || (cnp->cn_nameptr[1] != '.'))) {
236 vnode_t dvp = NFSTOV(dnp);
237 if (!vnode_get(dvp)) {
238 if (!vnode_ref(dvp))
239 np->n_parent = dvp;
240 vnode_put(dvp);
241 }
242 }
55e303ae 243
91447636 244 /* setup node's file handle */
1c79356b 245 if (fhsize > NFS_SMALLFH) {
91447636 246 MALLOC_ZONE(np->n_fhp, u_char *,
1c79356b 247 fhsize, M_NFSBIGFH, M_WAITOK);
91447636
A
248 if (!np->n_fhp) {
249 lck_mtx_unlock(nfs_node_hash_mutex);
250 FREE_ZONE(np, sizeof *np, M_NFSNODE);
251 *npp = 0;
2d21ac55 252 FSDBG_BOT(263, dnp, *npp, 0x80000002, ENOMEM);
91447636
A
253 return (ENOMEM);
254 }
255 } else {
256 np->n_fhp = &np->n_fh[0];
257 }
258 bcopy(fhp, np->n_fhp, fhsize);
1c79356b 259 np->n_fhsize = fhsize;
91447636
A
260
261 /* Insert the nfsnode in the hash queue for its new file handle */
91447636 262 LIST_INSERT_HEAD(nhpp, np, n_hash);
2d21ac55
A
263 np->n_hflag |= NHHASHED;
264 FSDBG(266, 0, np, np->n_flag, np->n_hflag);
265
266 /* lock the new nfsnode */
267 lck_rw_init(&np->n_lock, nfs_node_lck_grp, LCK_ATTR_NULL);
268 lck_rw_init(&np->n_datalock, nfs_node_lck_grp, LCK_ATTR_NULL);
269 nfs_lock(np, NFS_NODE_LOCK_FORCE);
1c79356b 270
55e303ae 271 /* release lock on hash table */
91447636
A
272 lck_mtx_unlock(nfs_node_hash_mutex);
273
274 /* do initial loading of attributes */
275 error = nfs_loadattrcache(np, nvap, xidp, 1);
276 if (error) {
2d21ac55
A
277 FSDBG(266, 0, np, np->n_flag, 0xb1eb1e);
278 nfs_unlock(np);
91447636
A
279 lck_mtx_lock(nfs_node_hash_mutex);
280 LIST_REMOVE(np, n_hash);
2d21ac55
A
281 np->n_hflag &= ~(NHHASHED|NHINIT|NHLOCKED);
282 if (np->n_hflag & NHLOCKWANT) {
283 np->n_hflag &= ~NHLOCKWANT;
284 wakeup(np);
91447636
A
285 }
286 lck_mtx_unlock(nfs_node_hash_mutex);
2d21ac55
A
287 if (np->n_parent) {
288 if (!vnode_get(np->n_parent)) {
289 vnode_rele(np->n_parent);
290 vnode_put(np->n_parent);
291 }
292 np->n_parent = NULL;
293 }
294 lck_rw_destroy(&np->n_lock, nfs_node_lck_grp);
295 lck_rw_destroy(&np->n_datalock, nfs_node_lck_grp);
91447636
A
296 if (np->n_fhsize > NFS_SMALLFH)
297 FREE_ZONE(np->n_fhp, np->n_fhsize, M_NFSBIGFH);
298 FREE_ZONE(np, sizeof *np, M_NFSNODE);
299 *npp = 0;
2d21ac55 300 FSDBG_BOT(263, dnp, *npp, 0x80000003, error);
91447636
A
301 return (error);
302 }
2d21ac55 303 NFS_CHANGED_UPDATE(nfsvers, np, nvap);
91447636 304 if (nvap->nva_type == VDIR)
2d21ac55 305 NFS_CHANGED_UPDATE_NC(nfsvers, np, nvap);
91447636 306 NMODEINVALIDATE(np);
1c79356b 307
55e303ae 308 /* now, attempt to get a new vnode */
2d21ac55 309 vfsp.vnfs_mp = mp;
91447636
A
310 vfsp.vnfs_vtype = nvap->nva_type;
311 vfsp.vnfs_str = "nfs";
2d21ac55 312 vfsp.vnfs_dvp = dnp ? NFSTOV(dnp) : NULL;
91447636 313 vfsp.vnfs_fsnode = np;
2d21ac55
A
314 if (nfsvers == NFS_VER4) {
315#if FIFO
316 if (nvap->nva_type == VFIFO)
317 vfsp.vnfs_vops = fifo_nfsv4nodeop_p;
318 else
319#endif /* FIFO */
320 if (nvap->nva_type == VBLK || nvap->nva_type == VCHR)
321 vfsp.vnfs_vops = spec_nfsv4nodeop_p;
322 else
323 vfsp.vnfs_vops = nfsv4_vnodeop_p;
324 } else {
325#if FIFO
326 if (nvap->nva_type == VFIFO)
327 vfsp.vnfs_vops = fifo_nfsv2nodeop_p;
328 else
329#endif /* FIFO */
330 if (nvap->nva_type == VBLK || nvap->nva_type == VCHR)
331 vfsp.vnfs_vops = spec_nfsv2nodeop_p;
332 else
333 vfsp.vnfs_vops = nfsv2_vnodeop_p;
334 }
91447636
A
335 vfsp.vnfs_markroot = (flags & NG_MARKROOT) ? 1 : 0;
336 vfsp.vnfs_marksystem = 0;
337 vfsp.vnfs_rdev = 0;
338 vfsp.vnfs_filesize = nvap->nva_size;
339 vfsp.vnfs_cnp = cnp;
2d21ac55
A
340 vfsp.vnfs_flags = VNFS_ADDFSREF;
341 if (!dnp || !cnp || !(flags & NG_MAKEENTRY))
342 vfsp.vnfs_flags |= VNFS_NOCACHE;
343
344 error = vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &vfsp, &np->n_vnode);
55e303ae 345 if (error) {
2d21ac55
A
346 FSDBG(266, 0, np, np->n_flag, 0xb1eb1e);
347 nfs_unlock(np);
91447636 348 lck_mtx_lock(nfs_node_hash_mutex);
55e303ae 349 LIST_REMOVE(np, n_hash);
2d21ac55
A
350 np->n_hflag &= ~(NHHASHED|NHINIT|NHLOCKED);
351 if (np->n_hflag & NHLOCKWANT) {
352 np->n_hflag &= ~NHLOCKWANT;
353 wakeup(np);
91447636
A
354 }
355 lck_mtx_unlock(nfs_node_hash_mutex);
2d21ac55
A
356 if (np->n_parent) {
357 if (!vnode_get(np->n_parent)) {
358 vnode_rele(np->n_parent);
359 vnode_put(np->n_parent);
360 }
361 np->n_parent = NULL;
362 }
363 lck_rw_destroy(&np->n_lock, nfs_node_lck_grp);
364 lck_rw_destroy(&np->n_datalock, nfs_node_lck_grp);
55e303ae 365 if (np->n_fhsize > NFS_SMALLFH)
91447636 366 FREE_ZONE(np->n_fhp, np->n_fhsize, M_NFSBIGFH);
55e303ae
A
367 FREE_ZONE(np, sizeof *np, M_NFSNODE);
368 *npp = 0;
2d21ac55 369 FSDBG_BOT(263, dnp, *npp, 0x80000004, error);
55e303ae
A
370 return (error);
371 }
2d21ac55
A
372 vp = np->n_vnode;
373 vnode_settag(vp, VT_NFS);
91447636 374 /* node is now initialized */
55e303ae 375
91447636
A
376 /* check if anyone's waiting on this node */
377 lck_mtx_lock(nfs_node_hash_mutex);
2d21ac55
A
378 np->n_hflag &= ~(NHINIT|NHLOCKED);
379 if (np->n_hflag & NHLOCKWANT) {
380 np->n_hflag &= ~NHLOCKWANT;
381 wakeup(np);
55e303ae 382 }
91447636 383 lck_mtx_unlock(nfs_node_hash_mutex);
1c79356b 384
2d21ac55
A
385 *npp = np;
386
387 FSDBG_BOT(263, dnp, vp, *npp, error);
fa4905b1 388 return (error);
1c79356b
A
389}
390
91447636 391
1c79356b 392int
2d21ac55 393nfs_vnop_inactive(ap)
91447636
A
394 struct vnop_inactive_args /* {
395 struct vnodeop_desc *a_desc;
396 vnode_t a_vp;
397 vfs_context_t a_context;
1c79356b
A
398 } */ *ap;
399{
2d21ac55
A
400 vnode_t vp;
401 nfsnode_t np;
402 struct nfs_sillyrename *nsp;
403 struct nfs_vattr nvattr;
404 int unhash, attrerr;
1c79356b 405
2d21ac55 406 vp = ap->a_vp;
1c79356b 407 np = VTONFS(ap->a_vp);
2d21ac55
A
408
409 nfs_lock(np, NFS_NODE_LOCK_FORCE);
410
411 if (vnode_vtype(vp) != VDIR) {
412 nsp = np->n_sillyrename;
413 np->n_sillyrename = NULL;
1c79356b 414 } else
2d21ac55 415 nsp = NULL;
1c79356b 416
2d21ac55
A
417 FSDBG_TOP(264, vp, np, np->n_flag, nsp);
418
419 if (!nsp) {
420 /* no silly file to clean up... */
421 /* clear all flags other than these */
422 np->n_flag &= (NMODIFIED);
423 nfs_unlock(np);
424 FSDBG_BOT(264, vp, np, np->n_flag, 0);
425 return (0);
426 }
427
428 /* Remove the silly file that was rename'd earlier */
429
430 /* flush all the buffers */
431 nfs_unlock(np);
432 nfs_vinvalbuf2(vp, V_SAVE, vfs_context_thread(ap->a_context), nsp->nsr_cred, 1);
433
434 /* purge the name cache to deter others from finding it */
435 cache_purge(vp);
436
437 /* try to get the latest attributes */
438 attrerr = nfs_getattr(np, &nvattr, ap->a_context, 0);
439
440 /* Check if we should remove it from the node hash. */
441 /* Leave it if inuse or it has multiple hard links. */
442 if (vnode_isinuse(vp, 0) || (!attrerr && (nvattr.nva_nlink > 1))) {
443 unhash = 0;
444 } else {
445 unhash = 1;
446 ubc_setsize(vp, 0);
447 }
448
449 /* grab node lock on this node and the directory */
450 nfs_lock2(nsp->nsr_dnp, np, NFS_NODE_LOCK_FORCE);
451
452 /* lock the node while we remove the silly file */
453 lck_mtx_lock(nfs_node_hash_mutex);
454 while (np->n_hflag & NHLOCKED) {
455 np->n_hflag |= NHLOCKWANT;
456 msleep(np, nfs_node_hash_mutex, PINOD, "nfs_inactive", NULL);
457 }
458 np->n_hflag |= NHLOCKED;
459 lck_mtx_unlock(nfs_node_hash_mutex);
460
461 /* purge again in case it was looked up while we were locking */
462 cache_purge(vp);
463
464 FSDBG(264, np, np->n_size, np->n_vattr.nva_size, 0xf00d00f1);
465
466 /* now remove the silly file */
467 nfs_removeit(nsp);
468
469 /* clear all flags other than these */
470 np->n_flag &= (NMODIFIED);
471 nfs_unlock2(nsp->nsr_dnp, np);
472
473 if (unhash && vnode_isinuse(vp, 0)) {
474 /* vnode now inuse after silly remove? */
475 unhash = 0;
476 ubc_setsize(vp, np->n_size);
477 }
478
479 lck_mtx_lock(nfs_node_hash_mutex);
480 if (unhash) {
55e303ae
A
481 /*
482 * remove nfsnode from hash now so we can't accidentally find it
483 * again if another object gets created with the same filehandle
484 * before this vnode gets reclaimed
485 */
2d21ac55
A
486 if (np->n_hflag & NHHASHED) {
487 LIST_REMOVE(np, n_hash);
488 np->n_hflag &= ~NHHASHED;
489 FSDBG(266, 0, np, np->n_flag, 0xb1eb1e);
1c79356b 490 }
2d21ac55 491 vnode_recycle(vp);
1c79356b 492 }
2d21ac55
A
493 /* unlock the node */
494 np->n_hflag &= ~NHLOCKED;
495 if (np->n_hflag & NHLOCKWANT) {
496 np->n_hflag &= ~NHLOCKWANT;
497 wakeup(np);
498 }
499 lck_mtx_unlock(nfs_node_hash_mutex);
500
501 /* cleanup sillyrename info */
502 if (nsp->nsr_cred != NOCRED)
503 kauth_cred_unref(&nsp->nsr_cred);
504 vnode_rele(NFSTOV(nsp->nsr_dnp));
505 FREE_ZONE(nsp, sizeof(*nsp), M_NFSREQ);
506
507 FSDBG_BOT(264, vp, np, np->n_flag, 0);
1c79356b
A
508 return (0);
509}
510
511/*
512 * Reclaim an nfsnode so that it can be used for other purposes.
513 */
514int
2d21ac55 515nfs_vnop_reclaim(ap)
91447636
A
516 struct vnop_reclaim_args /* {
517 struct vnodeop_desc *a_desc;
518 vnode_t a_vp;
519 vfs_context_t a_context;
1c79356b
A
520 } */ *ap;
521{
91447636 522 vnode_t vp = ap->a_vp;
2d21ac55 523 nfsnode_t np = VTONFS(vp);
91447636 524 struct nfsdmap *dp, *dp2;
1c79356b 525
2d21ac55
A
526 FSDBG_TOP(265, vp, np, np->n_flag, 0);
527
528 lck_mtx_lock(nfs_node_hash_mutex);
529
530 if ((vnode_vtype(vp) != VDIR) && np->n_sillyrename)
531 printf("nfs_reclaim: leaving unlinked file %s\n", np->n_sillyrename->nsr_name);
532
91447636 533 vnode_removefsref(vp);
1c79356b 534
2d21ac55 535 if (np->n_hflag & NHHASHED) {
55e303ae 536 LIST_REMOVE(np, n_hash);
2d21ac55
A
537 np->n_hflag &= ~NHHASHED;
538 FSDBG(266, 0, np, np->n_flag, 0xb1eb1e);
1c79356b 539 }
2d21ac55 540 lck_mtx_unlock(nfs_node_hash_mutex);
1c79356b
A
541
542 /*
543 * Free up any directory cookie structures and
544 * large file handle structures that might be associated with
545 * this nfs node.
546 */
2d21ac55 547 nfs_lock(np, NFS_NODE_LOCK_FORCE);
91447636 548 if (vnode_vtype(vp) == VDIR) {
1c79356b
A
549 dp = np->n_cookies.lh_first;
550 while (dp) {
551 dp2 = dp;
552 dp = dp->ndm_list.le_next;
553 FREE_ZONE((caddr_t)dp2,
554 sizeof (struct nfsdmap), M_NFSDIROFF);
555 }
556 }
557 if (np->n_fhsize > NFS_SMALLFH) {
91447636 558 FREE_ZONE(np->n_fhp, np->n_fhsize, M_NFSBIGFH);
1c79356b 559 }
2d21ac55
A
560
561 nfs_unlock(np);
91447636 562 vnode_clearfsnode(vp);
1c79356b 563
2d21ac55
A
564 if (np->n_parent) {
565 if (!vnode_get(np->n_parent)) {
566 vnode_rele(np->n_parent);
567 vnode_put(np->n_parent);
568 }
569 np->n_parent = NULL;
570 }
571
572 lck_rw_destroy(&np->n_lock, nfs_node_lck_grp);
573 lck_rw_destroy(&np->n_datalock, nfs_node_lck_grp);
574
575 FSDBG_BOT(265, vp, np, np->n_flag, 0xd1ed1e);
91447636 576 FREE_ZONE(np, sizeof(struct nfsnode), M_NFSNODE);
1c79356b
A
577 return (0);
578}
579
2d21ac55
A
580/*
581 * Acquire an NFS node lock
582 */
583int
584nfs_lock(nfsnode_t np, int locktype)
585{
586 FSDBG_TOP(268, np, locktype, np->n_lockowner, 0);
587 if (locktype == NFS_NODE_LOCK_SHARED) {
588 lck_rw_lock_shared(&np->n_lock);
589 } else {
590 lck_rw_lock_exclusive(&np->n_lock);
591 np->n_lockowner = current_thread();
592 }
593 if ((locktype != NFS_NODE_LOCK_FORCE) && !(np->n_hflag && NHHASHED)) {
594 FSDBG_BOT(268, np, 0xdead, np->n_lockowner, 0);
595 nfs_unlock(np);
596 return (ENOENT);
597 }
598 FSDBG_BOT(268, np, locktype, np->n_lockowner, 0);
599 return (0);
600}
601
602/*
603 * Release an NFS node lock
604 */
605void
606nfs_unlock(nfsnode_t np)
607{
608 FSDBG(269, np, np->n_lockowner, current_thread(), 0);
609 np->n_lockowner = NULL;
610 lck_rw_done(&np->n_lock);
611}
612
613/*
614 * Acquire 2 NFS node locks
615 * - locks taken in order given (assumed to be parent-child order)
616 * - both or neither of the locks are taken
617 * - only one lock taken per node (dup nodes are skipped)
618 */
619int
620nfs_lock2(nfsnode_t np1, nfsnode_t np2, int locktype)
621{
622 int error;
623
624 if ((error = nfs_lock(np1, locktype)))
625 return (error);
626 if (np1 == np2)
627 return (error);
628 if ((error = nfs_lock(np2, locktype)))
629 nfs_unlock(np1);
630 return (error);
631}
632
633/*
634 * Unlock a couple of NFS nodes
635 */
636void
637nfs_unlock2(nfsnode_t np1, nfsnode_t np2)
638{
639 nfs_unlock(np1);
640 if (np1 != np2)
641 nfs_unlock(np2);
642}
643
644/*
645 * Acquire 4 NFS node locks
646 * - fdnp/fnp and tdnp/tnp locks taken in order given
647 * - otherwise locks taken in node address order.
648 * - all or none of the locks are taken
649 * - only one lock taken per node (dup nodes are skipped)
650 * - some of the node pointers may be null
651 */
652int
653nfs_lock4(nfsnode_t fdnp, nfsnode_t fnp, nfsnode_t tdnp, nfsnode_t tnp, int locktype)
654{
655 nfsnode_t list[4];
656 int i, lcnt = 0, error;
657
658 if (fdnp == tdnp) {
659 list[lcnt++] = fdnp;
660 } else if (fdnp->n_parent && (tdnp == VTONFS(fdnp->n_parent))) {
661 list[lcnt++] = tdnp;
662 list[lcnt++] = fdnp;
663 } else if (tdnp->n_parent && (fdnp == VTONFS(tdnp->n_parent))) {
664 list[lcnt++] = fdnp;
665 list[lcnt++] = tdnp;
666 } else if (fdnp < tdnp) {
667 list[lcnt++] = fdnp;
668 list[lcnt++] = tdnp;
669 } else {
670 list[lcnt++] = tdnp;
671 list[lcnt++] = fdnp;
672 }
673
674 if (!tnp || (fnp == tnp) || (tnp == fdnp)) {
675 list[lcnt++] = fnp;
676 } else if (fnp < tnp) {
677 list[lcnt++] = fnp;
678 list[lcnt++] = tnp;
679 } else {
680 list[lcnt++] = tnp;
681 list[lcnt++] = fnp;
682 }
683
684 /* Now we can lock using list[0 - lcnt-1] */
685 for (i = 0; i < lcnt; ++i) {
686 if (list[i])
687 if ((error = nfs_lock(list[i], locktype))) {
688 /* Drop any locks we acquired. */
689 while (--i >= 0) {
690 if (list[i])
691 nfs_unlock(list[i]);
692 }
693 return (error);
694 }
695 }
696 return (0);
697}
698
699/*
700 * Unlock a group of NFS nodes
701 */
702void
703nfs_unlock4(nfsnode_t np1, nfsnode_t np2, nfsnode_t np3, nfsnode_t np4)
704{
705 nfsnode_t list[4];
706 int i, k = 0;
707
708 if (np1) {
709 nfs_unlock(np1);
710 list[k++] = np1;
711 }
712 if (np2) {
713 for (i = 0; i < k; ++i)
714 if (list[i] == np2)
715 goto skip2;
716 nfs_unlock(np2);
717 list[k++] = np2;
718 }
719skip2:
720 if (np3) {
721 for (i = 0; i < k; ++i)
722 if (list[i] == np3)
723 goto skip3;
724 nfs_unlock(np3);
725 list[k++] = np3;
726 }
727skip3:
728 if (np4) {
729 for (i = 0; i < k; ++i)
730 if (list[i] == np4)
731 return;
732 nfs_unlock(np4);
733 }
734}
735
736/*
737 * Acquire an NFS node data lock
738 */
739void
740nfs_data_lock(nfsnode_t np, int locktype)
741{
742 nfs_data_lock2(np, locktype, 1);
743}
744void
745nfs_data_lock2(nfsnode_t np, int locktype, int updatesize)
746{
747 FSDBG_TOP(270, np, locktype, np->n_datalockowner, 0);
748 if (locktype == NFS_NODE_LOCK_SHARED) {
749 if (updatesize && ISSET(np->n_flag, NUPDATESIZE))
750 nfs_data_update_size(np, 0);
751 lck_rw_lock_shared(&np->n_datalock);
752 } else {
753 lck_rw_lock_exclusive(&np->n_datalock);
754 np->n_datalockowner = current_thread();
755 if (updatesize && ISSET(np->n_flag, NUPDATESIZE))
756 nfs_data_update_size(np, 1);
757 }
758 FSDBG_BOT(270, np, locktype, np->n_datalockowner, 0);
759}
760
761/*
762 * Release an NFS node data lock
763 */
764void
765nfs_data_unlock(nfsnode_t np)
766{
767 nfs_data_unlock2(np, 1);
768}
769void
770nfs_data_unlock2(nfsnode_t np, int updatesize)
771{
772 int mine = (np->n_datalockowner == current_thread());
773 FSDBG_TOP(271, np, np->n_datalockowner, current_thread(), 0);
774 if (updatesize && mine && ISSET(np->n_flag, NUPDATESIZE))
775 nfs_data_update_size(np, 1);
776 np->n_datalockowner = NULL;
777 lck_rw_done(&np->n_datalock);
778 if (updatesize && !mine && ISSET(np->n_flag, NUPDATESIZE))
779 nfs_data_update_size(np, 0);
780 FSDBG_BOT(271, np, np->n_datalockowner, current_thread(), 0);
781}
782
783
784/*
785 * update an NFS node's size
786 */
787void
788nfs_data_update_size(nfsnode_t np, int datalocked)
789{
790 int error;
791
792 FSDBG_TOP(272, np, np->n_flag, np->n_size, np->n_newsize);
793 if (!datalocked) {
794 nfs_data_lock(np, NFS_NODE_LOCK_EXCLUSIVE);
795 /* grabbing data lock will automatically update size */
796 nfs_data_unlock(np);
797 FSDBG_BOT(272, np, np->n_flag, np->n_size, np->n_newsize);
798 return;
799 }
800 error = nfs_lock(np, NFS_NODE_LOCK_EXCLUSIVE);
801 if (error || !ISSET(np->n_flag, NUPDATESIZE)) {
802 if (!error)
803 nfs_unlock(np);
804 FSDBG_BOT(272, np, np->n_flag, np->n_size, np->n_newsize);
805 return;
806 }
807 CLR(np->n_flag, NUPDATESIZE);
808 np->n_size = np->n_newsize;
809 /* make sure we invalidate buffers the next chance we get */
810 SET(np->n_flag, NNEEDINVALIDATE);
811 nfs_unlock(np);
812 ubc_setsize(NFSTOV(np), (off_t)np->n_size); /* XXX error? */
813 FSDBG_BOT(272, np, np->n_flag, np->n_size, np->n_newsize);
814}
815