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 */