2  * Copyright (c) 2000-2020 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, 1995 
  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_vfsops.c        8.12 (Berkeley) 5/20/95 
  65  * FreeBSD-Id: nfs_vfsops.c,v 1.52 1997/11/12 05:42:21 julian Exp $ 
  68 #include <nfs/nfs_conf.h> 
  72  * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce 
  73  * support for mandatory and extensible security protections.  This notice 
  74  * is included in support of clause 2.2 (b) of the Apple Public License, 
  78 #include <sys/param.h> 
  79 #include <sys/systm.h> 
  81 #include <sys/ioctl.h> 
  82 #include <sys/signal.h> 
  83 #include <sys/proc_internal.h> /* for fs rooting to update rootdir in fdp */ 
  84 #include <sys/kauth.h> 
  85 #include <sys/vnode_internal.h> 
  86 #include <sys/malloc.h> 
  87 #include <sys/kernel.h> 
  88 #include <sys/sysctl.h> 
  89 #include <sys/mount_internal.h> 
  90 #include <sys/kpi_mbuf.h> 
  91 #include <sys/socket.h> 
  93 #include <sys/socketvar.h> 
  94 #include <sys/fcntl.h> 
  95 #include <sys/quota.h> 
  97 #include <libkern/OSAtomic.h> 
 100 #include <sys/vmparam.h> 
 102 #if !defined(NO_MOUNT_PRIVATE) 
 103 #include <sys/filedesc.h> 
 104 #endif /* NO_MOUNT_PRIVATE */ 
 107 #include <net/route.h> 
 108 #include <netinet/in.h> 
 110 #include <nfs/rpcv2.h> 
 111 #include <nfs/krpc.h> 
 112 #include <nfs/nfsproto.h> 
 114 #include <nfs/nfsnode.h> 
 115 #include <nfs/nfs_gss.h> 
 116 #include <nfs/nfsmount.h> 
 117 #include <nfs/xdr_subs.h> 
 118 #include <nfs/nfsm_subs.h> 
 119 #include <nfs/nfsdiskless.h> 
 120 #include <nfs/nfs_lock.h> 
 122 #include <security/mac_framework.h> 
 125 #include <pexpert/pexpert.h> 
 127 #define NFS_VFS_DBG(...) NFS_DBG(NFS_FAC_VFS, 7, ## __VA_ARGS__) 
 133 ZONE_DECLARE(nfsmnt_zone
, "NFS mount", 
 134     sizeof(struct nfsmount
), ZC_ZFREE_CLEARMEM
); 
 137 static lck_grp_t 
*nfs_global_grp
, *nfs_mount_grp
; 
 138 lck_mtx_t 
*nfs_global_mutex
; 
 139 uint32_t nfs_fs_attr_bitmap
[NFS_ATTR_BITMAP_LEN
]; 
 140 uint32_t nfs_object_attr_bitmap
[NFS_ATTR_BITMAP_LEN
]; 
 141 uint32_t nfs_getattr_bitmap
[NFS_ATTR_BITMAP_LEN
]; 
 142 uint32_t nfs4_getattr_write_bitmap
[NFS_ATTR_BITMAP_LEN
]; 
 143 struct nfsclientidlist nfsclientids
; 
 146 struct nfs_reqqhead nfs_reqq
; 
 147 lck_grp_t 
*nfs_request_grp
; 
 148 lck_mtx_t 
*nfs_request_mutex
; 
 149 thread_call_t nfs_request_timer_call
; 
 150 int nfs_request_timer_on
; 
 151 u_int64_t nfs_xid 
= 0; 
 152 u_int64_t nfs_xidwrap 
= 0;              /* to build a (non-wrapping) 64 bit xid */ 
 154 thread_call_t nfs_buf_timer_call
; 
 157 lck_grp_t 
*nfs_open_grp
; 
 158 uint32_t nfs_open_owner_seqnum 
= 0; 
 159 uint32_t nfs_lock_owner_seqnum 
= 0; 
 160 thread_call_t nfs4_callback_timer_call
; 
 161 int nfs4_callback_timer_on 
= 0; 
 162 char nfs4_default_domain
[MAXPATHLEN
]; 
 165 lck_grp_t 
*nfsiod_lck_grp
; 
 166 lck_mtx_t 
*nfsiod_mutex
; 
 167 struct nfsiodlist nfsiodfree
, nfsiodwork
; 
 168 struct nfsiodmountlist nfsiodmounts
; 
 169 int nfsiod_thread_count 
= 0; 
 170 int nfsiod_thread_max 
= NFS_DEFASYNCTHREAD
; 
 171 int nfs_max_async_writes 
= NFS_DEFMAXASYNCWRITES
; 
 173 int nfs_iosize 
= NFS_IOSIZE
; 
 174 int nfs_access_cache_timeout 
= NFS_MAXATTRTIMO
; 
 175 int nfs_access_delete 
= 1; /* too many servers get this wrong - workaround on by default */ 
 176 int nfs_access_dotzfs 
= 1; 
 177 int nfs_access_for_getattr 
= 0; 
 178 int nfs_allow_async 
= 0; 
 179 int nfs_statfs_rate_limit 
= NFS_DEFSTATFSRATELIMIT
; 
 180 int nfs_lockd_mounts 
= 0; 
 181 int nfs_lockd_request_sent 
= 0; 
 182 int nfs_idmap_ctrl 
= NFS_IDMAP_CTRL_USE_IDMAP_SERVICE
; 
 183 int nfs_callback_port 
= 0; 
 185 int nfs_tprintf_initial_delay 
= NFS_TPRINTF_INITIAL_DELAY
; 
 186 int nfs_tprintf_delay 
= NFS_TPRINTF_DELAY
; 
 189 int             mountnfs(char *, mount_t
, vfs_context_t
, vnode_t 
*); 
 191 static int      nfs_mount_diskless(struct nfs_dlmount 
*, const char *, int, vnode_t 
*, mount_t 
*, vfs_context_t
); 
 192 #if !defined(NO_MOUNT_PRIVATE) 
 193 static int      nfs_mount_diskless_private(struct nfs_dlmount 
*, const char *, int, vnode_t 
*, mount_t 
*, vfs_context_t
); 
 194 #endif /* NO_MOUNT_PRIVATE */ 
 196 int             nfs_mount_connect(struct nfsmount 
*); 
 197 void            nfs_mount_drain_and_cleanup(struct nfsmount 
*); 
 198 void            nfs_mount_cleanup(struct nfsmount 
*); 
 199 int             nfs_mountinfo_assemble(struct nfsmount 
*, struct xdrbuf 
*); 
 200 int             nfs4_mount_update_path_with_symlink(struct nfsmount 
*, struct nfs_fs_path 
*, uint32_t, fhandle_t 
*, int *, fhandle_t 
*, vfs_context_t
); 
 203  * NFS VFS operations. 
 205 int     nfs_vfs_mount(mount_t
, vnode_t
, user_addr_t
, vfs_context_t
); 
 206 int     nfs_vfs_start(mount_t
, int, vfs_context_t
); 
 207 int     nfs_vfs_unmount(mount_t
, int, vfs_context_t
); 
 208 int     nfs_vfs_root(mount_t
, vnode_t 
*, vfs_context_t
); 
 209 int     nfs_vfs_quotactl(mount_t
, int, uid_t
, caddr_t
, vfs_context_t
); 
 210 int     nfs_vfs_getattr(mount_t
, struct vfs_attr 
*, vfs_context_t
); 
 211 int     nfs_vfs_sync(mount_t
, int, vfs_context_t
); 
 212 int     nfs_vfs_vget(mount_t
, ino64_t
, vnode_t 
*, vfs_context_t
); 
 213 int     nfs_vfs_vptofh(vnode_t
, int *, unsigned char *, vfs_context_t
); 
 214 int     nfs_vfs_fhtovp(mount_t
, int, unsigned char *, vnode_t 
*, vfs_context_t
); 
 215 int     nfs_vfs_init(struct vfsconf 
*); 
 216 int     nfs_vfs_sysctl(int *, u_int
, user_addr_t
, size_t *, user_addr_t
, size_t, vfs_context_t
); 
 218 const struct vfsops nfs_vfsops 
= { 
 219         .vfs_mount       
= nfs_vfs_mount
, 
 220         .vfs_start       
= nfs_vfs_start
, 
 221         .vfs_unmount     
= nfs_vfs_unmount
, 
 222         .vfs_root        
= nfs_vfs_root
, 
 223         .vfs_quotactl    
= nfs_vfs_quotactl
, 
 224         .vfs_getattr     
= nfs_vfs_getattr
, 
 225         .vfs_sync        
= nfs_vfs_sync
, 
 226         .vfs_vget        
= nfs_vfs_vget
, 
 227         .vfs_fhtovp      
= nfs_vfs_fhtovp
, 
 228         .vfs_vptofh      
= nfs_vfs_vptofh
, 
 229         .vfs_init        
= nfs_vfs_init
, 
 230         .vfs_sysctl      
= nfs_vfs_sysctl
, 
 231         // We do not support the remaining VFS ops 
 236  * version-specific NFS functions 
 238 int nfs3_mount(struct nfsmount 
*, vfs_context_t
, nfsnode_t 
*); 
 239 int nfs4_mount(struct nfsmount 
*, vfs_context_t
, nfsnode_t 
*); 
 240 int nfs3_fsinfo(struct nfsmount 
*, nfsnode_t
, vfs_context_t
); 
 241 int nfs3_update_statfs(struct nfsmount 
*, vfs_context_t
); 
 242 int nfs4_update_statfs(struct nfsmount 
*, vfs_context_t
); 
 244 #define nfs3_getquota   NULL 
 245 #define nfs4_getquota   NULL 
 247 int nfs3_getquota(struct nfsmount 
*, vfs_context_t
, uid_t
, int, struct dqblk 
*); 
 248 int nfs4_getquota(struct nfsmount 
*, vfs_context_t
, uid_t
, int, struct dqblk 
*); 
 251 const struct nfs_funcs nfs3_funcs 
= { 
 252         .nf_mount 
= nfs3_mount
, 
 253         .nf_update_statfs 
= nfs3_update_statfs
, 
 254         .nf_getquota 
= nfs3_getquota
, 
 255         .nf_access_rpc 
= nfs3_access_rpc
, 
 256         .nf_getattr_rpc 
= nfs3_getattr_rpc
, 
 257         .nf_setattr_rpc 
= nfs3_setattr_rpc
, 
 258         .nf_read_rpc_async 
= nfs3_read_rpc_async
, 
 259         .nf_read_rpc_async_finish 
= nfs3_read_rpc_async_finish
, 
 260         .nf_readlink_rpc 
= nfs3_readlink_rpc
, 
 261         .nf_write_rpc_async 
= nfs3_write_rpc_async
, 
 262         .nf_write_rpc_async_finish 
= nfs3_write_rpc_async_finish
, 
 263         .nf_commit_rpc 
= nfs3_commit_rpc
, 
 264         .nf_lookup_rpc_async 
= nfs3_lookup_rpc_async
, 
 265         .nf_lookup_rpc_async_finish 
= nfs3_lookup_rpc_async_finish
, 
 266         .nf_remove_rpc 
= nfs3_remove_rpc
, 
 267         .nf_rename_rpc 
= nfs3_rename_rpc
, 
 268         .nf_setlock_rpc 
= nfs3_setlock_rpc
, 
 269         .nf_unlock_rpc 
= nfs3_unlock_rpc
, 
 270         .nf_getlock_rpc 
= nfs3_getlock_rpc
 
 273 const struct nfs_funcs nfs4_funcs 
= { 
 274         .nf_mount 
= nfs4_mount
, 
 275         .nf_update_statfs 
= nfs4_update_statfs
, 
 276         .nf_getquota 
= nfs4_getquota
, 
 277         .nf_access_rpc 
= nfs4_access_rpc
, 
 278         .nf_getattr_rpc 
= nfs4_getattr_rpc
, 
 279         .nf_setattr_rpc 
= nfs4_setattr_rpc
, 
 280         .nf_read_rpc_async 
= nfs4_read_rpc_async
, 
 281         .nf_read_rpc_async_finish 
= nfs4_read_rpc_async_finish
, 
 282         .nf_readlink_rpc 
= nfs4_readlink_rpc
, 
 283         .nf_write_rpc_async 
= nfs4_write_rpc_async
, 
 284         .nf_write_rpc_async_finish 
= nfs4_write_rpc_async_finish
, 
 285         .nf_commit_rpc 
= nfs4_commit_rpc
, 
 286         .nf_lookup_rpc_async 
= nfs4_lookup_rpc_async
, 
 287         .nf_lookup_rpc_async_finish 
= nfs4_lookup_rpc_async_finish
, 
 288         .nf_remove_rpc 
= nfs4_remove_rpc
, 
 289         .nf_rename_rpc 
= nfs4_rename_rpc
, 
 290         .nf_setlock_rpc 
= nfs4_setlock_rpc
, 
 291         .nf_unlock_rpc 
= nfs4_unlock_rpc
, 
 292         .nf_getlock_rpc 
= nfs4_getlock_rpc
 
 297  * Called once to initialize data structures... 
 300 nfs_vfs_init(__unused 
struct vfsconf 
*vfsp
) 
 306          * Check to see if major data structures haven't bloated. 
 308         if (sizeof(struct nfsnode
) > NFS_NODEALLOC
) { 
 309                 printf("struct nfsnode bloated (> %dbytes)\n", NFS_NODEALLOC
); 
 310                 printf("Try reducing NFS_SMALLFH\n"); 
 312         if (sizeof(struct nfsmount
) > NFS_MNTALLOC
) { 
 313                 printf("struct nfsmount bloated (> %dbytes)\n", NFS_MNTALLOC
); 
 316         nfs_ticks 
= (hz 
* NFS_TICKINTVL 
+ 500) / 1000; 
 321         /* init async I/O thread pool state */ 
 322         TAILQ_INIT(&nfsiodfree
); 
 323         TAILQ_INIT(&nfsiodwork
); 
 324         TAILQ_INIT(&nfsiodmounts
); 
 325         nfsiod_lck_grp 
= lck_grp_alloc_init("nfsiod", LCK_GRP_ATTR_NULL
); 
 326         nfsiod_mutex 
= lck_mtx_alloc_init(nfsiod_lck_grp
, LCK_ATTR_NULL
); 
 328         /* init lock groups, etc. */ 
 329         nfs_mount_grp 
= lck_grp_alloc_init("nfs_mount", LCK_GRP_ATTR_NULL
); 
 330         nfs_open_grp 
= lck_grp_alloc_init("nfs_open", LCK_GRP_ATTR_NULL
); 
 331         nfs_global_grp 
= lck_grp_alloc_init("nfs_global", LCK_GRP_ATTR_NULL
); 
 333         nfs_global_mutex 
= lck_mtx_alloc_init(nfs_global_grp
, LCK_ATTR_NULL
); 
 335         /* init request list mutex */ 
 336         nfs_request_grp 
= lck_grp_alloc_init("nfs_request", LCK_GRP_ATTR_NULL
); 
 337         nfs_request_mutex 
= lck_mtx_alloc_init(nfs_request_grp
, LCK_ATTR_NULL
); 
 339         /* initialize NFS request list */ 
 340         TAILQ_INIT(&nfs_reqq
); 
 342         nfs_nbinit();                   /* Init the nfsbuf table */ 
 343         nfs_nhinit();                   /* Init the nfsnode table */ 
 344         nfs_lockinit();                 /* Init the nfs lock state */ 
 346         nfs_gss_init();                 /* Init RPCSEC_GSS security */ 
 351         NFS4_PER_FS_ATTRIBUTES(nfs_fs_attr_bitmap
); 
 352         NFS4_PER_OBJECT_ATTRIBUTES(nfs_object_attr_bitmap
); 
 353         NFS4_DEFAULT_WRITE_ATTRIBUTES(nfs4_getattr_write_bitmap
); 
 354         NFS4_DEFAULT_ATTRIBUTES(nfs_getattr_bitmap
); 
 355         for (i 
= 0; i 
< NFS_ATTR_BITMAP_LEN
; i
++) { 
 356                 nfs_getattr_bitmap
[i
] &= nfs_object_attr_bitmap
[i
]; 
 357                 nfs4_getattr_write_bitmap
[i
] &= nfs_object_attr_bitmap
[i
]; 
 359         TAILQ_INIT(&nfsclientids
); 
 362         /* initialize NFS timer callouts */ 
 363         nfs_request_timer_call 
= thread_call_allocate(nfs_request_timer
, NULL
); 
 364         nfs_buf_timer_call 
= thread_call_allocate(nfs_buf_timer
, NULL
); 
 366         nfs4_callback_timer_call 
= thread_call_allocate(nfs4_callback_timer
, NULL
); 
 376 nfs3_update_statfs(struct nfsmount 
*nmp
, vfs_context_t ctx
) 
 379         int error 
= 0, lockerror
, status
, nfsvers
; 
 381         struct nfsm_chain nmreq
, nmrep
; 
 384         nfsvers 
= nmp
->nm_vers
; 
 389         if ((error 
= vnode_get(NFSTOV(np
)))) { 
 393         nfsm_chain_null(&nmreq
); 
 394         nfsm_chain_null(&nmrep
); 
 396         nfsm_chain_build_alloc_init(error
, &nmreq
, NFSX_FH(nfsvers
)); 
 397         nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, np
->n_fhp
, np
->n_fhsize
); 
 398         nfsm_chain_build_done(error
, &nmreq
); 
 400         error 
= nfs_request2(np
, NULL
, &nmreq
, NFSPROC_FSSTAT
, vfs_context_thread(ctx
), 
 401             vfs_context_ucred(ctx
), NULL
, R_SOFT
, &nmrep
, &xid
, &status
); 
 402         if (error 
== ETIMEDOUT
) { 
 405         if ((lockerror 
= nfs_node_lock(np
))) { 
 408         if (nfsvers 
== NFS_VER3
) { 
 409                 nfsm_chain_postop_attr_update(error
, &nmrep
, np
, &xid
); 
 417         nfsm_assert(error
, NFSTONMP(np
), ENXIO
); 
 419         lck_mtx_lock(&nmp
->nm_lock
); 
 420         NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_TOTAL
); 
 421         NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_FREE
); 
 422         NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_AVAIL
); 
 423         if (nfsvers 
== NFS_VER3
) { 
 424                 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_FILES_AVAIL
); 
 425                 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_FILES_TOTAL
); 
 426                 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_FILES_FREE
); 
 427                 nmp
->nm_fsattr
.nfsa_bsize 
= NFS_FABLKSIZE
; 
 428                 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_space_total
); 
 429                 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_space_free
); 
 430                 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_space_avail
); 
 431                 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_files_total
); 
 432                 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_files_free
); 
 433                 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_files_avail
); 
 436                 nfsm_chain_adv(error
, &nmrep
, NFSX_UNSIGNED
); // skip tsize? 
 437                 nfsm_chain_get_32(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_bsize
); 
 438                 nfsm_chain_get_32(error
, &nmrep
, val
); 
 440                 if (nmp
->nm_fsattr
.nfsa_bsize 
<= 0) { 
 441                         nmp
->nm_fsattr
.nfsa_bsize 
= NFS_FABLKSIZE
; 
 443                 nmp
->nm_fsattr
.nfsa_space_total 
= (uint64_t)val 
* nmp
->nm_fsattr
.nfsa_bsize
; 
 444                 nfsm_chain_get_32(error
, &nmrep
, val
); 
 446                 nmp
->nm_fsattr
.nfsa_space_free 
= (uint64_t)val 
* nmp
->nm_fsattr
.nfsa_bsize
; 
 447                 nfsm_chain_get_32(error
, &nmrep
, val
); 
 449                 nmp
->nm_fsattr
.nfsa_space_avail 
= (uint64_t)val 
* nmp
->nm_fsattr
.nfsa_bsize
; 
 451         lck_mtx_unlock(&nmp
->nm_lock
); 
 453         nfsm_chain_cleanup(&nmreq
); 
 454         nfsm_chain_cleanup(&nmrep
); 
 455         vnode_put(NFSTOV(np
)); 
 461 nfs4_update_statfs(struct nfsmount 
*nmp
, vfs_context_t ctx
) 
 464         int error 
= 0, lockerror
, status
, nfsvers
, numops
; 
 466         struct nfsm_chain nmreq
, nmrep
; 
 467         uint32_t bitmap
[NFS_ATTR_BITMAP_LEN
]; 
 468         struct nfs_vattr nvattr
; 
 469         struct nfsreq_secinfo_args si
; 
 471         nfsvers 
= nmp
->nm_vers
; 
 476         if ((error 
= vnode_get(NFSTOV(np
)))) { 
 480         NFSREQ_SECINFO_SET(&si
, np
, NULL
, 0, NULL
, 0); 
 481         NVATTR_INIT(&nvattr
); 
 482         nfsm_chain_null(&nmreq
); 
 483         nfsm_chain_null(&nmrep
); 
 487         nfsm_chain_build_alloc_init(error
, &nmreq
, 15 * NFSX_UNSIGNED
); 
 488         nfsm_chain_add_compound_header(error
, &nmreq
, "statfs", nmp
->nm_minor_vers
, numops
); 
 490         nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
); 
 491         nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, np
->n_fhp
, np
->n_fhsize
); 
 493         nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
); 
 494         NFS_COPY_ATTRIBUTES(nfs_getattr_bitmap
, bitmap
); 
 495         NFS4_STATFS_ATTRIBUTES(bitmap
); 
 496         nfsm_chain_add_bitmap_supported(error
, &nmreq
, bitmap
, nmp
, np
); 
 497         nfsm_chain_build_done(error
, &nmreq
); 
 498         nfsm_assert(error
, (numops 
== 0), EPROTO
); 
 500         error 
= nfs_request2(np
, NULL
, &nmreq
, NFSPROC4_COMPOUND
, 
 501             vfs_context_thread(ctx
), vfs_context_ucred(ctx
), 
 502             NULL
, R_SOFT
, &nmrep
, &xid
, &status
); 
 503         nfsm_chain_skip_tag(error
, &nmrep
); 
 504         nfsm_chain_get_32(error
, &nmrep
, numops
); 
 505         nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
); 
 506         nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
); 
 507         nfsm_assert(error
, NFSTONMP(np
), ENXIO
); 
 509         lck_mtx_lock(&nmp
->nm_lock
); 
 510         error 
