2  * Copyright (c) 2000-2009 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/kernel.h> 
  71 #include <sys/systm.h> 
  73 #include <sys/kauth.h> 
  74 #include <sys/mount_internal.h> 
  75 #include <sys/vnode.h> 
  77 #include <sys/malloc.h> 
  79 #include <nfs/rpcv2.h> 
  80 #include <nfs/nfsproto.h> 
  82 #include <nfs/nfsnode.h> 
  83 #include <nfs/nfs_gss.h> 
  84 #include <nfs/nfsmount.h> 
  86 #define NFSNOHASH(fhsum) \ 
  87         (&nfsnodehashtbl[(fhsum) & nfsnodehash]) 
  88 static LIST_HEAD(nfsnodehashhead
, nfsnode
) *nfsnodehashtbl
; 
  89 static u_long nfsnodehash
; 
  91 static lck_grp_t 
*nfs_node_hash_lck_grp
; 
  92 static lck_grp_t 
*nfs_node_lck_grp
; 
  93 static lck_grp_t 
*nfs_data_lck_grp
; 
  94 lck_mtx_t 
*nfs_node_hash_mutex
; 
  97  * Initialize hash links for nfsnodes 
  98  * and build nfsnode free list. 
 103         nfs_node_hash_lck_grp 
= lck_grp_alloc_init("nfs_node_hash", LCK_GRP_ATTR_NULL
); 
 104         nfs_node_hash_mutex 
= lck_mtx_alloc_init(nfs_node_hash_lck_grp
, LCK_ATTR_NULL
); 
 105         nfs_node_lck_grp 
= lck_grp_alloc_init("nfs_node", LCK_GRP_ATTR_NULL
); 
 106         nfs_data_lck_grp 
= lck_grp_alloc_init("nfs_data", LCK_GRP_ATTR_NULL
); 
 110 nfs_nhinit_finish(void) 
 112         lck_mtx_lock(nfs_node_hash_mutex
); 
 114                 nfsnodehashtbl 
= hashinit(desiredvnodes
, M_NFSNODE
, &nfsnodehash
); 
 115         lck_mtx_unlock(nfs_node_hash_mutex
); 
 119  * Compute an entry in the NFS hash table structure 
 122 nfs_hash(u_char 
*fhp
, int fhsize
) 
 128         for (i 
= 0; i 
< fhsize
; i
++) 
 134  * Look up a vnode/nfsnode by file handle. 
 135  * Callers must check for mount points!! 
 136  * In all cases, a pointer to a 
 137  * nfsnode structure is returned. 
 143         struct componentname 
*cnp
, 
 146         struct nfs_vattr 
*nvap
, 
 152         struct nfsnodehashhead 
*nhpp
; 
 156         struct vnode_fsparam vfsp
