]>
git.saurik.com Git - apple/xnu.git/blob - bsd/nfs/nfs_node.c
2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
30 * Copyright (c) 1989, 1993
31 * The Regents of the University of California. All rights reserved.
33 * This code is derived from software contributed to Berkeley by
34 * Rick Macklem at The University of Guelph.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
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.
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
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 $
69 #include <sys/param.h>
70 #include <sys/systm.h>
72 #include <sys/kauth.h>
73 #include <sys/mount_internal.h>
74 #include <sys/vnode.h>
76 #include <sys/malloc.h>
78 #include <nfs/rpcv2.h>
79 #include <nfs/nfsproto.h>
81 #include <nfs/nfsnode.h>
82 #include <nfs/nfs_gss.h>
83 #include <nfs/nfsmount.h>
85 #define NFSNOHASH(fhsum) \
86 (&nfsnodehashtbl[(fhsum) & nfsnodehash])
87 static LIST_HEAD(nfsnodehashhead
, nfsnode
) *nfsnodehashtbl
;
88 static u_long nfsnodehash
;
90 static lck_grp_t
*nfs_node_hash_lck_grp
;
91 static lck_grp_t
*nfs_node_lck_grp
;
92 lck_mtx_t
*nfs_node_hash_mutex
;
95 * Initialize hash links for nfsnodes
96 * and build nfsnode free list.
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
);
107 nfs_nhinit_finish(void)
109 lck_mtx_lock(nfs_node_hash_mutex
);
111 nfsnodehashtbl
= hashinit(desiredvnodes
, M_NFSNODE
, &nfsnodehash
);
112 lck_mtx_unlock(nfs_node_hash_mutex
);
116 * Compute an entry in the NFS hash table structure
119 nfs_hash(u_char
*fhp
, int fhsize
)
125 for (i
= 0; i
< fhsize
; i
++)
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.
140 struct componentname
*cnp
,
143 struct nfs_vattr
*nvap
,
149 struct nfsnodehashhead
*nhpp
;
153 struct vnode_fsparam vfsp
;
156 FSDBG_TOP(263, mp
, dnp
, flags
, npp
);
158 /* Check for unmount in progress */
159 if (!mp
|| (mp
->mnt_kern_flag
& MNTK_FRCUNMOUNT
)) {
162 FSDBG_BOT(263, mp
, dnp
, 0xd1e, error
);
165 nfsvers
= VFSTONFS(mp
)->nm_vers
;
167 nhpp
= NFSNOHASH(nfs_hash(fhp
, fhsize
));
169 lck_mtx_lock(nfs_node_hash_mutex
);
170 for (np
= nhpp
->lh_first
; np
!= 0; np
= np
->n_hash
.le_next
) {
171 mp2
= (np
->n_hflag
& NHINIT
) ? np
->n_mount
: NFSTOMP(np
);
172 if (mp
!= mp2
|| np
->n_fhsize
!= fhsize
||
173 bcmp(fhp
, np
->n_fhp
, fhsize
))
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);
186 lck_mtx_unlock(nfs_node_hash_mutex
);
187 if ((error
= vnode_getwithvid(vp
, vid
))) {
189 * If vnode is being reclaimed or has already
190 * changed identity, no need to wait.
192 FSDBG_BOT(263, dnp
, *npp
, 0xcace0d1e, error
);
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
);
202 /* update attributes */
203 error
= nfs_loadattrcache(np
, nvap
, xidp
, 0);
208 if (dnp
&& cnp
&& (flags
& NG_MAKEENTRY
))
209 cache_enter(NFSTOV(dnp
), vp
, cnp
);
212 FSDBG_BOT(263, dnp
, *npp
, 0xcace0000, error
);
216 FSDBG(263, mp
, dnp
, npp
, 0xaaaaaaaa);
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.
223 MALLOC_ZONE(np
, nfsnode_t
, sizeof *np
, M_NFSNODE
, M_WAITOK
);
225 lck_mtx_unlock(nfs_node_hash_mutex
);
227 FSDBG_BOT(263, dnp
, *npp
, 0x80000001, ENOMEM
);
230 bzero(np
, sizeof *np
);
231 np
->n_hflag
|= (NHINIT
| NHLOCKED
);
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
)) {
244 /* setup node's file handle */
245 if (fhsize
> NFS_SMALLFH
) {
246 MALLOC_ZONE(np
->n_fhp
, u_char
*,
247 fhsize
, M_NFSBIGFH
, M_WAITOK
);
249 lck_mtx_unlock(nfs_node_hash_mutex
);
250 FREE_ZONE(np
, sizeof *np
, M_NFSNODE
);
252 FSDBG_BOT(263, dnp
, *npp
, 0x80000002, ENOMEM
);
256 np
->n_fhp
= &np
->n_fh
[0];
258 bcopy(fhp
, np
->n_fhp
, fhsize
);
259 np
->n_fhsize
= fhsize
;
261 /* Insert the nfsnode in the hash queue for its new file handle */
262 LIST_INSERT_HEAD(nhpp
, np
, n_hash
);
263 np
->n_hflag
|= NHHASHED
;
264 FSDBG(266, 0, np
, np
->n_flag
, np
->n_hflag
);
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
);
271 /* release lock on hash table */
272 lck_mtx_unlock(nfs_node_hash_mutex
);
274 /* do initial loading of attributes */
275 error
= nfs_loadattrcache(np
, nvap
, xidp
, 1);
277 FSDBG(266, 0, np
, np
->n_flag
, 0xb1eb1e);
279 lck_mtx_lock(nfs_node_hash_mutex
);
280 LIST_REMOVE(np
, n_hash
);
281 np
->n_hflag
&= ~(NHHASHED
|NHINIT
|NHLOCKED
);
282 if (np
->n_hflag
& NHLOCKWANT
) {
283 np
->n_hflag
&= ~NHLOCKWANT
;
286 lck_mtx_unlock(nfs_node_hash_mutex
);
288 if (!vnode_get(np
->n_parent
)) {
289 vnode_rele(np
->n_parent
);
290 vnode_put(np
->n_parent
);
294 lck_rw_destroy(&np
->n_lock
, nfs_node_lck_grp
);
295 lck_rw_destroy(&np
->n_datalock
, nfs_node_lck_grp
);
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
);
300 FSDBG_BOT(263, dnp
, *npp
, 0x80000003, error
);
303 NFS_CHANGED_UPDATE(nfsvers
, np
, nvap
);
304 if (nvap
->nva_type
== VDIR
)
305 NFS_CHANGED_UPDATE_NC(nfsvers
, np
, nvap
);
308 /* now, attempt to get a new vnode */
310 vfsp
.vnfs_vtype
= nvap
->nva_type
;
311 vfsp
.vnfs_str
= "nfs";
312 vfsp
.vnfs_dvp
= dnp
? NFSTOV(dnp
) : NULL
;
313 vfsp
.vnfs_fsnode
= np
;
314 if (nfsvers
== NFS_VER4
) {
316 if (nvap
->nva_type
== VFIFO
)
317 vfsp
.vnfs_vops
= fifo_nfsv4nodeop_p
;
320 if (nvap
->nva_type
== VBLK
|| nvap
->nva_type
== VCHR
)
321 vfsp
.vnfs_vops
= spec_nfsv4nodeop_p
;
323 vfsp
.vnfs_vops
= nfsv4_vnodeop_p
;
326 if (nvap
->nva_type
== VFIFO
)
327 vfsp
.vnfs_vops
= fifo_nfsv2nodeop_p
;
330 if (nvap
->nva_type
== VBLK
|| nvap
->nva_type
== VCHR
)
331 vfsp
.vnfs_vops
= spec_nfsv2nodeop_p
;
333 vfsp
.vnfs_vops
= nfsv2_vnodeop_p
;
335 vfsp
.vnfs_markroot
= (flags
& NG_MARKROOT
) ? 1 : 0;
336 vfsp
.vnfs_marksystem
= 0;
338 vfsp
.vnfs_filesize
= nvap
->nva_size
;
340 vfsp
.vnfs_flags
= VNFS_ADDFSREF
;
341 if (!dnp
|| !cnp
|| !(flags
& NG_MAKEENTRY
))
342 vfsp
.vnfs_flags
|= VNFS_NOCACHE
;
344 error
= vnode_create(VNCREATE_FLAVOR
, VCREATESIZE
, &vfsp
, &np
->n_vnode
);
346 FSDBG(266, 0, np
, np
->n_flag
, 0xb1eb1e);
348 lck_mtx_lock(nfs_node_hash_mutex
);
349 LIST_REMOVE(np
, n_hash
);
350 np
->n_hflag
&= ~(NHHASHED
|NHINIT
|NHLOCKED
);
351 if (np
->n_hflag
& NHLOCKWANT
) {
352 np
->n_hflag
&= ~NHLOCKWANT
;
355 lck_mtx_unlock(nfs_node_hash_mutex
);
357 if (!vnode_get(np
->n_parent
)) {
358 vnode_rele(np
->n_parent
);
359 vnode_put(np
->n_parent
);
363 lck_rw_destroy(&np
->n_lock
, nfs_node_lck_grp
);
364 lck_rw_destroy(&np
->n_datalock
, nfs_node_lck_grp
);
365 if (np
->n_fhsize
> NFS_SMALLFH
)
366 FREE_ZONE(np
->n_fhp
, np
->n_fhsize
, M_NFSBIGFH
);
367 FREE_ZONE(np
, sizeof *np
, M_NFSNODE
);
369 FSDBG_BOT(263, dnp
, *npp
, 0x80000004, error
);
373 vnode_settag(vp
, VT_NFS
);
374 /* node is now initialized */
376 /* check if anyone's waiting on this node */
377 lck_mtx_lock(nfs_node_hash_mutex
);
378 np
->n_hflag
&= ~(NHINIT
|NHLOCKED
);
379 if (np
->n_hflag
& NHLOCKWANT
) {
380 np
->n_hflag
&= ~NHLOCKWANT
;
383 lck_mtx_unlock(nfs_node_hash_mutex
);
387 FSDBG_BOT(263, dnp
, vp
, *npp
, error
);
393 nfs_vnop_inactive(ap
)
394 struct vnop_inactive_args
/* {
395 struct vnodeop_desc *a_desc;
397 vfs_context_t a_context;
402 struct nfs_sillyrename
*nsp
;
403 struct nfs_vattr nvattr
;
407 np
= VTONFS(ap
->a_vp
);
409 nfs_lock(np
, NFS_NODE_LOCK_FORCE
);
411 if (vnode_vtype(vp
) != VDIR
) {
412 nsp
= np
->n_sillyrename
;
413 np
->n_sillyrename
= NULL
;
417 FSDBG_TOP(264, vp
, np
, np
->n_flag
, nsp
);
420 /* no silly file to clean up... */
421 /* clear all flags other than these */
422 np
->n_flag
&= (NMODIFIED
);
424 FSDBG_BOT(264, vp
, np
, np
->n_flag
, 0);
428 /* Remove the silly file that was rename'd earlier */
430 /* flush all the buffers */
432 nfs_vinvalbuf2(vp
, V_SAVE
, vfs_context_thread(ap
->a_context
), nsp
->nsr_cred
, 1);
434 /* purge the name cache to deter others from finding it */
437 /* try to get the latest attributes */
438 attrerr
= nfs_getattr(np
, &nvattr
, ap
->a_context
, 0);
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))) {
449 /* grab node lock on this node and the directory */
450 nfs_lock2(nsp
->nsr_dnp
, np
, NFS_NODE_LOCK_FORCE
);
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
);
458 np
->n_hflag
|= NHLOCKED
;
459 lck_mtx_unlock(nfs_node_hash_mutex
);
461 /* purge again in case it was looked up while we were locking */
464 FSDBG(264, np
, np
->n_size
, np
->n_vattr
.nva_size
, 0xf00d00f1);
466 /* now remove the silly file */
469 /* clear all flags other than these */
470 np
->n_flag
&= (NMODIFIED
);
471 nfs_unlock2(nsp
->nsr_dnp
, np
);
473 if (unhash
&& vnode_isinuse(vp
, 0)) {
474 /* vnode now inuse after silly remove? */
476 ubc_setsize(vp
, np
->n_size
);
479 lck_mtx_lock(nfs_node_hash_mutex
);
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
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);
493 /* unlock the node */
494 np
->n_hflag
&= ~NHLOCKED
;
495 if (np
->n_hflag
& NHLOCKWANT
) {
496 np
->n_hflag
&= ~NHLOCKWANT
;
499 lck_mtx_unlock(nfs_node_hash_mutex
);
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
);
507 FSDBG_BOT(264, vp
, np
, np
->n_flag
, 0);
512 * Reclaim an nfsnode so that it can be used for other purposes.
516 struct vnop_reclaim_args
/* {
517 struct vnodeop_desc *a_desc;
519 vfs_context_t a_context;
522 vnode_t vp
= ap
->a_vp
;
523 nfsnode_t np
= VTONFS(vp
);
524 struct nfsdmap
*dp
, *dp2
;
526 FSDBG_TOP(265, vp
, np
, np
->n_flag
, 0);
528 lck_mtx_lock(nfs_node_hash_mutex
);
530 if ((vnode_vtype(vp
) != VDIR
) && np
->n_sillyrename
)
531 printf("nfs_reclaim: leaving unlinked file %s\n", np
->n_sillyrename
->nsr_name
);
533 vnode_removefsref(vp
);
535 if (np
->n_hflag
& NHHASHED
) {
536 LIST_REMOVE(np
, n_hash
);
537 np
->n_hflag
&= ~NHHASHED
;
538 FSDBG(266, 0, np
, np
->n_flag
, 0xb1eb1e);
540 lck_mtx_unlock(nfs_node_hash_mutex
);
543 * Free up any directory cookie structures and
544 * large file handle structures that might be associated with
547 nfs_lock(np
, NFS_NODE_LOCK_FORCE
);
548 if (vnode_vtype(vp
) == VDIR
) {
549 dp
= np
->n_cookies
.lh_first
;
552 dp
= dp
->ndm_list
.le_next
;
553 FREE_ZONE((caddr_t
)dp2
,
554 sizeof (struct nfsdmap
), M_NFSDIROFF
);
557 if (np
->n_fhsize
> NFS_SMALLFH
) {
558 FREE_ZONE(np
->n_fhp
, np
->n_fhsize
, M_NFSBIGFH
);
562 vnode_clearfsnode(vp
);
565 if (!vnode_get(np
->n_parent
)) {
566 vnode_rele(np
->n_parent
);
567 vnode_put(np
->n_parent
);
572 lck_rw_destroy(&np
->n_lock
, nfs_node_lck_grp
);
573 lck_rw_destroy(&np
->n_datalock
, nfs_node_lck_grp
);
575 FSDBG_BOT(265, vp
, np
, np
->n_flag
, 0xd1ed1e);
576 FREE_ZONE(np
, sizeof(struct nfsnode
), M_NFSNODE
);
581 * Acquire an NFS node lock
584 nfs_lock(nfsnode_t np
, int locktype
)
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
);
590 lck_rw_lock_exclusive(&np
->n_lock
);
591 np
->n_lockowner
= current_thread();
593 if ((locktype
!= NFS_NODE_LOCK_FORCE
) && !(np
->n_hflag
&& NHHASHED
)) {
594 FSDBG_BOT(268, np
, 0xdead, np
->n_lockowner
, 0);
598 FSDBG_BOT(268, np
, locktype
, np
->n_lockowner
, 0);
603 * Release an NFS node lock
606 nfs_unlock(nfsnode_t np
)
608 FSDBG(269, np
, np
->n_lockowner
, current_thread(), 0);
609 np
->n_lockowner
= NULL
;
610 lck_rw_done(&np
->n_lock
);
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)
620 nfs_lock2(nfsnode_t np1
, nfsnode_t np2
, int locktype
)
624 if ((error
= nfs_lock(np1
, locktype
)))
628 if ((error
= nfs_lock(np2
, locktype
)))
634 * Unlock a couple of NFS nodes
637 nfs_unlock2(nfsnode_t np1
, nfsnode_t np2
)
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
653 nfs_lock4(nfsnode_t fdnp
, nfsnode_t fnp
, nfsnode_t tdnp
, nfsnode_t tnp
, int locktype
)
656 int i
, lcnt
= 0, error
;
660 } else if (fdnp
->n_parent
&& (tdnp
== VTONFS(fdnp
->n_parent
))) {
663 } else if (tdnp
->n_parent
&& (fdnp
== VTONFS(tdnp
->n_parent
))) {
666 } else if (fdnp
< tdnp
) {
674 if (!tnp
|| (fnp
== tnp
) || (tnp
== fdnp
)) {
676 } else if (fnp
< tnp
) {
684 /* Now we can lock using list[0 - lcnt-1] */
685 for (i
= 0; i
< lcnt
; ++i
) {
687 if ((error
= nfs_lock(list
[i
], locktype
))) {
688 /* Drop any locks we acquired. */
700 * Unlock a group of NFS nodes
703 nfs_unlock4(nfsnode_t np1
, nfsnode_t np2
, nfsnode_t np3
, nfsnode_t np4
)
713 for (i
= 0; i
< k
; ++i
)
721 for (i
= 0; i
< k
; ++i
)
729 for (i
= 0; i
< k
; ++i
)
737 * Acquire an NFS node data lock
740 nfs_data_lock(nfsnode_t np
, int locktype
)
742 nfs_data_lock2(np
, locktype
, 1);
745 nfs_data_lock2(nfsnode_t np
, int locktype
, int updatesize
)
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
);
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);
758 FSDBG_BOT(270, np
, locktype
, np
->n_datalockowner
, 0);
762 * Release an NFS node data lock
765 nfs_data_unlock(nfsnode_t np
)
767 nfs_data_unlock2(np
, 1);
770 nfs_data_unlock2(nfsnode_t np
, int updatesize
)
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);
785 * update an NFS node's size
788 nfs_data_update_size(nfsnode_t np
, int datalocked
)
792 FSDBG_TOP(272, np
, np
->n_flag
, np
->n_size
, np
->n_newsize
);
794 nfs_data_lock(np
, NFS_NODE_LOCK_EXCLUSIVE
);
795 /* grabbing data lock will automatically update size */
797 FSDBG_BOT(272, np
, np
->n_flag
, np
->n_size
, np
->n_newsize
);
800 error
= nfs_lock(np
, NFS_NODE_LOCK_EXCLUSIVE
);
801 if (error
|| !ISSET(np
->n_flag
, NUPDATESIZE
)) {
804 FSDBG_BOT(272, np
, np
->n_flag
, np
->n_size
, np
->n_newsize
);
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
);
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
);