= nfs4_parsefattr(&nmrep
, &nmp
->nm_fsattr
, &nvattr
, NULL
, NULL
, NULL
); 
 511         lck_mtx_unlock(&nmp
->nm_lock
); 
 513         if ((lockerror 
= nfs_node_lock(np
))) { 
 517                 nfs_loadattrcache(np
, &nvattr
, &xid
, 0); 
 522         nfsm_assert(error
, NFSTONMP(np
), ENXIO
); 
 524         nmp
->nm_fsattr
.nfsa_bsize 
= NFS_FABLKSIZE
; 
 526         NVATTR_CLEANUP(&nvattr
); 
 527         nfsm_chain_cleanup(&nmreq
); 
 528         nfsm_chain_cleanup(&nmrep
); 
 529         vnode_put(NFSTOV(np
)); 
 532 #endif /* CONFIG_NFS4 */ 
 536  * Return an NFS volume name from the mntfrom name. 
 539 nfs_get_volname(struct mount 
*mp
, char *volname
, size_t len
, __unused vfs_context_t ctx
) 
 541         const char *ptr
, *cptr
; 
 542         const char *mntfrom 
= mp
->mnt_vfsstat
.f_mntfromname
; 
 546         mflen 
= strnlen(mntfrom
, MAXPATHLEN 
+ 1); 
 548         if (mflen 
> MAXPATHLEN 
|| mflen 
== 0) { 
 549                 strlcpy(volname
, "Bad volname", len
); 
 553         /* Move back over trailing slashes */ 
 554         for (ptr 
= &mntfrom
[mflen 
- 1]; ptr 
!= mntfrom 
&& *ptr 
== '/'; ptr
--) { 
 558         /* Find first character after the last slash */ 
 560         for (size_t i 
= 0; i 
< mflen
; i
++) { 
 561                 if (mntfrom
[i
] == '/') { 
 562                         ptr 
= &mntfrom
[i 
+ 1]; 
 564                 /* And the first character after the first colon */ 
 565                 else if (cptr 
== NULL 
&& mntfrom
[i
] == ':') { 
 566                         cptr 
= &mntfrom
[i 
+ 1]; 
 571          * No slash or nothing after the last slash 
 572          * use everything past the first colon 
 574         if (ptr 
== NULL 
|| *ptr 
== '\0') { 
 577         /* Otherwise use the mntfrom name */ 
 582         mflen 
= &mntfrom
[mflen
] - ptr
; 
 583         len 
= mflen 
+ 1 < len 
? mflen 
+ 1 : len
; 
 585         strlcpy(volname
, ptr
, len
); 
 590  * The NFS VFS_GETATTR function: "statfs"-type information is retrieved 
 591  * using the nf_update_statfs() function, and other attributes are cobbled 
 592  * together from whatever sources we can (getattr, fsinfo, pathconf). 
 595 nfs_vfs_getattr(mount_t mp
, struct vfs_attr 
*fsap
, vfs_context_t ctx
) 
 597         struct nfsmount 
*nmp
; 
 599         int error 
= 0, nfsvers
; 
 602         if (nfs_mount_gone(nmp
)) { 
 605         nfsvers 
= nmp
->nm_vers
; 
 607         if (VFSATTR_IS_ACTIVE(fsap
, f_bsize
) || 
 608             VFSATTR_IS_ACTIVE(fsap
, f_iosize
) || 
 609             VFSATTR_IS_ACTIVE(fsap
, f_blocks
) || 
 610             VFSATTR_IS_ACTIVE(fsap
, f_bfree
) || 
 611             VFSATTR_IS_ACTIVE(fsap
, f_bavail
) || 
 612             VFSATTR_IS_ACTIVE(fsap
, f_bused
) || 
 613             VFSATTR_IS_ACTIVE(fsap
, f_files
) || 
 614             VFSATTR_IS_ACTIVE(fsap
, f_ffree
)) { 
 615                 int statfsrate 
= nfs_statfs_rate_limit
; 
 619                  * Are we rate-limiting statfs RPCs? 
 620                  * (Treat values less than 1 or greater than 1,000,000 as no limit.) 
 622                 if ((statfsrate 
> 0) && (statfsrate 
< 1000000)) { 
 627                         lck_mtx_lock(&nmp
->nm_lock
); 
 628                         stamp 
= (now
.tv_sec 
* statfsrate
) + (now
.tv_usec 
/ (1000000 / statfsrate
)); 
 629                         if (stamp 
!= nmp
->nm_fsattrstamp
) { 
 631                                 nmp
->nm_fsattrstamp 
= stamp
; 
 635                         lck_mtx_unlock(&nmp
->nm_lock
); 
 638                 if (refresh 
&& !nfs_use_cache(nmp
)) { 
 639                         error 
= nmp
->nm_funcs
->nf_update_statfs(nmp
, ctx
); 
 641                 if ((error 
== ESTALE
) || (error 
== ETIMEDOUT
)) { 
 648                 lck_mtx_lock(&nmp
->nm_lock
); 
 649                 VFSATTR_RETURN(fsap
, f_iosize
, nfs_iosize
); 
 650                 VFSATTR_RETURN(fsap
, f_bsize
, nmp
->nm_fsattr
.nfsa_bsize
); 
 651                 bsize 
= nmp
->nm_fsattr
.nfsa_bsize
; 
 652                 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_TOTAL
)) { 
 653                         VFSATTR_RETURN(fsap
, f_blocks
, nmp
->nm_fsattr
.nfsa_space_total 
/ bsize
); 
 655                 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_FREE
)) { 
 656                         VFSATTR_RETURN(fsap
, f_bfree
, nmp
->nm_fsattr
.nfsa_space_free 
/ bsize
); 
 658                 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_AVAIL
)) { 
 659                         VFSATTR_RETURN(fsap
, f_bavail
, nmp
->nm_fsattr
.nfsa_space_avail 
/ bsize
); 
 661                 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_TOTAL
) && 
 662                     NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_FREE
)) { 
 663                         VFSATTR_RETURN(fsap
, f_bused
, 
 664                             (nmp
->nm_fsattr
.nfsa_space_total 
/ bsize
) - 
 665                             (nmp
->nm_fsattr
.nfsa_space_free 
/ bsize
)); 
 667                 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_FILES_TOTAL
)) { 
 668                         VFSATTR_RETURN(fsap
, f_files
, nmp
->nm_fsattr
.nfsa_files_total
); 
 670                 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_FILES_FREE
)) { 
 671                         VFSATTR_RETURN(fsap
, f_ffree
, nmp
->nm_fsattr
.nfsa_files_free
); 
 673                 lck_mtx_unlock(&nmp
->nm_lock
); 
 676         if (VFSATTR_IS_ACTIVE(fsap
, f_vol_name
)) { 
 677                 /*%%% IF fail over support is implemented we may need to take nm_lock */ 
 678                 nfs_get_volname(mp
, fsap
->f_vol_name
, MAXPATHLEN
, ctx
); 
 679                 VFSATTR_SET_SUPPORTED(fsap
, f_vol_name
); 
 681         if (VFSATTR_IS_ACTIVE(fsap
, f_capabilities
) 
 683                 u_int32_t caps
, valid
; 
 684                 nfsnode_t np 
= nmp
->nm_dnp
; 
 686                 nfsm_assert(error
, VFSTONFS(mp
) && np
, ENXIO
); 
 690                 lck_mtx_lock(&nmp
->nm_lock
); 
 693                  * The capabilities[] array defines what this volume supports. 
 695                  * The valid[] array defines which bits this code understands 
 696                  * the meaning of (whether the volume has that capability or 
 697                  * not).  Any zero bits here means "I don't know what you're 
 698                  * asking about" and the caller cannot tell whether that 
 699                  * capability is present or not. 
 702                 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SYMLINK_SUPPORT
)) { 
 703                         valid 
|= VOL_CAP_FMT_SYMBOLICLINKS
; 
 704                         if (nmp
->nm_fsattr
.nfsa_flags 
& NFS_FSFLAG_SYMLINK
) { 
 705                                 caps 
|= VOL_CAP_FMT_SYMBOLICLINKS
; 
 708                 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_LINK_SUPPORT
)) { 
 709                         valid 
|= VOL_CAP_FMT_HARDLINKS
; 
 710                         if (nmp
->nm_fsattr
.nfsa_flags 
& NFS_FSFLAG_LINK
) { 
 711                                 caps 
|= VOL_CAP_FMT_HARDLINKS
; 
 714                 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_CASE_INSENSITIVE
)) { 
 715                         valid 
|= VOL_CAP_FMT_CASE_SENSITIVE
; 
 716                         if (!(nmp
->nm_fsattr
.nfsa_flags 
& NFS_FSFLAG_CASE_INSENSITIVE
)) { 
 717                                 caps 
|= VOL_CAP_FMT_CASE_SENSITIVE
; 
 720                 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_CASE_PRESERVING
)) { 
 721                         valid 
|= VOL_CAP_FMT_CASE_PRESERVING
; 
 722                         if (nmp
->nm_fsattr
.nfsa_flags 
& NFS_FSFLAG_CASE_PRESERVING
) { 
 723                                 caps 
|= VOL_CAP_FMT_CASE_PRESERVING
; 
 726                 /* Note: VOL_CAP_FMT_2TB_FILESIZE is actually used to test for "large file support" */ 
 727                 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXFILESIZE
)) { 
 728                         /* Is server's max file size at least 4GB? */ 
 729                         if (nmp
->nm_fsattr
.nfsa_maxfilesize 
>= 0x100000000ULL
) { 
 730                                 caps 
|= VOL_CAP_FMT_2TB_FILESIZE
; 
 732                 } else if (nfsvers 
>= NFS_VER3
) { 
 734                          * NFSv3 and up supports 64 bits of file size. 
 735                          * So, we'll just assume maxfilesize >= 4GB 
 737                         caps 
|= VOL_CAP_FMT_2TB_FILESIZE
; 
 740                 if (nfsvers 
>= NFS_VER4
) { 
 741                         caps 
|= VOL_CAP_FMT_HIDDEN_FILES
; 
 742                         valid 
|= VOL_CAP_FMT_HIDDEN_FILES
; 
 743                         // VOL_CAP_FMT_OPENDENYMODES 
 744 //                      caps |= VOL_CAP_FMT_OPENDENYMODES; 
 745 //                      valid |= VOL_CAP_FMT_OPENDENYMODES; 
 748                 // no version of nfs supports immutable files 
 749                 caps 
|= VOL_CAP_FMT_NO_IMMUTABLE_FILES
; 
 750                 valid 
|= VOL_CAP_FMT_NO_IMMUTABLE_FILES
; 
 752                 fsap
->f_capabilities
.capabilities
[VOL_CAPABILITIES_FORMAT
] = 
 753                     // VOL_CAP_FMT_PERSISTENTOBJECTIDS | 
 754                     // VOL_CAP_FMT_SYMBOLICLINKS | 
 755                     // VOL_CAP_FMT_HARDLINKS | 
 756                     // VOL_CAP_FMT_JOURNAL | 
 757                     // VOL_CAP_FMT_JOURNAL_ACTIVE | 
 758                     // VOL_CAP_FMT_NO_ROOT_TIMES | 
 759                     // VOL_CAP_FMT_SPARSE_FILES | 
 760                     // VOL_CAP_FMT_ZERO_RUNS | 
 761                     // VOL_CAP_FMT_CASE_SENSITIVE | 
 762                     // VOL_CAP_FMT_CASE_PRESERVING | 
 763                     // VOL_CAP_FMT_FAST_STATFS | 
 764                     // VOL_CAP_FMT_2TB_FILESIZE | 
 765                     // VOL_CAP_FMT_OPENDENYMODES | 
 766                     // VOL_CAP_FMT_HIDDEN_FILES | 
 768                 fsap
->f_capabilities
.valid
[VOL_CAPABILITIES_FORMAT
] = 
 769                     VOL_CAP_FMT_PERSISTENTOBJECTIDS 
| 
 770                     // VOL_CAP_FMT_SYMBOLICLINKS | 
 771                     // VOL_CAP_FMT_HARDLINKS | 
 772                     // VOL_CAP_FMT_JOURNAL | 
 773                     // VOL_CAP_FMT_JOURNAL_ACTIVE | 
 774                     // VOL_CAP_FMT_NO_ROOT_TIMES | 
 775                     // VOL_CAP_FMT_SPARSE_FILES | 
 776                     // VOL_CAP_FMT_ZERO_RUNS | 
 777                     // VOL_CAP_FMT_CASE_SENSITIVE | 
 778                     // VOL_CAP_FMT_CASE_PRESERVING | 
 779                     VOL_CAP_FMT_FAST_STATFS 
| 
 780                     VOL_CAP_FMT_2TB_FILESIZE 
| 
 781                     // VOL_CAP_FMT_OPENDENYMODES | 
 782                     // VOL_CAP_FMT_HIDDEN_FILES | 
 786                  * We don't support most of the interfaces. 
 788                  * We MAY support locking, but we don't have any easy way of 
 789                  * probing.  We can tell if there's no lockd running or if 
 790                  * locks have been disabled for a mount, so we can definitely 
 791                  * answer NO in that case.  Any attempt to send a request to 
 792                  * lockd to test for locking support may cause the lazily- 
 793                  * launched locking daemons to be started unnecessarily.  So 
 794                  * we avoid that.  However, we do record if we ever successfully 
 795                  * perform a lock operation on a mount point, so if it looks 
 796                  * like lock ops have worked, we do report that we support them. 
 800                 if (nfsvers 
>= NFS_VER4
) { 
 801                         caps 
= VOL_CAP_INT_ADVLOCK 
| VOL_CAP_INT_FLOCK
; 
 802                         valid 
= VOL_CAP_INT_ADVLOCK 
| VOL_CAP_INT_FLOCK
; 
 803                         if (nmp
->nm_fsattr
.nfsa_flags 
& NFS_FSFLAG_ACL
) { 
 804                                 caps 
|= VOL_CAP_INT_EXTENDED_SECURITY
; 
 806                         valid 
|= VOL_CAP_INT_EXTENDED_SECURITY
; 
 807                         if (nmp
->nm_fsattr
.nfsa_flags 
& NFS_FSFLAG_NAMED_ATTR
) { 
 808                                 caps 
|= VOL_CAP_INT_EXTENDED_ATTR
; 
 810                         valid 
|= VOL_CAP_INT_EXTENDED_ATTR
; 
 812                         if (nmp
->nm_fsattr
.nfsa_flags 
& NFS_FSFLAG_NAMED_ATTR
) { 
 813                                 caps 
|= VOL_CAP_INT_NAMEDSTREAMS
; 
 815                         valid 
|= VOL_CAP_INT_NAMEDSTREAMS
; 
 819                 if (nmp
->nm_lockmode 
== NFS_LOCK_MODE_DISABLED
) { 
 820                         /* locks disabled on this mount, so they definitely won't work */ 
 821                         valid 
= VOL_CAP_INT_ADVLOCK 
| VOL_CAP_INT_FLOCK
; 
 822                 } else if (nmp
->nm_state 
& NFSSTA_LOCKSWORK
) { 
 823                         caps 
= VOL_CAP_INT_ADVLOCK 
| VOL_CAP_INT_FLOCK
; 
 824                         valid 
= VOL_CAP_INT_ADVLOCK 
| VOL_CAP_INT_FLOCK
; 
 826                 fsap
->f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] = 
 827                     // VOL_CAP_INT_SEARCHFS | 
 828                     // VOL_CAP_INT_ATTRLIST | 
 829                     // VOL_CAP_INT_NFSEXPORT | 
 830                     // VOL_CAP_INT_READDIRATTR | 
 831                     // VOL_CAP_INT_EXCHANGEDATA | 
 832                     // VOL_CAP_INT_COPYFILE | 
 833                     // VOL_CAP_INT_ALLOCATE | 
 834                     // VOL_CAP_INT_VOL_RENAME | 
 835                     // VOL_CAP_INT_ADVLOCK | 
 836                     // VOL_CAP_INT_FLOCK | 
 837                     // VOL_CAP_INT_EXTENDED_SECURITY | 
 838                     // VOL_CAP_INT_USERACCESS | 
 839                     // VOL_CAP_INT_MANLOCK | 
 840                     // VOL_CAP_INT_NAMEDSTREAMS | 
 841                     // VOL_CAP_INT_EXTENDED_ATTR | 
 842                     VOL_CAP_INT_REMOTE_EVENT 
| 
 844                 fsap
->f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] = 
 845                     VOL_CAP_INT_SEARCHFS 
| 
 846                     VOL_CAP_INT_ATTRLIST 
| 
 847                     VOL_CAP_INT_NFSEXPORT 
| 
 848                     VOL_CAP_INT_READDIRATTR 
| 
 849                     VOL_CAP_INT_EXCHANGEDATA 
| 
 850                     VOL_CAP_INT_COPYFILE 
| 
 851                     VOL_CAP_INT_ALLOCATE 
| 
 852                     VOL_CAP_INT_VOL_RENAME 
| 
 853                     // VOL_CAP_INT_ADVLOCK | 
 854                     // VOL_CAP_INT_FLOCK | 
 855                     // VOL_CAP_INT_EXTENDED_SECURITY | 
 856                     // VOL_CAP_INT_USERACCESS | 
 857                     // VOL_CAP_INT_MANLOCK | 
 858                     // VOL_CAP_INT_NAMEDSTREAMS | 
 859                     // VOL_CAP_INT_EXTENDED_ATTR | 
 860                     VOL_CAP_INT_REMOTE_EVENT 
| 
 863                 fsap
->f_capabilities
.capabilities
[VOL_CAPABILITIES_RESERVED1
] = 0; 
 864                 fsap
->f_capabilities
.valid
[VOL_CAPABILITIES_RESERVED1
] = 0; 
 866                 fsap
->f_capabilities
.capabilities
[VOL_CAPABILITIES_RESERVED2
] = 0; 
 867                 fsap
->f_capabilities
.valid
[VOL_CAPABILITIES_RESERVED2
] = 0; 
 869                 VFSATTR_SET_SUPPORTED(fsap
, f_capabilities
); 
 870                 lck_mtx_unlock(&nmp
->nm_lock
); 
 873         if (VFSATTR_IS_ACTIVE(fsap
, f_attributes
)) { 
 874                 fsap
->f_attributes
.validattr
.commonattr 
= 0; 
 875                 fsap
->f_attributes
.validattr
.volattr 
= 
 876                     ATTR_VOL_NAME 
| ATTR_VOL_CAPABILITIES 
| ATTR_VOL_ATTRIBUTES
; 
 877                 fsap
->f_attributes
.validattr
.dirattr 
= 0; 
 878                 fsap
->f_attributes
.validattr
.fileattr 
= 0; 
 879                 fsap
->f_attributes
.validattr
.forkattr 
= 0; 
 881                 fsap
->f_attributes
.nativeattr
.commonattr 
= 0; 
 882                 fsap
->f_attributes
.nativeattr
.volattr 
= 
 883                     ATTR_VOL_NAME 
| ATTR_VOL_CAPABILITIES 
| ATTR_VOL_ATTRIBUTES
; 
 884                 fsap
->f_attributes
.nativeattr
.dirattr 
= 0; 
 885                 fsap
->f_attributes
.nativeattr
.fileattr 
= 0; 
 886                 fsap
->f_attributes
.nativeattr
.forkattr 
= 0; 
 888                 VFSATTR_SET_SUPPORTED(fsap
, f_attributes
); 
 895  * nfs version 3 fsinfo rpc call 
 898 nfs3_fsinfo(struct nfsmount 
*nmp
, nfsnode_t np
, vfs_context_t ctx
) 
 900         int error 
= 0, lockerror
, status
, nmlocked 
= 0; 
 902         uint32_t val
, prefsize
, maxsize
; 
 903         struct nfsm_chain nmreq
, nmrep
; 
 905         nfsm_chain_null(&nmreq
); 
 906         nfsm_chain_null(&nmrep
); 
 908         nfsm_chain_build_alloc_init(error
, &nmreq
, NFSX_FH(nmp
->nm_vers
)); 
 909         nfsm_chain_add_fh(error
, &nmreq
, nmp
->nm_vers
, np
->n_fhp
, np
->n_fhsize
); 
 910         nfsm_chain_build_done(error
, &nmreq
); 
 912         error 
= nfs_request(np
, NULL
, &nmreq
, NFSPROC_FSINFO
, ctx
, NULL
, &nmrep
, &xid
, &status
); 
 913         if ((lockerror 
= nfs_node_lock(np
))) { 
 916         nfsm_chain_postop_attr_update(error
, &nmrep
, np
, &xid
); 
 925         lck_mtx_lock(&nmp
->nm_lock
); 
 928         nfsm_chain_get_32(error
, &nmrep
, maxsize
); 
 929         nfsm_chain_get_32(error
, &nmrep
, prefsize
); 
 931         nmp
->nm_fsattr
.nfsa_maxread 
= maxsize
; 
 932         if (prefsize 
< nmp
->nm_rsize
) { 
 933                 nmp
->nm_rsize 
= (prefsize 
+ NFS_FABLKSIZE 
- 1) & 
 934                     ~(NFS_FABLKSIZE 
- 1); 
 936         if ((maxsize 
> 0) && (maxsize 
< nmp
->nm_rsize
)) { 
 937                 nmp
->nm_rsize 
= maxsize 
& ~(NFS_FABLKSIZE 
- 1); 
 938                 if (nmp
->nm_rsize 
== 0) { 
 939                         nmp
->nm_rsize 
= maxsize
; 
 942         nfsm_chain_adv(error
, &nmrep
, NFSX_UNSIGNED
); // skip rtmult 
 944         nfsm_chain_get_32(error
, &nmrep
, maxsize
); 
 945         nfsm_chain_get_32(error
, &nmrep
, prefsize
); 
 947         nmp
->nm_fsattr
.nfsa_maxwrite 
= maxsize
; 
 948         if (prefsize 
< nmp
->nm_wsize
) { 
 949                 nmp
->nm_wsize 
= (prefsize 
+ NFS_FABLKSIZE 
- 1) & 
 950                     ~(NFS_FABLKSIZE 
- 1); 
 952         if ((maxsize 
> 0) && (maxsize 
< nmp
->nm_wsize
)) { 
 953                 nmp
->nm_wsize 
= maxsize 
& ~(NFS_FABLKSIZE 
- 1); 
 954                 if (nmp
->nm_wsize 
== 0) { 
 955                         nmp
->nm_wsize 
= maxsize
; 
 958         nfsm_chain_adv(error
, &nmrep
, NFSX_UNSIGNED
); // skip wtmult 
 960         nfsm_chain_get_32(error
, &nmrep
, prefsize
); 
 962         if ((prefsize 
> 0) && (prefsize 
< nmp
->nm_readdirsize
)) { 
 963                 nmp
->nm_readdirsize 
= prefsize
; 
 965         if ((nmp
->nm_fsattr
.nfsa_maxread 
> 0) && 
 966             (nmp
->nm_fsattr
.nfsa_maxread 
< nmp
->nm_readdirsize
)) { 
 967                 nmp
->nm_readdirsize 
= nmp
->nm_fsattr
.nfsa_maxread
; 
 970         nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_maxfilesize
); 
 972         nfsm_chain_adv(error
, &nmrep
, 2 * NFSX_UNSIGNED
); // skip time_delta 
 974         /* convert FS properties to our own flags */ 
 975         nfsm_chain_get_32(error
, &nmrep
, val
); 
 977         if (val 
& NFSV3FSINFO_LINK
) { 
 978                 nmp
->nm_fsattr
.nfsa_flags 
|= NFS_FSFLAG_LINK
; 
 980         if (val 
& NFSV3FSINFO_SYMLINK
) { 
 981                 nmp
->nm_fsattr
.nfsa_flags 
|= NFS_FSFLAG_SYMLINK
; 
 983         if (val 
& NFSV3FSINFO_HOMOGENEOUS
) { 
 984                 nmp
->nm_fsattr
.nfsa_flags 
|= NFS_FSFLAG_HOMOGENEOUS
; 
 986         if (val 
& NFSV3FSINFO_CANSETTIME
) { 
 987                 nmp
->nm_fsattr
.nfsa_flags 
|= NFS_FSFLAG_SET_TIME
; 
 989         nmp
->nm_state 
|= NFSSTA_GOTFSINFO
; 
 990         NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXREAD
); 
 991         NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXWRITE
); 
 992         NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXFILESIZE
); 
 993         NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_LINK_SUPPORT
); 
 994         NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SYMLINK_SUPPORT
); 
 995         NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_HOMOGENEOUS
); 
 996         NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_CANSETTIME
); 
 999                 lck_mtx_unlock(&nmp
->nm_lock
); 
1001         nfsm_chain_cleanup(&nmreq
); 
1002         nfsm_chain_cleanup(&nmrep
); 
1007  * Mount a remote root fs via. nfs. This depends on the info in the 
1008  * nfs_diskless structure that has been filled in properly by some primary 
1010  * It goes something like this: 
1011  * - do enough of "ifconfig" by calling ifioctl() so that the system 
1012  *   can talk to the server 
1013  * - If nfs_diskless.mygateway is filled in, use that address as 
1014  *   a default gateway. 
1015  * - hand craft the swap nfs vnode hanging off a fake mount point 
1016  *      if swdevt[0].sw_dev == NODEV 
1017  * - build the rootfs mount point and call mountnfs() to do the rest. 
1023         struct nfs_diskless nd
; 
1028 #if !defined(NO_MOUNT_PRIVATE) 
1029         mount_t mppriv 
= NULL
; 
1030         vnode_t vppriv 
= NULL
; 
1031 #endif /* NO_MOUNT_PRIVATE */ 
1035          * Call nfs_boot_init() to fill in the nfs_diskless struct. 
1036          * Note: networking must already have been configured before 
1039         bzero((caddr_t
) &nd
, sizeof(nd
)); 
1040         error 
= nfs_boot_init(&nd
); 
1042                 panic("nfs_boot_init: unable to initialize NFS root system information, " 
1043                     "error %d, check configuration: %s\n", error
, PE_boot_args()); 
1047          * Try NFSv3 first, then fallback to NFSv2. 
1048          * Likewise, try TCP first, then fall back to UDP. 
1051         sotype 
= SOCK_STREAM
; 
1054         error 
= nfs_boot_getfh(&nd
, v3
, sotype
); 
1056                 if (error 
== EHOSTDOWN 
|| error 
== EHOSTUNREACH
) { 
1057                         if (nd
.nd_root
.ndm_mntfrom
) { 
1058                                 NFS_ZFREE(ZV_NAMEI
, nd
.nd_root
.ndm_mntfrom
); 
1060                         if (nd
.nd_root
.ndm_path
) { 
1061                                 NFS_ZFREE(ZV_NAMEI
, nd
.nd_root
.ndm_path
); 
1063                         if (nd
.nd_private
.ndm_mntfrom
) { 
1064                                 NFS_ZFREE(ZV_NAMEI
, nd
.nd_private
.ndm_mntfrom
); 
1066                         if (nd
.nd_private
.ndm_path
) { 
1067                                 NFS_ZFREE(ZV_NAMEI
, nd
.nd_private
.ndm_path
); 
1072                         if (sotype 
== SOCK_STREAM
) { 
1073                                 printf("NFS mount (v3,TCP) failed with error %d, trying UDP...\n", error
); 
1074                                 sotype 
= SOCK_DGRAM
; 
1077                         printf("NFS mount (v3,UDP) failed with error %d, trying v2...\n", error
); 
1079                         sotype 
= SOCK_STREAM
; 
1081                 } else if (sotype 
== SOCK_STREAM
) { 
1082                         printf("NFS mount (v2,TCP) failed with error %d, trying UDP...\n", error
); 
1083                         sotype 
= SOCK_DGRAM
; 
1086                         printf("NFS mount (v2,UDP) failed with error %d, giving up...\n", error
); 
1090                         panic("NFS mount failed: NFS server mountd not responding, check server configuration: %s", PE_boot_args()); 
1093                         panic("NFS mount failed: NFS server refused mount, check server configuration: %s", PE_boot_args()); 
1095                         panic("NFS mount failed with error %d, check configuration: %s", error
, PE_boot_args()); 
1099         ctx 
= vfs_context_kernel(); 
1102          * Create the root mount point. 
1104 #if !defined(NO_MOUNT_PRIVATE) 
1106                 //PWC hack until we have a real "mount" tool to remount root rw 
1108                 int flags 
= MNT_ROOTFS 
| MNT_RDONLY
; 
1109                 PE_parse_boot_argn("-rwroot_hack", &rw_root
, sizeof(rw_root
)); 
1112                         kprintf("-rwroot_hack in effect: mounting root fs read/write\n"); 
1115                 if ((error 
= nfs_mount_diskless(&nd
.nd_root
, "/", flags
, &vp
, &mp
, ctx
))) 
1117         if ((error 
= nfs_mount_diskless(&nd
.nd_root
, "/", MNT_ROOTFS
, &vp
, &mp
, ctx
))) 
1118 #endif /* NO_MOUNT_PRIVATE */ 
1121                                 if (sotype 
== SOCK_STREAM
) { 
1122                                         printf("NFS root mount (v3,TCP) failed with %d, trying UDP...\n", error
); 
1123                                         sotype 
= SOCK_DGRAM
; 
1126                                 printf("NFS root mount (v3,UDP) failed with %d, trying v2...\n", error
); 
1128                                 sotype 
= SOCK_STREAM
; 
1130                         } else if (sotype 
== SOCK_STREAM
) { 
1131                                 printf("NFS root mount (v2,TCP) failed with %d, trying UDP...\n", error
); 
1132                                 sotype 
= SOCK_DGRAM
; 
1135                                 printf("NFS root mount (v2,UDP) failed with error %d, giving up...\n", error
); 
1137                         panic("NFS root mount failed with error %d, check configuration: %s\n", error
, PE_boot_args()); 
1140         printf("root on %s\n", nd
.nd_root
.ndm_mntfrom
); 
1146 #if !defined(NO_MOUNT_PRIVATE) 
1147         if (nd
.nd_private
.ndm_saddr
.sin_addr
.s_addr
) { 
1148                 error 
= nfs_mount_diskless_private(&nd
.nd_private
, "/private", 
1149                     0, &vppriv
, &mppriv
, ctx
); 
1151                         panic("NFS /private mount failed with error %d, check configuration: %s\n", error
, PE_boot_args()); 
1153                 printf("private on %s\n", nd
.nd_private
.ndm_mntfrom
); 
1156                 mount_list_add(mppriv
); 
1159 #endif /* NO_MOUNT_PRIVATE */ 
1161         if (nd
.nd_root
.ndm_mntfrom
) { 
1162                 NFS_ZFREE(ZV_NAMEI
, nd
.nd_root
.ndm_mntfrom
); 
1164         if (nd
.nd_root
.ndm_path
) { 
1165                 NFS_ZFREE(ZV_NAMEI
, nd
.nd_root
.ndm_path
); 
1167         if (nd
.nd_private
.ndm_mntfrom
) { 
1168                 NFS_ZFREE(ZV_NAMEI
, nd
.nd_private
.ndm_mntfrom
); 
1170         if (nd
.nd_private
.ndm_path
) { 
1171                 NFS_ZFREE(ZV_NAMEI
, nd
.nd_private
.ndm_path
); 
1174         /* Get root attributes (for the time). */ 
1175         error 
= nfs_getattr(VTONFS(vp
), NULL
, ctx
, NGA_UNCACHED
); 
1177                 panic("NFS mount: failed to get attributes for root directory, error %d, check server", error
); 
1183  * Internal version of mount system call for diskless setup. 
1187         struct nfs_dlmount 
*ndmntp
, 
1188         const char *mntname
, 
1195         int error
, numcomps
; 
1196         char *xdrbuf
, *p
, *cp
, *frompath
, *endserverp
; 
1197         char uaddr
[MAX_IPv4_STR_LEN
]; 
1199         uint32_t mattrs
[NFS_MATTR_BITMAP_LEN
]; 
1200         uint32_t mflags_mask
[NFS_MFLAG_BITMAP_LEN
]; 
1201         uint32_t mflags
[NFS_MFLAG_BITMAP_LEN
]; 
1202         uint64_t argslength_offset
, attrslength_offset
, end_offset
; 
1204         if ((error 
= vfs_rootmountalloc("nfs", ndmntp
->ndm_mntfrom
, &mp
))) { 
1205                 printf("nfs_mount_diskless: NFS not configured\n"); 
1209         mp
->mnt_flag 
|= mntflag
; 
1210         if (!(mntflag 
& MNT_RDONLY
)) { 
1211                 mp
->mnt_flag 
&= ~MNT_RDONLY
; 
1214         /* find the server-side path being mounted */ 
1215         frompath 
= ndmntp
->ndm_mntfrom
; 
1216         if (*frompath 
== '[') {  /* skip IPv6 literal address */ 
1217                 while (*frompath 
&& (*frompath 
!= ']')) { 
1220                 if (*frompath 
== ']') { 
1224         while (*frompath 
&& (*frompath 
!= ':')) { 
1227         endserverp 
= frompath
; 
1228         while (*frompath 
&& (*frompath 
== ':')) { 
1231         /* count fs location path components */ 
1233         while (*p 
&& (*p 
== '/')) { 
1239                 while (*p 
&& (*p 
!= '/')) { 
1242                 while (*p 
&& (*p 
== '/')) { 
1247         /* convert address to universal address string */ 
1248         if (inet_ntop(AF_INET
, &ndmntp
->ndm_saddr
.sin_addr
, uaddr
, sizeof(uaddr
)) != uaddr
) { 
1249                 printf("nfs_mount_diskless: bad address\n"); 
1253         /* prepare mount attributes */ 
1254         NFS_BITMAP_ZERO(mattrs
, NFS_MATTR_BITMAP_LEN
); 
1255         NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_VERSION
); 
1256         NFS_BITMAP_SET(mattrs
, NFS_MATTR_SOCKET_TYPE
); 
1257         NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_PORT
); 
1258         NFS_BITMAP_SET(mattrs
, NFS_MATTR_FH
); 
1259         NFS_BITMAP_SET(mattrs
, NFS_MATTR_FS_LOCATIONS
); 
1260         NFS_BITMAP_SET(mattrs
, NFS_MATTR_MNTFLAGS
); 
1262         /* prepare mount flags */ 
1263         NFS_BITMAP_ZERO(mflags_mask
, NFS_MFLAG_BITMAP_LEN
); 
1264         NFS_BITMAP_ZERO(mflags
, NFS_MFLAG_BITMAP_LEN
); 
1265         NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_RESVPORT
); 
1266         NFS_BITMAP_SET(mflags
, NFS_MFLAG_RESVPORT
); 
1268         /* build xdr buffer */ 
1269         xb_init_buffer(&xb
, NULL
, 0); 
1270         xb_add_32(error
, &xb
, NFS_ARGSVERSION_XDR
); 
1271         argslength_offset 
= xb_offset(&xb
); 
1272         xb_add_32(error
, &xb
, 0); // args length 
1273         xb_add_32(error
, &xb
, NFS_XDRARGS_VERSION_0
); 
1274         xb_add_bitmap(error
, &xb
, mattrs
, NFS_MATTR_BITMAP_LEN
); 
1275         attrslength_offset 
= xb_offset(&xb
); 
1276         xb_add_32(error
, &xb
, 0); // attrs length 
1277         xb_add_32(error
, &xb
, ndmntp
->ndm_nfsv3 
? 3 : 2); // NFS version 
1278         xb_add_string(error
, &xb
, ((ndmntp
->ndm_sotype 
== SOCK_DGRAM
) ? "udp" : "tcp"), 3); 
1279         xb_add_32(error
, &xb
, ntohs(ndmntp
->ndm_saddr
.sin_port
)); // NFS port 
1280         xb_add_fh(error
, &xb
, &ndmntp
->ndm_fh
[0], ndmntp
->ndm_fhlen
); 
1282         xb_add_32(error
, &xb
, 1); /* fs location count */ 
1283         xb_add_32(error
, &xb
, 1); /* server count */ 
1284         xb_add_string(error
, &xb
, ndmntp
->ndm_mntfrom
, (endserverp 
- ndmntp
->ndm_mntfrom
)); /* server name */ 
1285         xb_add_32(error
, &xb
, 1); /* address count */ 
1286         xb_add_string(error
, &xb
, uaddr
, strlen(uaddr
)); /* address */ 
1287         xb_add_32(error
, &xb
, 0); /* empty server info */ 
1288         xb_add_32(error
, &xb
, numcomps
); /* pathname component count */ 
1290         while (*p 
&& (*p 
== '/')) { 
1295                 while (*p 
&& (*p 
!= '/')) { 
1298                 xb_add_string(error
, &xb
, cp
, (p 
- cp
)); /* component */ 
1302                 while (*p 
&& (*p 
== '/')) { 
1306         xb_add_32(error
, &xb
, 0); /* empty fsl info */ 
1307         xb_add_32(error
, &xb
, mntflag
); /* MNT flags */ 
1308         xb_build_done(error
, &xb
); 
1310         /* update opaque counts */ 
1311         end_offset 
= xb_offset(&xb
); 
1313                 error 
= xb_seek(&xb
, argslength_offset
); 
1314                 xb_add_32(error
, &xb
, end_offset 
- argslength_offset 
+ XDRWORD 
/*version*/); 
1317                 error 
= xb_seek(&xb
, attrslength_offset
); 
1318                 xb_add_32(error
, &xb
, end_offset 
- attrslength_offset 
- XDRWORD 
/*don't include length field*/); 
1321                 printf("nfs_mount_diskless: error %d assembling mount args\n", error
); 
1325         /* grab the assembled buffer */ 
1326         xdrbuf 
= xb_buffer_base(&xb
); 
1327         xb
.xb_flags 
&= ~XB_CLEANUP
; 
1330         if ((error 
= mountnfs(xdrbuf
, mp
, ctx
, vpp
))) { 
1331                 printf("nfs_mountroot: mount %s failed: %d\n", mntname
, error
); 
1332                 // XXX vfs_rootmountfailed(mp); 
1334                 mp
->mnt_vtable
->vfc_refcount
--; 
1335                 mount_list_unlock(); 
1337                 mount_lock_destroy(mp
); 
1339                 mac_mount_label_destroy(mp
); 
1341                 NFS_ZFREE(mount_zone
, mp
); 
1349 #if !defined(NO_MOUNT_PRIVATE) 
1351  * Internal version of mount system call to mount "/private" 
1352  * separately in diskless setup 
1355 nfs_mount_diskless_private( 
1356         struct nfs_dlmount 
*ndmntp
, 
1357         const char *mntname
, 
1364         int error
, numcomps
; 
1366         struct vfstable 
*vfsp
; 
1367         struct nameidata nd
; 
1369         char *xdrbuf 
= NULL
, *p
, *cp
, *frompath
, *endserverp
; 
1370         char uaddr
[MAX_IPv4_STR_LEN
]; 
1372         uint32_t mattrs
[NFS_MATTR_BITMAP_LEN
]; 
1373         uint32_t mflags_mask
[NFS_MFLAG_BITMAP_LEN
], mflags
[NFS_MFLAG_BITMAP_LEN
]; 
1374         uint64_t argslength_offset
, attrslength_offset
, end_offset
; 
1376         procp 
= current_proc(); /* XXX */ 
1377         xb_init(&xb
, XDRBUF_NONE
); 
1381                  * mimic main()!. Temporarily set up rootvnode and other stuff so 
1382                  * that namei works. Need to undo this because main() does it, too 
1384                 struct filedesc 
*fdp
;   /* pointer to file descriptor state */ 
1386                 mountlist
.tqh_first
->mnt_flag 
|= MNT_ROOTFS
; 
1388                 /* Get the vnode for '/'. Set fdp->fd_cdir to reference it. */ 
1389                 if (VFS_ROOT(mountlist
.tqh_first
, &rootvnode
, NULL
)) { 
1390                         panic("cannot find root vnode"); 
1392                 error 
= vnode_ref(rootvnode
); 
1394                         printf("nfs_mountroot: vnode_ref() failed on root vnode!\n"); 
1397                 fdp
->fd_cdir 
= rootvnode
; 
1398                 fdp
->fd_rdir 
= NULL
; 
1402          * Get vnode to be covered 
1404         NDINIT(&nd
, LOOKUP
, OP_LOOKUP
, FOLLOW 
| LOCKLEAF
, UIO_SYSSPACE
, 
1405             CAST_USER_ADDR_T(mntname
), ctx
); 
1408                 /* undo vnode_ref() in mimic main()! */ 
1409                 vnode_rele(rootvnode
); 
1412                 printf("nfs_mountroot: private namei failed!\n"); 
1418         if ((error 
= VNOP_FSYNC(vp
, MNT_WAIT
, ctx
)) || 
1419             (error 
= buf_invalidateblks(vp
, BUF_WRITE_DATA
, 0, 0))) { 
1423         if (vnode_vtype(vp
) != VDIR
) { 
1428         for (vfsp 
= vfsconf
; vfsp
; vfsp 
= vfsp
->vfc_next
) { 
1429                 if (!strncmp(vfsp
->vfc_name
, "nfs", sizeof(vfsp
->vfc_name
))) { 
1434                 printf("nfs_mountroot: private NFS not configured\n"); 
1439         if (vnode_mountedhere(vp
) != NULL
) { 
1446          * Allocate and initialize the filesystem. 
1448         mp 
= zalloc_flags(mount_zone
, Z_WAITOK 
| Z_ZERO
); 
1449         /* Initialize the default IO constraints */ 
1450         mp
->mnt_maxreadcnt 
= mp
->mnt_maxwritecnt 
= MAXPHYS
; 
1451         mp
->mnt_segreadcnt 
= mp
->mnt_segwritecnt 
= 32; 
1452         mp
->mnt_ioflags 
= 0; 
1453         mp
->mnt_realrootvp 
= NULLVP
; 
1454         mp
->mnt_authcache_ttl 
= 0; /* Allways go to our lookup */ 
1456         mount_lock_init(mp
); 
1457         TAILQ_INIT(&mp
->mnt_vnodelist
); 
1458         TAILQ_INIT(&mp
->mnt_workerqueue
); 
1459         TAILQ_INIT(&mp
->mnt_newvnodes
); 
1460         (void)vfs_busy(mp
, LK_NOWAIT
); 
1461         TAILQ_INIT(&mp
->mnt_vnodelist
); 
1463         vfsp
->vfc_refcount
++; 
1464         mount_list_unlock(); 
1465         mp
->mnt_vtable 
= vfsp
; 
1466         mp
->mnt_op 
= vfsp
->vfc_vfsops
; 
1467         // mp->mnt_stat.f_type = vfsp->vfc_typenum; 
1468         mp
->mnt_flag 
= mntflag
; 
1469         mp
->mnt_flag 
|= vfsp
->vfc_flags 
& MNT_VISFLAGMASK
; 
1470         strncpy(mp
->mnt_vfsstat
.f_fstypename
, vfsp
->vfc_name
, MFSNAMELEN 
- 1); 
1471         vp
->v_mountedhere 
= mp
; 
1472         mp
->mnt_vnodecovered 
= vp
; 
1474         mp
->mnt_vfsstat
.f_owner 
= kauth_cred_getuid(kauth_cred_get()); 
1475         (void) copystr(mntname
, mp
->mnt_vfsstat
.f_mntonname
, MAXPATHLEN 
- 1, 0); 
1476         (void) copystr(ndmntp
->ndm_mntfrom
, mp
->mnt_vfsstat
.f_mntfromname
, MAXPATHLEN 
- 1, 0); 
1478         mac_mount_label_init(mp
); 
1479         mac_mount_label_associate(ctx
, mp
); 
1482         /* find the server-side path being mounted */ 
1483         frompath 
= ndmntp
->ndm_mntfrom
; 
1484         if (*frompath 
== '[') {  /* skip IPv6 literal address */ 
1485                 while (*frompath 
&& (*frompath 
!= ']')) { 
1488                 if (*frompath 
== ']') { 
1492         while (*frompath 
&& (*frompath 
!= ':')) { 
1495         endserverp 
= frompath
; 
1496         while (*frompath 
&& (*frompath 
== ':')) { 
1499         /* count fs location path components */ 
1501         while (*p 
&& (*p 
== '/')) { 
1507                 while (*p 
&& (*p 
!= '/')) { 
1510                 while (*p 
&& (*p 
== '/')) { 
1515         /* convert address to universal address string */ 
1516         if (inet_ntop(AF_INET
, &ndmntp
->ndm_saddr
.sin_addr
, uaddr
, sizeof(uaddr
)) != uaddr
) { 
1517                 printf("nfs_mountroot: bad address\n"); 
1522         /* prepare mount attributes */ 
1523         NFS_BITMAP_ZERO(mattrs
, NFS_MATTR_BITMAP_LEN
); 
1524         NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_VERSION
); 
1525         NFS_BITMAP_SET(mattrs
, NFS_MATTR_SOCKET_TYPE
); 
1526         NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_PORT
); 
1527         NFS_BITMAP_SET(mattrs
, NFS_MATTR_FH
); 
1528         NFS_BITMAP_SET(mattrs
, NFS_MATTR_FS_LOCATIONS
); 
1529         NFS_BITMAP_SET(mattrs
, NFS_MATTR_MNTFLAGS
); 
1531         /* prepare mount flags */ 
1532         NFS_BITMAP_ZERO(mflags_mask
, NFS_MFLAG_BITMAP_LEN
); 
1533         NFS_BITMAP_ZERO(mflags
, NFS_MFLAG_BITMAP_LEN
); 
1534         NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_RESVPORT
); 
1535         NFS_BITMAP_SET(mflags
, NFS_MFLAG_RESVPORT
); 
1537         /* build xdr buffer */ 
1538         xb_init_buffer(&xb
, NULL
, 0); 
1539         xb_add_32(error
, &xb
, NFS_ARGSVERSION_XDR
); 
1540         argslength_offset 
= xb_offset(&xb
); 
1541         xb_add_32(error
, &xb
, 0); // args length 
1542         xb_add_32(error
, &xb
, NFS_XDRARGS_VERSION_0
); 
1543         xb_add_bitmap(error
, &xb
, mattrs
, NFS_MATTR_BITMAP_LEN
); 
1544         attrslength_offset 
= xb_offset(&xb
); 
1545         xb_add_32(error
, &xb
, 0); // attrs length 
1546         xb_add_32(error
, &xb
, ndmntp
->ndm_nfsv3 
? 3 : 2); // NFS version 
1547         xb_add_string(error
, &xb
, ((ndmntp
->ndm_sotype 
== SOCK_DGRAM
) ? "udp" : "tcp"), 3); 
1548         xb_add_32(error
, &xb
, ntohs(ndmntp
->ndm_saddr
.sin_port
)); // NFS port 
1549         xb_add_fh(error
, &xb
, &ndmntp
->ndm_fh
[0], ndmntp
->ndm_fhlen
); 
1551         xb_add_32(error
, &xb
, 1); /* fs location count */ 
1552         xb_add_32(error
, &xb
, 1); /* server count */ 
1553         xb_add_string(error
, &xb
, ndmntp
->ndm_mntfrom
, (endserverp 
- ndmntp
->ndm_mntfrom
)); /* server name */ 
1554         xb_add_32(error
, &xb
, 1); /* address count */ 
1555         xb_add_string(error
, &xb
, uaddr
, strlen(uaddr
)); /* address */ 
1556         xb_add_32(error
, &xb
, 0); /* empty server info */ 
1557         xb_add_32(error
, &xb
, numcomps
); /* pathname component count */ 
1559         while (*p 
&& (*p 
== '/')) { 
1564                 while (*p 
&& (*p 
!= '/')) { 
1567                 xb_add_string(error
, &xb
, cp
, (p 
- cp
)); /* component */ 
1571                 while (*p 
&& (*p 
== '/')) { 
1575         xb_add_32(error
, &xb
, 0); /* empty fsl info */ 
1576         xb_add_32(error
, &xb
, mntflag
); /* MNT flags */ 
1577         xb_build_done(error
, &xb
); 
1579         /* update opaque counts */ 
1580         end_offset 
= xb_offset(&xb
); 
1582                 error 
= xb_seek(&xb
, argslength_offset
); 
1583                 xb_add_32(error
, &xb
, end_offset 
- argslength_offset 
+ XDRWORD 
/*version*/); 
1586                 error 
= xb_seek(&xb
, attrslength_offset
); 
1587                 xb_add_32(error
, &xb
, end_offset 
- attrslength_offset 
- XDRWORD 
/*don't include length field*/); 
1590                 printf("nfs_mountroot: error %d assembling mount args\n", error
); 
1593         /* grab the assembled buffer */ 
1594         xdrbuf 
= xb_buffer_base(&xb
); 
1595         xb
.xb_flags 
&= ~XB_CLEANUP
; 
1598         if ((error 
= mountnfs(xdrbuf
, mp
, ctx
, &vp
))) { 
1599                 printf("nfs_mountroot: mount %s failed: %d\n", mntname
, error
); 
1600                 vnode_put(mp
->mnt_vnodecovered
); 
1602                 vfsp
->vfc_refcount
--; 
1603                 mount_list_unlock(); 
1605                 mount_lock_destroy(mp
); 
1607                 mac_mount_label_destroy(mp
); 
1609                 NFS_ZFREE(mount_zone
, mp
); 
1619 #endif /* NO_MOUNT_PRIVATE */ 
1624  * Convert old style NFS mount args to XDR. 
1627 nfs_convert_old_nfs_args(mount_t mp
, user_addr_t data
, vfs_context_t ctx
, int argsversion
, int inkernel
, char **xdrbufp
) 
1629         int error 
= 0, args64bit
, argsize
, numcomps
; 
1630         struct user_nfs_args args
; 
1631         struct nfs_args tempargs
; 
1634         u_char nfh
[NFS4_FHSIZE
]; 
1635         char *mntfrom
, *endserverp
, *frompath
, *p
, *cp
; 
1636         struct sockaddr_storage ss
; 
1637         void *sinaddr 
= NULL
; 
1638         char uaddr
[MAX_IPv6_STR_LEN
]; 
1639         uint32_t mattrs
[NFS_MATTR_BITMAP_LEN
]; 
1640         uint32_t mflags_mask
[NFS_MFLAG_BITMAP_LEN
], mflags
[NFS_MFLAG_BITMAP_LEN
]; 
1641         uint32_t nfsvers
, nfslockmode 
= 0; 
1642         size_t argslength_offset
, attrslength_offset
, end_offset
; 
1647         /* allocate a temporary buffer for mntfrom */ 
1648         mntfrom 
= zalloc(ZV_NAMEI
); 
1650         args64bit 
= (inkernel 
|| vfs_context_is64bit(ctx
)); 
1651         argsp 
= args64bit 
? (void*)&args 
: (void*)&tempargs
; 
1653         argsize 
= args64bit 
? sizeof(args
) : sizeof(tempargs
); 
1654         switch (argsversion
) { 
1656                 argsize 
-= NFS_ARGSVERSION4_INCSIZE
; 
1659                 argsize 
-= NFS_ARGSVERSION5_INCSIZE
; 
1662                 argsize 
-= NFS_ARGSVERSION6_INCSIZE
; 
1667                 error 
= EPROGMISMATCH
; 
1671         /* read in the structure */ 
1673                 bcopy(CAST_DOWN(void *, data
), argsp
, argsize
); 
1675                 error 
= copyin(data
, argsp
, argsize
); 
1680                 args
.addrlen 
= tempargs
.addrlen
; 
1681                 args
.sotype 
= tempargs
.sotype
; 
1682                 args
.proto 
= tempargs
.proto
; 
1683                 args
.fhsize 
= tempargs
.fhsize
; 
1684                 args
.flags 
= tempargs
.flags
; 
1685                 args
.wsize 
= tempargs
.wsize
; 
1686                 args
.rsize 
= tempargs
.rsize
; 
1687                 args
.readdirsize 
= tempargs
.readdirsize
; 
1688                 args
.timeo 
= tempargs
.timeo
; 
1689                 args
.retrans 
= tempargs
.retrans
; 
1690                 args
.maxgrouplist 
= tempargs
.maxgrouplist
; 
1691                 args
.readahead 
= tempargs
.readahead
; 
1692                 args
.leaseterm 
= tempargs
.leaseterm
; 
1693                 args
.deadthresh 
= tempargs
.deadthresh
; 
1694                 args
.addr 
= CAST_USER_ADDR_T(tempargs
.addr
); 
1695                 args
.fh 
= CAST_USER_ADDR_T(tempargs
.fh
); 
1696                 args
.hostname 
= CAST_USER_ADDR_T(tempargs
.hostname
); 
1697                 if (args
.version 
>= 4) { 
1698                         args
.acregmin 
= tempargs
.acregmin
; 
1699                         args
.acregmax 
= tempargs
.acregmax
; 
1700                         args
.acdirmin 
= tempargs
.acdirmin
; 
1701                         args
.acdirmax 
= tempargs
.acdirmax
; 
1703                 if (args
.version 
>= 5) { 
1704                         args
.auth 
= tempargs
.auth
; 
1706                 if (args
.version 
>= 6) { 
1707                         args
.deadtimeout 
= tempargs
.deadtimeout
; 
1711         if ((args
.fhsize 
< 0) || (args
.fhsize 
> NFS4_FHSIZE
)) { 
1715         if (args
.fhsize 
> 0) { 
1717                         bcopy(CAST_DOWN(void *, args
.fh
), (caddr_t
)nfh
, args
.fhsize
); 
1719                         error 
= copyin(args
.fh
, (caddr_t
)nfh
, args
.fhsize
); 
1725                 error 
= copystr(CAST_DOWN(void *, args
.hostname
), mntfrom
, MAXPATHLEN 
- 1, &len
); 
1727                 error 
= copyinstr(args
.hostname
, mntfrom
, MAXPATHLEN 
- 1, &len
); 
1730         bzero(&mntfrom
[len
], MAXPATHLEN 
- len
); 
1732         /* find the server-side path being mounted */ 
1734         if (*frompath 
== '[') {  /* skip IPv6 literal address */ 
1735                 while (*frompath 
&& (*frompath 
!= ']')) { 
1738                 if (*frompath 
== ']') { 
1742         while (*frompath 
&& (*frompath 
!= ':')) { 
1745         endserverp 
= frompath
; 
1746         while (*frompath 
&& (*frompath 
== ':')) { 
1749         /* count fs location path components */ 
1751         while (*p 
&& (*p 
== '/')) { 
1757                 while (*p 
&& (*p 
!= '/')) { 
1760                 while (*p 
&& (*p 
== '/')) { 
1765         /* copy socket address */ 
1767                 bcopy(CAST_DOWN(void *, args
.addr
), &ss
, args
.addrlen
); 
1769                 if (args
.addrlen 
> sizeof(struct sockaddr_storage
)) { 
1772                         error 
= copyin(args
.addr
, &ss
, args
.addrlen
); 
1776         ss
.ss_len 
= args
.addrlen
; 
1778         /* convert address to universal address string */ 
1779         if (ss
.ss_family 
== AF_INET
) { 
1780                 sinaddr 
= &((struct sockaddr_in
*)&ss
)->sin_addr
; 
1781         } else if (ss
.ss_family 
== AF_INET6
) { 
1782                 sinaddr 
= &((struct sockaddr_in6
*)&ss
)->sin6_addr
; 
1786         if (!sinaddr 
|| (inet_ntop(ss
.ss_family
, sinaddr
, uaddr
, sizeof(uaddr
)) != uaddr
)) { 
1791         /* prepare mount flags */ 
1792         NFS_BITMAP_ZERO(mflags_mask
, NFS_MFLAG_BITMAP_LEN
); 
1793         NFS_BITMAP_ZERO(mflags
, NFS_MFLAG_BITMAP_LEN
); 
1794         NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_SOFT
); 
1795         NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_INTR
); 
1796         NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_RESVPORT
); 
1797         NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NOCONNECT
); 
1798         NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_DUMBTIMER
); 
1799         NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_CALLUMNT
); 
1800         NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_RDIRPLUS
); 
1801         NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NONEGNAMECACHE
); 
1802         NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_MUTEJUKEBOX
); 
1803         NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NOQUOTA
); 
1804         if (args
.flags 
& NFSMNT_SOFT
) { 
1805                 NFS_BITMAP_SET(mflags
, NFS_MFLAG_SOFT
); 
1807         if (args
.flags 
& NFSMNT_INT
) { 
1808                 NFS_BITMAP_SET(mflags
, NFS_MFLAG_INTR
); 
1810         if (args
.flags 
& NFSMNT_RESVPORT
) { 
1811                 NFS_BITMAP_SET(mflags
, NFS_MFLAG_RESVPORT
); 
1813         if (args
.flags 
& NFSMNT_NOCONN
) { 
1814                 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NOCONNECT
); 
1816         if (args
.flags 
& NFSMNT_DUMBTIMR
) { 
1817                 NFS_BITMAP_SET(mflags
, NFS_MFLAG_DUMBTIMER
); 
1819         if (args
.flags 
& NFSMNT_CALLUMNT
) { 
1820                 NFS_BITMAP_SET(mflags
, NFS_MFLAG_CALLUMNT
); 
1822         if (args
.flags 
& NFSMNT_RDIRPLUS
) { 
1823                 NFS_BITMAP_SET(mflags
, NFS_MFLAG_RDIRPLUS
); 
1825         if (args
.flags 
& NFSMNT_NONEGNAMECACHE
) { 
1826                 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NONEGNAMECACHE
); 
1828         if (args
.flags 
& NFSMNT_MUTEJUKEBOX
) { 
1829                 NFS_BITMAP_SET(mflags
, NFS_MFLAG_MUTEJUKEBOX
); 
1831         if (args
.flags 
& NFSMNT_NOQUOTA
) { 
1832                 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NOQUOTA
); 
1835         /* prepare mount attributes */ 
1836         NFS_BITMAP_ZERO(mattrs
, NFS_MATTR_BITMAP_LEN
); 
1837         NFS_BITMAP_SET(mattrs
, NFS_MATTR_FLAGS
); 
1838         NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_VERSION
); 
1839         NFS_BITMAP_SET(mattrs
, NFS_MATTR_SOCKET_TYPE
); 
1840         NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_PORT
); 
1841         NFS_BITMAP_SET(mattrs
, NFS_MATTR_FH
); 
1842         NFS_BITMAP_SET(mattrs
, NFS_MATTR_FS_LOCATIONS
); 
1843         NFS_BITMAP_SET(mattrs
, NFS_MATTR_MNTFLAGS
); 
1844         NFS_BITMAP_SET(mattrs
, NFS_MATTR_MNTFROM
); 
1845         if (args
.flags 
& NFSMNT_NFSV4
) { 
1847         } else if (args
.flags 
& NFSMNT_NFSV3
) { 
1852         if ((args
.flags 
& NFSMNT_RSIZE
) && (args
.rsize 
> 0)) { 
1853                 NFS_BITMAP_SET(mattrs
, NFS_MATTR_READ_SIZE
); 
1855         if ((args
.flags 
& NFSMNT_WSIZE
) && (args
.wsize 
> 0)) { 
1856                 NFS_BITMAP_SET(mattrs
, NFS_MATTR_WRITE_SIZE
); 
1858         if ((args
.flags 
& NFSMNT_TIMEO
) && (args
.timeo 
> 0)) { 
1859                 NFS_BITMAP_SET(mattrs
, NFS_MATTR_REQUEST_TIMEOUT
); 
1861         if ((args
.flags 
& NFSMNT_RETRANS
) && (args
.retrans 
> 0)) { 
1862                 NFS_BITMAP_SET(mattrs
, NFS_MATTR_SOFT_RETRY_COUNT
); 
1864         if ((args
.flags 
& NFSMNT_MAXGRPS
) && (args
.maxgrouplist 
> 0)) { 
1865                 NFS_BITMAP_SET(mattrs
, NFS_MATTR_MAX_GROUP_LIST
); 
1867         if ((args
.flags 
& NFSMNT_READAHEAD
) && (args
.readahead 
> 0)) { 
1868                 NFS_BITMAP_SET(mattrs
, NFS_MATTR_READAHEAD
); 
1870         if ((args
.flags 
& NFSMNT_READDIRSIZE
) && (args
.readdirsize 
> 0)) { 
1871                 NFS_BITMAP_SET(mattrs
, NFS_MATTR_READDIR_SIZE
); 
1873         if ((args
.flags 
& NFSMNT_NOLOCKS
) || 
1874             (args
.flags 
& NFSMNT_LOCALLOCKS
)) { 
1875                 NFS_BITMAP_SET(mattrs
, NFS_MATTR_LOCK_MODE
); 
1876                 if (args
.flags 
& NFSMNT_NOLOCKS
) { 
1877                         nfslockmode 
= NFS_LOCK_MODE_DISABLED
; 
1878                 } else if (args
.flags 
& NFSMNT_LOCALLOCKS
) { 
1879                         nfslockmode 
= NFS_LOCK_MODE_LOCAL
; 
1881                         nfslockmode 
= NFS_LOCK_MODE_ENABLED
; 
1884         if (args
.version 
>= 4) { 
1885                 if ((args
.flags 
& NFSMNT_ACREGMIN
) && (args
.acregmin 
> 0)) { 
1886                         NFS_BITMAP_SET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MIN
); 
1888                 if ((args
.flags 
& NFSMNT_ACREGMAX
) && (args
.acregmax 
> 0)) { 
1889                         NFS_BITMAP_SET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MAX
); 
1891                 if ((args
.flags 
& NFSMNT_ACDIRMIN
) && (args
.acdirmin 
> 0)) { 
1892                         NFS_BITMAP_SET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MIN
); 
1894                 if ((args
.flags 
& NFSMNT_ACDIRMAX
) && (args
.acdirmax 
> 0)) { 
1895                         NFS_BITMAP_SET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MAX
); 
1898         if (args
.version 
>= 5) { 
1899                 if ((args
.flags 
& NFSMNT_SECFLAVOR
) || (args
.flags 
& NFSMNT_SECSYSOK
)) { 
1900                         NFS_BITMAP_SET(mattrs
, NFS_MATTR_SECURITY
); 
1903         if (args
.version 
>= 6) { 
1904                 if ((args
.flags 
& NFSMNT_DEADTIMEOUT
) && (args
.deadtimeout 
> 0)) { 
1905                         NFS_BITMAP_SET(mattrs
, NFS_MATTR_DEAD_TIMEOUT
); 
1909         /* build xdr buffer */ 
1910         xb_init_buffer(&xb
, NULL
, 0); 
1911         xb_add_32(error
, &xb
, args
.version
); 
1912         argslength_offset 
= xb_offset(&xb
); 
1913         xb_add_32(error
, &xb
, 0); // args length 
1914         xb_add_32(error
, &xb
, NFS_XDRARGS_VERSION_0
); 
1915         xb_add_bitmap(error
, &xb
, mattrs
, NFS_MATTR_BITMAP_LEN
); 
1916         attrslength_offset 
= xb_offset(&xb
); 
1917         xb_add_32(error
, &xb
, 0); // attrs length 
1918         xb_add_bitmap(error
, &xb
, mflags_mask
, NFS_MFLAG_BITMAP_LEN
); /* mask */ 
1919         xb_add_bitmap(error
, &xb
, mflags
, NFS_MFLAG_BITMAP_LEN
); /* value */ 
1920         xb_add_32(error
, &xb
, nfsvers
); 
1921         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READ_SIZE
)) { 
1922                 xb_add_32(error
, &xb
, args
.rsize
); 
1924         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_WRITE_SIZE
)) { 
1925                 xb_add_32(error
, &xb
, args
.wsize
); 
1927         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READDIR_SIZE
)) { 
1928                 xb_add_32(error
, &xb
, args
.readdirsize
); 
1930         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READAHEAD
)) { 
1931                 xb_add_32(error
, &xb
, args
.readahead
); 
1933         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MIN
)) { 
1934                 xb_add_32(error
, &xb
, args
.acregmin
); 
1935                 xb_add_32(error
, &xb
, 0); 
1937         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MAX
)) { 
1938                 xb_add_32(error
, &xb
, args
.acregmax
); 
1939                 xb_add_32(error
, &xb
, 0); 
1941         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MIN
)) { 
1942                 xb_add_32(error
, &xb
, args
.acdirmin
); 
1943                 xb_add_32(error
, &xb
, 0); 
1945         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MAX
)) { 
1946                 xb_add_32(error
, &xb
, args
.acdirmax
); 
1947                 xb_add_32(error
, &xb
, 0); 
1949         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_LOCK_MODE
)) { 
1950                 xb_add_32(error
, &xb
, nfslockmode
); 
1952         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SECURITY
)) { 
1953                 uint32_t flavors
[2], i 
= 0; 
1954                 if (args
.flags 
& NFSMNT_SECFLAVOR
) { 
1955                         flavors
[i
++] = args
.auth
; 
1957                 if ((args
.flags 
& NFSMNT_SECSYSOK
) && ((i 
== 0) || (flavors
[0] != RPCAUTH_SYS
))) { 
1958                         flavors
[i
++] = RPCAUTH_SYS
; 
1960                 xb_add_word_array(error
, &xb
, flavors
, i
); 
1962         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MAX_GROUP_LIST
)) { 
1963                 xb_add_32(error
, &xb
, args
.maxgrouplist
); 
1965         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SOCKET_TYPE
)) { 
1966                 xb_add_string(error
, &xb
, ((args
.sotype 
== SOCK_DGRAM
) ? "udp" : "tcp"), 3); 
1968         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_PORT
)) { 
1969                 xb_add_32(error
, &xb
, ((ss
.ss_family 
== AF_INET
) ? 
1970                     ntohs(((struct sockaddr_in
*)&ss
)->sin_port
) : 
1971                     ntohs(((struct sockaddr_in6
*)&ss
)->sin6_port
))); 
1973         /* NFS_MATTR_MOUNT_PORT (not available in old args) */ 
1974         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_REQUEST_TIMEOUT
)) { 
1975                 /* convert from .1s increments to time */ 
1976                 xb_add_32(error
, &xb
, args
.timeo 
/ 10); 
1977                 xb_add_32(error
, &xb
, (args
.timeo 
% 10) * 100000000); 
1979         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SOFT_RETRY_COUNT
)) { 
1980                 xb_add_32(error
, &xb
, args
.retrans
); 
1982         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_DEAD_TIMEOUT
)) { 
1983                 xb_add_32(error
, &xb
, args
.deadtimeout
); 
1984                 xb_add_32(error
, &xb
, 0); 
1986         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_FH
)) { 
1987                 xb_add_fh(error
, &xb
, &nfh
[0], args
.fhsize
); 
1989         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_FS_LOCATIONS
)) { 
1990                 xb_add_32(error
, &xb
, 1); /* fs location count */ 
1991                 xb_add_32(error
, &xb
, 1); /* server count */ 
1992                 xb_add_string(error
, &xb
, mntfrom
, (endserverp 
- mntfrom
)); /* server name */ 
1993                 xb_add_32(error
, &xb
, 1); /* address count */ 
1994                 xb_add_string(error
, &xb
, uaddr
, strlen(uaddr
)); /* address */ 
1995                 xb_add_32(error
, &xb
, 0); /* empty server info */ 
1996                 xb_add_32(error
, &xb
, numcomps
); /* pathname component count */ 
1999                 while (*p 
&& (*p 
== '/')) { 
2004                         while (*p 
&& (*p 
!= '/')) { 
2007                         xb_add_string(error
, &xb
, cp
, (p 
- cp
)); /* component */ 
2009                         while (*p 
&& (*p 
== '/')) { 
2013                 xb_add_32(error
, &xb
, 0); /* empty fsl info */ 
2015         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MNTFLAGS
)) { 
2016                 xb_add_32(error
, &xb
, (vfs_flags(mp
) & MNT_VISFLAGMASK
)); /* VFS MNT_* flags */ 
2018         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MNTFROM
)) { 
2019                 xb_add_string(error
, &xb
, mntfrom
, strlen(mntfrom
)); /* fixed f_mntfromname */ 
2021         xb_build_done(error
, &xb
); 
2023         /* update opaque counts */ 
2024         end_offset 
= xb_offset(&xb
); 
2025         error 
= xb_seek(&xb
, argslength_offset
); 
2026         xb_add_32(error
, &xb
, end_offset 
- argslength_offset 
+ XDRWORD 
/*version*/); 
2028         error 
= xb_seek(&xb
, attrslength_offset
); 
2029         xb_add_32(error
, &xb
, end_offset 
- attrslength_offset 
- XDRWORD 
/*don't include length field*/); 
2032                 /* grab the assembled buffer */ 
2033                 *xdrbufp 
= xb_buffer_base(&xb
); 
2034                 xb
.xb_flags 
&= ~XB_CLEANUP
; 
2038         NFS_ZFREE(ZV_NAMEI
, mntfrom
); 
2048 nfs_vfs_mount(mount_t mp
, vnode_t vp
, user_addr_t data
, vfs_context_t ctx
) 
2050         int error 
= 0, inkernel 
= vfs_iskernelmount(mp
); 
2051         uint32_t argsversion
, argslength
; 
2052         char *xdrbuf 
= NULL
; 
2054         /* read in version */ 
2056                 bcopy(CAST_DOWN(void *, data
), &argsversion
, sizeof(argsversion
)); 
2057         } else if ((error 
= copyin(data
, &argsversion
, sizeof(argsversion
)))) { 
2061         /* If we have XDR args, then all values in the buffer are in network order */ 
2062         if (argsversion 
== htonl(NFS_ARGSVERSION_XDR
)) { 
2063                 argsversion 
= NFS_ARGSVERSION_XDR
; 
2066         switch (argsversion
) { 
2071                 /* convert old-style args to xdr */ 
2072                 error 
= nfs_convert_old_nfs_args(mp
, data
, ctx
, argsversion
, inkernel
, &xdrbuf
); 
2074         case NFS_ARGSVERSION_XDR
: 
2075                 /* copy in xdr buffer */ 
2077                         bcopy(CAST_DOWN(void *, (data 
+ XDRWORD
)), &argslength
, XDRWORD
); 
2079                         error 
= copyin((data 
+ XDRWORD
), &argslength
, XDRWORD
); 
2084                 argslength 
= ntohl(argslength
); 
2085                 /* put a reasonable limit on the size of the XDR args */ 
2086                 if (argslength 
> 16 * 1024) { 
2090                 /* allocate xdr buffer */ 
2091                 xdrbuf 
= xb_malloc(xdr_rndup(argslength
)); 
2097                         bcopy(CAST_DOWN(void *, data
), xdrbuf
, argslength
); 
2099                         error 
= copyin(data
, xdrbuf
, argslength
); 
2103                         /* Recheck buffer size to avoid double fetch vulnerability */ 
2105                         uint32_t _version
, _length
; 
2106                         xb_init_buffer(&xb
, xdrbuf
, 2 * XDRWORD
); 
2107                         xb_get_32(error
, &xb
, _version
); /* version */ 
2108                         xb_get_32(error
, &xb
, _length
); /* args length */ 
2109                         if (_length 
!= argslength
) { 
2110                                 printf("nfs: actual buffer length (%u) does not match the initial value (%u)\n", _length
, argslength
); 
2118                 error 
= EPROGMISMATCH
; 
2127         error 
= mountnfs(xdrbuf
, mp
, ctx
, &vp
); 
2132  * Common code for mount and mountroot 
2135 /* Set up an NFSv2/v3 mount */ 
2138         struct nfsmount 
*nmp
, 
2143         struct nfs_vattr nvattr
; 
2153          * Get file attributes for the mountpoint.  These are needed 
2154          * in order to properly create the root vnode. 
2156         error 
= nfs3_getattr_rpc(NULL
, nmp
->nm_mountp
, nmp
->nm_fh
->fh_data
, nmp
->nm_fh
->fh_len
, 0, 
2157             ctx
, &nvattr
, &xid
); 
2162         error 
= nfs_nget(nmp
->nm_mountp
, NULL
, NULL
, nmp
->nm_fh
->fh_data
, nmp
->nm_fh
->fh_len
, 
2163             &nvattr
, &xid
, RPCAUTH_UNKNOWN
, NG_MARKROOT
, npp
); 
2165                 nfs_node_unlock(*npp
); 
2172          * Try to make sure we have all the general info from the server. 
2174         if (nmp
->nm_vers 
== NFS_VER2
) { 
2175                 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXNAME
); 
2176                 nmp
->nm_fsattr
.nfsa_maxname 
= NFS_MAXNAMLEN
; 
2177         } else if (nmp
->nm_vers 
== NFS_VER3
) { 
2178                 /* get the NFSv3 FSINFO */ 
2179                 error 
= nfs3_fsinfo(nmp
, *npp
, ctx
); 
2183                 /* grab a copy of root info now (even if server does not support FSF_HOMOGENEOUS) */ 
2184                 struct nfs_fsattr nfsa
; 
2185                 if (!nfs3_pathconf_rpc(*npp
, &nfsa
, ctx
)) { 
2186                         /* cache a copy of the results */ 
2187                         lck_mtx_lock(&nmp
->nm_lock
); 
2188                         nfs3_pathconf_cache(nmp
, &nfsa
); 
2189                         lck_mtx_unlock(&nmp
->nm_lock
); 
2193         if (*npp 
&& error
) { 
2194                 vnode_put(NFSTOV(*npp
)); 
2195                 vnode_recycle(NFSTOV(*npp
)); 
2203  * Update an NFSv4 mount path with the contents of the symlink. 
2205  * Read the link for the given file handle. 
2206  * Insert the link's components into the path. 
2209 nfs4_mount_update_path_with_symlink(struct nfsmount 
*nmp
, struct nfs_fs_path 
*nfsp
, uint32_t curcomp
, fhandle_t 
*dirfhp
, int *depthp
, fhandle_t 
*fhp
, vfs_context_t ctx
) 
2211         int error 
= 0, status
, numops
; 
2212         uint32_t len 
= 0, comp
, newcomp
, linkcompcount
; 
2214         struct nfsm_chain nmreq
, nmrep
; 
2215         struct nfsreq rq
, *req 
= &rq
; 
2216         struct nfsreq_secinfo_args si
; 
2217         char *link 
= NULL
, *p
, *q
, ch
; 
2218         struct nfs_fs_path nfsp2
; 
2220         bzero(&nfsp2
, sizeof(nfsp2
)); 
2221         if (dirfhp
->fh_len
) { 
2222                 NFSREQ_SECINFO_SET(&si
, NULL
, dirfhp
->fh_data
, dirfhp
->fh_len
, nfsp
->np_components
[curcomp
], 0); 
2224                 NFSREQ_SECINFO_SET(&si
, NULL
, NULL
, 0, nfsp
->np_components
[curcomp
], 0); 
2226         nfsm_chain_null(&nmreq
); 
2227         nfsm_chain_null(&nmrep
); 
2229         link 
= zalloc(ZV_NAMEI
); 
2233         nfsm_chain_build_alloc_init(error
, &nmreq
, 12 * NFSX_UNSIGNED
); 
2234         nfsm_chain_add_compound_header(error
, &nmreq
, "readlink", nmp
->nm_minor_vers
, numops
); 
2236         nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
); 
2237         nfsm_chain_add_fh(error
, &nmreq
, NFS_VER4
, fhp
->fh_data
, fhp
->fh_len
); 
2239         nfsm_chain_add_32(error
, &nmreq
, NFS_OP_READLINK
); 
2240         nfsm_chain_build_done(error
, &nmreq
); 
2241         nfsm_assert(error
, (numops 
== 0), EPROTO
); 
2244         error 
= nfs_request_async(NULL
, nmp
->nm_mountp
, &nmreq
, NFSPROC4_COMPOUND
, 
2245             vfs_context_thread(ctx
), vfs_context_ucred(ctx
), &si
, 0, NULL
, &req
); 
2247                 error 
= nfs_request_async_finish(req
, &nmrep
, &xid
, &status
); 
2250         nfsm_chain_skip_tag(error
, &nmrep
); 
2251         nfsm_chain_get_32(error
, &nmrep
, numops
); 
2252         nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
); 
2253         nfsm_chain_op_check(error
, &nmrep
, NFS_OP_READLINK
); 
2254         nfsm_chain_get_32(error
, &nmrep
, len
); 
2258         } else if (len 
>= MAXPATHLEN
) { 
2259                 len 
= MAXPATHLEN 
- 1; 
2261         nfsm_chain_get_opaque(error
, &nmrep
, len
, link
); 
2263         /* make sure link string is terminated properly */ 
2266         /* count the number of components in link */ 
2268         while (*p 
&& (*p 
== '/')) { 
2274                 while (*p 
&& (*p 
!= '/')) { 
2277                 while (*p 
&& (*p 
== '/')) { 
2282         /* free up used components */ 
2283         for (comp 
= 0; comp 
<= curcomp
; comp
++) { 
2284                 if (nfsp
->np_components
[comp
]) { 
2285                         FREE(nfsp
->np_components
[comp
], M_TEMP
); 
2286                         nfsp
->np_components
[comp
] = NULL
; 
2290         /* set up new path */ 
2291         nfsp2
.np_compcount 
= nfsp
->np_compcount 
- curcomp 
- 1 + linkcompcount
; 
2292         MALLOC(nfsp2
.np_components
, char **, nfsp2
.np_compcount 
* sizeof(char*), M_TEMP
, M_WAITOK 
| M_ZERO
); 
2293         if (!nfsp2
.np_components
) { 
2298         /* add link components */ 
2300         while (*p 
&& (*p 
== '/')) { 
2303         for (newcomp 
= 0; newcomp 
< linkcompcount
; newcomp
++) { 
2304                 /* find end of component */ 
2306                 while (*q 
&& (*q 
!= '/')) { 
2309                 MALLOC(nfsp2
.np_components
[newcomp
], char *, q 
- p 
+ 1, M_TEMP
, M_WAITOK 
| M_ZERO
); 
2310                 if (!nfsp2
.np_components
[newcomp
]) { 
2316                 strlcpy(nfsp2
.np_components
[newcomp
], p
, q 
- p 
+ 1); 
2319                 while (*p 
&& (*p 
== '/')) { 
2325         /* add remaining components */ 
2326         for (comp 
= curcomp 
+ 1; comp 
< nfsp
->np_compcount
; comp
++, newcomp
++) { 
2327                 nfsp2
.np_components
[newcomp
] = nfsp
->np_components
[comp
]; 
2328                 nfsp
->np_components
[comp
] = NULL
; 
2331         /* move new path into place */ 
2332         FREE(nfsp
->np_components
, M_TEMP
); 
2333         nfsp
->np_components 
= nfsp2
.np_components
; 
2334         nfsp
->np_compcount 
= nfsp2
.np_compcount
; 
2335         nfsp2
.np_components 
= NULL
; 
2337         /* for absolute link, let the caller now that the next dirfh is root */ 
2338         if (link
[0] == '/') { 
2344                 NFS_ZFREE(ZV_NAMEI
, link
); 
2346         if (nfsp2
.np_components
) { 
2347                 for (comp 
= 0; comp 
< nfsp2
.np_compcount
; comp
++) { 
2348                         if (nfsp2
.np_components
[comp
]) { 
2349                                 FREE(nfsp2
.np_components
[comp
], M_TEMP
); 
2352                 FREE(nfsp2
.np_components
, M_TEMP
); 
2354         nfsm_chain_cleanup(&nmreq
); 
2355         nfsm_chain_cleanup(&nmrep
); 
2359 /* Set up an NFSv4 mount */ 
2362         struct nfsmount 
*nmp
, 
2366         struct nfsm_chain nmreq
, nmrep
; 
2367         int error 
= 0, numops
, status
, interval
, isdotdot
, loopcnt 
= 0, depth 
= 0; 
2368         struct nfs_fs_path fspath
, *nfsp
, fspath2
; 
2369         uint32_t bitmap
[NFS_ATTR_BITMAP_LEN
], comp
, comp2
; 
2370         fhandle_t fh
, dirfh
; 
2371         struct nfs_vattr nvattr
; 
2373         struct nfsreq rq
, *req 
= &rq
; 
2374         struct nfsreq_secinfo_args si
; 
2376         struct nfs_fs_locations nfsls
; 
2379         fh
.fh_len 
= dirfh
.fh_len 
= 0; 
2380         TAILQ_INIT(&nmp
->nm_open_owners
); 
2381         TAILQ_INIT(&nmp
->nm_delegations
); 
2382         TAILQ_INIT(&nmp
->nm_dreturnq
); 
2383         nmp
->nm_stategenid 
= 1; 
2384         NVATTR_INIT(&nvattr
); 
2385         bzero(&nfsls
, sizeof(nfsls
)); 
2386         nfsm_chain_null(&nmreq
); 
2387         nfsm_chain_null(&nmrep
); 
2390          * If no security flavors were specified we'll want to default to the server's 
2391          * preferred flavor.  For NFSv4.0 we need a file handle and name to get that via 
2392          * SECINFO, so we'll do that on the last component of the server path we are 
2393          * mounting.  If we are mounting the server's root, we'll need to defer the 
2394          * SECINFO call to the first successful LOOKUP request. 
2396         if (!nmp
->nm_sec
.count
) { 
2397                 nmp
->nm_state 
|= NFSSTA_NEEDSECINFO
; 
2400         /* make a copy of the current location's path */ 
2401         nfsp 
= &nmp
->nm_locations
.nl_locations
[nmp
->nm_locations
.nl_current
.nli_loc
]->nl_path
; 
2402         bzero(&fspath
, sizeof(fspath
)); 
2403         fspath
.np_compcount 
= nfsp
->np_compcount
; 
2404         if (fspath
.np_compcount 
> 0) { 
2405                 MALLOC(fspath
.np_components
, char **, fspath
.np_compcount 
* sizeof(char*), M_TEMP
, M_WAITOK 
| M_ZERO
); 
2406                 if (!fspath
.np_components
) { 
2410                 for (comp 
= 0; comp 
< nfsp
->np_compcount
; comp
++) { 
2411                         size_t slen 
= strlen(nfsp
->np_components
[comp
]); 
2412                         MALLOC(fspath
.np_components
[comp
], char *, slen 
+ 1, M_TEMP
, M_WAITOK 
| M_ZERO
); 
2413                         if (!fspath
.np_components
[comp
]) { 
2417                         strlcpy(fspath
.np_components
[comp
], nfsp
->np_components
[comp
], slen 
+ 1); 
2424         /* for mirror mounts, we can just use the file handle passed in */ 
2426                 dirfh
.fh_len 
= nmp
->nm_fh
->fh_len
; 
2427                 bcopy(nmp
->nm_fh
->fh_data
, dirfh
.fh_data
, dirfh
.fh_len
); 
2428                 NFSREQ_SECINFO_SET(&si
, NULL
, dirfh
.fh_data
, dirfh
.fh_len
, NULL
, 0); 
2432         /* otherwise, we need to get the fh for the directory we are mounting */ 
2434         /* if no components, just get root */ 
2435         if (fspath
.np_compcount 
== 0) { 
2437                 // PUTROOTFH + GETATTR(FH) 
2438                 NFSREQ_SECINFO_SET(&si
, NULL
, NULL
, 0, NULL
, 0); 
2440                 nfsm_chain_build_alloc_init(error
, &nmreq
, 9 * NFSX_UNSIGNED
); 
2441                 nfsm_chain_add_compound_header(error
, &nmreq
, "mount", nmp
->nm_minor_vers
, numops
); 
2443                 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTROOTFH
); 
2445                 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
); 
2446                 NFS_CLEAR_ATTRIBUTES(bitmap
); 
2447                 NFS4_DEFAULT_ATTRIBUTES(bitmap
); 
2448                 NFS_BITMAP_SET(bitmap
, NFS_FATTR_FILEHANDLE
); 
2449                 nfsm_chain_add_bitmap(error
, &nmreq
, bitmap
, NFS_ATTR_BITMAP_LEN
); 
2450                 nfsm_chain_build_done(error
, &nmreq
); 
2451                 nfsm_assert(error
, (numops 
== 0), EPROTO
); 
2453                 error 
= nfs_request_async(NULL
, nmp
->nm_mountp
, &nmreq
, NFSPROC4_COMPOUND
, 
2454                     vfs_context_thread(ctx
), vfs_context_ucred(ctx
), &si
, 0, NULL
, &req
); 
2456                         error 
= nfs_request_async_finish(req
, &nmrep
, &xid
, &status
); 
2458                 nfsm_chain_skip_tag(error
, &nmrep
); 
2459                 nfsm_chain_get_32(error
, &nmrep
, numops
); 
2460                 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTROOTFH
); 
2461                 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
); 
2463                 NFS_CLEAR_ATTRIBUTES(nmp
->nm_fsattr
.nfsa_bitmap
); 
2464                 error 
= nfs4_parsefattr(&nmrep
, &nmp
->nm_fsattr
, &nvattr
, &dirfh
, NULL
, NULL
); 
2465                 if (!error 
&& !NFS_BITMAP_ISSET(&nvattr
.nva_bitmap
, NFS_FATTR_FILEHANDLE
)) { 
2466                         printf("nfs: mount didn't return filehandle?\n"); 
2470                 nfsm_chain_cleanup(&nmrep
); 
2471                 nfsm_chain_null(&nmreq
); 
2472                 NVATTR_CLEANUP(&nvattr
); 
2476         /* look up each path component */ 
2477         for (comp 
= 0; comp 
< fspath
.np_compcount
;) { 
2479                 if (fspath
.np_components
[comp
][0] == '.') { 
2480                         if (fspath
.np_components
[comp
][1] == '\0') { 
2485                         /* treat ".." specially */ 
2486                         if ((fspath
.np_components
[comp
][1] == '.') && 
2487                             (fspath
.np_components
[comp
][2] == '\0')) { 
2490                         if (isdotdot 
&& (dirfh
.fh_len 
== 0)) { 
2491                                 /* ".." in root directory is same as "." */ 
2496                 // PUT(ROOT)FH + LOOKUP(P) + GETFH + GETATTR 
2497                 if (dirfh
.fh_len 
== 0) { 
2498                         NFSREQ_SECINFO_SET(&si
, NULL
, NULL
, 0, isdotdot 
? NULL 
: fspath
.np_components
[comp
], 0); 
2500                         NFSREQ_SECINFO_SET(&si
, NULL
, dirfh
.fh_data
, dirfh
.fh_len
, isdotdot 
? NULL 
: fspath
.np_components
[comp
], 0); 
2503                 nfsm_chain_build_alloc_init(error
, &nmreq
, 18 * NFSX_UNSIGNED
); 
2504                 nfsm_chain_add_compound_header(error
, &nmreq
, "mount", nmp
->nm_minor_vers
, numops
); 
2507                         nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
); 
2508                         nfsm_chain_add_fh(error
, &nmreq
, NFS_VER4
, dirfh
.fh_data
, dirfh
.fh_len
); 
2510                         nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTROOTFH
); 
2514                         nfsm_chain_add_32(error
, &nmreq
, NFS_OP_LOOKUPP
); 
2516                         nfsm_chain_add_32(error
, &nmreq
, NFS_OP_LOOKUP
); 
2517                         nfsm_chain_add_name(error
, &nmreq
, 
2518                             fspath
.np_components
[comp
], strlen(fspath
.np_components
[comp
]), nmp
); 
2521                 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETFH
); 
2523                 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
); 
2524                 NFS_CLEAR_ATTRIBUTES(bitmap
); 
2525                 NFS4_DEFAULT_ATTRIBUTES(bitmap
); 
2526                 /* if no namedattr support or component is ".zfs", clear NFS_FATTR_NAMED_ATTR */ 
2527                 if (!NMFLAG(nmp
, NAMEDATTR
) || !strcmp(fspath
.np_components
[comp
], ".zfs")) { 
2528                         NFS_BITMAP_CLR(bitmap
, NFS_FATTR_NAMED_ATTR
); 
2530                 nfsm_chain_add_bitmap(error
, &nmreq
, bitmap
, NFS_ATTR_BITMAP_LEN
); 
2531                 nfsm_chain_build_done(error
, &nmreq
); 
2532                 nfsm_assert(error
, (numops 
== 0), EPROTO
); 
2534                 error 
= nfs_request_async(NULL
, nmp
->nm_mountp
, &nmreq
, NFSPROC4_COMPOUND
, 
2535                     vfs_context_thread(ctx
), vfs_context_ucred(ctx
), &si
, 0, NULL
, &req
); 
2537                         error 
= nfs_request_async_finish(req
, &nmrep
, &xid
, &status
); 
2539                 nfsm_chain_skip_tag(error
, &nmrep
); 
2540                 nfsm_chain_get_32(error
, &nmrep
, numops
); 
2541                 nfsm_chain_op_check(error
, &nmrep
, dirfh
.fh_len 
? NFS_OP_PUTFH 
: NFS_OP_PUTROOTFH
); 
2542                 nfsm_chain_op_check(error
, &nmrep
, isdotdot 
? NFS_OP_LOOKUPP 
: NFS_OP_LOOKUP
); 
2544                 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETFH
); 
2545                 nfsm_chain_get_32(error
, &nmrep
, fh
.fh_len
); 
2546                 if (fh
.fh_len 
> sizeof(fh
.fh_data
)) { 
2550                 nfsm_chain_get_opaque(error
, &nmrep
, fh
.fh_len
, fh
.fh_data
); 
2551                 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
); 
2553                         NFS_CLEAR_ATTRIBUTES(nmp
->nm_fsattr
.nfsa_bitmap
); 
2554                         error 
= nfs4_parsefattr(&nmrep
, &nmp
->nm_fsattr
, &nvattr
, NULL
, NULL
, &nfsls
); 
2556                 nfsm_chain_cleanup(&nmrep
); 
2557                 nfsm_chain_null(&nmreq
); 
2559                         /* LOOKUP succeeded but GETATTR failed?  This could be a referral. */ 
2560                         /* Try the lookup again with a getattr for fs_locations. */ 
2561                         nfs_fs_locations_cleanup(&nfsls
); 
2562                         error 
= nfs4_get_fs_locations(nmp
, NULL
, dirfh
.fh_data
, dirfh
.fh_len
, fspath
.np_components
[comp
], ctx
, &nfsls
); 
2563                         if (!error 
&& (nfsls
.nl_numlocs 
< 1)) { 
2567                         if (++loopcnt 
> MAXSYMLINKS
) { 
2568                                 /* too many symlink/referral redirections */ 
2572                         /* tear down the current connection */ 
2573                         nfs_disconnect(nmp
); 
2574                         /* replace fs locations */ 
2575                         nfs_fs_locations_cleanup(&nmp
->nm_locations
); 
2576                         nmp
->nm_locations 
= nfsls
; 
2577                         bzero(&nfsls
, sizeof(nfsls
)); 
2578                         /* initiate a connection using the new fs locations */ 
2579                         error 
= nfs_mount_connect(nmp
); 
2580                         if (!error 
&& !(nmp
->nm_locations
.nl_current
.nli_flags 
& NLI_VALID
)) { 
2584                         /* add new server's remote path to beginning of our path and continue */ 
2585                         nfsp 
= &nmp
->nm_locations
.nl_locations
[nmp
->nm_locations
.nl_current
.nli_loc
]->nl_path
; 
2586                         bzero(&fspath2
, sizeof(fspath2
)); 
2587                         fspath2
.np_compcount 
= (fspath
.np_compcount 
- comp 
- 1) + nfsp
->np_compcount
; 
2588                         if (fspath2
.np_compcount 
> 0) { 
2589                                 MALLOC(fspath2
.np_components
, char **, fspath2
.np_compcount 
* sizeof(char*), M_TEMP
, M_WAITOK 
| M_ZERO
); 
2590                                 if (!fspath2
.np_components
) { 
2594                                 for (comp2 
= 0; comp2 
< nfsp
->np_compcount
; comp2
++) { 
2595                                         size_t slen 
= strlen(nfsp
->np_components
[comp2
]); 
2596                                         MALLOC(fspath2
.np_components
[comp2
], char *, slen 
+ 1, M_TEMP
, M_WAITOK 
| M_ZERO
); 
2597                                         if (!fspath2
.np_components
[comp2
]) { 
2598                                                 /* clean up fspath2, then error out */ 
2601                                                         FREE(fspath2
.np_components
[comp2
], M_TEMP
); 
2603                                                 FREE(fspath2
.np_components
, M_TEMP
); 
2607                                         strlcpy(fspath2
.np_components
[comp2
], nfsp
->np_components
[comp2
], slen 
+ 1); 
2609                                 if ((fspath
.np_compcount 
- comp 
- 1) > 0) { 
2610                                         bcopy(&fspath
.np_components
[comp 
+ 1], &fspath2
.np_components
[nfsp
->np_compcount
], (fspath
.np_compcount 
- comp 
- 1) * sizeof(char*)); 
2612                                 /* free up unused parts of old path (prior components and component array) */ 
2614                                         FREE(fspath
.np_components
[comp
], M_TEMP
); 
2615                                 } while (comp
-- > 0); 
2616                                 FREE(fspath
.np_components
, M_TEMP
); 
2617                                 /* put new path in place */ 
2620                         /* reset dirfh and component index */ 
2623                         NVATTR_CLEANUP(&nvattr
); 
2624                         if (fspath
.np_compcount 
== 0) { 
2630                 /* if file handle is for a symlink, then update the path with the symlink contents */ 
2631                 if (NFS_BITMAP_ISSET(&nvattr
.nva_bitmap
, NFS_FATTR_TYPE
) && (nvattr
.nva_type 
== VLNK
)) { 
2632                         if (++loopcnt 
> MAXSYMLINKS
) { 
2635                                 error 
= nfs4_mount_update_path_with_symlink(nmp
, &fspath
, comp
, &dirfh
, &depth
, &fh
, ctx
); 
2638                         /* directory file handle is either left the same or reset to root (if link was absolute) */ 
2639                         /* path traversal starts at beginning of the path again */ 
2641                         NVATTR_CLEANUP(&nvattr
); 
2642                         nfs_fs_locations_cleanup(&nfsls
); 
2645                 NVATTR_CLEANUP(&nvattr
); 
2646                 nfs_fs_locations_cleanup(&nfsls
); 
2647                 /* not a symlink... */ 
2648                 if ((nmp
->nm_state 
& NFSSTA_NEEDSECINFO
) && (comp 
== (fspath
.np_compcount 
- 1)) && !isdotdot
) { 
2649                         /* need to get SECINFO for the directory being mounted */ 
2650                         if (dirfh
.fh_len 
== 0) { 
2651                                 NFSREQ_SECINFO_SET(&si
, NULL
, NULL
, 0, isdotdot 
? NULL 
: fspath
.np_components
[comp
], 0); 
2653                                 NFSREQ_SECINFO_SET(&si
, NULL
, dirfh
.fh_data
, dirfh
.fh_len
, isdotdot 
? NULL 
: fspath
.np_components
[comp
], 0); 
2655                         sec
.count 
= NX_MAX_SEC_FLAVORS
; 
2656                         error 
= nfs4_secinfo_rpc(nmp
, &si
, vfs_context_ucred(ctx
), sec
.flavors
, &sec
.count
); 
2657                         /* [sigh] some implementations return "illegal" error for unsupported ops */ 
2658                         if (error 
== NFSERR_OP_ILLEGAL
) { 
2662                         /* set our default security flavor to the first in the list */ 
2664                                 nmp
->nm_auth 
= sec
.flavors
[0]; 
2666                         nmp
->nm_state 
&= ~NFSSTA_NEEDSECINFO
; 
2668                 /* advance directory file handle, component index, & update depth */ 
2671                 if (!isdotdot
) { /* going down the hierarchy */ 
2673                 } else if (--depth 
<= 0) { /* going up the hierarchy */ 
2674                         dirfh
.fh_len 
= 0; /* clear dirfh when we hit root */ 
2679         /* get attrs for mount point root */ 
2680         numops 
= NMFLAG(nmp
, NAMEDATTR
) ? 3 : 2; // PUTFH + GETATTR + OPENATTR 
2681         nfsm_chain_build_alloc_init(error
, &nmreq
, 25 * NFSX_UNSIGNED
); 
2682         nfsm_chain_add_compound_header(error
, &nmreq
, "mount", nmp
->nm_minor_vers
, numops
); 
2684         nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
); 
2685         nfsm_chain_add_fh(error
, &nmreq
, NFS_VER4
, dirfh
.fh_data
, dirfh
.fh_len
); 
2687         nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
); 
2688         NFS_CLEAR_ATTRIBUTES(bitmap
); 
2689         NFS4_DEFAULT_ATTRIBUTES(bitmap
); 
2690         /* if no namedattr support or last component is ".zfs", clear NFS_FATTR_NAMED_ATTR */ 
2691         if (!NMFLAG(nmp
, NAMEDATTR
) || ((fspath
.np_compcount 
> 0) && !strcmp(fspath
.np_components
[fspath
.np_compcount 
- 1], ".zfs"))) { 
2692                 NFS_BITMAP_CLR(bitmap
, NFS_FATTR_NAMED_ATTR
); 
2694         nfsm_chain_add_bitmap(error
, &nmreq
, bitmap
, NFS_ATTR_BITMAP_LEN
); 
2695         if (NMFLAG(nmp
, NAMEDATTR
)) { 
2697                 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_OPENATTR
); 
2698                 nfsm_chain_add_32(error
, &nmreq
, 0); 
2700         nfsm_chain_build_done(error
, &nmreq
); 
2701         nfsm_assert(error
, (numops 
== 0), EPROTO
); 
2703         error 
= nfs_request_async(NULL
, nmp
->nm_mountp
, &nmreq
, NFSPROC4_COMPOUND
, 
2704             vfs_context_thread(ctx
), vfs_context_ucred(ctx
), &si
, 0, NULL
, &req
); 
2706                 error 
= nfs_request_async_finish(req
, &nmrep
, &xid
, &status
); 
2708         nfsm_chain_skip_tag(error
, &nmrep
); 
2709         nfsm_chain_get_32(error
, &nmrep
, numops
); 
2710         nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
); 
2711         nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
); 
2713         NFS_CLEAR_ATTRIBUTES(nmp
->nm_fsattr
.nfsa_bitmap
); 
2714         error 
= nfs4_parsefattr(&nmrep
, &nmp
->nm_fsattr
, &nvattr
, NULL
, NULL
, NULL
); 
2716         if (NMFLAG(nmp
, NAMEDATTR
)) { 
2717                 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_OPENATTR
); 
2718                 if (error 
== ENOENT
) { 
2721                 /* [sigh] some implementations return "illegal" error for unsupported ops */ 
2722                 if (error 
|| !NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_NAMED_ATTR
)) { 
2723                         nmp
->nm_fsattr
.nfsa_flags 
&= ~NFS_FSFLAG_NAMED_ATTR
; 
2725                         nmp
->nm_fsattr
.nfsa_flags 
|= NFS_FSFLAG_NAMED_ATTR
; 
2728                 nmp
->nm_fsattr
.nfsa_flags 
&= ~NFS_FSFLAG_NAMED_ATTR
; 
2730         if (NMFLAG(nmp
, NOACL
)) { /* make sure ACL support is turned off */ 
2731                 nmp
->nm_fsattr
.nfsa_flags 
&= ~NFS_FSFLAG_ACL
; 
2733         if (NMFLAG(nmp
, ACLONLY
) && !(nmp
->nm_fsattr
.nfsa_flags 
& NFS_FSFLAG_ACL
)) { 
2734                 NFS_BITMAP_CLR(nmp
->nm_flags
, NFS_MFLAG_ACLONLY
); 
2736         if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_FH_EXPIRE_TYPE
)) { 
2737                 uint32_t fhtype 
= ((nmp
->nm_fsattr
.nfsa_flags 
& NFS_FSFLAG_FHTYPE_MASK
) >> NFS_FSFLAG_FHTYPE_SHIFT
); 
2738                 if (fhtype 
!= NFS_FH_PERSISTENT
) { 
2739                         printf("nfs: warning: non-persistent file handles! for %s\n", vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
); 
2743         /* make sure it's a directory */ 
2744         if (!NFS_BITMAP_ISSET(&nvattr
.nva_bitmap
, NFS_FATTR_TYPE
) || (nvattr
.nva_type 
!= VDIR
)) { 
2749         /* save the NFS fsid */ 
2750         nmp
->nm_fsid 
= nvattr
.nva_fsid
; 
2752         /* create the root node */ 
2753         error 
= nfs_nget(nmp
->nm_mountp
, NULL
, NULL
, dirfh
.fh_data
, dirfh
.fh_len
, &nvattr
, &xid
, rq
.r_auth
, NG_MARKROOT
, npp
); 
2756         if (nmp
->nm_fsattr
.nfsa_flags 
& NFS_FSFLAG_ACL
) { 
2757                 vfs_setextendedsecurity(nmp
->nm_mountp
); 
2760         /* adjust I/O sizes to server limits */ 
2761         if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXREAD
) && (nmp
->nm_fsattr
.nfsa_maxread 
> 0)) { 
2762                 if (nmp
->nm_fsattr
.nfsa_maxread 
< (uint64_t)nmp
->nm_rsize
) { 
2763                         nmp
->nm_rsize 
= nmp
->nm_fsattr
.nfsa_maxread 
& ~(NFS_FABLKSIZE 
- 1); 
2764                         if (nmp
->nm_rsize 
== 0) { 
2765                                 nmp
->nm_rsize 
= nmp
->nm_fsattr
.nfsa_maxread
; 
2769         if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXWRITE
) && (nmp
->nm_fsattr
.nfsa_maxwrite 
> 0)) { 
2770                 if (nmp
->nm_fsattr
.nfsa_maxwrite 
< (uint64_t)nmp
->nm_wsize
) { 
2771                         nmp
->nm_wsize 
= nmp
->nm_fsattr
.nfsa_maxwrite 
& ~(NFS_FABLKSIZE 
- 1); 
2772                         if (nmp
->nm_wsize 
== 0) { 
2773                                 nmp
->nm_wsize 
= nmp
->nm_fsattr
.nfsa_maxwrite
; 
2778         /* set up lease renew timer */ 
2779         nmp
->nm_renew_timer 
= thread_call_allocate(nfs4_renew_timer
, nmp
); 
2780         interval 
= nmp
->nm_fsattr
.nfsa_lease 
/ 2; 
2784         nfs_interval_timer_start(nmp
->nm_renew_timer
, interval 
* 1000); 
2787         if (fspath
.np_components
) { 
2788                 for (comp 
= 0; comp 
< fspath
.np_compcount
; comp
++) { 
2789                         if (fspath
.np_components
[comp
]) { 
2790                                 FREE(fspath
.np_components
[comp
], M_TEMP
); 
2793                 FREE(fspath
.np_components
, M_TEMP
); 
2795         NVATTR_CLEANUP(&nvattr
); 
2796         nfs_fs_locations_cleanup(&nfsls
); 
2798                 nfs_node_unlock(*npp
); 
2800         nfsm_chain_cleanup(&nmreq
); 
2801         nfsm_chain_cleanup(&nmrep
); 
2804 #endif /* CONFIG_NFS4 */ 
2807  * Thread to handle initial NFS mount connection. 
2810 nfs_mount_connect_thread(void *arg
, __unused wait_result_t wr
) 
2812         struct nfsmount 
*nmp 
= arg
; 
2813         int error 
= 0, savederror 
= 0, slpflag 
= (NMFLAG(nmp
, INTR
) ? PCATCH 
: 0); 
2814         int done 
= 0, timeo
, tries
, maxtries
; 
2816         if (NM_OMFLAG(nmp
, MNTQUICK
)) { 
2824         for (tries 
= 0; tries 
< maxtries
; tries
++) { 
2825                 error 
= nfs_connect(nmp
, 1, timeo
); 
2842                         /* just keep retrying on any of these errors */ 
2846                         /* looks like we got an answer... */ 
2851                 /* save the best error */ 
2852                 if (nfs_connect_error_class(error
) >= nfs_connect_error_class(savederror
)) { 
2860                 /* pause before next attempt */ 
2861                 if ((error 
= nfs_sigintr(nmp
, NULL
, current_thread(), 0))) { 
2864                 error 
= tsleep(nmp
, PSOCK 
| slpflag
, "nfs_mount_connect_retry", 2 * hz
); 
2865                 if (error 
&& (error 
!= EWOULDBLOCK
)) { 
2871         /* update status of mount connect */ 
2872         lck_mtx_lock(&nmp
->nm_lock
); 
2873         if (!nmp
->nm_mounterror
) { 
2874                 nmp
->nm_mounterror 
= error
; 
2876         nmp
->nm_state 
&= ~NFSSTA_MOUNT_THREAD
; 
2877         lck_mtx_unlock(&nmp
->nm_lock
); 
2878         wakeup(&nmp
->nm_nss
); 
2882 nfs_mount_connect(struct nfsmount 
*nmp
) 
2884         int error 
= 0, slpflag
; 
2886         struct timespec ts 
= { .tv_sec 
= 2, .tv_nsec 
= 0 }; 
2889          * Set up the socket.  Perform initial search for a location/server/address to 
2890          * connect to and negotiate any unspecified mount parameters.  This work is 
2891          * done on a kernel thread to satisfy reserved port usage needs. 
2893         slpflag 
= NMFLAG(nmp
, INTR
) ? PCATCH 
: 0; 
2894         lck_mtx_lock(&nmp
->nm_lock
); 
2895         /* set flag that the thread is running */ 
2896         nmp
->nm_state 
|= NFSSTA_MOUNT_THREAD
; 
2897         if (kernel_thread_start(nfs_mount_connect_thread
, nmp
, &thd
) != KERN_SUCCESS
) { 
2898                 nmp
->nm_state 
&= ~NFSSTA_MOUNT_THREAD
; 
2899                 nmp
->nm_mounterror 
= EIO
; 
2900                 printf("nfs mount %s start socket connect thread failed\n", vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
); 
2902                 thread_deallocate(thd
); 
2905         /* wait until mount connect thread is finished/gone */ 
2906         while (nmp
->nm_state 
& NFSSTA_MOUNT_THREAD
) { 
2907                 error 
= msleep(&nmp
->nm_nss
, &nmp
->nm_lock
, slpflag 
| PSOCK
, "nfsconnectthread", &ts
); 
2908                 if ((error 
&& (error 
!= EWOULDBLOCK
)) || ((error 
= nfs_sigintr(nmp
, NULL
, current_thread(), 1)))) { 
2910                         if (!nmp
->nm_mounterror
) { 
2911                                 nmp
->nm_mounterror 
= error
; 
2913                         /* signal the thread that we are aborting */ 
2914                         nmp
->nm_sockflags 
|= NMSOCK_UNMOUNT
; 
2916                                 wakeup(nmp
->nm_nss
); 
2918                         /* and continue waiting on it to finish */ 
2922         lck_mtx_unlock(&nmp
->nm_lock
); 
2924         /* grab mount connect status */ 
2925         error 
= nmp
->nm_mounterror
; 
2930 /* Table of maximum minor version for a given version */ 
2931 uint32_t maxminorverstab
[] = { 
2932         0, /* Version 0 (does not exist) */ 
2933         0, /* Version 1 (does not exist) */ 
2939 #define NFS_MAX_SUPPORTED_VERSION  ((long)(sizeof (maxminorverstab) / sizeof (uint32_t) - 1)) 
2940 #define NFS_MAX_SUPPORTED_MINOR_VERSION(v) ((long)(maxminorverstab[(v)])) 
2942 #define DEFAULT_NFS_MIN_VERS VER2PVER(2, 0) 
2943 #define DEFAULT_NFS_MAX_VERS VER2PVER(3, 0) 
2946  * Common code to mount an NFS file system. 
2955         struct nfsmount 
*nmp
; 
2958         struct vfsstatfs 
*sbp
; 
2960         uint32_t i
, val
, maxio
, iosize
, len
; 
2962         uint32_t *mflags_mask
; 
2964         uint32_t argslength
, attrslength
; 
2965         uid_t set_owner 
= 0; 
2966         struct nfs_location_index firstloc 
= { 
2967                 .nli_flags 
= NLI_VALID
, 
2972         static const struct nfs_etype nfs_default_etypes 
= { 
2973                 .count 
= NFS_MAX_ETYPES
, 
2974                 .selected 
= NFS_MAX_ETYPES
, 
2975                 .etypes 
= { NFS_AES256_CTS_HMAC_SHA1_96
, 
2976                             NFS_AES128_CTS_HMAC_SHA1_96
, 
2977                             NFS_DES3_CBC_SHA1_KD
} 
2980         /* make sure mbuf constants are set up */ 
2981         if (!nfs_mbuf_mhlen
) { 
2985         if (vfs_flags(mp
) & MNT_UPDATE
) { 
2987                 /* update paths, file handles, etc, here        XXX */ 
2991                 /* allocate an NFS mount structure for this mount */ 
2992                 nmp 
= zalloc_flags(nfsmnt_zone
, Z_WAITOK 
| Z_ZERO
); 
2993                 lck_mtx_init(&nmp
->nm_lock
, nfs_mount_grp
, LCK_ATTR_NULL
); 
2994                 TAILQ_INIT(&nmp
->nm_resendq
); 
2995                 TAILQ_INIT(&nmp
->nm_iodq
); 
2996                 TAILQ_INIT(&nmp
->nm_gsscl
); 
2997                 LIST_INIT(&nmp
->nm_monlist
); 
2998                 vfs_setfsprivate(mp
, nmp
); 
3000                 nmp
->nm_mountp 
= mp
; 
3001                 vfs_setauthopaque(mp
); 
3003                  * Disable cache_lookup_path for NFS.  NFS lookup always needs 
3004                  * to be called to check if the directory attribute cache is 
3005                  * valid and possibly purge the directory before calling 
3008                 vfs_setauthcache_ttl(mp
, 0); 
3010                 nfs_nhinit_finish(); 
3012                 nmp
->nm_args 
= xdrbuf
; 
3014                 /* set up defaults */ 
3017                 nmp
->nm_min_vers 
= DEFAULT_NFS_MIN_VERS
; 
3018                 nmp
->nm_max_vers 
= DEFAULT_NFS_MAX_VERS
; 
3019                 nmp
->nm_timeo 
= NFS_TIMEO
; 
3020                 nmp
->nm_retry 
= NFS_RETRANS
; 
3022                 nmp
->nm_sofamily 
= 0; 
3023                 nmp
->nm_nfsport 
= 0; 
3024                 nmp
->nm_wsize 
= NFS_WSIZE
; 
3025                 nmp
->nm_rsize 
= NFS_RSIZE
; 
3026                 nmp
->nm_readdirsize 
= NFS_READDIRSIZE
; 
3027                 nmp
->nm_numgrps 
= NFS_MAXGRPS
; 
3028                 nmp
->nm_readahead 
= NFS_DEFRAHEAD
; 
3029                 nmp
->nm_tprintf_delay 
= nfs_tprintf_delay
; 
3030                 if (nmp
->nm_tprintf_delay 
< 0) { 
3031                         nmp
->nm_tprintf_delay 
= 0; 
3033                 nmp
->nm_tprintf_initial_delay 
= nfs_tprintf_initial_delay
; 
3034                 if (nmp
->nm_tprintf_initial_delay 
< 0) { 
3035                         nmp
->nm_tprintf_initial_delay 
= 0; 
3037                 nmp
->nm_acregmin 
= NFS_MINATTRTIMO
; 
3038                 nmp
->nm_acregmax 
= NFS_MAXATTRTIMO
; 
3039                 nmp
->nm_acdirmin 
= NFS_MINDIRATTRTIMO
; 
3040                 nmp
->nm_acdirmax 
= NFS_MAXDIRATTRTIMO
; 
3041                 nmp
->nm_etype 
= nfs_default_etypes
; 
3042                 nmp
->nm_auth 
= RPCAUTH_SYS
; 
3043                 nmp
->nm_iodlink
.tqe_next 
= NFSNOLIST
; 
3044                 nmp
->nm_deadtimeout 
= 0; 
3045                 nmp
->nm_curdeadtimeout 
= 0; 
3046                 NFS_BITMAP_SET(nmp
->nm_flags
, NFS_MFLAG_RDIRPLUS
); /* enable RDIRPLUS by default. It will be reverted later in case NFSv2 is used */ 
3047                 NFS_BITMAP_SET(nmp
->nm_flags
, NFS_MFLAG_NOACL
); 
3048                 nmp
->nm_realm 
= NULL
; 
3049                 nmp
->nm_principal 
= NULL
; 
3050                 nmp
->nm_sprinc 
= NULL
; 
3053         mattrs 
= nmp
->nm_mattrs
; 
3054         mflags 
= nmp
->nm_mflags
; 
3055         mflags_mask 
= nmp
->nm_mflags_mask
; 
3057         /* set up NFS mount with args */ 
3058         xb_init_buffer(&xb
, xdrbuf
, 2 * XDRWORD
); 
3059         xb_get_32(error
, &xb
, val
); /* version */ 
3060         xb_get_32(error
, &xb
, argslength
); /* args length */ 
3062         xb_init_buffer(&xb
, xdrbuf
, argslength
);        /* restart parsing with actual buffer length */ 
3063         xb_get_32(error
, &xb
, val
); /* version */ 
3064         xb_get_32(error
, &xb
, argslength
); /* args length */ 
3065         xb_get_32(error
, &xb
, val
); /* XDR args version */ 
3066         if (val 
!= NFS_XDRARGS_VERSION_0 
|| argslength 
< ((4 + NFS_MATTR_BITMAP_LEN 
+ 1) * XDRWORD
)) { 
3069         len 
= NFS_MATTR_BITMAP_LEN
; 
3070         xb_get_bitmap(error
, &xb
, mattrs
, len
); /* mount attribute bitmap */ 
3072         xb_get_32(error
, &xb
, attrslength
); /* attrs length */ 
3073         if (!error 
&& (attrslength 
> (argslength 
- ((4 + NFS_MATTR_BITMAP_LEN 
+ 1) * XDRWORD
)))) { 
3077         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_FLAGS
)) { 
3078                 len 
= NFS_MFLAG_BITMAP_LEN
; 
3079                 xb_get_bitmap(error
, &xb
, mflags_mask
, len
); /* mount flag mask */ 
3080                 len 
= NFS_MFLAG_BITMAP_LEN
; 
3081                 xb_get_bitmap(error
, &xb
, mflags
, len
); /* mount flag values */ 
3083                         /* clear all mask bits and OR in all the ones that are set */ 
3084                         nmp
->nm_flags
[0] &= ~mflags_mask
[0]; 
3085                         nmp
->nm_flags
[0] |= (mflags_mask
[0] & mflags
[0]); 
3088         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_VERSION
)) { 
3089                 /* Can't specify a single version and a range */ 
3090                 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_VERSION_RANGE
)) { 
3093                 xb_get_32(error
, &xb
, nmp
->nm_vers
); 
3094                 if (nmp
->nm_vers 
> NFS_MAX_SUPPORTED_VERSION 
|| 
3095                     nmp
->nm_vers 
< NFS_VER2
) { 
3098                 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_MINOR_VERSION
)) { 
3099                         xb_get_32(error
, &xb
, nmp
->nm_minor_vers
); 
3101                         nmp
->nm_minor_vers 
= maxminorverstab
[nmp
->nm_vers
]; 
3103                 if (nmp
->nm_minor_vers 
> maxminorverstab
[nmp
->nm_vers
]) { 
3106                 nmp
->nm_max_vers 
= nmp
->nm_min_vers 
= 
3107                     VER2PVER(nmp
->nm_vers
, nmp
->nm_minor_vers
); 
3109         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_MINOR_VERSION
)) { 
3110                 /* should have also gotten NFS version (and already gotten minor version) */ 
3111                 if (!NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_VERSION
)) { 
3115         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_VERSION_RANGE
)) { 
3116                 xb_get_32(error
, &xb
, nmp
->nm_min_vers
); 
3117                 xb_get_32(error
, &xb
, nmp
->nm_max_vers
); 
3118                 if ((nmp
->nm_min_vers 
> nmp
->nm_max_vers
) || 
3119                     (PVER2MAJOR(nmp
->nm_max_vers
) > NFS_MAX_SUPPORTED_VERSION
) || 
3120                     (PVER2MINOR(nmp
->nm_min_vers
) > maxminorverstab
[PVER2MAJOR(nmp
->nm_min_vers
)]) || 
3121                     (PVER2MINOR(nmp
->nm_max_vers
) > maxminorverstab
[PVER2MAJOR(nmp
->nm_max_vers
)])) { 
3125         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READ_SIZE
)) { 
3126                 xb_get_32(error
, &xb
, nmp
->nm_rsize
); 
3128         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_WRITE_SIZE
)) { 
3129                 xb_get_32(error
, &xb
, nmp
->nm_wsize
); 
3131         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READDIR_SIZE
)) { 
3132                 xb_get_32(error
, &xb
, nmp
->nm_readdirsize
); 
3134         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READAHEAD
)) { 
3135                 xb_get_32(error
, &xb
, nmp
->nm_readahead
); 
3137         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MIN
)) { 
3138                 xb_get_32(error
, &xb
, nmp
->nm_acregmin
); 
3139                 xb_skip(error
, &xb
, XDRWORD
); 
3141         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MAX
)) { 
3142                 xb_get_32(error
, &xb
, nmp
->nm_acregmax
); 
3143                 xb_skip(error
, &xb
, XDRWORD
); 
3145         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MIN
)) { 
3146                 xb_get_32(error
, &xb
, nmp
->nm_acdirmin
); 
3147                 xb_skip(error
, &xb
, XDRWORD
); 
3149         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MAX
)) { 
3150                 xb_get_32(error
, &xb
, nmp
->nm_acdirmax
); 
3151                 xb_skip(error
, &xb
, XDRWORD
); 
3154         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_LOCK_MODE
)) { 
3155                 xb_get_32(error
, &xb
, val
); 
3157                 case NFS_LOCK_MODE_DISABLED
: 
3158                 case NFS_LOCK_MODE_LOCAL
: 
3160                         if (nmp
->nm_vers 
>= NFS_VER4
) { 
3161                                 /* disabled/local lock mode only allowed on v2/v3 */ 
3167                 case NFS_LOCK_MODE_ENABLED
: 
3168                         nmp
->nm_lockmode 
= val
; 
3175         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SECURITY
)) { 
3177                 xb_get_32(error
, &xb
, seccnt
); 
3178                 if (!error 
&& ((seccnt 
< 1) || (seccnt 
> NX_MAX_SEC_FLAVORS
))) { 
3182                 nmp
->nm_sec
.count 
= seccnt
; 
3183                 for (i 
= 0; i 
< seccnt
; i
++) { 
3184                         xb_get_32(error
, &xb
, nmp
->nm_sec
.flavors
[i
]); 
3185                         /* Check for valid security flavor */ 
3186                         switch (nmp
->nm_sec
.flavors
[i
]) { 
3197                 /* start with the first flavor */ 
3198                 nmp
->nm_auth 
= nmp
->nm_sec
.flavors
[0]; 
3200         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_KERB_ETYPE
)) { 
3202                 xb_get_32(error
, &xb
, etypecnt
); 
3203                 if (!error 
&& ((etypecnt 
< 1) || (etypecnt 
> NFS_MAX_ETYPES
))) { 
3207                 nmp
->nm_etype
.count 
= etypecnt
; 
3208                 xb_get_32(error
, &xb
, nmp
->nm_etype
.selected
); 
3211                         nmp
->nm_etype
.selected 
= etypecnt
; /* Nothing is selected yet, so set selected to count */ 
3212                         for (i 
= 0; i 
< etypecnt
; i
++) { 
3213                                 xb_get_32(error
, &xb
, nmp
->nm_etype
.etypes
[i
]); 
3214                                 /* Check for valid encryption type */ 
3215                                 switch (nmp
->nm_etype
.etypes
[i
]) { 
3216                                 case NFS_DES3_CBC_SHA1_KD
: 
3217                                 case NFS_AES128_CTS_HMAC_SHA1_96
: 
3218                                 case NFS_AES256_CTS_HMAC_SHA1_96
: 
3226         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MAX_GROUP_LIST
)) { 
3227                 xb_get_32(error
, &xb
, nmp
->nm_numgrps
); 
3229         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SOCKET_TYPE
)) { 
3233                 xb_get_32(error
, &xb
, val
); 
3234                 if (!error 
&& ((val 
< 3) || (val 
> sizeof(sotype
)))) { 
3238                 error 
= xb_get_bytes(&xb
, sotype
, val
, 0); 
3241                 if (!strcmp(sotype
, "tcp")) { 
3242                         nmp
->nm_sotype 
= SOCK_STREAM
; 
3243                 } else if (!strcmp(sotype
, "udp")) { 
3244                         nmp
->nm_sotype 
= SOCK_DGRAM
; 
3245                 } else if (!strcmp(sotype
, "tcp4")) { 
3246                         nmp
->nm_sotype 
= SOCK_STREAM
; 
3247                         nmp
->nm_sofamily 
= AF_INET
; 
3248                 } else if (!strcmp(sotype
, "udp4")) { 
3249                         nmp
->nm_sotype 
= SOCK_DGRAM
; 
3250                         nmp
->nm_sofamily 
= AF_INET
; 
3251                 } else if (!strcmp(sotype
, "tcp6")) { 
3252                         nmp
->nm_sotype 
= SOCK_STREAM
; 
3253                         nmp
->nm_sofamily 
= AF_INET6
; 
3254                 } else if (!strcmp(sotype
, "udp6")) { 
3255                         nmp
->nm_sotype 
= SOCK_DGRAM
; 
3256                         nmp
->nm_sofamily 
= AF_INET6
; 
3257                 } else if (!strcmp(sotype
, "inet4")) { 
3258                         nmp
->nm_sofamily 
= AF_INET
; 
3259                 } else if (!strcmp(sotype
, "inet6")) { 
3260                         nmp
->nm_sofamily 
= AF_INET6
; 
3261                 } else if (!strcmp(sotype
, "inet")) { 
3262                         nmp
->nm_sofamily 
= 0; /* ok */ 
3263                 } else if (!strcmp(sotype
, "ticotsord")) { 
3264                         nmp
->nm_sofamily 
= AF_LOCAL
; 
3265                         nmp
->nm_sotype 
= SOCK_STREAM
; 
3266                 } else if (!strcmp(sotype
, "ticlts")) { 
3267                         nmp
->nm_sofamily 
= AF_LOCAL
; 
3268                         nmp
->nm_sotype 
= SOCK_DGRAM
; 
3273                 if (!error 
&& (nmp
->nm_vers 
>= NFS_VER4
) && nmp
->nm_sotype 
&& 
3274                     (nmp
->nm_sotype 
!= SOCK_STREAM
)) { 
3275                         error 
= EINVAL
;         /* NFSv4 is only allowed over TCP. */ 
3279                         NFS_VFS_DBG("EINVAL sotype = \"%s\"\n", sotype
); 
3283         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_PORT
)) { 
3284                 xb_get_32(error
, &xb
, val
); 
3285                 if (NFS_PORT_INVALID(val
)) { 
3289                 nmp
->nm_nfsport 
= (in_port_t
)val
; 
3291         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MOUNT_PORT
)) { 
3292                 xb_get_32(error
, &xb
, val
); 
3293                 if (NFS_PORT_INVALID(val
)) { 
3297                 nmp
->nm_mountport 
= (in_port_t
)val
; 
3299         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_REQUEST_TIMEOUT
)) { 
3300                 /* convert from time to 0.1s units */ 
3301                 xb_get_32(error
, &xb
, nmp
->nm_timeo
); 
3302                 xb_get_32(error
, &xb
, val
); 
3304                 if (val 
>= 1000000000) { 
3308                 nmp
->nm_timeo 
*= 10; 
3309                 nmp
->nm_timeo 
+= (val 
+ 100000000 - 1) / 100000000; 
3310                 /* now convert to ticks */ 
3311                 nmp
->nm_timeo 
= (nmp
->nm_timeo 
* NFS_HZ 
+ 5) / 10; 
3313         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SOFT_RETRY_COUNT
)) { 
3314                 xb_get_32(error
, &xb
, val
); 
3315                 if (!error 
&& (val 
> 1)) { 
3316                         nmp
->nm_retry 
= val
; 
3319         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_DEAD_TIMEOUT
)) { 
3320                 xb_get_32(error
, &xb
, nmp
->nm_deadtimeout
); 
3321                 xb_skip(error
, &xb
, XDRWORD
); 
3323         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_FH
)) { 
3325                 nmp
->nm_fh 
= zalloc(nfs_fhandle_zone
); 
3326                 xb_get_32(error
, &xb
, nmp
->nm_fh
->fh_len
); 
3328                 if ((size_t)nmp
->nm_fh
->fh_len 
> sizeof(nmp
->nm_fh
->fh_data
)) { 
3331                         error 
= xb_get_bytes(&xb
, (char*)&nmp
->nm_fh
->fh_data
[0], nmp
->nm_fh
->fh_len
, 0); 
3335         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_FS_LOCATIONS
)) { 
3336                 uint32_t loc
, serv
, addr
, comp
; 
3337                 struct nfs_fs_location 
*fsl
; 
3338                 struct nfs_fs_server 
*fss
; 
3339                 struct nfs_fs_path 
*fsp
; 
3341                 xb_get_32(error
, &xb
, nmp
->nm_locations
.nl_numlocs
); /* fs location count */ 
3342                 /* sanity check location count */ 
3343                 if (!error 
&& ((nmp
->nm_locations
.nl_numlocs 
< 1) || (nmp
->nm_locations
.nl_numlocs 
> 256))) { 
3344                         NFS_VFS_DBG("Invalid number of fs_locations: %d", nmp
->nm_locations
.nl_numlocs
); 
3348                 MALLOC(nmp
->nm_locations
.nl_locations
, struct nfs_fs_location 
**, nmp
->nm_locations
.nl_numlocs 
* sizeof(struct nfs_fs_location
*), M_TEMP
, M_WAITOK 
| M_ZERO
); 
3349                 if (!nmp
->nm_locations
.nl_locations
) { 
3352                 for (loc 
= 0; loc 
< nmp
->nm_locations
.nl_numlocs
; loc
++) { 
3354                         MALLOC(fsl
, struct nfs_fs_location 
*, sizeof(struct nfs_fs_location
), M_TEMP
, M_WAITOK 
| M_ZERO
); 
3358                         nmp
->nm_locations
.nl_locations
[loc
] = fsl
; 
3359                         xb_get_32(error
, &xb
, fsl
->nl_servcount
); /* server count */ 
3360                         /* sanity check server count */ 
3361                         if (!error 
&& ((fsl
->nl_servcount 
< 1) || (fsl
->nl_servcount 
> 256))) { 
3362                                 NFS_VFS_DBG("Invalid server count %d", fsl
->nl_servcount
); 
3366                         MALLOC(fsl
->nl_servers
, struct nfs_fs_server 
**, fsl
->nl_servcount 
* sizeof(struct nfs_fs_server
*), M_TEMP
, M_WAITOK 
| M_ZERO
); 
3367                         if (!fsl
->nl_servers
) { 
3369                                 NFS_VFS_DBG("Server count = %d, error = %d\n", fsl
->nl_servcount
, error
); 
3371                         for (serv 
= 0; serv 
< fsl
->nl_servcount
; serv
++) { 
3373                                 MALLOC(fss
, struct nfs_fs_server 
*, sizeof(struct nfs_fs_server
), M_TEMP
, M_WAITOK 
| M_ZERO
); 
3377                                 fsl
->nl_servers
[serv
] = fss
; 
3378                                 xb_get_32(error
, &xb
, val
); /* server name length */ 
3379                                 /* sanity check server name length */ 
3380                                 if (!error 
&& (val 
> MAXPATHLEN
)) { 
3381                                         NFS_VFS_DBG("Invalid server name length %d", val
); 
3385                                 MALLOC(fss
->ns_name
, char *, val 
+ 1, M_TEMP
, M_WAITOK 
| M_ZERO
); 
3386                                 if (!fss
->ns_name
) { 
3390                                 error 
= xb_get_bytes(&xb
, fss
->ns_name
, val
, 0); /* server name */ 
3391                                 xb_get_32(error
, &xb
, fss
->ns_addrcount
); /* address count */ 
3392                                 /* sanity check address count (OK to be zero) */ 
3393                                 if (!error 
&& (fss
->ns_addrcount 
> 256)) { 
3394                                         NFS_VFS_DBG("Invalid address count %d", fss
->ns_addrcount
); 
3398                                 if (fss
->ns_addrcount 
> 0) { 
3399                                         MALLOC(fss
->ns_addresses
, char **, fss
->ns_addrcount 
* sizeof(char *), M_TEMP
, M_WAITOK 
| M_ZERO
); 
3400                                         if (!fss
->ns_addresses
) { 
3403                                         for (addr 
= 0; addr 
< fss
->ns_addrcount
; addr
++) { 
3404                                                 xb_get_32(error
, &xb
, val
); /* address length */ 
3405                                                 /* sanity check address length */ 
3406                                                 if (!error 
&& val 
> 128) { 
3407                                                         NFS_VFS_DBG("Invalid address length %d", val
); 
3411                                                 MALLOC(fss
->ns_addresses
[addr
], char *, val 
+ 1, M_TEMP
, M_WAITOK 
| M_ZERO
); 
3412                                                 if (!fss
->ns_addresses
[addr
]) { 
3416                                                 error 
= xb_get_bytes(&xb
, fss
->ns_addresses
[addr
], val
, 0); /* address */ 
3419                                 xb_get_32(error
, &xb
, val
); /* server info length */ 
3420                                 xb_skip(error
, &xb
, val
); /* skip server info */ 
3423                         fsp 
= &fsl
->nl_path
; 
3424                         xb_get_32(error
, &xb
, fsp
->np_compcount
); /* component count */ 
3425                         /* sanity check component count */ 
3426                         if (!error 
&& (fsp
->np_compcount 
> MAXPATHLEN
)) { 
3427                                 NFS_VFS_DBG("Invalid component count %d", fsp
->np_compcount
); 
3431                         if (fsp
->np_compcount
) { 
3432                                 MALLOC(fsp
->np_components
, char **, fsp
->np_compcount 
* sizeof(char*), M_TEMP
, M_WAITOK 
| M_ZERO
); 
3433                                 if (!fsp
->np_components
) { 
3437                         for (comp 
= 0; comp 
< fsp
->np_compcount
; comp
++) { 
3438                                 xb_get_32(error
, &xb
, val
); /* component length */ 
3439                                 /* sanity check component length */ 
3440                                 if (!error 
&& (val 
== 0)) { 
3442                                          * Apparently some people think a path with zero components should 
3443                                          * be encoded with one zero-length component.  So, just ignore any 
3444                                          * zero length components. 
3447                                         fsp
->np_compcount
--; 
3448                                         if (fsp
->np_compcount 
== 0) { 
3449                                                 FREE(fsp
->np_components
, M_TEMP
); 
3450                                                 fsp
->np_components 
= NULL
; 
3454                                 if (!error 
&& ((val 
< 1) || (val 
> MAXPATHLEN
))) { 
3455                                         NFS_VFS_DBG("Invalid component path length %d", val
); 
3459                                 MALLOC(fsp
->np_components
[comp
], char *, val 
+ 1, M_TEMP
, M_WAITOK 
| M_ZERO
); 
3460                                 if (!fsp
->np_components
[comp
]) { 
3464                                 error 
= xb_get_bytes(&xb
, fsp
->np_components
[comp
], val
, 0); /* component */ 
3466                         xb_get_32(error
, &xb
, val
); /* fs location info length */ 
3467                         NFS_VFS_DBG("Skipping fs location info bytes %d", val
); 
3468                         xb_skip(error
, &xb
, xdr_rndup(val
)); /* skip fs location info */ 
3471         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MNTFLAGS
)) { 
3472                 xb_skip(error
, &xb
, XDRWORD
); 
3474         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MNTFROM
)) { 
3475                 xb_get_32(error
, &xb
, len
); 
3478                 if (val 
>= sizeof(vfs_statfs(mp
)->f_mntfromname
)) { 
3479                         val 
= sizeof(vfs_statfs(mp
)->f_mntfromname
) - 1; 
3481                 error 
= xb_get_bytes(&xb
, vfs_statfs(mp
)->f_mntfromname
, val
, 0); 
3482                 if ((len 
- val
) > 0) { 
3483                         xb_skip(error
, &xb
, len 
- val
); 
3486                 vfs_statfs(mp
)->f_mntfromname
[val
] = '\0'; 
3490         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_REALM
)) { 
3491                 xb_get_32(error
, &xb
, len
); 
3492                 if (!error 
&& ((len 
< 1) || (len 
> MAXPATHLEN
))) { 
3496                 /* allocate an extra byte for a leading '@' if its not already prepended to the realm */ 
3497                 MALLOC(nmp
->nm_realm
, char *, len 
+ 2, M_TEMP
, M_WAITOK 
| M_ZERO
); 
3498                 if (!nmp
->nm_realm
) { 
3502                 error 
= xb_get_bytes(&xb
, nmp
->nm_realm
, len
, 0); 
3503                 if (error 
== 0 && *nmp
->nm_realm 
!= '@') { 
3504                         bcopy(nmp
->nm_realm
, &nmp
->nm_realm
[1], len
); 
3505                         nmp
->nm_realm
[0] = '@'; 
3510         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_PRINCIPAL
)) { 
3511                 xb_get_32(error
, &xb
, len
); 
3512                 if (!error 
&& ((len 
< 1) || (len 
> MAXPATHLEN
))) { 
3516                 MALLOC(nmp
->nm_principal
, char *, len 
+ 1, M_TEMP
, M_WAITOK 
| M_ZERO
); 
3517                 if (!nmp
->nm_principal
) { 
3521                 error 
= xb_get_bytes(&xb
, nmp
->nm_principal
, len
, 0); 
3525         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SVCPRINCIPAL
)) { 
3526                 xb_get_32(error
, &xb
, len
); 
3527                 if (!error 
&& ((len 
< 1) || (len 
> MAXPATHLEN
))) { 
3531                 MALLOC(nmp
->nm_sprinc
, char *, len 
+ 1, M_TEMP
, M_WAITOK 
| M_ZERO
); 
3532                 if (!nmp
->nm_sprinc
) { 
3536                 error 
= xb_get_bytes(&xb
, nmp
->nm_sprinc
, len
, 0); 
3540         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_LOCAL_NFS_PORT
)) { 
3541                 if (nmp
->nm_nfsport
) { 
3543                         NFS_VFS_DBG("Can't have ports specified over incompatible socket families"); 
3546                 xb_get_32(error
, &xb
, len
); 
3547                 if (!error 
&& ((len 
< 1) || (len 
> sizeof(((struct sockaddr_un 
*)0)->sun_path
)))) { 
3551                 MALLOC(nmp
->nm_nfs_localport
, char *, len 
+ 1, M_TEMP
, M_WAITOK 
| M_ZERO
); 
3552                 if (!nmp
->nm_nfs_localport
) { 
3556                 error 
= xb_get_bytes(&xb
, nmp
->nm_nfs_localport
, len
, 0); 
3557                 nmp
->nm_sofamily 
= AF_LOCAL
; 
3558                 nmp
->nm_nfsport 
= 1; /* We use the now deprecated tpcmux port to indcate that we have an AF_LOCAL port */ 
3559                 NFS_VFS_DBG("Setting nfs local port %s (%d)\n", nmp
->nm_nfs_localport
, nmp
->nm_nfsport
); 
3561         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_LOCAL_MOUNT_PORT
)) { 
3562                 if (nmp
->nm_mountport
) { 
3564                         NFS_VFS_DBG("Can't have ports specified over mulitple socket families"); 
3567                 xb_get_32(error
, &xb
, len
); 
3568                 if (!error 
&& ((len 
< 1) || (len 
> sizeof(((struct sockaddr_un 
*)0)->sun_path
)))) { 
3572                 MALLOC(nmp
->nm_mount_localport
, char *, len 
+ 1, M_TEMP
, M_WAITOK 
| M_ZERO
); 
3573                 if (!nmp
->nm_mount_localport
) { 
3577                 error 
= xb_get_bytes(&xb
, nmp
->nm_mount_localport
, len
, 0); 
3578                 nmp
->nm_sofamily 
= AF_LOCAL
; 
3579                 nmp
->nm_mountport 
= 1; /* We use the now deprecated tpcmux port to indcate that we have an AF_LOCAL port */ 
3580                 NFS_VFS_DBG("Setting mount local port %s (%d)\n", nmp
->nm_mount_localport
, nmp
->nm_mountport
); 
3582         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SET_MOUNT_OWNER
)) { 
3583                 xb_get_32(error
, &xb
, set_owner
); 
3585                 error 
= vfs_context_suser(ctx
); 
3587                  * root can set owner to whatever, user can set owner to self 
3589                 if ((error
) && (set_owner 
== kauth_cred_getuid(vfs_context_ucred(ctx
)))) { 
3590                         /* ok for non-root can set owner to self */ 
3597          * Sanity check/finalize settings. 
3600         if (nmp
->nm_timeo 
< NFS_MINTIMEO
) { 
3601                 nmp
->nm_timeo 
= NFS_MINTIMEO
; 
3602         } else if (nmp
->nm_timeo 
> NFS_MAXTIMEO
) { 
3603                 nmp
->nm_timeo 
= NFS_MAXTIMEO
; 
3605         if (nmp
->nm_retry 
> NFS_MAXREXMIT
) { 
3606                 nmp
->nm_retry 
= NFS_MAXREXMIT
; 
3609         if (nmp
->nm_numgrps 
> NFS_MAXGRPS
) { 
3610                 nmp
->nm_numgrps 
= NFS_MAXGRPS
; 
3612         if (nmp
->nm_readahead 
> NFS_MAXRAHEAD
) { 
3613                 nmp
->nm_readahead 
= NFS_MAXRAHEAD
; 
3615         if (nmp
->nm_acregmin 
> nmp
->nm_acregmax
) { 
3616                 nmp
->nm_acregmin 
= nmp
->nm_acregmax
; 
3618         if (nmp
->nm_acdirmin 
> nmp
->nm_acdirmax
) { 
3619                 nmp
->nm_acdirmin 
= nmp
->nm_acdirmax
; 
3622         /* need at least one fs location */ 
3623         if (nmp
->nm_locations
.nl_numlocs 
< 1) { 
3628         if (!NM_OMATTR_GIVEN(nmp
, MNTFROM
)) { 
3629                 /* init mount's mntfromname to first location */ 
3630                 nfs_location_mntfromname(&nmp
->nm_locations
, firstloc
, 
3631                     vfs_statfs(mp
)->f_mntfromname
, 
3632                     sizeof(vfs_statfs(mp
)->f_mntfromname
), 0); 
3635         /* Need to save the mounting credential for v4. */ 
3636         nmp
->nm_mcred 
= vfs_context_ucred(ctx
); 
3637         if (IS_VALID_CRED(nmp
->nm_mcred
)) { 
3638                 kauth_cred_ref(nmp
->nm_mcred
); 
3642          * If a reserved port is required, check for that privilege. 
3643          * (Note that mirror mounts are exempt because the privilege was 
3644          * already checked for the original mount.) 
3646         if (NMFLAG(nmp
, RESVPORT
) && !vfs_iskernelmount(mp
)) { 
3647                 error 
= priv_check_cred(nmp
->nm_mcred
, PRIV_NETINET_RESERVEDPORT
, 0); 
3651         /* set up the version-specific function tables */ 
3652         if (nmp
->nm_vers 
< NFS_VER4
) { 
3653                 nmp
->nm_funcs 
= &nfs3_funcs
; 
3656                 nmp
->nm_funcs 
= &nfs4_funcs
; 
3658                 /* don't go any further if we don't support NFS4 */ 
3659                 nmp
->nm_funcs 
= NULL
; 
3665         /* do mount's initial socket connection */ 
3666         error 
= nfs_mount_connect(nmp
); 
3669         /* sanity check settings now that version/connection is set */ 
3670         if (nmp
->nm_vers 
== NFS_VER2
) {         /* ignore RDIRPLUS on NFSv2 */ 
3671                 NFS_BITMAP_CLR(nmp
->nm_flags
, NFS_MFLAG_RDIRPLUS
); 
3674         if (nmp
->nm_vers 
>= NFS_VER4
) { 
3675                 if (NFS_BITMAP_ISSET(nmp
->nm_flags
, NFS_MFLAG_ACLONLY
)) { /* aclonly trumps noacl */ 
3676                         NFS_BITMAP_CLR(nmp
->nm_flags
, NFS_MFLAG_NOACL
); 
3678                 NFS_BITMAP_CLR(nmp
->nm_flags
, NFS_MFLAG_CALLUMNT
); 
3679                 if (nmp
->nm_lockmode 
!= NFS_LOCK_MODE_ENABLED
) { 
3680                         error 
= EINVAL
; /* disabled/local lock mode only allowed on v2/v3 */ 
3684         /* ignore these if not v4 */ 
3685         NFS_BITMAP_CLR(nmp
->nm_flags
, NFS_MFLAG_NOCALLBACK
); 
3686         NFS_BITMAP_CLR(nmp
->nm_flags
, NFS_MFLAG_NAMEDATTR
); 
3687         NFS_BITMAP_CLR(nmp
->nm_flags
, NFS_MFLAG_NOACL
); 
3688         NFS_BITMAP_CLR(nmp
->nm_flags
, NFS_MFLAG_ACLONLY
); 
3694         if (nmp
->nm_sotype 
== SOCK_DGRAM
) { 
3695                 /* I/O size defaults for UDP are different */ 
3696                 if (!NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READ_SIZE
)) { 
3697                         nmp
->nm_rsize 
= NFS_DGRAM_RSIZE
; 
3699                 if (!NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_WRITE_SIZE
)) { 
3700                         nmp
->nm_wsize 
= NFS_DGRAM_WSIZE
; 
3704         /* round down I/O sizes to multiple of NFS_FABLKSIZE */ 
3705         nmp
->nm_rsize 
&= ~(NFS_FABLKSIZE 
- 1); 
3706         if (nmp
->nm_rsize 
<= 0) { 
3707                 nmp
->nm_rsize 
= NFS_FABLKSIZE
; 
3709         nmp
->nm_wsize 
&= ~(NFS_FABLKSIZE 
- 1); 
3710         if (nmp
->nm_wsize 
<= 0) { 
3711                 nmp
->nm_wsize 
= NFS_FABLKSIZE
; 
3714         /* and limit I/O sizes to maximum allowed */ 
3715         maxio 
= (nmp
->nm_vers 
== NFS_VER2
) ? NFS_V2MAXDATA 
: 
3716             (nmp
->nm_sotype 
== SOCK_DGRAM
) ? NFS_MAXDGRAMDATA 
: NFS_MAXDATA
; 
3717         if (maxio 
> NFS_MAXBSIZE
) { 
3718                 maxio 
= NFS_MAXBSIZE
; 
3720         if (nmp
->nm_rsize 
> maxio
) { 
3721                 nmp
->nm_rsize 
= maxio
; 
3723         if (nmp
->nm_wsize 
> maxio
) { 
3724                 nmp
->nm_wsize 
= maxio
; 
3727         if (nmp
->nm_readdirsize 
> maxio
) { 
3728                 nmp
->nm_readdirsize 
= maxio
; 
3730         if (nmp
->nm_readdirsize 
> nmp
->nm_rsize
) { 
3731                 nmp
->nm_readdirsize 
= nmp
->nm_rsize
; 
3734         /* Set up the sockets and related info */ 
3735         if (nmp
->nm_sotype 
== SOCK_DGRAM
) { 
3736                 TAILQ_INIT(&nmp
->nm_cwndq
); 
3739         if (nmp
->nm_saddr
->sa_family 
== AF_LOCAL
) { 
3740                 struct sockaddr_un 
*un 
= (struct sockaddr_un 
*)nmp
->nm_saddr
; 
3742                 int n 
= snprintf(vfs_statfs(mp
)->f_mntfromname
, sizeof(vfs_statfs(mp
)->f_mntfromname
), "<%s>:", un
->sun_path
); 
3744                 if (n 
> 0 && (size_t)n 
< sizeof(vfs_statfs(mp
)->f_mntfromname
)) { 
3745                         size 
= sizeof(vfs_statfs(mp
)->f_mntfromname
) - n
; 
3746                         nfs_location_mntfromname(&nmp
->nm_locations
, firstloc
, 
3747                             &vfs_statfs(mp
)->f_mntfromname
[n
], size
, 1); 
3753          * Get the root node/attributes from the NFS server and 
3754          * do any basic, version-specific setup. 
3756         error 
= nmp
->nm_funcs
->nf_mount(nmp
, ctx
, &np
); 
3760          * A reference count is needed on the node representing the 
3761          * remote root.  If this object is not persistent, then backward 
3762          * traversals of the mount point (i.e. "..") will not work if 
3763          * the node gets flushed out of the cache. 
3769         /* get usecount and drop iocount */ 
3770         error 
= vnode_ref(*vpp
); 
3773                 vnode_recycle(*vpp
); 
3778          * Do statfs to ensure static info gets set to reasonable values. 
3780         if ((error 
= nmp
->nm_funcs
->nf_update_statfs(nmp
, ctx
))) { 
3781                 int error2 
= vnode_getwithref(*vpp
); 
3786                 vnode_recycle(*vpp
); 
3789         sbp 
= vfs_statfs(mp
); 
3790         sbp
->f_bsize 
= nmp
->nm_fsattr
.nfsa_bsize
; 
3791         sbp
->f_blocks 
= nmp
->nm_fsattr
.nfsa_space_total 
/ sbp
->f_bsize
; 
3792         sbp
->f_bfree 
= nmp
->nm_fsattr
.nfsa_space_free 
/ sbp
->f_bsize
; 
3793         sbp
->f_bavail 
= nmp
->nm_fsattr
.nfsa_space_avail 
/ sbp
->f_bsize
; 
3794         sbp
->f_bused 
= (nmp
->nm_fsattr
.nfsa_space_total 
/ sbp
->f_bsize
) - 
3795             (nmp
->nm_fsattr
.nfsa_space_free 
/ sbp
->f_bsize
); 
3796         sbp
->f_files 
= nmp
->nm_fsattr
.nfsa_files_total
; 
3797         sbp
->f_ffree 
= nmp
->nm_fsattr
.nfsa_files_free
; 
3798         sbp
->f_iosize 
= nfs_iosize
; 
3800         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SET_MOUNT_OWNER
)) { 
3801                 sbp
->f_owner 
= set_owner
; 
3805          * Calculate the size used for I/O buffers.  Use the larger 
3806          * of the two sizes to minimise NFS requests but make sure 
3807          * that it is at least one VM page to avoid wasting buffer 
3808          * space and to allow easy mmapping of I/O buffers. 
3809          * The read/write RPC calls handle the splitting up of 
3810          * buffers into multiple requests if the buffer size is 
3811          * larger than the I/O size. 
3813         iosize 
= max(nmp
->nm_rsize
, nmp
->nm_wsize
); 
3814         if (iosize 
< PAGE_SIZE
) { 
3817         nmp
->nm_biosize 
= trunc_page_32(iosize
); 
3819         /* For NFSv3 and greater, there is a (relatively) reliable ACCESS call. */ 
3820         if (nmp
->nm_vers 
> NFS_VER2 
&& !NMFLAG(nmp
, NOOPAQUE_AUTH
) 
3822                 vfs_setauthopaqueaccess(mp
); 
3825         switch (nmp
->nm_lockmode
) { 
3826         case NFS_LOCK_MODE_DISABLED
: 
3828         case NFS_LOCK_MODE_LOCAL
: 
3829                 vfs_setlocklocal(nmp
->nm_mountp
); 
3831         case NFS_LOCK_MODE_ENABLED
: 
3833                 if (nmp
->nm_vers 
<= NFS_VER3
) { 
3834                         nfs_lockd_mount_register(nmp
); 
3841         lck_mtx_lock(&nmp
->nm_lock
); 
3842         nmp
->nm_state 
|= NFSSTA_MOUNTED
; 
3843         lck_mtx_unlock(&nmp
->nm_lock
); 
3846         nfs_mount_drain_and_cleanup(nmp
); 
3853  * We've detected a file system boundary on the server and 
3854  * need to mount a new file system so that our file systems 
3855  * MIRROR the file systems on the server. 
3857  * Build the mount arguments for the new mount and call kernel_mount(). 
3860 nfs_mirror_mount_domount(vnode_t dvp
, vnode_t vp
, vfs_context_t ctx
) 
3862         nfsnode_t np 
= VTONFS(vp
); 
3864         nfsnode_t dnp 
= VTONFS(dvp
); 
3866         struct nfsmount 
*nmp 
= NFSTONMP(np
); 
3867         char fstype
[MFSTYPENAMELEN
], *mntfromname 
= NULL
, *path 
= NULL
, *relpath
, *p
, *cp
; 
3868         int error 
= 0, pathbuflen 
= MAXPATHLEN
, i
, mntflags 
= 0, referral
, skipcopy 
= 0; 
3869         size_t nlen
, rlen
, mlen
, mlen2
, count
; 
3870         struct xdrbuf xb
, xbnew
; 
3871         uint32_t mattrs
[NFS_MATTR_BITMAP_LEN
]; 
3872         uint32_t newmattrs
[NFS_MATTR_BITMAP_LEN
]; 
3873         uint32_t newmflags
[NFS_MFLAG_BITMAP_LEN
]; 
3874         uint32_t newmflags_mask
[NFS_MFLAG_BITMAP_LEN
]; 
3875         uint32_t val
, relpathcomps
; 
3876         uint64_t argslength 
= 0, argslength_offset
, attrslength_offset
, end_offset
; 
3877         uint32_t numlocs
, loc
, numserv
, serv
, numaddr
, addr
, numcomp
, comp
; 
3879         struct nfs_fs_locations nfsls
; 
3881         referral 
= (np
->n_vattr
.nva_flags 
& NFS_FFLAG_TRIGGER_REFERRAL
); 
3883                 bzero(&nfsls
, sizeof(nfsls
)); 
3886         xb_init(&xbnew
, XDRBUF_NONE
); 
3888         if (!nmp 
|| (nmp
->nm_state 
& (NFSSTA_FORCE 
| NFSSTA_DEAD
))) { 
3892         /* allocate a couple path buffers we need */ 
3893         mntfromname 
= zalloc(ZV_NAMEI
); 
3894         path 
= zalloc(ZV_NAMEI
); 
3896         /* get the path for the directory being mounted on */ 
3897         error 
= vn_getpath(vp
, path
, &pathbuflen
); 
3904          * Set up the mntfromname for the new mount based on the 
3905          * current mount's mntfromname and the directory's path 
3906          * relative to the current mount's mntonname. 
3907          * Set up relpath to point at the relative path on the current mount. 
3908          * Also, count the number of components in relpath. 
3909          * We'll be adding those to each fs location path in the new args. 
3911         nlen 
= strlcpy(mntfromname
, vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
, MAXPATHLEN
); 
3912         if ((nlen 
> 0) && (mntfromname
[nlen 
- 1] == '/')) { /* avoid double '/' in new name */ 
3913                 mntfromname
[nlen 
- 1] = '\0'; 
3916         relpath 
= mntfromname 
+ nlen
; 
3917         nlen 
= strlcat(mntfromname
, path 
+ strlen(vfs_statfs(nmp
->nm_mountp
)->f_mntonname
), MAXPATHLEN
); 
3918         if (nlen 
>= MAXPATHLEN
) { 
3919                 error 
= ENAMETOOLONG
; 
3922         /* count the number of components in relpath */ 
3924         while (*p 
&& (*p 
== '/')) { 
3930                 while (*p 
&& (*p 
!= '/')) { 
3933                 while (*p 
&& (*p 
== '/')) { 
3938         /* grab a copy of the file system type */ 
3939         vfs_name(vnode_mount(vp
), fstype
); 
3941         /* for referrals, fetch the fs locations */ 
3943                 const char *vname 
= vnode_getname(NFSTOV(np
)); 
3949                         error 
= nfs4_get_fs_locations(nmp
, dnp
, NULL
, 0, vname
, ctx
, &nfsls
); 
3950                         vnode_putname(vname
); 
3951                         if (!error 
&& (nfsls
.nl_numlocs 
< 1)) { 
3959         /* set up NFS mount args based on current mount args */ 
3961 #define xb_copy_32(E, XBSRC, XBDST, V) \ 
3964                 xb_get_32((E), (XBSRC), (V)); \ 
3965                 if (skipcopy) break; \ 
3966                 xb_add_32((E), (XBDST), (V)); \ 
3968 #define xb_copy_opaque(E, XBSRC, XBDST) \ 
3970                 uint32_t __count = 0, __val; \ 
3971                 xb_copy_32((E), (XBSRC), (XBDST), __count); \ 
3973                 __count = nfsm_rndup(__count); \ 
3974                 __count /= XDRWORD; \ 
3975                 while (__count-- > 0) \ 
3976                         xb_copy_32((E), (XBSRC), (XBDST), __val); \ 
3979         xb_init_buffer(&xb
, nmp
->nm_args
, 2 * XDRWORD
); 
3980         xb_get_32(error
, &xb
, val
); /* version */ 
3981         xb_get_32(error
, &xb
, argslength
); /* args length */ 
3982         xb_init_buffer(&xb
, nmp
->nm_args
, argslength
); 
3984         xb_init_buffer(&xbnew
, NULL
, 0); 
3985         xb_copy_32(error
, &xb
, &xbnew
, val
); /* version */ 
3986         argslength_offset 
= xb_offset(&xbnew
); 
3987         xb_copy_32(error
, &xb
, &xbnew
, val
); /* args length */ 
3988         xb_copy_32(error
, &xb
, &xbnew
, val
); /* XDR args version */ 
3989         count 
= NFS_MATTR_BITMAP_LEN
; 
3990         xb_get_bitmap(error
, &xb
, mattrs
, count
); /* mount attribute bitmap */ 
3992         for (i 
= 0; i 
< NFS_MATTR_BITMAP_LEN
; i
++) { 
3993                 newmattrs
[i
] = mattrs
[i
]; 
3996                 NFS_BITMAP_SET(newmattrs
, NFS_MATTR_FS_LOCATIONS
); 
3997                 NFS_BITMAP_CLR(newmattrs
, NFS_MATTR_MNTFROM
); 
3999                 NFS_BITMAP_SET(newmattrs
, NFS_MATTR_FH
); 
4001         NFS_BITMAP_SET(newmattrs
, NFS_MATTR_FLAGS
); 
4002         NFS_BITMAP_SET(newmattrs
, NFS_MATTR_MNTFLAGS
); 
4003         NFS_BITMAP_SET(newmattrs
, NFS_MATTR_SET_MOUNT_OWNER
); 
4004         xb_add_bitmap(error
, &xbnew
, newmattrs
, NFS_MATTR_BITMAP_LEN
); 
4005         attrslength_offset 
= xb_offset(&xbnew
); 
4006         xb_copy_32(error
, &xb
, &xbnew
, val
); /* attrs length */ 
4007         NFS_BITMAP_ZERO(newmflags_mask
, NFS_MFLAG_BITMAP_LEN
); 
4008         NFS_BITMAP_ZERO(newmflags
, NFS_MFLAG_BITMAP_LEN
); 
4009         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_FLAGS
)) { 
4010                 count 
= NFS_MFLAG_BITMAP_LEN
; 
4011                 xb_get_bitmap(error
, &xb
, newmflags_mask
, count
); /* mount flag mask bitmap */ 
4012                 count 
= NFS_MFLAG_BITMAP_LEN
; 
4013                 xb_get_bitmap(error
, &xb
, newmflags
, count
); /* mount flag bitmap */ 
4015         NFS_BITMAP_SET(newmflags_mask
, NFS_MFLAG_EPHEMERAL
); 
4016         NFS_BITMAP_SET(newmflags
, NFS_MFLAG_EPHEMERAL
); 
4017         xb_add_bitmap(error
, &xbnew
, newmflags_mask
, NFS_MFLAG_BITMAP_LEN
); 
4018         xb_add_bitmap(error
, &xbnew
, newmflags
, NFS_MFLAG_BITMAP_LEN
); 
4019         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_VERSION
)) { 
4020                 xb_copy_32(error
, &xb
, &xbnew
, val
); 
4022         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_MINOR_VERSION
)) { 
4023                 xb_copy_32(error
, &xb
, &xbnew
, val
); 
4025         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_VERSION_RANGE
)) { 
4026                 xb_copy_32(error
, &xb
, &xbnew
, val
); 
4027                 xb_copy_32(error
, &xb
, &xbnew
, val
); 
4029         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READ_SIZE
)) { 
4030                 xb_copy_32(error
, &xb
, &xbnew
, val
); 
4032         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_WRITE_SIZE
)) { 
4033                 xb_copy_32(error
, &xb
, &xbnew
, val
); 
4035         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READDIR_SIZE
)) { 
4036                 xb_copy_32(error
, &xb
, &xbnew
, val
); 
4038         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READAHEAD
)) { 
4039                 xb_copy_32(error
, &xb
, &xbnew
, val
); 
4041         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MIN
)) { 
4042                 xb_copy_32(error
, &xb
, &xbnew
, val
); 
4043                 xb_copy_32(error
, &xb
, &xbnew
, val
); 
4045         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MAX
)) { 
4046                 xb_copy_32(error
, &xb
, &xbnew
, val
); 
4047                 xb_copy_32(error
, &xb
, &xbnew
, val
); 
4049         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MIN
)) { 
4050                 xb_copy_32(error
, &xb
, &xbnew
, val
); 
4051                 xb_copy_32(error
, &xb
, &xbnew
, val
); 
4053         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MAX
)) { 
4054                 xb_copy_32(error
, &xb
, &xbnew
, val
); 
4055                 xb_copy_32(error
, &xb
, &xbnew
, val
); 
4057         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_LOCK_MODE
)) { 
4058                 xb_copy_32(error
, &xb
, &xbnew
, val
); 
4060         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SECURITY
)) { 
4061                 xb_copy_32(error
, &xb
, &xbnew
, count
); 
4062                 while (!error 
&& (count
-- > 0)) { 
4063                         xb_copy_32(error
, &xb
, &xbnew
, val
); 
4066         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_KERB_ETYPE
)) { 
4067                 xb_copy_32(error
, &xb
, &xbnew
, count
); 
4068                 xb_add_32(error
, &xbnew
, -1); 
4069                 while (!error 
&& (count
-- > 0)) { 
4070                         xb_copy_32(error
, &xb
, &xbnew
, val
); 
4073         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MAX_GROUP_LIST
)) { 
4074                 xb_copy_32(error
, &xb
, &xbnew
, val
); 
4076         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SOCKET_TYPE
)) { 
4077                 xb_copy_opaque(error
, &xb
, &xbnew
); 
4079         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_PORT
)) { 
4080                 xb_copy_32(error
, &xb
, &xbnew
, val
); 
4082         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MOUNT_PORT
)) { 
4083                 xb_copy_32(error
, &xb
, &xbnew
, val
); 
4085         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_REQUEST_TIMEOUT
)) { 
4086                 xb_copy_32(error
, &xb
, &xbnew
, val
); 
4087                 xb_copy_32(error
, &xb
, &xbnew
, val
); 
4089         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SOFT_RETRY_COUNT
)) { 
4090                 xb_copy_32(error
, &xb
, &xbnew
, val
); 
4092         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_DEAD_TIMEOUT
)) { 
4093                 xb_copy_32(error
, &xb
, &xbnew
, val
); 
4094                 xb_copy_32(error
, &xb
, &xbnew
, val
); 
4096         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_FH
)) { 
4097                 xb_get_32(error
, &xb
, count
); 
4098                 xb_skip(error
, &xb
, count
); 
4101                 /* set the initial file handle to the directory's file handle */ 
4102                 xb_add_fh(error
, &xbnew
, np
->n_fhp
, np
->n_fhsize
); 
4104         /* copy/extend/skip fs locations */ 
4105         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_FS_LOCATIONS
)) { 
4106                 numlocs 
= numserv 
= numaddr 
= numcomp 
= 0; 
4107                 if (referral
) { /* don't copy the fs locations for a referral */ 
4110                 xb_copy_32(error
, &xb
, &xbnew
, numlocs
); /* location count */ 
4111                 for (loc 
= 0; !error 
&& (loc 
< numlocs
); loc
++) { 
4112                         xb_copy_32(error
, &xb
, &xbnew
, numserv
); /* server count */ 
4113                         for (serv 
= 0; !error 
&& (serv 
< numserv
); serv
++) { 
4114                                 xb_copy_opaque(error
, &xb
, &xbnew
); /* server name */ 
4115                                 xb_copy_32(error
, &xb
, &xbnew
, numaddr
); /* address count */ 
4116                                 for (addr 
= 0; !error 
&& (addr 
< numaddr
); addr
++) { 
4117                                         xb_copy_opaque(error
, &xb
, &xbnew
); /* address */ 
4119                                 xb_copy_opaque(error
, &xb
, &xbnew
); /* server info */ 
4122                         xb_get_32(error
, &xb
, numcomp
); /* component count */ 
4124                                 uint64_t totalcomps 
= numcomp 
+ relpathcomps
; 
4126                                 /* set error to ERANGE in the event of overflow */ 
4127                                 if (totalcomps 
> UINT32_MAX
) { 
4128                                         nfsmerr_if((error 
= ERANGE
)); 
4131                                 xb_add_32(error
, &xbnew
, (uint32_t) totalcomps
); /* new component count */ 
4133                         for (comp 
= 0; !error 
&& (comp 
< numcomp
); comp
++) { 
4134                                 xb_copy_opaque(error
, &xb
, &xbnew
); /* component */ 
4136                         /* add additional components */ 
4138                         while (*p 
&& (*p 
== '/')) { 
4141                         while (*p 
&& !error
) { 
4143                                 while (*p 
&& (*p 
!= '/')) { 
4146                                 xb_add_string(error
, &xbnew
, cp
, (p 
- cp
)); /* component */ 
4147                                 while (*p 
&& (*p 
== '/')) { 
4151                         xb_copy_opaque(error
, &xb
, &xbnew
); /* fs location info */ 
4158                 /* add referral's fs locations */ 
4159                 xb_add_32(error
, &xbnew
, nfsls
.nl_numlocs
);                     /* FS_LOCATIONS */ 
4160                 for (loc 
= 0; !error 
&& (loc 
< nfsls
.nl_numlocs
); loc
++) { 
4161                         xb_add_32(error
, &xbnew
, nfsls
.nl_locations
[loc
]->nl_servcount
); 
4162                         for (serv 
= 0; !error 
&& (serv 
< nfsls
.nl_locations
[loc
]->nl_servcount
); serv
++) { 
4163                                 xb_add_string(error
, &xbnew
, nfsls
.nl_locations
[loc
]->nl_servers
[serv
]->ns_name
, 
4164                                     strlen(nfsls
.nl_locations
[loc
]->nl_servers
[serv
]->ns_name
)); 
4165                                 xb_add_32(error
, &xbnew
, nfsls
.nl_locations
[loc
]->nl_servers
[serv
]->ns_addrcount
); 
4166                                 for (addr 
= 0; !error 
&& (addr 
< nfsls
.nl_locations
[loc
]->nl_servers
[serv
]->ns_addrcount
); addr
++) { 
4167                                         xb_add_string(error
, &xbnew
, nfsls
.nl_locations
[loc
]->nl_servers
[serv
]->ns_addresses
[addr
], 
4168                                             strlen(nfsls
.nl_locations
[loc
]->nl_servers
[serv
]->ns_addresses
[addr
])); 
4170                                 xb_add_32(error
, &xbnew
, 0); /* empty server info */ 
4172                         xb_add_32(error
, &xbnew
, nfsls
.nl_locations
[loc
]->nl_path
.np_compcount
); 
4173                         for (comp 
= 0; !error 
&& (comp 
< nfsls
.nl_locations
[loc
]->nl_path
.np_compcount
); comp
++) { 
4174                                 xb_add_string(error
, &xbnew
, nfsls
.nl_locations
[loc
]->nl_path
.np_components
[comp
], 
4175                                     strlen(nfsls
.nl_locations
[loc
]->nl_path
.np_components
[comp
])); 
4177                         xb_add_32(error
, &xbnew
, 0); /* empty fs location info */ 
4180         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MNTFLAGS
)) { 
4181                 xb_get_32(error
, &xb
, mntflags
); 
4184          * We add the following mount flags to the ones for the mounted-on mount: 
4185          * MNT_DONTBROWSE - to keep the mount from showing up as a separate volume 
4186          * MNT_AUTOMOUNTED - to keep DiskArb from retriggering the mount after 
4187          *                   an unmount (looking for /.autodiskmounted) 
4189         mntflags 
|= (MNT_AUTOMOUNTED 
| MNT_DONTBROWSE
); 
4190         xb_add_32(error
, &xbnew
, mntflags
); 
4191         if (!referral 
&& NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MNTFROM
)) { 
4192                 /* copy mntfrom string and add relpath */ 
4193                 rlen 
= strlen(relpath
); 
4194                 xb_get_32(error
, &xb
, mlen
); 
4196                 mlen2 
= mlen 
+ ((relpath
[0] != '/') ? 1 : 0) + rlen
; 
4197                 xb_add_32(error
, &xbnew
, mlen2
); 
4198                 count 
= mlen 
/ XDRWORD
; 
4199                 /* copy the original string */ 
4200                 while (count
-- > 0) { 
4201                         xb_copy_32(error
, &xb
, &xbnew
, val
); 
4203                 if (!error 
&& (mlen 
% XDRWORD
)) { 
4204                         error 
= xb_get_bytes(&xb
, buf
, mlen 
% XDRWORD
, 0); 
4206                                 error 
= xb_add_bytes(&xbnew
, buf
, mlen 
% XDRWORD
, 1); 
4209                 /* insert a '/' if the relative path doesn't start with one */ 
4210                 if (!error 
&& (relpath
[0] != '/')) { 
4212                         error 
= xb_add_bytes(&xbnew
, buf
, 1, 1); 
4214                 /* add the additional relative path */ 
4216                         error 
= xb_add_bytes(&xbnew
, relpath
, rlen
, 1); 
4218                 /* make sure the resulting string has the right number of pad bytes */ 
4219                 if (!error 
&& (mlen2 
!= nfsm_rndup(mlen2
))) { 
4220                         bzero(buf
, sizeof(buf
)); 
4221                         count 
= nfsm_rndup(mlen2
) - mlen2
; 
4222                         error 
= xb_add_bytes(&xbnew
, buf
, count
, 1); 
4226          * The following string copies rely on the fact that we already validated 
4227          * these data when creating the initial mount point. 
4229         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_REALM
)) { 
4230                 xb_add_string(error
, &xbnew
, nmp
->nm_realm
, strlen(nmp
->nm_realm
)); 
4232         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_PRINCIPAL
)) { 
4233                 xb_add_string(error
, &xbnew
, nmp
->nm_principal
, strlen(nmp
->nm_principal
)); 
4235         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SVCPRINCIPAL
)) { 
4236                 xb_add_string(error
, &xbnew
, nmp
->nm_sprinc
, strlen(nmp
->nm_sprinc
)); 
4238         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_LOCAL_NFS_PORT
)) { 
4239                 xb_add_string(error
, &xbnew
, nmp
->nm_nfs_localport
, strlen(nmp
->nm_nfs_localport
)); 
4241         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_LOCAL_MOUNT_PORT
)) { 
4242                 xb_add_string(error
, &xbnew
, nmp
->nm_mount_localport
, strlen(nmp
->nm_mount_localport
)); 
4244         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SET_MOUNT_OWNER
)) { 
4245                 /* drop embedded owner value */ 
4246                 xb_get_32(error
, &xb
, count
); 
4248         /* New mount always gets same owner as this mount */ 
4249         xb_add_32(error
, &xbnew
, vnode_mount(vp
)->mnt_vfsstat
.f_owner
); 
4250         xb_build_done(error
, &xbnew
); 
4252         /* update opaque counts */ 
4253         end_offset 
= xb_offset(&xbnew
); 
4255                 error 
= xb_seek(&xbnew
, argslength_offset
); 
4256                 argslength 
= end_offset 
- argslength_offset 
+ XDRWORD 
/*version*/; 
4257                 xb_add_32(error
, &xbnew
, argslength
); 
4260                 error 
= xb_seek(&xbnew
, attrslength_offset
); 
4261                 xb_add_32(error
, &xbnew
, end_offset 
- attrslength_offset 
- XDRWORD 
/*don't include length field*/); 
4266          * For kernel_mount() call, use the existing mount flags (instead of the 
4267          * original flags) because flags like MNT_NOSUID and MNT_NODEV may have 
4268          * been silently enforced. Also, in terms of MACF, the _kernel_ is 
4269          * performing the mount (and enforcing all of the mount options), so we 
4270          * use the kernel context for the mount call. 
4272         mntflags 
= vnode_vfsvisflags(vp
); 
4273         mntflags 
|= (MNT_AUTOMOUNTED 
| MNT_DONTBROWSE
); 
4274         ctx 
= vfs_context_kernel(); 
4277         error 
= kernel_mount(fstype
, dvp
, vp
, path
, xb_buffer_base(&xbnew
), argslength
, 
4278             mntflags
, KERNEL_MOUNT_PERMIT_UNMOUNT 
| KERNEL_MOUNT_NOAUTH
, ctx
); 
4282                 printf("nfs: mirror mount of %s on %s failed (%d)\n", 
4283                     mntfromname
, path
, error
); 
4288                 nfs_fs_locations_cleanup(&nfsls
); 
4291                 NFS_ZFREE(ZV_NAMEI
, path
); 
4294                 NFS_ZFREE(ZV_NAMEI
, mntfromname
); 
4297                 nfs_ephemeral_mount_harvester_start(); 
4303  * trigger vnode functions 
4305 #define NFS_TRIGGER_DEBUG 1 
4308 nfs_mirror_mount_trigger_resolve( 
4310         const struct componentname 
*cnp
, 
4311         enum path_operation pop
, 
4313         __unused 
void *data
, 
4316         nfsnode_t         np 
= VTONFS(vp
); 
4317         vnode_t           pvp 
= NULLVP
; 
4320         resolver_result_t result
; 
4323          * We have a trigger node that doesn't have anything mounted on it yet. 
4324          * We'll do the mount if either: 
4325          * (a) this isn't the last component of the path OR 
4326          * (b) this is an op that looks like it should trigger the mount. 
4328         if (cnp
->cn_flags 
& ISLASTCN
) { 
4346                         /* don't perform the mount for these operations */ 
4347                         result 
= vfs_resolver_result(np
->n_trigseq
, RESOLVER_NOCHANGE
, 0); 
4348 #ifdef NFS_TRIGGER_DEBUG 
4349                         NP(np
, "nfs trigger RESOLVE: no change, last %d nameiop %d, seq %d", 
4350                             (cnp
->cn_flags 
& ISLASTCN
) ? 1 : 0, cnp
->cn_nameiop
, np
->n_trigseq
); 
4361                 case OP_EXCHANGEDATA
: 
4365                 case OP_REMOVEXATTR
: 
4367                         /* go ahead and do the mount */ 
4372         if (vnode_mountedhere(vp
) != NULL
) { 
4374                  * Um... there's already something mounted. 
4375                  * Been there.  Done that.  Let's just say it succeeded. 
4381         if ((error 
= nfs_node_set_busy(np
, vfs_context_thread(ctx
)))) { 
4382                 result 
= vfs_resolver_result(np
->n_trigseq
, RESOLVER_ERROR
, error
); 
4383 #ifdef NFS_TRIGGER_DEBUG 
4384                 NP(np
, "nfs trigger RESOLVE: busy error %d, last %d nameiop %d, seq %d", 
4385                     error
, (cnp
->cn_flags 
& ISLASTCN
) ? 1 : 0, cnp
->cn_nameiop
, np
->n_trigseq
); 
4391         /* Check again, in case the mount happened while we were setting busy */ 
4392         if (vnode_mountedhere(vp
) != NULL
) { 
4393                 /* Been there.  Done that.  Let's just say it succeeded.  */ 
4397         nfs_node_lock_force(np
); 
4398         if (np
->n_flag 
& NDISARMTRIGGER
) { 
4400                 nfs_node_unlock(np
); 
4403         nfs_node_unlock(np
); 
4405         pvp 
= vnode_getparent(vp
); 
4406         if (pvp 
== NULLVP
) { 
4410                 error 
= nfs_mirror_mount_domount(pvp
, vp
, ctx
); 
4416         result 
= vfs_resolver_result(np
->n_trigseq
, error 
? RESOLVER_ERROR 
: RESOLVER_RESOLVED
, error
); 
4417 #ifdef NFS_TRIGGER_DEBUG 
4418         NP(np
, "nfs trigger RESOLVE: %s %d, last %d nameiop %d, seq %d", 
4419             error 
? "error" : "resolved", error
, 
4420             (cnp
->cn_flags 
& ISLASTCN
) ? 1 : 0, cnp
->cn_nameiop
, np
->n_trigseq
); 
4423         if (pvp 
!= NULLVP
) { 
4427                 nfs_node_clear_busy(np
); 
4433 nfs_mirror_mount_trigger_unresolve( 
4436         __unused 
void *data
, 
4439         nfsnode_t np 
= VTONFS(vp
); 
4442         resolver_result_t result
; 
4444         if ((error 
= nfs_node_set_busy(np
, vfs_context_thread(ctx
)))) { 
4445                 result 
= vfs_resolver_result(np
->n_trigseq
, RESOLVER_ERROR
, error
); 
4446 #ifdef NFS_TRIGGER_DEBUG 
4447                 NP(np
, "nfs trigger UNRESOLVE: busy error %d, seq %d", error
, np
->n_trigseq
); 
4452         mp 
= vnode_mountedhere(vp
); 
4457                 error 
= vfs_unmountbyfsid(&(vfs_statfs(mp
)->f_fsid
), flags
, ctx
); 
4462         result 
= vfs_resolver_result(np
->n_trigseq
, error 
? RESOLVER_ERROR 
: RESOLVER_UNRESOLVED
, error
); 
4463 #ifdef NFS_TRIGGER_DEBUG 
4464         NP(np
, "nfs trigger UNRESOLVE: %s %d, seq %d", 
4465             error 
? "error" : "unresolved", error
, np
->n_trigseq
); 
4467         nfs_node_clear_busy(np
); 
4472 nfs_mirror_mount_trigger_rearm( 
4475         __unused 
void *data
, 
4478         nfsnode_t np 
= VTONFS(vp
); 
4480         resolver_result_t result
; 
4482         if ((error 
= nfs_node_set_busy(np
, vfs_context_thread(ctx
)))) { 
4483                 result 
= vfs_resolver_result(np
->n_trigseq
, RESOLVER_ERROR
, error
); 
4484 #ifdef NFS_TRIGGER_DEBUG 
4485                 NP(np
, "nfs trigger REARM: busy error %d, seq %d", error
, np
->n_trigseq
); 
4491         result 
= vfs_resolver_result(np
->n_trigseq
, 
4492             vnode_mountedhere(vp
) ? RESOLVER_RESOLVED 
: RESOLVER_UNRESOLVED
, 0); 
4493 #ifdef NFS_TRIGGER_DEBUG 
4494         NP(np
, "nfs trigger REARM: %s, seq %d", 
4495             vnode_mountedhere(vp
) ? "resolved" : "unresolved", np
->n_trigseq
); 
4497         nfs_node_clear_busy(np
); 
4502  * Periodically attempt to unmount ephemeral (mirror) mounts in an attempt to limit 
4503  * the number of unused mounts. 
4506 #define NFS_EPHEMERAL_MOUNT_HARVEST_INTERVAL    120     /* how often the harvester runs */ 
4507 struct nfs_ephemeral_mount_harvester_info 
{ 
4508         fsid_t          fsid
;           /* FSID that we need to try to unmount */ 
4509         uint32_t        mountcount
;     /* count of ephemeral mounts seen in scan */ 
4511 /* various globals for the harvester */ 
4512 static thread_call_t nfs_ephemeral_mount_harvester_timer 
= NULL
; 
4513 static int nfs_ephemeral_mount_harvester_on 
= 0; 
4515 kern_return_t 
thread_terminate(thread_t
); 
4518 nfs_ephemeral_mount_harvester_callback(mount_t mp
, void *arg
) 
4520         struct nfs_ephemeral_mount_harvester_info 
*hinfo 
= arg
; 
4521         struct nfsmount 
*nmp
; 
4524         if (strcmp(mp
->mnt_vfsstat
.f_fstypename
, "nfs")) { 
4525                 return VFS_RETURNED
; 
4528         if (!nmp 
|| !NMFLAG(nmp
, EPHEMERAL
) 
4530                 return VFS_RETURNED
; 
4532         hinfo
->mountcount
++; 
4534         /* avoid unmounting mounts that have been triggered within the last harvest interval */ 
4536         if ((nmp
->nm_mounttime 
>> 32) > ((uint32_t)now
.tv_sec 
- NFS_EPHEMERAL_MOUNT_HARVEST_INTERVAL
)) { 
4537                 return VFS_RETURNED
; 
4540         if (hinfo
->fsid
.val
[0] || hinfo
->fsid
.val
[1]) { 
4541                 /* attempt to unmount previously-found ephemeral mount */ 
4542                 vfs_unmountbyfsid(&hinfo
->fsid
, 0, vfs_context_kernel()); 
4543                 hinfo
->fsid
.val
[0] = hinfo
->fsid
.val
[1] = 0; 
4547          * We can't call unmount here since we hold a mount iter ref 
4548          * on mp so save its fsid for the next call iteration to unmount. 
4550         hinfo
->fsid
.val
[0] = mp
->mnt_vfsstat
.f_fsid
.val
[0]; 
4551         hinfo
->fsid
.val
[1] = mp
->mnt_vfsstat
.f_fsid
.val
[1]; 
4553         return VFS_RETURNED
; 
4557  * Spawn a thread to do the ephemeral mount harvesting. 
4560 nfs_ephemeral_mount_harvester_timer_func(void) 
4564         if (kernel_thread_start(nfs_ephemeral_mount_harvester
, NULL
, &thd
) == KERN_SUCCESS
) { 
4565                 thread_deallocate(thd
); 
4570  * Iterate all mounts looking for NFS ephemeral mounts to try to unmount. 
4573 nfs_ephemeral_mount_harvester(__unused 
void *arg
, __unused wait_result_t wr
) 
4575         struct nfs_ephemeral_mount_harvester_info hinfo
; 
4578         hinfo
.mountcount 
= 0; 
4579         hinfo
.fsid
.val
[0] = hinfo
.fsid
.val
[1] = 0; 
4580         vfs_iterate(VFS_ITERATE_TAIL_FIRST
, nfs_ephemeral_mount_harvester_callback
, &hinfo
); 
4581         if (hinfo
.fsid
.val
[0] || hinfo
.fsid
.val
[1]) { 
4582                 /* attempt to unmount last found ephemeral mount */ 
4583                 vfs_unmountbyfsid(&hinfo
.fsid
, 0, vfs_context_kernel()); 
4586         lck_mtx_lock(nfs_global_mutex
); 
4587         if (!hinfo
.mountcount
) { 
4588                 /* no more ephemeral mounts - don't need timer */ 
4589                 nfs_ephemeral_mount_harvester_on 
= 0; 
4591                 /* re-arm the timer */ 
4592                 clock_interval_to_deadline(NFS_EPHEMERAL_MOUNT_HARVEST_INTERVAL
, NSEC_PER_SEC
, &deadline
); 
4593                 thread_call_enter_delayed(nfs_ephemeral_mount_harvester_timer
, deadline
); 
4594                 nfs_ephemeral_mount_harvester_on 
= 1; 
4596         lck_mtx_unlock(nfs_global_mutex
); 
4599         thread_terminate(current_thread()); 
4603  * Make sure the NFS ephemeral mount harvester timer is running. 
4606 nfs_ephemeral_mount_harvester_start(void) 
4610         lck_mtx_lock(nfs_global_mutex
); 
4611         if (nfs_ephemeral_mount_harvester_on
) { 
4612                 lck_mtx_unlock(nfs_global_mutex
); 
4615         if (nfs_ephemeral_mount_harvester_timer 
== NULL
) { 
4616                 nfs_ephemeral_mount_harvester_timer 
= thread_call_allocate((thread_call_func_t
)nfs_ephemeral_mount_harvester_timer_func
, NULL
); 
4618         clock_interval_to_deadline(NFS_EPHEMERAL_MOUNT_HARVEST_INTERVAL
, NSEC_PER_SEC
, &deadline
); 
4619         thread_call_enter_delayed(nfs_ephemeral_mount_harvester_timer
, deadline
); 
4620         nfs_ephemeral_mount_harvester_on 
= 1; 
4621         lck_mtx_unlock(nfs_global_mutex
); 
4627  *  Send a STAT protocol request to the server to verify statd is running. 
4628  *  rpc-statd service, which responsible to provide locks for the NFS server, is disabled by default on Ubuntu. 
4629  *  Please see Radar 45969553 for more info. 
4632 nfs3_check_lockmode(struct nfsmount 
*nmp
, struct sockaddr 
*sa
, int sotype
, int timeo
) 
4634         struct sockaddr_storage ss
; 
4635         int error
, port 
= 0; 
4637         if (nmp
->nm_lockmode 
== NFS_LOCK_MODE_ENABLED
) { 
4638                 bcopy(sa
, &ss
, sa
->sa_len
); 
4639                 error 
= nfs_portmap_lookup(nmp
, vfs_context_current(), (struct sockaddr
*)&ss
, NULL
, RPCPROG_STAT
, RPCMNT_VER1
, NM_OMFLAG(nmp
, MNTUDP
) ? SOCK_DGRAM 
: sotype
, timeo
); 
4641                         if (ss
.ss_family 
== AF_INET
) { 
4642                                 port 
= ntohs(((struct sockaddr_in
*)&ss
)->sin_port
); 
4643                         } else if (ss
.ss_family 
== AF_INET6
) { 
4644                                 port 
= ntohs(((struct sockaddr_in6
*)&ss
)->sin6_port
); 
4645                         } else if (ss
.ss_family 
== AF_LOCAL
) { 
4646                                 port 
= (((struct sockaddr_un
*)&ss
)->sun_path
[0] != '\0'); 
4650                                 printf("nfs: STAT(NSM) rpc service is not available, unable to mount with current lock mode.\n"); 
4651                                 return EPROGUNAVAIL
; 
4659  * Send a MOUNT protocol MOUNT request to the server to get the initial file handle (and security). 
4662 nfs3_mount_rpc(struct nfsmount 
*nmp
, struct sockaddr 
*sa
, int sotype
, int nfsvers
, char *path
, vfs_context_t ctx
, int timeo
, fhandle_t 
*fh
, struct nfs_sec 
*sec
) 
4664         int error 
= 0, mntproto
; 
4665         thread_t thd 
= vfs_context_thread(ctx
); 
4666         kauth_cred_t cred 
= vfs_context_ucred(ctx
); 
4669         struct nfsm_chain nmreq
, nmrep
; 
4671         uint32_t mntvers
, mntport
, val
; 
4672         struct sockaddr_storage ss
; 
4673         struct sockaddr 
*saddr 
= (struct sockaddr
*)&ss
; 
4674         struct sockaddr_un 
*sun 
= (struct sockaddr_un
*)saddr
; 
4676         nfsm_chain_null(&nmreq
); 
4677         nfsm_chain_null(&nmrep
); 
4679         mntvers 
= (nfsvers 
== NFS_VER2
) ? RPCMNT_VER1 
: RPCMNT_VER3
; 
4680         mntproto 
= (NM_OMFLAG(nmp
, MNTUDP
) || (sotype 
== SOCK_DGRAM
)) ? IPPROTO_UDP 
: IPPROTO_TCP
; 
4683         bcopy(sa
, saddr
, min(sizeof(ss
), sa
->sa_len
)); 
4684         if (saddr
->sa_family 
== AF_INET
) { 
4685                 if (nmp
->nm_mountport
) { 
4686                         ((struct sockaddr_in
*)saddr
)->sin_port 
= htons(nmp
->nm_mountport
); 
4688                 mntport 
= ntohs(((struct sockaddr_in
*)saddr
)->sin_port
); 
4689         } else if (saddr
->sa_family 
== AF_INET6
) { 
4690                 if (nmp
->nm_mountport
) { 
4691                         ((struct sockaddr_in6
*)saddr
)->sin6_port 
= htons(nmp
->nm_mountport
); 
4693                 mntport 
= ntohs(((struct sockaddr_in6
*)saddr
)->sin6_port
); 
4694         } else {  /* Local domain socket */ 
4695                 mntport 
= ((struct sockaddr_un 
*)saddr
)->sun_path
[0]; /* Do we have and address? */ 
4696                 mntproto 
= IPPROTO_TCP
;  /* XXX rpcbind only listens on streams sockets for now */ 
4700                 error 
= nfs_portmap_lookup(nmp
, ctx
, saddr
, NULL
, RPCPROG_MNT
, mntvers
, 
4701                     mntproto 
== IPPROTO_UDP 
? SOCK_DGRAM 
: SOCK_STREAM
, timeo
); 
4703                 if (saddr
->sa_family 
== AF_INET
) { 
4704                         mntport 
= ntohs(((struct sockaddr_in
*)saddr
)->sin_port
); 
4705                 } else if (saddr
->sa_family 
== AF_INET6
) { 
4706                         mntport 
= ntohs(((struct sockaddr_in6
*)saddr
)->sin6_port
); 
4707                 } else if (saddr
->sa_family 
== AF_LOCAL
) { 
4708                         mntport 
= ((struct sockaddr_un
*)saddr
)->sun_path
[0]; 
4711                         /* if not found and TCP, then retry with UDP */ 
4712                         if (mntproto 
== IPPROTO_UDP
) { 
4713                                 error 
= EPROGUNAVAIL
; 
4716                         mntproto 
= IPPROTO_UDP
; 
4717                         bcopy(sa
, saddr
, min(sizeof(ss
), sa
->sa_len
)); 
4718                         if (saddr
->sa_family 
== AF_LOCAL
) { 
4719                                 strlcpy(sun
->sun_path
, RPCB_TICLTS_PATH
, sizeof(sun
->sun_path
)); 
4723         nfsmout_if(error 
|| !mntport
); 
4725         /* MOUNT protocol MOUNT request */ 
4726         slen 
= strlen(path
); 
4727         nfsm_chain_build_alloc_init(error
, &nmreq
, NFSX_UNSIGNED 
+ nfsm_rndup(slen
)); 
4728         nfsm_chain_add_name(error
, &nmreq
, path
, slen
, nmp
); 
4729         nfsm_chain_build_done(error
, &nmreq
); 
4731         error 
= nfsm_rpchead2(nmp
, (mntproto 
== IPPROTO_UDP
) ? SOCK_DGRAM 
: SOCK_STREAM
, 
4732             RPCPROG_MNT
, mntvers
, RPCMNT_MOUNT
, 
4733             RPCAUTH_SYS
, cred
, NULL
, nmreq
.nmc_mhead
, &xid
, &mreq
); 
4735         nmreq
.nmc_mhead 
= NULL
; 
4736         error 
= nfs_aux_request(nmp
, thd
, saddr
, NULL
, 
4737             ((mntproto 
== IPPROTO_UDP
) ? SOCK_DGRAM 
: SOCK_STREAM
), 
4738             mreq
, R_XID32(xid
), 1, timeo
, &nmrep
); 
4740         nfsm_chain_get_32(error
, &nmrep
, val
); 
4741         if (!error 
&& val
) { 
4745         nfsm_chain_get_fh(error
, &nmrep
, nfsvers
, fh
); 
4746         if (!error 
&& (nfsvers 
> NFS_VER2
)) { 
4747                 sec
->count 
= NX_MAX_SEC_FLAVORS
; 
4748                 error 
= nfsm_chain_get_secinfo(&nmrep
, &sec
->flavors
[0], &sec
->count
); 
4751         nfsm_chain_cleanup(&nmreq
); 
4752         nfsm_chain_cleanup(&nmrep
); 
4758  * Send a MOUNT protocol UNMOUNT request to tell the server we've unmounted it. 
4761 nfs3_umount_rpc(struct nfsmount 
*nmp
, vfs_context_t ctx
, int timeo
) 
4763         int error 
= 0, mntproto
; 
4764         thread_t thd 
= vfs_context_thread(ctx
); 
4765         kauth_cred_t cred 
= vfs_context_ucred(ctx
); 
4769         struct nfsm_chain nmreq
, nmrep
; 
4773         struct sockaddr_storage ss
; 
4774         struct sockaddr 
*saddr 
= (struct sockaddr
*)&ss
; 
4776         if (!nmp
->nm_saddr
) { 
4780         nfsm_chain_null(&nmreq
); 
4781         nfsm_chain_null(&nmrep
); 
4783         mntvers 
= (nmp
->nm_vers 
== NFS_VER2
) ? RPCMNT_VER1 
: RPCMNT_VER3
; 
4784         mntproto 
= (NM_OMFLAG(nmp
, MNTUDP
) || (nmp
->nm_sotype 
== SOCK_DGRAM
)) ? IPPROTO_UDP 
: IPPROTO_TCP
; 
4785         mntport 
= nmp
->nm_mountport
; 
4787         bcopy(nmp
->nm_saddr
, saddr
, min(sizeof(ss
), nmp
->nm_saddr
->sa_len
)); 
4788         if (saddr
->sa_family 
== AF_INET
) { 
4789                 ((struct sockaddr_in
*)saddr
)->sin_port 
= htons(mntport
); 
4790         } else if (saddr
->sa_family 
== AF_INET6
) { 
4791                 ((struct sockaddr_in6
*)saddr
)->sin6_port 
= htons(mntport
); 
4792         } else { /* Local domain socket */ 
4793                 mntport 
= ((struct sockaddr_un 
*)saddr
)->sun_path
[0]; /* Do we have and address? */ 
4797                 error 
= nfs_portmap_lookup(nmp
, ctx
, saddr
, NULL
, RPCPROG_MNT
, mntvers
, mntproto
, timeo
); 
4799                 if (saddr
->sa_family 
== AF_INET
) { 
4800                         mntport 
= ntohs(((struct sockaddr_in
*)saddr
)->sin_port
); 
4801                 } else if (saddr
->sa_family 
== AF_INET6
) { 
4802                         mntport 
= ntohs(((struct sockaddr_in6
*)saddr
)->sin6_port
); 
4803                 } else { /* Local domain socket */ 
4804                         mntport 
= ((struct sockaddr_un 
*)saddr
)->sun_path
[0]; /* Do we have and address? */ 
4806                 /* if not found and mntvers > VER1, then retry with VER1 */ 
4808                         if (mntvers 
> RPCMNT_VER1
) { 
4809                                 mntvers 
= RPCMNT_VER1
; 
4810                         } else if (mntproto 
== IPPROTO_TCP
) { 
4811                                 mntproto 
= IPPROTO_UDP
; 
4812                                 mntvers 
= (nmp
->nm_vers 
== NFS_VER2
) ? RPCMNT_VER1 
: RPCMNT_VER3
; 
4816                         bcopy(nmp
->nm_saddr
, saddr
, min(sizeof(ss
), nmp
->nm_saddr
->sa_len
)); 
4819         nfsmout_if(!mntport
); 
4821         /* MOUNT protocol UNMOUNT request */ 
4822         path 
= &vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
[0]; 
4823         while (*path 
&& (*path 
!= '/')) { 
4826         slen 
= strlen(path
); 
4827         nfsm_chain_build_alloc_init(error
, &nmreq
, NFSX_UNSIGNED 
+ nfsm_rndup(slen
)); 
4828         nfsm_chain_add_name(error
, &nmreq
, path
, slen
, nmp
); 
4829         nfsm_chain_build_done(error
, &nmreq
); 
4831         error 
= nfsm_rpchead2(nmp
, (mntproto 
== IPPROTO_UDP
) ? SOCK_DGRAM 
: SOCK_STREAM
, 
4832             RPCPROG_MNT
, RPCMNT_VER1
, RPCMNT_UMOUNT
, 
4833             RPCAUTH_SYS
, cred
, NULL
, nmreq
.nmc_mhead
, &xid
, &mreq
); 
4835         nmreq
.nmc_mhead 
= NULL
; 
4836         error 
= nfs_aux_request(nmp
, thd
, saddr
, NULL
, 
4837             ((mntproto 
== IPPROTO_UDP
) ? SOCK_DGRAM 
: SOCK_STREAM
), 
4838             mreq
, R_XID32(xid
), 1, timeo
, &nmrep
); 
4840         nfsm_chain_cleanup(&nmreq
); 
4841         nfsm_chain_cleanup(&nmrep
); 
4845  * unmount system call 
4851         __unused vfs_context_t ctx
) 
4853         struct nfsmount 
*nmp
; 
4855         int error
, flags 
= 0; 
4856         struct timespec ts 
= { .tv_sec 
= 1, .tv_nsec 
= 0 }; 
4859         lck_mtx_lock(&nmp
->nm_lock
); 
4861          * Set the flag indicating that an unmount attempt is in progress. 
4863         nmp
->nm_state 
|= NFSSTA_UNMOUNTING
; 
4865          * During a force unmount we want to... 
4866          *   Mark that we are doing a force unmount. 
4867          *   Make the mountpoint soft. 
4869         if (mntflags 
& MNT_FORCE
) { 
4870                 flags 
|= FORCECLOSE
; 
4871                 nmp
->nm_state 
|= NFSSTA_FORCE
; 
4872                 NFS_BITMAP_SET(nmp
->nm_flags
, NFS_MFLAG_SOFT
); 
4875          * Wait for any in-progress monitored node scan to complete. 
4877         while (nmp
->nm_state 
& NFSSTA_MONITOR_SCAN
) { 
4878                 msleep(&nmp
->nm_state
, &nmp
->nm_lock
, PZERO 
- 1, "nfswaitmonscan", &ts
); 
4881          * Goes something like this.. 
4882          * - Call vflush() to clear out vnodes for this file system, 
4883          *   except for the swap files. Deal with them in 2nd pass. 
4884          * - Decrement reference on the vnode representing remote root. 
4885          * - Clean up the NFS mount structure. 
4887         vp 
= NFSTOV(nmp
->nm_dnp
); 
4888         lck_mtx_unlock(&nmp
->nm_lock
); 
4891          * vflush will check for busy vnodes on mountpoint. 
4892          * Will do the right thing for MNT_FORCE. That is, we should 
4893          * not get EBUSY back. 
4895         error 
= vflush(mp
, vp
, SKIPSWAP 
| flags
); 
4896         if (mntflags 
& MNT_FORCE
) { 
4897                 error 
= vflush(mp
, NULLVP
, flags
); /* locks vp in the process */ 
4899                 if (vnode_isinuse(vp
, 1)) { 
4902                         error 
= vflush(mp
, vp
, flags
); 
4906                 lck_mtx_lock(&nmp
->nm_lock
); 
4907                 nmp
->nm_state 
&= ~NFSSTA_UNMOUNTING
; 
4908                 lck_mtx_unlock(&nmp
->nm_lock
); 
4912         lck_mtx_lock(&nmp
->nm_lock
); 
4914         lck_mtx_unlock(&nmp
->nm_lock
); 
4917          * Release the root vnode reference held by mountnfs() 
4919         error 
= vnode_get(vp
); 
4925         vflush(mp
, NULLVP
, FORCECLOSE
); 
4927         /* Wait for all other references to be released and free the mount */ 
4928         nfs_mount_drain_and_cleanup(nmp
); 
4934  * cleanup/destroy NFS fs locations structure 
4937 nfs_fs_locations_cleanup(struct nfs_fs_locations 
*nfslsp
) 
4939         struct nfs_fs_location 
*fsl
; 
4940         struct nfs_fs_server 
*fss
; 
4941         struct nfs_fs_path 
*fsp
; 
4942         uint32_t loc
, serv
, addr
, comp
; 
4944         /* free up fs locations */ 
4945         if (!nfslsp
->nl_numlocs 
|| !nfslsp
->nl_locations
) { 
4949         for (loc 
= 0; loc 
< nfslsp
->nl_numlocs
; loc
++) { 
4950                 fsl 
= nfslsp
->nl_locations
[loc
]; 
4954                 if ((fsl
->nl_servcount 
> 0) && fsl
->nl_servers
) { 
4955                         for (serv 
= 0; serv 
< fsl
->nl_servcount
; serv
++) { 
4956                                 fss 
= fsl
->nl_servers
[serv
]; 
4960                                 if ((fss
->ns_addrcount 
> 0) && fss
->ns_addresses
) { 
4961                                         for (addr 
= 0; addr 
< fss
->ns_addrcount
; addr
++) { 
4962                                                 FREE(fss
->ns_addresses
[addr
], M_TEMP
); 
4964                                         FREE(fss
->ns_addresses
, M_TEMP
); 
4966                                 FREE(fss
->ns_name
, M_TEMP
); 
4969                         FREE(fsl
->nl_servers
, M_TEMP
); 
4971                 fsp 
= &fsl
->nl_path
; 
4972                 if (fsp
->np_compcount 
&& fsp
->np_components
) { 
4973                         for (comp 
= 0; comp 
< fsp
->np_compcount
; comp
++) { 
4974                                 if (fsp
->np_components
[comp
]) { 
4975                                         FREE(fsp
->np_components
[comp
], M_TEMP
); 
4978                         FREE(fsp
->np_components
, M_TEMP
); 
4982         FREE(nfslsp
->nl_locations
, M_TEMP
); 
4983         nfslsp
->nl_numlocs 
= 0; 
4984         nfslsp
->nl_locations 
= NULL
; 
4988 nfs_mount_rele(struct nfsmount 
*nmp
) 
4992         lck_mtx_lock(&nmp
->nm_lock
); 
4993         if (nmp
->nm_ref 
< 1) { 
4994                 panic("nfs zombie mount underflow\n"); 
4997         if (nmp
->nm_ref 
== 0) { 
4998                 wup 
= nmp
->nm_state 
& NFSSTA_MOUNT_DRAIN
; 
5000         lck_mtx_unlock(&nmp
->nm_lock
); 
5002                 wakeup(&nmp
->nm_ref
); 
5007 nfs_mount_drain_and_cleanup(struct nfsmount 
*nmp
) 
5009         lck_mtx_lock(&nmp
->nm_lock
); 
5010         nmp
->nm_state 
|= NFSSTA_MOUNT_DRAIN
; 
5011         while (nmp
->nm_ref 
> 0) { 
5012                 msleep(&nmp
->nm_ref
, &nmp
->nm_lock
, PZERO 
- 1, "nfs_mount_drain", NULL
); 
5014         assert(nmp
->nm_ref 
== 0); 
5015         lck_mtx_unlock(&nmp
->nm_lock
); 
5016         nfs_mount_cleanup(nmp
); 
5023 nfs_mount_zombie(struct nfsmount 
*nmp
, int nm_state_flags
) 
5025         struct nfsreq 
*req
, *treq
; 
5026         struct nfs_reqqhead iodq
, resendq
; 
5027         struct timespec ts 
= { .tv_sec 
= 1, .tv_nsec 
= 0 }; 
5028         struct nfs_open_owner 
*noop
, *nextnoop
; 
5032         lck_mtx_lock(&nmp
->nm_lock
); 
5033         nmp
->nm_state 
|= nm_state_flags
; 
5035         lck_mtx_unlock(&nmp
->nm_lock
); 
5037         /* stop callbacks */ 
5038         if ((nmp
->nm_vers 
>= NFS_VER4
) && !NMFLAG(nmp
, NOCALLBACK
) && nmp
->nm_cbid
) { 
5039                 nfs4_mount_callback_shutdown(nmp
); 
5043         /* Destroy any RPCSEC_GSS contexts */ 
5044         nfs_gss_clnt_ctx_unmount(nmp
); 
5047         /* mark the socket for termination */ 
5048         lck_mtx_lock(&nmp
->nm_lock
); 
5049         nmp
->nm_sockflags 
|= NMSOCK_UNMOUNT
; 
5051         /* Have the socket thread send the unmount RPC, if requested/appropriate. */ 
5052         if ((nmp
->nm_vers 
< NFS_VER4
) && (nmp
->nm_state 
& NFSSTA_MOUNTED
) && 
5053             !(nmp
->nm_state 
& (NFSSTA_FORCE 
| NFSSTA_DEAD
)) && NMFLAG(nmp
, CALLUMNT
)) { 
5054                 nfs_mount_sock_thread_wake(nmp
); 
5057         /* wait for the socket thread to terminate */ 
5058         while (nmp
->nm_sockthd 
&& current_thread() != nmp
->nm_sockthd
) { 
5059                 wakeup(&nmp
->nm_sockthd
); 
5060                 msleep(&nmp
->nm_sockthd
, &nmp
->nm_lock
, PZERO 
- 1, "nfswaitsockthd", &ts
); 
5062         lck_mtx_unlock(&nmp
->nm_lock
); 
5064         /* tear down the socket */ 
5065         nfs_disconnect(nmp
); 
5067         lck_mtx_lock(&nmp
->nm_lock
); 
5070         if ((nmp
->nm_vers 
>= NFS_VER4
) && !NMFLAG(nmp
, NOCALLBACK
) && nmp
->nm_cbid
) { 
5071                 /* clear out any pending delegation return requests */ 
5072                 while ((np 
= TAILQ_FIRST(&nmp
->nm_dreturnq
))) { 
5073                         TAILQ_REMOVE(&nmp
->nm_dreturnq
, np
, n_dreturn
); 
5074                         np
->n_dreturn
.tqe_next 
= NFSNOLIST
; 
5078         /* cancel any renew timer */ 
5079         if ((nmp
->nm_vers 
>= NFS_VER4
) && nmp
->nm_renew_timer
) { 
5080                 thread_call_cancel(nmp
->nm_renew_timer
); 
5081                 thread_call_free(nmp
->nm_renew_timer
); 
5082                 nmp
->nm_renew_timer 
= NULL
; 
5085         lck_mtx_unlock(&nmp
->nm_lock
); 
5087         if (nmp
->nm_state 
& NFSSTA_MOUNTED
) { 
5088                 switch (nmp
->nm_lockmode
) { 
5089                 case NFS_LOCK_MODE_DISABLED
: 
5090                 case NFS_LOCK_MODE_LOCAL
: 
5092                 case NFS_LOCK_MODE_ENABLED
: 
5094                         if (nmp
->nm_vers 
<= NFS_VER3
) { 
5095                                 nfs_lockd_mount_unregister(nmp
); 
5096                                 nmp
->nm_lockmode 
= NFS_LOCK_MODE_DISABLED
; 
5103         if ((nmp
->nm_vers 
>= NFS_VER4
) && nmp
->nm_longid
) { 
5104                 /* remove/deallocate the client ID data */ 
5105                 lck_mtx_lock(nfs_global_mutex
); 
5106                 TAILQ_REMOVE(&nfsclientids
, nmp
->nm_longid
, nci_link
); 
5107                 if (nmp
->nm_longid
->nci_id
) { 
5108                         FREE(nmp
->nm_longid
->nci_id
, M_TEMP
); 
5110                 FREE(nmp
->nm_longid
, M_TEMP
); 
5111                 nmp
->nm_longid 
= NULL
; 
5112                 lck_mtx_unlock(nfs_global_mutex
); 
5116          * Be sure all requests for this mount are completed 
5117          * and removed from the resend queue. 
5119         TAILQ_INIT(&resendq
); 
5120         lck_mtx_lock(nfs_request_mutex
); 
5121         TAILQ_FOREACH(req
, &nfs_reqq
, r_chain
) { 
5122                 if (req
->r_nmp 
== nmp
) { 
5123                         lck_mtx_lock(&req
->r_mtx
); 
5124                         if (!req
->r_error 
&& req
->r_nmrep
.nmc_mhead 
== NULL
) { 
5127                         if (req
->r_flags 
& R_RESENDQ
) { 
5128                                 lck_mtx_lock(&nmp
->nm_lock
); 
5129                                 if ((req
->r_flags 
& R_RESENDQ
) && req
->r_rchain
.tqe_next 
!= NFSREQNOLIST
) { 
5130                                         TAILQ_REMOVE(&nmp
->nm_resendq
, req
, r_rchain
); 
5131                                         req
->r_flags 
&= ~R_RESENDQ
; 
5132                                         req
->r_rchain
.tqe_next 
= NFSREQNOLIST
; 
5134                                          * Queue up the request so that we can unreference them 
5135                                          * with out holding nfs_request_mutex 
5137                                         TAILQ_INSERT_TAIL(&resendq
, req
, r_rchain
); 
5139                                 lck_mtx_unlock(&nmp
->nm_lock
); 
5142                         lck_mtx_unlock(&req
->r_mtx
); 
5145         lck_mtx_unlock(nfs_request_mutex
); 
5147         /* Since we've drop the request mutex we can now safely unreference the request */ 
5148         TAILQ_FOREACH_SAFE(req
, &resendq
, r_rchain
, treq
) { 
5149                 TAILQ_REMOVE(&resendq
, req
, r_rchain
); 
5150                 /* Make sure we don't try and remove again in nfs_request_destroy */ 
5151                 req
->r_rchain
.tqe_next 
= NFSREQNOLIST
; 
5152                 nfs_request_rele(req
); 
5156          * Now handle and outstanding async requests. We need to walk the 
5157          * request queue again this time with the nfsiod_mutex held. No 
5158          * other iods can grab our requests until we've put them on our own 
5159          * local iod queue for processing. 
5162         lck_mtx_lock(nfs_request_mutex
); 
5163         lck_mtx_lock(nfsiod_mutex
); 
5164         TAILQ_FOREACH(req
, &nfs_reqq
, r_chain
) { 
5165                 if (req
->r_nmp 
== nmp
) { 
5166                         lck_mtx_lock(&req
->r_mtx
); 
5167                         if (req
->r_callback
.rcb_func
 
5168                             && !(req
->r_flags 
& R_WAITSENT
) && !(req
->r_flags 
& R_IOD
)) { 
5170                                  * Since R_IOD is not set then we need to handle it. If 
5171                                  * we're not on a list add it to our iod queue. Otherwise 
5172                                  * we must already be on nm_iodq which is added to our 
5173                                  * local queue below. 
5174                                  * %%% We should really keep a back pointer to our iod queue 
5177                                 req
->r_flags 
|= R_IOD
; 
5178                                 if (req
->r_achain
.tqe_next 
== NFSREQNOLIST
) { 
5179                                         TAILQ_INSERT_TAIL(&iodq
, req
, r_achain
); 
5182                         lck_mtx_unlock(&req
->r_mtx
); 
5186         /* finish any async I/O RPCs queued up */ 
5187         if (nmp
->nm_iodlink
.tqe_next 
!= NFSNOLIST
) { 
5188                 TAILQ_REMOVE(&nfsiodmounts
, nmp
, nm_iodlink
); 
5190         TAILQ_CONCAT(&iodq
, &nmp
->nm_iodq
, r_achain
); 
5191         lck_mtx_unlock(nfsiod_mutex
); 
5192         lck_mtx_unlock(nfs_request_mutex
); 
5194         TAILQ_FOREACH_SAFE(req
, &iodq
, r_achain
, treq
) { 
5195                 TAILQ_REMOVE(&iodq
, req
, r_achain
); 
5196                 req
->r_achain
.tqe_next 
= NFSREQNOLIST
; 
5197                 lck_mtx_lock(&req
->r_mtx
); 
5198                 docallback 
= !(req
->r_flags 
& R_WAITSENT
); 
5199                 lck_mtx_unlock(&req
->r_mtx
); 
5201                         req
->r_callback
.rcb_func(req
); 
5205         /* clean up common state */ 
5206         lck_mtx_lock(&nmp
->nm_lock
); 
5207         while ((np 
= LIST_FIRST(&nmp
->nm_monlist
))) { 
5208                 LIST_REMOVE(np
, n_monlink
); 
5209                 np
->n_monlink
.le_next 
= NFSNOLIST
; 
5211         TAILQ_FOREACH_SAFE(noop
, &nmp
->nm_open_owners
, noo_link
, nextnoop
) { 
5212                 os_ref_count_t newcount
; 
5214                 TAILQ_REMOVE(&nmp
->nm_open_owners
, noop
, noo_link
); 
5215                 noop
->noo_flags 
&= ~NFS_OPEN_OWNER_LINK
; 
5216                 newcount 
= os_ref_release_locked(&noop
->noo_refcnt
); 
5221                 nfs_open_owner_destroy(noop
); 
5223         lck_mtx_unlock(&nmp
->nm_lock
); 
5226         /* clean up NFSv4 state */ 
5227         if (nmp
->nm_vers 
>= NFS_VER4
) { 
5228                 lck_mtx_lock(&nmp
->nm_lock
); 
5229                 while ((np 
= TAILQ_FIRST(&nmp
->nm_delegations
))) { 
5230                         TAILQ_REMOVE(&nmp
->nm_delegations
, np
, n_dlink
); 
5231                         np
->n_dlink
.tqe_next 
= NFSNOLIST
; 
5233                 lck_mtx_unlock(&nmp
->nm_lock
); 
5236         nfs_mount_rele(nmp
); 
5240  * cleanup/destroy an nfsmount 
5243 nfs_mount_cleanup(struct nfsmount 
*nmp
) 
5249         nfs_mount_zombie(nmp
, 0); 
5251         NFS_VFS_DBG("Unmounting %s from %s\n", 
5252             vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
, 
5253             vfs_statfs(nmp
->nm_mountp
)->f_mntonname
); 
5254         NFS_VFS_DBG("nfs state = 0x%8.8x\n", nmp
->nm_state
); 
5255         NFS_VFS_DBG("nfs socket flags = 0x%8.8x\n", nmp
->nm_sockflags
); 
5256         NFS_VFS_DBG("nfs mount ref count is %d\n", nmp
->nm_ref
); 
5257         NFS_VFS_DBG("mount ref count is %d\n", nmp
->nm_mountp
->mnt_count
); 
5259         if (nmp
->nm_mountp
) { 
5260                 vfs_setfsprivate(nmp
->nm_mountp
, NULL
); 
5263         lck_mtx_lock(&nmp
->nm_lock
); 
5265                 panic("Some one has grabbed a ref %d state flags = 0x%8.8x\n", nmp
->nm_ref
, nmp
->nm_state
); 
5268         if (nmp
->nm_saddr
) { 
5269                 FREE(nmp
->nm_saddr
, M_SONAME
); 
5271         if ((nmp
->nm_vers 
< NFS_VER4
) && nmp
->nm_rqsaddr
) { 
5272                 FREE(nmp
->nm_rqsaddr
, M_SONAME
); 
5275         if (IS_VALID_CRED(nmp
->nm_mcred
)) { 
5276                 kauth_cred_unref(&nmp
->nm_mcred
); 
5279         nfs_fs_locations_cleanup(&nmp
->nm_locations
); 
5281         if (nmp
->nm_realm
) { 
5282                 FREE(nmp
->nm_realm
, M_TEMP
); 
5284         if (nmp
->nm_principal
) { 
5285                 FREE(nmp
->nm_principal
, M_TEMP
); 
5287         if (nmp
->nm_sprinc
) { 
5288                 FREE(nmp
->nm_sprinc
, M_TEMP
); 
5292                 xb_free(nmp
->nm_args
); 
5295         lck_mtx_unlock(&nmp
->nm_lock
); 
5297         lck_mtx_destroy(&nmp
->nm_lock
, nfs_mount_grp
); 
5299                 NFS_ZFREE(nfs_fhandle_zone
, nmp
->nm_fh
); 
5303         NFS_ZFREE(nfsmnt_zone
, nmp
); 
5307  * Return root of a filesystem 
5310 nfs_vfs_root(mount_t mp
, vnode_t 
*vpp
, __unused vfs_context_t ctx
) 
5313         struct nfsmount 
*nmp
; 
5318         if (!nmp 
|| !nmp
->nm_dnp
) { 
5321         vp 
= NFSTOV(nmp
->nm_dnp
); 
5322         vpid 
= vnode_vid(vp
); 
5323         while ((error 
= vnode_getwithvid(vp
, vpid
))) { 
5324                 /* vnode_get() may return ENOENT if the dir changes. */ 
5325                 /* If that happens, just try it again, else return the error. */ 
5326                 if ((error 
!= ENOENT
) || (vnode_vid(vp
) == vpid
)) { 
5329                 vpid 
= vnode_vid(vp
); 
5336  * Do operations associated with quotas 
5341         __unused mount_t mp
, 
5344         __unused caddr_t datap
, 
5345         __unused vfs_context_t context
) 
5352 nfs_sa_getport(struct sockaddr 
*sa
, int *error
) 
5356         if (sa
->sa_family 
== AF_INET6
) { 
5357                 port 
= ntohs(((struct sockaddr_in6
*)sa
)->sin6_port
); 
5358         } else if (sa
->sa_family 
== AF_INET
) { 
5359                 port 
= ntohs(((struct sockaddr_in
*)sa
)->sin_port
); 
5368 nfs_sa_setport(struct sockaddr 
*sa
, in_port_t port
) 
5370         if (sa
->sa_family 
== AF_INET6
) { 
5371                 ((struct sockaddr_in6
*)sa
)->sin6_port 
= htons(port
); 
5372         } else if (sa
->sa_family 
== AF_INET
) { 
5373                 ((struct sockaddr_in
*)sa
)->sin_port 
= htons(port
); 
5378 nfs3_getquota(struct nfsmount 
*nmp
, vfs_context_t ctx
, uid_t id
, int type
, struct dqblk 
*dqb
) 
5380         int error 
= 0, timeo
; 
5381         int rqproto
, rqvers 
= (type 
== GRPQUOTA
) ? RPCRQUOTA_EXT_VER 
: RPCRQUOTA_VER
; 
5382         in_port_t rqport 
= 0; 
5383         thread_t thd 
= vfs_context_thread(ctx
); 
5384         kauth_cred_t cred 
= vfs_context_ucred(ctx
); 
5386         uint64_t slen
, xid 
= 0; 
5387         struct nfsm_chain nmreq
, nmrep
; 
5389         uint32_t val 
= 0, bsize 
= 0; 
5390         struct sockaddr 
*rqsaddr
; 
5392         struct timespec ts 
= { .tv_sec 
= 1, .tv_nsec 
= 0 }; 
5394         if (!nmp
->nm_saddr
) { 
5398         if (NMFLAG(nmp
, NOQUOTA
) || nmp
->nm_saddr
->sa_family 
== AF_LOCAL 
/* XXX for now */) { 
5403          * Allocate an address for rquotad if needed 
5405         if (!nmp
->nm_rqsaddr
) { 
5408                 MALLOC(rqsaddr
, struct sockaddr 
*, sizeof(struct sockaddr_storage
), M_SONAME
, M_WAITOK 
| M_ZERO
); 
5409                 bcopy(nmp
->nm_saddr
, rqsaddr
, min(sizeof(struct sockaddr_storage
), nmp
->nm_saddr
->sa_len
)); 
5410                 /* Set the port to zero, will call rpcbind to get the port below */ 
5411                 nfs_sa_setport(rqsaddr
, 0); 
5414                 lck_mtx_lock(&nmp
->nm_lock
); 
5415                 if (!nmp
->nm_rqsaddr
) { 
5416                         nmp
->nm_rqsaddr 
= rqsaddr
; 
5417                         nmp
->nm_rqsaddrstamp 
= now
.tv_sec
; 
5421                 lck_mtx_unlock(&nmp
->nm_lock
); 
5423                         FREE(rqsaddr
, M_SONAME
); 
5427         timeo 
= NMFLAG(nmp
, SOFT
) ? 10 : 60; 
5428         rqproto 
= IPPROTO_UDP
; /* XXX should prefer TCP if mount is TCP */ 
5430         /* check if we have a recently cached rquota port */ 
5432         lck_mtx_lock(&nmp
->nm_lock
); 
5433         rqsaddr 
= nmp
->nm_rqsaddr
; 
5434         rqport 
= nfs_sa_getport(rqsaddr
, &error
); 
5435         while (!error 
&& (!rqport 
|| ((nmp
->nm_rqsaddrstamp 
+ 60) <= (uint32_t)now
.tv_sec
))) { 
5436                 error 
= nfs_sigintr(nmp
, NULL
, thd
, 1); 
5438                         lck_mtx_unlock(&nmp
->nm_lock
); 
5441                 if (nmp
->nm_state 
& NFSSTA_RQUOTAINPROG
) { 
5442                         nmp
->nm_state 
|= NFSSTA_WANTRQUOTA
; 
5443                         msleep(&nmp
->nm_rqsaddr
, &nmp
->nm_lock
, PZERO 
- 1, "nfswaitrquotaaddr", &ts
); 
5444                         rqport 
= nfs_sa_getport(rqsaddr
, &error
); 
5447                 nmp
->nm_state 
|= NFSSTA_RQUOTAINPROG
; 
5448                 lck_mtx_unlock(&nmp
->nm_lock
); 
5450                 /* send portmap request to get rquota port */ 
5451                 error 
= nfs_portmap_lookup(nmp
, ctx
, rqsaddr
, NULL
, RPCPROG_RQUOTA
, rqvers
, rqproto
, timeo
); 
5455                 rqport 
= nfs_sa_getport(rqsaddr
, &error
); 
5462                          * We overload PMAPPORT for the port if rquotad is not 
5463                          * currently registered or up at the server.  In the 
5464                          * while loop above, port will be set and we will defer 
5465                          * for a bit.  Perhaps the service isn't online yet. 
5467                          * Note that precludes using indirect, but we're not doing 
5471                         nfs_sa_setport(rqsaddr
, rqport
); 
5474                 nmp
->nm_rqsaddrstamp 
= now
.tv_sec
; 
5476                 lck_mtx_lock(&nmp
->nm_lock
); 
5477                 nmp
->nm_state 
&= ~NFSSTA_RQUOTAINPROG
; 
5478                 if (nmp
->nm_state 
& NFSSTA_WANTRQUOTA
) { 
5479                         nmp
->nm_state 
&= ~NFSSTA_WANTRQUOTA
; 
5480                         wakeup(&nmp
->nm_rqsaddr
); 
5483         lck_mtx_unlock(&nmp
->nm_lock
); 
5488         /* Using PMAPPORT for unavailabe rquota service */ 
5489         if (rqport 
== PMAPPORT
) { 
5493         /* rquota request */ 
5494         nfsm_chain_null(&nmreq
); 
5495         nfsm_chain_null(&nmrep
); 
5496         path 
= &vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
[0]; 
5497         while (*path 
&& (*path 
!= '/')) { 
5500         slen 
= strlen(path
); 
5501         nfsm_chain_build_alloc_init(error
, &nmreq
, 3 * NFSX_UNSIGNED 
+ nfsm_rndup(slen
)); 
5502         nfsm_chain_add_name(error
, &nmreq
, path
, slen
, nmp
); 
5503         if (type 
== GRPQUOTA
) { 
5504                 nfsm_chain_add_32(error
, &nmreq
, type
); 
5506         nfsm_chain_add_32(error
, &nmreq
, id
); 
5507         nfsm_chain_build_done(error
, &nmreq
); 
5509         error 
= nfsm_rpchead2(nmp
, (rqproto 
== IPPROTO_UDP
) ? SOCK_DGRAM 
: SOCK_STREAM
, 
5510             RPCPROG_RQUOTA
, rqvers
, RPCRQUOTA_GET
, 
5511             RPCAUTH_SYS
, cred
, NULL
, nmreq
.nmc_mhead
, &xid
, &mreq
); 
5513         nmreq
.nmc_mhead 
= NULL
; 
5514         error 
= nfs_aux_request(nmp
, thd
, rqsaddr
, NULL
, 
5515             (rqproto 
== IPPROTO_UDP
) ? SOCK_DGRAM 
: SOCK_STREAM
, 
5516             mreq
, R_XID32(xid
), 0, timeo
, &nmrep
); 
5519         /* parse rquota response */ 
5520         nfsm_chain_get_32(error
, &nmrep
, val
); 
5521         if (!error 
&& (val 
!= RQUOTA_STAT_OK
)) { 
5522                 if (val 
== RQUOTA_STAT_NOQUOTA
) { 
5524                 } else if (val 
== RQUOTA_STAT_EPERM
) { 
5530         nfsm_chain_get_32(error
, &nmrep
, bsize
); 
5531         nfsm_chain_adv(error
, &nmrep
, NFSX_UNSIGNED
); 
5532         nfsm_chain_get_32(error
, &nmrep
, val
); 
5534         dqb
->dqb_bhardlimit 
= (uint64_t)val 
* bsize
; 
5535         nfsm_chain_get_32(error
, &nmrep
, val
); 
5537         dqb
->dqb_bsoftlimit 
= (uint64_t)val 
* bsize
; 
5538         nfsm_chain_get_32(error
, &nmrep
, val
); 
5540         dqb
->dqb_curbytes 
= (uint64_t)val 
* bsize
; 
5541         nfsm_chain_get_32(error
, &nmrep
, dqb
->dqb_ihardlimit
); 
5542         nfsm_chain_get_32(error
, &nmrep
, dqb
->dqb_isoftlimit
); 
5543         nfsm_chain_get_32(error
, &nmrep
, dqb
->dqb_curinodes
); 
5544         nfsm_chain_get_32(error
, &nmrep
, dqb
->dqb_btime
); 
5545         nfsm_chain_get_32(error
, &nmrep
, dqb
->dqb_itime
); 
5549         nfsm_chain_cleanup(&nmreq
); 
5550         nfsm_chain_cleanup(&nmrep
); 
5555 nfs4_getquota(struct nfsmount 
*nmp
, vfs_context_t ctx
, uid_t id
, int type
, struct dqblk 
*dqb
) 
5558         int error 
= 0, status
, nfsvers
, numops
; 
5560         struct nfsm_chain nmreq
, nmrep
; 
5561         uint32_t bitmap
[NFS_ATTR_BITMAP_LEN
]; 
5562         thread_t thd 
= vfs_context_thread(ctx
); 
5563         kauth_cred_t cred 
= vfs_context_ucred(ctx
); 
5564         struct nfsreq_secinfo_args si
; 
5566         if (type 
!= USRQUOTA
) { /* NFSv4 only supports user quotas */ 
5570         /* first check that the server supports any of the quota attributes */ 
5571         if (!NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_QUOTA_AVAIL_HARD
) && 
5572             !NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_QUOTA_AVAIL_SOFT
) && 
5573             !NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_QUOTA_USED
)) { 
5578          * The credential passed to the server needs to have 
5579          * an effective uid that matches the given uid. 
5581         if (id 
!= kauth_cred_getuid(cred
)) { 
5582                 struct posix_cred temp_pcred
; 
5583                 posix_cred_t pcred 
= posix_cred_get(cred
); 
5584                 bzero(&temp_pcred
, sizeof(temp_pcred
)); 
5585                 temp_pcred
.cr_uid 
= id
; 
5586                 temp_pcred
.cr_ngroups 
= pcred
->cr_ngroups
; 
5587                 bcopy(pcred
->cr_groups
, temp_pcred
.cr_groups
, sizeof(temp_pcred
.cr_groups
)); 
5588                 cred 
= posix_cred_create(&temp_pcred
); 
5589                 if (!IS_VALID_CRED(cred
)) { 
5593                 kauth_cred_ref(cred
); 
5596         nfsvers 
= nmp
->nm_vers
; 
5601         if (error 
|| ((error 
= vnode_get(NFSTOV(np
))))) { 
5602                 kauth_cred_unref(&cred
); 
5606         NFSREQ_SECINFO_SET(&si
, np
, NULL
, 0, NULL
, 0); 
5607         nfsm_chain_null(&nmreq
); 
5608         nfsm_chain_null(&nmrep
); 
5612         nfsm_chain_build_alloc_init(error
, &nmreq
, 15 * NFSX_UNSIGNED
); 
5613         nfsm_chain_add_compound_header(error
, &nmreq
, "quota", nmp
->nm_minor_vers
, numops
); 
5615         nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
); 
5616         nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, np
->n_fhp
, np
->n_fhsize
); 
5618         nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
); 
5619         NFS_CLEAR_ATTRIBUTES(bitmap
); 
5620         NFS_BITMAP_SET(bitmap
, NFS_FATTR_QUOTA_AVAIL_HARD
); 
5621         NFS_BITMAP_SET(bitmap
, NFS_FATTR_QUOTA_AVAIL_SOFT
); 
5622         NFS_BITMAP_SET(bitmap
, NFS_FATTR_QUOTA_USED
); 
5623         nfsm_chain_add_bitmap_supported(error
, &nmreq
, bitmap
, nmp
, NULL
); 
5624         nfsm_chain_build_done(error
, &nmreq
); 
5625         nfsm_assert(error
, (numops 
== 0), EPROTO
); 
5627         error 
= nfs_request2(np
, NULL
, &nmreq
, NFSPROC4_COMPOUND
, thd
, cred
, &si
, 0, &nmrep
, &xid
, &status
); 
5628         nfsm_chain_skip_tag(error
, &nmrep
); 
5629         nfsm_chain_get_32(error
, &nmrep
, numops
); 
5630         nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
); 
5631         nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
); 
5632         nfsm_assert(error
, NFSTONMP(np
), ENXIO
); 
5634         error 
= nfs4_parsefattr(&nmrep
, NULL
, NULL
, NULL
, dqb
, NULL
); 
5636         nfsm_assert(error
, NFSTONMP(np
), ENXIO
); 
5638         nfsm_chain_cleanup(&nmreq
); 
5639         nfsm_chain_cleanup(&nmrep
); 
5640         vnode_put(NFSTOV(np
)); 
5641         kauth_cred_unref(&cred
); 
5644 #endif /* CONFIG_NFS4 */ 
5646 nfs_vfs_quotactl(mount_t mp
, int cmds
, uid_t uid
, caddr_t datap
, vfs_context_t ctx
) 
5648         struct nfsmount 
*nmp
; 
5649         int cmd
, type
, error
, nfsvers
; 
5650         uid_t euid 
= kauth_cred_getuid(vfs_context_ucred(ctx
)); 
5651         struct dqblk 
*dqb 
= (struct dqblk
*)datap
; 
5654         if (nfs_mount_gone(nmp
)) { 
5657         nfsvers 
= nmp
->nm_vers
; 
5663         /* we can only support Q_GETQUOTA */ 
5664         cmd 
= cmds 
>> SUBCMDSHIFT
; 
5679         type 
= cmds 
& SUBCMDMASK
; 
5680         if ((u_int
)type 
>= MAXQUOTAS
) { 
5683         if ((uid 
!= euid
) && ((error 
= vfs_context_suser(ctx
)))) { 
5687         if (vfs_busy(mp
, LK_NOWAIT
)) { 
5690         bzero(dqb
, sizeof(*dqb
)); 
5691         error 
= nmp
->nm_funcs
->nf_getquota(nmp
, ctx
, uid
, type
, dqb
); 
5698  * Flush out the buffer cache 
5700 int nfs_sync_callout(vnode_t
, void *); 
5702 struct nfs_sync_cargs 
{ 
5709 nfs_sync_callout(vnode_t vp
, void *arg
) 
5711         struct nfs_sync_cargs 
*cargs 
= (struct nfs_sync_cargs
*)arg
; 
5712         nfsnode_t np 
= VTONFS(vp
); 
5715         if (np
->n_flag 
& NREVOKE
) { 
5716                 vn_revoke(vp
, REVOKEALL
, cargs
->ctx
); 
5717                 return VNODE_RETURNED
; 
5720         if (LIST_EMPTY(&np
->n_dirtyblkhd
)) { 
5721                 return VNODE_RETURNED
; 
5723         if (np
->n_wrbusy 
> 0) { 
5724                 return VNODE_RETURNED
; 
5726         if (np
->n_bflag 
& (NBFLUSHINPROG 
| NBINVALINPROG
)) { 
5727                 return VNODE_RETURNED
; 
5730         error 
= nfs_flush(np
, cargs
->waitfor
, vfs_context_thread(cargs
->ctx
), 0); 
5732                 cargs
->error 
= error
; 
5735         return VNODE_RETURNED
; 
5739 nfs_vfs_sync(mount_t mp
, int waitfor
, vfs_context_t ctx
) 
5741         struct nfs_sync_cargs cargs
; 
5743         cargs
.waitfor 
= waitfor
; 
5747         vnode_iterate(mp
, 0, nfs_sync_callout
, &cargs
); 
5753  * NFS flat namespace lookup. 
5754  * Currently unsupported. 
5759         __unused mount_t mp
, 
5760         __unused ino64_t ino
, 
5761         __unused vnode_t 
*vpp
, 
5762         __unused vfs_context_t ctx
) 
5768  * At this point, this should never happen 
5773         __unused mount_t mp
, 
5775         __unused 
unsigned char *fhp
, 
5776         __unused vnode_t 
*vpp
, 
5777         __unused vfs_context_t ctx
) 
5783  * Vnode pointer to File handle, should never happen either 
5788         __unused vnode_t vp
, 
5789         __unused 
int *fhlenp
, 
5790         __unused 
unsigned char *fhp
, 
5791         __unused vfs_context_t ctx
) 
5797  * Vfs start routine, a no-op. 
5802         __unused mount_t mp
, 
5804         __unused vfs_context_t ctx
) 
5810  * Build the mount info buffer for NFS_MOUNTINFO. 
5813 nfs_mountinfo_assemble(struct nfsmount 
*nmp
, struct xdrbuf 
*xb
) 
5815         struct xdrbuf xbinfo
, xborig
; 
5817         uint32_t origargsvers
, origargslength
; 
5818         size_t infolength_offset
, curargsopaquelength_offset
, curargslength_offset
, attrslength_offset
, curargs_end_offset
, end_offset
; 
5819         uint32_t miattrs
[NFS_MIATTR_BITMAP_LEN
]; 
5820         uint32_t miflags_mask
[NFS_MIFLAG_BITMAP_LEN
]; 
5821         uint32_t miflags
[NFS_MIFLAG_BITMAP_LEN
]; 
5822         uint32_t mattrs
[NFS_MATTR_BITMAP_LEN
]; 
5823         uint32_t mflags_mask
[NFS_MFLAG_BITMAP_LEN
]; 
5824         uint32_t mflags
[NFS_MFLAG_BITMAP_LEN
]; 
5825         uint32_t loc
, serv
, addr
, comp
; 
5826         int i
, timeo
, error 
= 0; 
5828         /* set up mount info attr and flag bitmaps */ 
5829         NFS_BITMAP_ZERO(miattrs
, NFS_MIATTR_BITMAP_LEN
); 
5830         NFS_BITMAP_SET(miattrs
, NFS_MIATTR_FLAGS
); 
5831         NFS_BITMAP_SET(miattrs
, NFS_MIATTR_ORIG_ARGS
); 
5832         NFS_BITMAP_SET(miattrs
, NFS_MIATTR_CUR_ARGS
); 
5833         NFS_BITMAP_SET(miattrs
, NFS_MIATTR_CUR_LOC_INDEX
); 
5834         NFS_BITMAP_ZERO(miflags_mask
, NFS_MIFLAG_BITMAP_LEN
); 
5835         NFS_BITMAP_ZERO(miflags
, NFS_MIFLAG_BITMAP_LEN
); 
5836         NFS_BITMAP_SET(miflags_mask
, NFS_MIFLAG_DEAD
); 
5837         NFS_BITMAP_SET(miflags_mask
, NFS_MIFLAG_NOTRESP
); 
5838         NFS_BITMAP_SET(miflags_mask
, NFS_MIFLAG_RECOVERY
); 
5839         if (nmp
->nm_state 
& NFSSTA_DEAD
) { 
5840                 NFS_BITMAP_SET(miflags
, NFS_MIFLAG_DEAD
); 
5842         if ((nmp
->nm_state 
& (NFSSTA_TIMEO 
| NFSSTA_JUKEBOXTIMEO
)) || 
5843             ((nmp
->nm_state 
& NFSSTA_LOCKTIMEO
) && (nmp
->nm_lockmode 
== NFS_LOCK_MODE_ENABLED
))) { 
5844                 NFS_BITMAP_SET(miflags
, NFS_MIFLAG_NOTRESP
); 
5846         if (nmp
->nm_state 
& NFSSTA_RECOVER
) { 
5847                 NFS_BITMAP_SET(miflags
, NFS_MIFLAG_RECOVERY
); 
5850         /* get original mount args length */ 
5851         xb_init_buffer(&xborig
, nmp
->nm_args
, 2 * XDRWORD
); 
5852         xb_get_32(error
, &xborig
, origargsvers
); /* version */ 
5853         xb_get_32(error
, &xborig
, origargslength
); /* args length */ 
5856         /* set up current mount attributes bitmap */ 
5857         NFS_BITMAP_ZERO(mattrs
, NFS_MATTR_BITMAP_LEN
); 
5858         NFS_BITMAP_SET(mattrs
, NFS_MATTR_FLAGS
); 
5859         NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_VERSION
); 
5861         if (nmp
->nm_vers 
>= NFS_VER4
) { 
5862                 NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_MINOR_VERSION
); 
5865         NFS_BITMAP_SET(mattrs
, NFS_MATTR_READ_SIZE
); 
5866         NFS_BITMAP_SET(mattrs
, NFS_MATTR_WRITE_SIZE
); 
5867         NFS_BITMAP_SET(mattrs
, NFS_MATTR_READDIR_SIZE
); 
5868         NFS_BITMAP_SET(mattrs
, NFS_MATTR_READAHEAD
); 
5869         NFS_BITMAP_SET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MIN
); 
5870         NFS_BITMAP_SET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MAX
); 
5871         NFS_BITMAP_SET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MIN
); 
5872         NFS_BITMAP_SET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MAX
); 
5873         NFS_BITMAP_SET(mattrs
, NFS_MATTR_LOCK_MODE
); 
5874         NFS_BITMAP_SET(mattrs
, NFS_MATTR_SECURITY
); 
5875         if (nmp
->nm_etype
.selected 
< nmp
->nm_etype
.count
) { 
5876                 NFS_BITMAP_SET(mattrs
, NFS_MATTR_KERB_ETYPE
); 
5878         NFS_BITMAP_SET(mattrs
, NFS_MATTR_MAX_GROUP_LIST
); 
5879         NFS_BITMAP_SET(mattrs
, NFS_MATTR_SOCKET_TYPE
); 
5880         if (nmp
->nm_saddr
->sa_family 
!= AF_LOCAL
) { 
5881                 NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_PORT
); 
5883         if ((nmp
->nm_vers 
< NFS_VER4
) && nmp
->nm_mountport 
&& !nmp
->nm_mount_localport
) { 
5884                 NFS_BITMAP_SET(mattrs
, NFS_MATTR_MOUNT_PORT
); 
5886         NFS_BITMAP_SET(mattrs
, NFS_MATTR_REQUEST_TIMEOUT
); 
5887         if (NMFLAG(nmp
, SOFT
)) { 
5888                 NFS_BITMAP_SET(mattrs
, NFS_MATTR_SOFT_RETRY_COUNT
); 
5890         if (nmp
->nm_deadtimeout
) { 
5891                 NFS_BITMAP_SET(mattrs
, NFS_MATTR_DEAD_TIMEOUT
); 
5894                 NFS_BITMAP_SET(mattrs
, NFS_MATTR_FH
); 
5896         NFS_BITMAP_SET(mattrs
, NFS_MATTR_FS_LOCATIONS
); 
5897         NFS_BITMAP_SET(mattrs
, NFS_MATTR_MNTFLAGS
); 
5898         if (origargsvers 
< NFS_ARGSVERSION_XDR
) { 
5899                 NFS_BITMAP_SET(mattrs
, NFS_MATTR_MNTFROM
); 
5901         if (nmp
->nm_realm
) { 
5902                 NFS_BITMAP_SET(mattrs
, NFS_MATTR_REALM
); 
5904         if (nmp
->nm_principal
) { 
5905                 NFS_BITMAP_SET(mattrs
, NFS_MATTR_PRINCIPAL
); 
5907         if (nmp
->nm_sprinc
) { 
5908                 NFS_BITMAP_SET(mattrs
, NFS_MATTR_SVCPRINCIPAL
); 
5910         if (nmp
->nm_nfs_localport
) { 
5911                 NFS_BITMAP_SET(mattrs
, NFS_MATTR_LOCAL_NFS_PORT
); 
5913         if ((nmp
->nm_vers 
< NFS_VER4
) && nmp
->nm_mount_localport
) { 
5914                 NFS_BITMAP_SET(mattrs
, NFS_MATTR_LOCAL_MOUNT_PORT
); 
5917         /* set up current mount flags bitmap */ 
5918         /* first set the flags that we will be setting - either on OR off */ 
5919         NFS_BITMAP_ZERO(mflags_mask
, NFS_MFLAG_BITMAP_LEN
); 
5920         NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_SOFT
); 
5921         NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_INTR
); 
5922         NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_RESVPORT
); 
5923         if (nmp
->nm_sotype 
== SOCK_DGRAM
) { 
5924                 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NOCONNECT
); 
5926         NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_DUMBTIMER
); 
5927         if (nmp
->nm_vers 
< NFS_VER4
) { 
5928                 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_CALLUMNT
); 
5930         if (nmp
->nm_vers 
>= NFS_VER3
) { 
5931                 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_RDIRPLUS
); 
5933         NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NONEGNAMECACHE
); 
5934         NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_MUTEJUKEBOX
); 
5936         if (nmp
->nm_vers 
>= NFS_VER4
) { 
5937                 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_EPHEMERAL
); 
5938                 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NOCALLBACK
); 
5939                 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NAMEDATTR
); 
5940                 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NOACL
); 
5941                 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_ACLONLY
); 
5944         NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NFC
); 
5945         NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NOQUOTA
); 
5946         if (nmp
->nm_vers 
< NFS_VER4
) { 
5947                 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_MNTUDP
); 
5949         NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_MNTQUICK
); 
5950         /* now set the flags that should be set */ 
5951         NFS_BITMAP_ZERO(mflags
, NFS_MFLAG_BITMAP_LEN
); 
5952         if (NMFLAG(nmp
, SOFT
)) { 
5953                 NFS_BITMAP_SET(mflags
, NFS_MFLAG_SOFT
); 
5955         if (NMFLAG(nmp
, INTR
)) { 
5956                 NFS_BITMAP_SET(mflags
, NFS_MFLAG_INTR
); 
5958         if (NMFLAG(nmp
, RESVPORT
)) { 
5959                 NFS_BITMAP_SET(mflags
, NFS_MFLAG_RESVPORT
); 
5961         if ((nmp
->nm_sotype 
== SOCK_DGRAM
) && NMFLAG(nmp
, NOCONNECT
)) { 
5962                 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NOCONNECT
); 
5964         if (NMFLAG(nmp
, DUMBTIMER
)) { 
5965                 NFS_BITMAP_SET(mflags
, NFS_MFLAG_DUMBTIMER
); 
5967         if ((nmp
->nm_vers 
< NFS_VER4
) && NMFLAG(nmp
, CALLUMNT
)) { 
5968                 NFS_BITMAP_SET(mflags
, NFS_MFLAG_CALLUMNT
); 
5970         if ((nmp
->nm_vers 
>= NFS_VER3
) && NMFLAG(nmp
, RDIRPLUS
)) { 
5971                 NFS_BITMAP_SET(mflags
, NFS_MFLAG_RDIRPLUS
); 
5973         if (NMFLAG(nmp
, NONEGNAMECACHE
)) { 
5974                 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NONEGNAMECACHE
); 
5976         if (NMFLAG(nmp
, MUTEJUKEBOX
)) { 
5977                 NFS_BITMAP_SET(mflags
, NFS_MFLAG_MUTEJUKEBOX
); 
5980         if (nmp
->nm_vers 
>= NFS_VER4
) { 
5981                 if (NMFLAG(nmp
, EPHEMERAL
)) { 
5982                         NFS_BITMAP_SET(mflags
, NFS_MFLAG_EPHEMERAL
); 
5984                 if (NMFLAG(nmp
, NOCALLBACK
)) { 
5985                         NFS_BITMAP_SET(mflags
, NFS_MFLAG_NOCALLBACK
); 
5987                 if (NMFLAG(nmp
, NAMEDATTR
)) { 
5988                         NFS_BITMAP_SET(mflags
, NFS_MFLAG_NAMEDATTR
); 
5990                 if (NMFLAG(nmp
, NOACL
)) { 
5991                         NFS_BITMAP_SET(mflags
, NFS_MFLAG_NOACL
); 
5993                 if (NMFLAG(nmp
, ACLONLY
)) { 
5994                         NFS_BITMAP_SET(mflags
, NFS_MFLAG_ACLONLY
); 
5998         if (NMFLAG(nmp
, NFC
)) { 
5999                 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NFC
); 
6001         if (NMFLAG(nmp
, NOQUOTA
) || ((nmp
->nm_vers 
>= NFS_VER4
) && 
6002             !NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_QUOTA_AVAIL_HARD
) && 
6003             !NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_QUOTA_AVAIL_SOFT
) && 
6004             !NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_QUOTA_USED
))) { 
6005                 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NOQUOTA
); 
6007         if ((nmp
->nm_vers 
< NFS_VER4
) && NMFLAG(nmp
, MNTUDP
)) { 
6008                 NFS_BITMAP_SET(mflags
, NFS_MFLAG_MNTUDP
); 
6010         if (NMFLAG(nmp
, MNTQUICK
)) { 
6011                 NFS_BITMAP_SET(mflags
, NFS_MFLAG_MNTQUICK
); 
6014         /* assemble info buffer: */ 
6015         xb_init_buffer(&xbinfo
, NULL
, 0); 
6016         xb_add_32(error
, &xbinfo
, NFS_MOUNT_INFO_VERSION
); 
6017         infolength_offset 
= xb_offset(&xbinfo
); 
6018         xb_add_32(error
, &xbinfo
, 0); 
6019         xb_add_bitmap(error
, &xbinfo
, miattrs
, NFS_MIATTR_BITMAP_LEN
); 
6020         xb_add_bitmap(error
, &xbinfo
, miflags
, NFS_MIFLAG_BITMAP_LEN
); 
6021         xb_add_32(error
, &xbinfo
, origargslength
); 
6023                 error 
= xb_add_bytes(&xbinfo
, nmp
->nm_args
, origargslength
, 0); 
6026         /* the opaque byte count for the current mount args values: */ 
6027         curargsopaquelength_offset 
= xb_offset(&xbinfo
); 
6028         xb_add_32(error
, &xbinfo
, 0); 
6030         /* Encode current mount args values */ 
6031         xb_add_32(error
, &xbinfo
, NFS_ARGSVERSION_XDR
); 
6032         curargslength_offset 
= xb_offset(&xbinfo
); 
6033         xb_add_32(error
, &xbinfo
, 0); 
6034         xb_add_32(error
, &xbinfo
, NFS_XDRARGS_VERSION_0
); 
6035         xb_add_bitmap(error
, &xbinfo
, mattrs
, NFS_MATTR_BITMAP_LEN
); 
6036         attrslength_offset 
= xb_offset(&xbinfo
); 
6037         xb_add_32(error
, &xbinfo
, 0); 
6038         xb_add_bitmap(error
, &xbinfo
, mflags_mask
, NFS_MFLAG_BITMAP_LEN
); 
6039         xb_add_bitmap(error
, &xbinfo
, mflags
, NFS_MFLAG_BITMAP_LEN
); 
6040         xb_add_32(error
, &xbinfo
, nmp
->nm_vers
);                /* NFS_VERSION */ 
6042         if (nmp
->nm_vers 
>= NFS_VER4
) { 
6043                 xb_add_32(error
, &xbinfo
, nmp
->nm_minor_vers
);  /* NFS_MINOR_VERSION */ 
6046         xb_add_32(error
, &xbinfo
, nmp
->nm_rsize
);               /* READ_SIZE */ 
6047         xb_add_32(error
, &xbinfo
, nmp
->nm_wsize
);               /* WRITE_SIZE */ 
6048         xb_add_32(error
, &xbinfo
, nmp
->nm_readdirsize
);         /* READDIR_SIZE */ 
6049         xb_add_32(error
, &xbinfo
, nmp
->nm_readahead
);           /* READAHEAD */ 
6050         xb_add_32(error
, &xbinfo
, nmp
->nm_acregmin
);            /* ATTRCACHE_REG_MIN */ 
6051         xb_add_32(error
, &xbinfo
, 0);                           /* ATTRCACHE_REG_MIN */ 
6052         xb_add_32(error
, &xbinfo
, nmp
->nm_acregmax
);            /* ATTRCACHE_REG_MAX */ 
6053         xb_add_32(error
, &xbinfo
, 0);                           /* ATTRCACHE_REG_MAX */ 
6054         xb_add_32(error
, &xbinfo
, nmp
->nm_acdirmin
);            /* ATTRCACHE_DIR_MIN */ 
6055         xb_add_32(error
, &xbinfo
, 0);                           /* ATTRCACHE_DIR_MIN */ 
6056         xb_add_32(error
, &xbinfo
, nmp
->nm_acdirmax
);            /* ATTRCACHE_DIR_MAX */ 
6057         xb_add_32(error
, &xbinfo
, 0);                           /* ATTRCACHE_DIR_MAX */ 
6058         xb_add_32(error
, &xbinfo
, nmp
->nm_lockmode
);            /* LOCK_MODE */ 
6059         if (nmp
->nm_sec
.count
) { 
6060                 xb_add_32(error
, &xbinfo
, nmp
->nm_sec
.count
);           /* SECURITY */ 
6062                 for (i 
= 0; i 
< nmp
->nm_sec
.count
; i
++) { 
6063                         xb_add_32(error
, &xbinfo
, nmp
->nm_sec
.flavors
[i
]); 
6065         } else if (nmp
->nm_servsec
.count
) { 
6066                 xb_add_32(error
, &xbinfo
, nmp
->nm_servsec
.count
);       /* SECURITY */ 
6068                 for (i 
= 0; i 
< nmp
->nm_servsec
.count
; i
++) { 
6069                         xb_add_32(error
, &xbinfo
, nmp
->nm_servsec
.flavors
[i
]); 
6072                 xb_add_32(error
, &xbinfo
, 1);                           /* SECURITY */ 
6073                 xb_add_32(error
, &xbinfo
, nmp
->nm_auth
); 
6075         if (nmp
->nm_etype
.selected 
< nmp
->nm_etype
.count
) { 
6076                 xb_add_32(error
, &xbinfo
, nmp
->nm_etype
.count
); 
6077                 xb_add_32(error
, &xbinfo
, nmp
->nm_etype
.selected
); 
6078                 for (uint32_t j 
= 0; j 
< nmp
->nm_etype
.count
; j
++) { 
6079                         xb_add_32(error
, &xbinfo
, nmp
->nm_etype
.etypes
[j
]); 
6083         xb_add_32(error
, &xbinfo
, nmp
->nm_numgrps
);             /* MAX_GROUP_LIST */ 
6086         switch (nmp
->nm_saddr
->sa_family
) { 
6089                 snprintf(sotype
, sizeof(sotype
), "%s%s", (nmp
->nm_sotype 
== SOCK_DGRAM
) ? "udp" : "tcp", 
6090                     nmp
->nm_sofamily 
? (nmp
->nm_sofamily 
== AF_INET
) ? "4" : "6" : ""); 
6091                 xb_add_string(error
, &xbinfo
, sotype
, strlen(sotype
));  /* SOCKET_TYPE */ 
6092                 xb_add_32(error
, &xbinfo
, ntohs(((struct sockaddr_in
*)nmp
->nm_saddr
)->sin_port
)); /* NFS_PORT */ 
6093                 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MOUNT_PORT
)) { 
6094                         xb_add_32(error
, &xbinfo
, nmp
->nm_mountport
);   /* MOUNT_PORT */ 
6098                 strlcpy(sotype
, (nmp
->nm_sotype 
== SOCK_DGRAM
) ? "ticlts" : "ticotsord", sizeof(sotype
)); 
6099                 xb_add_string(error
, &xbinfo
, sotype
, strlen(sotype
)); 
6102                 NFS_VFS_DBG("Unsupported address family %d\n", nmp
->nm_saddr
->sa_family
); 
6103                 printf("Unsupported address family %d\n", nmp
->nm_saddr
->sa_family
); 
6108         timeo 
= (nmp
->nm_timeo 
* 10) / NFS_HZ
; 
6109         xb_add_32(error
, &xbinfo
, timeo 
/ 10);                    /* REQUEST_TIMEOUT */ 
6110         xb_add_32(error
, &xbinfo
, (timeo 
% 10) * 100000000);        /* REQUEST_TIMEOUT */ 
6111         if (NMFLAG(nmp
, SOFT
)) { 
6112                 xb_add_32(error
, &xbinfo
, nmp
->nm_retry
);       /* SOFT_RETRY_COUNT */ 
6114         if (nmp
->nm_deadtimeout
) { 
6115                 xb_add_32(error
, &xbinfo
, nmp
->nm_deadtimeout
); /* DEAD_TIMEOUT */ 
6116                 xb_add_32(error
, &xbinfo
, 0);                   /* DEAD_TIMEOUT */ 
6119                 xb_add_fh(error
, &xbinfo
, &nmp
->nm_fh
->fh_data
[0], nmp
->nm_fh
->fh_len
); /* FH */ 
6121         xb_add_32(error
, &xbinfo
, nmp
->nm_locations
.nl_numlocs
);                        /* FS_LOCATIONS */ 
6122         for (loc 
= 0; !error 
&& (loc 
< nmp
->nm_locations
.nl_numlocs
); loc
++) { 
6123                 xb_add_32(error
, &xbinfo
, nmp
->nm_locations
.nl_locations
[loc
]->nl_servcount
); 
6124                 for (serv 
= 0; !error 
&& (serv 
< nmp
->nm_locations
.nl_locations
[loc
]->nl_servcount
); serv
++) { 
6125                         xb_add_string(error
, &xbinfo
, nmp
->nm_locations
.nl_locations
[loc
]->nl_servers
[serv
]->ns_name
, 
6126                             strlen(nmp
->nm_locations
.nl_locations
[loc
]->nl_servers
[serv
]->ns_name
)); 
6127                         xb_add_32(error
, &xbinfo
, nmp
->nm_locations
.nl_locations
[loc
]->nl_servers
[serv
]->ns_addrcount
); 
6128                         for (addr 
= 0; !error 
&& (addr 
< nmp
->nm_locations
.nl_locations
[loc
]->nl_servers
[serv
]->ns_addrcount
); addr
++) { 
6129                                 xb_add_string(error
, &xbinfo
, nmp
->nm_locations
.nl_locations
[loc
]->nl_servers
[serv
]->ns_addresses
[addr
], 
6130                                     strlen(nmp
->nm_locations
.nl_locations
[loc
]->nl_servers
[serv
]->ns_addresses
[addr
])); 
6132                         xb_add_32(error
, &xbinfo
, 0); /* empty server info */ 
6134                 xb_add_32(error
, &xbinfo
, nmp
->nm_locations
.nl_locations
[loc
]->nl_path
.np_compcount
); 
6135                 for (comp 
= 0; !error 
&& (comp 
< nmp
->nm_locations
.nl_locations
[loc
]->nl_path
.np_compcount
); comp
++) { 
6136                         xb_add_string(error
, &xbinfo
, nmp
->nm_locations
.nl_locations
[loc
]->nl_path
.np_components
[comp
], 
6137                             strlen(nmp
->nm_locations
.nl_locations
[loc
]->nl_path
.np_components
[comp
])); 
6139                 xb_add_32(error
, &xbinfo
, 0); /* empty fs location info */ 
6141         xb_add_32(error
, &xbinfo
, vfs_flags(nmp
->nm_mountp
));           /* MNTFLAGS */ 
6142         if (origargsvers 
< NFS_ARGSVERSION_XDR
) { 
6143                 xb_add_string(error
, &xbinfo
, vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
, 
6144                     strlen(vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
));         /* MNTFROM */ 
6146         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_REALM
)) { 
6147                 xb_add_string(error
, &xbinfo
, nmp
->nm_realm
, strlen(nmp
->nm_realm
)); 
6149         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_PRINCIPAL
)) { 
6150                 xb_add_string(error
, &xbinfo
, nmp
->nm_principal
, strlen(nmp
->nm_principal
)); 
6152         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SVCPRINCIPAL
)) { 
6153                 xb_add_string(error
, &xbinfo
, nmp
->nm_sprinc
, strlen(nmp
->nm_sprinc
)); 
6155         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_LOCAL_NFS_PORT
)) { 
6156                 struct sockaddr_un 
*un 
= (struct sockaddr_un 
*)nmp
->nm_saddr
; 
6157                 xb_add_string(error
, &xbinfo
, un
->sun_path
, strlen(un
->sun_path
)); 
6159         if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_LOCAL_MOUNT_PORT
)) { 
6160                 xb_add_string(error
, &xbinfo
, nmp
->nm_mount_localport
, strlen(nmp
->nm_mount_localport
)); 
6162         curargs_end_offset 
= xb_offset(&xbinfo
); 
6164         /* NFS_MIATTR_CUR_LOC_INDEX */ 
6165         xb_add_32(error
, &xbinfo
, nmp
->nm_locations
.nl_current
.nli_flags
); 
6166         xb_add_32(error
, &xbinfo
, nmp
->nm_locations
.nl_current
.nli_loc
); 
6167         xb_add_32(error
, &xbinfo
, nmp
->nm_locations
.nl_current
.nli_serv
); 
6168         xb_add_32(error
, &xbinfo
, nmp
->nm_locations
.nl_current
.nli_addr
); 
6170         xb_build_done(error
, &xbinfo
); 
6172         /* update opaque counts */ 
6173         end_offset 
= xb_offset(&xbinfo
); 
6175                 error 
= xb_seek(&xbinfo
, attrslength_offset
); 
6176                 xb_add_32(error
, &xbinfo
, curargs_end_offset 
- attrslength_offset 
- XDRWORD 
/*don't include length field*/); 
6179                 error 
= xb_seek(&xbinfo
, curargslength_offset
); 
6180                 xb_add_32(error
, &xbinfo
, curargs_end_offset 
- curargslength_offset 
+ XDRWORD 
/*version*/); 
6183                 error 
= xb_seek(&xbinfo
, curargsopaquelength_offset
); 
6184                 xb_add_32(error
, &xbinfo
, curargs_end_offset 
- curargslength_offset 
+ XDRWORD 
/*version*/); 
6187                 error 
= xb_seek(&xbinfo
, infolength_offset
); 
6188                 xb_add_32(error
, &xbinfo
, end_offset 
- infolength_offset 
+ XDRWORD 
/*version*/); 
6192         /* copy result xdrbuf to caller */ 
6195         /* and mark the local copy as not needing cleanup */ 
6196         xbinfo
.xb_flags 
&= ~XB_CLEANUP
; 
6198         xb_cleanup(&xbinfo
); 
6203  * Do that sysctl thang... 
6206 nfs_vfs_sysctl(int *name
, u_int namelen
, user_addr_t oldp
, size_t *oldlenp
, 
6207     user_addr_t newp
, size_t newlen
, vfs_context_t ctx
) 
6210         struct sysctl_req 
*req 
= NULL
; 
6211         union union_vfsidctl vc
; 
6213         struct nfsmount 
*nmp 
= NULL
; 
6216         boolean_t is_64_bit
; 
6219         struct netfs_status 
*nsp 
= NULL
; 
6221         uint totlen
, count
, numThreads
; 
6222 #if CONFIG_NFS_SERVER 
6224         struct nfs_exportfs 
*nxfs
; 
6225         struct nfs_export 
*nx
; 
6226         struct nfs_active_user_list 
*ulist
; 
6227         struct nfs_export_stat_desc stat_desc 
= {}; 
6228         struct nfs_export_stat_rec statrec
; 
6229         struct nfs_user_stat_node 
*unode
, *unode_next
; 
6230         struct nfs_user_stat_desc ustat_desc 
= {}; 
6231         struct nfs_user_stat_user_rec ustat_rec
; 
6232         struct nfs_user_stat_path_rec upath_rec
; 
6233         uint bytes_total
, recs_copied
; 
6235         size_t bytes_avail
, numRecs
; 
6236 #endif /* CONFIG_NFS_SERVER */ 
6239          * All names at this level are terminal. 
6242                 return ENOTDIR
;       /* overloaded */ 
6244         is_64_bit 
= vfs_context_is64bit(ctx
); 
6246         /* common code for "new style" VFS_CTL sysctl, get the mount. */ 
6249         case VFS_CTL_NOLOCKS
: 
6250         case VFS_CTL_NSTATUS
: 
6251 #if defined(XNU_TARGET_OS_OSX) 
6253 #endif /* XNU_TARGET_OS_OSX */ 
6254                 req 
= CAST_DOWN(struct sysctl_req 
*, oldp
); 
6258                 error 
= SYSCTL_IN(req
, &vc
, is_64_bit
? sizeof(vc
.vc64
):sizeof(vc
.vc32
)); 
6262                 mp 
= vfs_getvfs(&vc
.vc32
.vc_fsid
); /* works for 32 and 64 */ 
6270                 bzero(&vq
, sizeof(vq
)); 
6273                         req
->newptr 
= vc
.vc64
.vc_ptr
; 
6274                         req
->newlen 
= (size_t)vc
.vc64
.vc_len
; 
6276                         req
->newptr 
= CAST_USER_ADDR_T(vc
.vc32
.vc_ptr
); 
6277                         req
->newlen 
= vc
.vc32
.vc_len
; 
6280 #if !defined(XNU_TARGET_OS_OSX) 
6283 #endif /* ! XNU_TARGET_OS_OSX */ 
6289                         *oldlenp 
= sizeof nfsstats
; 
6293                 if (*oldlenp 
< sizeof nfsstats
) { 
6294                         *oldlenp 
= sizeof nfsstats
; 
6298                 error 
= copyout(&nfsstats
, oldp
, sizeof nfsstats
); 
6303                 if (newp 
&& newlen 
!= sizeof nfsstats
) { 
6308                         return copyin(newp
, &nfsstats
, sizeof nfsstats
); 
6311         case NFS_NFSZEROSTATS
: 
6312                 bzero(&nfsstats
, sizeof nfsstats
); 
6315                 /* read in the fsid */ 
6316                 if (*oldlenp 
< sizeof(fsid
)) { 
6319                 if ((error 
= copyin(oldp
, &fsid
, sizeof(fsid
)))) { 
6322                 /* swizzle it back to host order */ 
6323                 fsid
.val
[0] = ntohl(fsid
.val
[0]); 
6324                 fsid
.val
[1] = ntohl(fsid
.val
[1]); 
6325                 /* find mount and make sure it's NFS */ 
6326                 if (((mp 
= vfs_getvfs(&fsid
))) == NULL
) { 
6329                 if (strcmp(mp
->mnt_vfsstat
.f_fstypename
, "nfs")) { 
6332                 if (((nmp 
= VFSTONFS(mp
))) == NULL
) { 
6335                 xb_init(&xb
, XDRBUF_NONE
); 
6336                 if ((error 
= nfs_mountinfo_assemble(nmp
, &xb
))) { 
6339                 if (*oldlenp 
< xb
.xb_u
.xb_buffer
.xbb_len
) { 
6342                         error 
= copyout(xb_buffer_base(&xb
), oldp
, xb
.xb_u
.xb_buffer
.xbb_len
); 
6344                 *oldlenp 
= xb
.xb_u
.xb_buffer
.xbb_len
; 
6347 #if CONFIG_NFS_SERVER 
6348         case NFS_EXPORTSTATS
: 
6349                 /* setup export stat descriptor */ 
6350                 stat_desc
.rec_vers 
= NFS_EXPORT_STAT_REC_VERSION
; 
6352                 if (!nfsrv_is_initialized()) { 
6353                         stat_desc
.rec_count 
= 0; 
6354                         if (oldp 
&& (*oldlenp 
>= sizeof(struct nfs_export_stat_desc
))) { 
6355                                 error 
= copyout(&stat_desc
, oldp
, sizeof(struct nfs_export_stat_desc
)); 
6357                         *oldlenp 
= sizeof(struct nfs_export_stat_desc
); 
6361                 /* Count the number of exported directories */ 
6362                 lck_rw_lock_shared(&nfsrv_export_rwlock
); 
6364                 LIST_FOREACH(nxfs
, &nfsrv_exports
, nxfs_next
) 
6365                 LIST_FOREACH(nx
, &nxfs
->nxfs_exports
, nx_next
) 
6368                 /* update stat descriptor's export record count */ 
6369                 stat_desc
.rec_count 
= numExports
; 
6371                 /* calculate total size of required buffer */ 
6372                 totlen 
= sizeof(struct nfs_export_stat_desc
) + (numExports 
* sizeof(struct nfs_export_stat_rec
)); 
6374                 /* Check caller's buffer */ 
6376                         lck_rw_done(&nfsrv_export_rwlock
); 
6377                         /* indicate required buffer len */ 
6382                 /* We require the caller's buffer to be at least large enough to hold the descriptor */ 
6383                 if (*oldlenp 
< sizeof(struct nfs_export_stat_desc
)) { 
6384                         lck_rw_done(&nfsrv_export_rwlock
); 
6385                         /* indicate required buffer len */ 
6390                 /* indicate required buffer len */ 
6393                 /* check if export table is empty */ 
6395                         lck_rw_done(&nfsrv_export_rwlock
); 
6396                         error 
= copyout(&stat_desc
, oldp
, sizeof(struct nfs_export_stat_desc
)); 
6400                 /* calculate how many actual export stat records fit into caller's buffer */ 
6401                 numRecs 
= (*oldlenp 
- sizeof(struct nfs_export_stat_desc
)) / sizeof(struct nfs_export_stat_rec
); 
6404                         /* caller's buffer can only accomodate descriptor */ 
6405                         lck_rw_done(&nfsrv_export_rwlock
); 
6406                         stat_desc
.rec_count 
= 0; 
6407                         error 
= copyout(&stat_desc
, oldp
, sizeof(struct nfs_export_stat_desc
)); 
6411                 /* adjust to actual number of records to copyout to caller's buffer */ 
6412                 if (numRecs 
> numExports
) { 
6413                         numRecs 
= numExports
; 
6416                 /* set actual number of records we are returning */ 
6417                 stat_desc
.rec_count 
= numRecs
; 
6419                 /* first copy out the stat descriptor */ 
6421                 error 
= copyout(&stat_desc
, oldp 
+ pos
, sizeof(struct nfs_export_stat_desc
)); 
6423                         lck_rw_done(&nfsrv_export_rwlock
); 
6426                 pos 
+= sizeof(struct nfs_export_stat_desc
); 
6428                 /* Loop through exported directories */ 
6430                 LIST_FOREACH(nxfs
, &nfsrv_exports
, nxfs_next
) { 
6431                         LIST_FOREACH(nx
, &nxfs
->nxfs_exports
, nx_next
) { 
6432                                 if (count 
>= numRecs
) { 
6436                                 /* build exported filesystem path */ 
6437                                 memset(statrec
.path
, 0, sizeof(statrec
.path
)); 
6438                                 snprintf(statrec
.path
, sizeof(statrec
.path
), "%s%s%s", 
6439                                     nxfs
->nxfs_path
, ((nxfs
->nxfs_path
[1] && nx
->nx_path
[0]) ? "/" : ""), 
6442                                 /* build the 64-bit export stat counters */ 
6443                                 statrec
.ops 
= ((uint64_t)nx
->nx_stats
.ops
.hi 
<< 32) | 
6444                                     nx
->nx_stats
.ops
.lo
; 
6445                                 statrec
.bytes_read 
= ((uint64_t)nx
->nx_stats
.bytes_read
.hi 
<< 32) | 
6446                                     nx
->nx_stats
.bytes_read
.lo
; 
6447                                 statrec
.bytes_written 
= ((uint64_t)nx
->nx_stats
.bytes_written
.hi 
<< 32) | 
6448                                     nx
->nx_stats
.bytes_written
.lo
; 
6449                                 error 
= copyout(&statrec
, oldp 
+ pos
, sizeof(statrec
)); 
6451                                         lck_rw_done(&nfsrv_export_rwlock
); 
6454                                 /* advance buffer position */ 
6455                                 pos 
+= sizeof(statrec
); 
6458                 lck_rw_done(&nfsrv_export_rwlock
); 
6461                 /* init structures used for copying out of kernel */ 
6462                 ustat_desc
.rec_vers 
= NFS_USER_STAT_REC_VERSION
; 
6463                 ustat_rec
.rec_type 
= NFS_USER_STAT_USER_REC
; 
6464                 upath_rec
.rec_type 
= NFS_USER_STAT_PATH_REC
; 
6466                 /* initialize counters */ 
6467                 bytes_total 
= sizeof(struct nfs_user_stat_desc
); 
6468                 bytes_avail  
= *oldlenp
; 
6471                 if (!nfsrv_is_initialized()) { /* NFS server not initialized, so no stats */ 
6475                 /* reclaim old expired user nodes */ 
6476                 nfsrv_active_user_list_reclaim(); 
6478                 /* reserve space for the buffer descriptor */ 
6479                 if (bytes_avail 
>= sizeof(struct nfs_user_stat_desc
)) { 
6480                         bytes_avail 
-= sizeof(struct nfs_user_stat_desc
); 
6485                 /* put buffer position past the buffer descriptor */ 
6486                 pos 
= sizeof(struct nfs_user_stat_desc
); 
6488                 /* Loop through exported directories */ 
6489                 lck_rw_lock_shared(&nfsrv_export_rwlock
); 
6490                 LIST_FOREACH(nxfs
, &nfsrv_exports
, nxfs_next
) { 
6491                         LIST_FOREACH(nx
, &nxfs
->nxfs_exports
, nx_next
) { 
6493                                 if (bytes_avail 
>= sizeof(struct nfs_user_stat_path_rec
)) { 
6494                                         memset(upath_rec
.path
, 0, sizeof(upath_rec
.path
)); 
6495                                         snprintf(upath_rec
.path
, sizeof(upath_rec
.path
), "%s%s%s", 
6496                                             nxfs
->nxfs_path
, ((nxfs
->nxfs_path
[1] && nx
->nx_path
[0]) ? "/" : ""), 
6499                                         error 
= copyout(&upath_rec
, oldp 
+ pos
, sizeof(struct nfs_user_stat_path_rec
)); 
6505                                         pos 
+= sizeof(struct nfs_user_stat_path_rec
); 
6506                                         bytes_avail 
-= sizeof(struct nfs_user_stat_path_rec
); 
6509                                         /* Caller's buffer is exhausted */ 
6513                                 bytes_total 
+= sizeof(struct nfs_user_stat_path_rec
); 
6515                                 /* Scan through all user nodes of this export */ 
6516                                 ulist 
= &nx
->nx_user_list
; 
6517                                 lck_mtx_lock(&ulist
->user_mutex
); 
6518                                 for (unode 
= TAILQ_FIRST(&ulist
->user_lru
); unode
; unode 
= unode_next
) { 
6519                                         unode_next 
= TAILQ_NEXT(unode
, lru_link
); 
6521                                         /* copy out node if there is space */ 
6522                                         if (bytes_avail 
>= sizeof(struct nfs_user_stat_user_rec
)) { 
6523                                                 /* prepare a user stat rec for copying out */ 
6524                                                 ustat_rec
.uid 
= unode
->uid
; 
6525                                                 memset(&ustat_rec
.sock
, 0, sizeof(ustat_rec
.sock
)); 
6526                                                 bcopy(&unode
->sock
, &ustat_rec
.sock
, unode
->sock
.ss_len
); 
6527                                                 ustat_rec
.ops 
= unode
->ops
; 
6528                                                 ustat_rec
.bytes_read 
= unode
->bytes_read
; 
6529                                                 ustat_rec
.bytes_written 
= unode
->bytes_written
; 
6530                                                 ustat_rec
.tm_start 
= unode
->tm_start
; 
6531                                                 ustat_rec
.tm_last 
= unode
->tm_last
; 
6533                                                 error 
= copyout(&ustat_rec
, oldp 
+ pos
, sizeof(struct nfs_user_stat_user_rec
)); 
6537                                                         lck_mtx_unlock(&ulist
->user_mutex
); 
6541                                                 pos 
+= sizeof(struct nfs_user_stat_user_rec
); 
6542                                                 bytes_avail 
-= sizeof(struct nfs_user_stat_user_rec
); 
6545                                                 /* Caller's buffer is exhausted */ 
6548                                         bytes_total 
+= sizeof(struct nfs_user_stat_user_rec
); 
6550                                 /* can unlock this export's list now */ 
6551                                 lck_mtx_unlock(&ulist
->user_mutex
); 
6556                 /* unlock the export table */ 
6557                 lck_rw_done(&nfsrv_export_rwlock
); 
6560                 /* indicate number of actual records copied */ 
6561                 ustat_desc
.rec_count 
= recs_copied
; 
6564                         /* check if there was enough room for the buffer descriptor */ 
6565                         if (*oldlenp 
>= sizeof(struct nfs_user_stat_desc
)) { 
6566                                 error 
= copyout(&ustat_desc
, oldp
, sizeof(struct nfs_user_stat_desc
)); 
6571                         /* always indicate required buffer size */ 
6572                         *oldlenp 
= bytes_total
; 
6577                         *oldlenp 
= sizeof(nfsrv_user_stat_node_count
); 
6581                 if (*oldlenp 
< sizeof(nfsrv_user_stat_node_count
)) { 
6582                         *oldlenp 
= sizeof(nfsrv_user_stat_node_count
); 
6586                 if (nfsrv_is_initialized()) { 
6587                         /* reclaim old expired user nodes */ 
6588                         nfsrv_active_user_list_reclaim(); 
6591                 error 
= copyout(&nfsrv_user_stat_node_count
, oldp
, sizeof(nfsrv_user_stat_node_count
)); 
6593 #endif /* CONFIG_NFS_SERVER */ 
6594         case VFS_CTL_NOLOCKS
: 
6595                 if (req
->oldptr 
!= USER_ADDR_NULL
) { 
6596                         lck_mtx_lock(&nmp
->nm_lock
); 
6597                         val 
= (nmp
->nm_lockmode 
== NFS_LOCK_MODE_DISABLED
) ? 1 : 0; 
6598                         lck_mtx_unlock(&nmp
->nm_lock
); 
6599                         error 
= SYSCTL_OUT(req
, &val
, sizeof(val
)); 
6604                 if (req
->newptr 
!= USER_ADDR_NULL
) { 
6605                         error 
= SYSCTL_IN(req
, &val
, sizeof(val
)); 
6609                         lck_mtx_lock(&nmp
->nm_lock
); 
6610                         if (nmp
->nm_lockmode 
== NFS_LOCK_MODE_LOCAL
) { 
6611                                 /* can't toggle locks when using local locks */ 
6614                         } else if ((nmp
->nm_vers 
>= NFS_VER4
) && val
) { 
6615                                 /* can't disable locks for NFSv4 */ 
6619                                 if ((nmp
->nm_vers 
<= NFS_VER3
) && (nmp
->nm_lockmode 
== NFS_LOCK_MODE_ENABLED
)) { 
6620                                         nfs_lockd_mount_unregister(nmp
); 
6622                                 nmp
->nm_lockmode 
= NFS_LOCK_MODE_DISABLED
; 
6623                                 nmp
->nm_state 
&= ~NFSSTA_LOCKTIMEO
; 
6625                                 if ((nmp
->nm_vers 
<= NFS_VER3
) && (nmp
->nm_lockmode 
== NFS_LOCK_MODE_DISABLED
)) { 
6626                                         nfs_lockd_mount_register(nmp
); 
6628                                 nmp
->nm_lockmode 
= NFS_LOCK_MODE_ENABLED
; 
6630                         lck_mtx_unlock(&nmp
->nm_lock
); 
6633 #if defined(XNU_TARGET_OS_OSX) 
6635                 lck_mtx_lock(&nmp
->nm_lock
); 
6636                 /* XXX don't allow users to know about/disconnect unresponsive, soft, nobrowse mounts */ 
6637                 int softnobrowse 
= (NMFLAG(nmp
, SOFT
) && (vfs_flags(nmp
->nm_mountp
) & MNT_DONTBROWSE
)); 
6638                 if (!softnobrowse 
&& (nmp
->nm_state 
& NFSSTA_TIMEO
)) { 
6639                         vq
.vq_flags 
|= VQ_NOTRESP
; 
6641                 if (!softnobrowse 
&& (nmp
->nm_state 
& NFSSTA_JUKEBOXTIMEO
) && !NMFLAG(nmp
, MUTEJUKEBOX
)) { 
6642                         vq
.vq_flags 
|= VQ_NOTRESP
; 
6644                 if (!softnobrowse 
&& (nmp
->nm_state 
& NFSSTA_LOCKTIMEO
) && 
6645                     (nmp
->nm_lockmode 
== NFS_LOCK_MODE_ENABLED
)) { 
6646                         vq
.vq_flags 
|= VQ_NOTRESP
; 
6648                 if (nmp
->nm_state 
& NFSSTA_DEAD
) { 
6649                         vq
.vq_flags 
|= VQ_DEAD
; 
6651                 lck_mtx_unlock(&nmp
->nm_lock
); 
6652                 error 
= SYSCTL_OUT(req
, &vq
, sizeof(vq
)); 
6654 #endif /* XNU_TARGET_OS_OSX */ 
6656                 if (req
->oldptr 
!= USER_ADDR_NULL
) { 
6657                         lck_mtx_lock(&nmp
->nm_lock
); 
6658                         val 
= nmp
->nm_tprintf_initial_delay
; 
6659                         lck_mtx_unlock(&nmp
->nm_lock
); 
6660                         error 
= SYSCTL_OUT(req
, &val
, sizeof(val
)); 
6665                 if (req
->newptr 
!= USER_ADDR_NULL
) { 
6666                         error 
= SYSCTL_IN(req
, &val
, sizeof(val
)); 
6670                         lck_mtx_lock(&nmp
->nm_lock
); 
6672                                 nmp
->nm_tprintf_initial_delay 
= 0; 
6674                                 nmp
->nm_tprintf_initial_delay 
= val
; 
6676                         lck_mtx_unlock(&nmp
->nm_lock
); 
6679         case VFS_CTL_NSTATUS
: 
6681                  * Return the status of this mount.  This is much more 
6682                  * information than VFS_CTL_QUERY.  In addition to the 
6683                  * vq_flags return the significant mount options along 
6684                  * with the list of threads blocked on the mount and 
6685                  * how long the threads have been waiting. 
6688                 lck_mtx_lock(nfs_request_mutex
); 
6689                 lck_mtx_lock(&nmp
->nm_lock
); 
6692                  * Count the number of requests waiting for a reply. 
6693                  * Note: there could be multiple requests from the same thread. 
6696                 TAILQ_FOREACH(rq
, &nfs_reqq
, r_chain
) { 
6697                         if (rq
->r_nmp 
== nmp
) { 
6702                 /* Calculate total size of result buffer */ 
6703                 totlen 
= sizeof(struct netfs_status
) + (numThreads 
* sizeof(uint64_t)); 
6705                 if (req
->oldptr 
== USER_ADDR_NULL
) {            // Caller is querying buffer size 
6706                         lck_mtx_unlock(&nmp
->nm_lock
); 
6707                         lck_mtx_unlock(nfs_request_mutex
); 
6708                         return SYSCTL_OUT(req
, NULL
, totlen
); 
6710                 if (req
->oldlen 
< totlen
) {     // Check if caller's buffer is big enough 
6711                         lck_mtx_unlock(&nmp
->nm_lock
); 
6712                         lck_mtx_unlock(nfs_request_mutex
); 
6716                 MALLOC(nsp
, struct netfs_status 
*, totlen
, M_TEMP
, M_WAITOK 
| M_ZERO
); 
6718                         lck_mtx_unlock(&nmp
->nm_lock
); 
6719                         lck_mtx_unlock(nfs_request_mutex
); 
6722                 timeoutmask 
= NFSSTA_TIMEO 
| NFSSTA_LOCKTIMEO 
| NFSSTA_JUKEBOXTIMEO
; 
6723                 if (nmp
->nm_state 
& timeoutmask
) { 
6724                         nsp
->ns_status 
|= VQ_NOTRESP
; 
6726                 if (nmp
->nm_state 
& NFSSTA_DEAD
) { 
6727                         nsp
->ns_status 
|= VQ_DEAD
; 
6730                 (void) nfs_mountopts(nmp
, nsp
->ns_mountopts
, sizeof(nsp
->ns_mountopts
)); 
6731                 nsp
->ns_threadcount 
= numThreads
; 
6734                  * Get the thread ids of threads waiting for a reply 
6735                  * and find the longest wait time. 
6737                 if (numThreads 
> 0) { 
6744                         sendtime 
= now
.tv_sec
; 
6745                         TAILQ_FOREACH(rq
, &nfs_reqq
, r_chain
) { 
6746                                 if (rq
->r_nmp 
== nmp
) { 
6747                                         if (rq
->r_start 
< sendtime
) { 
6748                                                 sendtime 
= rq
->r_start
; 
6750                                         // A thread_id of zero is used to represent an async I/O request. 
6751                                         nsp
->ns_threadids
[count
] = 
6752                                             rq
->r_thread 
? thread_tid(rq
->r_thread
) : 0; 
6753                                         if (++count 
>= numThreads
) { 
6758                         waittime 
= now
.tv_sec 
- sendtime
; 
6759                         nsp
->ns_waittime 
= waittime 
> UINT32_MAX 
? UINT32_MAX 
: (uint32_t)waittime
; 
6762                 lck_mtx_unlock(&nmp
->nm_lock
); 
6763                 lck_mtx_unlock(nfs_request_mutex
); 
6765                 error 
= SYSCTL_OUT(req
, nsp
, totlen
); 
6774 #endif /* CONFIG_NFS_CLIENT */