; 
 159         FSDBG_TOP(263, mp
, dnp
, flags
, npp
); 
 161         /* Check for unmount in progress */ 
 162         if (!mp 
|| (mp
->mnt_kern_flag 
& MNTK_FRCUNMOUNT
)) { 
 165                 FSDBG_BOT(263, mp
, dnp
, 0xd1e, error
); 
 168         nfsvers 
= VFSTONFS(mp
)->nm_vers
; 
 170         nhpp 
= NFSNOHASH(nfs_hash(fhp
, fhsize
)); 
 172         lck_mtx_lock(nfs_node_hash_mutex
); 
 173         for (np 
= nhpp
->lh_first
; np 
!= 0; np 
= np
->n_hash
.le_next
) { 
 174                 mp2 
= (np
->n_hflag 
& NHINIT
) ? np
->n_mount 
: NFSTOMP(np
); 
 175                 if (mp 
!= mp2 
|| np
->n_fhsize 
!= fhsize 
|| 
 176                     bcmp(fhp
, np
->n_fhp
, fhsize
)) 
 178                 FSDBG(263, dnp
, np
, np
->n_flag
, 0xcace0000); 
 179                 /* if the node is locked, sleep on it */ 
 180                 if ((np
->n_hflag 
& NHLOCKED
) && !(flags 
& NG_NOCREATE
)) { 
 181                         np
->n_hflag 
|= NHLOCKWANT
; 
 182                         FSDBG(263, dnp
, np
, np
->n_flag
, 0xcace2222); 
 183                         msleep(np
, nfs_node_hash_mutex
, PDROP 
| PINOD
, "nfs_nget", NULL
); 
 184                         FSDBG(263, dnp
, np
, np
->n_flag
, 0xcace3333); 
 189                 lck_mtx_unlock(nfs_node_hash_mutex
); 
 190                 if ((error 
= vnode_getwithvid(vp
, vid
))) { 
 192                          * If vnode is being reclaimed or has already 
 193                          * changed identity, no need to wait. 
 195                         FSDBG_BOT(263, dnp
, *npp
, 0xcace0d1e, error
); 
 198                 if ((error 
= nfs_node_lock(np
))) { 
 199                         /* this only fails if the node is now unhashed */ 
 200                         /* so let's see if we can find/create it again */ 
 201                         FSDBG(263, dnp
, *npp
, 0xcaced1e2, error
); 
 203                         if (flags 
& NG_NOCREATE
) { 
 205                                 FSDBG_BOT(263, dnp
, *npp
, 0xcaced1e0, ENOENT
); 
 210                 /* update attributes */ 
 212                         error 
= nfs_loadattrcache(np
, nvap
, xidp
, 0); 
 217                         if (dnp 
&& cnp 
&& (flags 
& NG_MAKEENTRY
)) 
 218                                 cache_enter(NFSTOV(dnp
), vp
, cnp
); 
 221                 FSDBG_BOT(263, dnp
, *npp
, 0xcace0000, error
); 
 225         FSDBG(263, mp
, dnp
, npp
, 0xaaaaaaaa); 
 227         if (flags 
& NG_NOCREATE
) { 
 228                 lck_mtx_unlock(nfs_node_hash_mutex
); 
 230                 FSDBG_BOT(263, dnp
, *npp
, 0x80000001, ENOENT
); 
 235          * allocate and initialize nfsnode and stick it in the hash 
 236          * before calling getnewvnode().  Anyone finding it in the 
 237          * hash before initialization is complete will wait for it. 
 239         MALLOC_ZONE(np
, nfsnode_t
, sizeof *np
, M_NFSNODE
, M_WAITOK
); 
 241                 lck_mtx_unlock(nfs_node_hash_mutex
); 
 243                 FSDBG_BOT(263, dnp
, *npp
, 0x80000001, ENOMEM
); 
 246         bzero(np
, sizeof *np
); 
 247         np
->n_hflag 
|= (NHINIT 
| NHLOCKED
); 
 249         TAILQ_INIT(&np
->n_opens
); 
 250         TAILQ_INIT(&np
->n_lock_owners
); 
 251         TAILQ_INIT(&np
->n_locks
); 
 252         np
->n_dlink
.tqe_next 
= NFSNOLIST
; 
 254         if (dnp 
&& cnp 
&& ((cnp
->cn_namelen 
!= 2) || 
 255             (cnp
->cn_nameptr
[0] != '.') || (cnp
->cn_nameptr
[1] != '.'))) { 
 256                 vnode_t dvp 
= NFSTOV(dnp
); 
 257                 if (!vnode_get(dvp
)) { 
 264         /* setup node's file handle */ 
 265         if (fhsize 
> NFS_SMALLFH
) { 
 266                 MALLOC_ZONE(np
->n_fhp
, u_char 
*, 
 267                                 fhsize
, M_NFSBIGFH
, M_WAITOK
); 
 269                         lck_mtx_unlock(nfs_node_hash_mutex
); 
 270                         FREE_ZONE(np
, sizeof *np
, M_NFSNODE
); 
 272                         FSDBG_BOT(263, dnp
, *npp
, 0x80000002, ENOMEM
); 
 276                 np
->n_fhp 
= &np
->n_fh
[0]; 
 278         bcopy(fhp
, np
->n_fhp
, fhsize
); 
 279         np
->n_fhsize 
= fhsize
; 
 281         /* Insert the nfsnode in the hash queue for its new file handle */ 
 282         LIST_INSERT_HEAD(nhpp
, np
, n_hash
); 
 283         np
->n_hflag 
|= NHHASHED
; 
 284         FSDBG(266, 0, np
, np
->n_flag
, np
->n_hflag
); 
 286         /* lock the new nfsnode */ 
 287         lck_mtx_init(&np
->n_lock
, nfs_node_lck_grp
, LCK_ATTR_NULL
); 
 288         lck_rw_init(&np
->n_datalock
, nfs_data_lck_grp
, LCK_ATTR_NULL
); 
 289         lck_mtx_init(&np
->n_openlock
, nfs_open_grp
, LCK_ATTR_NULL
); 
 290         lck_mtx_lock(&np
->n_lock
); 
 292         /* release lock on hash table */ 
 293         lck_mtx_unlock(nfs_node_hash_mutex
); 
 295         /* do initial loading of attributes */ 
 296         error 
= nfs_loadattrcache(np
, nvap
, xidp
, 1); 
 298                 FSDBG(266, 0, np
, np
->n_flag
, 0xb1eb1e); 
 300                 lck_mtx_lock(nfs_node_hash_mutex
); 
 301                 LIST_REMOVE(np
, n_hash
); 
 302                 np
->n_hflag 
&= ~(NHHASHED
|NHINIT
|NHLOCKED
); 
 303                 if (np
->n_hflag 
& NHLOCKWANT
) { 
 304                         np
->n_hflag 
&= ~NHLOCKWANT
; 
 307                 lck_mtx_unlock(nfs_node_hash_mutex
); 
 309                         if (!vnode_get(np
->n_parent
)) { 
 310                                 vnode_rele(np
->n_parent
); 
 311                                 vnode_put(np
->n_parent
); 
 315                 lck_mtx_destroy(&np
->n_lock
, nfs_node_lck_grp
); 
 316                 lck_rw_destroy(&np
->n_datalock
, nfs_data_lck_grp
); 
 317                 lck_mtx_destroy(&np
->n_openlock
, nfs_open_grp
); 
 318                 if (np
->n_fhsize 
> NFS_SMALLFH
) 
 319                         FREE_ZONE(np
->n_fhp
, np
->n_fhsize
, M_NFSBIGFH
); 
 320                 FREE_ZONE(np
, sizeof *np
, M_NFSNODE
); 
 322                 FSDBG_BOT(263, dnp
, *npp
, 0x80000003, error
); 
 325         NFS_CHANGED_UPDATE(nfsvers
, np
, nvap
); 
 326         if (nvap
->nva_type 
== VDIR
) 
 327                 NFS_CHANGED_UPDATE_NC(nfsvers
, np
, nvap
); 
 330         /* now, attempt to get a new vnode */ 
 332         vfsp
.vnfs_vtype 
= nvap
->nva_type
; 
 333         vfsp
.vnfs_str 
= "nfs"; 
 334         vfsp
.vnfs_dvp 
= dnp 
? NFSTOV(dnp
) : NULL
; 
 335         vfsp
.vnfs_fsnode 
= np
; 
 336         if (nfsvers 
== NFS_VER4
) { 
 338                 if (nvap
->nva_type 
== VFIFO
) 
 339                         vfsp
.vnfs_vops 
= fifo_nfsv4nodeop_p
; 
 342                 if (nvap
->nva_type 
== VBLK 
|| nvap
->nva_type 
== VCHR
) 
 343                         vfsp
.vnfs_vops 
= spec_nfsv4nodeop_p
; 
 345                         vfsp
.vnfs_vops 
= nfsv4_vnodeop_p
; 
 348                 if (nvap
->nva_type 
== VFIFO
) 
 349                         vfsp
.vnfs_vops 
= fifo_nfsv2nodeop_p
; 
 352                 if (nvap
->nva_type 
== VBLK 
|| nvap
->nva_type 
== VCHR
) 
 353                         vfsp
.vnfs_vops 
= spec_nfsv2nodeop_p
; 
 355                         vfsp
.vnfs_vops 
= nfsv2_vnodeop_p
; 
 357         vfsp
.vnfs_markroot 
= (flags 
& NG_MARKROOT
) ? 1 : 0; 
 358         vfsp
.vnfs_marksystem 
= 0; 
 360         vfsp
.vnfs_filesize 
= nvap
->nva_size
; 
 362         vfsp
.vnfs_flags 
= VNFS_ADDFSREF
; 
 363         if (!dnp 
|| !cnp 
|| !(flags 
& NG_MAKEENTRY
)) 
 364                 vfsp
.vnfs_flags 
|= VNFS_NOCACHE
; 
 366         error 
= vnode_create(VNCREATE_FLAVOR
, VCREATESIZE
, &vfsp
, &np
->n_vnode
); 
 368                 FSDBG(266, 0, np
, np
->n_flag
, 0xb1eb1e); 
 370                 lck_mtx_lock(nfs_node_hash_mutex
); 
 371                 LIST_REMOVE(np
, n_hash
); 
 372                 np
->n_hflag 
&= ~(NHHASHED
|NHINIT
|NHLOCKED
); 
 373                 if (np
->n_hflag 
& NHLOCKWANT
) { 
 374                         np
->n_hflag 
&= ~NHLOCKWANT
; 
 377                 lck_mtx_unlock(nfs_node_hash_mutex
); 
 379                         if (!vnode_get(np
->n_parent
)) { 
 380                                 vnode_rele(np
->n_parent
); 
 381                                 vnode_put(np
->n_parent
); 
 385                 lck_mtx_destroy(&np
->n_lock
, nfs_node_lck_grp
); 
 386                 lck_rw_destroy(&np
->n_datalock
, nfs_data_lck_grp
); 
 387                 lck_mtx_destroy(&np
->n_openlock
, nfs_open_grp
); 
 388                 if (np
->n_fhsize 
> NFS_SMALLFH
) 
 389                         FREE_ZONE(np
->n_fhp
, np
->n_fhsize
, M_NFSBIGFH
); 
 390                 FREE_ZONE(np
, sizeof *np
, M_NFSNODE
); 
 392                 FSDBG_BOT(263, dnp
, *npp
, 0x80000004, error
); 
 396         vnode_settag(vp
, VT_NFS
); 
 397         /* node is now initialized */ 
 399         /* check if anyone's waiting on this node */ 
 400         lck_mtx_lock(nfs_node_hash_mutex
); 
 401         np
->n_hflag 
&= ~(NHINIT
|NHLOCKED
); 
 402         if (np
->n_hflag 
& NHLOCKWANT
) { 
 403                 np
->n_hflag 
&= ~NHLOCKWANT
; 
 406         lck_mtx_unlock(nfs_node_hash_mutex
); 
 410         FSDBG_BOT(263, dnp
, vp
, *npp
, error
); 
 416 nfs_vnop_inactive(ap
) 
 417         struct vnop_inactive_args 
/* { 
 418                 struct vnodeop_desc *a_desc; 
 420                 vfs_context_t a_context; 
 423         vnode_t vp 
= ap
->a_vp
; 
 424         vfs_context_t ctx 
= ap
->a_context
; 
 425         nfsnode_t np 
= VTONFS(ap
->a_vp
); 
 426         struct nfs_sillyrename 
*nsp
; 
 427         struct nfs_vattr nvattr
; 
 428         int unhash
, attrerr
, busyerror
, error
, inuse
, busied
; 
 429         struct nfs_open_file 
*nofp
; 
 430         const char *vname 
= NULL
; 
 431         struct componentname cn
; 
 432         struct nfsmount 
*nmp 
= NFSTONMP(np
); 
 436         inuse 
= ((nmp
->nm_vers 
>= NFS_VER4
) && (nfs_mount_state_in_use_start(nmp
) == 0)); 
 438         /* There shouldn't be any open or lock state at this point */ 
 439         lck_mtx_lock(&np
->n_openlock
); 
 440         if (np
->n_openrefcnt
) { 
 441                 vname 
= vnode_getname(vp
); 
 442                 printf("nfs_vnop_inactive: still open: %d %s\n", np
->n_openrefcnt
, vname 
? vname 
: "//"); 
 444         TAILQ_FOREACH(nofp
, &np
->n_opens
, nof_link
) { 
 445                 lck_mtx_lock(&nofp
->nof_lock
); 
 446                 if (nofp
->nof_flags 
& NFS_OPEN_FILE_BUSY
) { 
 448                                 vname 
= vnode_getname(vp
); 
 449                         printf("nfs_vnop_inactive: open file busy: %s\n", vname 
? vname 
: "//"); 
 452                         nofp
->nof_flags 
|= NFS_OPEN_FILE_BUSY
; 
 455                 lck_mtx_unlock(&nofp
->nof_lock
); 
 457                  * If we just created the file, we already had it open in 
 458                  * anticipation of getting a subsequent open call.  If the 
 459                  * node has gone inactive without being open, we need to 
 460                  * clean up (close) the open done in the create. 
 462                 if ((nofp
->nof_flags 
& NFS_OPEN_FILE_CREATE
) && nofp
->nof_creator
) { 
 463                         if (nofp
->nof_flags 
& NFS_OPEN_FILE_REOPEN
) { 
 464                                 lck_mtx_unlock(&np
->n_openlock
); 
 466                                         nfs_open_file_clear_busy(nofp
); 
 468                                         nfs_mount_state_in_use_end(nmp
, 0); 
 469                                 nfs4_reopen(nofp
, vfs_context_thread(ctx
)); 
 472                         nofp
->nof_flags 
&= ~NFS_OPEN_FILE_CREATE
; 
 473                         lck_mtx_unlock(&np
->n_openlock
); 
 474                         error 
= nfs4_close(np
, nofp
, NFS_OPEN_SHARE_ACCESS_BOTH
, NFS_OPEN_SHARE_DENY_NONE
, ctx
); 
 477                                         vname 
= vnode_getname(vp
); 
 478                                 printf("nfs_vnop_inactive: create close error: %d, %s\n", error
, vname
); 
 479                                 nofp
->nof_flags 
|= NFS_OPEN_FILE_CREATE
; 
 482                                 nfs_open_file_clear_busy(nofp
); 
 484                                 nfs_mount_state_in_use_end(nmp
, error
); 
 487                 if (nofp
->nof_flags 
& NFS_OPEN_FILE_NEEDCLOSE
) { 
 489                          * If the file is marked as needing reopen, but this was the only 
 490                          * open on the file, just drop the open. 
 492                         nofp
->nof_flags 
&= ~NFS_OPEN_FILE_NEEDCLOSE
; 
 493                         if ((nofp
->nof_flags 
& NFS_OPEN_FILE_REOPEN
) && (nofp
->nof_opencnt 
== 1)) { 
 494                                 nofp
->nof_flags 
&= ~NFS_OPEN_FILE_REOPEN
; 
 497                                 nofp
->nof_access 
= 0; 
 499                                 lck_mtx_unlock(&np
->n_openlock
); 
 500                                 if (nofp
->nof_flags 
& NFS_OPEN_FILE_REOPEN
) { 
 502                                                 nfs_open_file_clear_busy(nofp
); 
 504                                                 nfs_mount_state_in_use_end(nmp
, 0); 
 505                                         nfs4_reopen(nofp
, vfs_context_thread(ctx
)); 
 508                                 error 
= nfs4_close(np
, nofp
, NFS_OPEN_SHARE_ACCESS_READ
, NFS_OPEN_SHARE_DENY_NONE
, ctx
); 
 511                                                 vname 
= vnode_getname(vp
); 
 512                                         printf("nfs_vnop_inactive: need close error: %d, %s\n", error
, vname
); 
 513                                         nofp
->nof_flags 
|= NFS_OPEN_FILE_NEEDCLOSE
; 
 516                                         nfs_open_file_clear_busy(nofp
); 
 518                                         nfs_mount_state_in_use_end(nmp
, error
); 
 522                 if (nofp
->nof_opencnt
) { 
 524                                 vname 
= vnode_getname(vp
); 
 525                         printf("nfs_vnop_inactive: file still open: %d %s\n", nofp
->nof_opencnt
, vname 
? vname 
: "//"); 
 527                 if (nofp
->nof_access 
|| nofp
->nof_deny 
|| 
 528                     nofp
->nof_mmap_access 
|| nofp
->nof_mmap_deny 
|| 
 529                     nofp
->nof_r 
|| nofp
->nof_w 
|| nofp
->nof_rw 
|| 
 530                     nofp
->nof_r_dw 
|| nofp
->nof_w_dw 
|| nofp
->nof_rw_dw 
|| 
 531                     nofp
->nof_r_drw 
|| nofp
->nof_w_drw 
|| nofp
->nof_rw_drw
) { 
 533                                 vname 
= vnode_getname(vp
); 
 534                         printf("nfs_vnop_inactive: non-zero access: %d %d %d %d # %u %u %u dw %u %u %u drw %u %u %u %s\n", 
 535                                 nofp
->nof_access
, nofp
->nof_deny
, 
 536                                 nofp
->nof_mmap_access
, nofp
->nof_mmap_deny
, 
 537                                 nofp
->nof_r
, nofp
->nof_w
, nofp
->nof_rw
, 
 538                                 nofp
->nof_r_dw
, nofp
->nof_w_dw
, nofp
->nof_rw_dw
, 
 539                                 nofp
->nof_r_drw
, nofp
->nof_w_drw
, nofp
->nof_rw_drw
, 
 540                                 vname 
? vname 
: "//"); 
 543                         nfs_open_file_clear_busy(nofp
); 
 545         lck_mtx_unlock(&np
->n_openlock
); 
 547                 vnode_putname(vname
); 
 549         if (inuse 
&& nfs_mount_state_in_use_end(nmp
, error
)) 
 552         nfs_node_lock_force(np
); 
 554         if (vnode_vtype(vp
) != VDIR
) { 
 555                 nsp 
= np
->n_sillyrename
;  
 556                 np
->n_sillyrename 
= NULL
; 
 561         FSDBG_TOP(264, vp
, np
, np
->n_flag
, nsp
); 
 564                 /* no silly file to clean up... */ 
 565                 /* clear all flags other than these */ 
 566                 np
->n_flag 
&= (NMODIFIED
); 
 568                 FSDBG_BOT(264, vp
, np
, np
->n_flag
, 0); 
 573         /* Remove the silly file that was rename'd earlier */ 
 575         /* flush all the buffers */ 
 576         nfs_vinvalbuf2(vp
, V_SAVE
, vfs_context_thread(ctx
), nsp
->nsr_cred
, 1); 
 578         /* try to get the latest attributes */ 
 579         attrerr 
= nfs_getattr(np
, &nvattr
, ctx
, NGA_UNCACHED
); 
 581         /* Check if we should remove it from the node hash. */ 
 582         /* Leave it if inuse or it has multiple hard links. */ 
 583         if (vnode_isinuse(vp
, 0) || (!attrerr 
&& (nvattr
.nva_nlink 
> 1))) { 
 590         /* mark this node and the directory busy while we do the remove */ 
 591         busyerror 
= nfs_node_set_busy2(nsp
->nsr_dnp
, np
, vfs_context_thread(ctx
)); 
 593         /* lock the node while we remove the silly file */ 
 594         lck_mtx_lock(nfs_node_hash_mutex
); 
 595         while (np
->n_hflag 
& NHLOCKED
) { 
 596                 np
->n_hflag 
|= NHLOCKWANT
; 
 597                 msleep(np
, nfs_node_hash_mutex
, PINOD
, "nfs_inactive", NULL
); 
 599         np
->n_hflag 
|= NHLOCKED
; 
 600         lck_mtx_unlock(nfs_node_hash_mutex
); 
 602         /* purge the name cache to deter others from finding it */ 
 603         bzero(&cn
, sizeof(cn
)); 
 604         cn
.cn_nameptr 
= nsp
->nsr_name
; 
 605         cn
.cn_namelen 
= nsp
->nsr_namlen
; 
 606         nfs_name_cache_purge(nsp
->nsr_dnp
, np
, &cn
, ctx
); 
 608         FSDBG(264, np
, np
->n_size
, np
->n_vattr
.nva_size
, 0xf00d00f1); 
 610         /* now remove the silly file */ 
 613         /* clear all flags other than these */ 
 614         nfs_node_lock_force(np
); 
 615         np
->n_flag 
&= (NMODIFIED
); 
 619                 nfs_node_clear_busy2(nsp
->nsr_dnp
, np
); 
 621         if (unhash 
&& vnode_isinuse(vp
, 0)) { 
 622                 /* vnode now inuse after silly remove? */ 
 624                 ubc_setsize(vp
, np
->n_size
); 
 627         lck_mtx_lock(nfs_node_hash_mutex
); 
 630                  * remove nfsnode from hash now so we can't accidentally find it 
 631                  * again if another object gets created with the same filehandle 
 632                  * before this vnode gets reclaimed 
 634                 if (np
->n_hflag 
& NHHASHED
) { 
 635                         LIST_REMOVE(np
, n_hash
); 
 636                         np
->n_hflag 
&= ~NHHASHED
; 
 637                         FSDBG(266, 0, np
, np
->n_flag
, 0xb1eb1e); 
 641         /* unlock the node */ 
 642         np
->n_hflag 
&= ~NHLOCKED
; 
 643         if (np
->n_hflag 
& NHLOCKWANT
) { 
 644                 np
->n_hflag 
&= ~NHLOCKWANT
; 
 647         lck_mtx_unlock(nfs_node_hash_mutex
); 
 649         /* cleanup sillyrename info */ 
 650         if (nsp
->nsr_cred 
!= NOCRED
) 
 651                 kauth_cred_unref(&nsp
->nsr_cred
); 
 652         vnode_rele(NFSTOV(nsp
->nsr_dnp
)); 
 653         FREE_ZONE(nsp
, sizeof(*nsp
), M_NFSREQ
); 
 655         FSDBG_BOT(264, vp
, np
, np
->n_flag
, 0); 
 660  * Reclaim an nfsnode so that it can be used for other purposes. 
 664         struct vnop_reclaim_args 
/* { 
 665                 struct vnodeop_desc *a_desc; 
 667                 vfs_context_t a_context; 
 670         vnode_t vp 
= ap
->a_vp
; 
 671         nfsnode_t np 
= VTONFS(vp
); 
 672         vfs_context_t ctx 
= ap
->a_context
; 
 673         struct nfs_open_file 
*nofp
, *nextnofp
; 
 674         struct nfs_file_lock 
*nflp
, *nextnflp
; 
 675         struct nfs_lock_owner 
*nlop
, *nextnlop
; 
 676         const char *vname 
= NULL
; 
 677         struct nfsmount 
*nmp 
= np
->n_mount 
? VFSTONFS(np
->n_mount
) : NFSTONMP(np
); 
 679         FSDBG_TOP(265, vp
, np
, np
->n_flag
, 0); 
 681         /* There shouldn't be any open or lock state at this point */ 
 682         lck_mtx_lock(&np
->n_openlock
); 
 684         if (nmp 
&& (nmp
->nm_vers 
>= NFS_VER4
)) { 
 685                 /* need to drop a delegation */ 
 686                 if (np
->n_dlink
.tqe_next 
!= NFSNOLIST
) { 
 687                         /* remove this node from the recall list */ 
 688                         lck_mtx_lock(&nmp
->nm_lock
); 
 689                         if (np
->n_dlink
.tqe_next 
!= NFSNOLIST
) { 
 690                                 TAILQ_REMOVE(&nmp
->nm_recallq
, np
, n_dlink
); 
 691                                 np
->n_dlink
.tqe_next 
= NFSNOLIST
; 
 693                         lck_mtx_unlock(&nmp
->nm_lock
); 
 695                 if (np
->n_openflags 
& N_DELEG_MASK
) { 
 696                         np
->n_openflags 
&= ~N_DELEG_MASK
; 
 697                         nfs4_delegreturn_rpc(nmp
, np
->n_fhp
, np
->n_fhsize
, &np
->n_dstateid
, 
 698                                 vfs_context_thread(ctx
), vfs_context_ucred(ctx
)); 
 702         /* clean up file locks */ 
 703         TAILQ_FOREACH_SAFE(nflp
, &np
->n_locks
, nfl_link
, nextnflp
) { 
 704                 if (!(nflp
->nfl_flags 
& NFS_FILE_LOCK_DEAD
)) { 
 706                                 vname 
= vnode_getname(vp
); 
 707                         printf("nfs_vnop_reclaim: lock 0x%llx 0x%llx 0x%x (bc %d) %s\n", 
 708                                 nflp
->nfl_start
, nflp
->nfl_end
, nflp
->nfl_flags
, 
 709                                 nflp
->nfl_blockcnt
, vname 
? vname 
: "//"); 
 711                 if (!(nflp
->nfl_flags 
& NFS_FILE_LOCK_BLOCKED
)) { 
 712                         lck_mtx_lock(&nflp
->nfl_owner
->nlo_lock
); 
 713                         TAILQ_REMOVE(&nflp
->nfl_owner
->nlo_locks
, nflp
, nfl_lolink
); 
 714                         lck_mtx_unlock(&nflp
->nfl_owner
->nlo_lock
); 
 716                 TAILQ_REMOVE(&np
->n_locks
, nflp
, nfl_link
); 
 717                 nfs_file_lock_destroy(nflp
); 
 719         /* clean up lock owners */ 
 720         TAILQ_FOREACH_SAFE(nlop
, &np
->n_lock_owners
, nlo_link
, nextnlop
) { 
 721                 if (!TAILQ_EMPTY(&nlop
->nlo_locks
)) { 
 723                                 vname 
= vnode_getname(vp
); 
 724                         printf("nfs_vnop_reclaim: lock owner with locks %s\n", 
 725                                 vname 
? vname 
: "//"); 
 727                 TAILQ_REMOVE(&np
->n_lock_owners
, nlop
, nlo_link
); 
 728                 nfs_lock_owner_destroy(nlop
); 
 730         /* clean up open state */ 
 731         if (np
->n_openrefcnt
) { 
 733                         vname 
= vnode_getname(vp
); 
 734                 printf("nfs_vnop_reclaim: still open: %d %s\n", 
 735                         np
->n_openrefcnt
, vname 
? vname 
: "//"); 
 737         TAILQ_FOREACH_SAFE(nofp
, &np
->n_opens
, nof_link
, nextnofp
) { 
 738                 if (nofp
->nof_flags 
& NFS_OPEN_FILE_BUSY
) { 
 740                                 vname 
= vnode_getname(vp
); 
 741                         printf("nfs_vnop_reclaim: open file busy: %s\n", 
 742                                 vname 
? vname 
: "//"); 
 744                 if (nofp
->nof_opencnt
) { 
 746                                 vname 
= vnode_getname(vp
); 
 747                         printf("nfs_vnop_reclaim: file still open: %d %s\n", 
 748                                 nofp
->nof_opencnt
, vname 
? vname 
: "//"); 
 750                 if (nofp
->nof_access 
|| nofp
->nof_deny 
|| 
 751                     nofp
->nof_mmap_access 
|| nofp
->nof_mmap_deny 
|| 
 752                     nofp
->nof_r 
|| nofp
->nof_w 
|| nofp
->nof_rw 
|| 
 753                     nofp
->nof_r_dw 
|| nofp
->nof_w_dw 
|| nofp
->nof_rw_dw 
|| 
 754                     nofp
->nof_r_drw 
|| nofp
->nof_w_drw 
|| nofp
->nof_rw_drw
) { 
 756                                 vname 
= vnode_getname(vp
); 
 757                         printf("nfs_vnop_reclaim: non-zero access: %d %d %d %d # %u %u %u dw %u %u %u drw %u %u %u %s\n", 
 758                                 nofp
->nof_access
, nofp
->nof_deny
, 
 759                                 nofp
->nof_mmap_access
, nofp
->nof_mmap_deny
, 
 760                                 nofp
->nof_r
, nofp
->nof_w
, nofp
->nof_rw
, 
 761                                 nofp
->nof_r_dw
, nofp
->nof_w_dw
, nofp
->nof_rw_dw
, 
 762                                 nofp
->nof_r_drw
, nofp
->nof_w_drw
, nofp
->nof_rw_drw
, 
 763                                 vname 
? vname 
: "//"); 
 765                 TAILQ_REMOVE(&np
->n_opens
, nofp
, nof_link
); 
 766                 nfs_open_file_destroy(nofp
); 
 768         lck_mtx_unlock(&np
->n_openlock
); 
 770         lck_mtx_lock(nfs_buf_mutex
); 
 771         if (!LIST_EMPTY(&np
->n_dirtyblkhd
) || !LIST_EMPTY(&np
->n_cleanblkhd
)) { 
 773                         vname 
= vnode_getname(vp
); 
 774                 printf("nfs_reclaim: dropping %s buffers for file %s\n", 
 775                         (!LIST_EMPTY(&np
->n_dirtyblkhd
) ? "dirty" : "clean"), 
 776                         (vname 
? vname 
: "//")); 
 778         lck_mtx_unlock(nfs_buf_mutex
); 
 780                 vnode_putname(vname
); 
 781         nfs_vinvalbuf(vp
, V_IGNORE_WRITEERR
, ap
->a_context
, 0); 
 783         lck_mtx_lock(nfs_node_hash_mutex
); 
 785         if ((vnode_vtype(vp
) != VDIR
) && np
->n_sillyrename
) { 
 786                 printf("nfs_reclaim: leaving unlinked file %s\n", np
->n_sillyrename
->nsr_name
); 
 787                 if (np
->n_sillyrename
->nsr_cred 
!= NOCRED
) 
 788                         kauth_cred_unref(&np
->n_sillyrename
->nsr_cred
); 
 789                 vnode_rele(NFSTOV(np
->n_sillyrename
->nsr_dnp
)); 
 790                 FREE_ZONE(np
->n_sillyrename
, sizeof(*np
->n_sillyrename
), M_NFSREQ
); 
 793         vnode_removefsref(vp
); 
 795         if (np
->n_hflag 
& NHHASHED
) { 
 796                 LIST_REMOVE(np
, n_hash
); 
 797                 np
->n_hflag 
&= ~NHHASHED
; 
 798                 FSDBG(266, 0, np
, np
->n_flag
, 0xb1eb1e); 
 800         lck_mtx_unlock(nfs_node_hash_mutex
); 
 803          * Free up any directory cookie structures and large file handle 
 804          * structures that might be associated with this nfs node. 
 806         nfs_node_lock_force(np
); 
 807         if ((vnode_vtype(vp
) == VDIR
) && np
->n_cookiecache
) 
 808                 FREE_ZONE(np
->n_cookiecache
, sizeof(struct nfsdmap
), M_NFSDIROFF
); 
 809         if (np
->n_fhsize 
> NFS_SMALLFH
) 
 810                 FREE_ZONE(np
->n_fhp
, np
->n_fhsize
, M_NFSBIGFH
); 
 812         vnode_clearfsnode(vp
); 
 815                 if (!vnode_get(np
->n_parent
)) { 
 816                         vnode_rele(np
->n_parent
); 
 817                         vnode_put(np
->n_parent
); 
 822         lck_mtx_destroy(&np
->n_lock
, nfs_node_lck_grp
); 
 823         lck_rw_destroy(&np
->n_datalock
, nfs_data_lck_grp
); 
 824         lck_mtx_destroy(&np
->n_openlock
, nfs_open_grp
); 
 826         FSDBG_BOT(265, vp
, np
, np
->n_flag
, 0xd1ed1e); 
 827         FREE_ZONE(np
, sizeof(struct nfsnode
), M_NFSNODE
); 
 832  * Acquire an NFS node lock 
 836 nfs_node_lock_internal(nfsnode_t np
, int force
) 
 838         FSDBG_TOP(268, np
, force
, 0, 0); 
 839         lck_mtx_lock(&np
->n_lock
); 
 840         if (!force 
&& !(np
->n_hflag 
&& NHHASHED
)) { 
 841                 FSDBG_BOT(268, np
, 0xdead, 0, 0); 
 842                 lck_mtx_unlock(&np
->n_lock
); 
 845         FSDBG_BOT(268, np
, force
, 0, 0); 
 850 nfs_node_lock(nfsnode_t np
) 
 852         return nfs_node_lock_internal(np
, 0); 
 856 nfs_node_lock_force(nfsnode_t np
) 
 858         nfs_node_lock_internal(np
, 1); 
 862  * Release an NFS node lock 
 865 nfs_node_unlock(nfsnode_t np
) 
 867         FSDBG(269, np
, current_thread(), 0, 0); 
 868         lck_mtx_unlock(&np
->n_lock
); 
 872  * Acquire 2 NFS node locks 
 873  *   - locks taken in reverse address order 
 874  *   - both or neither of the locks are taken 
 875  *   - only one lock taken per node (dup nodes are skipped) 
 878 nfs_node_lock2(nfsnode_t np1
, nfsnode_t np2
) 
 880         nfsnode_t first
, second
; 
 883         first 
= (np1 
> np2
) ? np1 
: np2
; 
 884         second 
= (np1 
> np2
) ? np2 
: np1
; 
 885         if ((error 
= nfs_node_lock(first
))) 
 889         if ((error 
= nfs_node_lock(second
))) 
 890                 nfs_node_unlock(first
); 
 895 nfs_node_unlock2(nfsnode_t np1
, nfsnode_t np2
) 
 897         nfs_node_unlock(np1
); 
 899                 nfs_node_unlock(np2
); 
 903  * Manage NFS node busy state. 
 904  * (Similar to NFS node locks above) 
 907 nfs_node_set_busy(nfsnode_t np
, thread_t thd
) 
 909         struct timespec ts 
= { 2, 0 }; 
 912         if ((error 
= nfs_node_lock(np
))) 
 914         while (ISSET(np
->n_flag
, NBUSY
)) { 
 915                 SET(np
->n_flag
, NBUSYWANT
); 
 916                 msleep(np
, &np
->n_lock
, PZERO
-1, "nfsbusywant", &ts
); 
 917                 if ((error 
= nfs_sigintr(NFSTONMP(np
), NULL
, thd
, 0))) 
 921                 SET(np
->n_flag
, NBUSY
); 
 927 nfs_node_clear_busy(nfsnode_t np
) 
 931         nfs_node_lock_force(np
); 
 932         wanted 
= ISSET(np
->n_flag
, NBUSYWANT
); 
 933         CLR(np
->n_flag
, NBUSY
|NBUSYWANT
); 
 940 nfs_node_set_busy2(nfsnode_t np1
, nfsnode_t np2
, thread_t thd
) 
 942         nfsnode_t first
, second
; 
 945         first 
= (np1 
> np2
) ? np1 
: np2
; 
 946         second 
= (np1 
> np2
) ? np2 
: np1
; 
 947         if ((error 
= nfs_node_set_busy(first
, thd
))) 
 951         if ((error 
= nfs_node_set_busy(second
, thd
))) 
 952                 nfs_node_clear_busy(first
); 
 957 nfs_node_clear_busy2(nfsnode_t np1
, nfsnode_t np2
) 
 959         nfs_node_clear_busy(np1
); 
 961                 nfs_node_clear_busy(np2
); 
 964 /* helper function to sort four nodes in reverse address order (no dupes) */ 
 966 nfs_node_sort4(nfsnode_t np1
, nfsnode_t np2
, nfsnode_t np3
, nfsnode_t np4
, nfsnode_t 
*list
, int *lcntp
) 
 968         nfsnode_t na
[2], nb
[2]; 
 971         /* sort pairs then merge */ 
 972         na
[0] = (np1 
> np2
) ? np1 
: np2
; 
 973         na
[1] = (np1 
> np2
) ? np2 
: np1
; 
 974         nb
[0] = (np3 
> np4
) ? np3 
: np4
; 
 975         nb
[1] = (np3 
> np4
) ? np4 
: np3
; 
 976         for (a 
= b 
= i 
= lcnt 
= 0; i 
< 4; i
++) { 
 978                         list
[lcnt
] = nb
[b
++]; 
 979                 else if ((b 
>= 2) || (na
[a
] >= nb
[b
])) 
 980                         list
[lcnt
] = na
[a
++]; 
 982                         list
[lcnt
] = nb
[b
++]; 
 983                 if ((lcnt 
<= 0) || (list
[lcnt
] != list
[lcnt
-1])) 
 984                         lcnt
++; /* omit dups */ 
 986         if (list
[lcnt
-1] == NULL
) 
 992 nfs_node_set_busy4(nfsnode_t np1
, nfsnode_t np2
, nfsnode_t np3
, nfsnode_t np4
, thread_t thd
) 
 997         nfs_node_sort4(np1
, np2
, np3
, np4
, list
, &lcnt
); 
 999         /* Now we can lock using list[0 - lcnt-1] */ 
1000         for (i 
= 0; i 
< lcnt
; ++i
) 
1001                 if ((error 
= nfs_node_set_busy(list
[i
], thd
))) { 
1002                         /* Drop any locks we acquired. */ 
1004                                 nfs_node_clear_busy(list
[i
]); 
1011 nfs_node_clear_busy4(nfsnode_t np1
, nfsnode_t np2
, nfsnode_t np3
, nfsnode_t np4
) 
1016         nfs_node_sort4(np1
, np2
, np3
, np4
, list
, &lcnt
); 
1018                 nfs_node_clear_busy(list
[lcnt
]); 
1022  * Acquire an NFS node data lock 
1025 nfs_data_lock(nfsnode_t np
, int locktype
) 
1027         nfs_data_lock_internal(np
, locktype
, 1); 
1030 nfs_data_lock_noupdate(nfsnode_t np
, int locktype
) 
1032         nfs_data_lock_internal(np
, locktype
, 0); 
1035 nfs_data_lock_internal(nfsnode_t np
, int locktype
, int updatesize
) 
1037         FSDBG_TOP(270, np
, locktype
, np
->n_datalockowner
, 0); 
1038         if (locktype 
== NFS_DATA_LOCK_SHARED
) { 
1039                 if (updatesize 
&& ISSET(np
->n_flag
, NUPDATESIZE
)) 
1040                         nfs_data_update_size(np
, 0); 
1041                 lck_rw_lock_shared(&np
->n_datalock
); 
1043                 lck_rw_lock_exclusive(&np
->n_datalock
); 
1044                 np
->n_datalockowner 
= current_thread(); 
1045                 if (updatesize 
&& ISSET(np
->n_flag
, NUPDATESIZE
)) 
1046                         nfs_data_update_size(np
, 1); 
1048         FSDBG_BOT(270, np
, locktype
, np
->n_datalockowner
, 0); 
1052  * Release an NFS node data lock 
1055 nfs_data_unlock(nfsnode_t np
) 
1057         nfs_data_unlock_internal(np
, 1); 
1060 nfs_data_unlock_noupdate(nfsnode_t np
) 
1062         nfs_data_unlock_internal(np
, 0); 
1065 nfs_data_unlock_internal(nfsnode_t np
, int updatesize
) 
1067         int mine 
= (np
->n_datalockowner 
== current_thread()); 
1068         FSDBG_TOP(271, np
, np
->n_datalockowner
, current_thread(), 0); 
1069         if (updatesize 
&& mine 
&& ISSET(np
->n_flag
, NUPDATESIZE
)) 
1070                 nfs_data_update_size(np
, 1); 
1071         np
->n_datalockowner 
= NULL
; 
1072         lck_rw_done(&np
->n_datalock
); 
1073         if (updatesize 
&& !mine 
&& ISSET(np
->n_flag
, NUPDATESIZE
)) 
1074                 nfs_data_update_size(np
, 0); 
1075         FSDBG_BOT(271, np
, np
->n_datalockowner
, current_thread(), 0); 
1080  * update an NFS node's size 
1083 nfs_data_update_size(nfsnode_t np
, int datalocked
) 
1087         FSDBG_TOP(272, np
, np
->n_flag
, np
->n_size
, np
->n_newsize
); 
1089                 nfs_data_lock(np
, NFS_DATA_LOCK_EXCLUSIVE
); 
1090                 /* grabbing data lock will automatically update size */ 
1091                 nfs_data_unlock(np
); 
1092                 FSDBG_BOT(272, np
, np
->n_flag
, np
->n_size
, np
->n_newsize
); 
1095         error 
= nfs_node_lock(np
); 
1096         if (error 
|| !ISSET(np
->n_flag
, NUPDATESIZE
)) { 
1098                         nfs_node_unlock(np
); 
1099                 FSDBG_BOT(272, np
, np
->n_flag
, np
->n_size
, np
->n_newsize
); 
1102         CLR(np
->n_flag
, NUPDATESIZE
); 
1103         np
->n_size 
= np
->n_newsize
; 
1104         /* make sure we invalidate buffers the next chance we get */ 
1105         SET(np
->n_flag
, NNEEDINVALIDATE
); 
1106         nfs_node_unlock(np
); 
1107         ubc_setsize(NFSTOV(np
), (off_t
)np
->n_size
); /* XXX error? */ 
1108         FSDBG_BOT(272, np
, np
->n_flag
, np
->n_size
, np
->n_newsize
);