2 * Copyright (c) 2000-2017 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 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
69 * support for mandatory and extensible security protections. This notice
70 * is included in support of clause 2.2 (b) of the Apple Public License,
74 #include <sys/param.h>
75 #include <sys/systm.h>
77 #include <sys/ioctl.h>
78 #include <sys/signal.h>
79 #include <sys/proc_internal.h> /* for fs rooting to update rootdir in fdp */
80 #include <sys/kauth.h>
81 #include <sys/vnode_internal.h>
82 #include <sys/malloc.h>
83 #include <sys/kernel.h>
84 #include <sys/sysctl.h>
85 #include <sys/mount_internal.h>
86 #include <sys/kpi_mbuf.h>
87 #include <sys/socket.h>
88 #include <sys/socketvar.h>
89 #include <sys/fcntl.h>
90 #include <sys/quota.h>
92 #include <libkern/OSAtomic.h>
95 #include <sys/vmparam.h>
97 #if !defined(NO_MOUNT_PRIVATE)
98 #include <sys/filedesc.h>
99 #endif /* NO_MOUNT_PRIVATE */
102 #include <net/route.h>
103 #include <netinet/in.h>
105 #include <nfs/rpcv2.h>
106 #include <nfs/krpc.h>
107 #include <nfs/nfsproto.h>
109 #include <nfs/nfsnode.h>
110 #include <nfs/nfs_gss.h>
111 #include <nfs/nfsmount.h>
112 #include <nfs/xdr_subs.h>
113 #include <nfs/nfsm_subs.h>
114 #include <nfs/nfsdiskless.h>
115 #include <nfs/nfs_lock.h>
117 #include <security/mac_framework.h>
120 #include <pexpert/pexpert.h>
122 #define NFS_VFS_DBG(...) NFS_DBG(NFS_FAC_VFS, 7, ## __VA_ARGS__)
129 static lck_grp_t
*nfs_global_grp
, *nfs_mount_grp
;
130 lck_mtx_t
*nfs_global_mutex
;
131 uint32_t nfs_fs_attr_bitmap
[NFS_ATTR_BITMAP_LEN
];
132 uint32_t nfs_object_attr_bitmap
[NFS_ATTR_BITMAP_LEN
];
133 uint32_t nfs_getattr_bitmap
[NFS_ATTR_BITMAP_LEN
];
134 struct nfsclientidlist nfsclientids
;
137 struct nfs_reqqhead nfs_reqq
;
138 lck_grp_t
*nfs_request_grp
;
139 lck_mtx_t
*nfs_request_mutex
;
140 thread_call_t nfs_request_timer_call
;
141 int nfs_request_timer_on
;
142 u_int32_t nfs_xid
= 0;
143 u_int32_t nfs_xidwrap
= 0; /* to build a (non-wrapping) 64 bit xid */
145 thread_call_t nfs_buf_timer_call
;
148 lck_grp_t
*nfs_open_grp
;
149 uint32_t nfs_open_owner_seqnum
= 0;
150 uint32_t nfs_lock_owner_seqnum
= 0;
151 thread_call_t nfs4_callback_timer_call
;
152 int nfs4_callback_timer_on
= 0;
153 char nfs4_default_domain
[MAXPATHLEN
];
156 lck_grp_t
*nfsiod_lck_grp
;
157 lck_mtx_t
*nfsiod_mutex
;
158 struct nfsiodlist nfsiodfree
, nfsiodwork
;
159 struct nfsiodmountlist nfsiodmounts
;
160 int nfsiod_thread_count
= 0;
161 int nfsiod_thread_max
= NFS_DEFASYNCTHREAD
;
162 int nfs_max_async_writes
= NFS_DEFMAXASYNCWRITES
;
164 int nfs_iosize
= NFS_IOSIZE
;
165 int nfs_access_cache_timeout
= NFS_MAXATTRTIMO
;
166 int nfs_access_delete
= 1; /* too many servers get this wrong - workaround on by default */
167 int nfs_access_dotzfs
= 1;
168 int nfs_access_for_getattr
= 0;
169 int nfs_allow_async
= 0;
170 int nfs_statfs_rate_limit
= NFS_DEFSTATFSRATELIMIT
;
171 int nfs_lockd_mounts
= 0;
172 int nfs_lockd_request_sent
= 0;
173 int nfs_idmap_ctrl
= NFS_IDMAP_CTRL_USE_IDMAP_SERVICE
;
174 int nfs_callback_port
= 0;
176 int nfs_tprintf_initial_delay
= NFS_TPRINTF_INITIAL_DELAY
;
177 int nfs_tprintf_delay
= NFS_TPRINTF_DELAY
;
180 int mountnfs(char *, mount_t
, vfs_context_t
, vnode_t
*);
181 static int nfs_mount_diskless(struct nfs_dlmount
*, const char *, int, vnode_t
*, mount_t
*, vfs_context_t
);
182 #if !defined(NO_MOUNT_PRIVATE)
183 static int nfs_mount_diskless_private(struct nfs_dlmount
*, const char *, int, vnode_t
*, mount_t
*, vfs_context_t
);
184 #endif /* NO_MOUNT_PRIVATE */
185 int nfs_mount_connect(struct nfsmount
*);
186 void nfs_mount_drain_and_cleanup(struct nfsmount
*);
187 void nfs_mount_cleanup(struct nfsmount
*);
188 int nfs_mountinfo_assemble(struct nfsmount
*, struct xdrbuf
*);
189 int nfs4_mount_update_path_with_symlink(struct nfsmount
*, struct nfs_fs_path
*, uint32_t, fhandle_t
*, int *, fhandle_t
*, vfs_context_t
);
192 * NFS VFS operations.
194 int nfs_vfs_mount(mount_t
, vnode_t
, user_addr_t
, vfs_context_t
);
195 int nfs_vfs_start(mount_t
, int, vfs_context_t
);
196 int nfs_vfs_unmount(mount_t
, int, vfs_context_t
);
197 int nfs_vfs_root(mount_t
, vnode_t
*, vfs_context_t
);
198 int nfs_vfs_quotactl(mount_t
, int, uid_t
, caddr_t
, vfs_context_t
);
199 int nfs_vfs_getattr(mount_t
, struct vfs_attr
*, vfs_context_t
);
200 int nfs_vfs_sync(mount_t
, int, vfs_context_t
);
201 int nfs_vfs_vget(mount_t
, ino64_t
, vnode_t
*, vfs_context_t
);
202 int nfs_vfs_vptofh(vnode_t
, int *, unsigned char *, vfs_context_t
);
203 int nfs_vfs_fhtovp(mount_t
, int, unsigned char *, vnode_t
*, vfs_context_t
);
204 int nfs_vfs_init(struct vfsconf
*);
205 int nfs_vfs_sysctl(int *, u_int
, user_addr_t
, size_t *, user_addr_t
, size_t, vfs_context_t
);
207 const struct vfsops nfs_vfsops
= {
208 .vfs_mount
= nfs_vfs_mount
,
209 .vfs_start
= nfs_vfs_start
,
210 .vfs_unmount
= nfs_vfs_unmount
,
211 .vfs_root
= nfs_vfs_root
,
212 .vfs_quotactl
= nfs_vfs_quotactl
,
213 .vfs_getattr
= nfs_vfs_getattr
,
214 .vfs_sync
= nfs_vfs_sync
,
215 .vfs_vget
= nfs_vfs_vget
,
216 .vfs_fhtovp
= nfs_vfs_fhtovp
,
217 .vfs_vptofh
= nfs_vfs_vptofh
,
218 .vfs_init
= nfs_vfs_init
,
219 .vfs_sysctl
= nfs_vfs_sysctl
,
220 // We do not support the remaining VFS ops
225 * version-specific NFS functions
227 int nfs3_mount(struct nfsmount
*, vfs_context_t
, nfsnode_t
*);
228 int nfs4_mount(struct nfsmount
*, vfs_context_t
, nfsnode_t
*);
229 int nfs3_fsinfo(struct nfsmount
*, nfsnode_t
, vfs_context_t
);
230 int nfs3_update_statfs(struct nfsmount
*, vfs_context_t
);
231 int nfs4_update_statfs(struct nfsmount
*, vfs_context_t
);
233 #define nfs3_getquota NULL
234 #define nfs4_getquota NULL
236 int nfs3_getquota(struct nfsmount
*, vfs_context_t
, uid_t
, int, struct dqblk
*);
237 int nfs4_getquota(struct nfsmount
*, vfs_context_t
, uid_t
, int, struct dqblk
*);
240 const struct nfs_funcs nfs3_funcs
= {
248 nfs3_read_rpc_async_finish
,
250 nfs3_write_rpc_async
,
251 nfs3_write_rpc_async_finish
,
253 nfs3_lookup_rpc_async
,
254 nfs3_lookup_rpc_async_finish
,
261 const struct nfs_funcs nfs4_funcs
= {
269 nfs4_read_rpc_async_finish
,
271 nfs4_write_rpc_async
,
272 nfs4_write_rpc_async_finish
,
274 nfs4_lookup_rpc_async
,
275 nfs4_lookup_rpc_async_finish
,
284 * Called once to initialize data structures...
287 nfs_vfs_init(__unused
struct vfsconf
*vfsp
)
292 * Check to see if major data structures haven't bloated.
294 if (sizeof(struct nfsnode
) > NFS_NODEALLOC
) {
295 printf("struct nfsnode bloated (> %dbytes)\n", NFS_NODEALLOC
);
296 printf("Try reducing NFS_SMALLFH\n");
298 if (sizeof(struct nfsmount
) > NFS_MNTALLOC
) {
299 printf("struct nfsmount bloated (> %dbytes)\n", NFS_MNTALLOC
);
302 nfs_ticks
= (hz
* NFS_TICKINTVL
+ 500) / 1000;
307 /* init async I/O thread pool state */
308 TAILQ_INIT(&nfsiodfree
);
309 TAILQ_INIT(&nfsiodwork
);
310 TAILQ_INIT(&nfsiodmounts
);
311 nfsiod_lck_grp
= lck_grp_alloc_init("nfsiod", LCK_GRP_ATTR_NULL
);
312 nfsiod_mutex
= lck_mtx_alloc_init(nfsiod_lck_grp
, LCK_ATTR_NULL
);
314 /* init lock groups, etc. */
315 nfs_mount_grp
= lck_grp_alloc_init("nfs_mount", LCK_GRP_ATTR_NULL
);
316 nfs_open_grp
= lck_grp_alloc_init("nfs_open", LCK_GRP_ATTR_NULL
);
317 nfs_global_grp
= lck_grp_alloc_init("nfs_global", LCK_GRP_ATTR_NULL
);
319 nfs_global_mutex
= lck_mtx_alloc_init(nfs_global_grp
, LCK_ATTR_NULL
);
321 /* init request list mutex */
322 nfs_request_grp
= lck_grp_alloc_init("nfs_request", LCK_GRP_ATTR_NULL
);
323 nfs_request_mutex
= lck_mtx_alloc_init(nfs_request_grp
, LCK_ATTR_NULL
);
325 /* initialize NFS request list */
326 TAILQ_INIT(&nfs_reqq
);
328 nfs_nbinit(); /* Init the nfsbuf table */
329 nfs_nhinit(); /* Init the nfsnode table */
330 nfs_lockinit(); /* Init the nfs lock state */
331 nfs_gss_init(); /* Init RPCSEC_GSS security */
334 NFS4_PER_FS_ATTRIBUTES(nfs_fs_attr_bitmap
);
335 NFS4_PER_OBJECT_ATTRIBUTES(nfs_object_attr_bitmap
);
336 NFS4_DEFAULT_ATTRIBUTES(nfs_getattr_bitmap
);
337 for (i
= 0; i
< NFS_ATTR_BITMAP_LEN
; i
++) {
338 nfs_getattr_bitmap
[i
] &= nfs_object_attr_bitmap
[i
];
340 TAILQ_INIT(&nfsclientids
);
342 /* initialize NFS timer callouts */
343 nfs_request_timer_call
= thread_call_allocate(nfs_request_timer
, NULL
);
344 nfs_buf_timer_call
= thread_call_allocate(nfs_buf_timer
, NULL
);
345 nfs4_callback_timer_call
= thread_call_allocate(nfs4_callback_timer
, NULL
);
354 nfs3_update_statfs(struct nfsmount
*nmp
, vfs_context_t ctx
)
357 int error
= 0, lockerror
, status
, nfsvers
;
359 struct nfsm_chain nmreq
, nmrep
;
362 nfsvers
= nmp
->nm_vers
;
367 if ((error
= vnode_get(NFSTOV(np
)))) {
371 nfsm_chain_null(&nmreq
);
372 nfsm_chain_null(&nmrep
);
374 nfsm_chain_build_alloc_init(error
, &nmreq
, NFSX_FH(nfsvers
));
375 nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, np
->n_fhp
, np
->n_fhsize
);
376 nfsm_chain_build_done(error
, &nmreq
);
378 error
= nfs_request2(np
, NULL
, &nmreq
, NFSPROC_FSSTAT
, vfs_context_thread(ctx
),
379 vfs_context_ucred(ctx
), NULL
, R_SOFT
, &nmrep
, &xid
, &status
);
380 if (error
== ETIMEDOUT
) {
383 if ((lockerror
= nfs_node_lock(np
))) {
386 if (nfsvers
== NFS_VER3
) {
387 nfsm_chain_postop_attr_update(error
, &nmrep
, np
, &xid
);
395 nfsm_assert(error
, NFSTONMP(np
), ENXIO
);
397 lck_mtx_lock(&nmp
->nm_lock
);
398 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_TOTAL
);
399 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_FREE
);
400 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_AVAIL
);
401 if (nfsvers
== NFS_VER3
) {
402 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_FILES_AVAIL
);
403 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_FILES_TOTAL
);
404 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_FILES_FREE
);
405 nmp
->nm_fsattr
.nfsa_bsize
= NFS_FABLKSIZE
;
406 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_space_total
);
407 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_space_free
);
408 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_space_avail
);
409 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_files_total
);
410 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_files_free
);
411 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_files_avail
);
414 nfsm_chain_adv(error
, &nmrep
, NFSX_UNSIGNED
); // skip tsize?
415 nfsm_chain_get_32(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_bsize
);
416 nfsm_chain_get_32(error
, &nmrep
, val
);
418 if (nmp
->nm_fsattr
.nfsa_bsize
<= 0) {
419 nmp
->nm_fsattr
.nfsa_bsize
= NFS_FABLKSIZE
;
421 nmp
->nm_fsattr
.nfsa_space_total
= (uint64_t)val
* nmp
->nm_fsattr
.nfsa_bsize
;
422 nfsm_chain_get_32(error
, &nmrep
, val
);
424 nmp
->nm_fsattr
.nfsa_space_free
= (uint64_t)val
* nmp
->nm_fsattr
.nfsa_bsize
;
425 nfsm_chain_get_32(error
, &nmrep
, val
);
427 nmp
->nm_fsattr
.nfsa_space_avail
= (uint64_t)val
* nmp
->nm_fsattr
.nfsa_bsize
;
429 lck_mtx_unlock(&nmp
->nm_lock
);
431 nfsm_chain_cleanup(&nmreq
);
432 nfsm_chain_cleanup(&nmrep
);
433 vnode_put(NFSTOV(np
));
438 nfs4_update_statfs(struct nfsmount
*nmp
, vfs_context_t ctx
)
441 int error
= 0, lockerror
, status
, nfsvers
, numops
;
443 struct nfsm_chain nmreq
, nmrep
;
444 uint32_t bitmap
[NFS_ATTR_BITMAP_LEN
];
445 struct nfs_vattr nvattr
;
446 struct nfsreq_secinfo_args si
;
448 nfsvers
= nmp
->nm_vers
;
453 if ((error
= vnode_get(NFSTOV(np
)))) {
457 NFSREQ_SECINFO_SET(&si
, np
, NULL
, 0, NULL
, 0);
458 NVATTR_INIT(&nvattr
);
459 nfsm_chain_null(&nmreq
);
460 nfsm_chain_null(&nmrep
);
464 nfsm_chain_build_alloc_init(error
, &nmreq
, 15 * NFSX_UNSIGNED
);
465 nfsm_chain_add_compound_header(error
, &nmreq
, "statfs", nmp
->nm_minor_vers
, numops
);
467 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
468 nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, np
->n_fhp
, np
->n_fhsize
);
470 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
471 NFS_COPY_ATTRIBUTES(nfs_getattr_bitmap
, bitmap
);
472 NFS4_STATFS_ATTRIBUTES(bitmap
);
473 nfsm_chain_add_bitmap_supported(error
, &nmreq
, bitmap
, nmp
, np
);
474 nfsm_chain_build_done(error
, &nmreq
);
475 nfsm_assert(error
, (numops
== 0), EPROTO
);
477 error
= nfs_request2(np
, NULL
, &nmreq
, NFSPROC4_COMPOUND
,
478 vfs_context_thread(ctx
), vfs_context_ucred(ctx
),
479 NULL
, R_SOFT
, &nmrep
, &xid
, &status
);
480 nfsm_chain_skip_tag(error
, &nmrep
);
481 nfsm_chain_get_32(error
, &nmrep
, numops
);
482 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
483 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
484 nfsm_assert(error
, NFSTONMP(np
), ENXIO
);
486 lck_mtx_lock(&nmp
->nm_lock
);
487 error
= nfs4_parsefattr(&nmrep
, &nmp
->nm_fsattr
, &nvattr
, NULL
, NULL
, NULL
);
488 lck_mtx_unlock(&nmp
->nm_lock
);
490 if ((lockerror
= nfs_node_lock(np
))) {
494 nfs_loadattrcache(np
, &nvattr
, &xid
, 0);
499 nfsm_assert(error
, NFSTONMP(np
), ENXIO
);
501 nmp
->nm_fsattr
.nfsa_bsize
= NFS_FABLKSIZE
;
503 NVATTR_CLEANUP(&nvattr
);
504 nfsm_chain_cleanup(&nmreq
);
505 nfsm_chain_cleanup(&nmrep
);
506 vnode_put(NFSTOV(np
));
511 * Return an NFS volume name from the mntfrom name.
514 nfs_get_volname(struct mount
*mp
, char *volname
, size_t len
)
516 const char *ptr
, *cptr
;
517 const char *mntfrom
= mp
->mnt_vfsstat
.f_mntfromname
;
518 size_t mflen
= strnlen(mntfrom
, MAXPATHLEN
+ 1);
520 if (mflen
> MAXPATHLEN
|| mflen
== 0) {
521 strlcpy(volname
, "Bad volname", len
);
525 /* Move back over trailing slashes */
526 for (ptr
= &mntfrom
[mflen
- 1]; ptr
!= mntfrom
&& *ptr
== '/'; ptr
--) {
530 /* Find first character after the last slash */
532 for (size_t i
= 0; i
< mflen
; i
++) {
533 if (mntfrom
[i
] == '/') {
534 ptr
= &mntfrom
[i
+ 1];
536 /* And the first character after the first colon */
537 else if (cptr
== NULL
&& mntfrom
[i
] == ':') {
538 cptr
= &mntfrom
[i
+ 1];
543 * No slash or nothing after the last slash
544 * use everything past the first colon
546 if (ptr
== NULL
|| *ptr
== '\0') {
549 /* Otherwise use the mntfrom name */
554 mflen
= &mntfrom
[mflen
] - ptr
;
555 len
= mflen
+ 1 < len
? mflen
+ 1 : len
;
557 strlcpy(volname
, ptr
, len
);
561 * The NFS VFS_GETATTR function: "statfs"-type information is retrieved
562 * using the nf_update_statfs() function, and other attributes are cobbled
563 * together from whatever sources we can (getattr, fsinfo, pathconf).
566 nfs_vfs_getattr(mount_t mp
, struct vfs_attr
*fsap
, vfs_context_t ctx
)
568 struct nfsmount
*nmp
;
570 int error
= 0, nfsvers
;
573 if (nfs_mount_gone(nmp
)) {
576 nfsvers
= nmp
->nm_vers
;
578 if (VFSATTR_IS_ACTIVE(fsap
, f_bsize
) ||
579 VFSATTR_IS_ACTIVE(fsap
, f_iosize
) ||
580 VFSATTR_IS_ACTIVE(fsap
, f_blocks
) ||
581 VFSATTR_IS_ACTIVE(fsap
, f_bfree
) ||
582 VFSATTR_IS_ACTIVE(fsap
, f_bavail
) ||
583 VFSATTR_IS_ACTIVE(fsap
, f_bused
) ||
584 VFSATTR_IS_ACTIVE(fsap
, f_files
) ||
585 VFSATTR_IS_ACTIVE(fsap
, f_ffree
)) {
586 int statfsrate
= nfs_statfs_rate_limit
;
590 * Are we rate-limiting statfs RPCs?
591 * (Treat values less than 1 or greater than 1,000,000 as no limit.)
593 if ((statfsrate
> 0) && (statfsrate
< 1000000)) {
598 lck_mtx_lock(&nmp
->nm_lock
);
599 stamp
= (now
.tv_sec
* statfsrate
) + (now
.tv_usec
/ (1000000 / statfsrate
));
600 if (stamp
!= nmp
->nm_fsattrstamp
) {
602 nmp
->nm_fsattrstamp
= stamp
;
606 lck_mtx_unlock(&nmp
->nm_lock
);
609 if (refresh
&& !nfs_use_cache(nmp
)) {
610 error
= nmp
->nm_funcs
->nf_update_statfs(nmp
, ctx
);
612 if ((error
== ESTALE
) || (error
== ETIMEDOUT
)) {
619 lck_mtx_lock(&nmp
->nm_lock
);
620 VFSATTR_RETURN(fsap
, f_iosize
, nfs_iosize
);
621 VFSATTR_RETURN(fsap
, f_bsize
, nmp
->nm_fsattr
.nfsa_bsize
);
622 bsize
= nmp
->nm_fsattr
.nfsa_bsize
;
623 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_TOTAL
)) {
624 VFSATTR_RETURN(fsap
, f_blocks
, nmp
->nm_fsattr
.nfsa_space_total
/ bsize
);
626 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_FREE
)) {
627 VFSATTR_RETURN(fsap
, f_bfree
, nmp
->nm_fsattr
.nfsa_space_free
/ bsize
);
629 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_AVAIL
)) {
630 VFSATTR_RETURN(fsap
, f_bavail
, nmp
->nm_fsattr
.nfsa_space_avail
/ bsize
);
632 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_TOTAL
) &&
633 NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_FREE
)) {
634 VFSATTR_RETURN(fsap
, f_bused
,
635 (nmp
->nm_fsattr
.nfsa_space_total
/ bsize
) -
636 (nmp
->nm_fsattr
.nfsa_space_free
/ bsize
));
638 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_FILES_TOTAL
)) {
639 VFSATTR_RETURN(fsap
, f_files
, nmp
->nm_fsattr
.nfsa_files_total
);
641 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_FILES_FREE
)) {
642 VFSATTR_RETURN(fsap
, f_ffree
, nmp
->nm_fsattr
.nfsa_files_free
);
644 lck_mtx_unlock(&nmp
->nm_lock
);
647 if (VFSATTR_IS_ACTIVE(fsap
, f_vol_name
)) {
648 /*%%% IF fail over support is implemented we may need to take nm_lock */
649 nfs_get_volname(mp
, fsap
->f_vol_name
, MAXPATHLEN
);
650 VFSATTR_SET_SUPPORTED(fsap
, f_vol_name
);
652 if (VFSATTR_IS_ACTIVE(fsap
, f_capabilities
)) {
653 u_int32_t caps
, valid
;
654 nfsnode_t np
= nmp
->nm_dnp
;
656 nfsm_assert(error
, VFSTONFS(mp
) && np
, ENXIO
);
660 lck_mtx_lock(&nmp
->nm_lock
);
663 * The capabilities[] array defines what this volume supports.
665 * The valid[] array defines which bits this code understands
666 * the meaning of (whether the volume has that capability or not).
667 * Any zero bits here means "I don't know what you're asking about"
668 * and the caller cannot tell whether that capability is
672 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SYMLINK_SUPPORT
)) {
673 valid
|= VOL_CAP_FMT_SYMBOLICLINKS
;
674 if (nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_SYMLINK
) {
675 caps
|= VOL_CAP_FMT_SYMBOLICLINKS
;
678 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_LINK_SUPPORT
)) {
679 valid
|= VOL_CAP_FMT_HARDLINKS
;
680 if (nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_LINK
) {
681 caps
|= VOL_CAP_FMT_HARDLINKS
;
684 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_CASE_INSENSITIVE
)) {
685 valid
|= VOL_CAP_FMT_CASE_SENSITIVE
;
686 if (!(nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_CASE_INSENSITIVE
)) {
687 caps
|= VOL_CAP_FMT_CASE_SENSITIVE
;
690 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_CASE_PRESERVING
)) {
691 valid
|= VOL_CAP_FMT_CASE_PRESERVING
;
692 if (nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_CASE_PRESERVING
) {
693 caps
|= VOL_CAP_FMT_CASE_PRESERVING
;
696 /* Note: VOL_CAP_FMT_2TB_FILESIZE is actually used to test for "large file support" */
697 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXFILESIZE
)) {
698 /* Is server's max file size at least 4GB? */
699 if (nmp
->nm_fsattr
.nfsa_maxfilesize
>= 0x100000000ULL
) {
700 caps
|= VOL_CAP_FMT_2TB_FILESIZE
;
702 } else if (nfsvers
>= NFS_VER3
) {
704 * NFSv3 and up supports 64 bits of file size.
705 * So, we'll just assume maxfilesize >= 4GB
707 caps
|= VOL_CAP_FMT_2TB_FILESIZE
;
709 if (nfsvers
>= NFS_VER4
) {
710 caps
|= VOL_CAP_FMT_HIDDEN_FILES
;
711 valid
|= VOL_CAP_FMT_HIDDEN_FILES
;
712 // VOL_CAP_FMT_OPENDENYMODES
713 // caps |= VOL_CAP_FMT_OPENDENYMODES;
714 // valid |= VOL_CAP_FMT_OPENDENYMODES;
716 // no version of nfs supports immutable files
717 caps
|= VOL_CAP_FMT_NO_IMMUTABLE_FILES
;
718 valid
|= VOL_CAP_FMT_NO_IMMUTABLE_FILES
;
720 fsap
->f_capabilities
.capabilities
[VOL_CAPABILITIES_FORMAT
] =
721 // VOL_CAP_FMT_PERSISTENTOBJECTIDS |
722 // VOL_CAP_FMT_SYMBOLICLINKS |
723 // VOL_CAP_FMT_HARDLINKS |
724 // VOL_CAP_FMT_JOURNAL |
725 // VOL_CAP_FMT_JOURNAL_ACTIVE |
726 // VOL_CAP_FMT_NO_ROOT_TIMES |
727 // VOL_CAP_FMT_SPARSE_FILES |
728 // VOL_CAP_FMT_ZERO_RUNS |
729 // VOL_CAP_FMT_CASE_SENSITIVE |
730 // VOL_CAP_FMT_CASE_PRESERVING |
731 // VOL_CAP_FMT_FAST_STATFS |
732 // VOL_CAP_FMT_2TB_FILESIZE |
733 // VOL_CAP_FMT_OPENDENYMODES |
734 // VOL_CAP_FMT_HIDDEN_FILES |
736 fsap
->f_capabilities
.valid
[VOL_CAPABILITIES_FORMAT
] =
737 VOL_CAP_FMT_PERSISTENTOBJECTIDS
|
738 // VOL_CAP_FMT_SYMBOLICLINKS |
739 // VOL_CAP_FMT_HARDLINKS |
740 // VOL_CAP_FMT_JOURNAL |
741 // VOL_CAP_FMT_JOURNAL_ACTIVE |
742 // VOL_CAP_FMT_NO_ROOT_TIMES |
743 // VOL_CAP_FMT_SPARSE_FILES |
744 // VOL_CAP_FMT_ZERO_RUNS |
745 // VOL_CAP_FMT_CASE_SENSITIVE |
746 // VOL_CAP_FMT_CASE_PRESERVING |
747 VOL_CAP_FMT_FAST_STATFS
|
748 VOL_CAP_FMT_2TB_FILESIZE
|
749 // VOL_CAP_FMT_OPENDENYMODES |
750 // VOL_CAP_FMT_HIDDEN_FILES |
754 * We don't support most of the interfaces.
756 * We MAY support locking, but we don't have any easy way of probing.
757 * We can tell if there's no lockd running or if locks have been
758 * disabled for a mount, so we can definitely answer NO in that case.
759 * Any attempt to send a request to lockd to test for locking support
760 * may cause the lazily-launched locking daemons to be started
761 * unnecessarily. So we avoid that. However, we do record if we ever
762 * successfully perform a lock operation on a mount point, so if it
763 * looks like lock ops have worked, we do report that we support them.
766 if (nfsvers
>= NFS_VER4
) {
767 caps
= VOL_CAP_INT_ADVLOCK
| VOL_CAP_INT_FLOCK
;
768 valid
= VOL_CAP_INT_ADVLOCK
| VOL_CAP_INT_FLOCK
;
769 if (nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_ACL
) {
770 caps
|= VOL_CAP_INT_EXTENDED_SECURITY
;
772 valid
|= VOL_CAP_INT_EXTENDED_SECURITY
;
773 if (nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_NAMED_ATTR
) {
774 caps
|= VOL_CAP_INT_EXTENDED_ATTR
;
776 valid
|= VOL_CAP_INT_EXTENDED_ATTR
;
778 if (nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_NAMED_ATTR
) {
779 caps
|= VOL_CAP_INT_NAMEDSTREAMS
;
781 valid
|= VOL_CAP_INT_NAMEDSTREAMS
;
783 } else if (nmp
->nm_lockmode
== NFS_LOCK_MODE_DISABLED
) {
784 /* locks disabled on this mount, so they definitely won't work */
785 valid
= VOL_CAP_INT_ADVLOCK
| VOL_CAP_INT_FLOCK
;
786 } else if (nmp
->nm_state
& NFSSTA_LOCKSWORK
) {
787 caps
= VOL_CAP_INT_ADVLOCK
| VOL_CAP_INT_FLOCK
;
788 valid
= VOL_CAP_INT_ADVLOCK
| VOL_CAP_INT_FLOCK
;
790 fsap
->f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] =
791 // VOL_CAP_INT_SEARCHFS |
792 // VOL_CAP_INT_ATTRLIST |
793 // VOL_CAP_INT_NFSEXPORT |
794 // VOL_CAP_INT_READDIRATTR |
795 // VOL_CAP_INT_EXCHANGEDATA |
796 // VOL_CAP_INT_COPYFILE |
797 // VOL_CAP_INT_ALLOCATE |
798 // VOL_CAP_INT_VOL_RENAME |
799 // VOL_CAP_INT_ADVLOCK |
800 // VOL_CAP_INT_FLOCK |
801 // VOL_CAP_INT_EXTENDED_SECURITY |
802 // VOL_CAP_INT_USERACCESS |
803 // VOL_CAP_INT_MANLOCK |
804 // VOL_CAP_INT_NAMEDSTREAMS |
805 // VOL_CAP_INT_EXTENDED_ATTR |
806 VOL_CAP_INT_REMOTE_EVENT
|
808 fsap
->f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] =
809 VOL_CAP_INT_SEARCHFS
|
810 VOL_CAP_INT_ATTRLIST
|
811 VOL_CAP_INT_NFSEXPORT
|
812 VOL_CAP_INT_READDIRATTR
|
813 VOL_CAP_INT_EXCHANGEDATA
|
814 VOL_CAP_INT_COPYFILE
|
815 VOL_CAP_INT_ALLOCATE
|
816 VOL_CAP_INT_VOL_RENAME
|
817 // VOL_CAP_INT_ADVLOCK |
818 // VOL_CAP_INT_FLOCK |
819 // VOL_CAP_INT_EXTENDED_SECURITY |
820 // VOL_CAP_INT_USERACCESS |
821 // VOL_CAP_INT_MANLOCK |
822 // VOL_CAP_INT_NAMEDSTREAMS |
823 // VOL_CAP_INT_EXTENDED_ATTR |
824 VOL_CAP_INT_REMOTE_EVENT
|
827 fsap
->f_capabilities
.capabilities
[VOL_CAPABILITIES_RESERVED1
] = 0;
828 fsap
->f_capabilities
.valid
[VOL_CAPABILITIES_RESERVED1
] = 0;
830 fsap
->f_capabilities
.capabilities
[VOL_CAPABILITIES_RESERVED2
] = 0;
831 fsap
->f_capabilities
.valid
[VOL_CAPABILITIES_RESERVED2
] = 0;
833 VFSATTR_SET_SUPPORTED(fsap
, f_capabilities
);
834 lck_mtx_unlock(&nmp
->nm_lock
);
837 if (VFSATTR_IS_ACTIVE(fsap
, f_attributes
)) {
838 fsap
->f_attributes
.validattr
.commonattr
= 0;
839 fsap
->f_attributes
.validattr
.volattr
=
840 ATTR_VOL_NAME
| ATTR_VOL_CAPABILITIES
| ATTR_VOL_ATTRIBUTES
;
841 fsap
->f_attributes
.validattr
.dirattr
= 0;
842 fsap
->f_attributes
.validattr
.fileattr
= 0;
843 fsap
->f_attributes
.validattr
.forkattr
= 0;
845 fsap
->f_attributes
.nativeattr
.commonattr
= 0;
846 fsap
->f_attributes
.nativeattr
.volattr
=
847 ATTR_VOL_NAME
| ATTR_VOL_CAPABILITIES
| ATTR_VOL_ATTRIBUTES
;
848 fsap
->f_attributes
.nativeattr
.dirattr
= 0;
849 fsap
->f_attributes
.nativeattr
.fileattr
= 0;
850 fsap
->f_attributes
.nativeattr
.forkattr
= 0;
852 VFSATTR_SET_SUPPORTED(fsap
, f_attributes
);
859 * nfs version 3 fsinfo rpc call
862 nfs3_fsinfo(struct nfsmount
*nmp
, nfsnode_t np
, vfs_context_t ctx
)
864 int error
= 0, lockerror
, status
, nmlocked
= 0;
866 uint32_t val
, prefsize
, maxsize
;
867 struct nfsm_chain nmreq
, nmrep
;
869 nfsm_chain_null(&nmreq
);
870 nfsm_chain_null(&nmrep
);
872 nfsm_chain_build_alloc_init(error
, &nmreq
, NFSX_FH(nmp
->nm_vers
));
873 nfsm_chain_add_fh(error
, &nmreq
, nmp
->nm_vers
, np
->n_fhp
, np
->n_fhsize
);
874 nfsm_chain_build_done(error
, &nmreq
);
876 error
= nfs_request(np
, NULL
, &nmreq
, NFSPROC_FSINFO
, ctx
, NULL
, &nmrep
, &xid
, &status
);
877 if ((lockerror
= nfs_node_lock(np
))) {
880 nfsm_chain_postop_attr_update(error
, &nmrep
, np
, &xid
);
889 lck_mtx_lock(&nmp
->nm_lock
);
892 nfsm_chain_get_32(error
, &nmrep
, maxsize
);
893 nfsm_chain_get_32(error
, &nmrep
, prefsize
);
895 nmp
->nm_fsattr
.nfsa_maxread
= maxsize
;
896 if (prefsize
< nmp
->nm_rsize
) {
897 nmp
->nm_rsize
= (prefsize
+ NFS_FABLKSIZE
- 1) &
898 ~(NFS_FABLKSIZE
- 1);
900 if ((maxsize
> 0) && (maxsize
< nmp
->nm_rsize
)) {
901 nmp
->nm_rsize
= maxsize
& ~(NFS_FABLKSIZE
- 1);
902 if (nmp
->nm_rsize
== 0) {
903 nmp
->nm_rsize
= maxsize
;
906 nfsm_chain_adv(error
, &nmrep
, NFSX_UNSIGNED
); // skip rtmult
908 nfsm_chain_get_32(error
, &nmrep
, maxsize
);
909 nfsm_chain_get_32(error
, &nmrep
, prefsize
);
911 nmp
->nm_fsattr
.nfsa_maxwrite
= maxsize
;
912 if (prefsize
< nmp
->nm_wsize
) {
913 nmp
->nm_wsize
= (prefsize
+ NFS_FABLKSIZE
- 1) &
914 ~(NFS_FABLKSIZE
- 1);
916 if ((maxsize
> 0) && (maxsize
< nmp
->nm_wsize
)) {
917 nmp
->nm_wsize
= maxsize
& ~(NFS_FABLKSIZE
- 1);
918 if (nmp
->nm_wsize
== 0) {
919 nmp
->nm_wsize
= maxsize
;
922 nfsm_chain_adv(error
, &nmrep
, NFSX_UNSIGNED
); // skip wtmult
924 nfsm_chain_get_32(error
, &nmrep
, prefsize
);
926 if ((prefsize
> 0) && (prefsize
< nmp
->nm_readdirsize
)) {
927 nmp
->nm_readdirsize
= prefsize
;
929 if ((nmp
->nm_fsattr
.nfsa_maxread
> 0) &&
930 (nmp
->nm_fsattr
.nfsa_maxread
< nmp
->nm_readdirsize
)) {
931 nmp
->nm_readdirsize
= nmp
->nm_fsattr
.nfsa_maxread
;
934 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_maxfilesize
);
936 nfsm_chain_adv(error
, &nmrep
, 2 * NFSX_UNSIGNED
); // skip time_delta
938 /* convert FS properties to our own flags */
939 nfsm_chain_get_32(error
, &nmrep
, val
);
941 if (val
& NFSV3FSINFO_LINK
) {
942 nmp
->nm_fsattr
.nfsa_flags
|= NFS_FSFLAG_LINK
;
944 if (val
& NFSV3FSINFO_SYMLINK
) {
945 nmp
->nm_fsattr
.nfsa_flags
|= NFS_FSFLAG_SYMLINK
;
947 if (val
& NFSV3FSINFO_HOMOGENEOUS
) {
948 nmp
->nm_fsattr
.nfsa_flags
|= NFS_FSFLAG_HOMOGENEOUS
;
950 if (val
& NFSV3FSINFO_CANSETTIME
) {
951 nmp
->nm_fsattr
.nfsa_flags
|= NFS_FSFLAG_SET_TIME
;
953 nmp
->nm_state
|= NFSSTA_GOTFSINFO
;
954 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXREAD
);
955 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXWRITE
);
956 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXFILESIZE
);
957 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_LINK_SUPPORT
);
958 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SYMLINK_SUPPORT
);
959 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_HOMOGENEOUS
);
960 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_CANSETTIME
);
963 lck_mtx_unlock(&nmp
->nm_lock
);
965 nfsm_chain_cleanup(&nmreq
);
966 nfsm_chain_cleanup(&nmrep
);
971 * Mount a remote root fs via. nfs. This depends on the info in the
972 * nfs_diskless structure that has been filled in properly by some primary
974 * It goes something like this:
975 * - do enough of "ifconfig" by calling ifioctl() so that the system
976 * can talk to the server
977 * - If nfs_diskless.mygateway is filled in, use that address as
979 * - hand craft the swap nfs vnode hanging off a fake mount point
980 * if swdevt[0].sw_dev == NODEV
981 * - build the rootfs mount point and call mountnfs() to do the rest.
986 struct nfs_diskless nd
;
991 #if !defined(NO_MOUNT_PRIVATE)
992 mount_t mppriv
= NULL
;
993 vnode_t vppriv
= NULL
;
994 #endif /* NO_MOUNT_PRIVATE */
998 * Call nfs_boot_init() to fill in the nfs_diskless struct.
999 * Note: networking must already have been configured before
1002 bzero((caddr_t
) &nd
, sizeof(nd
));
1003 error
= nfs_boot_init(&nd
);
1005 panic("nfs_boot_init: unable to initialize NFS root system information, "
1006 "error %d, check configuration: %s\n", error
, PE_boot_args());
1010 * Try NFSv3 first, then fallback to NFSv2.
1011 * Likewise, try TCP first, then fall back to UDP.
1014 sotype
= SOCK_STREAM
;
1017 error
= nfs_boot_getfh(&nd
, v3
, sotype
);
1019 if (error
== EHOSTDOWN
|| error
== EHOSTUNREACH
) {
1020 if (nd
.nd_root
.ndm_mntfrom
) {
1021 FREE_ZONE(nd
.nd_root
.ndm_mntfrom
,
1022 MAXPATHLEN
, M_NAMEI
);
1024 if (nd
.nd_root
.ndm_path
) {
1025 FREE_ZONE(nd
.nd_root
.ndm_path
,
1026 MAXPATHLEN
, M_NAMEI
);
1028 if (nd
.nd_private
.ndm_mntfrom
) {
1029 FREE_ZONE(nd
.nd_private
.ndm_mntfrom
,
1030 MAXPATHLEN
, M_NAMEI
);
1032 if (nd
.nd_private
.ndm_path
) {
1033 FREE_ZONE(nd
.nd_private
.ndm_path
,
1034 MAXPATHLEN
, M_NAMEI
);
1039 if (sotype
== SOCK_STREAM
) {
1040 printf("NFS mount (v3,TCP) failed with error %d, trying UDP...\n", error
);
1041 sotype
= SOCK_DGRAM
;
1044 printf("NFS mount (v3,UDP) failed with error %d, trying v2...\n", error
);
1046 sotype
= SOCK_STREAM
;
1048 } else if (sotype
== SOCK_STREAM
) {
1049 printf("NFS mount (v2,TCP) failed with error %d, trying UDP...\n", error
);
1050 sotype
= SOCK_DGRAM
;
1053 printf("NFS mount (v2,UDP) failed with error %d, giving up...\n", error
);
1057 panic("NFS mount failed: NFS server mountd not responding, check server configuration: %s", PE_boot_args());
1060 panic("NFS mount failed: NFS server refused mount, check server configuration: %s", PE_boot_args());
1062 panic("NFS mount failed with error %d, check configuration: %s", error
, PE_boot_args());
1066 ctx
= vfs_context_kernel();
1069 * Create the root mount point.
1071 #if !defined(NO_MOUNT_PRIVATE)
1073 //PWC hack until we have a real "mount" tool to remount root rw
1075 int flags
= MNT_ROOTFS
| MNT_RDONLY
;
1076 PE_parse_boot_argn("-rwroot_hack", &rw_root
, sizeof(rw_root
));
1079 kprintf("-rwroot_hack in effect: mounting root fs read/write\n");
1082 if ((error
= nfs_mount_diskless(&nd
.nd_root
, "/", flags
, &vp
, &mp
, ctx
)))
1084 if ((error
= nfs_mount_diskless(&nd
.nd_root
, "/", MNT_ROOTFS
, &vp
, &mp
, ctx
)))
1085 #endif /* NO_MOUNT_PRIVATE */
1088 if (sotype
== SOCK_STREAM
) {
1089 printf("NFS root mount (v3,TCP) failed with %d, trying UDP...\n", error
);
1090 sotype
= SOCK_DGRAM
;
1093 printf("NFS root mount (v3,UDP) failed with %d, trying v2...\n", error
);
1095 sotype
= SOCK_STREAM
;
1097 } else if (sotype
== SOCK_STREAM
) {
1098 printf("NFS root mount (v2,TCP) failed with %d, trying UDP...\n", error
);
1099 sotype
= SOCK_DGRAM
;
1102 printf("NFS root mount (v2,UDP) failed with error %d, giving up...\n", error
);
1104 panic("NFS root mount failed with error %d, check configuration: %s\n", error
, PE_boot_args());
1107 printf("root on %s\n", nd
.nd_root
.ndm_mntfrom
);
1113 #if !defined(NO_MOUNT_PRIVATE)
1114 if (nd
.nd_private
.ndm_saddr
.sin_addr
.s_addr
) {
1115 error
= nfs_mount_diskless_private(&nd
.nd_private
, "/private",
1116 0, &vppriv
, &mppriv
, ctx
);
1118 panic("NFS /private mount failed with error %d, check configuration: %s\n", error
, PE_boot_args());
1120 printf("private on %s\n", nd
.nd_private
.ndm_mntfrom
);
1123 mount_list_add(mppriv
);
1126 #endif /* NO_MOUNT_PRIVATE */
1128 if (nd
.nd_root
.ndm_mntfrom
) {
1129 FREE_ZONE(nd
.nd_root
.ndm_mntfrom
, MAXPATHLEN
, M_NAMEI
);
1131 if (nd
.nd_root
.ndm_path
) {
1132 FREE_ZONE(nd
.nd_root
.ndm_path
, MAXPATHLEN
, M_NAMEI
);
1134 if (nd
.nd_private
.ndm_mntfrom
) {
1135 FREE_ZONE(nd
.nd_private
.ndm_mntfrom
, MAXPATHLEN
, M_NAMEI
);
1137 if (nd
.nd_private
.ndm_path
) {
1138 FREE_ZONE(nd
.nd_private
.ndm_path
, MAXPATHLEN
, M_NAMEI
);
1141 /* Get root attributes (for the time). */
1142 error
= nfs_getattr(VTONFS(vp
), NULL
, ctx
, NGA_UNCACHED
);
1144 panic("NFS mount: failed to get attributes for root directory, error %d, check server", error
);
1150 * Internal version of mount system call for diskless setup.
1154 struct nfs_dlmount
*ndmntp
,
1155 const char *mntname
,
1162 int error
, numcomps
;
1163 char *xdrbuf
, *p
, *cp
, *frompath
, *endserverp
;
1164 char uaddr
[MAX_IPv4_STR_LEN
];
1166 uint32_t mattrs
[NFS_MATTR_BITMAP_LEN
];
1167 uint32_t mflags_mask
[NFS_MFLAG_BITMAP_LEN
];
1168 uint32_t mflags
[NFS_MFLAG_BITMAP_LEN
];
1169 uint32_t argslength_offset
, attrslength_offset
, end_offset
;
1171 if ((error
= vfs_rootmountalloc("nfs", ndmntp
->ndm_mntfrom
, &mp
))) {
1172 printf("nfs_mount_diskless: NFS not configured\n");
1176 mp
->mnt_flag
|= mntflag
;
1177 if (!(mntflag
& MNT_RDONLY
)) {
1178 mp
->mnt_flag
&= ~MNT_RDONLY
;
1181 /* find the server-side path being mounted */
1182 frompath
= ndmntp
->ndm_mntfrom
;
1183 if (*frompath
== '[') { /* skip IPv6 literal address */
1184 while (*frompath
&& (*frompath
!= ']')) {
1187 if (*frompath
== ']') {
1191 while (*frompath
&& (*frompath
!= ':')) {
1194 endserverp
= frompath
;
1195 while (*frompath
&& (*frompath
== ':')) {
1198 /* count fs location path components */
1200 while (*p
&& (*p
== '/')) {
1206 while (*p
&& (*p
!= '/')) {
1209 while (*p
&& (*p
== '/')) {
1214 /* convert address to universal address string */
1215 if (inet_ntop(AF_INET
, &ndmntp
->ndm_saddr
.sin_addr
, uaddr
, sizeof(uaddr
)) != uaddr
) {
1216 printf("nfs_mount_diskless: bad address\n");
1220 /* prepare mount attributes */
1221 NFS_BITMAP_ZERO(mattrs
, NFS_MATTR_BITMAP_LEN
);
1222 NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_VERSION
);
1223 NFS_BITMAP_SET(mattrs
, NFS_MATTR_SOCKET_TYPE
);
1224 NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_PORT
);
1225 NFS_BITMAP_SET(mattrs
, NFS_MATTR_FH
);
1226 NFS_BITMAP_SET(mattrs
, NFS_MATTR_FS_LOCATIONS
);
1227 NFS_BITMAP_SET(mattrs
, NFS_MATTR_MNTFLAGS
);
1229 /* prepare mount flags */
1230 NFS_BITMAP_ZERO(mflags_mask
, NFS_MFLAG_BITMAP_LEN
);
1231 NFS_BITMAP_ZERO(mflags
, NFS_MFLAG_BITMAP_LEN
);
1232 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_RESVPORT
);
1233 NFS_BITMAP_SET(mflags
, NFS_MFLAG_RESVPORT
);
1235 /* build xdr buffer */
1236 xb_init_buffer(&xb
, NULL
, 0);
1237 xb_add_32(error
, &xb
, NFS_ARGSVERSION_XDR
);
1238 argslength_offset
= xb_offset(&xb
);
1239 xb_add_32(error
, &xb
, 0); // args length
1240 xb_add_32(error
, &xb
, NFS_XDRARGS_VERSION_0
);
1241 xb_add_bitmap(error
, &xb
, mattrs
, NFS_MATTR_BITMAP_LEN
);
1242 attrslength_offset
= xb_offset(&xb
);
1243 xb_add_32(error
, &xb
, 0); // attrs length
1244 xb_add_32(error
, &xb
, ndmntp
->ndm_nfsv3
? 3 : 2); // NFS version
1245 xb_add_string(error
, &xb
, ((ndmntp
->ndm_sotype
== SOCK_DGRAM
) ? "udp" : "tcp"), 3);
1246 xb_add_32(error
, &xb
, ntohs(ndmntp
->ndm_saddr
.sin_port
)); // NFS port
1247 xb_add_fh(error
, &xb
, &ndmntp
->ndm_fh
[0], ndmntp
->ndm_fhlen
);
1249 xb_add_32(error
, &xb
, 1); /* fs location count */
1250 xb_add_32(error
, &xb
, 1); /* server count */
1251 xb_add_string(error
, &xb
, ndmntp
->ndm_mntfrom
, (endserverp
- ndmntp
->ndm_mntfrom
)); /* server name */
1252 xb_add_32(error
, &xb
, 1); /* address count */
1253 xb_add_string(error
, &xb
, uaddr
, strlen(uaddr
)); /* address */
1254 xb_add_32(error
, &xb
, 0); /* empty server info */
1255 xb_add_32(error
, &xb
, numcomps
); /* pathname component count */
1257 while (*p
&& (*p
== '/')) {
1262 while (*p
&& (*p
!= '/')) {
1265 xb_add_string(error
, &xb
, cp
, (p
- cp
)); /* component */
1269 while (*p
&& (*p
== '/')) {
1273 xb_add_32(error
, &xb
, 0); /* empty fsl info */
1274 xb_add_32(error
, &xb
, mntflag
); /* MNT flags */
1275 xb_build_done(error
, &xb
);
1277 /* update opaque counts */
1278 end_offset
= xb_offset(&xb
);
1280 error
= xb_seek(&xb
, argslength_offset
);
1281 xb_add_32(error
, &xb
, end_offset
- argslength_offset
+ XDRWORD
/*version*/);
1284 error
= xb_seek(&xb
, attrslength_offset
);
1285 xb_add_32(error
, &xb
, end_offset
- attrslength_offset
- XDRWORD
/*don't include length field*/);
1288 printf("nfs_mount_diskless: error %d assembling mount args\n", error
);
1292 /* grab the assembled buffer */
1293 xdrbuf
= xb_buffer_base(&xb
);
1294 xb
.xb_flags
&= ~XB_CLEANUP
;
1297 if ((error
= mountnfs(xdrbuf
, mp
, ctx
, vpp
))) {
1298 printf("nfs_mountroot: mount %s failed: %d\n", mntname
, error
);
1299 // XXX vfs_rootmountfailed(mp);
1301 mp
->mnt_vtable
->vfc_refcount
--;
1302 mount_list_unlock();
1304 mount_lock_destroy(mp
);
1306 mac_mount_label_destroy(mp
);
1308 FREE_ZONE(mp
, sizeof(struct mount
), M_MOUNT
);
1316 #if !defined(NO_MOUNT_PRIVATE)
1318 * Internal version of mount system call to mount "/private"
1319 * separately in diskless setup
1322 nfs_mount_diskless_private(
1323 struct nfs_dlmount
*ndmntp
,
1324 const char *mntname
,
1331 int error
, numcomps
;
1333 struct vfstable
*vfsp
;
1334 struct nameidata nd
;
1336 char *xdrbuf
= NULL
, *p
, *cp
, *frompath
, *endserverp
;
1337 char uaddr
[MAX_IPv4_STR_LEN
];
1339 uint32_t mattrs
[NFS_MATTR_BITMAP_LEN
];
1340 uint32_t mflags_mask
[NFS_MFLAG_BITMAP_LEN
], mflags
[NFS_MFLAG_BITMAP_LEN
];
1341 uint32_t argslength_offset
, attrslength_offset
, end_offset
;
1343 procp
= current_proc(); /* XXX */
1348 * mimic main()!. Temporarily set up rootvnode and other stuff so
1349 * that namei works. Need to undo this because main() does it, too
1351 struct filedesc
*fdp
; /* pointer to file descriptor state */
1353 mountlist
.tqh_first
->mnt_flag
|= MNT_ROOTFS
;
1355 /* Get the vnode for '/'. Set fdp->fd_cdir to reference it. */
1356 if (VFS_ROOT(mountlist
.tqh_first
, &rootvnode
, NULL
)) {
1357 panic("cannot find root vnode");
1359 error
= vnode_ref(rootvnode
);
1361 printf("nfs_mountroot: vnode_ref() failed on root vnode!\n");
1364 fdp
->fd_cdir
= rootvnode
;
1365 fdp
->fd_rdir
= NULL
;
1369 * Get vnode to be covered
1371 NDINIT(&nd
, LOOKUP
, OP_LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_SYSSPACE
,
1372 CAST_USER_ADDR_T(mntname
), ctx
);
1373 if ((error
= namei(&nd
))) {
1374 printf("nfs_mountroot: private namei failed!\n");
1378 /* undo vnode_ref() in mimic main()! */
1379 vnode_rele(rootvnode
);
1384 if ((error
= VNOP_FSYNC(vp
, MNT_WAIT
, ctx
)) ||
1385 (error
= buf_invalidateblks(vp
, BUF_WRITE_DATA
, 0, 0))) {
1389 if (vnode_vtype(vp
) != VDIR
) {
1394 for (vfsp
= vfsconf
; vfsp
; vfsp
= vfsp
->vfc_next
) {
1395 if (!strncmp(vfsp
->vfc_name
, "nfs", sizeof(vfsp
->vfc_name
))) {
1400 printf("nfs_mountroot: private NFS not configured\n");
1405 if (vnode_mountedhere(vp
) != NULL
) {
1412 * Allocate and initialize the filesystem.
1414 mp
= _MALLOC_ZONE((u_int32_t
)sizeof(struct mount
), M_MOUNT
, M_WAITOK
);
1416 printf("nfs_mountroot: unable to allocate mount structure\n");
1421 bzero((char *)mp
, sizeof(struct mount
));
1423 /* Initialize the default IO constraints */
1424 mp
->mnt_maxreadcnt
= mp
->mnt_maxwritecnt
= MAXPHYS
;
1425 mp
->mnt_segreadcnt
= mp
->mnt_segwritecnt
= 32;
1426 mp
->mnt_ioflags
= 0;
1427 mp
->mnt_realrootvp
= NULLVP
;
1428 mp
->mnt_authcache_ttl
= 0; /* Allways go to our lookup */
1430 mount_lock_init(mp
);
1431 TAILQ_INIT(&mp
->mnt_vnodelist
);
1432 TAILQ_INIT(&mp
->mnt_workerqueue
);
1433 TAILQ_INIT(&mp
->mnt_newvnodes
);
1434 (void)vfs_busy(mp
, LK_NOWAIT
);
1435 TAILQ_INIT(&mp
->mnt_vnodelist
);
1437 vfsp
->vfc_refcount
++;
1438 mount_list_unlock();
1439 mp
->mnt_vtable
= vfsp
;
1440 mp
->mnt_op
= vfsp
->vfc_vfsops
;
1441 // mp->mnt_stat.f_type = vfsp->vfc_typenum;
1442 mp
->mnt_flag
= mntflag
;
1443 mp
->mnt_flag
|= vfsp
->vfc_flags
& MNT_VISFLAGMASK
;
1444 strncpy(mp
->mnt_vfsstat
.f_fstypename
, vfsp
->vfc_name
, MFSNAMELEN
- 1);
1445 vp
->v_mountedhere
= mp
;
1446 mp
->mnt_vnodecovered
= vp
;
1448 mp
->mnt_vfsstat
.f_owner
= kauth_cred_getuid(kauth_cred_get());
1449 (void) copystr(mntname
, mp
->mnt_vfsstat
.f_mntonname
, MAXPATHLEN
- 1, 0);
1450 (void) copystr(ndmntp
->ndm_mntfrom
, mp
->mnt_vfsstat
.f_mntfromname
, MAXPATHLEN
- 1, 0);
1452 mac_mount_label_init(mp
);
1453 mac_mount_label_associate(ctx
, mp
);
1456 /* find the server-side path being mounted */
1457 frompath
= ndmntp
->ndm_mntfrom
;
1458 if (*frompath
== '[') { /* skip IPv6 literal address */
1459 while (*frompath
&& (*frompath
!= ']')) {
1462 if (*frompath
== ']') {
1466 while (*frompath
&& (*frompath
!= ':')) {
1469 endserverp
= frompath
;
1470 while (*frompath
&& (*frompath
== ':')) {
1473 /* count fs location path components */
1475 while (*p
&& (*p
== '/')) {
1481 while (*p
&& (*p
!= '/')) {
1484 while (*p
&& (*p
== '/')) {
1489 /* convert address to universal address string */
1490 if (inet_ntop(AF_INET
, &ndmntp
->ndm_saddr
.sin_addr
, uaddr
, sizeof(uaddr
)) != uaddr
) {
1491 printf("nfs_mountroot: bad address\n");
1496 /* prepare mount attributes */
1497 NFS_BITMAP_ZERO(mattrs
, NFS_MATTR_BITMAP_LEN
);
1498 NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_VERSION
);
1499 NFS_BITMAP_SET(mattrs
, NFS_MATTR_SOCKET_TYPE
);
1500 NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_PORT
);
1501 NFS_BITMAP_SET(mattrs
, NFS_MATTR_FH
);
1502 NFS_BITMAP_SET(mattrs
, NFS_MATTR_FS_LOCATIONS
);
1503 NFS_BITMAP_SET(mattrs
, NFS_MATTR_MNTFLAGS
);
1505 /* prepare mount flags */
1506 NFS_BITMAP_ZERO(mflags_mask
, NFS_MFLAG_BITMAP_LEN
);
1507 NFS_BITMAP_ZERO(mflags
, NFS_MFLAG_BITMAP_LEN
);
1508 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_RESVPORT
);
1509 NFS_BITMAP_SET(mflags
, NFS_MFLAG_RESVPORT
);
1511 /* build xdr buffer */
1512 xb_init_buffer(&xb
, NULL
, 0);
1513 xb_add_32(error
, &xb
, NFS_ARGSVERSION_XDR
);
1514 argslength_offset
= xb_offset(&xb
);
1515 xb_add_32(error
, &xb
, 0); // args length
1516 xb_add_32(error
, &xb
, NFS_XDRARGS_VERSION_0
);
1517 xb_add_bitmap(error
, &xb
, mattrs
, NFS_MATTR_BITMAP_LEN
);
1518 attrslength_offset
= xb_offset(&xb
);
1519 xb_add_32(error
, &xb
, 0); // attrs length
1520 xb_add_32(error
, &xb
, ndmntp
->ndm_nfsv3
? 3 : 2); // NFS version
1521 xb_add_string(error
, &xb
, ((ndmntp
->ndm_sotype
== SOCK_DGRAM
) ? "udp" : "tcp"), 3);
1522 xb_add_32(error
, &xb
, ntohs(ndmntp
->ndm_saddr
.sin_port
)); // NFS port
1523 xb_add_fh(error
, &xb
, &ndmntp
->ndm_fh
[0], ndmntp
->ndm_fhlen
);
1525 xb_add_32(error
, &xb
, 1); /* fs location count */
1526 xb_add_32(error
, &xb
, 1); /* server count */
1527 xb_add_string(error
, &xb
, ndmntp
->ndm_mntfrom
, (endserverp
- ndmntp
->ndm_mntfrom
)); /* server name */
1528 xb_add_32(error
, &xb
, 1); /* address count */
1529 xb_add_string(error
, &xb
, uaddr
, strlen(uaddr
)); /* address */
1530 xb_add_32(error
, &xb
, 0); /* empty server info */
1531 xb_add_32(error
, &xb
, numcomps
); /* pathname component count */
1533 while (*p
&& (*p
== '/')) {
1538 while (*p
&& (*p
!= '/')) {
1541 xb_add_string(error
, &xb
, cp
, (p
- cp
)); /* component */
1545 while (*p
&& (*p
== '/')) {
1549 xb_add_32(error
, &xb
, 0); /* empty fsl info */
1550 xb_add_32(error
, &xb
, mntflag
); /* MNT flags */
1551 xb_build_done(error
, &xb
);
1553 /* update opaque counts */
1554 end_offset
= xb_offset(&xb
);
1556 error
= xb_seek(&xb
, argslength_offset
);
1557 xb_add_32(error
, &xb
, end_offset
- argslength_offset
+ XDRWORD
/*version*/);
1560 error
= xb_seek(&xb
, attrslength_offset
);
1561 xb_add_32(error
, &xb
, end_offset
- attrslength_offset
- XDRWORD
/*don't include length field*/);
1564 printf("nfs_mountroot: error %d assembling mount args\n", error
);
1567 /* grab the assembled buffer */
1568 xdrbuf
= xb_buffer_base(&xb
);
1569 xb
.xb_flags
&= ~XB_CLEANUP
;
1572 if ((error
= mountnfs(xdrbuf
, mp
, ctx
, &vp
))) {
1573 printf("nfs_mountroot: mount %s failed: %d\n", mntname
, error
);
1574 vnode_put(mp
->mnt_vnodecovered
);
1576 vfsp
->vfc_refcount
--;
1577 mount_list_unlock();
1579 mount_lock_destroy(mp
);
1581 mac_mount_label_destroy(mp
);
1583 FREE_ZONE(mp
, sizeof(struct mount
), M_MOUNT
);
1593 #endif /* NO_MOUNT_PRIVATE */
1596 * Convert old style NFS mount args to XDR.
1599 nfs_convert_old_nfs_args(mount_t mp
, user_addr_t data
, vfs_context_t ctx
, int argsversion
, int inkernel
, char **xdrbufp
)
1601 int error
= 0, args64bit
, argsize
, numcomps
;
1602 struct user_nfs_args args
;
1603 struct nfs_args tempargs
;
1606 u_char nfh
[NFS4_FHSIZE
];
1607 char *mntfrom
, *endserverp
, *frompath
, *p
, *cp
;
1608 struct sockaddr_storage ss
;
1610 char uaddr
[MAX_IPv6_STR_LEN
];
1611 uint32_t mattrs
[NFS_MATTR_BITMAP_LEN
];
1612 uint32_t mflags_mask
[NFS_MFLAG_BITMAP_LEN
], mflags
[NFS_MFLAG_BITMAP_LEN
];
1613 uint32_t nfsvers
, nfslockmode
= 0, argslength_offset
, attrslength_offset
, end_offset
;
1618 /* allocate a temporary buffer for mntfrom */
1619 MALLOC_ZONE(mntfrom
, char*, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1624 args64bit
= (inkernel
|| vfs_context_is64bit(ctx
));
1625 argsp
= args64bit
? (void*)&args
: (void*)&tempargs
;
1627 argsize
= args64bit
? sizeof(args
) : sizeof(tempargs
);
1628 switch (argsversion
) {
1630 argsize
-= NFS_ARGSVERSION4_INCSIZE
;
1632 argsize
-= NFS_ARGSVERSION5_INCSIZE
;
1634 argsize
-= NFS_ARGSVERSION6_INCSIZE
;
1638 error
= EPROGMISMATCH
;
1642 /* read in the structure */
1644 bcopy(CAST_DOWN(void *, data
), argsp
, argsize
);
1646 error
= copyin(data
, argsp
, argsize
);
1651 args
.addrlen
= tempargs
.addrlen
;
1652 args
.sotype
= tempargs
.sotype
;
1653 args
.proto
= tempargs
.proto
;
1654 args
.fhsize
= tempargs
.fhsize
;
1655 args
.flags
= tempargs
.flags
;
1656 args
.wsize
= tempargs
.wsize
;
1657 args
.rsize
= tempargs
.rsize
;
1658 args
.readdirsize
= tempargs
.readdirsize
;
1659 args
.timeo
= tempargs
.timeo
;
1660 args
.retrans
= tempargs
.retrans
;
1661 args
.maxgrouplist
= tempargs
.maxgrouplist
;
1662 args
.readahead
= tempargs
.readahead
;
1663 args
.leaseterm
= tempargs
.leaseterm
;
1664 args
.deadthresh
= tempargs
.deadthresh
;
1665 args
.addr
= CAST_USER_ADDR_T(tempargs
.addr
);
1666 args
.fh
= CAST_USER_ADDR_T(tempargs
.fh
);
1667 args
.hostname
= CAST_USER_ADDR_T(tempargs
.hostname
);
1668 if (args
.version
>= 4) {
1669 args
.acregmin
= tempargs
.acregmin
;
1670 args
.acregmax
= tempargs
.acregmax
;
1671 args
.acdirmin
= tempargs
.acdirmin
;
1672 args
.acdirmax
= tempargs
.acdirmax
;
1674 if (args
.version
>= 5) {
1675 args
.auth
= tempargs
.auth
;
1677 if (args
.version
>= 6) {
1678 args
.deadtimeout
= tempargs
.deadtimeout
;
1682 if ((args
.fhsize
< 0) || (args
.fhsize
> NFS4_FHSIZE
)) {
1686 if (args
.fhsize
> 0) {
1688 bcopy(CAST_DOWN(void *, args
.fh
), (caddr_t
)nfh
, args
.fhsize
);
1690 error
= copyin(args
.fh
, (caddr_t
)nfh
, args
.fhsize
);
1696 error
= copystr(CAST_DOWN(void *, args
.hostname
), mntfrom
, MAXPATHLEN
- 1, &len
);
1698 error
= copyinstr(args
.hostname
, mntfrom
, MAXPATHLEN
- 1, &len
);
1701 bzero(&mntfrom
[len
], MAXPATHLEN
- len
);
1703 /* find the server-side path being mounted */
1705 if (*frompath
== '[') { /* skip IPv6 literal address */
1706 while (*frompath
&& (*frompath
!= ']')) {
1709 if (*frompath
== ']') {
1713 while (*frompath
&& (*frompath
!= ':')) {
1716 endserverp
= frompath
;
1717 while (*frompath
&& (*frompath
== ':')) {
1720 /* count fs location path components */
1722 while (*p
&& (*p
== '/')) {
1728 while (*p
&& (*p
!= '/')) {
1731 while (*p
&& (*p
== '/')) {
1736 /* copy socket address */
1738 bcopy(CAST_DOWN(void *, args
.addr
), &ss
, args
.addrlen
);
1740 if ((size_t)args
.addrlen
> sizeof(struct sockaddr_storage
)) {
1743 error
= copyin(args
.addr
, &ss
, args
.addrlen
);
1747 ss
.ss_len
= args
.addrlen
;
1749 /* convert address to universal address string */
1750 if (ss
.ss_family
== AF_INET
) {
1751 sinaddr
= &((struct sockaddr_in
*)&ss
)->sin_addr
;
1752 } else if (ss
.ss_family
== AF_INET6
) {
1753 sinaddr
= &((struct sockaddr_in6
*)&ss
)->sin6_addr
;
1757 if (!sinaddr
|| (inet_ntop(ss
.ss_family
, sinaddr
, uaddr
, sizeof(uaddr
)) != uaddr
)) {
1762 /* prepare mount flags */
1763 NFS_BITMAP_ZERO(mflags_mask
, NFS_MFLAG_BITMAP_LEN
);
1764 NFS_BITMAP_ZERO(mflags
, NFS_MFLAG_BITMAP_LEN
);
1765 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_SOFT
);
1766 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_INTR
);
1767 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_RESVPORT
);
1768 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NOCONNECT
);
1769 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_DUMBTIMER
);
1770 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_CALLUMNT
);
1771 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_RDIRPLUS
);
1772 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NONEGNAMECACHE
);
1773 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_MUTEJUKEBOX
);
1774 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NOQUOTA
);
1775 if (args
.flags
& NFSMNT_SOFT
) {
1776 NFS_BITMAP_SET(mflags
, NFS_MFLAG_SOFT
);
1778 if (args
.flags
& NFSMNT_INT
) {
1779 NFS_BITMAP_SET(mflags
, NFS_MFLAG_INTR
);
1781 if (args
.flags
& NFSMNT_RESVPORT
) {
1782 NFS_BITMAP_SET(mflags
, NFS_MFLAG_RESVPORT
);
1784 if (args
.flags
& NFSMNT_NOCONN
) {
1785 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NOCONNECT
);
1787 if (args
.flags
& NFSMNT_DUMBTIMR
) {
1788 NFS_BITMAP_SET(mflags
, NFS_MFLAG_DUMBTIMER
);
1790 if (args
.flags
& NFSMNT_CALLUMNT
) {
1791 NFS_BITMAP_SET(mflags
, NFS_MFLAG_CALLUMNT
);
1793 if (args
.flags
& NFSMNT_RDIRPLUS
) {
1794 NFS_BITMAP_SET(mflags
, NFS_MFLAG_RDIRPLUS
);
1796 if (args
.flags
& NFSMNT_NONEGNAMECACHE
) {
1797 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NONEGNAMECACHE
);
1799 if (args
.flags
& NFSMNT_MUTEJUKEBOX
) {
1800 NFS_BITMAP_SET(mflags
, NFS_MFLAG_MUTEJUKEBOX
);
1802 if (args
.flags
& NFSMNT_NOQUOTA
) {
1803 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NOQUOTA
);
1806 /* prepare mount attributes */
1807 NFS_BITMAP_ZERO(mattrs
, NFS_MATTR_BITMAP_LEN
);
1808 NFS_BITMAP_SET(mattrs
, NFS_MATTR_FLAGS
);
1809 NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_VERSION
);
1810 NFS_BITMAP_SET(mattrs
, NFS_MATTR_SOCKET_TYPE
);
1811 NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_PORT
);
1812 NFS_BITMAP_SET(mattrs
, NFS_MATTR_FH
);
1813 NFS_BITMAP_SET(mattrs
, NFS_MATTR_FS_LOCATIONS
);
1814 NFS_BITMAP_SET(mattrs
, NFS_MATTR_MNTFLAGS
);
1815 NFS_BITMAP_SET(mattrs
, NFS_MATTR_MNTFROM
);
1816 if (args
.flags
& NFSMNT_NFSV4
) {
1818 } else if (args
.flags
& NFSMNT_NFSV3
) {
1823 if ((args
.flags
& NFSMNT_RSIZE
) && (args
.rsize
> 0)) {
1824 NFS_BITMAP_SET(mattrs
, NFS_MATTR_READ_SIZE
);
1826 if ((args
.flags
& NFSMNT_WSIZE
) && (args
.wsize
> 0)) {
1827 NFS_BITMAP_SET(mattrs
, NFS_MATTR_WRITE_SIZE
);
1829 if ((args
.flags
& NFSMNT_TIMEO
) && (args
.timeo
> 0)) {
1830 NFS_BITMAP_SET(mattrs
, NFS_MATTR_REQUEST_TIMEOUT
);
1832 if ((args
.flags
& NFSMNT_RETRANS
) && (args
.retrans
> 0)) {
1833 NFS_BITMAP_SET(mattrs
, NFS_MATTR_SOFT_RETRY_COUNT
);
1835 if ((args
.flags
& NFSMNT_MAXGRPS
) && (args
.maxgrouplist
> 0)) {
1836 NFS_BITMAP_SET(mattrs
, NFS_MATTR_MAX_GROUP_LIST
);
1838 if ((args
.flags
& NFSMNT_READAHEAD
) && (args
.readahead
> 0)) {
1839 NFS_BITMAP_SET(mattrs
, NFS_MATTR_READAHEAD
);
1841 if ((args
.flags
& NFSMNT_READDIRSIZE
) && (args
.readdirsize
> 0)) {
1842 NFS_BITMAP_SET(mattrs
, NFS_MATTR_READDIR_SIZE
);
1844 if ((args
.flags
& NFSMNT_NOLOCKS
) ||
1845 (args
.flags
& NFSMNT_LOCALLOCKS
)) {
1846 NFS_BITMAP_SET(mattrs
, NFS_MATTR_LOCK_MODE
);
1847 if (args
.flags
& NFSMNT_NOLOCKS
) {
1848 nfslockmode
= NFS_LOCK_MODE_DISABLED
;
1849 } else if (args
.flags
& NFSMNT_LOCALLOCKS
) {
1850 nfslockmode
= NFS_LOCK_MODE_LOCAL
;
1852 nfslockmode
= NFS_LOCK_MODE_ENABLED
;
1855 if (args
.version
>= 4) {
1856 if ((args
.flags
& NFSMNT_ACREGMIN
) && (args
.acregmin
> 0)) {
1857 NFS_BITMAP_SET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MIN
);
1859 if ((args
.flags
& NFSMNT_ACREGMAX
) && (args
.acregmax
> 0)) {
1860 NFS_BITMAP_SET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MAX
);
1862 if ((args
.flags
& NFSMNT_ACDIRMIN
) && (args
.acdirmin
> 0)) {
1863 NFS_BITMAP_SET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MIN
);
1865 if ((args
.flags
& NFSMNT_ACDIRMAX
) && (args
.acdirmax
> 0)) {
1866 NFS_BITMAP_SET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MAX
);
1869 if (args
.version
>= 5) {
1870 if ((args
.flags
& NFSMNT_SECFLAVOR
) || (args
.flags
& NFSMNT_SECSYSOK
)) {
1871 NFS_BITMAP_SET(mattrs
, NFS_MATTR_SECURITY
);
1874 if (args
.version
>= 6) {
1875 if ((args
.flags
& NFSMNT_DEADTIMEOUT
) && (args
.deadtimeout
> 0)) {
1876 NFS_BITMAP_SET(mattrs
, NFS_MATTR_DEAD_TIMEOUT
);
1880 /* build xdr buffer */
1881 xb_init_buffer(&xb
, NULL
, 0);
1882 xb_add_32(error
, &xb
, args
.version
);
1883 argslength_offset
= xb_offset(&xb
);
1884 xb_add_32(error
, &xb
, 0); // args length
1885 xb_add_32(error
, &xb
, NFS_XDRARGS_VERSION_0
);
1886 xb_add_bitmap(error
, &xb
, mattrs
, NFS_MATTR_BITMAP_LEN
);
1887 attrslength_offset
= xb_offset(&xb
);
1888 xb_add_32(error
, &xb
, 0); // attrs length
1889 xb_add_bitmap(error
, &xb
, mflags_mask
, NFS_MFLAG_BITMAP_LEN
); /* mask */
1890 xb_add_bitmap(error
, &xb
, mflags
, NFS_MFLAG_BITMAP_LEN
); /* value */
1891 xb_add_32(error
, &xb
, nfsvers
);
1892 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READ_SIZE
)) {
1893 xb_add_32(error
, &xb
, args
.rsize
);
1895 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_WRITE_SIZE
)) {
1896 xb_add_32(error
, &xb
, args
.wsize
);
1898 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READDIR_SIZE
)) {
1899 xb_add_32(error
, &xb
, args
.readdirsize
);
1901 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READAHEAD
)) {
1902 xb_add_32(error
, &xb
, args
.readahead
);
1904 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MIN
)) {
1905 xb_add_32(error
, &xb
, args
.acregmin
);
1906 xb_add_32(error
, &xb
, 0);
1908 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MAX
)) {
1909 xb_add_32(error
, &xb
, args
.acregmax
);
1910 xb_add_32(error
, &xb
, 0);
1912 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MIN
)) {
1913 xb_add_32(error
, &xb
, args
.acdirmin
);
1914 xb_add_32(error
, &xb
, 0);
1916 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MAX
)) {
1917 xb_add_32(error
, &xb
, args
.acdirmax
);
1918 xb_add_32(error
, &xb
, 0);
1920 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_LOCK_MODE
)) {
1921 xb_add_32(error
, &xb
, nfslockmode
);
1923 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SECURITY
)) {
1924 uint32_t flavors
[2], i
= 0;
1925 if (args
.flags
& NFSMNT_SECFLAVOR
) {
1926 flavors
[i
++] = args
.auth
;
1928 if ((args
.flags
& NFSMNT_SECSYSOK
) && ((i
== 0) || (flavors
[0] != RPCAUTH_SYS
))) {
1929 flavors
[i
++] = RPCAUTH_SYS
;
1931 xb_add_word_array(error
, &xb
, flavors
, i
);
1933 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MAX_GROUP_LIST
)) {
1934 xb_add_32(error
, &xb
, args
.maxgrouplist
);
1936 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SOCKET_TYPE
)) {
1937 xb_add_string(error
, &xb
, ((args
.sotype
== SOCK_DGRAM
) ? "udp" : "tcp"), 3);
1939 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_PORT
)) {
1940 xb_add_32(error
, &xb
, ((ss
.ss_family
== AF_INET
) ?
1941 ntohs(((struct sockaddr_in
*)&ss
)->sin_port
) :
1942 ntohs(((struct sockaddr_in6
*)&ss
)->sin6_port
)));
1944 /* NFS_MATTR_MOUNT_PORT (not available in old args) */
1945 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_REQUEST_TIMEOUT
)) {
1946 /* convert from .1s increments to time */
1947 xb_add_32(error
, &xb
, args
.timeo
/ 10);
1948 xb_add_32(error
, &xb
, (args
.timeo
% 10) * 100000000);
1950 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SOFT_RETRY_COUNT
)) {
1951 xb_add_32(error
, &xb
, args
.retrans
);
1953 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_DEAD_TIMEOUT
)) {
1954 xb_add_32(error
, &xb
, args
.deadtimeout
);
1955 xb_add_32(error
, &xb
, 0);
1957 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_FH
)) {
1958 xb_add_fh(error
, &xb
, &nfh
[0], args
.fhsize
);
1960 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_FS_LOCATIONS
)) {
1961 xb_add_32(error
, &xb
, 1); /* fs location count */
1962 xb_add_32(error
, &xb
, 1); /* server count */
1963 xb_add_string(error
, &xb
, mntfrom
, (endserverp
- mntfrom
)); /* server name */
1964 xb_add_32(error
, &xb
, 1); /* address count */
1965 xb_add_string(error
, &xb
, uaddr
, strlen(uaddr
)); /* address */
1966 xb_add_32(error
, &xb
, 0); /* empty server info */
1967 xb_add_32(error
, &xb
, numcomps
); /* pathname component count */
1970 while (*p
&& (*p
== '/')) {
1975 while (*p
&& (*p
!= '/')) {
1978 xb_add_string(error
, &xb
, cp
, (p
- cp
)); /* component */
1980 while (*p
&& (*p
== '/')) {
1984 xb_add_32(error
, &xb
, 0); /* empty fsl info */
1986 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MNTFLAGS
)) {
1987 xb_add_32(error
, &xb
, (vfs_flags(mp
) & MNT_VISFLAGMASK
)); /* VFS MNT_* flags */
1989 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MNTFROM
)) {
1990 xb_add_string(error
, &xb
, mntfrom
, strlen(mntfrom
)); /* fixed f_mntfromname */
1992 xb_build_done(error
, &xb
);
1994 /* update opaque counts */
1995 end_offset
= xb_offset(&xb
);
1996 error
= xb_seek(&xb
, argslength_offset
);
1997 xb_add_32(error
, &xb
, end_offset
- argslength_offset
+ XDRWORD
/*version*/);
1999 error
= xb_seek(&xb
, attrslength_offset
);
2000 xb_add_32(error
, &xb
, end_offset
- attrslength_offset
- XDRWORD
/*don't include length field*/);
2003 /* grab the assembled buffer */
2004 *xdrbufp
= xb_buffer_base(&xb
);
2005 xb
.xb_flags
&= ~XB_CLEANUP
;
2009 FREE_ZONE(mntfrom
, MAXPATHLEN
, M_NAMEI
);
2019 nfs_vfs_mount(mount_t mp
, vnode_t vp
, user_addr_t data
, vfs_context_t ctx
)
2021 int error
= 0, inkernel
= vfs_iskernelmount(mp
);
2022 uint32_t argsversion
, argslength
;
2023 char *xdrbuf
= NULL
;
2025 /* read in version */
2027 bcopy(CAST_DOWN(void *, data
), &argsversion
, sizeof(argsversion
));
2028 } else if ((error
= copyin(data
, &argsversion
, sizeof(argsversion
)))) {
2032 /* If we have XDR args, then all values in the buffer are in network order */
2033 if (argsversion
== htonl(NFS_ARGSVERSION_XDR
)) {
2034 argsversion
= NFS_ARGSVERSION_XDR
;
2037 switch (argsversion
) {
2042 /* convert old-style args to xdr */
2043 error
= nfs_convert_old_nfs_args(mp
, data
, ctx
, argsversion
, inkernel
, &xdrbuf
);
2045 case NFS_ARGSVERSION_XDR
:
2046 /* copy in xdr buffer */
2048 bcopy(CAST_DOWN(void *, (data
+ XDRWORD
)), &argslength
, XDRWORD
);
2050 error
= copyin((data
+ XDRWORD
), &argslength
, XDRWORD
);
2055 argslength
= ntohl(argslength
);
2056 /* put a reasonable limit on the size of the XDR args */
2057 if (argslength
> 16 * 1024) {
2061 /* allocate xdr buffer */
2062 xdrbuf
= xb_malloc(xdr_rndup(argslength
));
2068 bcopy(CAST_DOWN(void *, data
), xdrbuf
, argslength
);
2070 error
= copyin(data
, xdrbuf
, argslength
);
2074 error
= EPROGMISMATCH
;
2083 error
= mountnfs(xdrbuf
, mp
, ctx
, &vp
);
2088 * Common code for mount and mountroot
2091 /* Set up an NFSv2/v3 mount */
2094 struct nfsmount
*nmp
,
2099 struct nfs_vattr nvattr
;
2109 * Get file attributes for the mountpoint. These are needed
2110 * in order to properly create the root vnode.
2112 error
= nfs3_getattr_rpc(NULL
, nmp
->nm_mountp
, nmp
->nm_fh
->fh_data
, nmp
->nm_fh
->fh_len
, 0,
2113 ctx
, &nvattr
, &xid
);
2118 error
= nfs_nget(nmp
->nm_mountp
, NULL
, NULL
, nmp
->nm_fh
->fh_data
, nmp
->nm_fh
->fh_len
,
2119 &nvattr
, &xid
, RPCAUTH_UNKNOWN
, NG_MARKROOT
, npp
);
2121 nfs_node_unlock(*npp
);
2128 * Try to make sure we have all the general info from the server.
2130 if (nmp
->nm_vers
== NFS_VER2
) {
2131 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXNAME
);
2132 nmp
->nm_fsattr
.nfsa_maxname
= NFS_MAXNAMLEN
;
2133 } else if (nmp
->nm_vers
== NFS_VER3
) {
2134 /* get the NFSv3 FSINFO */
2135 error
= nfs3_fsinfo(nmp
, *npp
, ctx
);
2139 /* If the server indicates all pathconf info is */
2140 /* the same, grab a copy of that info now */
2141 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_HOMOGENEOUS
) &&
2142 (nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_HOMOGENEOUS
)) {
2143 struct nfs_fsattr nfsa
;
2144 if (!nfs3_pathconf_rpc(*npp
, &nfsa
, ctx
)) {
2145 /* cache a copy of the results */
2146 lck_mtx_lock(&nmp
->nm_lock
);
2147 nfs3_pathconf_cache(nmp
, &nfsa
);
2148 lck_mtx_unlock(&nmp
->nm_lock
);
2153 if (*npp
&& error
) {
2154 vnode_put(NFSTOV(*npp
));
2155 vnode_recycle(NFSTOV(*npp
));
2162 * Update an NFSv4 mount path with the contents of the symlink.
2164 * Read the link for the given file handle.
2165 * Insert the link's components into the path.
2168 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
)
2170 int error
= 0, status
, numops
;
2171 uint32_t len
= 0, comp
, newcomp
, linkcompcount
;
2173 struct nfsm_chain nmreq
, nmrep
;
2174 struct nfsreq rq
, *req
= &rq
;
2175 struct nfsreq_secinfo_args si
;
2176 char *link
= NULL
, *p
, *q
, ch
;
2177 struct nfs_fs_path nfsp2
;
2179 bzero(&nfsp2
, sizeof(nfsp2
));
2180 if (dirfhp
->fh_len
) {
2181 NFSREQ_SECINFO_SET(&si
, NULL
, dirfhp
->fh_data
, dirfhp
->fh_len
, nfsp
->np_components
[curcomp
], 0);
2183 NFSREQ_SECINFO_SET(&si
, NULL
, NULL
, 0, nfsp
->np_components
[curcomp
], 0);
2185 nfsm_chain_null(&nmreq
);
2186 nfsm_chain_null(&nmrep
);
2188 MALLOC_ZONE(link
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
2195 nfsm_chain_build_alloc_init(error
, &nmreq
, 12 * NFSX_UNSIGNED
);
2196 nfsm_chain_add_compound_header(error
, &nmreq
, "readlink", nmp
->nm_minor_vers
, numops
);
2198 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
2199 nfsm_chain_add_fh(error
, &nmreq
, NFS_VER4
, fhp
->fh_data
, fhp
->fh_len
);
2201 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_READLINK
);
2202 nfsm_chain_build_done(error
, &nmreq
);
2203 nfsm_assert(error
, (numops
== 0), EPROTO
);
2206 error
= nfs_request_async(NULL
, nmp
->nm_mountp
, &nmreq
, NFSPROC4_COMPOUND
,
2207 vfs_context_thread(ctx
), vfs_context_ucred(ctx
), &si
, 0, NULL
, &req
);
2209 error
= nfs_request_async_finish(req
, &nmrep
, &xid
, &status
);
2212 nfsm_chain_skip_tag(error
, &nmrep
);
2213 nfsm_chain_get_32(error
, &nmrep
, numops
);
2214 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
2215 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_READLINK
);
2216 nfsm_chain_get_32(error
, &nmrep
, len
);
2220 } else if (len
>= MAXPATHLEN
) {
2221 len
= MAXPATHLEN
- 1;
2223 nfsm_chain_get_opaque(error
, &nmrep
, len
, link
);
2225 /* make sure link string is terminated properly */
2228 /* count the number of components in link */
2230 while (*p
&& (*p
== '/')) {
2236 while (*p
&& (*p
!= '/')) {
2239 while (*p
&& (*p
== '/')) {
2244 /* free up used components */
2245 for (comp
= 0; comp
<= curcomp
; comp
++) {
2246 if (nfsp
->np_components
[comp
]) {
2247 FREE(nfsp
->np_components
[comp
], M_TEMP
);
2248 nfsp
->np_components
[comp
] = NULL
;
2252 /* set up new path */
2253 nfsp2
.np_compcount
= nfsp
->np_compcount
- curcomp
- 1 + linkcompcount
;
2254 MALLOC(nfsp2
.np_components
, char **, nfsp2
.np_compcount
* sizeof(char*), M_TEMP
, M_WAITOK
| M_ZERO
);
2255 if (!nfsp2
.np_components
) {
2260 /* add link components */
2262 while (*p
&& (*p
== '/')) {
2265 for (newcomp
= 0; newcomp
< linkcompcount
; newcomp
++) {
2266 /* find end of component */
2268 while (*q
&& (*q
!= '/')) {
2271 MALLOC(nfsp2
.np_components
[newcomp
], char *, q
- p
+ 1, M_TEMP
, M_WAITOK
| M_ZERO
);
2272 if (!nfsp2
.np_components
[newcomp
]) {
2278 strlcpy(nfsp2
.np_components
[newcomp
], p
, q
- p
+ 1);
2281 while (*p
&& (*p
== '/')) {
2287 /* add remaining components */
2288 for (comp
= curcomp
+ 1; comp
< nfsp
->np_compcount
; comp
++, newcomp
++) {
2289 nfsp2
.np_components
[newcomp
] = nfsp
->np_components
[comp
];
2290 nfsp
->np_components
[comp
] = NULL
;
2293 /* move new path into place */
2294 FREE(nfsp
->np_components
, M_TEMP
);
2295 nfsp
->np_components
= nfsp2
.np_components
;
2296 nfsp
->np_compcount
= nfsp2
.np_compcount
;
2297 nfsp2
.np_components
= NULL
;
2299 /* for absolute link, let the caller now that the next dirfh is root */
2300 if (link
[0] == '/') {
2306 FREE_ZONE(link
, MAXPATHLEN
, M_NAMEI
);
2308 if (nfsp2
.np_components
) {
2309 for (comp
= 0; comp
< nfsp2
.np_compcount
; comp
++) {
2310 if (nfsp2
.np_components
[comp
]) {
2311 FREE(nfsp2
.np_components
[comp
], M_TEMP
);
2314 FREE(nfsp2
.np_components
, M_TEMP
);
2316 nfsm_chain_cleanup(&nmreq
);
2317 nfsm_chain_cleanup(&nmrep
);
2321 /* Set up an NFSv4 mount */
2324 struct nfsmount
*nmp
,
2328 struct nfsm_chain nmreq
, nmrep
;
2329 int error
= 0, numops
, status
, interval
, isdotdot
, loopcnt
= 0, depth
= 0;
2330 struct nfs_fs_path fspath
, *nfsp
, fspath2
;
2331 uint32_t bitmap
[NFS_ATTR_BITMAP_LEN
], comp
, comp2
;
2332 fhandle_t fh
, dirfh
;
2333 struct nfs_vattr nvattr
;
2335 struct nfsreq rq
, *req
= &rq
;
2336 struct nfsreq_secinfo_args si
;
2338 struct nfs_fs_locations nfsls
;
2341 fh
.fh_len
= dirfh
.fh_len
= 0;
2342 TAILQ_INIT(&nmp
->nm_open_owners
);
2343 TAILQ_INIT(&nmp
->nm_delegations
);
2344 TAILQ_INIT(&nmp
->nm_dreturnq
);
2345 nmp
->nm_stategenid
= 1;
2346 NVATTR_INIT(&nvattr
);
2347 bzero(&nfsls
, sizeof(nfsls
));
2348 nfsm_chain_null(&nmreq
);
2349 nfsm_chain_null(&nmrep
);
2352 * If no security flavors were specified we'll want to default to the server's
2353 * preferred flavor. For NFSv4.0 we need a file handle and name to get that via
2354 * SECINFO, so we'll do that on the last component of the server path we are
2355 * mounting. If we are mounting the server's root, we'll need to defer the
2356 * SECINFO call to the first successful LOOKUP request.
2358 if (!nmp
->nm_sec
.count
) {
2359 nmp
->nm_state
|= NFSSTA_NEEDSECINFO
;
2362 /* make a copy of the current location's path */
2363 nfsp
= &nmp
->nm_locations
.nl_locations
[nmp
->nm_locations
.nl_current
.nli_loc
]->nl_path
;
2364 bzero(&fspath
, sizeof(fspath
));
2365 fspath
.np_compcount
= nfsp
->np_compcount
;
2366 if (fspath
.np_compcount
> 0) {
2367 MALLOC(fspath
.np_components
, char **, fspath
.np_compcount
* sizeof(char*), M_TEMP
, M_WAITOK
| M_ZERO
);
2368 if (!fspath
.np_components
) {
2372 for (comp
= 0; comp
< nfsp
->np_compcount
; comp
++) {
2373 int slen
= strlen(nfsp
->np_components
[comp
]);
2374 MALLOC(fspath
.np_components
[comp
], char *, slen
+ 1, M_TEMP
, M_WAITOK
| M_ZERO
);
2375 if (!fspath
.np_components
[comp
]) {
2379 strlcpy(fspath
.np_components
[comp
], nfsp
->np_components
[comp
], slen
+ 1);
2386 /* for mirror mounts, we can just use the file handle passed in */
2388 dirfh
.fh_len
= nmp
->nm_fh
->fh_len
;
2389 bcopy(nmp
->nm_fh
->fh_data
, dirfh
.fh_data
, dirfh
.fh_len
);
2390 NFSREQ_SECINFO_SET(&si
, NULL
, dirfh
.fh_data
, dirfh
.fh_len
, NULL
, 0);
2394 /* otherwise, we need to get the fh for the directory we are mounting */
2396 /* if no components, just get root */
2397 if (fspath
.np_compcount
== 0) {
2399 // PUTROOTFH + GETATTR(FH)
2400 NFSREQ_SECINFO_SET(&si
, NULL
, NULL
, 0, NULL
, 0);
2402 nfsm_chain_build_alloc_init(error
, &nmreq
, 9 * NFSX_UNSIGNED
);
2403 nfsm_chain_add_compound_header(error
, &nmreq
, "mount", nmp
->nm_minor_vers
, numops
);
2405 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTROOTFH
);
2407 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
2408 NFS_CLEAR_ATTRIBUTES(bitmap
);
2409 NFS4_DEFAULT_ATTRIBUTES(bitmap
);
2410 NFS_BITMAP_SET(bitmap
, NFS_FATTR_FILEHANDLE
);
2411 nfsm_chain_add_bitmap(error
, &nmreq
, bitmap
, NFS_ATTR_BITMAP_LEN
);
2412 nfsm_chain_build_done(error
, &nmreq
);
2413 nfsm_assert(error
, (numops
== 0), EPROTO
);
2415 error
= nfs_request_async(NULL
, nmp
->nm_mountp
, &nmreq
, NFSPROC4_COMPOUND
,
2416 vfs_context_thread(ctx
), vfs_context_ucred(ctx
), &si
, 0, NULL
, &req
);
2418 error
= nfs_request_async_finish(req
, &nmrep
, &xid
, &status
);
2420 nfsm_chain_skip_tag(error
, &nmrep
);
2421 nfsm_chain_get_32(error
, &nmrep
, numops
);
2422 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTROOTFH
);
2423 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
2425 NFS_CLEAR_ATTRIBUTES(nmp
->nm_fsattr
.nfsa_bitmap
);
2426 error
= nfs4_parsefattr(&nmrep
, &nmp
->nm_fsattr
, &nvattr
, &dirfh
, NULL
, NULL
);
2427 if (!error
&& !NFS_BITMAP_ISSET(&nvattr
.nva_bitmap
, NFS_FATTR_FILEHANDLE
)) {
2428 printf("nfs: mount didn't return filehandle?\n");
2432 nfsm_chain_cleanup(&nmrep
);
2433 nfsm_chain_null(&nmreq
);
2434 NVATTR_CLEANUP(&nvattr
);
2438 /* look up each path component */
2439 for (comp
= 0; comp
< fspath
.np_compcount
;) {
2441 if (fspath
.np_components
[comp
][0] == '.') {
2442 if (fspath
.np_components
[comp
][1] == '\0') {
2447 /* treat ".." specially */
2448 if ((fspath
.np_components
[comp
][1] == '.') &&
2449 (fspath
.np_components
[comp
][2] == '\0')) {
2452 if (isdotdot
&& (dirfh
.fh_len
== 0)) {
2453 /* ".." in root directory is same as "." */
2458 // PUT(ROOT)FH + LOOKUP(P) + GETFH + GETATTR
2459 if (dirfh
.fh_len
== 0) {
2460 NFSREQ_SECINFO_SET(&si
, NULL
, NULL
, 0, isdotdot
? NULL
: fspath
.np_components
[comp
], 0);
2462 NFSREQ_SECINFO_SET(&si
, NULL
, dirfh
.fh_data
, dirfh
.fh_len
, isdotdot
? NULL
: fspath
.np_components
[comp
], 0);
2465 nfsm_chain_build_alloc_init(error
, &nmreq
, 18 * NFSX_UNSIGNED
);
2466 nfsm_chain_add_compound_header(error
, &nmreq
, "mount", nmp
->nm_minor_vers
, numops
);
2469 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
2470 nfsm_chain_add_fh(error
, &nmreq
, NFS_VER4
, dirfh
.fh_data
, dirfh
.fh_len
);
2472 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTROOTFH
);
2476 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_LOOKUPP
);
2478 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_LOOKUP
);
2479 nfsm_chain_add_name(error
, &nmreq
,
2480 fspath
.np_components
[comp
], strlen(fspath
.np_components
[comp
]), nmp
);
2483 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETFH
);
2485 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
2486 NFS_CLEAR_ATTRIBUTES(bitmap
);
2487 NFS4_DEFAULT_ATTRIBUTES(bitmap
);
2488 /* if no namedattr support or component is ".zfs", clear NFS_FATTR_NAMED_ATTR */
2489 if (!NMFLAG(nmp
, NAMEDATTR
) || !strcmp(fspath
.np_components
[comp
], ".zfs")) {
2490 NFS_BITMAP_CLR(bitmap
, NFS_FATTR_NAMED_ATTR
);
2492 nfsm_chain_add_bitmap(error
, &nmreq
, bitmap
, NFS_ATTR_BITMAP_LEN
);
2493 nfsm_chain_build_done(error
, &nmreq
);
2494 nfsm_assert(error
, (numops
== 0), EPROTO
);
2496 error
= nfs_request_async(NULL
, nmp
->nm_mountp
, &nmreq
, NFSPROC4_COMPOUND
,
2497 vfs_context_thread(ctx
), vfs_context_ucred(ctx
), &si
, 0, NULL
, &req
);
2499 error
= nfs_request_async_finish(req
, &nmrep
, &xid
, &status
);
2501 nfsm_chain_skip_tag(error
, &nmrep
);
2502 nfsm_chain_get_32(error
, &nmrep
, numops
);
2503 nfsm_chain_op_check(error
, &nmrep
, dirfh
.fh_len
? NFS_OP_PUTFH
: NFS_OP_PUTROOTFH
);
2504 nfsm_chain_op_check(error
, &nmrep
, isdotdot
? NFS_OP_LOOKUPP
: NFS_OP_LOOKUP
);
2506 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETFH
);
2507 nfsm_chain_get_32(error
, &nmrep
, fh
.fh_len
);
2508 if (fh
.fh_len
> sizeof(fh
.fh_data
)) {
2512 nfsm_chain_get_opaque(error
, &nmrep
, fh
.fh_len
, fh
.fh_data
);
2513 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
2515 NFS_CLEAR_ATTRIBUTES(nmp
->nm_fsattr
.nfsa_bitmap
);
2516 error
= nfs4_parsefattr(&nmrep
, &nmp
->nm_fsattr
, &nvattr
, NULL
, NULL
, &nfsls
);
2518 nfsm_chain_cleanup(&nmrep
);
2519 nfsm_chain_null(&nmreq
);
2521 /* LOOKUP succeeded but GETATTR failed? This could be a referral. */
2522 /* Try the lookup again with a getattr for fs_locations. */
2523 nfs_fs_locations_cleanup(&nfsls
);
2524 error
= nfs4_get_fs_locations(nmp
, NULL
, dirfh
.fh_data
, dirfh
.fh_len
, fspath
.np_components
[comp
], ctx
, &nfsls
);
2525 if (!error
&& (nfsls
.nl_numlocs
< 1)) {
2529 if (++loopcnt
> MAXSYMLINKS
) {
2530 /* too many symlink/referral redirections */
2534 /* tear down the current connection */
2535 nfs_disconnect(nmp
);
2536 /* replace fs locations */
2537 nfs_fs_locations_cleanup(&nmp
->nm_locations
);
2538 nmp
->nm_locations
= nfsls
;
2539 bzero(&nfsls
, sizeof(nfsls
));
2540 /* initiate a connection using the new fs locations */
2541 error
= nfs_mount_connect(nmp
);
2542 if (!error
&& !(nmp
->nm_locations
.nl_current
.nli_flags
& NLI_VALID
)) {
2546 /* add new server's remote path to beginning of our path and continue */
2547 nfsp
= &nmp
->nm_locations
.nl_locations
[nmp
->nm_locations
.nl_current
.nli_loc
]->nl_path
;
2548 bzero(&fspath2
, sizeof(fspath2
));
2549 fspath2
.np_compcount
= (fspath
.np_compcount
- comp
- 1) + nfsp
->np_compcount
;
2550 if (fspath2
.np_compcount
> 0) {
2551 MALLOC(fspath2
.np_components
, char **, fspath2
.np_compcount
* sizeof(char*), M_TEMP
, M_WAITOK
| M_ZERO
);
2552 if (!fspath2
.np_components
) {
2556 for (comp2
= 0; comp2
< nfsp
->np_compcount
; comp2
++) {
2557 int slen
= strlen(nfsp
->np_components
[comp2
]);
2558 MALLOC(fspath2
.np_components
[comp2
], char *, slen
+ 1, M_TEMP
, M_WAITOK
| M_ZERO
);
2559 if (!fspath2
.np_components
[comp2
]) {
2560 /* clean up fspath2, then error out */
2563 FREE(fspath2
.np_components
[comp2
], M_TEMP
);
2565 FREE(fspath2
.np_components
, M_TEMP
);
2569 strlcpy(fspath2
.np_components
[comp2
], nfsp
->np_components
[comp2
], slen
+ 1);
2571 if ((fspath
.np_compcount
- comp
- 1) > 0) {
2572 bcopy(&fspath
.np_components
[comp
+ 1], &fspath2
.np_components
[nfsp
->np_compcount
], (fspath
.np_compcount
- comp
- 1) * sizeof(char*));
2574 /* free up unused parts of old path (prior components and component array) */
2576 FREE(fspath
.np_components
[comp
], M_TEMP
);
2577 } while (comp
-- > 0);
2578 FREE(fspath
.np_components
, M_TEMP
);
2579 /* put new path in place */
2582 /* reset dirfh and component index */
2585 NVATTR_CLEANUP(&nvattr
);
2586 if (fspath
.np_compcount
== 0) {
2592 /* if file handle is for a symlink, then update the path with the symlink contents */
2593 if (NFS_BITMAP_ISSET(&nvattr
.nva_bitmap
, NFS_FATTR_TYPE
) && (nvattr
.nva_type
== VLNK
)) {
2594 if (++loopcnt
> MAXSYMLINKS
) {
2597 error
= nfs4_mount_update_path_with_symlink(nmp
, &fspath
, comp
, &dirfh
, &depth
, &fh
, ctx
);
2600 /* directory file handle is either left the same or reset to root (if link was absolute) */
2601 /* path traversal starts at beginning of the path again */
2603 NVATTR_CLEANUP(&nvattr
);
2604 nfs_fs_locations_cleanup(&nfsls
);
2607 NVATTR_CLEANUP(&nvattr
);
2608 nfs_fs_locations_cleanup(&nfsls
);
2609 /* not a symlink... */
2610 if ((nmp
->nm_state
& NFSSTA_NEEDSECINFO
) && (comp
== (fspath
.np_compcount
- 1)) && !isdotdot
) {
2611 /* need to get SECINFO for the directory being mounted */
2612 if (dirfh
.fh_len
== 0) {
2613 NFSREQ_SECINFO_SET(&si
, NULL
, NULL
, 0, isdotdot
? NULL
: fspath
.np_components
[comp
], 0);
2615 NFSREQ_SECINFO_SET(&si
, NULL
, dirfh
.fh_data
, dirfh
.fh_len
, isdotdot
? NULL
: fspath
.np_components
[comp
], 0);
2617 sec
.count
= NX_MAX_SEC_FLAVORS
;
2618 error
= nfs4_secinfo_rpc(nmp
, &si
, vfs_context_ucred(ctx
), sec
.flavors
, &sec
.count
);
2619 /* [sigh] some implementations return "illegal" error for unsupported ops */
2620 if (error
== NFSERR_OP_ILLEGAL
) {
2624 /* set our default security flavor to the first in the list */
2626 nmp
->nm_auth
= sec
.flavors
[0];
2628 nmp
->nm_state
&= ~NFSSTA_NEEDSECINFO
;
2630 /* advance directory file handle, component index, & update depth */
2633 if (!isdotdot
) { /* going down the hierarchy */
2635 } else if (--depth
<= 0) { /* going up the hierarchy */
2636 dirfh
.fh_len
= 0; /* clear dirfh when we hit root */
2641 /* get attrs for mount point root */
2642 numops
= NMFLAG(nmp
, NAMEDATTR
) ? 3 : 2; // PUTFH + GETATTR + OPENATTR
2643 nfsm_chain_build_alloc_init(error
, &nmreq
, 25 * NFSX_UNSIGNED
);
2644 nfsm_chain_add_compound_header(error
, &nmreq
, "mount", nmp
->nm_minor_vers
, numops
);
2646 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
2647 nfsm_chain_add_fh(error
, &nmreq
, NFS_VER4
, dirfh
.fh_data
, dirfh
.fh_len
);
2649 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
2650 NFS_CLEAR_ATTRIBUTES(bitmap
);
2651 NFS4_DEFAULT_ATTRIBUTES(bitmap
);
2652 /* if no namedattr support or last component is ".zfs", clear NFS_FATTR_NAMED_ATTR */
2653 if (!NMFLAG(nmp
, NAMEDATTR
) || ((fspath
.np_compcount
> 0) && !strcmp(fspath
.np_components
[fspath
.np_compcount
- 1], ".zfs"))) {
2654 NFS_BITMAP_CLR(bitmap
, NFS_FATTR_NAMED_ATTR
);
2656 nfsm_chain_add_bitmap(error
, &nmreq
, bitmap
, NFS_ATTR_BITMAP_LEN
);
2657 if (NMFLAG(nmp
, NAMEDATTR
)) {
2659 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_OPENATTR
);
2660 nfsm_chain_add_32(error
, &nmreq
, 0);
2662 nfsm_chain_build_done(error
, &nmreq
);
2663 nfsm_assert(error
, (numops
== 0), EPROTO
);
2665 error
= nfs_request_async(NULL
, nmp
->nm_mountp
, &nmreq
, NFSPROC4_COMPOUND
,
2666 vfs_context_thread(ctx
), vfs_context_ucred(ctx
), &si
, 0, NULL
, &req
);
2668 error
= nfs_request_async_finish(req
, &nmrep
, &xid
, &status
);
2670 nfsm_chain_skip_tag(error
, &nmrep
);
2671 nfsm_chain_get_32(error
, &nmrep
, numops
);
2672 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
2673 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
2675 NFS_CLEAR_ATTRIBUTES(nmp
->nm_fsattr
.nfsa_bitmap
);
2676 error
= nfs4_parsefattr(&nmrep
, &nmp
->nm_fsattr
, &nvattr
, NULL
, NULL
, NULL
);
2678 if (NMFLAG(nmp
, NAMEDATTR
)) {
2679 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_OPENATTR
);
2680 if (error
== ENOENT
) {
2683 /* [sigh] some implementations return "illegal" error for unsupported ops */
2684 if (error
|| !NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_NAMED_ATTR
)) {
2685 nmp
->nm_fsattr
.nfsa_flags
&= ~NFS_FSFLAG_NAMED_ATTR
;
2687 nmp
->nm_fsattr
.nfsa_flags
|= NFS_FSFLAG_NAMED_ATTR
;
2690 nmp
->nm_fsattr
.nfsa_flags
&= ~NFS_FSFLAG_NAMED_ATTR
;
2692 if (NMFLAG(nmp
, NOACL
)) { /* make sure ACL support is turned off */
2693 nmp
->nm_fsattr
.nfsa_flags
&= ~NFS_FSFLAG_ACL
;
2695 if (NMFLAG(nmp
, ACLONLY
) && !(nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_ACL
)) {
2696 NFS_BITMAP_CLR(nmp
->nm_flags
, NFS_MFLAG_ACLONLY
);
2698 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_FH_EXPIRE_TYPE
)) {
2699 uint32_t fhtype
= ((nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_FHTYPE_MASK
) >> NFS_FSFLAG_FHTYPE_SHIFT
);
2700 if (fhtype
!= NFS_FH_PERSISTENT
) {
2701 printf("nfs: warning: non-persistent file handles! for %s\n", vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
);
2705 /* make sure it's a directory */
2706 if (!NFS_BITMAP_ISSET(&nvattr
.nva_bitmap
, NFS_FATTR_TYPE
) || (nvattr
.nva_type
!= VDIR
)) {
2711 /* save the NFS fsid */
2712 nmp
->nm_fsid
= nvattr
.nva_fsid
;
2714 /* create the root node */
2715 error
= nfs_nget(nmp
->nm_mountp
, NULL
, NULL
, dirfh
.fh_data
, dirfh
.fh_len
, &nvattr
, &xid
, rq
.r_auth
, NG_MARKROOT
, npp
);
2718 if (nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_ACL
) {
2719 vfs_setextendedsecurity(nmp
->nm_mountp
);
2722 /* adjust I/O sizes to server limits */
2723 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXREAD
) && (nmp
->nm_fsattr
.nfsa_maxread
> 0)) {
2724 if (nmp
->nm_fsattr
.nfsa_maxread
< (uint64_t)nmp
->nm_rsize
) {
2725 nmp
->nm_rsize
= nmp
->nm_fsattr
.nfsa_maxread
& ~(NFS_FABLKSIZE
- 1);
2726 if (nmp
->nm_rsize
== 0) {
2727 nmp
->nm_rsize
= nmp
->nm_fsattr
.nfsa_maxread
;
2731 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXWRITE
) && (nmp
->nm_fsattr
.nfsa_maxwrite
> 0)) {
2732 if (nmp
->nm_fsattr
.nfsa_maxwrite
< (uint64_t)nmp
->nm_wsize
) {
2733 nmp
->nm_wsize
= nmp
->nm_fsattr
.nfsa_maxwrite
& ~(NFS_FABLKSIZE
- 1);
2734 if (nmp
->nm_wsize
== 0) {
2735 nmp
->nm_wsize
= nmp
->nm_fsattr
.nfsa_maxwrite
;
2740 /* set up lease renew timer */
2741 nmp
->nm_renew_timer
= thread_call_allocate(nfs4_renew_timer
, nmp
);
2742 interval
= nmp
->nm_fsattr
.nfsa_lease
/ 2;
2746 nfs_interval_timer_start(nmp
->nm_renew_timer
, interval
* 1000);
2749 if (fspath
.np_components
) {
2750 for (comp
= 0; comp
< fspath
.np_compcount
; comp
++) {
2751 if (fspath
.np_components
[comp
]) {
2752 FREE(fspath
.np_components
[comp
], M_TEMP
);
2755 FREE(fspath
.np_components
, M_TEMP
);
2757 NVATTR_CLEANUP(&nvattr
);
2758 nfs_fs_locations_cleanup(&nfsls
);
2760 nfs_node_unlock(*npp
);
2762 nfsm_chain_cleanup(&nmreq
);
2763 nfsm_chain_cleanup(&nmrep
);
2768 * Thread to handle initial NFS mount connection.
2771 nfs_mount_connect_thread(void *arg
, __unused wait_result_t wr
)
2773 struct nfsmount
*nmp
= arg
;
2774 int error
= 0, savederror
= 0, slpflag
= (NMFLAG(nmp
, INTR
) ? PCATCH
: 0);
2775 int done
= 0, timeo
, tries
, maxtries
;
2777 if (NM_OMFLAG(nmp
, MNTQUICK
)) {
2785 for (tries
= 0; tries
< maxtries
; tries
++) {
2786 error
= nfs_connect(nmp
, 1, timeo
);
2803 /* just keep retrying on any of these errors */
2807 /* looks like we got an answer... */
2812 /* save the best error */
2813 if (nfs_connect_error_class(error
) >= nfs_connect_error_class(savederror
)) {
2821 /* pause before next attempt */
2822 if ((error
= nfs_sigintr(nmp
, NULL
, current_thread(), 0))) {
2825 error
= tsleep(nmp
, PSOCK
| slpflag
, "nfs_mount_connect_retry", 2 * hz
);
2826 if (error
&& (error
!= EWOULDBLOCK
)) {
2832 /* update status of mount connect */
2833 lck_mtx_lock(&nmp
->nm_lock
);
2834 if (!nmp
->nm_mounterror
) {
2835 nmp
->nm_mounterror
= error
;
2837 nmp
->nm_state
&= ~NFSSTA_MOUNT_THREAD
;
2838 lck_mtx_unlock(&nmp
->nm_lock
);
2839 wakeup(&nmp
->nm_nss
);
2843 nfs_mount_connect(struct nfsmount
*nmp
)
2845 int error
= 0, slpflag
;
2847 struct timespec ts
= { 2, 0 };
2850 * Set up the socket. Perform initial search for a location/server/address to
2851 * connect to and negotiate any unspecified mount parameters. This work is
2852 * done on a kernel thread to satisfy reserved port usage needs.
2854 slpflag
= NMFLAG(nmp
, INTR
) ? PCATCH
: 0;
2855 lck_mtx_lock(&nmp
->nm_lock
);
2856 /* set flag that the thread is running */
2857 nmp
->nm_state
|= NFSSTA_MOUNT_THREAD
;
2858 if (kernel_thread_start(nfs_mount_connect_thread
, nmp
, &thd
) != KERN_SUCCESS
) {
2859 nmp
->nm_state
&= ~NFSSTA_MOUNT_THREAD
;
2860 nmp
->nm_mounterror
= EIO
;
2861 printf("nfs mount %s start socket connect thread failed\n", vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
);
2863 thread_deallocate(thd
);
2866 /* wait until mount connect thread is finished/gone */
2867 while (nmp
->nm_state
& NFSSTA_MOUNT_THREAD
) {
2868 error
= msleep(&nmp
->nm_nss
, &nmp
->nm_lock
, slpflag
| PSOCK
, "nfsconnectthread", &ts
);
2869 if ((error
&& (error
!= EWOULDBLOCK
)) || ((error
= nfs_sigintr(nmp
, NULL
, current_thread(), 1)))) {
2871 if (!nmp
->nm_mounterror
) {
2872 nmp
->nm_mounterror
= error
;
2874 /* signal the thread that we are aborting */
2875 nmp
->nm_sockflags
|= NMSOCK_UNMOUNT
;
2877 wakeup(nmp
->nm_nss
);
2879 /* and continue waiting on it to finish */
2883 lck_mtx_unlock(&nmp
->nm_lock
);
2885 /* grab mount connect status */
2886 error
= nmp
->nm_mounterror
;
2891 /* Table of maximum minor version for a given version */
2892 uint32_t maxminorverstab
[] = {
2893 0, /* Version 0 (does not exist) */
2894 0, /* Version 1 (does not exist) */
2900 #define NFS_MAX_SUPPORTED_VERSION ((long)(sizeof (maxminorverstab) / sizeof (uint32_t) - 1))
2901 #define NFS_MAX_SUPPORTED_MINOR_VERSION(v) ((long)(maxminorverstab[(v)]))
2903 #define DEFAULT_NFS_MIN_VERS VER2PVER(2, 0)
2904 #define DEFAULT_NFS_MAX_VERS VER2PVER(3, 0)
2907 * Common code to mount an NFS file system.
2916 struct nfsmount
*nmp
;
2919 struct vfsstatfs
*sbp
;
2921 uint32_t i
, val
, maxio
, iosize
, len
;
2923 uint32_t *mflags_mask
;
2925 uint32_t argslength
, attrslength
;
2926 struct nfs_location_index firstloc
= { NLI_VALID
, 0, 0, 0 };
2927 static const struct nfs_etype nfs_default_etypes
= {
2928 .count
= NFS_MAX_ETYPES
,
2929 .selected
= NFS_MAX_ETYPES
,
2930 .etypes
= { NFS_AES256_CTS_HMAC_SHA1_96
,
2931 NFS_AES128_CTS_HMAC_SHA1_96
,
2932 NFS_DES3_CBC_SHA1_KD
}
2934 /* make sure mbuf constants are set up */
2935 if (!nfs_mbuf_mhlen
) {
2939 if (vfs_flags(mp
) & MNT_UPDATE
) {
2941 /* update paths, file handles, etc, here XXX */
2945 /* allocate an NFS mount structure for this mount */
2946 MALLOC_ZONE(nmp
, struct nfsmount
*,
2947 sizeof(struct nfsmount
), M_NFSMNT
, M_WAITOK
);
2952 bzero((caddr_t
)nmp
, sizeof(struct nfsmount
));
2953 lck_mtx_init(&nmp
->nm_lock
, nfs_mount_grp
, LCK_ATTR_NULL
);
2954 TAILQ_INIT(&nmp
->nm_resendq
);
2955 TAILQ_INIT(&nmp
->nm_iodq
);
2956 TAILQ_INIT(&nmp
->nm_gsscl
);
2957 LIST_INIT(&nmp
->nm_monlist
);
2958 vfs_setfsprivate(mp
, nmp
);
2960 nmp
->nm_mountp
= mp
;
2961 vfs_setauthopaque(mp
);
2963 * Disable cache_lookup_path for NFS. NFS lookup always needs
2964 * to be called to check if the directory attribute cache is
2965 * valid and possibly purge the directory before calling
2968 vfs_setauthcache_ttl(mp
, 0);
2970 nfs_nhinit_finish();
2972 nmp
->nm_args
= xdrbuf
;
2974 /* set up defaults */
2977 nmp
->nm_min_vers
= DEFAULT_NFS_MIN_VERS
;
2978 nmp
->nm_max_vers
= DEFAULT_NFS_MAX_VERS
;
2979 nmp
->nm_timeo
= NFS_TIMEO
;
2980 nmp
->nm_retry
= NFS_RETRANS
;
2982 nmp
->nm_sofamily
= 0;
2983 nmp
->nm_nfsport
= 0;
2984 nmp
->nm_wsize
= NFS_WSIZE
;
2985 nmp
->nm_rsize
= NFS_RSIZE
;
2986 nmp
->nm_readdirsize
= NFS_READDIRSIZE
;
2987 nmp
->nm_numgrps
= NFS_MAXGRPS
;
2988 nmp
->nm_readahead
= NFS_DEFRAHEAD
;
2989 nmp
->nm_tprintf_delay
= nfs_tprintf_delay
;
2990 if (nmp
->nm_tprintf_delay
< 0) {
2991 nmp
->nm_tprintf_delay
= 0;
2993 nmp
->nm_tprintf_initial_delay
= nfs_tprintf_initial_delay
;
2994 if (nmp
->nm_tprintf_initial_delay
< 0) {
2995 nmp
->nm_tprintf_initial_delay
= 0;
2997 nmp
->nm_acregmin
= NFS_MINATTRTIMO
;
2998 nmp
->nm_acregmax
= NFS_MAXATTRTIMO
;
2999 nmp
->nm_acdirmin
= NFS_MINDIRATTRTIMO
;
3000 nmp
->nm_acdirmax
= NFS_MAXDIRATTRTIMO
;
3001 nmp
->nm_etype
= nfs_default_etypes
;
3002 nmp
->nm_auth
= RPCAUTH_SYS
;
3003 nmp
->nm_iodlink
.tqe_next
= NFSNOLIST
;
3004 nmp
->nm_deadtimeout
= 0;
3005 nmp
->nm_curdeadtimeout
= 0;
3006 NFS_BITMAP_SET(nmp
->nm_flags
, NFS_MFLAG_NOACL
);
3007 nmp
->nm_realm
= NULL
;
3008 nmp
->nm_principal
= NULL
;
3009 nmp
->nm_sprinc
= NULL
;
3012 mattrs
= nmp
->nm_mattrs
;
3013 mflags
= nmp
->nm_mflags
;
3014 mflags_mask
= nmp
->nm_mflags_mask
;
3016 /* set up NFS mount with args */
3017 xb_init_buffer(&xb
, xdrbuf
, 2 * XDRWORD
);
3018 xb_get_32(error
, &xb
, val
); /* version */
3019 xb_get_32(error
, &xb
, argslength
); /* args length */
3021 xb_init_buffer(&xb
, xdrbuf
, argslength
); /* restart parsing with actual buffer length */
3022 xb_get_32(error
, &xb
, val
); /* version */
3023 xb_get_32(error
, &xb
, argslength
); /* args length */
3024 xb_get_32(error
, &xb
, val
); /* XDR args version */
3025 if (val
!= NFS_XDRARGS_VERSION_0
|| argslength
< ((4 + NFS_MATTR_BITMAP_LEN
+ 1) * XDRWORD
)) {
3028 len
= NFS_MATTR_BITMAP_LEN
;
3029 xb_get_bitmap(error
, &xb
, mattrs
, len
); /* mount attribute bitmap */
3031 xb_get_32(error
, &xb
, attrslength
); /* attrs length */
3032 if (!error
&& (attrslength
> (argslength
- ((4 + NFS_MATTR_BITMAP_LEN
+ 1) * XDRWORD
)))) {
3036 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_FLAGS
)) {
3037 len
= NFS_MFLAG_BITMAP_LEN
;
3038 xb_get_bitmap(error
, &xb
, mflags_mask
, len
); /* mount flag mask */
3039 len
= NFS_MFLAG_BITMAP_LEN
;
3040 xb_get_bitmap(error
, &xb
, mflags
, len
); /* mount flag values */
3042 /* clear all mask bits and OR in all the ones that are set */
3043 nmp
->nm_flags
[0] &= ~mflags_mask
[0];
3044 nmp
->nm_flags
[0] |= (mflags_mask
[0] & mflags
[0]);
3047 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_VERSION
)) {
3048 /* Can't specify a single version and a range */
3049 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_VERSION_RANGE
)) {
3052 xb_get_32(error
, &xb
, nmp
->nm_vers
);
3053 if (nmp
->nm_vers
> NFS_MAX_SUPPORTED_VERSION
||
3054 nmp
->nm_vers
< NFS_VER2
) {
3057 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_MINOR_VERSION
)) {
3058 xb_get_32(error
, &xb
, nmp
->nm_minor_vers
);
3060 nmp
->nm_minor_vers
= maxminorverstab
[nmp
->nm_vers
];
3062 if (nmp
->nm_minor_vers
> maxminorverstab
[nmp
->nm_vers
]) {
3065 nmp
->nm_max_vers
= nmp
->nm_min_vers
=
3066 VER2PVER(nmp
->nm_vers
, nmp
->nm_minor_vers
);
3068 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_MINOR_VERSION
)) {
3069 /* should have also gotten NFS version (and already gotten minor version) */
3070 if (!NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_VERSION
)) {
3074 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_VERSION_RANGE
)) {
3075 xb_get_32(error
, &xb
, nmp
->nm_min_vers
);
3076 xb_get_32(error
, &xb
, nmp
->nm_max_vers
);
3077 if ((nmp
->nm_min_vers
> nmp
->nm_max_vers
) ||
3078 (PVER2MAJOR(nmp
->nm_max_vers
) > NFS_MAX_SUPPORTED_VERSION
) ||
3079 (PVER2MINOR(nmp
->nm_min_vers
) > maxminorverstab
[PVER2MAJOR(nmp
->nm_min_vers
)]) ||
3080 (PVER2MINOR(nmp
->nm_max_vers
) > maxminorverstab
[PVER2MAJOR(nmp
->nm_max_vers
)])) {
3084 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READ_SIZE
)) {
3085 xb_get_32(error
, &xb
, nmp
->nm_rsize
);
3087 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_WRITE_SIZE
)) {
3088 xb_get_32(error
, &xb
, nmp
->nm_wsize
);
3090 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READDIR_SIZE
)) {
3091 xb_get_32(error
, &xb
, nmp
->nm_readdirsize
);
3093 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READAHEAD
)) {
3094 xb_get_32(error
, &xb
, nmp
->nm_readahead
);
3096 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MIN
)) {
3097 xb_get_32(error
, &xb
, nmp
->nm_acregmin
);
3098 xb_skip(error
, &xb
, XDRWORD
);
3100 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MAX
)) {
3101 xb_get_32(error
, &xb
, nmp
->nm_acregmax
);
3102 xb_skip(error
, &xb
, XDRWORD
);
3104 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MIN
)) {
3105 xb_get_32(error
, &xb
, nmp
->nm_acdirmin
);
3106 xb_skip(error
, &xb
, XDRWORD
);
3108 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MAX
)) {
3109 xb_get_32(error
, &xb
, nmp
->nm_acdirmax
);
3110 xb_skip(error
, &xb
, XDRWORD
);
3113 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_LOCK_MODE
)) {
3114 xb_get_32(error
, &xb
, val
);
3116 case NFS_LOCK_MODE_DISABLED
:
3117 case NFS_LOCK_MODE_LOCAL
:
3118 if (nmp
->nm_vers
>= NFS_VER4
) {
3119 /* disabled/local lock mode only allowed on v2/v3 */
3124 case NFS_LOCK_MODE_ENABLED
:
3125 nmp
->nm_lockmode
= val
;
3132 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SECURITY
)) {
3134 xb_get_32(error
, &xb
, seccnt
);
3135 if (!error
&& ((seccnt
< 1) || (seccnt
> NX_MAX_SEC_FLAVORS
))) {
3139 nmp
->nm_sec
.count
= seccnt
;
3140 for (i
= 0; i
< seccnt
; i
++) {
3141 xb_get_32(error
, &xb
, nmp
->nm_sec
.flavors
[i
]);
3142 /* Check for valid security flavor */
3143 switch (nmp
->nm_sec
.flavors
[i
]) {
3154 /* start with the first flavor */
3155 nmp
->nm_auth
= nmp
->nm_sec
.flavors
[0];
3157 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_KERB_ETYPE
)) {
3159 xb_get_32(error
, &xb
, etypecnt
);
3160 if (!error
&& ((etypecnt
< 1) || (etypecnt
> NFS_MAX_ETYPES
))) {
3164 nmp
->nm_etype
.count
= etypecnt
;
3165 xb_get_32(error
, &xb
, nmp
->nm_etype
.selected
);
3168 nmp
->nm_etype
.selected
= etypecnt
; /* Nothing is selected yet, so set selected to count */
3169 for (i
= 0; i
< etypecnt
; i
++) {
3170 xb_get_32(error
, &xb
, nmp
->nm_etype
.etypes
[i
]);
3171 /* Check for valid encryption type */
3172 switch (nmp
->nm_etype
.etypes
[i
]) {
3173 case NFS_DES3_CBC_SHA1_KD
:
3174 case NFS_AES128_CTS_HMAC_SHA1_96
:
3175 case NFS_AES256_CTS_HMAC_SHA1_96
:
3183 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MAX_GROUP_LIST
)) {
3184 xb_get_32(error
, &xb
, nmp
->nm_numgrps
);
3186 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SOCKET_TYPE
)) {
3189 xb_get_32(error
, &xb
, val
);
3190 if (!error
&& ((val
< 3) || (val
> 5))) {
3194 error
= xb_get_bytes(&xb
, sotype
, val
, 0);
3197 if (!strcmp(sotype
, "tcp")) {
3198 nmp
->nm_sotype
= SOCK_STREAM
;
3199 } else if (!strcmp(sotype
, "udp")) {
3200 nmp
->nm_sotype
= SOCK_DGRAM
;
3201 } else if (!strcmp(sotype
, "tcp4")) {
3202 nmp
->nm_sotype
= SOCK_STREAM
;
3203 nmp
->nm_sofamily
= AF_INET
;
3204 } else if (!strcmp(sotype
, "udp4")) {
3205 nmp
->nm_sotype
= SOCK_DGRAM
;
3206 nmp
->nm_sofamily
= AF_INET
;
3207 } else if (!strcmp(sotype
, "tcp6")) {
3208 nmp
->nm_sotype
= SOCK_STREAM
;
3209 nmp
->nm_sofamily
= AF_INET6
;
3210 } else if (!strcmp(sotype
, "udp6")) {
3211 nmp
->nm_sotype
= SOCK_DGRAM
;
3212 nmp
->nm_sofamily
= AF_INET6
;
3213 } else if (!strcmp(sotype
, "inet4")) {
3214 nmp
->nm_sofamily
= AF_INET
;
3215 } else if (!strcmp(sotype
, "inet6")) {
3216 nmp
->nm_sofamily
= AF_INET6
;
3217 } else if (!strcmp(sotype
, "inet")) {
3218 nmp
->nm_sofamily
= 0; /* ok */
3222 if (!error
&& (nmp
->nm_vers
>= NFS_VER4
) && nmp
->nm_sotype
&&
3223 (nmp
->nm_sotype
!= SOCK_STREAM
)) {
3224 error
= EINVAL
; /* NFSv4 is only allowed over TCP. */
3228 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_PORT
)) {
3229 xb_get_32(error
, &xb
, nmp
->nm_nfsport
);
3231 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MOUNT_PORT
)) {
3232 xb_get_32(error
, &xb
, nmp
->nm_mountport
);
3234 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_REQUEST_TIMEOUT
)) {
3235 /* convert from time to 0.1s units */
3236 xb_get_32(error
, &xb
, nmp
->nm_timeo
);
3237 xb_get_32(error
, &xb
, val
);
3239 if (val
>= 1000000000) {
3243 nmp
->nm_timeo
*= 10;
3244 nmp
->nm_timeo
+= (val
+ 100000000 - 1) / 100000000;
3245 /* now convert to ticks */
3246 nmp
->nm_timeo
= (nmp
->nm_timeo
* NFS_HZ
+ 5) / 10;
3248 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SOFT_RETRY_COUNT
)) {
3249 xb_get_32(error
, &xb
, val
);
3250 if (!error
&& (val
> 1)) {
3251 nmp
->nm_retry
= val
;
3254 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_DEAD_TIMEOUT
)) {
3255 xb_get_32(error
, &xb
, nmp
->nm_deadtimeout
);
3256 xb_skip(error
, &xb
, XDRWORD
);
3258 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_FH
)) {
3260 MALLOC(nmp
->nm_fh
, fhandle_t
*, sizeof(fhandle_t
), M_TEMP
, M_WAITOK
| M_ZERO
);
3264 xb_get_32(error
, &xb
, nmp
->nm_fh
->fh_len
);
3266 if ((size_t)nmp
->nm_fh
->fh_len
> sizeof(nmp
->nm_fh
->fh_data
)) {
3269 error
= xb_get_bytes(&xb
, (char*)&nmp
->nm_fh
->fh_data
[0], nmp
->nm_fh
->fh_len
, 0);
3273 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_FS_LOCATIONS
)) {
3274 uint32_t loc
, serv
, addr
, comp
;
3275 struct nfs_fs_location
*fsl
;
3276 struct nfs_fs_server
*fss
;
3277 struct nfs_fs_path
*fsp
;
3279 xb_get_32(error
, &xb
, nmp
->nm_locations
.nl_numlocs
); /* fs location count */
3280 /* sanity check location count */
3281 if (!error
&& ((nmp
->nm_locations
.nl_numlocs
< 1) || (nmp
->nm_locations
.nl_numlocs
> 256))) {
3285 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
);
3286 if (!nmp
->nm_locations
.nl_locations
) {
3289 for (loc
= 0; loc
< nmp
->nm_locations
.nl_numlocs
; loc
++) {
3291 MALLOC(fsl
, struct nfs_fs_location
*, sizeof(struct nfs_fs_location
), M_TEMP
, M_WAITOK
| M_ZERO
);
3295 nmp
->nm_locations
.nl_locations
[loc
] = fsl
;
3296 xb_get_32(error
, &xb
, fsl
->nl_servcount
); /* server count */
3297 /* sanity check server count */
3298 if (!error
&& ((fsl
->nl_servcount
< 1) || (fsl
->nl_servcount
> 256))) {
3302 MALLOC(fsl
->nl_servers
, struct nfs_fs_server
**, fsl
->nl_servcount
* sizeof(struct nfs_fs_server
*), M_TEMP
, M_WAITOK
| M_ZERO
);
3303 if (!fsl
->nl_servers
) {
3306 for (serv
= 0; serv
< fsl
->nl_servcount
; serv
++) {
3308 MALLOC(fss
, struct nfs_fs_server
*, sizeof(struct nfs_fs_server
), M_TEMP
, M_WAITOK
| M_ZERO
);
3312 fsl
->nl_servers
[serv
] = fss
;
3313 xb_get_32(error
, &xb
, val
); /* server name length */
3314 /* sanity check server name length */
3315 if (!error
&& ((val
< 1) || (val
> MAXPATHLEN
))) {
3319 MALLOC(fss
->ns_name
, char *, val
+ 1, M_TEMP
, M_WAITOK
| M_ZERO
);
3320 if (!fss
->ns_name
) {
3324 error
= xb_get_bytes(&xb
, fss
->ns_name
, val
, 0); /* server name */
3325 xb_get_32(error
, &xb
, fss
->ns_addrcount
); /* address count */
3326 /* sanity check address count (OK to be zero) */
3327 if (!error
&& (fss
->ns_addrcount
> 256)) {
3331 if (fss
->ns_addrcount
> 0) {
3332 MALLOC(fss
->ns_addresses
, char **, fss
->ns_addrcount
* sizeof(char *), M_TEMP
, M_WAITOK
| M_ZERO
);
3333 if (!fss
->ns_addresses
) {
3336 for (addr
= 0; addr
< fss
->ns_addrcount
; addr
++) {
3337 xb_get_32(error
, &xb
, val
); /* address length */
3338 /* sanity check address length */
3339 if (!error
&& ((val
< 1) || (val
> 128))) {
3343 MALLOC(fss
->ns_addresses
[addr
], char *, val
+ 1, M_TEMP
, M_WAITOK
| M_ZERO
);
3344 if (!fss
->ns_addresses
[addr
]) {
3348 error
= xb_get_bytes(&xb
, fss
->ns_addresses
[addr
], val
, 0); /* address */
3351 xb_get_32(error
, &xb
, val
); /* server info length */
3352 xb_skip(error
, &xb
, val
); /* skip server info */
3355 fsp
= &fsl
->nl_path
;
3356 xb_get_32(error
, &xb
, fsp
->np_compcount
); /* component count */
3357 /* sanity check component count */
3358 if (!error
&& (fsp
->np_compcount
> MAXPATHLEN
)) {
3362 if (fsp
->np_compcount
) {
3363 MALLOC(fsp
->np_components
, char **, fsp
->np_compcount
* sizeof(char*), M_TEMP
, M_WAITOK
| M_ZERO
);
3364 if (!fsp
->np_components
) {
3368 for (comp
= 0; comp
< fsp
->np_compcount
; comp
++) {
3369 xb_get_32(error
, &xb
, val
); /* component length */
3370 /* sanity check component length */
3371 if (!error
&& (val
== 0)) {
3373 * Apparently some people think a path with zero components should
3374 * be encoded with one zero-length component. So, just ignore any
3375 * zero length components.
3378 fsp
->np_compcount
--;
3379 if (fsp
->np_compcount
== 0) {
3380 FREE(fsp
->np_components
, M_TEMP
);
3381 fsp
->np_components
= NULL
;
3385 if (!error
&& ((val
< 1) || (val
> MAXPATHLEN
))) {
3389 MALLOC(fsp
->np_components
[comp
], char *, val
+ 1, M_TEMP
, M_WAITOK
| M_ZERO
);
3390 if (!fsp
->np_components
[comp
]) {
3394 error
= xb_get_bytes(&xb
, fsp
->np_components
[comp
], val
, 0); /* component */
3396 xb_get_32(error
, &xb
, val
); /* fs location info length */
3397 xb_skip(error
, &xb
, val
); /* skip fs location info */
3400 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MNTFLAGS
)) {
3401 xb_skip(error
, &xb
, XDRWORD
);
3403 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MNTFROM
)) {
3404 xb_get_32(error
, &xb
, len
);
3407 if (val
>= sizeof(vfs_statfs(mp
)->f_mntfromname
)) {
3408 val
= sizeof(vfs_statfs(mp
)->f_mntfromname
) - 1;
3410 error
= xb_get_bytes(&xb
, vfs_statfs(mp
)->f_mntfromname
, val
, 0);
3411 if ((len
- val
) > 0) {
3412 xb_skip(error
, &xb
, len
- val
);
3415 vfs_statfs(mp
)->f_mntfromname
[val
] = '\0';
3419 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_REALM
)) {
3420 xb_get_32(error
, &xb
, len
);
3421 if (!error
&& ((len
< 1) || (len
> MAXPATHLEN
))) {
3425 /* allocate an extra byte for a leading '@' if its not already prepended to the realm */
3426 MALLOC(nmp
->nm_realm
, char *, len
+ 2, M_TEMP
, M_WAITOK
| M_ZERO
);
3427 if (!nmp
->nm_realm
) {
3431 error
= xb_get_bytes(&xb
, nmp
->nm_realm
, len
, 0);
3432 if (error
== 0 && *nmp
->nm_realm
!= '@') {
3433 bcopy(nmp
->nm_realm
, &nmp
->nm_realm
[1], len
);
3434 nmp
->nm_realm
[0] = '@';
3439 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_PRINCIPAL
)) {
3440 xb_get_32(error
, &xb
, len
);
3441 if (!error
&& ((len
< 1) || (len
> MAXPATHLEN
))) {
3445 MALLOC(nmp
->nm_principal
, char *, len
+ 1, M_TEMP
, M_WAITOK
| M_ZERO
);
3446 if (!nmp
->nm_principal
) {
3450 error
= xb_get_bytes(&xb
, nmp
->nm_principal
, len
, 0);
3454 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SVCPRINCIPAL
)) {
3455 xb_get_32(error
, &xb
, len
);
3456 if (!error
&& ((len
< 1) || (len
> MAXPATHLEN
))) {
3460 MALLOC(nmp
->nm_sprinc
, char *, len
+ 1, M_TEMP
, M_WAITOK
| M_ZERO
);
3461 if (!nmp
->nm_sprinc
) {
3465 error
= xb_get_bytes(&xb
, nmp
->nm_sprinc
, len
, 0);
3470 * Sanity check/finalize settings.
3473 if (nmp
->nm_timeo
< NFS_MINTIMEO
) {
3474 nmp
->nm_timeo
= NFS_MINTIMEO
;
3475 } else if (nmp
->nm_timeo
> NFS_MAXTIMEO
) {
3476 nmp
->nm_timeo
= NFS_MAXTIMEO
;
3478 if (nmp
->nm_retry
> NFS_MAXREXMIT
) {
3479 nmp
->nm_retry
= NFS_MAXREXMIT
;
3482 if (nmp
->nm_numgrps
> NFS_MAXGRPS
) {
3483 nmp
->nm_numgrps
= NFS_MAXGRPS
;
3485 if (nmp
->nm_readahead
> NFS_MAXRAHEAD
) {
3486 nmp
->nm_readahead
= NFS_MAXRAHEAD
;
3488 if (nmp
->nm_acregmin
> nmp
->nm_acregmax
) {
3489 nmp
->nm_acregmin
= nmp
->nm_acregmax
;
3491 if (nmp
->nm_acdirmin
> nmp
->nm_acdirmax
) {
3492 nmp
->nm_acdirmin
= nmp
->nm_acdirmax
;
3495 /* need at least one fs location */
3496 if (nmp
->nm_locations
.nl_numlocs
< 1) {
3501 /* init mount's mntfromname to first location */
3502 if (!NM_OMATTR_GIVEN(nmp
, MNTFROM
)) {
3503 nfs_location_mntfromname(&nmp
->nm_locations
, firstloc
,
3504 vfs_statfs(mp
)->f_mntfromname
, sizeof(vfs_statfs(mp
)->f_mntfromname
), 0);
3507 /* Need to save the mounting credential for v4. */
3508 nmp
->nm_mcred
= vfs_context_ucred(ctx
);
3509 if (IS_VALID_CRED(nmp
->nm_mcred
)) {
3510 kauth_cred_ref(nmp
->nm_mcred
);
3514 * If a reserved port is required, check for that privilege.
3515 * (Note that mirror mounts are exempt because the privilege was
3516 * already checked for the original mount.)
3518 if (NMFLAG(nmp
, RESVPORT
) && !vfs_iskernelmount(mp
)) {
3519 error
= priv_check_cred(nmp
->nm_mcred
, PRIV_NETINET_RESERVEDPORT
, 0);
3523 /* do mount's initial socket connection */
3524 error
= nfs_mount_connect(nmp
);
3527 /* set up the version-specific function tables */
3528 if (nmp
->nm_vers
< NFS_VER4
) {
3529 nmp
->nm_funcs
= &nfs3_funcs
;
3531 nmp
->nm_funcs
= &nfs4_funcs
;
3534 /* sanity check settings now that version/connection is set */
3535 if (nmp
->nm_vers
== NFS_VER2
) { /* ignore RDIRPLUS on NFSv2 */
3536 NFS_BITMAP_CLR(nmp
->nm_flags
, NFS_MFLAG_RDIRPLUS
);
3538 if (nmp
->nm_vers
>= NFS_VER4
) {
3539 if (NFS_BITMAP_ISSET(nmp
->nm_flags
, NFS_MFLAG_ACLONLY
)) { /* aclonly trumps noacl */
3540 NFS_BITMAP_CLR(nmp
->nm_flags
, NFS_MFLAG_NOACL
);
3542 NFS_BITMAP_CLR(nmp
->nm_flags
, NFS_MFLAG_CALLUMNT
);
3543 if (nmp
->nm_lockmode
!= NFS_LOCK_MODE_ENABLED
) {
3544 error
= EINVAL
; /* disabled/local lock mode only allowed on v2/v3 */
3547 /* ignore these if not v4 */
3548 NFS_BITMAP_CLR(nmp
->nm_flags
, NFS_MFLAG_NOCALLBACK
);
3549 NFS_BITMAP_CLR(nmp
->nm_flags
, NFS_MFLAG_NAMEDATTR
);
3550 NFS_BITMAP_CLR(nmp
->nm_flags
, NFS_MFLAG_NOACL
);
3551 NFS_BITMAP_CLR(nmp
->nm_flags
, NFS_MFLAG_ACLONLY
);
3555 if (nmp
->nm_sotype
== SOCK_DGRAM
) {
3556 /* I/O size defaults for UDP are different */
3557 if (!NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READ_SIZE
)) {
3558 nmp
->nm_rsize
= NFS_DGRAM_RSIZE
;
3560 if (!NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_WRITE_SIZE
)) {
3561 nmp
->nm_wsize
= NFS_DGRAM_WSIZE
;
3565 /* round down I/O sizes to multiple of NFS_FABLKSIZE */
3566 nmp
->nm_rsize
&= ~(NFS_FABLKSIZE
- 1);
3567 if (nmp
->nm_rsize
<= 0) {
3568 nmp
->nm_rsize
= NFS_FABLKSIZE
;
3570 nmp
->nm_wsize
&= ~(NFS_FABLKSIZE
- 1);
3571 if (nmp
->nm_wsize
<= 0) {
3572 nmp
->nm_wsize
= NFS_FABLKSIZE
;
3575 /* and limit I/O sizes to maximum allowed */
3576 maxio
= (nmp
->nm_vers
== NFS_VER2
) ? NFS_V2MAXDATA
:
3577 (nmp
->nm_sotype
== SOCK_DGRAM
) ? NFS_MAXDGRAMDATA
: NFS_MAXDATA
;
3578 if (maxio
> NFS_MAXBSIZE
) {
3579 maxio
= NFS_MAXBSIZE
;
3581 if (nmp
->nm_rsize
> maxio
) {
3582 nmp
->nm_rsize
= maxio
;
3584 if (nmp
->nm_wsize
> maxio
) {
3585 nmp
->nm_wsize
= maxio
;
3588 if (nmp
->nm_readdirsize
> maxio
) {
3589 nmp
->nm_readdirsize
= maxio
;
3591 if (nmp
->nm_readdirsize
> nmp
->nm_rsize
) {
3592 nmp
->nm_readdirsize
= nmp
->nm_rsize
;
3595 /* Set up the sockets and related info */
3596 if (nmp
->nm_sotype
== SOCK_DGRAM
) {
3597 TAILQ_INIT(&nmp
->nm_cwndq
);
3601 * Get the root node/attributes from the NFS server and
3602 * do any basic, version-specific setup.
3604 error
= nmp
->nm_funcs
->nf_mount(nmp
, ctx
, &np
);
3608 * A reference count is needed on the node representing the
3609 * remote root. If this object is not persistent, then backward
3610 * traversals of the mount point (i.e. "..") will not work if
3611 * the node gets flushed out of the cache.
3615 /* get usecount and drop iocount */
3616 error
= vnode_ref(*vpp
);
3619 vnode_recycle(*vpp
);
3624 * Do statfs to ensure static info gets set to reasonable values.
3626 if ((error
= nmp
->nm_funcs
->nf_update_statfs(nmp
, ctx
))) {
3627 int error2
= vnode_getwithref(*vpp
);
3632 vnode_recycle(*vpp
);
3635 sbp
= vfs_statfs(mp
);
3636 sbp
->f_bsize
= nmp
->nm_fsattr
.nfsa_bsize
;
3637 sbp
->f_blocks
= nmp
->nm_fsattr
.nfsa_space_total
/ sbp
->f_bsize
;
3638 sbp
->f_bfree
= nmp
->nm_fsattr
.nfsa_space_free
/ sbp
->f_bsize
;
3639 sbp
->f_bavail
= nmp
->nm_fsattr
.nfsa_space_avail
/ sbp
->f_bsize
;
3640 sbp
->f_bused
= (nmp
->nm_fsattr
.nfsa_space_total
/ sbp
->f_bsize
) -
3641 (nmp
->nm_fsattr
.nfsa_space_free
/ sbp
->f_bsize
);
3642 sbp
->f_files
= nmp
->nm_fsattr
.nfsa_files_total
;
3643 sbp
->f_ffree
= nmp
->nm_fsattr
.nfsa_files_free
;
3644 sbp
->f_iosize
= nfs_iosize
;
3647 * Calculate the size used for I/O buffers. Use the larger
3648 * of the two sizes to minimise NFS requests but make sure
3649 * that it is at least one VM page to avoid wasting buffer
3650 * space and to allow easy mmapping of I/O buffers.
3651 * The read/write RPC calls handle the splitting up of
3652 * buffers into multiple requests if the buffer size is
3653 * larger than the I/O size.
3655 #ifndef CONFIG_EMBEDDED
3656 iosize
= max(nmp
->nm_rsize
, nmp
->nm_wsize
);
3657 if (iosize
< PAGE_SIZE
) {
3663 nmp
->nm_biosize
= trunc_page_32(iosize
);
3665 /* For NFSv3 and greater, there is a (relatively) reliable ACCESS call. */
3666 if (nmp
->nm_vers
> NFS_VER2
) {
3667 vfs_setauthopaqueaccess(mp
);
3670 switch (nmp
->nm_lockmode
) {
3671 case NFS_LOCK_MODE_DISABLED
:
3673 case NFS_LOCK_MODE_LOCAL
:
3674 vfs_setlocklocal(nmp
->nm_mountp
);
3676 case NFS_LOCK_MODE_ENABLED
:
3678 if (nmp
->nm_vers
<= NFS_VER3
) {
3679 nfs_lockd_mount_register(nmp
);
3685 lck_mtx_lock(&nmp
->nm_lock
);
3686 nmp
->nm_state
|= NFSSTA_MOUNTED
;
3687 lck_mtx_unlock(&nmp
->nm_lock
);
3690 nfs_mount_drain_and_cleanup(nmp
);
3697 * We've detected a file system boundary on the server and
3698 * need to mount a new file system so that our file systems
3699 * MIRROR the file systems on the server.
3701 * Build the mount arguments for the new mount and call kernel_mount().
3704 nfs_mirror_mount_domount(vnode_t dvp
, vnode_t vp
, vfs_context_t ctx
)
3706 nfsnode_t np
= VTONFS(vp
);
3707 nfsnode_t dnp
= VTONFS(dvp
);
3708 struct nfsmount
*nmp
= NFSTONMP(np
);
3709 char fstype
[MFSTYPENAMELEN
], *mntfromname
= NULL
, *path
= NULL
, *relpath
, *p
, *cp
;
3710 int error
= 0, pathbuflen
= MAXPATHLEN
, i
, mntflags
= 0, referral
, skipcopy
= 0;
3712 struct xdrbuf xb
, xbnew
;
3713 uint32_t mattrs
[NFS_MATTR_BITMAP_LEN
];
3714 uint32_t newmattrs
[NFS_MATTR_BITMAP_LEN
];
3715 uint32_t newmflags
[NFS_MFLAG_BITMAP_LEN
];
3716 uint32_t newmflags_mask
[NFS_MFLAG_BITMAP_LEN
];
3717 uint32_t argslength
= 0, val
, count
, mlen
, mlen2
, rlen
, relpathcomps
;
3718 uint32_t argslength_offset
, attrslength_offset
, end_offset
;
3719 uint32_t numlocs
, loc
, numserv
, serv
, numaddr
, addr
, numcomp
, comp
;
3721 struct nfs_fs_locations nfsls
;
3723 referral
= (np
->n_vattr
.nva_flags
& NFS_FFLAG_TRIGGER_REFERRAL
);
3725 bzero(&nfsls
, sizeof(nfsls
));
3730 if (!nmp
|| (nmp
->nm_state
& (NFSSTA_FORCE
| NFSSTA_DEAD
))) {
3734 /* allocate a couple path buffers we need */
3735 MALLOC_ZONE(mntfromname
, char *, pathbuflen
, M_NAMEI
, M_WAITOK
);
3740 MALLOC_ZONE(path
, char *, pathbuflen
, M_NAMEI
, M_WAITOK
);
3746 /* get the path for the directory being mounted on */
3747 error
= vn_getpath(vp
, path
, &pathbuflen
);
3754 * Set up the mntfromname for the new mount based on the
3755 * current mount's mntfromname and the directory's path
3756 * relative to the current mount's mntonname.
3757 * Set up relpath to point at the relative path on the current mount.
3758 * Also, count the number of components in relpath.
3759 * We'll be adding those to each fs location path in the new args.
3761 nlen
= strlcpy(mntfromname
, vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
, MAXPATHLEN
);
3762 if ((nlen
> 0) && (mntfromname
[nlen
- 1] == '/')) { /* avoid double '/' in new name */
3763 mntfromname
[nlen
- 1] = '\0';
3766 relpath
= mntfromname
+ nlen
;
3767 nlen
= strlcat(mntfromname
, path
+ strlen(vfs_statfs(nmp
->nm_mountp
)->f_mntonname
), MAXPATHLEN
);
3768 if (nlen
>= MAXPATHLEN
) {
3769 error
= ENAMETOOLONG
;
3772 /* count the number of components in relpath */
3774 while (*p
&& (*p
== '/')) {
3780 while (*p
&& (*p
!= '/')) {
3783 while (*p
&& (*p
== '/')) {
3788 /* grab a copy of the file system type */
3789 vfs_name(vnode_mount(vp
), fstype
);
3791 /* for referrals, fetch the fs locations */
3793 const char *vname
= vnode_getname(NFSTOV(np
));
3797 error
= nfs4_get_fs_locations(nmp
, dnp
, NULL
, 0, vname
, ctx
, &nfsls
);
3798 vnode_putname(vname
);
3799 if (!error
&& (nfsls
.nl_numlocs
< 1)) {
3806 /* set up NFS mount args based on current mount args */
3808 #define xb_copy_32(E, XBSRC, XBDST, V) \
3811 xb_get_32((E), (XBSRC), (V)); \
3812 if (skipcopy) break; \
3813 xb_add_32((E), (XBDST), (V)); \
3815 #define xb_copy_opaque(E, XBSRC, XBDST) \
3817 uint32_t __count, __val; \
3818 xb_copy_32((E), (XBSRC), (XBDST), __count); \
3820 __count = nfsm_rndup(__count); \
3821 __count /= XDRWORD; \
3822 while (__count-- > 0) \
3823 xb_copy_32((E), (XBSRC), (XBDST), __val); \
3826 xb_init_buffer(&xb
, nmp
->nm_args
, 2 * XDRWORD
);
3827 xb_get_32(error
, &xb
, val
); /* version */
3828 xb_get_32(error
, &xb
, argslength
); /* args length */
3829 xb_init_buffer(&xb
, nmp
->nm_args
, argslength
);
3831 xb_init_buffer(&xbnew
, NULL
, 0);
3832 xb_copy_32(error
, &xb
, &xbnew
, val
); /* version */
3833 argslength_offset
= xb_offset(&xbnew
);
3834 xb_copy_32(error
, &xb
, &xbnew
, val
); /* args length */
3835 xb_copy_32(error
, &xb
, &xbnew
, val
); /* XDR args version */
3836 count
= NFS_MATTR_BITMAP_LEN
;
3837 xb_get_bitmap(error
, &xb
, mattrs
, count
); /* mount attribute bitmap */
3839 for (i
= 0; i
< NFS_MATTR_BITMAP_LEN
; i
++) {
3840 newmattrs
[i
] = mattrs
[i
];
3843 NFS_BITMAP_SET(newmattrs
, NFS_MATTR_FS_LOCATIONS
);
3845 NFS_BITMAP_SET(newmattrs
, NFS_MATTR_FH
);
3847 NFS_BITMAP_SET(newmattrs
, NFS_MATTR_FLAGS
);
3848 NFS_BITMAP_SET(newmattrs
, NFS_MATTR_MNTFLAGS
);
3849 NFS_BITMAP_CLR(newmattrs
, NFS_MATTR_MNTFROM
);
3850 xb_add_bitmap(error
, &xbnew
, newmattrs
, NFS_MATTR_BITMAP_LEN
);
3851 attrslength_offset
= xb_offset(&xbnew
);
3852 xb_copy_32(error
, &xb
, &xbnew
, val
); /* attrs length */
3853 NFS_BITMAP_ZERO(newmflags_mask
, NFS_MFLAG_BITMAP_LEN
);
3854 NFS_BITMAP_ZERO(newmflags
, NFS_MFLAG_BITMAP_LEN
);
3855 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_FLAGS
)) {
3856 count
= NFS_MFLAG_BITMAP_LEN
;
3857 xb_get_bitmap(error
, &xb
, newmflags_mask
, count
); /* mount flag mask bitmap */
3858 count
= NFS_MFLAG_BITMAP_LEN
;
3859 xb_get_bitmap(error
, &xb
, newmflags
, count
); /* mount flag bitmap */
3861 NFS_BITMAP_SET(newmflags_mask
, NFS_MFLAG_EPHEMERAL
);
3862 NFS_BITMAP_SET(newmflags
, NFS_MFLAG_EPHEMERAL
);
3863 xb_add_bitmap(error
, &xbnew
, newmflags_mask
, NFS_MFLAG_BITMAP_LEN
);
3864 xb_add_bitmap(error
, &xbnew
, newmflags
, NFS_MFLAG_BITMAP_LEN
);
3865 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_VERSION
)) {
3866 xb_copy_32(error
, &xb
, &xbnew
, val
);
3868 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_MINOR_VERSION
)) {
3869 xb_copy_32(error
, &xb
, &xbnew
, val
);
3871 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_VERSION_RANGE
)) {
3872 xb_copy_32(error
, &xb
, &xbnew
, val
);
3873 xb_copy_32(error
, &xb
, &xbnew
, val
);
3875 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READ_SIZE
)) {
3876 xb_copy_32(error
, &xb
, &xbnew
, val
);
3878 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_WRITE_SIZE
)) {
3879 xb_copy_32(error
, &xb
, &xbnew
, val
);
3881 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READDIR_SIZE
)) {
3882 xb_copy_32(error
, &xb
, &xbnew
, val
);
3884 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READAHEAD
)) {
3885 xb_copy_32(error
, &xb
, &xbnew
, val
);
3887 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MIN
)) {
3888 xb_copy_32(error
, &xb
, &xbnew
, val
);
3889 xb_copy_32(error
, &xb
, &xbnew
, val
);
3891 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MAX
)) {
3892 xb_copy_32(error
, &xb
, &xbnew
, val
);
3893 xb_copy_32(error
, &xb
, &xbnew
, val
);
3895 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MIN
)) {
3896 xb_copy_32(error
, &xb
, &xbnew
, val
);
3897 xb_copy_32(error
, &xb
, &xbnew
, val
);
3899 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MAX
)) {
3900 xb_copy_32(error
, &xb
, &xbnew
, val
);
3901 xb_copy_32(error
, &xb
, &xbnew
, val
);
3903 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_LOCK_MODE
)) {
3904 xb_copy_32(error
, &xb
, &xbnew
, val
);
3906 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SECURITY
)) {
3907 xb_copy_32(error
, &xb
, &xbnew
, count
);
3908 while (!error
&& (count
-- > 0)) {
3909 xb_copy_32(error
, &xb
, &xbnew
, val
);
3912 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_KERB_ETYPE
)) {
3913 xb_copy_32(error
, &xb
, &xbnew
, count
);
3914 xb_add_32(error
, &xbnew
, -1);
3915 while (!error
&& (count
-- > 0)) {
3916 xb_copy_32(error
, &xb
, &xbnew
, val
);
3919 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MAX_GROUP_LIST
)) {
3920 xb_copy_32(error
, &xb
, &xbnew
, val
);
3922 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SOCKET_TYPE
)) {
3923 xb_copy_opaque(error
, &xb
, &xbnew
);
3925 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_PORT
)) {
3926 xb_copy_32(error
, &xb
, &xbnew
, val
);
3928 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MOUNT_PORT
)) {
3929 xb_copy_32(error
, &xb
, &xbnew
, val
);
3931 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_REQUEST_TIMEOUT
)) {
3932 xb_copy_32(error
, &xb
, &xbnew
, val
);
3933 xb_copy_32(error
, &xb
, &xbnew
, val
);
3935 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SOFT_RETRY_COUNT
)) {
3936 xb_copy_32(error
, &xb
, &xbnew
, val
);
3938 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_DEAD_TIMEOUT
)) {
3939 xb_copy_32(error
, &xb
, &xbnew
, val
);
3940 xb_copy_32(error
, &xb
, &xbnew
, val
);
3942 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_FH
)) {
3943 xb_get_32(error
, &xb
, count
);
3944 xb_skip(error
, &xb
, count
);
3947 /* set the initial file handle to the directory's file handle */
3948 xb_add_fh(error
, &xbnew
, np
->n_fhp
, np
->n_fhsize
);
3950 /* copy/extend/skip fs locations */
3951 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_FS_LOCATIONS
)) {
3952 numlocs
= numserv
= numaddr
= numcomp
= 0;
3953 if (referral
) { /* don't copy the fs locations for a referral */
3956 xb_copy_32(error
, &xb
, &xbnew
, numlocs
); /* location count */
3957 for (loc
= 0; !error
&& (loc
< numlocs
); loc
++) {
3958 xb_copy_32(error
, &xb
, &xbnew
, numserv
); /* server count */
3959 for (serv
= 0; !error
&& (serv
< numserv
); serv
++) {
3960 xb_copy_opaque(error
, &xb
, &xbnew
); /* server name */
3961 xb_copy_32(error
, &xb
, &xbnew
, numaddr
); /* address count */
3962 for (addr
= 0; !error
&& (addr
< numaddr
); addr
++) {
3963 xb_copy_opaque(error
, &xb
, &xbnew
); /* address */
3965 xb_copy_opaque(error
, &xb
, &xbnew
); /* server info */
3968 xb_get_32(error
, &xb
, numcomp
); /* component count */
3970 uint64_t totalcomps
= numcomp
+ relpathcomps
;
3972 /* set error to ERANGE in the event of overflow */
3973 if (totalcomps
> UINT32_MAX
) {
3974 nfsmerr_if((error
= ERANGE
));
3977 xb_add_32(error
, &xbnew
, (uint32_t) totalcomps
); /* new component count */
3979 for (comp
= 0; !error
&& (comp
< numcomp
); comp
++) {
3980 xb_copy_opaque(error
, &xb
, &xbnew
); /* component */
3982 /* add additional components */
3983 for (comp
= 0; !skipcopy
&& !error
&& (comp
< relpathcomps
); comp
++) {
3985 while (*p
&& (*p
== '/')) {
3988 while (*p
&& !error
) {
3990 while (*p
&& (*p
!= '/')) {
3993 xb_add_string(error
, &xbnew
, cp
, (p
- cp
)); /* component */
3994 while (*p
&& (*p
== '/')) {
3999 xb_copy_opaque(error
, &xb
, &xbnew
); /* fs location info */
4006 /* add referral's fs locations */
4007 xb_add_32(error
, &xbnew
, nfsls
.nl_numlocs
); /* FS_LOCATIONS */
4008 for (loc
= 0; !error
&& (loc
< nfsls
.nl_numlocs
); loc
++) {
4009 xb_add_32(error
, &xbnew
, nfsls
.nl_locations
[loc
]->nl_servcount
);
4010 for (serv
= 0; !error
&& (serv
< nfsls
.nl_locations
[loc
]->nl_servcount
); serv
++) {
4011 xb_add_string(error
, &xbnew
, nfsls
.nl_locations
[loc
]->nl_servers
[serv
]->ns_name
,
4012 strlen(nfsls
.nl_locations
[loc
]->nl_servers
[serv
]->ns_name
));
4013 xb_add_32(error
, &xbnew
, nfsls
.nl_locations
[loc
]->nl_servers
[serv
]->ns_addrcount
);
4014 for (addr
= 0; !error
&& (addr
< nfsls
.nl_locations
[loc
]->nl_servers
[serv
]->ns_addrcount
); addr
++) {
4015 xb_add_string(error
, &xbnew
, nfsls
.nl_locations
[loc
]->nl_servers
[serv
]->ns_addresses
[addr
],
4016 strlen(nfsls
.nl_locations
[loc
]->nl_servers
[serv
]->ns_addresses
[addr
]));
4018 xb_add_32(error
, &xbnew
, 0); /* empty server info */
4020 xb_add_32(error
, &xbnew
, nfsls
.nl_locations
[loc
]->nl_path
.np_compcount
);
4021 for (comp
= 0; !error
&& (comp
< nfsls
.nl_locations
[loc
]->nl_path
.np_compcount
); comp
++) {
4022 xb_add_string(error
, &xbnew
, nfsls
.nl_locations
[loc
]->nl_path
.np_components
[comp
],
4023 strlen(nfsls
.nl_locations
[loc
]->nl_path
.np_components
[comp
]));
4025 xb_add_32(error
, &xbnew
, 0); /* empty fs location info */
4028 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MNTFLAGS
)) {
4029 xb_get_32(error
, &xb
, mntflags
);
4032 * We add the following mount flags to the ones for the mounted-on mount:
4033 * MNT_DONTBROWSE - to keep the mount from showing up as a separate volume
4034 * MNT_AUTOMOUNTED - to keep DiskArb from retriggering the mount after
4035 * an unmount (looking for /.autodiskmounted)
4037 mntflags
|= (MNT_AUTOMOUNTED
| MNT_DONTBROWSE
);
4038 xb_add_32(error
, &xbnew
, mntflags
);
4039 if (!referral
&& NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MNTFROM
)) {
4040 /* copy mntfrom string and add relpath */
4041 rlen
= strlen(relpath
);
4042 xb_get_32(error
, &xb
, mlen
);
4044 mlen2
= mlen
+ ((relpath
[0] != '/') ? 1 : 0) + rlen
;
4045 xb_add_32(error
, &xbnew
, mlen2
);
4046 count
= mlen
/ XDRWORD
;
4047 /* copy the original string */
4048 while (count
-- > 0) {
4049 xb_copy_32(error
, &xb
, &xbnew
, val
);
4051 if (!error
&& (mlen
% XDRWORD
)) {
4052 error
= xb_get_bytes(&xb
, buf
, mlen
% XDRWORD
, 0);
4054 error
= xb_add_bytes(&xbnew
, buf
, mlen
% XDRWORD
, 1);
4057 /* insert a '/' if the relative path doesn't start with one */
4058 if (!error
&& (relpath
[0] != '/')) {
4060 error
= xb_add_bytes(&xbnew
, buf
, 1, 1);
4062 /* add the additional relative path */
4064 error
= xb_add_bytes(&xbnew
, relpath
, rlen
, 1);
4066 /* make sure the resulting string has the right number of pad bytes */
4067 if (!error
&& (mlen2
!= nfsm_rndup(mlen2
))) {
4068 bzero(buf
, sizeof(buf
));
4069 count
= nfsm_rndup(mlen2
) - mlen2
;
4070 error
= xb_add_bytes(&xbnew
, buf
, count
, 1);
4073 xb_build_done(error
, &xbnew
);
4075 /* update opaque counts */
4076 end_offset
= xb_offset(&xbnew
);
4078 error
= xb_seek(&xbnew
, argslength_offset
);
4079 argslength
= end_offset
- argslength_offset
+ XDRWORD
/*version*/;
4080 xb_add_32(error
, &xbnew
, argslength
);
4083 error
= xb_seek(&xbnew
, attrslength_offset
);
4084 xb_add_32(error
, &xbnew
, end_offset
- attrslength_offset
- XDRWORD
/*don't include length field*/);
4089 * For kernel_mount() call, use the existing mount flags (instead of the
4090 * original flags) because flags like MNT_NOSUID and MNT_NODEV may have
4091 * been silently enforced.
4093 mntflags
= vnode_vfsvisflags(vp
);
4094 mntflags
|= (MNT_AUTOMOUNTED
| MNT_DONTBROWSE
);
4097 error
= kernel_mount(fstype
, dvp
, vp
, path
, xb_buffer_base(&xbnew
), argslength
,
4098 mntflags
, KERNEL_MOUNT_PERMIT_UNMOUNT
| KERNEL_MOUNT_NOAUTH
, ctx
);
4102 printf("nfs: mirror mount of %s on %s failed (%d)\n",
4103 mntfromname
, path
, error
);
4108 nfs_fs_locations_cleanup(&nfsls
);
4111 FREE_ZONE(path
, MAXPATHLEN
, M_NAMEI
);
4114 FREE_ZONE(mntfromname
, MAXPATHLEN
, M_NAMEI
);
4117 nfs_ephemeral_mount_harvester_start();
4123 * trigger vnode functions
4127 nfs_mirror_mount_trigger_resolve(
4129 const struct componentname
*cnp
,
4130 enum path_operation pop
,
4132 __unused
void *data
,
4135 nfsnode_t np
= VTONFS(vp
);
4136 vnode_t pvp
= NULLVP
;
4138 resolver_result_t result
;
4141 * We have a trigger node that doesn't have anything mounted on it yet.
4142 * We'll do the mount if either:
4143 * (a) this isn't the last component of the path OR
4144 * (b) this is an op that looks like it should trigger the mount.
4146 if (cnp
->cn_flags
& ISLASTCN
) {
4164 /* don't perform the mount for these operations */
4165 result
= vfs_resolver_result(np
->n_trigseq
, RESOLVER_NOCHANGE
, 0);
4166 #ifdef NFS_TRIGGER_DEBUG
4167 NP(np
, "nfs trigger RESOLVE: no change, last %d nameiop %d, seq %d",
4168 (cnp
->cn_flags
& ISLASTCN
) ? 1 : 0, cnp
->cn_nameiop
, np
->n_trigseq
);
4179 case OP_EXCHANGEDATA
:
4183 case OP_REMOVEXATTR
:
4185 /* go ahead and do the mount */
4190 if (vnode_mountedhere(vp
) != NULL
) {
4192 * Um... there's already something mounted.
4193 * Been there. Done that. Let's just say it succeeded.
4199 if ((error
= nfs_node_set_busy(np
, vfs_context_thread(ctx
)))) {
4200 result
= vfs_resolver_result(np
->n_trigseq
, RESOLVER_ERROR
, error
);
4201 #ifdef NFS_TRIGGER_DEBUG
4202 NP(np
, "nfs trigger RESOLVE: busy error %d, last %d nameiop %d, seq %d",
4203 error
, (cnp
->cn_flags
& ISLASTCN
) ? 1 : 0, cnp
->cn_nameiop
, np
->n_trigseq
);
4208 pvp
= vnode_getparent(vp
);
4209 if (pvp
== NULLVP
) {
4213 error
= nfs_mirror_mount_domount(pvp
, vp
, ctx
);
4219 result
= vfs_resolver_result(np
->n_trigseq
, error
? RESOLVER_ERROR
: RESOLVER_RESOLVED
, error
);
4220 #ifdef NFS_TRIGGER_DEBUG
4221 NP(np
, "nfs trigger RESOLVE: %s %d, last %d nameiop %d, seq %d",
4222 error
? "error" : "resolved", error
,
4223 (cnp
->cn_flags
& ISLASTCN
) ? 1 : 0, cnp
->cn_nameiop
, np
->n_trigseq
);
4226 if (pvp
!= NULLVP
) {
4229 nfs_node_clear_busy(np
);
4234 nfs_mirror_mount_trigger_unresolve(
4237 __unused
void *data
,
4240 nfsnode_t np
= VTONFS(vp
);
4243 resolver_result_t result
;
4245 if ((error
= nfs_node_set_busy(np
, vfs_context_thread(ctx
)))) {
4246 result
= vfs_resolver_result(np
->n_trigseq
, RESOLVER_ERROR
, error
);
4247 #ifdef NFS_TRIGGER_DEBUG
4248 NP(np
, "nfs trigger UNRESOLVE: busy error %d, seq %d", error
, np
->n_trigseq
);
4253 mp
= vnode_mountedhere(vp
);
4258 error
= vfs_unmountbyfsid(&(vfs_statfs(mp
)->f_fsid
), flags
, ctx
);
4263 result
= vfs_resolver_result(np
->n_trigseq
, error
? RESOLVER_ERROR
: RESOLVER_UNRESOLVED
, error
);
4264 #ifdef NFS_TRIGGER_DEBUG
4265 NP(np
, "nfs trigger UNRESOLVE: %s %d, seq %d",
4266 error
? "error" : "unresolved", error
, np
->n_trigseq
);
4268 nfs_node_clear_busy(np
);
4273 nfs_mirror_mount_trigger_rearm(
4276 __unused
void *data
,
4279 nfsnode_t np
= VTONFS(vp
);
4281 resolver_result_t result
;
4283 if ((error
= nfs_node_set_busy(np
, vfs_context_thread(ctx
)))) {
4284 result
= vfs_resolver_result(np
->n_trigseq
, RESOLVER_ERROR
, error
);
4285 #ifdef NFS_TRIGGER_DEBUG
4286 NP(np
, "nfs trigger REARM: busy error %d, seq %d", error
, np
->n_trigseq
);
4292 result
= vfs_resolver_result(np
->n_trigseq
,
4293 vnode_mountedhere(vp
) ? RESOLVER_RESOLVED
: RESOLVER_UNRESOLVED
, 0);
4294 #ifdef NFS_TRIGGER_DEBUG
4295 NP(np
, "nfs trigger REARM: %s, seq %d",
4296 vnode_mountedhere(vp
) ? "resolved" : "unresolved", np
->n_trigseq
);
4298 nfs_node_clear_busy(np
);
4303 * Periodically attempt to unmount ephemeral (mirror) mounts in an attempt to limit
4304 * the number of unused mounts.
4307 #define NFS_EPHEMERAL_MOUNT_HARVEST_INTERVAL 120 /* how often the harvester runs */
4308 struct nfs_ephemeral_mount_harvester_info
{
4309 fsid_t fsid
; /* FSID that we need to try to unmount */
4310 uint32_t mountcount
; /* count of ephemeral mounts seen in scan */
4312 /* various globals for the harvester */
4313 static thread_call_t nfs_ephemeral_mount_harvester_timer
= NULL
;
4314 static int nfs_ephemeral_mount_harvester_on
= 0;
4316 kern_return_t
thread_terminate(thread_t
);
4319 nfs_ephemeral_mount_harvester_callback(mount_t mp
, void *arg
)
4321 struct nfs_ephemeral_mount_harvester_info
*hinfo
= arg
;
4322 struct nfsmount
*nmp
;
4325 if (strcmp(mp
->mnt_vfsstat
.f_fstypename
, "nfs")) {
4326 return VFS_RETURNED
;
4329 if (!nmp
|| !NMFLAG(nmp
, EPHEMERAL
)) {
4330 return VFS_RETURNED
;
4332 hinfo
->mountcount
++;
4334 /* avoid unmounting mounts that have been triggered within the last harvest interval */
4336 if ((nmp
->nm_mounttime
>> 32) > ((uint32_t)now
.tv_sec
- NFS_EPHEMERAL_MOUNT_HARVEST_INTERVAL
)) {
4337 return VFS_RETURNED
;
4340 if (hinfo
->fsid
.val
[0] || hinfo
->fsid
.val
[1]) {
4341 /* attempt to unmount previously-found ephemeral mount */
4342 vfs_unmountbyfsid(&hinfo
->fsid
, 0, vfs_context_kernel());
4343 hinfo
->fsid
.val
[0] = hinfo
->fsid
.val
[1] = 0;
4347 * We can't call unmount here since we hold a mount iter ref
4348 * on mp so save its fsid for the next call iteration to unmount.
4350 hinfo
->fsid
.val
[0] = mp
->mnt_vfsstat
.f_fsid
.val
[0];
4351 hinfo
->fsid
.val
[1] = mp
->mnt_vfsstat
.f_fsid
.val
[1];
4353 return VFS_RETURNED
;
4357 * Spawn a thread to do the ephemeral mount harvesting.
4360 nfs_ephemeral_mount_harvester_timer_func(void)
4364 if (kernel_thread_start(nfs_ephemeral_mount_harvester
, NULL
, &thd
) == KERN_SUCCESS
) {
4365 thread_deallocate(thd
);
4370 * Iterate all mounts looking for NFS ephemeral mounts to try to unmount.
4373 nfs_ephemeral_mount_harvester(__unused
void *arg
, __unused wait_result_t wr
)
4375 struct nfs_ephemeral_mount_harvester_info hinfo
;
4378 hinfo
.mountcount
= 0;
4379 hinfo
.fsid
.val
[0] = hinfo
.fsid
.val
[1] = 0;
4380 vfs_iterate(VFS_ITERATE_TAIL_FIRST
, nfs_ephemeral_mount_harvester_callback
, &hinfo
);
4381 if (hinfo
.fsid
.val
[0] || hinfo
.fsid
.val
[1]) {
4382 /* attempt to unmount last found ephemeral mount */
4383 vfs_unmountbyfsid(&hinfo
.fsid
, 0, vfs_context_kernel());
4386 lck_mtx_lock(nfs_global_mutex
);
4387 if (!hinfo
.mountcount
) {
4388 /* no more ephemeral mounts - don't need timer */
4389 nfs_ephemeral_mount_harvester_on
= 0;
4391 /* re-arm the timer */
4392 clock_interval_to_deadline(NFS_EPHEMERAL_MOUNT_HARVEST_INTERVAL
, NSEC_PER_SEC
, &deadline
);
4393 thread_call_enter_delayed(nfs_ephemeral_mount_harvester_timer
, deadline
);
4394 nfs_ephemeral_mount_harvester_on
= 1;
4396 lck_mtx_unlock(nfs_global_mutex
);
4399 thread_terminate(current_thread());
4403 * Make sure the NFS ephemeral mount harvester timer is running.
4406 nfs_ephemeral_mount_harvester_start(void)
4410 lck_mtx_lock(nfs_global_mutex
);
4411 if (nfs_ephemeral_mount_harvester_on
) {
4412 lck_mtx_unlock(nfs_global_mutex
);
4415 if (nfs_ephemeral_mount_harvester_timer
== NULL
) {
4416 nfs_ephemeral_mount_harvester_timer
= thread_call_allocate((thread_call_func_t
)nfs_ephemeral_mount_harvester_timer_func
, NULL
);
4418 clock_interval_to_deadline(NFS_EPHEMERAL_MOUNT_HARVEST_INTERVAL
, NSEC_PER_SEC
, &deadline
);
4419 thread_call_enter_delayed(nfs_ephemeral_mount_harvester_timer
, deadline
);
4420 nfs_ephemeral_mount_harvester_on
= 1;
4421 lck_mtx_unlock(nfs_global_mutex
);
4427 * Send a MOUNT protocol MOUNT request to the server to get the initial file handle (and security).
4430 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
)
4432 int error
= 0, slen
, mntproto
;
4433 thread_t thd
= vfs_context_thread(ctx
);
4434 kauth_cred_t cred
= vfs_context_ucred(ctx
);
4436 struct nfsm_chain nmreq
, nmrep
;
4438 uint32_t mntvers
, mntport
, val
;
4439 struct sockaddr_storage ss
;
4440 struct sockaddr
*saddr
= (struct sockaddr
*)&ss
;
4442 nfsm_chain_null(&nmreq
);
4443 nfsm_chain_null(&nmrep
);
4445 mntvers
= (nfsvers
== NFS_VER2
) ? RPCMNT_VER1
: RPCMNT_VER3
;
4446 mntproto
= (NM_OMFLAG(nmp
, MNTUDP
) || (sotype
== SOCK_DGRAM
)) ? IPPROTO_UDP
: IPPROTO_TCP
;
4449 bcopy(sa
, saddr
, min(sizeof(ss
), sa
->sa_len
));
4450 if (saddr
->sa_family
== AF_INET
) {
4451 if (nmp
->nm_mountport
) {
4452 ((struct sockaddr_in
*)saddr
)->sin_port
= htons(nmp
->nm_mountport
);
4454 mntport
= ntohs(((struct sockaddr_in
*)saddr
)->sin_port
);
4456 if (nmp
->nm_mountport
) {
4457 ((struct sockaddr_in6
*)saddr
)->sin6_port
= htons(nmp
->nm_mountport
);
4459 mntport
= ntohs(((struct sockaddr_in6
*)saddr
)->sin6_port
);
4463 error
= nfs_portmap_lookup(nmp
, ctx
, saddr
, NULL
, RPCPROG_MNT
, mntvers
, mntproto
, timeo
);
4465 if (saddr
->sa_family
== AF_INET
) {
4466 mntport
= ntohs(((struct sockaddr_in
*)saddr
)->sin_port
);
4468 mntport
= ntohs(((struct sockaddr_in6
*)saddr
)->sin6_port
);
4471 /* if not found and TCP, then retry with UDP */
4472 if (mntproto
== IPPROTO_UDP
) {
4473 error
= EPROGUNAVAIL
;
4476 mntproto
= IPPROTO_UDP
;
4477 bcopy(sa
, saddr
, min(sizeof(ss
), sa
->sa_len
));
4480 nfsmout_if(error
|| !mntport
);
4482 /* MOUNT protocol MOUNT request */
4483 slen
= strlen(path
);
4484 nfsm_chain_build_alloc_init(error
, &nmreq
, NFSX_UNSIGNED
+ nfsm_rndup(slen
));
4485 nfsm_chain_add_name(error
, &nmreq
, path
, slen
, nmp
);
4486 nfsm_chain_build_done(error
, &nmreq
);
4488 error
= nfsm_rpchead2(nmp
, (mntproto
== IPPROTO_UDP
) ? SOCK_DGRAM
: SOCK_STREAM
,
4489 RPCPROG_MNT
, mntvers
, RPCMNT_MOUNT
,
4490 RPCAUTH_SYS
, cred
, NULL
, nmreq
.nmc_mhead
, &xid
, &mreq
);
4492 nmreq
.nmc_mhead
= NULL
;
4493 error
= nfs_aux_request(nmp
, thd
, saddr
, NULL
,
4494 ((mntproto
== IPPROTO_UDP
) ? SOCK_DGRAM
: SOCK_STREAM
),
4495 mreq
, R_XID32(xid
), 1, timeo
, &nmrep
);
4497 nfsm_chain_get_32(error
, &nmrep
, val
);
4498 if (!error
&& val
) {
4501 nfsm_chain_get_fh(error
, &nmrep
, nfsvers
, fh
);
4502 if (!error
&& (nfsvers
> NFS_VER2
)) {
4503 sec
->count
= NX_MAX_SEC_FLAVORS
;
4504 error
= nfsm_chain_get_secinfo(&nmrep
, &sec
->flavors
[0], &sec
->count
);
4507 nfsm_chain_cleanup(&nmreq
);
4508 nfsm_chain_cleanup(&nmrep
);
4514 * Send a MOUNT protocol UNMOUNT request to tell the server we've unmounted it.
4517 nfs3_umount_rpc(struct nfsmount
*nmp
, vfs_context_t ctx
, int timeo
)
4519 int error
= 0, slen
, mntproto
;
4520 thread_t thd
= vfs_context_thread(ctx
);
4521 kauth_cred_t cred
= vfs_context_ucred(ctx
);
4524 struct nfsm_chain nmreq
, nmrep
;
4526 uint32_t mntvers
, mntport
;
4527 struct sockaddr_storage ss
;
4528 struct sockaddr
*saddr
= (struct sockaddr
*)&ss
;
4530 if (!nmp
->nm_saddr
) {
4534 nfsm_chain_null(&nmreq
);
4535 nfsm_chain_null(&nmrep
);
4537 mntvers
= (nmp
->nm_vers
== NFS_VER2
) ? RPCMNT_VER1
: RPCMNT_VER3
;
4538 mntproto
= (NM_OMFLAG(nmp
, MNTUDP
) || (nmp
->nm_sotype
== SOCK_DGRAM
)) ? IPPROTO_UDP
: IPPROTO_TCP
;
4539 mntport
= nmp
->nm_mountport
;
4541 bcopy(nmp
->nm_saddr
, saddr
, min(sizeof(ss
), nmp
->nm_saddr
->sa_len
));
4542 if (saddr
->sa_family
== AF_INET
) {
4543 ((struct sockaddr_in
*)saddr
)->sin_port
= htons(mntport
);
4545 ((struct sockaddr_in6
*)saddr
)->sin6_port
= htons(mntport
);
4549 error
= nfs_portmap_lookup(nmp
, ctx
, saddr
, NULL
, RPCPROG_MNT
, mntvers
, mntproto
, timeo
);
4551 if (saddr
->sa_family
== AF_INET
) {
4552 mntport
= ntohs(((struct sockaddr_in
*)saddr
)->sin_port
);
4554 mntport
= ntohs(((struct sockaddr_in6
*)saddr
)->sin6_port
);
4556 /* if not found and mntvers > VER1, then retry with VER1 */
4558 if (mntvers
> RPCMNT_VER1
) {
4559 mntvers
= RPCMNT_VER1
;
4560 } else if (mntproto
== IPPROTO_TCP
) {
4561 mntproto
= IPPROTO_UDP
;
4562 mntvers
= (nmp
->nm_vers
== NFS_VER2
) ? RPCMNT_VER1
: RPCMNT_VER3
;
4566 bcopy(nmp
->nm_saddr
, saddr
, min(sizeof(ss
), nmp
->nm_saddr
->sa_len
));
4569 nfsmout_if(!mntport
);
4571 /* MOUNT protocol UNMOUNT request */
4572 path
= &vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
[0];
4573 while (*path
&& (*path
!= '/')) {
4576 slen
= strlen(path
);
4577 nfsm_chain_build_alloc_init(error
, &nmreq
, NFSX_UNSIGNED
+ nfsm_rndup(slen
));
4578 nfsm_chain_add_name(error
, &nmreq
, path
, slen
, nmp
);
4579 nfsm_chain_build_done(error
, &nmreq
);
4581 error
= nfsm_rpchead2(nmp
, (mntproto
== IPPROTO_UDP
) ? SOCK_DGRAM
: SOCK_STREAM
,
4582 RPCPROG_MNT
, RPCMNT_VER1
, RPCMNT_UMOUNT
,
4583 RPCAUTH_SYS
, cred
, NULL
, nmreq
.nmc_mhead
, &xid
, &mreq
);
4585 nmreq
.nmc_mhead
= NULL
;
4586 error
= nfs_aux_request(nmp
, thd
, saddr
, NULL
,
4587 ((mntproto
== IPPROTO_UDP
) ? SOCK_DGRAM
: SOCK_STREAM
),
4588 mreq
, R_XID32(xid
), 1, timeo
, &nmrep
);
4590 nfsm_chain_cleanup(&nmreq
);
4591 nfsm_chain_cleanup(&nmrep
);
4595 * unmount system call
4601 __unused vfs_context_t ctx
)
4603 struct nfsmount
*nmp
;
4605 int error
, flags
= 0;
4606 struct timespec ts
= { 1, 0 };
4609 lck_mtx_lock(&nmp
->nm_lock
);
4611 * Set the flag indicating that an unmount attempt is in progress.
4613 nmp
->nm_state
|= NFSSTA_UNMOUNTING
;
4615 * During a force unmount we want to...
4616 * Mark that we are doing a force unmount.
4617 * Make the mountpoint soft.
4619 if (mntflags
& MNT_FORCE
) {
4620 flags
|= FORCECLOSE
;
4621 nmp
->nm_state
|= NFSSTA_FORCE
;
4622 NFS_BITMAP_SET(nmp
->nm_flags
, NFS_MFLAG_SOFT
);
4625 * Wait for any in-progress monitored node scan to complete.
4627 while (nmp
->nm_state
& NFSSTA_MONITOR_SCAN
) {
4628 msleep(&nmp
->nm_state
, &nmp
->nm_lock
, PZERO
- 1, "nfswaitmonscan", &ts
);
4631 * Goes something like this..
4632 * - Call vflush() to clear out vnodes for this file system,
4633 * except for the swap files. Deal with them in 2nd pass.
4634 * - Decrement reference on the vnode representing remote root.
4635 * - Clean up the NFS mount structure.
4637 vp
= NFSTOV(nmp
->nm_dnp
);
4638 lck_mtx_unlock(&nmp
->nm_lock
);
4641 * vflush will check for busy vnodes on mountpoint.
4642 * Will do the right thing for MNT_FORCE. That is, we should
4643 * not get EBUSY back.
4645 error
= vflush(mp
, vp
, SKIPSWAP
| flags
);
4646 if (mntflags
& MNT_FORCE
) {
4647 error
= vflush(mp
, NULLVP
, flags
); /* locks vp in the process */
4649 if (vnode_isinuse(vp
, 1)) {
4652 error
= vflush(mp
, vp
, flags
);
4656 lck_mtx_lock(&nmp
->nm_lock
);
4657 nmp
->nm_state
&= ~NFSSTA_UNMOUNTING
;
4658 lck_mtx_unlock(&nmp
->nm_lock
);
4662 lck_mtx_lock(&nmp
->nm_lock
);
4664 lck_mtx_unlock(&nmp
->nm_lock
);
4667 * Release the root vnode reference held by mountnfs()
4669 error
= vnode_get(vp
);
4675 vflush(mp
, NULLVP
, FORCECLOSE
);
4677 /* Wait for all other references to be released and free the mount */
4678 nfs_mount_drain_and_cleanup(nmp
);
4684 * cleanup/destroy NFS fs locations structure
4687 nfs_fs_locations_cleanup(struct nfs_fs_locations
*nfslsp
)
4689 struct nfs_fs_location
*fsl
;
4690 struct nfs_fs_server
*fss
;
4691 struct nfs_fs_path
*fsp
;
4692 uint32_t loc
, serv
, addr
, comp
;
4694 /* free up fs locations */
4695 if (!nfslsp
->nl_numlocs
|| !nfslsp
->nl_locations
) {
4699 for (loc
= 0; loc
< nfslsp
->nl_numlocs
; loc
++) {
4700 fsl
= nfslsp
->nl_locations
[loc
];
4704 if ((fsl
->nl_servcount
> 0) && fsl
->nl_servers
) {
4705 for (serv
= 0; serv
< fsl
->nl_servcount
; serv
++) {
4706 fss
= fsl
->nl_servers
[serv
];
4710 if ((fss
->ns_addrcount
> 0) && fss
->ns_addresses
) {
4711 for (addr
= 0; addr
< fss
->ns_addrcount
; addr
++) {
4712 FREE(fss
->ns_addresses
[addr
], M_TEMP
);
4714 FREE(fss
->ns_addresses
, M_TEMP
);
4716 FREE(fss
->ns_name
, M_TEMP
);
4719 FREE(fsl
->nl_servers
, M_TEMP
);
4721 fsp
= &fsl
->nl_path
;
4722 if (fsp
->np_compcount
&& fsp
->np_components
) {
4723 for (comp
= 0; comp
< fsp
->np_compcount
; comp
++) {
4724 if (fsp
->np_components
[comp
]) {
4725 FREE(fsp
->np_components
[comp
], M_TEMP
);
4728 FREE(fsp
->np_components
, M_TEMP
);
4732 FREE(nfslsp
->nl_locations
, M_TEMP
);
4733 nfslsp
->nl_numlocs
= 0;
4734 nfslsp
->nl_locations
= NULL
;
4738 nfs_mount_rele(struct nfsmount
*nmp
)
4742 lck_mtx_lock(&nmp
->nm_lock
);
4743 if (nmp
->nm_ref
< 1) {
4744 panic("nfs zombie mount underflow\n");
4747 if (nmp
->nm_ref
== 0) {
4748 wup
= nmp
->nm_state
& NFSSTA_MOUNT_DRAIN
;
4750 lck_mtx_unlock(&nmp
->nm_lock
);
4752 wakeup(&nmp
->nm_ref
);
4757 nfs_mount_drain_and_cleanup(struct nfsmount
*nmp
)
4759 lck_mtx_lock(&nmp
->nm_lock
);
4760 nmp
->nm_state
|= NFSSTA_MOUNT_DRAIN
;
4761 while (nmp
->nm_ref
> 0) {
4762 msleep(&nmp
->nm_ref
, &nmp
->nm_lock
, PZERO
- 1, "nfs_mount_drain", NULL
);
4764 assert(nmp
->nm_ref
== 0);
4765 lck_mtx_unlock(&nmp
->nm_lock
);
4766 nfs_mount_cleanup(nmp
);
4773 nfs_mount_zombie(struct nfsmount
*nmp
, int nm_state_flags
)
4775 struct nfsreq
*req
, *treq
;
4776 struct nfs_reqqhead iodq
, resendq
;
4777 struct timespec ts
= { 1, 0 };
4778 struct nfs_open_owner
*noop
, *nextnoop
;
4782 lck_mtx_lock(&nmp
->nm_lock
);
4783 nmp
->nm_state
|= nm_state_flags
;
4785 lck_mtx_unlock(&nmp
->nm_lock
);
4787 /* stop callbacks */
4788 if ((nmp
->nm_vers
>= NFS_VER4
) && !NMFLAG(nmp
, NOCALLBACK
) && nmp
->nm_cbid
) {
4789 nfs4_mount_callback_shutdown(nmp
);
4792 /* Destroy any RPCSEC_GSS contexts */
4793 nfs_gss_clnt_ctx_unmount(nmp
);
4795 /* mark the socket for termination */
4796 lck_mtx_lock(&nmp
->nm_lock
);
4797 nmp
->nm_sockflags
|= NMSOCK_UNMOUNT
;
4799 /* Have the socket thread send the unmount RPC, if requested/appropriate. */
4800 if ((nmp
->nm_vers
< NFS_VER4
) && (nmp
->nm_state
& NFSSTA_MOUNTED
) &&
4801 !(nmp
->nm_state
& (NFSSTA_FORCE
| NFSSTA_DEAD
)) && NMFLAG(nmp
, CALLUMNT
)) {
4802 nfs_mount_sock_thread_wake(nmp
);
4805 /* wait for the socket thread to terminate */
4806 while (nmp
->nm_sockthd
&& current_thread() != nmp
->nm_sockthd
) {
4807 wakeup(&nmp
->nm_sockthd
);
4808 msleep(&nmp
->nm_sockthd
, &nmp
->nm_lock
, PZERO
- 1, "nfswaitsockthd", &ts
);
4810 lck_mtx_unlock(&nmp
->nm_lock
);
4812 /* tear down the socket */
4813 nfs_disconnect(nmp
);
4815 lck_mtx_lock(&nmp
->nm_lock
);
4817 if ((nmp
->nm_vers
>= NFS_VER4
) && !NMFLAG(nmp
, NOCALLBACK
) && nmp
->nm_cbid
) {
4818 /* clear out any pending delegation return requests */
4819 while ((np
= TAILQ_FIRST(&nmp
->nm_dreturnq
))) {
4820 TAILQ_REMOVE(&nmp
->nm_dreturnq
, np
, n_dreturn
);
4821 np
->n_dreturn
.tqe_next
= NFSNOLIST
;
4825 /* cancel any renew timer */
4826 if ((nmp
->nm_vers
>= NFS_VER4
) && nmp
->nm_renew_timer
) {
4827 thread_call_cancel(nmp
->nm_renew_timer
);
4828 thread_call_free(nmp
->nm_renew_timer
);
4829 nmp
->nm_renew_timer
= NULL
;
4832 lck_mtx_unlock(&nmp
->nm_lock
);
4834 if (nmp
->nm_state
& NFSSTA_MOUNTED
) {
4835 switch (nmp
->nm_lockmode
) {
4836 case NFS_LOCK_MODE_DISABLED
:
4837 case NFS_LOCK_MODE_LOCAL
:
4839 case NFS_LOCK_MODE_ENABLED
:
4841 if (nmp
->nm_vers
<= NFS_VER3
) {
4842 nfs_lockd_mount_unregister(nmp
);
4843 nmp
->nm_lockmode
= NFS_LOCK_MODE_DISABLED
;
4849 if ((nmp
->nm_vers
>= NFS_VER4
) && nmp
->nm_longid
) {
4850 /* remove/deallocate the client ID data */
4851 lck_mtx_lock(nfs_global_mutex
);
4852 TAILQ_REMOVE(&nfsclientids
, nmp
->nm_longid
, nci_link
);
4853 if (nmp
->nm_longid
->nci_id
) {
4854 FREE(nmp
->nm_longid
->nci_id
, M_TEMP
);
4856 FREE(nmp
->nm_longid
, M_TEMP
);
4857 nmp
->nm_longid
= NULL
;
4858 lck_mtx_unlock(nfs_global_mutex
);
4862 * Be sure all requests for this mount are completed
4863 * and removed from the resend queue.
4865 TAILQ_INIT(&resendq
);
4866 lck_mtx_lock(nfs_request_mutex
);
4867 TAILQ_FOREACH(req
, &nfs_reqq
, r_chain
) {
4868 if (req
->r_nmp
== nmp
) {
4869 lck_mtx_lock(&req
->r_mtx
);
4870 if (!req
->r_error
&& req
->r_nmrep
.nmc_mhead
== NULL
) {
4873 if (req
->r_flags
& R_RESENDQ
) {
4874 lck_mtx_lock(&nmp
->nm_lock
);
4875 req
->r_flags
&= ~R_RESENDQ
;
4876 if (req
->r_rchain
.tqe_next
!= NFSREQNOLIST
) {
4877 TAILQ_REMOVE(&nmp
->nm_resendq
, req
, r_rchain
);
4879 * Queue up the request so that we can unreference them
4880 * with out holding nfs_request_mutex
4882 TAILQ_INSERT_TAIL(&resendq
, req
, r_rchain
);
4884 lck_mtx_unlock(&nmp
->nm_lock
);
4887 lck_mtx_unlock(&req
->r_mtx
);
4890 lck_mtx_unlock(nfs_request_mutex
);
4892 /* Since we've drop the request mutex we can now safely unreference the request */
4893 TAILQ_FOREACH_SAFE(req
, &resendq
, r_rchain
, treq
) {
4894 TAILQ_REMOVE(&resendq
, req
, r_rchain
);
4895 /* Make sure we don't try and remove again in nfs_request_destroy */
4896 req
->r_rchain
.tqe_next
= NFSREQNOLIST
;
4897 nfs_request_rele(req
);
4901 * Now handle and outstanding async requests. We need to walk the
4902 * request queue again this time with the nfsiod_mutex held. No
4903 * other iods can grab our requests until we've put them on our own
4904 * local iod queue for processing.
4907 lck_mtx_lock(nfs_request_mutex
);
4908 lck_mtx_lock(nfsiod_mutex
);
4909 TAILQ_FOREACH(req
, &nfs_reqq
, r_chain
) {
4910 if (req
->r_nmp
== nmp
) {
4911 lck_mtx_lock(&req
->r_mtx
);
4912 if (req
->r_callback
.rcb_func
4913 && !(req
->r_flags
& R_WAITSENT
) && !(req
->r_flags
& R_IOD
)) {
4915 * Since R_IOD is not set then we need to handle it. If
4916 * we're not on a list add it to our iod queue. Otherwise
4917 * we must already be on nm_iodq which is added to our
4918 * local queue below.
4919 * %%% We should really keep a back pointer to our iod queue
4922 req
->r_flags
|= R_IOD
;
4923 if (req
->r_achain
.tqe_next
== NFSREQNOLIST
) {
4924 TAILQ_INSERT_TAIL(&iodq
, req
, r_achain
);
4927 lck_mtx_unlock(&req
->r_mtx
);
4931 /* finish any async I/O RPCs queued up */
4932 if (nmp
->nm_iodlink
.tqe_next
!= NFSNOLIST
) {
4933 TAILQ_REMOVE(&nfsiodmounts
, nmp
, nm_iodlink
);
4935 TAILQ_CONCAT(&iodq
, &nmp
->nm_iodq
, r_achain
);
4936 lck_mtx_unlock(nfsiod_mutex
);
4937 lck_mtx_unlock(nfs_request_mutex
);
4939 TAILQ_FOREACH_SAFE(req
, &iodq
, r_achain
, treq
) {
4940 TAILQ_REMOVE(&iodq
, req
, r_achain
);
4941 req
->r_achain
.tqe_next
= NFSREQNOLIST
;
4942 lck_mtx_lock(&req
->r_mtx
);
4943 docallback
= !(req
->r_flags
& R_WAITSENT
);
4944 lck_mtx_unlock(&req
->r_mtx
);
4946 req
->r_callback
.rcb_func(req
);
4950 /* clean up common state */
4951 lck_mtx_lock(&nmp
->nm_lock
);
4952 while ((np
= LIST_FIRST(&nmp
->nm_monlist
))) {
4953 LIST_REMOVE(np
, n_monlink
);
4954 np
->n_monlink
.le_next
= NFSNOLIST
;
4956 TAILQ_FOREACH_SAFE(noop
, &nmp
->nm_open_owners
, noo_link
, nextnoop
) {
4957 os_ref_count_t newcount
;
4959 TAILQ_REMOVE(&nmp
->nm_open_owners
, noop
, noo_link
);
4960 noop
->noo_flags
&= ~NFS_OPEN_OWNER_LINK
;
4961 newcount
= os_ref_release_locked(&noop
->noo_refcnt
);
4966 nfs_open_owner_destroy(noop
);
4968 lck_mtx_unlock(&nmp
->nm_lock
);
4970 /* clean up NFSv4 state */
4971 if (nmp
->nm_vers
>= NFS_VER4
) {
4972 lck_mtx_lock(&nmp
->nm_lock
);
4973 while ((np
= TAILQ_FIRST(&nmp
->nm_delegations
))) {
4974 TAILQ_REMOVE(&nmp
->nm_delegations
, np
, n_dlink
);
4975 np
->n_dlink
.tqe_next
= NFSNOLIST
;
4977 lck_mtx_unlock(&nmp
->nm_lock
);
4980 nfs_mount_rele(nmp
);
4984 * cleanup/destroy an nfsmount
4987 nfs_mount_cleanup(struct nfsmount
*nmp
)
4993 nfs_mount_zombie(nmp
, 0);
4995 NFS_VFS_DBG("Unmounting %s from %s\n",
4996 vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
,
4997 vfs_statfs(nmp
->nm_mountp
)->f_mntonname
);
4998 NFS_VFS_DBG("nfs state = 0x%8.8x\n", nmp
->nm_state
);
4999 NFS_VFS_DBG("nfs socket flags = 0x%8.8x\n", nmp
->nm_sockflags
);
5000 NFS_VFS_DBG("nfs mount ref count is %d\n", nmp
->nm_ref
);
5001 NFS_VFS_DBG("mount ref count is %d\n", nmp
->nm_mountp
->mnt_count
);
5003 if (nmp
->nm_mountp
) {
5004 vfs_setfsprivate(nmp
->nm_mountp
, NULL
);
5007 lck_mtx_lock(&nmp
->nm_lock
);
5009 panic("Some one has grabbed a ref %d state flags = 0x%8.8x\n", nmp
->nm_ref
, nmp
->nm_state
);
5012 if (nmp
->nm_saddr
) {
5013 FREE(nmp
->nm_saddr
, M_SONAME
);
5015 if ((nmp
->nm_vers
< NFS_VER4
) && nmp
->nm_rqsaddr
) {
5016 FREE(nmp
->nm_rqsaddr
, M_SONAME
);
5019 if (IS_VALID_CRED(nmp
->nm_mcred
)) {
5020 kauth_cred_unref(&nmp
->nm_mcred
);
5023 nfs_fs_locations_cleanup(&nmp
->nm_locations
);
5025 if (nmp
->nm_realm
) {
5026 FREE(nmp
->nm_realm
, M_TEMP
);
5028 if (nmp
->nm_principal
) {
5029 FREE(nmp
->nm_principal
, M_TEMP
);
5031 if (nmp
->nm_sprinc
) {
5032 FREE(nmp
->nm_sprinc
, M_TEMP
);
5036 xb_free(nmp
->nm_args
);
5039 lck_mtx_unlock(&nmp
->nm_lock
);
5041 lck_mtx_destroy(&nmp
->nm_lock
, nfs_mount_grp
);
5043 FREE(nmp
->nm_fh
, M_TEMP
);
5045 FREE_ZONE(nmp
, sizeof(struct nfsmount
), M_NFSMNT
);
5049 * Return root of a filesystem
5052 nfs_vfs_root(mount_t mp
, vnode_t
*vpp
, __unused vfs_context_t ctx
)
5055 struct nfsmount
*nmp
;
5060 if (!nmp
|| !nmp
->nm_dnp
) {
5063 vp
= NFSTOV(nmp
->nm_dnp
);
5064 vpid
= vnode_vid(vp
);
5065 while ((error
= vnode_getwithvid(vp
, vpid
))) {
5066 /* vnode_get() may return ENOENT if the dir changes. */
5067 /* If that happens, just try it again, else return the error. */
5068 if ((error
!= ENOENT
) || (vnode_vid(vp
) == vpid
)) {
5071 vpid
= vnode_vid(vp
);
5078 * Do operations associated with quotas
5083 __unused mount_t mp
,
5086 __unused caddr_t datap
,
5087 __unused vfs_context_t context
)
5094 nfs_sa_getport(struct sockaddr
*sa
, int *error
)
5098 if (sa
->sa_family
== AF_INET6
) {
5099 port
= ntohs(((struct sockaddr_in6
*)sa
)->sin6_port
);
5100 } else if (sa
->sa_family
== AF_INET
) {
5101 port
= ntohs(((struct sockaddr_in
*)sa
)->sin_port
);
5110 nfs_sa_setport(struct sockaddr
*sa
, int port
)
5112 if (sa
->sa_family
== AF_INET6
) {
5113 ((struct sockaddr_in6
*)sa
)->sin6_port
= htons(port
);
5114 } else if (sa
->sa_family
== AF_INET
) {
5115 ((struct sockaddr_in
*)sa
)->sin_port
= htons(port
);
5120 nfs3_getquota(struct nfsmount
*nmp
, vfs_context_t ctx
, uid_t id
, int type
, struct dqblk
*dqb
)
5122 int error
= 0, slen
, timeo
;
5123 int rqport
= 0, rqproto
, rqvers
= (type
== GRPQUOTA
) ? RPCRQUOTA_EXT_VER
: RPCRQUOTA_VER
;
5124 thread_t thd
= vfs_context_thread(ctx
);
5125 kauth_cred_t cred
= vfs_context_ucred(ctx
);
5128 struct nfsm_chain nmreq
, nmrep
;
5130 uint32_t val
= 0, bsize
= 0;
5131 struct sockaddr
*rqsaddr
;
5133 struct timespec ts
= { 1, 0 };
5135 if (!nmp
->nm_saddr
) {
5139 if (NMFLAG(nmp
, NOQUOTA
)) {
5144 * Allocate an address for rquotad if needed
5146 if (!nmp
->nm_rqsaddr
) {
5149 MALLOC(rqsaddr
, struct sockaddr
*, sizeof(struct sockaddr_storage
), M_SONAME
, M_WAITOK
| M_ZERO
);
5150 bcopy(nmp
->nm_saddr
, rqsaddr
, min(sizeof(struct sockaddr_storage
), nmp
->nm_saddr
->sa_len
));
5151 /* Set the port to zero, will call rpcbind to get the port below */
5152 nfs_sa_setport(rqsaddr
, 0);
5155 lck_mtx_lock(&nmp
->nm_lock
);
5156 if (!nmp
->nm_rqsaddr
) {
5157 nmp
->nm_rqsaddr
= rqsaddr
;
5158 nmp
->nm_rqsaddrstamp
= now
.tv_sec
;
5162 lck_mtx_unlock(&nmp
->nm_lock
);
5164 FREE(rqsaddr
, M_SONAME
);
5168 timeo
= NMFLAG(nmp
, SOFT
) ? 10 : 60;
5169 rqproto
= IPPROTO_UDP
; /* XXX should prefer TCP if mount is TCP */
5171 /* check if we have a recently cached rquota port */
5173 lck_mtx_lock(&nmp
->nm_lock
);
5174 rqsaddr
= nmp
->nm_rqsaddr
;
5175 rqport
= nfs_sa_getport(rqsaddr
, &error
);
5176 while (!error
&& (!rqport
|| ((nmp
->nm_rqsaddrstamp
+ 60) <= (uint32_t)now
.tv_sec
))) {
5177 error
= nfs_sigintr(nmp
, NULL
, thd
, 1);
5179 lck_mtx_unlock(&nmp
->nm_lock
);
5182 if (nmp
->nm_state
& NFSSTA_RQUOTAINPROG
) {
5183 nmp
->nm_state
|= NFSSTA_WANTRQUOTA
;
5184 msleep(&nmp
->nm_rqsaddr
, &nmp
->nm_lock
, PZERO
- 1, "nfswaitrquotaaddr", &ts
);
5185 rqport
= nfs_sa_getport(rqsaddr
, &error
);
5188 nmp
->nm_state
|= NFSSTA_RQUOTAINPROG
;
5189 lck_mtx_unlock(&nmp
->nm_lock
);
5191 /* send portmap request to get rquota port */
5192 error
= nfs_portmap_lookup(nmp
, ctx
, rqsaddr
, NULL
, RPCPROG_RQUOTA
, rqvers
, rqproto
, timeo
);
5196 rqport
= nfs_sa_getport(rqsaddr
, &error
);
5203 * We overload PMAPPORT for the port if rquotad is not
5204 * currently registered or up at the server. In the
5205 * while loop above, port will be set and we will defer
5206 * for a bit. Perhaps the service isn't online yet.
5208 * Note that precludes using indirect, but we're not doing
5212 nfs_sa_setport(rqsaddr
, rqport
);
5215 nmp
->nm_rqsaddrstamp
= now
.tv_sec
;
5217 lck_mtx_lock(&nmp
->nm_lock
);
5218 nmp
->nm_state
&= ~NFSSTA_RQUOTAINPROG
;
5219 if (nmp
->nm_state
& NFSSTA_WANTRQUOTA
) {
5220 nmp
->nm_state
&= ~NFSSTA_WANTRQUOTA
;
5221 wakeup(&nmp
->nm_rqsaddr
);
5224 lck_mtx_unlock(&nmp
->nm_lock
);
5229 /* Using PMAPPORT for unavailabe rquota service */
5230 if (rqport
== PMAPPORT
) {
5234 /* rquota request */
5235 nfsm_chain_null(&nmreq
);
5236 nfsm_chain_null(&nmrep
);
5237 path
= &vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
[0];
5238 while (*path
&& (*path
!= '/')) {
5241 slen
= strlen(path
);
5242 nfsm_chain_build_alloc_init(error
, &nmreq
, 3 * NFSX_UNSIGNED
+ nfsm_rndup(slen
));
5243 nfsm_chain_add_name(error
, &nmreq
, path
, slen
, nmp
);
5244 if (type
== GRPQUOTA
) {
5245 nfsm_chain_add_32(error
, &nmreq
, type
);
5247 nfsm_chain_add_32(error
, &nmreq
, id
);
5248 nfsm_chain_build_done(error
, &nmreq
);
5250 error
= nfsm_rpchead2(nmp
, (rqproto
== IPPROTO_UDP
) ? SOCK_DGRAM
: SOCK_STREAM
,
5251 RPCPROG_RQUOTA
, rqvers
, RPCRQUOTA_GET
,
5252 RPCAUTH_SYS
, cred
, NULL
, nmreq
.nmc_mhead
, &xid
, &mreq
);
5254 nmreq
.nmc_mhead
= NULL
;
5255 error
= nfs_aux_request(nmp
, thd
, rqsaddr
, NULL
,
5256 (rqproto
== IPPROTO_UDP
) ? SOCK_DGRAM
: SOCK_STREAM
,
5257 mreq
, R_XID32(xid
), 0, timeo
, &nmrep
);
5260 /* parse rquota response */
5261 nfsm_chain_get_32(error
, &nmrep
, val
);
5262 if (!error
&& (val
!= RQUOTA_STAT_OK
)) {
5263 if (val
== RQUOTA_STAT_NOQUOTA
) {
5265 } else if (val
== RQUOTA_STAT_EPERM
) {
5271 nfsm_chain_get_32(error
, &nmrep
, bsize
);
5272 nfsm_chain_adv(error
, &nmrep
, NFSX_UNSIGNED
);
5273 nfsm_chain_get_32(error
, &nmrep
, val
);
5275 dqb
->dqb_bhardlimit
= (uint64_t)val
* bsize
;
5276 nfsm_chain_get_32(error
, &nmrep
, val
);
5278 dqb
->dqb_bsoftlimit
= (uint64_t)val
* bsize
;
5279 nfsm_chain_get_32(error
, &nmrep
, val
);
5281 dqb
->dqb_curbytes
= (uint64_t)val
* bsize
;
5282 nfsm_chain_get_32(error
, &nmrep
, dqb
->dqb_ihardlimit
);
5283 nfsm_chain_get_32(error
, &nmrep
, dqb
->dqb_isoftlimit
);
5284 nfsm_chain_get_32(error
, &nmrep
, dqb
->dqb_curinodes
);
5285 nfsm_chain_get_32(error
, &nmrep
, dqb
->dqb_btime
);
5286 nfsm_chain_get_32(error
, &nmrep
, dqb
->dqb_itime
);
5290 nfsm_chain_cleanup(&nmreq
);
5291 nfsm_chain_cleanup(&nmrep
);
5296 nfs4_getquota(struct nfsmount
*nmp
, vfs_context_t ctx
, uid_t id
, int type
, struct dqblk
*dqb
)
5299 int error
= 0, status
, nfsvers
, numops
;
5301 struct nfsm_chain nmreq
, nmrep
;
5302 uint32_t bitmap
[NFS_ATTR_BITMAP_LEN
];
5303 thread_t thd
= vfs_context_thread(ctx
);
5304 kauth_cred_t cred
= vfs_context_ucred(ctx
);
5305 struct nfsreq_secinfo_args si
;
5307 if (type
!= USRQUOTA
) { /* NFSv4 only supports user quotas */
5311 /* first check that the server supports any of the quota attributes */
5312 if (!NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_QUOTA_AVAIL_HARD
) &&
5313 !NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_QUOTA_AVAIL_SOFT
) &&
5314 !NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_QUOTA_USED
)) {
5319 * The credential passed to the server needs to have
5320 * an effective uid that matches the given uid.
5322 if (id
!= kauth_cred_getuid(cred
)) {
5323 struct posix_cred temp_pcred
;
5324 posix_cred_t pcred
= posix_cred_get(cred
);
5325 bzero(&temp_pcred
, sizeof(temp_pcred
));
5326 temp_pcred
.cr_uid
= id
;
5327 temp_pcred
.cr_ngroups
= pcred
->cr_ngroups
;
5328 bcopy(pcred
->cr_groups
, temp_pcred
.cr_groups
, sizeof(temp_pcred
.cr_groups
));
5329 cred
= posix_cred_create(&temp_pcred
);
5330 if (!IS_VALID_CRED(cred
)) {
5334 kauth_cred_ref(cred
);
5337 nfsvers
= nmp
->nm_vers
;
5342 if (error
|| ((error
= vnode_get(NFSTOV(np
))))) {
5343 kauth_cred_unref(&cred
);
5347 NFSREQ_SECINFO_SET(&si
, np
, NULL
, 0, NULL
, 0);
5348 nfsm_chain_null(&nmreq
);
5349 nfsm_chain_null(&nmrep
);
5353 nfsm_chain_build_alloc_init(error
, &nmreq
, 15 * NFSX_UNSIGNED
);
5354 nfsm_chain_add_compound_header(error
, &nmreq
, "quota", nmp
->nm_minor_vers
, numops
);
5356 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
5357 nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, np
->n_fhp
, np
->n_fhsize
);
5359 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
5360 NFS_CLEAR_ATTRIBUTES(bitmap
);
5361 NFS_BITMAP_SET(bitmap
, NFS_FATTR_QUOTA_AVAIL_HARD
);
5362 NFS_BITMAP_SET(bitmap
, NFS_FATTR_QUOTA_AVAIL_SOFT
);
5363 NFS_BITMAP_SET(bitmap
, NFS_FATTR_QUOTA_USED
);
5364 nfsm_chain_add_bitmap_supported(error
, &nmreq
, bitmap
, nmp
, NULL
);
5365 nfsm_chain_build_done(error
, &nmreq
);
5366 nfsm_assert(error
, (numops
== 0), EPROTO
);
5368 error
= nfs_request2(np
, NULL
, &nmreq
, NFSPROC4_COMPOUND
, thd
, cred
, &si
, 0, &nmrep
, &xid
, &status
);
5369 nfsm_chain_skip_tag(error
, &nmrep
);
5370 nfsm_chain_get_32(error
, &nmrep
, numops
);
5371 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
5372 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
5373 nfsm_assert(error
, NFSTONMP(np
), ENXIO
);
5375 error
= nfs4_parsefattr(&nmrep
, NULL
, NULL
, NULL
, dqb
, NULL
);
5377 nfsm_assert(error
, NFSTONMP(np
), ENXIO
);
5379 nfsm_chain_cleanup(&nmreq
);
5380 nfsm_chain_cleanup(&nmrep
);
5381 vnode_put(NFSTOV(np
));
5382 kauth_cred_unref(&cred
);
5387 nfs_vfs_quotactl(mount_t mp
, int cmds
, uid_t uid
, caddr_t datap
, vfs_context_t ctx
)
5389 struct nfsmount
*nmp
;
5390 int cmd
, type
, error
, nfsvers
;
5391 uid_t euid
= kauth_cred_getuid(vfs_context_ucred(ctx
));
5392 struct dqblk
*dqb
= (struct dqblk
*)datap
;
5395 if (nfs_mount_gone(nmp
)) {
5398 nfsvers
= nmp
->nm_vers
;
5404 /* we can only support Q_GETQUOTA */
5405 cmd
= cmds
>> SUBCMDSHIFT
;
5420 type
= cmds
& SUBCMDMASK
;
5421 if ((u_int
)type
>= MAXQUOTAS
) {
5424 if ((uid
!= euid
) && ((error
= vfs_context_suser(ctx
)))) {
5428 if (vfs_busy(mp
, LK_NOWAIT
)) {
5431 bzero(dqb
, sizeof(*dqb
));
5432 error
= nmp
->nm_funcs
->nf_getquota(nmp
, ctx
, uid
, type
, dqb
);
5439 * Flush out the buffer cache
5441 int nfs_sync_callout(vnode_t
, void *);
5443 struct nfs_sync_cargs
{
5450 nfs_sync_callout(vnode_t vp
, void *arg
)
5452 struct nfs_sync_cargs
*cargs
= (struct nfs_sync_cargs
*)arg
;
5453 nfsnode_t np
= VTONFS(vp
);
5456 if (np
->n_flag
& NREVOKE
) {
5457 vn_revoke(vp
, REVOKEALL
, cargs
->ctx
);
5458 return VNODE_RETURNED
;
5461 if (LIST_EMPTY(&np
->n_dirtyblkhd
)) {
5462 return VNODE_RETURNED
;
5464 if (np
->n_wrbusy
> 0) {
5465 return VNODE_RETURNED
;
5467 if (np
->n_bflag
& (NBFLUSHINPROG
| NBINVALINPROG
)) {
5468 return VNODE_RETURNED
;
5471 error
= nfs_flush(np
, cargs
->waitfor
, vfs_context_thread(cargs
->ctx
), 0);
5473 cargs
->error
= error
;
5476 return VNODE_RETURNED
;
5480 nfs_vfs_sync(mount_t mp
, int waitfor
, vfs_context_t ctx
)
5482 struct nfs_sync_cargs cargs
;
5484 cargs
.waitfor
= waitfor
;
5488 vnode_iterate(mp
, 0, nfs_sync_callout
, &cargs
);
5494 * NFS flat namespace lookup.
5495 * Currently unsupported.
5500 __unused mount_t mp
,
5501 __unused ino64_t ino
,
5502 __unused vnode_t
*vpp
,
5503 __unused vfs_context_t ctx
)
5509 * At this point, this should never happen
5514 __unused mount_t mp
,
5516 __unused
unsigned char *fhp
,
5517 __unused vnode_t
*vpp
,
5518 __unused vfs_context_t ctx
)
5524 * Vnode pointer to File handle, should never happen either
5529 __unused vnode_t vp
,
5530 __unused
int *fhlenp
,
5531 __unused
unsigned char *fhp
,
5532 __unused vfs_context_t ctx
)
5538 * Vfs start routine, a no-op.
5543 __unused mount_t mp
,
5545 __unused vfs_context_t ctx
)
5551 * Build the mount info buffer for NFS_MOUNTINFO.
5554 nfs_mountinfo_assemble(struct nfsmount
*nmp
, struct xdrbuf
*xb
)
5556 struct xdrbuf xbinfo
, xborig
;
5558 uint32_t origargsvers
, origargslength
;
5559 uint32_t infolength_offset
, curargsopaquelength_offset
, curargslength_offset
, attrslength_offset
, curargs_end_offset
, end_offset
;
5560 uint32_t miattrs
[NFS_MIATTR_BITMAP_LEN
];
5561 uint32_t miflags_mask
[NFS_MIFLAG_BITMAP_LEN
];
5562 uint32_t miflags
[NFS_MIFLAG_BITMAP_LEN
];
5563 uint32_t mattrs
[NFS_MATTR_BITMAP_LEN
];
5564 uint32_t mflags_mask
[NFS_MFLAG_BITMAP_LEN
];
5565 uint32_t mflags
[NFS_MFLAG_BITMAP_LEN
];
5566 uint32_t loc
, serv
, addr
, comp
;
5567 int i
, timeo
, error
= 0;
5569 /* set up mount info attr and flag bitmaps */
5570 NFS_BITMAP_ZERO(miattrs
, NFS_MIATTR_BITMAP_LEN
);
5571 NFS_BITMAP_SET(miattrs
, NFS_MIATTR_FLAGS
);
5572 NFS_BITMAP_SET(miattrs
, NFS_MIATTR_ORIG_ARGS
);
5573 NFS_BITMAP_SET(miattrs
, NFS_MIATTR_CUR_ARGS
);
5574 NFS_BITMAP_SET(miattrs
, NFS_MIATTR_CUR_LOC_INDEX
);
5575 NFS_BITMAP_ZERO(miflags_mask
, NFS_MIFLAG_BITMAP_LEN
);
5576 NFS_BITMAP_ZERO(miflags
, NFS_MIFLAG_BITMAP_LEN
);
5577 NFS_BITMAP_SET(miflags_mask
, NFS_MIFLAG_DEAD
);
5578 NFS_BITMAP_SET(miflags_mask
, NFS_MIFLAG_NOTRESP
);
5579 NFS_BITMAP_SET(miflags_mask
, NFS_MIFLAG_RECOVERY
);
5580 if (nmp
->nm_state
& NFSSTA_DEAD
) {
5581 NFS_BITMAP_SET(miflags
, NFS_MIFLAG_DEAD
);
5583 if ((nmp
->nm_state
& (NFSSTA_TIMEO
| NFSSTA_JUKEBOXTIMEO
)) ||
5584 ((nmp
->nm_state
& NFSSTA_LOCKTIMEO
) && (nmp
->nm_lockmode
== NFS_LOCK_MODE_ENABLED
))) {
5585 NFS_BITMAP_SET(miflags
, NFS_MIFLAG_NOTRESP
);
5587 if (nmp
->nm_state
& NFSSTA_RECOVER
) {
5588 NFS_BITMAP_SET(miflags
, NFS_MIFLAG_RECOVERY
);
5591 /* get original mount args length */
5592 xb_init_buffer(&xborig
, nmp
->nm_args
, 2 * XDRWORD
);
5593 xb_get_32(error
, &xborig
, origargsvers
); /* version */
5594 xb_get_32(error
, &xborig
, origargslength
); /* args length */
5597 /* set up current mount attributes bitmap */
5598 NFS_BITMAP_ZERO(mattrs
, NFS_MATTR_BITMAP_LEN
);
5599 NFS_BITMAP_SET(mattrs
, NFS_MATTR_FLAGS
);
5600 NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_VERSION
);
5601 if (nmp
->nm_vers
>= NFS_VER4
) {
5602 NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_MINOR_VERSION
);
5604 NFS_BITMAP_SET(mattrs
, NFS_MATTR_READ_SIZE
);
5605 NFS_BITMAP_SET(mattrs
, NFS_MATTR_WRITE_SIZE
);
5606 NFS_BITMAP_SET(mattrs
, NFS_MATTR_READDIR_SIZE
);
5607 NFS_BITMAP_SET(mattrs
, NFS_MATTR_READAHEAD
);
5608 NFS_BITMAP_SET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MIN
);
5609 NFS_BITMAP_SET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MAX
);
5610 NFS_BITMAP_SET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MIN
);
5611 NFS_BITMAP_SET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MAX
);
5612 NFS_BITMAP_SET(mattrs
, NFS_MATTR_LOCK_MODE
);
5613 NFS_BITMAP_SET(mattrs
, NFS_MATTR_SECURITY
);
5614 if (nmp
->nm_etype
.selected
< nmp
->nm_etype
.count
) {
5615 NFS_BITMAP_SET(mattrs
, NFS_MATTR_KERB_ETYPE
);
5617 NFS_BITMAP_SET(mattrs
, NFS_MATTR_MAX_GROUP_LIST
);
5618 NFS_BITMAP_SET(mattrs
, NFS_MATTR_SOCKET_TYPE
);
5619 NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_PORT
);
5620 if ((nmp
->nm_vers
< NFS_VER4
) && nmp
->nm_mountport
) {
5621 NFS_BITMAP_SET(mattrs
, NFS_MATTR_MOUNT_PORT
);
5623 NFS_BITMAP_SET(mattrs
, NFS_MATTR_REQUEST_TIMEOUT
);
5624 if (NMFLAG(nmp
, SOFT
)) {
5625 NFS_BITMAP_SET(mattrs
, NFS_MATTR_SOFT_RETRY_COUNT
);
5627 if (nmp
->nm_deadtimeout
) {
5628 NFS_BITMAP_SET(mattrs
, NFS_MATTR_DEAD_TIMEOUT
);
5631 NFS_BITMAP_SET(mattrs
, NFS_MATTR_FH
);
5633 NFS_BITMAP_SET(mattrs
, NFS_MATTR_FS_LOCATIONS
);
5634 NFS_BITMAP_SET(mattrs
, NFS_MATTR_MNTFLAGS
);
5635 if (origargsvers
< NFS_ARGSVERSION_XDR
) {
5636 NFS_BITMAP_SET(mattrs
, NFS_MATTR_MNTFROM
);
5638 if (nmp
->nm_realm
) {
5639 NFS_BITMAP_SET(mattrs
, NFS_MATTR_REALM
);
5641 if (nmp
->nm_principal
) {
5642 NFS_BITMAP_SET(mattrs
, NFS_MATTR_PRINCIPAL
);
5644 if (nmp
->nm_sprinc
) {
5645 NFS_BITMAP_SET(mattrs
, NFS_MATTR_SVCPRINCIPAL
);
5648 /* set up current mount flags bitmap */
5649 /* first set the flags that we will be setting - either on OR off */
5650 NFS_BITMAP_ZERO(mflags_mask
, NFS_MFLAG_BITMAP_LEN
);
5651 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_SOFT
);
5652 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_INTR
);
5653 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_RESVPORT
);
5654 if (nmp
->nm_sotype
== SOCK_DGRAM
) {
5655 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NOCONNECT
);
5657 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_DUMBTIMER
);
5658 if (nmp
->nm_vers
< NFS_VER4
) {
5659 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_CALLUMNT
);
5661 if (nmp
->nm_vers
>= NFS_VER3
) {
5662 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_RDIRPLUS
);
5664 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NONEGNAMECACHE
);
5665 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_MUTEJUKEBOX
);
5666 if (nmp
->nm_vers
>= NFS_VER4
) {
5667 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_EPHEMERAL
);
5668 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NOCALLBACK
);
5669 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NAMEDATTR
);
5670 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NOACL
);
5671 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_ACLONLY
);
5673 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NFC
);
5674 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NOQUOTA
);
5675 if (nmp
->nm_vers
< NFS_VER4
) {
5676 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_MNTUDP
);
5678 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_MNTQUICK
);
5679 /* now set the flags that should be set */
5680 NFS_BITMAP_ZERO(mflags
, NFS_MFLAG_BITMAP_LEN
);
5681 if (NMFLAG(nmp
, SOFT
)) {
5682 NFS_BITMAP_SET(mflags
, NFS_MFLAG_SOFT
);
5684 if (NMFLAG(nmp
, INTR
)) {
5685 NFS_BITMAP_SET(mflags
, NFS_MFLAG_INTR
);
5687 if (NMFLAG(nmp
, RESVPORT
)) {
5688 NFS_BITMAP_SET(mflags
, NFS_MFLAG_RESVPORT
);
5690 if ((nmp
->nm_sotype
== SOCK_DGRAM
) && NMFLAG(nmp
, NOCONNECT
)) {
5691 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NOCONNECT
);
5693 if (NMFLAG(nmp
, DUMBTIMER
)) {
5694 NFS_BITMAP_SET(mflags
, NFS_MFLAG_DUMBTIMER
);
5696 if ((nmp
->nm_vers
< NFS_VER4
) && NMFLAG(nmp
, CALLUMNT
)) {
5697 NFS_BITMAP_SET(mflags
, NFS_MFLAG_CALLUMNT
);
5699 if ((nmp
->nm_vers
>= NFS_VER3
) && NMFLAG(nmp
, RDIRPLUS
)) {
5700 NFS_BITMAP_SET(mflags
, NFS_MFLAG_RDIRPLUS
);
5702 if (NMFLAG(nmp
, NONEGNAMECACHE
)) {
5703 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NONEGNAMECACHE
);
5705 if (NMFLAG(nmp
, MUTEJUKEBOX
)) {
5706 NFS_BITMAP_SET(mflags
, NFS_MFLAG_MUTEJUKEBOX
);
5708 if (nmp
->nm_vers
>= NFS_VER4
) {
5709 if (NMFLAG(nmp
, EPHEMERAL
)) {
5710 NFS_BITMAP_SET(mflags
, NFS_MFLAG_EPHEMERAL
);
5712 if (NMFLAG(nmp
, NOCALLBACK
)) {
5713 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NOCALLBACK
);
5715 if (NMFLAG(nmp
, NAMEDATTR
)) {
5716 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NAMEDATTR
);
5718 if (NMFLAG(nmp
, NOACL
)) {
5719 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NOACL
);
5721 if (NMFLAG(nmp
, ACLONLY
)) {
5722 NFS_BITMAP_SET(mflags
, NFS_MFLAG_ACLONLY
);
5725 if (NMFLAG(nmp
, NFC
)) {
5726 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NFC
);
5728 if (NMFLAG(nmp
, NOQUOTA
) || ((nmp
->nm_vers
>= NFS_VER4
) &&
5729 !NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_QUOTA_AVAIL_HARD
) &&
5730 !NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_QUOTA_AVAIL_SOFT
) &&
5731 !NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_QUOTA_USED
))) {
5732 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NOQUOTA
);
5734 if ((nmp
->nm_vers
< NFS_VER4
) && NMFLAG(nmp
, MNTUDP
)) {
5735 NFS_BITMAP_SET(mflags
, NFS_MFLAG_MNTUDP
);
5737 if (NMFLAG(nmp
, MNTQUICK
)) {
5738 NFS_BITMAP_SET(mflags
, NFS_MFLAG_MNTQUICK
);
5741 /* assemble info buffer: */
5742 xb_init_buffer(&xbinfo
, NULL
, 0);
5743 xb_add_32(error
, &xbinfo
, NFS_MOUNT_INFO_VERSION
);
5744 infolength_offset
= xb_offset(&xbinfo
);
5745 xb_add_32(error
, &xbinfo
, 0);
5746 xb_add_bitmap(error
, &xbinfo
, miattrs
, NFS_MIATTR_BITMAP_LEN
);
5747 xb_add_bitmap(error
, &xbinfo
, miflags
, NFS_MIFLAG_BITMAP_LEN
);
5748 xb_add_32(error
, &xbinfo
, origargslength
);
5750 error
= xb_add_bytes(&xbinfo
, nmp
->nm_args
, origargslength
, 0);
5753 /* the opaque byte count for the current mount args values: */
5754 curargsopaquelength_offset
= xb_offset(&xbinfo
);
5755 xb_add_32(error
, &xbinfo
, 0);
5757 /* Encode current mount args values */
5758 xb_add_32(error
, &xbinfo
, NFS_ARGSVERSION_XDR
);
5759 curargslength_offset
= xb_offset(&xbinfo
);
5760 xb_add_32(error
, &xbinfo
, 0);
5761 xb_add_32(error
, &xbinfo
, NFS_XDRARGS_VERSION_0
);
5762 xb_add_bitmap(error
, &xbinfo
, mattrs
, NFS_MATTR_BITMAP_LEN
);
5763 attrslength_offset
= xb_offset(&xbinfo
);
5764 xb_add_32(error
, &xbinfo
, 0);
5765 xb_add_bitmap(error
, &xbinfo
, mflags_mask
, NFS_MFLAG_BITMAP_LEN
);
5766 xb_add_bitmap(error
, &xbinfo
, mflags
, NFS_MFLAG_BITMAP_LEN
);
5767 xb_add_32(error
, &xbinfo
, nmp
->nm_vers
); /* NFS_VERSION */
5768 if (nmp
->nm_vers
>= NFS_VER4
) {
5769 xb_add_32(error
, &xbinfo
, nmp
->nm_minor_vers
); /* NFS_MINOR_VERSION */
5771 xb_add_32(error
, &xbinfo
, nmp
->nm_rsize
); /* READ_SIZE */
5772 xb_add_32(error
, &xbinfo
, nmp
->nm_wsize
); /* WRITE_SIZE */
5773 xb_add_32(error
, &xbinfo
, nmp
->nm_readdirsize
); /* READDIR_SIZE */
5774 xb_add_32(error
, &xbinfo
, nmp
->nm_readahead
); /* READAHEAD */
5775 xb_add_32(error
, &xbinfo
, nmp
->nm_acregmin
); /* ATTRCACHE_REG_MIN */
5776 xb_add_32(error
, &xbinfo
, 0); /* ATTRCACHE_REG_MIN */
5777 xb_add_32(error
, &xbinfo
, nmp
->nm_acregmax
); /* ATTRCACHE_REG_MAX */
5778 xb_add_32(error
, &xbinfo
, 0); /* ATTRCACHE_REG_MAX */
5779 xb_add_32(error
, &xbinfo
, nmp
->nm_acdirmin
); /* ATTRCACHE_DIR_MIN */
5780 xb_add_32(error
, &xbinfo
, 0); /* ATTRCACHE_DIR_MIN */
5781 xb_add_32(error
, &xbinfo
, nmp
->nm_acdirmax
); /* ATTRCACHE_DIR_MAX */
5782 xb_add_32(error
, &xbinfo
, 0); /* ATTRCACHE_DIR_MAX */
5783 xb_add_32(error
, &xbinfo
, nmp
->nm_lockmode
); /* LOCK_MODE */
5784 if (nmp
->nm_sec
.count
) {
5785 xb_add_32(error
, &xbinfo
, nmp
->nm_sec
.count
); /* SECURITY */
5787 for (i
= 0; i
< nmp
->nm_sec
.count
; i
++) {
5788 xb_add_32(error
, &xbinfo
, nmp
->nm_sec
.flavors
[i
]);
5790 } else if (nmp
->nm_servsec
.count
) {
5791 xb_add_32(error
, &xbinfo
, nmp
->nm_servsec
.count
); /* SECURITY */
5793 for (i
= 0; i
< nmp
->nm_servsec
.count
; i
++) {
5794 xb_add_32(error
, &xbinfo
, nmp
->nm_servsec
.flavors
[i
]);
5797 xb_add_32(error
, &xbinfo
, 1); /* SECURITY */
5798 xb_add_32(error
, &xbinfo
, nmp
->nm_auth
);
5800 if (nmp
->nm_etype
.selected
< nmp
->nm_etype
.count
) {
5801 xb_add_32(error
, &xbinfo
, nmp
->nm_etype
.count
);
5802 xb_add_32(error
, &xbinfo
, nmp
->nm_etype
.selected
);
5803 for (uint32_t j
= 0; j
< nmp
->nm_etype
.count
; j
++) {
5804 xb_add_32(error
, &xbinfo
, nmp
->nm_etype
.etypes
[j
]);
5808 xb_add_32(error
, &xbinfo
, nmp
->nm_numgrps
); /* MAX_GROUP_LIST */
5810 snprintf(sotype
, sizeof(sotype
), "%s%s", (nmp
->nm_sotype
== SOCK_DGRAM
) ? "udp" : "tcp",
5811 nmp
->nm_sofamily
? (nmp
->nm_sofamily
== AF_INET
) ? "4" : "6" : "");
5812 xb_add_string(error
, &xbinfo
, sotype
, strlen(sotype
)); /* SOCKET_TYPE */
5813 xb_add_32(error
, &xbinfo
, ntohs(((struct sockaddr_in
*)nmp
->nm_saddr
)->sin_port
)); /* NFS_PORT */
5814 if ((nmp
->nm_vers
< NFS_VER4
) && nmp
->nm_mountport
) {
5815 xb_add_32(error
, &xbinfo
, nmp
->nm_mountport
); /* MOUNT_PORT */
5817 timeo
= (nmp
->nm_timeo
* 10) / NFS_HZ
;
5818 xb_add_32(error
, &xbinfo
, timeo
/ 10); /* REQUEST_TIMEOUT */
5819 xb_add_32(error
, &xbinfo
, (timeo
% 10) * 100000000); /* REQUEST_TIMEOUT */
5820 if (NMFLAG(nmp
, SOFT
)) {
5821 xb_add_32(error
, &xbinfo
, nmp
->nm_retry
); /* SOFT_RETRY_COUNT */
5823 if (nmp
->nm_deadtimeout
) {
5824 xb_add_32(error
, &xbinfo
, nmp
->nm_deadtimeout
); /* DEAD_TIMEOUT */
5825 xb_add_32(error
, &xbinfo
, 0); /* DEAD_TIMEOUT */
5828 xb_add_fh(error
, &xbinfo
, &nmp
->nm_fh
->fh_data
[0], nmp
->nm_fh
->fh_len
); /* FH */
5830 xb_add_32(error
, &xbinfo
, nmp
->nm_locations
.nl_numlocs
); /* FS_LOCATIONS */
5831 for (loc
= 0; !error
&& (loc
< nmp
->nm_locations
.nl_numlocs
); loc
++) {
5832 xb_add_32(error
, &xbinfo
, nmp
->nm_locations
.nl_locations
[loc
]->nl_servcount
);
5833 for (serv
= 0; !error
&& (serv
< nmp
->nm_locations
.nl_locations
[loc
]->nl_servcount
); serv
++) {
5834 xb_add_string(error
, &xbinfo
, nmp
->nm_locations
.nl_locations
[loc
]->nl_servers
[serv
]->ns_name
,
5835 strlen(nmp
->nm_locations
.nl_locations
[loc
]->nl_servers
[serv
]->ns_name
));
5836 xb_add_32(error
, &xbinfo
, nmp
->nm_locations
.nl_locations
[loc
]->nl_servers
[serv
]->ns_addrcount
);
5837 for (addr
= 0; !error
&& (addr
< nmp
->nm_locations
.nl_locations
[loc
]->nl_servers
[serv
]->ns_addrcount
); addr
++) {
5838 xb_add_string(error
, &xbinfo
, nmp
->nm_locations
.nl_locations
[loc
]->nl_servers
[serv
]->ns_addresses
[addr
],
5839 strlen(nmp
->nm_locations
.nl_locations
[loc
]->nl_servers
[serv
]->ns_addresses
[addr
]));
5841 xb_add_32(error
, &xbinfo
, 0); /* empty server info */
5843 xb_add_32(error
, &xbinfo
, nmp
->nm_locations
.nl_locations
[loc
]->nl_path
.np_compcount
);
5844 for (comp
= 0; !error
&& (comp
< nmp
->nm_locations
.nl_locations
[loc
]->nl_path
.np_compcount
); comp
++) {
5845 xb_add_string(error
, &xbinfo
, nmp
->nm_locations
.nl_locations
[loc
]->nl_path
.np_components
[comp
],
5846 strlen(nmp
->nm_locations
.nl_locations
[loc
]->nl_path
.np_components
[comp
]));
5848 xb_add_32(error
, &xbinfo
, 0); /* empty fs location info */
5850 xb_add_32(error
, &xbinfo
, vfs_flags(nmp
->nm_mountp
)); /* MNTFLAGS */
5851 if (origargsvers
< NFS_ARGSVERSION_XDR
) {
5852 xb_add_string(error
, &xbinfo
, vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
,
5853 strlen(vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
)); /* MNTFROM */
5855 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_REALM
)) {
5856 xb_add_string(error
, &xbinfo
, nmp
->nm_realm
, strlen(nmp
->nm_realm
));
5858 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_PRINCIPAL
)) {
5859 xb_add_string(error
, &xbinfo
, nmp
->nm_principal
, strlen(nmp
->nm_principal
));
5861 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SVCPRINCIPAL
)) {
5862 xb_add_string(error
, &xbinfo
, nmp
->nm_sprinc
, strlen(nmp
->nm_sprinc
));
5865 curargs_end_offset
= xb_offset(&xbinfo
);
5867 /* NFS_MIATTR_CUR_LOC_INDEX */
5868 xb_add_32(error
, &xbinfo
, nmp
->nm_locations
.nl_current
.nli_flags
);
5869 xb_add_32(error
, &xbinfo
, nmp
->nm_locations
.nl_current
.nli_loc
);
5870 xb_add_32(error
, &xbinfo
, nmp
->nm_locations
.nl_current
.nli_serv
);
5871 xb_add_32(error
, &xbinfo
, nmp
->nm_locations
.nl_current
.nli_addr
);
5873 xb_build_done(error
, &xbinfo
);
5875 /* update opaque counts */
5876 end_offset
= xb_offset(&xbinfo
);
5878 error
= xb_seek(&xbinfo
, attrslength_offset
);
5879 xb_add_32(error
, &xbinfo
, curargs_end_offset
- attrslength_offset
- XDRWORD
/*don't include length field*/);
5882 error
= xb_seek(&xbinfo
, curargslength_offset
);
5883 xb_add_32(error
, &xbinfo
, curargs_end_offset
- curargslength_offset
+ XDRWORD
/*version*/);
5886 error
= xb_seek(&xbinfo
, curargsopaquelength_offset
);
5887 xb_add_32(error
, &xbinfo
, curargs_end_offset
- curargslength_offset
+ XDRWORD
/*version*/);
5890 error
= xb_seek(&xbinfo
, infolength_offset
);
5891 xb_add_32(error
, &xbinfo
, end_offset
- infolength_offset
+ XDRWORD
/*version*/);
5895 /* copy result xdrbuf to caller */
5898 /* and mark the local copy as not needing cleanup */
5899 xbinfo
.xb_flags
&= ~XB_CLEANUP
;
5901 xb_cleanup(&xbinfo
);
5906 * Do that sysctl thang...
5909 nfs_vfs_sysctl(int *name
, u_int namelen
, user_addr_t oldp
, size_t *oldlenp
,
5910 user_addr_t newp
, size_t newlen
, vfs_context_t ctx
)
5913 #ifndef CONFIG_EMBEDDED
5916 struct sysctl_req
*req
= NULL
;
5917 union union_vfsidctl vc
;
5919 struct nfsmount
*nmp
= NULL
;
5922 boolean_t is_64_bit
;
5925 struct netfs_status
*nsp
= NULL
;
5927 uint pos
, totlen
, count
, numThreads
;
5929 struct nfs_exportfs
*nxfs
;
5930 struct nfs_export
*nx
;
5931 struct nfs_active_user_list
*ulist
;
5932 struct nfs_export_stat_desc stat_desc
= {};
5933 struct nfs_export_stat_rec statrec
;
5934 struct nfs_user_stat_node
*unode
, *unode_next
;
5935 struct nfs_user_stat_desc ustat_desc
= {};
5936 struct nfs_user_stat_user_rec ustat_rec
;
5937 struct nfs_user_stat_path_rec upath_rec
;
5938 uint bytes_avail
, bytes_total
, recs_copied
;
5939 uint numExports
, numRecs
;
5940 #endif /* NFSSERVER */
5943 * All names at this level are terminal.
5946 return ENOTDIR
; /* overloaded */
5948 is_64_bit
= vfs_context_is64bit(ctx
);
5950 /* common code for "new style" VFS_CTL sysctl, get the mount. */
5953 case VFS_CTL_NOLOCKS
:
5954 case VFS_CTL_NSTATUS
:
5955 #ifndef CONFIG_EMBEDDED
5958 req
= CAST_DOWN(struct sysctl_req
*, oldp
);
5962 error
= SYSCTL_IN(req
, &vc
, is_64_bit
? sizeof(vc
.vc64
):sizeof(vc
.vc32
));
5966 mp
= vfs_getvfs(&vc
.vc32
.vc_fsid
); /* works for 32 and 64 */
5974 bzero(&vq
, sizeof(vq
));
5977 req
->newptr
= vc
.vc64
.vc_ptr
;
5978 req
->newlen
= (size_t)vc
.vc64
.vc_len
;
5980 req
->newptr
= CAST_USER_ADDR_T(vc
.vc32
.vc_ptr
);
5981 req
->newlen
= vc
.vc32
.vc_len
;
5993 *oldlenp
= sizeof nfsstats
;
5997 if (*oldlenp
< sizeof nfsstats
) {
5998 *oldlenp
= sizeof nfsstats
;
6002 error
= copyout(&nfsstats
, oldp
, sizeof nfsstats
);
6007 if (newp
&& newlen
!= sizeof nfsstats
) {
6012 return copyin(newp
, &nfsstats
, sizeof nfsstats
);
6016 /* read in the fsid */
6017 if (*oldlenp
< sizeof(fsid
)) {
6020 if ((error
= copyin(oldp
, &fsid
, sizeof(fsid
)))) {
6023 /* swizzle it back to host order */
6024 fsid
.val
[0] = ntohl(fsid
.val
[0]);
6025 fsid
.val
[1] = ntohl(fsid
.val
[1]);
6026 /* find mount and make sure it's NFS */
6027 if (((mp
= vfs_getvfs(&fsid
))) == NULL
) {
6030 if (strcmp(mp
->mnt_vfsstat
.f_fstypename
, "nfs")) {
6033 if (((nmp
= VFSTONFS(mp
))) == NULL
) {
6037 if ((error
= nfs_mountinfo_assemble(nmp
, &xb
))) {
6040 if (*oldlenp
< xb
.xb_u
.xb_buffer
.xbb_len
) {
6043 error
= copyout(xb_buffer_base(&xb
), oldp
, xb
.xb_u
.xb_buffer
.xbb_len
);
6045 *oldlenp
= xb
.xb_u
.xb_buffer
.xbb_len
;
6049 case NFS_EXPORTSTATS
:
6050 /* setup export stat descriptor */
6051 stat_desc
.rec_vers
= NFS_EXPORT_STAT_REC_VERSION
;
6053 if (!nfsrv_is_initialized()) {
6054 stat_desc
.rec_count
= 0;
6055 if (oldp
&& (*oldlenp
>= sizeof(struct nfs_export_stat_desc
))) {
6056 error
= copyout(&stat_desc
, oldp
, sizeof(struct nfs_export_stat_desc
));
6058 *oldlenp
= sizeof(struct nfs_export_stat_desc
);
6062 /* Count the number of exported directories */
6063 lck_rw_lock_shared(&nfsrv_export_rwlock
);
6065 LIST_FOREACH(nxfs
, &nfsrv_exports
, nxfs_next
)
6066 LIST_FOREACH(nx
, &nxfs
->nxfs_exports
, nx_next
)
6069 /* update stat descriptor's export record count */
6070 stat_desc
.rec_count
= numExports
;
6072 /* calculate total size of required buffer */
6073 totlen
= sizeof(struct nfs_export_stat_desc
) + (numExports
* sizeof(struct nfs_export_stat_rec
));
6075 /* Check caller's buffer */
6077 lck_rw_done(&nfsrv_export_rwlock
);
6078 /* indicate required buffer len */
6083 /* We require the caller's buffer to be at least large enough to hold the descriptor */
6084 if (*oldlenp
< sizeof(struct nfs_export_stat_desc
)) {
6085 lck_rw_done(&nfsrv_export_rwlock
);
6086 /* indicate required buffer len */
6091 /* indicate required buffer len */
6094 /* check if export table is empty */
6096 lck_rw_done(&nfsrv_export_rwlock
);
6097 error
= copyout(&stat_desc
, oldp
, sizeof(struct nfs_export_stat_desc
));
6101 /* calculate how many actual export stat records fit into caller's buffer */
6102 numRecs
= (*oldlenp
- sizeof(struct nfs_export_stat_desc
)) / sizeof(struct nfs_export_stat_rec
);
6105 /* caller's buffer can only accomodate descriptor */
6106 lck_rw_done(&nfsrv_export_rwlock
);
6107 stat_desc
.rec_count
= 0;
6108 error
= copyout(&stat_desc
, oldp
, sizeof(struct nfs_export_stat_desc
));
6112 /* adjust to actual number of records to copyout to caller's buffer */
6113 if (numRecs
> numExports
) {
6114 numRecs
= numExports
;
6117 /* set actual number of records we are returning */
6118 stat_desc
.rec_count
= numRecs
;
6120 /* first copy out the stat descriptor */
6122 error
= copyout(&stat_desc
, oldp
+ pos
, sizeof(struct nfs_export_stat_desc
));
6124 lck_rw_done(&nfsrv_export_rwlock
);
6127 pos
+= sizeof(struct nfs_export_stat_desc
);
6129 /* Loop through exported directories */
6131 LIST_FOREACH(nxfs
, &nfsrv_exports
, nxfs_next
) {
6132 LIST_FOREACH(nx
, &nxfs
->nxfs_exports
, nx_next
) {
6133 if (count
>= numRecs
) {
6137 /* build exported filesystem path */
6138 memset(statrec
.path
, 0, sizeof(statrec
.path
));
6139 snprintf(statrec
.path
, sizeof(statrec
.path
), "%s%s%s",
6140 nxfs
->nxfs_path
, ((nxfs
->nxfs_path
[1] && nx
->nx_path
[0]) ? "/" : ""),
6143 /* build the 64-bit export stat counters */
6144 statrec
.ops
= ((uint64_t)nx
->nx_stats
.ops
.hi
<< 32) |
6145 nx
->nx_stats
.ops
.lo
;
6146 statrec
.bytes_read
= ((uint64_t)nx
->nx_stats
.bytes_read
.hi
<< 32) |
6147 nx
->nx_stats
.bytes_read
.lo
;
6148 statrec
.bytes_written
= ((uint64_t)nx
->nx_stats
.bytes_written
.hi
<< 32) |
6149 nx
->nx_stats
.bytes_written
.lo
;
6150 error
= copyout(&statrec
, oldp
+ pos
, sizeof(statrec
));
6152 lck_rw_done(&nfsrv_export_rwlock
);
6155 /* advance buffer position */
6156 pos
+= sizeof(statrec
);
6159 lck_rw_done(&nfsrv_export_rwlock
);
6162 /* init structures used for copying out of kernel */
6163 ustat_desc
.rec_vers
= NFS_USER_STAT_REC_VERSION
;
6164 ustat_rec
.rec_type
= NFS_USER_STAT_USER_REC
;
6165 upath_rec
.rec_type
= NFS_USER_STAT_PATH_REC
;
6167 /* initialize counters */
6168 bytes_total
= sizeof(struct nfs_user_stat_desc
);
6169 bytes_avail
= *oldlenp
;
6172 if (!nfsrv_is_initialized()) { /* NFS server not initialized, so no stats */
6176 /* reclaim old expired user nodes */
6177 nfsrv_active_user_list_reclaim();
6179 /* reserve space for the buffer descriptor */
6180 if (bytes_avail
>= sizeof(struct nfs_user_stat_desc
)) {
6181 bytes_avail
-= sizeof(struct nfs_user_stat_desc
);
6186 /* put buffer position past the buffer descriptor */
6187 pos
= sizeof(struct nfs_user_stat_desc
);
6189 /* Loop through exported directories */
6190 lck_rw_lock_shared(&nfsrv_export_rwlock
);
6191 LIST_FOREACH(nxfs
, &nfsrv_exports
, nxfs_next
) {
6192 LIST_FOREACH(nx
, &nxfs
->nxfs_exports
, nx_next
) {
6194 if (bytes_avail
>= sizeof(struct nfs_user_stat_path_rec
)) {
6195 memset(upath_rec
.path
, 0, sizeof(upath_rec
.path
));
6196 snprintf(upath_rec
.path
, sizeof(upath_rec
.path
), "%s%s%s",
6197 nxfs
->nxfs_path
, ((nxfs
->nxfs_path
[1] && nx
->nx_path
[0]) ? "/" : ""),
6200 error
= copyout(&upath_rec
, oldp
+ pos
, sizeof(struct nfs_user_stat_path_rec
));
6206 pos
+= sizeof(struct nfs_user_stat_path_rec
);
6207 bytes_avail
-= sizeof(struct nfs_user_stat_path_rec
);
6210 /* Caller's buffer is exhausted */
6214 bytes_total
+= sizeof(struct nfs_user_stat_path_rec
);
6216 /* Scan through all user nodes of this export */
6217 ulist
= &nx
->nx_user_list
;
6218 lck_mtx_lock(&ulist
->user_mutex
);
6219 for (unode
= TAILQ_FIRST(&ulist
->user_lru
); unode
; unode
= unode_next
) {
6220 unode_next
= TAILQ_NEXT(unode
, lru_link
);
6222 /* copy out node if there is space */
6223 if (bytes_avail
>= sizeof(struct nfs_user_stat_user_rec
)) {
6224 /* prepare a user stat rec for copying out */
6225 ustat_rec
.uid
= unode
->uid
;
6226 memset(&ustat_rec
.sock
, 0, sizeof(ustat_rec
.sock
));
6227 bcopy(&unode
->sock
, &ustat_rec
.sock
, unode
->sock
.ss_len
);
6228 ustat_rec
.ops
= unode
->ops
;
6229 ustat_rec
.bytes_read
= unode
->bytes_read
;
6230 ustat_rec
.bytes_written
= unode
->bytes_written
;
6231 ustat_rec
.tm_start
= unode
->tm_start
;
6232 ustat_rec
.tm_last
= unode
->tm_last
;
6234 error
= copyout(&ustat_rec
, oldp
+ pos
, sizeof(struct nfs_user_stat_user_rec
));
6238 lck_mtx_unlock(&ulist
->user_mutex
);
6242 pos
+= sizeof(struct nfs_user_stat_user_rec
);
6243 bytes_avail
-= sizeof(struct nfs_user_stat_user_rec
);
6246 /* Caller's buffer is exhausted */
6249 bytes_total
+= sizeof(struct nfs_user_stat_user_rec
);
6251 /* can unlock this export's list now */
6252 lck_mtx_unlock(&ulist
->user_mutex
);
6257 /* unlock the export table */
6258 lck_rw_done(&nfsrv_export_rwlock
);
6261 /* indicate number of actual records copied */
6262 ustat_desc
.rec_count
= recs_copied
;
6265 /* check if there was enough room for the buffer descriptor */
6266 if (*oldlenp
>= sizeof(struct nfs_user_stat_desc
)) {
6267 error
= copyout(&ustat_desc
, oldp
, sizeof(struct nfs_user_stat_desc
));
6272 /* always indicate required buffer size */
6273 *oldlenp
= bytes_total
;
6278 *oldlenp
= sizeof(nfsrv_user_stat_node_count
);
6282 if (*oldlenp
< sizeof(nfsrv_user_stat_node_count
)) {
6283 *oldlenp
= sizeof(nfsrv_user_stat_node_count
);
6287 if (nfsrv_is_initialized()) {
6288 /* reclaim old expired user nodes */
6289 nfsrv_active_user_list_reclaim();
6292 error
= copyout(&nfsrv_user_stat_node_count
, oldp
, sizeof(nfsrv_user_stat_node_count
));
6294 #endif /* NFSSERVER */
6295 case VFS_CTL_NOLOCKS
:
6296 if (req
->oldptr
!= USER_ADDR_NULL
) {
6297 lck_mtx_lock(&nmp
->nm_lock
);
6298 val
= (nmp
->nm_lockmode
== NFS_LOCK_MODE_DISABLED
) ? 1 : 0;
6299 lck_mtx_unlock(&nmp
->nm_lock
);
6300 error
= SYSCTL_OUT(req
, &val
, sizeof(val
));
6305 if (req
->newptr
!= USER_ADDR_NULL
) {
6306 error
= SYSCTL_IN(req
, &val
, sizeof(val
));
6310 lck_mtx_lock(&nmp
->nm_lock
);
6311 if (nmp
->nm_lockmode
== NFS_LOCK_MODE_LOCAL
) {
6312 /* can't toggle locks when using local locks */
6314 } else if ((nmp
->nm_vers
>= NFS_VER4
) && val
) {
6315 /* can't disable locks for NFSv4 */
6318 if ((nmp
->nm_vers
<= NFS_VER3
) && (nmp
->nm_lockmode
== NFS_LOCK_MODE_ENABLED
)) {
6319 nfs_lockd_mount_unregister(nmp
);
6321 nmp
->nm_lockmode
= NFS_LOCK_MODE_DISABLED
;
6322 nmp
->nm_state
&= ~NFSSTA_LOCKTIMEO
;
6324 if ((nmp
->nm_vers
<= NFS_VER3
) && (nmp
->nm_lockmode
== NFS_LOCK_MODE_DISABLED
)) {
6325 nfs_lockd_mount_register(nmp
);
6327 nmp
->nm_lockmode
= NFS_LOCK_MODE_ENABLED
;
6329 lck_mtx_unlock(&nmp
->nm_lock
);
6332 #ifndef CONFIG_EMBEDDED
6334 lck_mtx_lock(&nmp
->nm_lock
);
6335 /* XXX don't allow users to know about/disconnect unresponsive, soft, nobrowse mounts */
6336 softnobrowse
= (NMFLAG(nmp
, SOFT
) && (vfs_flags(nmp
->nm_mountp
) & MNT_DONTBROWSE
));
6337 if (!softnobrowse
&& (nmp
->nm_state
& NFSSTA_TIMEO
)) {
6338 vq
.vq_flags
|= VQ_NOTRESP
;
6340 if (!softnobrowse
&& (nmp
->nm_state
& NFSSTA_JUKEBOXTIMEO
) && !NMFLAG(nmp
, MUTEJUKEBOX
)) {
6341 vq
.vq_flags
|= VQ_NOTRESP
;
6343 if (!softnobrowse
&& (nmp
->nm_state
& NFSSTA_LOCKTIMEO
) &&
6344 (nmp
->nm_lockmode
== NFS_LOCK_MODE_ENABLED
)) {
6345 vq
.vq_flags
|= VQ_NOTRESP
;
6347 if (nmp
->nm_state
& NFSSTA_DEAD
) {
6348 vq
.vq_flags
|= VQ_DEAD
;
6350 lck_mtx_unlock(&nmp
->nm_lock
);
6351 error
= SYSCTL_OUT(req
, &vq
, sizeof(vq
));
6355 if (req
->oldptr
!= USER_ADDR_NULL
) {
6356 lck_mtx_lock(&nmp
->nm_lock
);
6357 val
= nmp
->nm_tprintf_initial_delay
;
6358 lck_mtx_unlock(&nmp
->nm_lock
);
6359 error
= SYSCTL_OUT(req
, &val
, sizeof(val
));
6364 if (req
->newptr
!= USER_ADDR_NULL
) {
6365 error
= SYSCTL_IN(req
, &val
, sizeof(val
));
6369 lck_mtx_lock(&nmp
->nm_lock
);
6371 nmp
->nm_tprintf_initial_delay
= 0;
6373 nmp
->nm_tprintf_initial_delay
= val
;
6375 lck_mtx_unlock(&nmp
->nm_lock
);
6378 case VFS_CTL_NSTATUS
:
6380 * Return the status of this mount. This is much more
6381 * information than VFS_CTL_QUERY. In addition to the
6382 * vq_flags return the significant mount options along
6383 * with the list of threads blocked on the mount and
6384 * how long the threads have been waiting.
6387 lck_mtx_lock(nfs_request_mutex
);
6388 lck_mtx_lock(&nmp
->nm_lock
);
6391 * Count the number of requests waiting for a reply.
6392 * Note: there could be multiple requests from the same thread.
6395 TAILQ_FOREACH(rq
, &nfs_reqq
, r_chain
) {
6396 if (rq
->r_nmp
== nmp
) {
6401 /* Calculate total size of result buffer */
6402 totlen
= sizeof(struct netfs_status
) + (numThreads
* sizeof(uint64_t));
6404 if (req
->oldptr
== USER_ADDR_NULL
) { // Caller is querying buffer size
6405 lck_mtx_unlock(&nmp
->nm_lock
);
6406 lck_mtx_unlock(nfs_request_mutex
);
6407 return SYSCTL_OUT(req
, NULL
, totlen
);
6409 if (req
->oldlen
< totlen
) { // Check if caller's buffer is big enough
6410 lck_mtx_unlock(&nmp
->nm_lock
);
6411 lck_mtx_unlock(nfs_request_mutex
);
6415 MALLOC(nsp
, struct netfs_status
*, totlen
, M_TEMP
, M_WAITOK
| M_ZERO
);
6417 lck_mtx_unlock(&nmp
->nm_lock
);
6418 lck_mtx_unlock(nfs_request_mutex
);
6421 timeoutmask
= NFSSTA_TIMEO
| NFSSTA_LOCKTIMEO
| NFSSTA_JUKEBOXTIMEO
;
6422 if (nmp
->nm_state
& timeoutmask
) {
6423 nsp
->ns_status
|= VQ_NOTRESP
;
6425 if (nmp
->nm_state
& NFSSTA_DEAD
) {
6426 nsp
->ns_status
|= VQ_DEAD
;
6429 (void) nfs_mountopts(nmp
, nsp
->ns_mountopts
, sizeof(nsp
->ns_mountopts
));
6430 nsp
->ns_threadcount
= numThreads
;
6433 * Get the thread ids of threads waiting for a reply
6434 * and find the longest wait time.
6436 if (numThreads
> 0) {
6442 sendtime
= now
.tv_sec
;
6443 TAILQ_FOREACH(rq
, &nfs_reqq
, r_chain
) {
6444 if (rq
->r_nmp
== nmp
) {
6445 if (rq
->r_start
< sendtime
) {
6446 sendtime
= rq
->r_start
;
6448 // A thread_id of zero is used to represent an async I/O request.
6449 nsp
->ns_threadids
[count
] =
6450 rq
->r_thread
? thread_tid(rq
->r_thread
) : 0;
6451 if (++count
>= numThreads
) {
6456 nsp
->ns_waittime
= now
.tv_sec
- sendtime
;
6459 lck_mtx_unlock(&nmp
->nm_lock
);
6460 lck_mtx_unlock(nfs_request_mutex
);
6462 error
= SYSCTL_OUT(req
, nsp
, totlen
);