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
);
301 nfs_ticks
= (hz
* NFS_TICKINTVL
+ 500) / 1000;
305 /* init async I/O thread pool state */
306 TAILQ_INIT(&nfsiodfree
);
307 TAILQ_INIT(&nfsiodwork
);
308 TAILQ_INIT(&nfsiodmounts
);
309 nfsiod_lck_grp
= lck_grp_alloc_init("nfsiod", LCK_GRP_ATTR_NULL
);
310 nfsiod_mutex
= lck_mtx_alloc_init(nfsiod_lck_grp
, LCK_ATTR_NULL
);
312 /* init lock groups, etc. */
313 nfs_mount_grp
= lck_grp_alloc_init("nfs_mount", LCK_GRP_ATTR_NULL
);
314 nfs_open_grp
= lck_grp_alloc_init("nfs_open", LCK_GRP_ATTR_NULL
);
315 nfs_global_grp
= lck_grp_alloc_init("nfs_global", LCK_GRP_ATTR_NULL
);
317 nfs_global_mutex
= lck_mtx_alloc_init(nfs_global_grp
, LCK_ATTR_NULL
);
319 /* init request list mutex */
320 nfs_request_grp
= lck_grp_alloc_init("nfs_request", LCK_GRP_ATTR_NULL
);
321 nfs_request_mutex
= lck_mtx_alloc_init(nfs_request_grp
, LCK_ATTR_NULL
);
323 /* initialize NFS request list */
324 TAILQ_INIT(&nfs_reqq
);
326 nfs_nbinit(); /* Init the nfsbuf table */
327 nfs_nhinit(); /* Init the nfsnode table */
328 nfs_lockinit(); /* Init the nfs lock state */
329 nfs_gss_init(); /* Init RPCSEC_GSS security */
332 NFS4_PER_FS_ATTRIBUTES(nfs_fs_attr_bitmap
);
333 NFS4_PER_OBJECT_ATTRIBUTES(nfs_object_attr_bitmap
);
334 NFS4_DEFAULT_ATTRIBUTES(nfs_getattr_bitmap
);
335 for (i
=0; i
< NFS_ATTR_BITMAP_LEN
; i
++)
336 nfs_getattr_bitmap
[i
] &= nfs_object_attr_bitmap
[i
];
337 TAILQ_INIT(&nfsclientids
);
339 /* initialize NFS timer callouts */
340 nfs_request_timer_call
= thread_call_allocate(nfs_request_timer
, NULL
);
341 nfs_buf_timer_call
= thread_call_allocate(nfs_buf_timer
, NULL
);
342 nfs4_callback_timer_call
= thread_call_allocate(nfs4_callback_timer
, NULL
);
351 nfs3_update_statfs(struct nfsmount
*nmp
, vfs_context_t ctx
)
354 int error
= 0, lockerror
, status
, nfsvers
;
356 struct nfsm_chain nmreq
, nmrep
;
359 nfsvers
= nmp
->nm_vers
;
363 if ((error
= vnode_get(NFSTOV(np
))))
366 nfsm_chain_null(&nmreq
);
367 nfsm_chain_null(&nmrep
);
369 nfsm_chain_build_alloc_init(error
, &nmreq
, NFSX_FH(nfsvers
));
370 nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, np
->n_fhp
, np
->n_fhsize
);
371 nfsm_chain_build_done(error
, &nmreq
);
373 error
= nfs_request2(np
, NULL
, &nmreq
, NFSPROC_FSSTAT
, vfs_context_thread(ctx
),
374 vfs_context_ucred(ctx
), NULL
, R_SOFT
, &nmrep
, &xid
, &status
);
375 if (error
== ETIMEDOUT
)
377 if ((lockerror
= nfs_node_lock(np
)))
379 if (nfsvers
== NFS_VER3
)
380 nfsm_chain_postop_attr_update(error
, &nmrep
, np
, &xid
);
385 nfsm_assert(error
, NFSTONMP(np
), ENXIO
);
387 lck_mtx_lock(&nmp
->nm_lock
);
388 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_TOTAL
);
389 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_FREE
);
390 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_AVAIL
);
391 if (nfsvers
== NFS_VER3
) {
392 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_FILES_AVAIL
);
393 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_FILES_TOTAL
);
394 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_FILES_FREE
);
395 nmp
->nm_fsattr
.nfsa_bsize
= NFS_FABLKSIZE
;
396 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_space_total
);
397 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_space_free
);
398 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_space_avail
);
399 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_files_total
);
400 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_files_free
);
401 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_files_avail
);
404 nfsm_chain_adv(error
, &nmrep
, NFSX_UNSIGNED
); // skip tsize?
405 nfsm_chain_get_32(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_bsize
);
406 nfsm_chain_get_32(error
, &nmrep
, val
);
408 if (nmp
->nm_fsattr
.nfsa_bsize
<= 0)
409 nmp
->nm_fsattr
.nfsa_bsize
= NFS_FABLKSIZE
;
410 nmp
->nm_fsattr
.nfsa_space_total
= (uint64_t)val
* nmp
->nm_fsattr
.nfsa_bsize
;
411 nfsm_chain_get_32(error
, &nmrep
, val
);
413 nmp
->nm_fsattr
.nfsa_space_free
= (uint64_t)val
* nmp
->nm_fsattr
.nfsa_bsize
;
414 nfsm_chain_get_32(error
, &nmrep
, val
);
416 nmp
->nm_fsattr
.nfsa_space_avail
= (uint64_t)val
* nmp
->nm_fsattr
.nfsa_bsize
;
418 lck_mtx_unlock(&nmp
->nm_lock
);
420 nfsm_chain_cleanup(&nmreq
);
421 nfsm_chain_cleanup(&nmrep
);
422 vnode_put(NFSTOV(np
));
427 nfs4_update_statfs(struct nfsmount
*nmp
, vfs_context_t ctx
)
430 int error
= 0, lockerror
, status
, nfsvers
, numops
;
432 struct nfsm_chain nmreq
, nmrep
;
433 uint32_t bitmap
[NFS_ATTR_BITMAP_LEN
];
434 struct nfs_vattr nvattr
;
435 struct nfsreq_secinfo_args si
;
437 nfsvers
= nmp
->nm_vers
;
441 if ((error
= vnode_get(NFSTOV(np
))))
444 NFSREQ_SECINFO_SET(&si
, np
, NULL
, 0, NULL
, 0);
445 NVATTR_INIT(&nvattr
);
446 nfsm_chain_null(&nmreq
);
447 nfsm_chain_null(&nmrep
);
451 nfsm_chain_build_alloc_init(error
, &nmreq
, 15 * NFSX_UNSIGNED
);
452 nfsm_chain_add_compound_header(error
, &nmreq
, "statfs", nmp
->nm_minor_vers
, numops
);
454 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
455 nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, np
->n_fhp
, np
->n_fhsize
);
457 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
458 NFS_COPY_ATTRIBUTES(nfs_getattr_bitmap
, bitmap
);
459 NFS4_STATFS_ATTRIBUTES(bitmap
);
460 nfsm_chain_add_bitmap_supported(error
, &nmreq
, bitmap
, nmp
, np
);
461 nfsm_chain_build_done(error
, &nmreq
);
462 nfsm_assert(error
, (numops
== 0), EPROTO
);
464 error
= nfs_request2(np
, NULL
, &nmreq
, NFSPROC4_COMPOUND
,
465 vfs_context_thread(ctx
), vfs_context_ucred(ctx
),
466 NULL
, R_SOFT
, &nmrep
, &xid
, &status
);
467 nfsm_chain_skip_tag(error
, &nmrep
);
468 nfsm_chain_get_32(error
, &nmrep
, numops
);
469 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
470 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
471 nfsm_assert(error
, NFSTONMP(np
), ENXIO
);
473 lck_mtx_lock(&nmp
->nm_lock
);
474 error
= nfs4_parsefattr(&nmrep
, &nmp
->nm_fsattr
, &nvattr
, NULL
, NULL
, NULL
);
475 lck_mtx_unlock(&nmp
->nm_lock
);
477 if ((lockerror
= nfs_node_lock(np
)))
480 nfs_loadattrcache(np
, &nvattr
, &xid
, 0);
483 nfsm_assert(error
, NFSTONMP(np
), ENXIO
);
485 nmp
->nm_fsattr
.nfsa_bsize
= NFS_FABLKSIZE
;
487 NVATTR_CLEANUP(&nvattr
);
488 nfsm_chain_cleanup(&nmreq
);
489 nfsm_chain_cleanup(&nmrep
);
490 vnode_put(NFSTOV(np
));
495 * Return an NFS volume name from the mntfrom name.
498 nfs_get_volname(struct mount
*mp
, char *volname
, size_t len
)
500 const char *ptr
, *cptr
;
501 const char *mntfrom
= mp
->mnt_vfsstat
.f_mntfromname
;
502 size_t mflen
= strnlen(mntfrom
, MAXPATHLEN
+1);
504 if (mflen
> MAXPATHLEN
|| mflen
== 0) {
505 strlcpy(volname
, "Bad volname", len
);
509 /* Move back over trailing slashes */
510 for (ptr
= &mntfrom
[mflen
-1]; ptr
!= mntfrom
&& *ptr
== '/'; ptr
--) {
514 /* Find first character after the last slash */
516 for(size_t i
= 0; i
< mflen
; i
++) {
517 if (mntfrom
[i
] == '/')
519 /* And the first character after the first colon */
520 else if (cptr
== NULL
&& mntfrom
[i
] == ':')
521 cptr
= &mntfrom
[i
+1];
525 * No slash or nothing after the last slash
526 * use everything past the first colon
528 if (ptr
== NULL
|| *ptr
== '\0')
530 /* Otherwise use the mntfrom name */
534 mflen
= &mntfrom
[mflen
] - ptr
;
535 len
= mflen
+1 < len
? mflen
+1 : len
;
537 strlcpy(volname
, ptr
, len
);
541 * The NFS VFS_GETATTR function: "statfs"-type information is retrieved
542 * using the nf_update_statfs() function, and other attributes are cobbled
543 * together from whatever sources we can (getattr, fsinfo, pathconf).
546 nfs_vfs_getattr(mount_t mp
, struct vfs_attr
*fsap
, vfs_context_t ctx
)
548 struct nfsmount
*nmp
;
550 int error
= 0, nfsvers
;
553 if (nfs_mount_gone(nmp
))
555 nfsvers
= nmp
->nm_vers
;
557 if (VFSATTR_IS_ACTIVE(fsap
, f_bsize
) ||
558 VFSATTR_IS_ACTIVE(fsap
, f_iosize
) ||
559 VFSATTR_IS_ACTIVE(fsap
, f_blocks
) ||
560 VFSATTR_IS_ACTIVE(fsap
, f_bfree
) ||
561 VFSATTR_IS_ACTIVE(fsap
, f_bavail
) ||
562 VFSATTR_IS_ACTIVE(fsap
, f_bused
) ||
563 VFSATTR_IS_ACTIVE(fsap
, f_files
) ||
564 VFSATTR_IS_ACTIVE(fsap
, f_ffree
)) {
565 int statfsrate
= nfs_statfs_rate_limit
;
569 * Are we rate-limiting statfs RPCs?
570 * (Treat values less than 1 or greater than 1,000,000 as no limit.)
572 if ((statfsrate
> 0) && (statfsrate
< 1000000)) {
577 lck_mtx_lock(&nmp
->nm_lock
);
578 stamp
= (now
.tv_sec
* statfsrate
) + (now
.tv_usec
/ (1000000/statfsrate
));
579 if (stamp
!= nmp
->nm_fsattrstamp
) {
581 nmp
->nm_fsattrstamp
= stamp
;
585 lck_mtx_unlock(&nmp
->nm_lock
);
588 if (refresh
&& !nfs_use_cache(nmp
))
589 error
= nmp
->nm_funcs
->nf_update_statfs(nmp
, ctx
);
590 if ((error
== ESTALE
) || (error
== ETIMEDOUT
))
595 lck_mtx_lock(&nmp
->nm_lock
);
596 VFSATTR_RETURN(fsap
, f_iosize
, nfs_iosize
);
597 VFSATTR_RETURN(fsap
, f_bsize
, nmp
->nm_fsattr
.nfsa_bsize
);
598 bsize
= nmp
->nm_fsattr
.nfsa_bsize
;
599 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_TOTAL
))
600 VFSATTR_RETURN(fsap
, f_blocks
, nmp
->nm_fsattr
.nfsa_space_total
/ bsize
);
601 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_FREE
))
602 VFSATTR_RETURN(fsap
, f_bfree
, nmp
->nm_fsattr
.nfsa_space_free
/ bsize
);
603 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_AVAIL
))
604 VFSATTR_RETURN(fsap
, f_bavail
, nmp
->nm_fsattr
.nfsa_space_avail
/ bsize
);
605 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_TOTAL
) &&
606 NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_FREE
))
607 VFSATTR_RETURN(fsap
, f_bused
,
608 (nmp
->nm_fsattr
.nfsa_space_total
/ bsize
) -
609 (nmp
->nm_fsattr
.nfsa_space_free
/ bsize
));
610 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_FILES_TOTAL
))
611 VFSATTR_RETURN(fsap
, f_files
, nmp
->nm_fsattr
.nfsa_files_total
);
612 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_FILES_FREE
))
613 VFSATTR_RETURN(fsap
, f_ffree
, nmp
->nm_fsattr
.nfsa_files_free
);
614 lck_mtx_unlock(&nmp
->nm_lock
);
617 if (VFSATTR_IS_ACTIVE(fsap
, f_vol_name
)) {
618 /*%%% IF fail over support is implemented we may need to take nm_lock */
619 nfs_get_volname(mp
, fsap
->f_vol_name
, MAXPATHLEN
);
620 VFSATTR_SET_SUPPORTED(fsap
, f_vol_name
);
622 if (VFSATTR_IS_ACTIVE(fsap
, f_capabilities
)) {
623 u_int32_t caps
, valid
;
624 nfsnode_t np
= nmp
->nm_dnp
;
626 nfsm_assert(error
, VFSTONFS(mp
) && np
, ENXIO
);
629 lck_mtx_lock(&nmp
->nm_lock
);
632 * The capabilities[] array defines what this volume supports.
634 * The valid[] array defines which bits this code understands
635 * the meaning of (whether the volume has that capability or not).
636 * Any zero bits here means "I don't know what you're asking about"
637 * and the caller cannot tell whether that capability is
641 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SYMLINK_SUPPORT
)) {
642 valid
|= VOL_CAP_FMT_SYMBOLICLINKS
;
643 if (nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_SYMLINK
)
644 caps
|= VOL_CAP_FMT_SYMBOLICLINKS
;
646 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_LINK_SUPPORT
)) {
647 valid
|= VOL_CAP_FMT_HARDLINKS
;
648 if (nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_LINK
)
649 caps
|= VOL_CAP_FMT_HARDLINKS
;
651 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_CASE_INSENSITIVE
)) {
652 valid
|= VOL_CAP_FMT_CASE_SENSITIVE
;
653 if (!(nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_CASE_INSENSITIVE
))
654 caps
|= VOL_CAP_FMT_CASE_SENSITIVE
;
656 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_CASE_PRESERVING
)) {
657 valid
|= VOL_CAP_FMT_CASE_PRESERVING
;
658 if (nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_CASE_PRESERVING
)
659 caps
|= VOL_CAP_FMT_CASE_PRESERVING
;
661 /* Note: VOL_CAP_FMT_2TB_FILESIZE is actually used to test for "large file support" */
662 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXFILESIZE
)) {
663 /* Is server's max file size at least 4GB? */
664 if (nmp
->nm_fsattr
.nfsa_maxfilesize
>= 0x100000000ULL
)
665 caps
|= VOL_CAP_FMT_2TB_FILESIZE
;
666 } else if (nfsvers
>= NFS_VER3
) {
668 * NFSv3 and up supports 64 bits of file size.
669 * So, we'll just assume maxfilesize >= 4GB
671 caps
|= VOL_CAP_FMT_2TB_FILESIZE
;
673 if (nfsvers
>= NFS_VER4
) {
674 caps
|= VOL_CAP_FMT_HIDDEN_FILES
;
675 valid
|= VOL_CAP_FMT_HIDDEN_FILES
;
676 // VOL_CAP_FMT_OPENDENYMODES
677 // caps |= VOL_CAP_FMT_OPENDENYMODES;
678 // valid |= VOL_CAP_FMT_OPENDENYMODES;
680 // no version of nfs supports immutable files
681 caps
|= VOL_CAP_FMT_NO_IMMUTABLE_FILES
;
682 valid
|= VOL_CAP_FMT_NO_IMMUTABLE_FILES
;
684 fsap
->f_capabilities
.capabilities
[VOL_CAPABILITIES_FORMAT
] =
685 // VOL_CAP_FMT_PERSISTENTOBJECTIDS |
686 // VOL_CAP_FMT_SYMBOLICLINKS |
687 // VOL_CAP_FMT_HARDLINKS |
688 // VOL_CAP_FMT_JOURNAL |
689 // VOL_CAP_FMT_JOURNAL_ACTIVE |
690 // VOL_CAP_FMT_NO_ROOT_TIMES |
691 // VOL_CAP_FMT_SPARSE_FILES |
692 // VOL_CAP_FMT_ZERO_RUNS |
693 // VOL_CAP_FMT_CASE_SENSITIVE |
694 // VOL_CAP_FMT_CASE_PRESERVING |
695 // VOL_CAP_FMT_FAST_STATFS |
696 // VOL_CAP_FMT_2TB_FILESIZE |
697 // VOL_CAP_FMT_OPENDENYMODES |
698 // VOL_CAP_FMT_HIDDEN_FILES |
700 fsap
->f_capabilities
.valid
[VOL_CAPABILITIES_FORMAT
] =
701 VOL_CAP_FMT_PERSISTENTOBJECTIDS
|
702 // VOL_CAP_FMT_SYMBOLICLINKS |
703 // VOL_CAP_FMT_HARDLINKS |
704 // VOL_CAP_FMT_JOURNAL |
705 // VOL_CAP_FMT_JOURNAL_ACTIVE |
706 // VOL_CAP_FMT_NO_ROOT_TIMES |
707 // VOL_CAP_FMT_SPARSE_FILES |
708 // VOL_CAP_FMT_ZERO_RUNS |
709 // VOL_CAP_FMT_CASE_SENSITIVE |
710 // VOL_CAP_FMT_CASE_PRESERVING |
711 VOL_CAP_FMT_FAST_STATFS
|
712 VOL_CAP_FMT_2TB_FILESIZE
|
713 // VOL_CAP_FMT_OPENDENYMODES |
714 // VOL_CAP_FMT_HIDDEN_FILES |
718 * We don't support most of the interfaces.
720 * We MAY support locking, but we don't have any easy way of probing.
721 * We can tell if there's no lockd running or if locks have been
722 * disabled for a mount, so we can definitely answer NO in that case.
723 * Any attempt to send a request to lockd to test for locking support
724 * may cause the lazily-launched locking daemons to be started
725 * unnecessarily. So we avoid that. However, we do record if we ever
726 * successfully perform a lock operation on a mount point, so if it
727 * looks like lock ops have worked, we do report that we support them.
730 if (nfsvers
>= NFS_VER4
) {
731 caps
= VOL_CAP_INT_ADVLOCK
| VOL_CAP_INT_FLOCK
;
732 valid
= VOL_CAP_INT_ADVLOCK
| VOL_CAP_INT_FLOCK
;
733 if (nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_ACL
)
734 caps
|= VOL_CAP_INT_EXTENDED_SECURITY
;
735 valid
|= VOL_CAP_INT_EXTENDED_SECURITY
;
736 if (nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_NAMED_ATTR
)
737 caps
|= VOL_CAP_INT_EXTENDED_ATTR
;
738 valid
|= VOL_CAP_INT_EXTENDED_ATTR
;
740 if (nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_NAMED_ATTR
)
741 caps
|= VOL_CAP_INT_NAMEDSTREAMS
;
742 valid
|= VOL_CAP_INT_NAMEDSTREAMS
;
744 } else if (nmp
->nm_lockmode
== NFS_LOCK_MODE_DISABLED
) {
745 /* locks disabled on this mount, so they definitely won't work */
746 valid
= VOL_CAP_INT_ADVLOCK
| VOL_CAP_INT_FLOCK
;
747 } else if (nmp
->nm_state
& NFSSTA_LOCKSWORK
) {
748 caps
= VOL_CAP_INT_ADVLOCK
| VOL_CAP_INT_FLOCK
;
749 valid
= VOL_CAP_INT_ADVLOCK
| VOL_CAP_INT_FLOCK
;
751 fsap
->f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] =
752 // VOL_CAP_INT_SEARCHFS |
753 // VOL_CAP_INT_ATTRLIST |
754 // VOL_CAP_INT_NFSEXPORT |
755 // VOL_CAP_INT_READDIRATTR |
756 // VOL_CAP_INT_EXCHANGEDATA |
757 // VOL_CAP_INT_COPYFILE |
758 // VOL_CAP_INT_ALLOCATE |
759 // VOL_CAP_INT_VOL_RENAME |
760 // VOL_CAP_INT_ADVLOCK |
761 // VOL_CAP_INT_FLOCK |
762 // VOL_CAP_INT_EXTENDED_SECURITY |
763 // VOL_CAP_INT_USERACCESS |
764 // VOL_CAP_INT_MANLOCK |
765 // VOL_CAP_INT_NAMEDSTREAMS |
766 // VOL_CAP_INT_EXTENDED_ATTR |
767 VOL_CAP_INT_REMOTE_EVENT
|
769 fsap
->f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] =
770 VOL_CAP_INT_SEARCHFS
|
771 VOL_CAP_INT_ATTRLIST
|
772 VOL_CAP_INT_NFSEXPORT
|
773 VOL_CAP_INT_READDIRATTR
|
774 VOL_CAP_INT_EXCHANGEDATA
|
775 VOL_CAP_INT_COPYFILE
|
776 VOL_CAP_INT_ALLOCATE
|
777 VOL_CAP_INT_VOL_RENAME
|
778 // VOL_CAP_INT_ADVLOCK |
779 // VOL_CAP_INT_FLOCK |
780 // VOL_CAP_INT_EXTENDED_SECURITY |
781 // VOL_CAP_INT_USERACCESS |
782 // VOL_CAP_INT_MANLOCK |
783 // VOL_CAP_INT_NAMEDSTREAMS |
784 // VOL_CAP_INT_EXTENDED_ATTR |
785 VOL_CAP_INT_REMOTE_EVENT
|
788 fsap
->f_capabilities
.capabilities
[VOL_CAPABILITIES_RESERVED1
] = 0;
789 fsap
->f_capabilities
.valid
[VOL_CAPABILITIES_RESERVED1
] = 0;
791 fsap
->f_capabilities
.capabilities
[VOL_CAPABILITIES_RESERVED2
] = 0;
792 fsap
->f_capabilities
.valid
[VOL_CAPABILITIES_RESERVED2
] = 0;
794 VFSATTR_SET_SUPPORTED(fsap
, f_capabilities
);
795 lck_mtx_unlock(&nmp
->nm_lock
);
798 if (VFSATTR_IS_ACTIVE(fsap
, f_attributes
)) {
799 fsap
->f_attributes
.validattr
.commonattr
= 0;
800 fsap
->f_attributes
.validattr
.volattr
=
801 ATTR_VOL_NAME
| ATTR_VOL_CAPABILITIES
| ATTR_VOL_ATTRIBUTES
;
802 fsap
->f_attributes
.validattr
.dirattr
= 0;
803 fsap
->f_attributes
.validattr
.fileattr
= 0;
804 fsap
->f_attributes
.validattr
.forkattr
= 0;
806 fsap
->f_attributes
.nativeattr
.commonattr
= 0;
807 fsap
->f_attributes
.nativeattr
.volattr
=
808 ATTR_VOL_NAME
| ATTR_VOL_CAPABILITIES
| ATTR_VOL_ATTRIBUTES
;
809 fsap
->f_attributes
.nativeattr
.dirattr
= 0;
810 fsap
->f_attributes
.nativeattr
.fileattr
= 0;
811 fsap
->f_attributes
.nativeattr
.forkattr
= 0;
813 VFSATTR_SET_SUPPORTED(fsap
, f_attributes
);
820 * nfs version 3 fsinfo rpc call
823 nfs3_fsinfo(struct nfsmount
*nmp
, nfsnode_t np
, vfs_context_t ctx
)
825 int error
= 0, lockerror
, status
, nmlocked
= 0;
827 uint32_t val
, prefsize
, maxsize
;
828 struct nfsm_chain nmreq
, nmrep
;
830 nfsm_chain_null(&nmreq
);
831 nfsm_chain_null(&nmrep
);
833 nfsm_chain_build_alloc_init(error
, &nmreq
, NFSX_FH(nmp
->nm_vers
));
834 nfsm_chain_add_fh(error
, &nmreq
, nmp
->nm_vers
, np
->n_fhp
, np
->n_fhsize
);
835 nfsm_chain_build_done(error
, &nmreq
);
837 error
= nfs_request(np
, NULL
, &nmreq
, NFSPROC_FSINFO
, ctx
, NULL
, &nmrep
, &xid
, &status
);
838 if ((lockerror
= nfs_node_lock(np
)))
840 nfsm_chain_postop_attr_update(error
, &nmrep
, np
, &xid
);
847 lck_mtx_lock(&nmp
->nm_lock
);
850 nfsm_chain_get_32(error
, &nmrep
, maxsize
);
851 nfsm_chain_get_32(error
, &nmrep
, prefsize
);
853 nmp
->nm_fsattr
.nfsa_maxread
= maxsize
;
854 if (prefsize
< nmp
->nm_rsize
)
855 nmp
->nm_rsize
= (prefsize
+ NFS_FABLKSIZE
- 1) &
856 ~(NFS_FABLKSIZE
- 1);
857 if ((maxsize
> 0) && (maxsize
< nmp
->nm_rsize
)) {
858 nmp
->nm_rsize
= maxsize
& ~(NFS_FABLKSIZE
- 1);
859 if (nmp
->nm_rsize
== 0)
860 nmp
->nm_rsize
= maxsize
;
862 nfsm_chain_adv(error
, &nmrep
, NFSX_UNSIGNED
); // skip rtmult
864 nfsm_chain_get_32(error
, &nmrep
, maxsize
);
865 nfsm_chain_get_32(error
, &nmrep
, prefsize
);
867 nmp
->nm_fsattr
.nfsa_maxwrite
= maxsize
;
868 if (prefsize
< nmp
->nm_wsize
)
869 nmp
->nm_wsize
= (prefsize
+ NFS_FABLKSIZE
- 1) &
870 ~(NFS_FABLKSIZE
- 1);
871 if ((maxsize
> 0) && (maxsize
< nmp
->nm_wsize
)) {
872 nmp
->nm_wsize
= maxsize
& ~(NFS_FABLKSIZE
- 1);
873 if (nmp
->nm_wsize
== 0)
874 nmp
->nm_wsize
= maxsize
;
876 nfsm_chain_adv(error
, &nmrep
, NFSX_UNSIGNED
); // skip wtmult
878 nfsm_chain_get_32(error
, &nmrep
, prefsize
);
880 if ((prefsize
> 0) && (prefsize
< nmp
->nm_readdirsize
))
881 nmp
->nm_readdirsize
= prefsize
;
882 if ((nmp
->nm_fsattr
.nfsa_maxread
> 0) &&
883 (nmp
->nm_fsattr
.nfsa_maxread
< nmp
->nm_readdirsize
))
884 nmp
->nm_readdirsize
= nmp
->nm_fsattr
.nfsa_maxread
;
886 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_maxfilesize
);
888 nfsm_chain_adv(error
, &nmrep
, 2 * NFSX_UNSIGNED
); // skip time_delta
890 /* convert FS properties to our own flags */
891 nfsm_chain_get_32(error
, &nmrep
, val
);
893 if (val
& NFSV3FSINFO_LINK
)
894 nmp
->nm_fsattr
.nfsa_flags
|= NFS_FSFLAG_LINK
;
895 if (val
& NFSV3FSINFO_SYMLINK
)
896 nmp
->nm_fsattr
.nfsa_flags
|= NFS_FSFLAG_SYMLINK
;
897 if (val
& NFSV3FSINFO_HOMOGENEOUS
)
898 nmp
->nm_fsattr
.nfsa_flags
|= NFS_FSFLAG_HOMOGENEOUS
;
899 if (val
& NFSV3FSINFO_CANSETTIME
)
900 nmp
->nm_fsattr
.nfsa_flags
|= NFS_FSFLAG_SET_TIME
;
901 nmp
->nm_state
|= NFSSTA_GOTFSINFO
;
902 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXREAD
);
903 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXWRITE
);
904 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXFILESIZE
);
905 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_LINK_SUPPORT
);
906 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SYMLINK_SUPPORT
);
907 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_HOMOGENEOUS
);
908 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_CANSETTIME
);
911 lck_mtx_unlock(&nmp
->nm_lock
);
912 nfsm_chain_cleanup(&nmreq
);
913 nfsm_chain_cleanup(&nmrep
);
918 * Mount a remote root fs via. nfs. This depends on the info in the
919 * nfs_diskless structure that has been filled in properly by some primary
921 * It goes something like this:
922 * - do enough of "ifconfig" by calling ifioctl() so that the system
923 * can talk to the server
924 * - If nfs_diskless.mygateway is filled in, use that address as
926 * - hand craft the swap nfs vnode hanging off a fake mount point
927 * if swdevt[0].sw_dev == NODEV
928 * - build the rootfs mount point and call mountnfs() to do the rest.
933 struct nfs_diskless nd
;
938 #if !defined(NO_MOUNT_PRIVATE)
939 mount_t mppriv
= NULL
;
940 vnode_t vppriv
= NULL
;
941 #endif /* NO_MOUNT_PRIVATE */
945 * Call nfs_boot_init() to fill in the nfs_diskless struct.
946 * Note: networking must already have been configured before
949 bzero((caddr_t
) &nd
, sizeof(nd
));
950 error
= nfs_boot_init(&nd
);
952 panic("nfs_boot_init: unable to initialize NFS root system information, "
953 "error %d, check configuration: %s\n", error
, PE_boot_args());
956 * Try NFSv3 first, then fallback to NFSv2.
957 * Likewise, try TCP first, then fall back to UDP.
960 sotype
= SOCK_STREAM
;
963 error
= nfs_boot_getfh(&nd
, v3
, sotype
);
965 if (error
== EHOSTDOWN
|| error
== EHOSTUNREACH
) {
966 if (nd
.nd_root
.ndm_mntfrom
)
967 FREE_ZONE(nd
.nd_root
.ndm_mntfrom
,
968 MAXPATHLEN
, M_NAMEI
);
969 if (nd
.nd_root
.ndm_path
)
970 FREE_ZONE(nd
.nd_root
.ndm_path
,
971 MAXPATHLEN
, M_NAMEI
);
972 if (nd
.nd_private
.ndm_mntfrom
)
973 FREE_ZONE(nd
.nd_private
.ndm_mntfrom
,
974 MAXPATHLEN
, M_NAMEI
);
975 if (nd
.nd_private
.ndm_path
)
976 FREE_ZONE(nd
.nd_private
.ndm_path
,
977 MAXPATHLEN
, M_NAMEI
);
981 if (sotype
== SOCK_STREAM
) {
982 printf("NFS mount (v3,TCP) failed with error %d, trying UDP...\n", error
);
986 printf("NFS mount (v3,UDP) failed with error %d, trying v2...\n", error
);
988 sotype
= SOCK_STREAM
;
990 } else if (sotype
== SOCK_STREAM
) {
991 printf("NFS mount (v2,TCP) failed with error %d, trying UDP...\n", error
);
995 printf("NFS mount (v2,UDP) failed with error %d, giving up...\n", error
);
999 panic("NFS mount failed: NFS server mountd not responding, check server configuration: %s", PE_boot_args());
1002 panic("NFS mount failed: NFS server refused mount, check server configuration: %s", PE_boot_args());
1004 panic("NFS mount failed with error %d, check configuration: %s", error
, PE_boot_args());
1008 ctx
= vfs_context_kernel();
1011 * Create the root mount point.
1013 #if !defined(NO_MOUNT_PRIVATE)
1015 //PWC hack until we have a real "mount" tool to remount root rw
1017 int flags
= MNT_ROOTFS
|MNT_RDONLY
;
1018 PE_parse_boot_argn("-rwroot_hack", &rw_root
, sizeof (rw_root
));
1022 kprintf("-rwroot_hack in effect: mounting root fs read/write\n");
1025 if ((error
= nfs_mount_diskless(&nd
.nd_root
, "/", flags
, &vp
, &mp
, ctx
)))
1027 if ((error
= nfs_mount_diskless(&nd
.nd_root
, "/", MNT_ROOTFS
, &vp
, &mp
, ctx
)))
1028 #endif /* NO_MOUNT_PRIVATE */
1031 if (sotype
== SOCK_STREAM
) {
1032 printf("NFS root mount (v3,TCP) failed with %d, trying UDP...\n", error
);
1033 sotype
= SOCK_DGRAM
;
1036 printf("NFS root mount (v3,UDP) failed with %d, trying v2...\n", error
);
1038 sotype
= SOCK_STREAM
;
1040 } else if (sotype
== SOCK_STREAM
) {
1041 printf("NFS root mount (v2,TCP) failed with %d, trying UDP...\n", error
);
1042 sotype
= SOCK_DGRAM
;
1045 printf("NFS root mount (v2,UDP) failed with error %d, giving up...\n", error
);
1047 panic("NFS root mount failed with error %d, check configuration: %s\n", error
, PE_boot_args());
1050 printf("root on %s\n", nd
.nd_root
.ndm_mntfrom
);
1056 #if !defined(NO_MOUNT_PRIVATE)
1057 if (nd
.nd_private
.ndm_saddr
.sin_addr
.s_addr
) {
1058 error
= nfs_mount_diskless_private(&nd
.nd_private
, "/private",
1059 0, &vppriv
, &mppriv
, ctx
);
1061 panic("NFS /private mount failed with error %d, check configuration: %s\n", error
, PE_boot_args());
1062 printf("private on %s\n", nd
.nd_private
.ndm_mntfrom
);
1065 mount_list_add(mppriv
);
1068 #endif /* NO_MOUNT_PRIVATE */
1070 if (nd
.nd_root
.ndm_mntfrom
)
1071 FREE_ZONE(nd
.nd_root
.ndm_mntfrom
, MAXPATHLEN
, M_NAMEI
);
1072 if (nd
.nd_root
.ndm_path
)
1073 FREE_ZONE(nd
.nd_root
.ndm_path
, MAXPATHLEN
, M_NAMEI
);
1074 if (nd
.nd_private
.ndm_mntfrom
)
1075 FREE_ZONE(nd
.nd_private
.ndm_mntfrom
, MAXPATHLEN
, M_NAMEI
);
1076 if (nd
.nd_private
.ndm_path
)
1077 FREE_ZONE(nd
.nd_private
.ndm_path
, MAXPATHLEN
, M_NAMEI
);
1079 /* Get root attributes (for the time). */
1080 error
= nfs_getattr(VTONFS(vp
), NULL
, ctx
, NGA_UNCACHED
);
1082 panic("NFS mount: failed to get attributes for root directory, error %d, check server", error
);
1087 * Internal version of mount system call for diskless setup.
1091 struct nfs_dlmount
*ndmntp
,
1092 const char *mntname
,
1099 int error
, numcomps
;
1100 char *xdrbuf
, *p
, *cp
, *frompath
, *endserverp
;
1101 char uaddr
[MAX_IPv4_STR_LEN
];
1103 uint32_t mattrs
[NFS_MATTR_BITMAP_LEN
];
1104 uint32_t mflags_mask
[NFS_MFLAG_BITMAP_LEN
];
1105 uint32_t mflags
[NFS_MFLAG_BITMAP_LEN
];
1106 uint32_t argslength_offset
, attrslength_offset
, end_offset
;
1108 if ((error
= vfs_rootmountalloc("nfs", ndmntp
->ndm_mntfrom
, &mp
))) {
1109 printf("nfs_mount_diskless: NFS not configured\n");
1113 mp
->mnt_flag
|= mntflag
;
1114 if (!(mntflag
& MNT_RDONLY
))
1115 mp
->mnt_flag
&= ~MNT_RDONLY
;
1117 /* find the server-side path being mounted */
1118 frompath
= ndmntp
->ndm_mntfrom
;
1119 if (*frompath
== '[') { /* skip IPv6 literal address */
1120 while (*frompath
&& (*frompath
!= ']'))
1122 if (*frompath
== ']')
1125 while (*frompath
&& (*frompath
!= ':'))
1127 endserverp
= frompath
;
1128 while (*frompath
&& (*frompath
== ':'))
1130 /* count fs location path components */
1132 while (*p
&& (*p
== '/'))
1137 while (*p
&& (*p
!= '/'))
1139 while (*p
&& (*p
== '/'))
1143 /* convert address to universal address string */
1144 if (inet_ntop(AF_INET
, &ndmntp
->ndm_saddr
.sin_addr
, uaddr
, sizeof(uaddr
)) != uaddr
) {
1145 printf("nfs_mount_diskless: bad address\n");
1149 /* prepare mount attributes */
1150 NFS_BITMAP_ZERO(mattrs
, NFS_MATTR_BITMAP_LEN
);
1151 NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_VERSION
);
1152 NFS_BITMAP_SET(mattrs
, NFS_MATTR_SOCKET_TYPE
);
1153 NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_PORT
);
1154 NFS_BITMAP_SET(mattrs
, NFS_MATTR_FH
);
1155 NFS_BITMAP_SET(mattrs
, NFS_MATTR_FS_LOCATIONS
);
1156 NFS_BITMAP_SET(mattrs
, NFS_MATTR_MNTFLAGS
);
1158 /* prepare mount flags */
1159 NFS_BITMAP_ZERO(mflags_mask
, NFS_MFLAG_BITMAP_LEN
);
1160 NFS_BITMAP_ZERO(mflags
, NFS_MFLAG_BITMAP_LEN
);
1161 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_RESVPORT
);
1162 NFS_BITMAP_SET(mflags
, NFS_MFLAG_RESVPORT
);
1164 /* build xdr buffer */
1165 xb_init_buffer(&xb
, NULL
, 0);
1166 xb_add_32(error
, &xb
, NFS_ARGSVERSION_XDR
);
1167 argslength_offset
= xb_offset(&xb
);
1168 xb_add_32(error
, &xb
, 0); // args length
1169 xb_add_32(error
, &xb
, NFS_XDRARGS_VERSION_0
);
1170 xb_add_bitmap(error
, &xb
, mattrs
, NFS_MATTR_BITMAP_LEN
);
1171 attrslength_offset
= xb_offset(&xb
);
1172 xb_add_32(error
, &xb
, 0); // attrs length
1173 xb_add_32(error
, &xb
, ndmntp
->ndm_nfsv3
? 3 : 2); // NFS version
1174 xb_add_string(error
, &xb
, ((ndmntp
->ndm_sotype
== SOCK_DGRAM
) ? "udp" : "tcp"), 3);
1175 xb_add_32(error
, &xb
, ntohs(ndmntp
->ndm_saddr
.sin_port
)); // NFS port
1176 xb_add_fh(error
, &xb
, &ndmntp
->ndm_fh
[0], ndmntp
->ndm_fhlen
);
1178 xb_add_32(error
, &xb
, 1); /* fs location count */
1179 xb_add_32(error
, &xb
, 1); /* server count */
1180 xb_add_string(error
, &xb
, ndmntp
->ndm_mntfrom
, (endserverp
- ndmntp
->ndm_mntfrom
)); /* server name */
1181 xb_add_32(error
, &xb
, 1); /* address count */
1182 xb_add_string(error
, &xb
, uaddr
, strlen(uaddr
)); /* address */
1183 xb_add_32(error
, &xb
, 0); /* empty server info */
1184 xb_add_32(error
, &xb
, numcomps
); /* pathname component count */
1186 while (*p
&& (*p
== '/'))
1190 while (*p
&& (*p
!= '/'))
1192 xb_add_string(error
, &xb
, cp
, (p
- cp
)); /* component */
1195 while (*p
&& (*p
== '/'))
1198 xb_add_32(error
, &xb
, 0); /* empty fsl info */
1199 xb_add_32(error
, &xb
, mntflag
); /* MNT flags */
1200 xb_build_done(error
, &xb
);
1202 /* update opaque counts */
1203 end_offset
= xb_offset(&xb
);
1205 error
= xb_seek(&xb
, argslength_offset
);
1206 xb_add_32(error
, &xb
, end_offset
- argslength_offset
+ XDRWORD
/*version*/);
1209 error
= xb_seek(&xb
, attrslength_offset
);
1210 xb_add_32(error
, &xb
, end_offset
- attrslength_offset
- XDRWORD
/*don't include length field*/);
1213 printf("nfs_mount_diskless: error %d assembling mount args\n", error
);
1217 /* grab the assembled buffer */
1218 xdrbuf
= xb_buffer_base(&xb
);
1219 xb
.xb_flags
&= ~XB_CLEANUP
;
1222 if ((error
= mountnfs(xdrbuf
, mp
, ctx
, vpp
))) {
1223 printf("nfs_mountroot: mount %s failed: %d\n", mntname
, error
);
1224 // XXX vfs_rootmountfailed(mp);
1226 mp
->mnt_vtable
->vfc_refcount
--;
1227 mount_list_unlock();
1229 mount_lock_destroy(mp
);
1231 mac_mount_label_destroy(mp
);
1233 FREE_ZONE(mp
, sizeof(struct mount
), M_MOUNT
);
1241 #if !defined(NO_MOUNT_PRIVATE)
1243 * Internal version of mount system call to mount "/private"
1244 * separately in diskless setup
1247 nfs_mount_diskless_private(
1248 struct nfs_dlmount
*ndmntp
,
1249 const char *mntname
,
1256 int error
, numcomps
;
1258 struct vfstable
*vfsp
;
1259 struct nameidata nd
;
1261 char *xdrbuf
= NULL
, *p
, *cp
, *frompath
, *endserverp
;
1262 char uaddr
[MAX_IPv4_STR_LEN
];
1264 uint32_t mattrs
[NFS_MATTR_BITMAP_LEN
];
1265 uint32_t mflags_mask
[NFS_MFLAG_BITMAP_LEN
], mflags
[NFS_MFLAG_BITMAP_LEN
];
1266 uint32_t argslength_offset
, attrslength_offset
, end_offset
;
1268 procp
= current_proc(); /* XXX */
1273 * mimic main()!. Temporarily set up rootvnode and other stuff so
1274 * that namei works. Need to undo this because main() does it, too
1276 struct filedesc
*fdp
; /* pointer to file descriptor state */
1278 mountlist
.tqh_first
->mnt_flag
|= MNT_ROOTFS
;
1280 /* Get the vnode for '/'. Set fdp->fd_cdir to reference it. */
1281 if (VFS_ROOT(mountlist
.tqh_first
, &rootvnode
, NULL
))
1282 panic("cannot find root vnode");
1283 error
= vnode_ref(rootvnode
);
1285 printf("nfs_mountroot: vnode_ref() failed on root vnode!\n");
1288 fdp
->fd_cdir
= rootvnode
;
1289 fdp
->fd_rdir
= NULL
;
1293 * Get vnode to be covered
1295 NDINIT(&nd
, LOOKUP
, OP_LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_SYSSPACE
,
1296 CAST_USER_ADDR_T(mntname
), ctx
);
1297 if ((error
= namei(&nd
))) {
1298 printf("nfs_mountroot: private namei failed!\n");
1302 /* undo vnode_ref() in mimic main()! */
1303 vnode_rele(rootvnode
);
1308 if ((error
= VNOP_FSYNC(vp
, MNT_WAIT
, ctx
)) ||
1309 (error
= buf_invalidateblks(vp
, BUF_WRITE_DATA
, 0, 0))) {
1313 if (vnode_vtype(vp
) != VDIR
) {
1318 for (vfsp
= vfsconf
; vfsp
; vfsp
= vfsp
->vfc_next
)
1319 if (!strncmp(vfsp
->vfc_name
, "nfs", sizeof(vfsp
->vfc_name
)))
1322 printf("nfs_mountroot: private NFS not configured\n");
1327 if (vnode_mountedhere(vp
) != NULL
) {
1334 * Allocate and initialize the filesystem.
1336 mp
= _MALLOC_ZONE((u_int32_t
)sizeof(struct mount
), M_MOUNT
, M_WAITOK
);
1338 printf("nfs_mountroot: unable to allocate mount structure\n");
1343 bzero((char *)mp
, sizeof(struct mount
));
1345 /* Initialize the default IO constraints */
1346 mp
->mnt_maxreadcnt
= mp
->mnt_maxwritecnt
= MAXPHYS
;
1347 mp
->mnt_segreadcnt
= mp
->mnt_segwritecnt
= 32;
1348 mp
->mnt_ioflags
= 0;
1349 mp
->mnt_realrootvp
= NULLVP
;
1350 mp
->mnt_authcache_ttl
= 0; /* Allways go to our lookup */
1352 mount_lock_init(mp
);
1353 TAILQ_INIT(&mp
->mnt_vnodelist
);
1354 TAILQ_INIT(&mp
->mnt_workerqueue
);
1355 TAILQ_INIT(&mp
->mnt_newvnodes
);
1356 (void)vfs_busy(mp
, LK_NOWAIT
);
1357 TAILQ_INIT(&mp
->mnt_vnodelist
);
1359 vfsp
->vfc_refcount
++;
1360 mount_list_unlock();
1361 mp
->mnt_vtable
= vfsp
;
1362 mp
->mnt_op
= vfsp
->vfc_vfsops
;
1363 // mp->mnt_stat.f_type = vfsp->vfc_typenum;
1364 mp
->mnt_flag
= mntflag
;
1365 mp
->mnt_flag
|= vfsp
->vfc_flags
& MNT_VISFLAGMASK
;
1366 strncpy(mp
->mnt_vfsstat
.f_fstypename
, vfsp
->vfc_name
, MFSNAMELEN
-1);
1367 vp
->v_mountedhere
= mp
;
1368 mp
->mnt_vnodecovered
= vp
;
1370 mp
->mnt_vfsstat
.f_owner
= kauth_cred_getuid(kauth_cred_get());
1371 (void) copystr(mntname
, mp
->mnt_vfsstat
.f_mntonname
, MAXPATHLEN
- 1, 0);
1372 (void) copystr(ndmntp
->ndm_mntfrom
, mp
->mnt_vfsstat
.f_mntfromname
, MAXPATHLEN
- 1, 0);
1374 mac_mount_label_init(mp
);
1375 mac_mount_label_associate(ctx
, mp
);
1378 /* find the server-side path being mounted */
1379 frompath
= ndmntp
->ndm_mntfrom
;
1380 if (*frompath
== '[') { /* skip IPv6 literal address */
1381 while (*frompath
&& (*frompath
!= ']'))
1383 if (*frompath
== ']')
1386 while (*frompath
&& (*frompath
!= ':'))
1388 endserverp
= frompath
;
1389 while (*frompath
&& (*frompath
== ':'))
1391 /* count fs location path components */
1393 while (*p
&& (*p
== '/'))
1398 while (*p
&& (*p
!= '/'))
1400 while (*p
&& (*p
== '/'))
1404 /* convert address to universal address string */
1405 if (inet_ntop(AF_INET
, &ndmntp
->ndm_saddr
.sin_addr
, uaddr
, sizeof(uaddr
)) != uaddr
) {
1406 printf("nfs_mountroot: bad address\n");
1411 /* prepare mount attributes */
1412 NFS_BITMAP_ZERO(mattrs
, NFS_MATTR_BITMAP_LEN
);
1413 NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_VERSION
);
1414 NFS_BITMAP_SET(mattrs
, NFS_MATTR_SOCKET_TYPE
);
1415 NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_PORT
);
1416 NFS_BITMAP_SET(mattrs
, NFS_MATTR_FH
);
1417 NFS_BITMAP_SET(mattrs
, NFS_MATTR_FS_LOCATIONS
);
1418 NFS_BITMAP_SET(mattrs
, NFS_MATTR_MNTFLAGS
);
1420 /* prepare mount flags */
1421 NFS_BITMAP_ZERO(mflags_mask
, NFS_MFLAG_BITMAP_LEN
);
1422 NFS_BITMAP_ZERO(mflags
, NFS_MFLAG_BITMAP_LEN
);
1423 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_RESVPORT
);
1424 NFS_BITMAP_SET(mflags
, NFS_MFLAG_RESVPORT
);
1426 /* build xdr buffer */
1427 xb_init_buffer(&xb
, NULL
, 0);
1428 xb_add_32(error
, &xb
, NFS_ARGSVERSION_XDR
);
1429 argslength_offset
= xb_offset(&xb
);
1430 xb_add_32(error
, &xb
, 0); // args length
1431 xb_add_32(error
, &xb
, NFS_XDRARGS_VERSION_0
);
1432 xb_add_bitmap(error
, &xb
, mattrs
, NFS_MATTR_BITMAP_LEN
);
1433 attrslength_offset
= xb_offset(&xb
);
1434 xb_add_32(error
, &xb
, 0); // attrs length
1435 xb_add_32(error
, &xb
, ndmntp
->ndm_nfsv3
? 3 : 2); // NFS version
1436 xb_add_string(error
, &xb
, ((ndmntp
->ndm_sotype
== SOCK_DGRAM
) ? "udp" : "tcp"), 3);
1437 xb_add_32(error
, &xb
, ntohs(ndmntp
->ndm_saddr
.sin_port
)); // NFS port
1438 xb_add_fh(error
, &xb
, &ndmntp
->ndm_fh
[0], ndmntp
->ndm_fhlen
);
1440 xb_add_32(error
, &xb
, 1); /* fs location count */
1441 xb_add_32(error
, &xb
, 1); /* server count */
1442 xb_add_string(error
, &xb
, ndmntp
->ndm_mntfrom
, (endserverp
- ndmntp
->ndm_mntfrom
)); /* server name */
1443 xb_add_32(error
, &xb
, 1); /* address count */
1444 xb_add_string(error
, &xb
, uaddr
, strlen(uaddr
)); /* address */
1445 xb_add_32(error
, &xb
, 0); /* empty server info */
1446 xb_add_32(error
, &xb
, numcomps
); /* pathname component count */
1448 while (*p
&& (*p
== '/'))
1452 while (*p
&& (*p
!= '/'))
1454 xb_add_string(error
, &xb
, cp
, (p
- cp
)); /* component */
1457 while (*p
&& (*p
== '/'))
1460 xb_add_32(error
, &xb
, 0); /* empty fsl info */
1461 xb_add_32(error
, &xb
, mntflag
); /* MNT flags */
1462 xb_build_done(error
, &xb
);
1464 /* update opaque counts */
1465 end_offset
= xb_offset(&xb
);
1467 error
= xb_seek(&xb
, argslength_offset
);
1468 xb_add_32(error
, &xb
, end_offset
- argslength_offset
+ XDRWORD
/*version*/);
1471 error
= xb_seek(&xb
, attrslength_offset
);
1472 xb_add_32(error
, &xb
, end_offset
- attrslength_offset
- XDRWORD
/*don't include length field*/);
1475 printf("nfs_mountroot: error %d assembling mount args\n", error
);
1478 /* grab the assembled buffer */
1479 xdrbuf
= xb_buffer_base(&xb
);
1480 xb
.xb_flags
&= ~XB_CLEANUP
;
1483 if ((error
= mountnfs(xdrbuf
, mp
, ctx
, &vp
))) {
1484 printf("nfs_mountroot: mount %s failed: %d\n", mntname
, error
);
1485 vnode_put(mp
->mnt_vnodecovered
);
1487 vfsp
->vfc_refcount
--;
1488 mount_list_unlock();
1490 mount_lock_destroy(mp
);
1492 mac_mount_label_destroy(mp
);
1494 FREE_ZONE(mp
, sizeof (struct mount
), M_MOUNT
);
1504 #endif /* NO_MOUNT_PRIVATE */
1507 * Convert old style NFS mount args to XDR.
1510 nfs_convert_old_nfs_args(mount_t mp
, user_addr_t data
, vfs_context_t ctx
, int argsversion
, int inkernel
, char **xdrbufp
)
1512 int error
= 0, args64bit
, argsize
, numcomps
;
1513 struct user_nfs_args args
;
1514 struct nfs_args tempargs
;
1517 u_char nfh
[NFS4_FHSIZE
];
1518 char *mntfrom
, *endserverp
, *frompath
, *p
, *cp
;
1519 struct sockaddr_storage ss
;
1521 char uaddr
[MAX_IPv6_STR_LEN
];
1522 uint32_t mattrs
[NFS_MATTR_BITMAP_LEN
];
1523 uint32_t mflags_mask
[NFS_MFLAG_BITMAP_LEN
], mflags
[NFS_MFLAG_BITMAP_LEN
];
1524 uint32_t nfsvers
, nfslockmode
= 0, argslength_offset
, attrslength_offset
, end_offset
;
1529 /* allocate a temporary buffer for mntfrom */
1530 MALLOC_ZONE(mntfrom
, char*, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1534 args64bit
= (inkernel
|| vfs_context_is64bit(ctx
));
1535 argsp
= args64bit
? (void*)&args
: (void*)&tempargs
;
1537 argsize
= args64bit
? sizeof(args
) : sizeof(tempargs
);
1538 switch (argsversion
) {
1540 argsize
-= NFS_ARGSVERSION4_INCSIZE
;
1542 argsize
-= NFS_ARGSVERSION5_INCSIZE
;
1544 argsize
-= NFS_ARGSVERSION6_INCSIZE
;
1548 error
= EPROGMISMATCH
;
1552 /* read in the structure */
1554 bcopy(CAST_DOWN(void *, data
), argsp
, argsize
);
1556 error
= copyin(data
, argsp
, argsize
);
1560 args
.addrlen
= tempargs
.addrlen
;
1561 args
.sotype
= tempargs
.sotype
;
1562 args
.proto
= tempargs
.proto
;
1563 args
.fhsize
= tempargs
.fhsize
;
1564 args
.flags
= tempargs
.flags
;
1565 args
.wsize
= tempargs
.wsize
;
1566 args
.rsize
= tempargs
.rsize
;
1567 args
.readdirsize
= tempargs
.readdirsize
;
1568 args
.timeo
= tempargs
.timeo
;
1569 args
.retrans
= tempargs
.retrans
;
1570 args
.maxgrouplist
= tempargs
.maxgrouplist
;
1571 args
.readahead
= tempargs
.readahead
;
1572 args
.leaseterm
= tempargs
.leaseterm
;
1573 args
.deadthresh
= tempargs
.deadthresh
;
1574 args
.addr
= CAST_USER_ADDR_T(tempargs
.addr
);
1575 args
.fh
= CAST_USER_ADDR_T(tempargs
.fh
);
1576 args
.hostname
= CAST_USER_ADDR_T(tempargs
.hostname
);
1577 if (args
.version
>= 4) {
1578 args
.acregmin
= tempargs
.acregmin
;
1579 args
.acregmax
= tempargs
.acregmax
;
1580 args
.acdirmin
= tempargs
.acdirmin
;
1581 args
.acdirmax
= tempargs
.acdirmax
;
1583 if (args
.version
>= 5)
1584 args
.auth
= tempargs
.auth
;
1585 if (args
.version
>= 6)
1586 args
.deadtimeout
= tempargs
.deadtimeout
;
1589 if ((args
.fhsize
< 0) || (args
.fhsize
> NFS4_FHSIZE
)) {
1593 if (args
.fhsize
> 0) {
1595 bcopy(CAST_DOWN(void *, args
.fh
), (caddr_t
)nfh
, args
.fhsize
);
1597 error
= copyin(args
.fh
, (caddr_t
)nfh
, args
.fhsize
);
1602 error
= copystr(CAST_DOWN(void *, args
.hostname
), mntfrom
, MAXPATHLEN
-1, &len
);
1604 error
= copyinstr(args
.hostname
, mntfrom
, MAXPATHLEN
-1, &len
);
1606 bzero(&mntfrom
[len
], MAXPATHLEN
- len
);
1608 /* find the server-side path being mounted */
1610 if (*frompath
== '[') { /* skip IPv6 literal address */
1611 while (*frompath
&& (*frompath
!= ']'))
1613 if (*frompath
== ']')
1616 while (*frompath
&& (*frompath
!= ':'))
1618 endserverp
= frompath
;
1619 while (*frompath
&& (*frompath
== ':'))
1621 /* count fs location path components */
1623 while (*p
&& (*p
== '/'))
1628 while (*p
&& (*p
!= '/'))
1630 while (*p
&& (*p
== '/'))
1634 /* copy socket address */
1636 bcopy(CAST_DOWN(void *, args
.addr
), &ss
, args
.addrlen
);
1638 if ((size_t)args
.addrlen
> sizeof (struct sockaddr_storage
))
1641 error
= copyin(args
.addr
, &ss
, args
.addrlen
);
1644 ss
.ss_len
= args
.addrlen
;
1646 /* convert address to universal address string */
1647 if (ss
.ss_family
== AF_INET
)
1648 sinaddr
= &((struct sockaddr_in
*)&ss
)->sin_addr
;
1649 else if (ss
.ss_family
== AF_INET6
)
1650 sinaddr
= &((struct sockaddr_in6
*)&ss
)->sin6_addr
;
1653 if (!sinaddr
|| (inet_ntop(ss
.ss_family
, sinaddr
, uaddr
, sizeof(uaddr
)) != uaddr
)) {
1658 /* prepare mount flags */
1659 NFS_BITMAP_ZERO(mflags_mask
, NFS_MFLAG_BITMAP_LEN
);
1660 NFS_BITMAP_ZERO(mflags
, NFS_MFLAG_BITMAP_LEN
);
1661 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_SOFT
);
1662 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_INTR
);
1663 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_RESVPORT
);
1664 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NOCONNECT
);
1665 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_DUMBTIMER
);
1666 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_CALLUMNT
);
1667 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_RDIRPLUS
);
1668 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NONEGNAMECACHE
);
1669 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_MUTEJUKEBOX
);
1670 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NOQUOTA
);
1671 if (args
.flags
& NFSMNT_SOFT
)
1672 NFS_BITMAP_SET(mflags
, NFS_MFLAG_SOFT
);
1673 if (args
.flags
& NFSMNT_INT
)
1674 NFS_BITMAP_SET(mflags
, NFS_MFLAG_INTR
);
1675 if (args
.flags
& NFSMNT_RESVPORT
)
1676 NFS_BITMAP_SET(mflags
, NFS_MFLAG_RESVPORT
);
1677 if (args
.flags
& NFSMNT_NOCONN
)
1678 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NOCONNECT
);
1679 if (args
.flags
& NFSMNT_DUMBTIMR
)
1680 NFS_BITMAP_SET(mflags
, NFS_MFLAG_DUMBTIMER
);
1681 if (args
.flags
& NFSMNT_CALLUMNT
)
1682 NFS_BITMAP_SET(mflags
, NFS_MFLAG_CALLUMNT
);
1683 if (args
.flags
& NFSMNT_RDIRPLUS
)
1684 NFS_BITMAP_SET(mflags
, NFS_MFLAG_RDIRPLUS
);
1685 if (args
.flags
& NFSMNT_NONEGNAMECACHE
)
1686 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NONEGNAMECACHE
);
1687 if (args
.flags
& NFSMNT_MUTEJUKEBOX
)
1688 NFS_BITMAP_SET(mflags
, NFS_MFLAG_MUTEJUKEBOX
);
1689 if (args
.flags
& NFSMNT_NOQUOTA
)
1690 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NOQUOTA
);
1692 /* prepare mount attributes */
1693 NFS_BITMAP_ZERO(mattrs
, NFS_MATTR_BITMAP_LEN
);
1694 NFS_BITMAP_SET(mattrs
, NFS_MATTR_FLAGS
);
1695 NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_VERSION
);
1696 NFS_BITMAP_SET(mattrs
, NFS_MATTR_SOCKET_TYPE
);
1697 NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_PORT
);
1698 NFS_BITMAP_SET(mattrs
, NFS_MATTR_FH
);
1699 NFS_BITMAP_SET(mattrs
, NFS_MATTR_FS_LOCATIONS
);
1700 NFS_BITMAP_SET(mattrs
, NFS_MATTR_MNTFLAGS
);
1701 NFS_BITMAP_SET(mattrs
, NFS_MATTR_MNTFROM
);
1702 if (args
.flags
& NFSMNT_NFSV4
)
1704 else if (args
.flags
& NFSMNT_NFSV3
)
1708 if ((args
.flags
& NFSMNT_RSIZE
) && (args
.rsize
> 0))
1709 NFS_BITMAP_SET(mattrs
, NFS_MATTR_READ_SIZE
);
1710 if ((args
.flags
& NFSMNT_WSIZE
) && (args
.wsize
> 0))
1711 NFS_BITMAP_SET(mattrs
, NFS_MATTR_WRITE_SIZE
);
1712 if ((args
.flags
& NFSMNT_TIMEO
) && (args
.timeo
> 0))
1713 NFS_BITMAP_SET(mattrs
, NFS_MATTR_REQUEST_TIMEOUT
);
1714 if ((args
.flags
& NFSMNT_RETRANS
) && (args
.retrans
> 0))
1715 NFS_BITMAP_SET(mattrs
, NFS_MATTR_SOFT_RETRY_COUNT
);
1716 if ((args
.flags
& NFSMNT_MAXGRPS
) && (args
.maxgrouplist
> 0))
1717 NFS_BITMAP_SET(mattrs
, NFS_MATTR_MAX_GROUP_LIST
);
1718 if ((args
.flags
& NFSMNT_READAHEAD
) && (args
.readahead
> 0))
1719 NFS_BITMAP_SET(mattrs
, NFS_MATTR_READAHEAD
);
1720 if ((args
.flags
& NFSMNT_READDIRSIZE
) && (args
.readdirsize
> 0))
1721 NFS_BITMAP_SET(mattrs
, NFS_MATTR_READDIR_SIZE
);
1722 if ((args
.flags
& NFSMNT_NOLOCKS
) ||
1723 (args
.flags
& NFSMNT_LOCALLOCKS
)) {
1724 NFS_BITMAP_SET(mattrs
, NFS_MATTR_LOCK_MODE
);
1725 if (args
.flags
& NFSMNT_NOLOCKS
)
1726 nfslockmode
= NFS_LOCK_MODE_DISABLED
;
1727 else if (args
.flags
& NFSMNT_LOCALLOCKS
)
1728 nfslockmode
= NFS_LOCK_MODE_LOCAL
;
1730 nfslockmode
= NFS_LOCK_MODE_ENABLED
;
1732 if (args
.version
>= 4) {
1733 if ((args
.flags
& NFSMNT_ACREGMIN
) && (args
.acregmin
> 0))
1734 NFS_BITMAP_SET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MIN
);
1735 if ((args
.flags
& NFSMNT_ACREGMAX
) && (args
.acregmax
> 0))
1736 NFS_BITMAP_SET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MAX
);
1737 if ((args
.flags
& NFSMNT_ACDIRMIN
) && (args
.acdirmin
> 0))
1738 NFS_BITMAP_SET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MIN
);
1739 if ((args
.flags
& NFSMNT_ACDIRMAX
) && (args
.acdirmax
> 0))
1740 NFS_BITMAP_SET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MAX
);
1742 if (args
.version
>= 5) {
1743 if ((args
.flags
& NFSMNT_SECFLAVOR
) || (args
.flags
& NFSMNT_SECSYSOK
))
1744 NFS_BITMAP_SET(mattrs
, NFS_MATTR_SECURITY
);
1746 if (args
.version
>= 6) {
1747 if ((args
.flags
& NFSMNT_DEADTIMEOUT
) && (args
.deadtimeout
> 0))
1748 NFS_BITMAP_SET(mattrs
, NFS_MATTR_DEAD_TIMEOUT
);
1751 /* build xdr buffer */
1752 xb_init_buffer(&xb
, NULL
, 0);
1753 xb_add_32(error
, &xb
, args
.version
);
1754 argslength_offset
= xb_offset(&xb
);
1755 xb_add_32(error
, &xb
, 0); // args length
1756 xb_add_32(error
, &xb
, NFS_XDRARGS_VERSION_0
);
1757 xb_add_bitmap(error
, &xb
, mattrs
, NFS_MATTR_BITMAP_LEN
);
1758 attrslength_offset
= xb_offset(&xb
);
1759 xb_add_32(error
, &xb
, 0); // attrs length
1760 xb_add_bitmap(error
, &xb
, mflags_mask
, NFS_MFLAG_BITMAP_LEN
); /* mask */
1761 xb_add_bitmap(error
, &xb
, mflags
, NFS_MFLAG_BITMAP_LEN
); /* value */
1762 xb_add_32(error
, &xb
, nfsvers
);
1763 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READ_SIZE
))
1764 xb_add_32(error
, &xb
, args
.rsize
);
1765 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_WRITE_SIZE
))
1766 xb_add_32(error
, &xb
, args
.wsize
);
1767 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READDIR_SIZE
))
1768 xb_add_32(error
, &xb
, args
.readdirsize
);
1769 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READAHEAD
))
1770 xb_add_32(error
, &xb
, args
.readahead
);
1771 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MIN
)) {
1772 xb_add_32(error
, &xb
, args
.acregmin
);
1773 xb_add_32(error
, &xb
, 0);
1775 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MAX
)) {
1776 xb_add_32(error
, &xb
, args
.acregmax
);
1777 xb_add_32(error
, &xb
, 0);
1779 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MIN
)) {
1780 xb_add_32(error
, &xb
, args
.acdirmin
);
1781 xb_add_32(error
, &xb
, 0);
1783 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MAX
)) {
1784 xb_add_32(error
, &xb
, args
.acdirmax
);
1785 xb_add_32(error
, &xb
, 0);
1787 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_LOCK_MODE
))
1788 xb_add_32(error
, &xb
, nfslockmode
);
1789 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SECURITY
)) {
1790 uint32_t flavors
[2], i
=0;
1791 if (args
.flags
& NFSMNT_SECFLAVOR
)
1792 flavors
[i
++] = args
.auth
;
1793 if ((args
.flags
& NFSMNT_SECSYSOK
) && ((i
== 0) || (flavors
[0] != RPCAUTH_SYS
)))
1794 flavors
[i
++] = RPCAUTH_SYS
;
1795 xb_add_word_array(error
, &xb
, flavors
, i
);
1797 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MAX_GROUP_LIST
))
1798 xb_add_32(error
, &xb
, args
.maxgrouplist
);
1799 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SOCKET_TYPE
))
1800 xb_add_string(error
, &xb
, ((args
.sotype
== SOCK_DGRAM
) ? "udp" : "tcp"), 3);
1801 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_PORT
))
1802 xb_add_32(error
, &xb
, ((ss
.ss_family
== AF_INET
) ?
1803 ntohs(((struct sockaddr_in
*)&ss
)->sin_port
) :
1804 ntohs(((struct sockaddr_in6
*)&ss
)->sin6_port
)));
1805 /* NFS_MATTR_MOUNT_PORT (not available in old args) */
1806 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_REQUEST_TIMEOUT
)) {
1807 /* convert from .1s increments to time */
1808 xb_add_32(error
, &xb
, args
.timeo
/10);
1809 xb_add_32(error
, &xb
, (args
.timeo%10
)*100000000);
1811 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SOFT_RETRY_COUNT
))
1812 xb_add_32(error
, &xb
, args
.retrans
);
1813 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_DEAD_TIMEOUT
)) {
1814 xb_add_32(error
, &xb
, args
.deadtimeout
);
1815 xb_add_32(error
, &xb
, 0);
1817 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_FH
))
1818 xb_add_fh(error
, &xb
, &nfh
[0], args
.fhsize
);
1819 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_FS_LOCATIONS
)) {
1820 xb_add_32(error
, &xb
, 1); /* fs location count */
1821 xb_add_32(error
, &xb
, 1); /* server count */
1822 xb_add_string(error
, &xb
, mntfrom
, (endserverp
- mntfrom
)); /* server name */
1823 xb_add_32(error
, &xb
, 1); /* address count */
1824 xb_add_string(error
, &xb
, uaddr
, strlen(uaddr
)); /* address */
1825 xb_add_32(error
, &xb
, 0); /* empty server info */
1826 xb_add_32(error
, &xb
, numcomps
); /* pathname component count */
1829 while (*p
&& (*p
== '/'))
1833 while (*p
&& (*p
!= '/'))
1835 xb_add_string(error
, &xb
, cp
, (p
- cp
)); /* component */
1837 while (*p
&& (*p
== '/'))
1840 xb_add_32(error
, &xb
, 0); /* empty fsl info */
1842 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MNTFLAGS
))
1843 xb_add_32(error
, &xb
, (vfs_flags(mp
) & MNT_VISFLAGMASK
)); /* VFS MNT_* flags */
1844 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MNTFROM
))
1845 xb_add_string(error
, &xb
, mntfrom
, strlen(mntfrom
)); /* fixed f_mntfromname */
1846 xb_build_done(error
, &xb
);
1848 /* update opaque counts */
1849 end_offset
= xb_offset(&xb
);
1850 error
= xb_seek(&xb
, argslength_offset
);
1851 xb_add_32(error
, &xb
, end_offset
- argslength_offset
+ XDRWORD
/*version*/);
1853 error
= xb_seek(&xb
, attrslength_offset
);
1854 xb_add_32(error
, &xb
, end_offset
- attrslength_offset
- XDRWORD
/*don't include length field*/);
1857 /* grab the assembled buffer */
1858 *xdrbufp
= xb_buffer_base(&xb
);
1859 xb
.xb_flags
&= ~XB_CLEANUP
;
1863 FREE_ZONE(mntfrom
, MAXPATHLEN
, M_NAMEI
);
1873 nfs_vfs_mount(mount_t mp
, vnode_t vp
, user_addr_t data
, vfs_context_t ctx
)
1875 int error
= 0, inkernel
= vfs_iskernelmount(mp
);
1876 uint32_t argsversion
, argslength
;
1877 char *xdrbuf
= NULL
;
1879 /* read in version */
1881 bcopy(CAST_DOWN(void *, data
), &argsversion
, sizeof(argsversion
));
1882 else if ((error
= copyin(data
, &argsversion
, sizeof(argsversion
))))
1885 /* If we have XDR args, then all values in the buffer are in network order */
1886 if (argsversion
== htonl(NFS_ARGSVERSION_XDR
))
1887 argsversion
= NFS_ARGSVERSION_XDR
;
1889 switch (argsversion
) {
1894 /* convert old-style args to xdr */
1895 error
= nfs_convert_old_nfs_args(mp
, data
, ctx
, argsversion
, inkernel
, &xdrbuf
);
1897 case NFS_ARGSVERSION_XDR
:
1898 /* copy in xdr buffer */
1900 bcopy(CAST_DOWN(void *, (data
+ XDRWORD
)), &argslength
, XDRWORD
);
1902 error
= copyin((data
+ XDRWORD
), &argslength
, XDRWORD
);
1905 argslength
= ntohl(argslength
);
1906 /* put a reasonable limit on the size of the XDR args */
1907 if (argslength
> 16*1024) {
1911 /* allocate xdr buffer */
1912 xdrbuf
= xb_malloc(xdr_rndup(argslength
));
1918 bcopy(CAST_DOWN(void *, data
), xdrbuf
, argslength
);
1920 error
= copyin(data
, xdrbuf
, argslength
);
1923 error
= EPROGMISMATCH
;
1931 error
= mountnfs(xdrbuf
, mp
, ctx
, &vp
);
1936 * Common code for mount and mountroot
1939 /* Set up an NFSv2/v3 mount */
1942 struct nfsmount
*nmp
,
1947 struct nfs_vattr nvattr
;
1956 * Get file attributes for the mountpoint. These are needed
1957 * in order to properly create the root vnode.
1959 error
= nfs3_getattr_rpc(NULL
, nmp
->nm_mountp
, nmp
->nm_fh
->fh_data
, nmp
->nm_fh
->fh_len
, 0,
1960 ctx
, &nvattr
, &xid
);
1964 error
= nfs_nget(nmp
->nm_mountp
, NULL
, NULL
, nmp
->nm_fh
->fh_data
, nmp
->nm_fh
->fh_len
,
1965 &nvattr
, &xid
, RPCAUTH_UNKNOWN
, NG_MARKROOT
, npp
);
1967 nfs_node_unlock(*npp
);
1972 * Try to make sure we have all the general info from the server.
1974 if (nmp
->nm_vers
== NFS_VER2
) {
1975 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXNAME
);
1976 nmp
->nm_fsattr
.nfsa_maxname
= NFS_MAXNAMLEN
;
1977 } else if (nmp
->nm_vers
== NFS_VER3
) {
1978 /* get the NFSv3 FSINFO */
1979 error
= nfs3_fsinfo(nmp
, *npp
, ctx
);
1982 /* If the server indicates all pathconf info is */
1983 /* the same, grab a copy of that info now */
1984 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_HOMOGENEOUS
) &&
1985 (nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_HOMOGENEOUS
)) {
1986 struct nfs_fsattr nfsa
;
1987 if (!nfs3_pathconf_rpc(*npp
, &nfsa
, ctx
)) {
1988 /* cache a copy of the results */
1989 lck_mtx_lock(&nmp
->nm_lock
);
1990 nfs3_pathconf_cache(nmp
, &nfsa
);
1991 lck_mtx_unlock(&nmp
->nm_lock
);
1996 if (*npp
&& error
) {
1997 vnode_put(NFSTOV(*npp
));
1998 vnode_recycle(NFSTOV(*npp
));
2005 * Update an NFSv4 mount path with the contents of the symlink.
2007 * Read the link for the given file handle.
2008 * Insert the link's components into the path.
2011 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
)
2013 int error
= 0, status
, numops
;
2014 uint32_t len
= 0, comp
, newcomp
, linkcompcount
;
2016 struct nfsm_chain nmreq
, nmrep
;
2017 struct nfsreq rq
, *req
= &rq
;
2018 struct nfsreq_secinfo_args si
;
2019 char *link
= NULL
, *p
, *q
, ch
;
2020 struct nfs_fs_path nfsp2
;
2022 bzero(&nfsp2
, sizeof(nfsp2
));
2024 NFSREQ_SECINFO_SET(&si
, NULL
, dirfhp
->fh_data
, dirfhp
->fh_len
, nfsp
->np_components
[curcomp
], 0);
2026 NFSREQ_SECINFO_SET(&si
, NULL
, NULL
, 0, nfsp
->np_components
[curcomp
], 0);
2027 nfsm_chain_null(&nmreq
);
2028 nfsm_chain_null(&nmrep
);
2030 MALLOC_ZONE(link
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
2036 nfsm_chain_build_alloc_init(error
, &nmreq
, 12 * NFSX_UNSIGNED
);
2037 nfsm_chain_add_compound_header(error
, &nmreq
, "readlink", nmp
->nm_minor_vers
, numops
);
2039 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
2040 nfsm_chain_add_fh(error
, &nmreq
, NFS_VER4
, fhp
->fh_data
, fhp
->fh_len
);
2042 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_READLINK
);
2043 nfsm_chain_build_done(error
, &nmreq
);
2044 nfsm_assert(error
, (numops
== 0), EPROTO
);
2047 error
= nfs_request_async(NULL
, nmp
->nm_mountp
, &nmreq
, NFSPROC4_COMPOUND
,
2048 vfs_context_thread(ctx
), vfs_context_ucred(ctx
), &si
, 0, NULL
, &req
);
2050 error
= nfs_request_async_finish(req
, &nmrep
, &xid
, &status
);
2052 nfsm_chain_skip_tag(error
, &nmrep
);
2053 nfsm_chain_get_32(error
, &nmrep
, numops
);
2054 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
2055 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_READLINK
);
2056 nfsm_chain_get_32(error
, &nmrep
, len
);
2060 else if (len
>= MAXPATHLEN
)
2061 len
= MAXPATHLEN
- 1;
2062 nfsm_chain_get_opaque(error
, &nmrep
, len
, link
);
2064 /* make sure link string is terminated properly */
2067 /* count the number of components in link */
2069 while (*p
&& (*p
== '/'))
2074 while (*p
&& (*p
!= '/'))
2076 while (*p
&& (*p
== '/'))
2080 /* free up used components */
2081 for (comp
=0; comp
<= curcomp
; comp
++) {
2082 if (nfsp
->np_components
[comp
]) {
2083 FREE(nfsp
->np_components
[comp
], M_TEMP
);
2084 nfsp
->np_components
[comp
] = NULL
;
2088 /* set up new path */
2089 nfsp2
.np_compcount
= nfsp
->np_compcount
- curcomp
- 1 + linkcompcount
;
2090 MALLOC(nfsp2
.np_components
, char **, nfsp2
.np_compcount
*sizeof(char*), M_TEMP
, M_WAITOK
|M_ZERO
);
2091 if (!nfsp2
.np_components
) {
2096 /* add link components */
2098 while (*p
&& (*p
== '/'))
2100 for (newcomp
=0; newcomp
< linkcompcount
; newcomp
++) {
2101 /* find end of component */
2103 while (*q
&& (*q
!= '/'))
2105 MALLOC(nfsp2
.np_components
[newcomp
], char *, q
-p
+1, M_TEMP
, M_WAITOK
|M_ZERO
);
2106 if (!nfsp2
.np_components
[newcomp
]) {
2112 strlcpy(nfsp2
.np_components
[newcomp
], p
, q
-p
+1);
2115 while (*p
&& (*p
== '/'))
2120 /* add remaining components */
2121 for(comp
= curcomp
+ 1; comp
< nfsp
->np_compcount
; comp
++,newcomp
++) {
2122 nfsp2
.np_components
[newcomp
] = nfsp
->np_components
[comp
];
2123 nfsp
->np_components
[comp
] = NULL
;
2126 /* move new path into place */
2127 FREE(nfsp
->np_components
, M_TEMP
);
2128 nfsp
->np_components
= nfsp2
.np_components
;
2129 nfsp
->np_compcount
= nfsp2
.np_compcount
;
2130 nfsp2
.np_components
= NULL
;
2132 /* for absolute link, let the caller now that the next dirfh is root */
2133 if (link
[0] == '/') {
2139 FREE_ZONE(link
, MAXPATHLEN
, M_NAMEI
);
2140 if (nfsp2
.np_components
) {
2141 for (comp
=0; comp
< nfsp2
.np_compcount
; comp
++)
2142 if (nfsp2
.np_components
[comp
])
2143 FREE(nfsp2
.np_components
[comp
], M_TEMP
);
2144 FREE(nfsp2
.np_components
, M_TEMP
);
2146 nfsm_chain_cleanup(&nmreq
);
2147 nfsm_chain_cleanup(&nmrep
);
2151 /* Set up an NFSv4 mount */
2154 struct nfsmount
*nmp
,
2158 struct nfsm_chain nmreq
, nmrep
;
2159 int error
= 0, numops
, status
, interval
, isdotdot
, loopcnt
= 0, depth
= 0;
2160 struct nfs_fs_path fspath
, *nfsp
, fspath2
;
2161 uint32_t bitmap
[NFS_ATTR_BITMAP_LEN
], comp
, comp2
;
2162 fhandle_t fh
, dirfh
;
2163 struct nfs_vattr nvattr
;
2165 struct nfsreq rq
, *req
= &rq
;
2166 struct nfsreq_secinfo_args si
;
2168 struct nfs_fs_locations nfsls
;
2171 fh
.fh_len
= dirfh
.fh_len
= 0;
2172 TAILQ_INIT(&nmp
->nm_open_owners
);
2173 TAILQ_INIT(&nmp
->nm_delegations
);
2174 TAILQ_INIT(&nmp
->nm_dreturnq
);
2175 nmp
->nm_stategenid
= 1;
2176 NVATTR_INIT(&nvattr
);
2177 bzero(&nfsls
, sizeof(nfsls
));
2178 nfsm_chain_null(&nmreq
);
2179 nfsm_chain_null(&nmrep
);
2182 * If no security flavors were specified we'll want to default to the server's
2183 * preferred flavor. For NFSv4.0 we need a file handle and name to get that via
2184 * SECINFO, so we'll do that on the last component of the server path we are
2185 * mounting. If we are mounting the server's root, we'll need to defer the
2186 * SECINFO call to the first successful LOOKUP request.
2188 if (!nmp
->nm_sec
.count
)
2189 nmp
->nm_state
|= NFSSTA_NEEDSECINFO
;
2191 /* make a copy of the current location's path */
2192 nfsp
= &nmp
->nm_locations
.nl_locations
[nmp
->nm_locations
.nl_current
.nli_loc
]->nl_path
;
2193 bzero(&fspath
, sizeof(fspath
));
2194 fspath
.np_compcount
= nfsp
->np_compcount
;
2195 if (fspath
.np_compcount
> 0) {
2196 MALLOC(fspath
.np_components
, char **, fspath
.np_compcount
*sizeof(char*), M_TEMP
, M_WAITOK
|M_ZERO
);
2197 if (!fspath
.np_components
) {
2201 for (comp
=0; comp
< nfsp
->np_compcount
; comp
++) {
2202 int slen
= strlen(nfsp
->np_components
[comp
]);
2203 MALLOC(fspath
.np_components
[comp
], char *, slen
+1, M_TEMP
, M_WAITOK
|M_ZERO
);
2204 if (!fspath
.np_components
[comp
]) {
2208 strlcpy(fspath
.np_components
[comp
], nfsp
->np_components
[comp
], slen
+1);
2214 /* for mirror mounts, we can just use the file handle passed in */
2216 dirfh
.fh_len
= nmp
->nm_fh
->fh_len
;
2217 bcopy(nmp
->nm_fh
->fh_data
, dirfh
.fh_data
, dirfh
.fh_len
);
2218 NFSREQ_SECINFO_SET(&si
, NULL
, dirfh
.fh_data
, dirfh
.fh_len
, NULL
, 0);
2222 /* otherwise, we need to get the fh for the directory we are mounting */
2224 /* if no components, just get root */
2225 if (fspath
.np_compcount
== 0) {
2227 // PUTROOTFH + GETATTR(FH)
2228 NFSREQ_SECINFO_SET(&si
, NULL
, NULL
, 0, NULL
, 0);
2230 nfsm_chain_build_alloc_init(error
, &nmreq
, 9 * NFSX_UNSIGNED
);
2231 nfsm_chain_add_compound_header(error
, &nmreq
, "mount", nmp
->nm_minor_vers
, numops
);
2233 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTROOTFH
);
2235 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
2236 NFS_CLEAR_ATTRIBUTES(bitmap
);
2237 NFS4_DEFAULT_ATTRIBUTES(bitmap
);
2238 NFS_BITMAP_SET(bitmap
, NFS_FATTR_FILEHANDLE
);
2239 nfsm_chain_add_bitmap(error
, &nmreq
, bitmap
, NFS_ATTR_BITMAP_LEN
);
2240 nfsm_chain_build_done(error
, &nmreq
);
2241 nfsm_assert(error
, (numops
== 0), EPROTO
);
2243 error
= nfs_request_async(NULL
, nmp
->nm_mountp
, &nmreq
, NFSPROC4_COMPOUND
,
2244 vfs_context_thread(ctx
), vfs_context_ucred(ctx
), &si
, 0, NULL
, &req
);
2246 error
= nfs_request_async_finish(req
, &nmrep
, &xid
, &status
);
2247 nfsm_chain_skip_tag(error
, &nmrep
);
2248 nfsm_chain_get_32(error
, &nmrep
, numops
);
2249 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTROOTFH
);
2250 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
2252 NFS_CLEAR_ATTRIBUTES(nmp
->nm_fsattr
.nfsa_bitmap
);
2253 error
= nfs4_parsefattr(&nmrep
, &nmp
->nm_fsattr
, &nvattr
, &dirfh
, NULL
, NULL
);
2254 if (!error
&& !NFS_BITMAP_ISSET(&nvattr
.nva_bitmap
, NFS_FATTR_FILEHANDLE
)) {
2255 printf("nfs: mount didn't return filehandle?\n");
2259 nfsm_chain_cleanup(&nmrep
);
2260 nfsm_chain_null(&nmreq
);
2261 NVATTR_CLEANUP(&nvattr
);
2265 /* look up each path component */
2266 for (comp
=0; comp
< fspath
.np_compcount
; ) {
2268 if (fspath
.np_components
[comp
][0] == '.') {
2269 if (fspath
.np_components
[comp
][1] == '\0') {
2274 /* treat ".." specially */
2275 if ((fspath
.np_components
[comp
][1] == '.') &&
2276 (fspath
.np_components
[comp
][2] == '\0'))
2278 if (isdotdot
&& (dirfh
.fh_len
== 0)) {
2279 /* ".." in root directory is same as "." */
2284 // PUT(ROOT)FH + LOOKUP(P) + GETFH + GETATTR
2285 if (dirfh
.fh_len
== 0)
2286 NFSREQ_SECINFO_SET(&si
, NULL
, NULL
, 0, isdotdot
? NULL
: fspath
.np_components
[comp
], 0);
2288 NFSREQ_SECINFO_SET(&si
, NULL
, dirfh
.fh_data
, dirfh
.fh_len
, isdotdot
? NULL
: fspath
.np_components
[comp
], 0);
2290 nfsm_chain_build_alloc_init(error
, &nmreq
, 18 * NFSX_UNSIGNED
);
2291 nfsm_chain_add_compound_header(error
, &nmreq
, "mount", nmp
->nm_minor_vers
, numops
);
2294 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
2295 nfsm_chain_add_fh(error
, &nmreq
, NFS_VER4
, dirfh
.fh_data
, dirfh
.fh_len
);
2297 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTROOTFH
);
2301 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_LOOKUPP
);
2303 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_LOOKUP
);
2304 nfsm_chain_add_name(error
, &nmreq
,
2305 fspath
.np_components
[comp
], strlen(fspath
.np_components
[comp
]), nmp
);
2308 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETFH
);
2310 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
2311 NFS_CLEAR_ATTRIBUTES(bitmap
);
2312 NFS4_DEFAULT_ATTRIBUTES(bitmap
);
2313 /* if no namedattr support or component is ".zfs", clear NFS_FATTR_NAMED_ATTR */
2314 if (!NMFLAG(nmp
, NAMEDATTR
) || !strcmp(fspath
.np_components
[comp
], ".zfs"))
2315 NFS_BITMAP_CLR(bitmap
, NFS_FATTR_NAMED_ATTR
);
2316 nfsm_chain_add_bitmap(error
, &nmreq
, bitmap
, NFS_ATTR_BITMAP_LEN
);
2317 nfsm_chain_build_done(error
, &nmreq
);
2318 nfsm_assert(error
, (numops
== 0), EPROTO
);
2320 error
= nfs_request_async(NULL
, nmp
->nm_mountp
, &nmreq
, NFSPROC4_COMPOUND
,
2321 vfs_context_thread(ctx
), vfs_context_ucred(ctx
), &si
, 0, NULL
, &req
);
2323 error
= nfs_request_async_finish(req
, &nmrep
, &xid
, &status
);
2324 nfsm_chain_skip_tag(error
, &nmrep
);
2325 nfsm_chain_get_32(error
, &nmrep
, numops
);
2326 nfsm_chain_op_check(error
, &nmrep
, dirfh
.fh_len
? NFS_OP_PUTFH
: NFS_OP_PUTROOTFH
);
2327 nfsm_chain_op_check(error
, &nmrep
, isdotdot
? NFS_OP_LOOKUPP
: NFS_OP_LOOKUP
);
2329 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETFH
);
2330 nfsm_chain_get_32(error
, &nmrep
, fh
.fh_len
);
2331 if (fh
.fh_len
> sizeof(fh
.fh_data
))
2334 nfsm_chain_get_opaque(error
, &nmrep
, fh
.fh_len
, fh
.fh_data
);
2335 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
2337 NFS_CLEAR_ATTRIBUTES(nmp
->nm_fsattr
.nfsa_bitmap
);
2338 error
= nfs4_parsefattr(&nmrep
, &nmp
->nm_fsattr
, &nvattr
, NULL
, NULL
, &nfsls
);
2340 nfsm_chain_cleanup(&nmrep
);
2341 nfsm_chain_null(&nmreq
);
2343 /* LOOKUP succeeded but GETATTR failed? This could be a referral. */
2344 /* Try the lookup again with a getattr for fs_locations. */
2345 nfs_fs_locations_cleanup(&nfsls
);
2346 error
= nfs4_get_fs_locations(nmp
, NULL
, dirfh
.fh_data
, dirfh
.fh_len
, fspath
.np_components
[comp
], ctx
, &nfsls
);
2347 if (!error
&& (nfsls
.nl_numlocs
< 1))
2350 if (++loopcnt
> MAXSYMLINKS
) {
2351 /* too many symlink/referral redirections */
2355 /* tear down the current connection */
2356 nfs_disconnect(nmp
);
2357 /* replace fs locations */
2358 nfs_fs_locations_cleanup(&nmp
->nm_locations
);
2359 nmp
->nm_locations
= nfsls
;
2360 bzero(&nfsls
, sizeof(nfsls
));
2361 /* initiate a connection using the new fs locations */
2362 error
= nfs_mount_connect(nmp
);
2363 if (!error
&& !(nmp
->nm_locations
.nl_current
.nli_flags
& NLI_VALID
))
2366 /* add new server's remote path to beginning of our path and continue */
2367 nfsp
= &nmp
->nm_locations
.nl_locations
[nmp
->nm_locations
.nl_current
.nli_loc
]->nl_path
;
2368 bzero(&fspath2
, sizeof(fspath2
));
2369 fspath2
.np_compcount
= (fspath
.np_compcount
- comp
- 1) + nfsp
->np_compcount
;
2370 if (fspath2
.np_compcount
> 0) {
2371 MALLOC(fspath2
.np_components
, char **, fspath2
.np_compcount
*sizeof(char*), M_TEMP
, M_WAITOK
|M_ZERO
);
2372 if (!fspath2
.np_components
) {
2376 for (comp2
=0; comp2
< nfsp
->np_compcount
; comp2
++) {
2377 int slen
= strlen(nfsp
->np_components
[comp2
]);
2378 MALLOC(fspath2
.np_components
[comp2
], char *, slen
+1, M_TEMP
, M_WAITOK
|M_ZERO
);
2379 if (!fspath2
.np_components
[comp2
]) {
2380 /* clean up fspath2, then error out */
2383 FREE(fspath2
.np_components
[comp2
], M_TEMP
);
2385 FREE(fspath2
.np_components
, M_TEMP
);
2389 strlcpy(fspath2
.np_components
[comp2
], nfsp
->np_components
[comp2
], slen
+1);
2391 if ((fspath
.np_compcount
- comp
- 1) > 0)
2392 bcopy(&fspath
.np_components
[comp
+1], &fspath2
.np_components
[nfsp
->np_compcount
], (fspath
.np_compcount
- comp
- 1)*sizeof(char*));
2393 /* free up unused parts of old path (prior components and component array) */
2395 FREE(fspath
.np_components
[comp
], M_TEMP
);
2396 } while (comp
-- > 0);
2397 FREE(fspath
.np_components
, M_TEMP
);
2398 /* put new path in place */
2401 /* reset dirfh and component index */
2404 NVATTR_CLEANUP(&nvattr
);
2405 if (fspath
.np_compcount
== 0)
2410 /* if file handle is for a symlink, then update the path with the symlink contents */
2411 if (NFS_BITMAP_ISSET(&nvattr
.nva_bitmap
, NFS_FATTR_TYPE
) && (nvattr
.nva_type
== VLNK
)) {
2412 if (++loopcnt
> MAXSYMLINKS
)
2415 error
= nfs4_mount_update_path_with_symlink(nmp
, &fspath
, comp
, &dirfh
, &depth
, &fh
, ctx
);
2417 /* directory file handle is either left the same or reset to root (if link was absolute) */
2418 /* path traversal starts at beginning of the path again */
2420 NVATTR_CLEANUP(&nvattr
);
2421 nfs_fs_locations_cleanup(&nfsls
);
2424 NVATTR_CLEANUP(&nvattr
);
2425 nfs_fs_locations_cleanup(&nfsls
);
2426 /* not a symlink... */
2427 if ((nmp
->nm_state
& NFSSTA_NEEDSECINFO
) && (comp
== (fspath
.np_compcount
-1)) && !isdotdot
) {
2428 /* need to get SECINFO for the directory being mounted */
2429 if (dirfh
.fh_len
== 0)
2430 NFSREQ_SECINFO_SET(&si
, NULL
, NULL
, 0, isdotdot
? NULL
: fspath
.np_components
[comp
], 0);
2432 NFSREQ_SECINFO_SET(&si
, NULL
, dirfh
.fh_data
, dirfh
.fh_len
, isdotdot
? NULL
: fspath
.np_components
[comp
], 0);
2433 sec
.count
= NX_MAX_SEC_FLAVORS
;
2434 error
= nfs4_secinfo_rpc(nmp
, &si
, vfs_context_ucred(ctx
), sec
.flavors
, &sec
.count
);
2435 /* [sigh] some implementations return "illegal" error for unsupported ops */
2436 if (error
== NFSERR_OP_ILLEGAL
)
2439 /* set our default security flavor to the first in the list */
2441 nmp
->nm_auth
= sec
.flavors
[0];
2442 nmp
->nm_state
&= ~NFSSTA_NEEDSECINFO
;
2444 /* advance directory file handle, component index, & update depth */
2447 if (!isdotdot
) /* going down the hierarchy */
2449 else if (--depth
<= 0) /* going up the hierarchy */
2450 dirfh
.fh_len
= 0; /* clear dirfh when we hit root */
2454 /* get attrs for mount point root */
2455 numops
= NMFLAG(nmp
, NAMEDATTR
) ? 3 : 2; // PUTFH + GETATTR + OPENATTR
2456 nfsm_chain_build_alloc_init(error
, &nmreq
, 25 * NFSX_UNSIGNED
);
2457 nfsm_chain_add_compound_header(error
, &nmreq
, "mount", nmp
->nm_minor_vers
, numops
);
2459 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
2460 nfsm_chain_add_fh(error
, &nmreq
, NFS_VER4
, dirfh
.fh_data
, dirfh
.fh_len
);
2462 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
2463 NFS_CLEAR_ATTRIBUTES(bitmap
);
2464 NFS4_DEFAULT_ATTRIBUTES(bitmap
);
2465 /* if no namedattr support or last component is ".zfs", clear NFS_FATTR_NAMED_ATTR */
2466 if (!NMFLAG(nmp
, NAMEDATTR
) || ((fspath
.np_compcount
> 0) && !strcmp(fspath
.np_components
[fspath
.np_compcount
-1], ".zfs")))
2467 NFS_BITMAP_CLR(bitmap
, NFS_FATTR_NAMED_ATTR
);
2468 nfsm_chain_add_bitmap(error
, &nmreq
, bitmap
, NFS_ATTR_BITMAP_LEN
);
2469 if (NMFLAG(nmp
, NAMEDATTR
)) {
2471 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_OPENATTR
);
2472 nfsm_chain_add_32(error
, &nmreq
, 0);
2474 nfsm_chain_build_done(error
, &nmreq
);
2475 nfsm_assert(error
, (numops
== 0), EPROTO
);
2477 error
= nfs_request_async(NULL
, nmp
->nm_mountp
, &nmreq
, NFSPROC4_COMPOUND
,
2478 vfs_context_thread(ctx
), vfs_context_ucred(ctx
), &si
, 0, NULL
, &req
);
2480 error
= nfs_request_async_finish(req
, &nmrep
, &xid
, &status
);
2481 nfsm_chain_skip_tag(error
, &nmrep
);
2482 nfsm_chain_get_32(error
, &nmrep
, numops
);
2483 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
2484 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
2486 NFS_CLEAR_ATTRIBUTES(nmp
->nm_fsattr
.nfsa_bitmap
);
2487 error
= nfs4_parsefattr(&nmrep
, &nmp
->nm_fsattr
, &nvattr
, NULL
, NULL
, NULL
);
2489 if (NMFLAG(nmp
, NAMEDATTR
)) {
2490 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_OPENATTR
);
2491 if (error
== ENOENT
)
2493 /* [sigh] some implementations return "illegal" error for unsupported ops */
2494 if (error
|| !NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_NAMED_ATTR
)) {
2495 nmp
->nm_fsattr
.nfsa_flags
&= ~NFS_FSFLAG_NAMED_ATTR
;
2497 nmp
->nm_fsattr
.nfsa_flags
|= NFS_FSFLAG_NAMED_ATTR
;
2500 nmp
->nm_fsattr
.nfsa_flags
&= ~NFS_FSFLAG_NAMED_ATTR
;
2502 if (NMFLAG(nmp
, NOACL
)) /* make sure ACL support is turned off */
2503 nmp
->nm_fsattr
.nfsa_flags
&= ~NFS_FSFLAG_ACL
;
2504 if (NMFLAG(nmp
, ACLONLY
) && !(nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_ACL
))
2505 NFS_BITMAP_CLR(nmp
->nm_flags
, NFS_MFLAG_ACLONLY
);
2506 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_FH_EXPIRE_TYPE
)) {
2507 uint32_t fhtype
= ((nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_FHTYPE_MASK
) >> NFS_FSFLAG_FHTYPE_SHIFT
);
2508 if (fhtype
!= NFS_FH_PERSISTENT
)
2509 printf("nfs: warning: non-persistent file handles! for %s\n", vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
);
2512 /* make sure it's a directory */
2513 if (!NFS_BITMAP_ISSET(&nvattr
.nva_bitmap
, NFS_FATTR_TYPE
) || (nvattr
.nva_type
!= VDIR
)) {
2518 /* save the NFS fsid */
2519 nmp
->nm_fsid
= nvattr
.nva_fsid
;
2521 /* create the root node */
2522 error
= nfs_nget(nmp
->nm_mountp
, NULL
, NULL
, dirfh
.fh_data
, dirfh
.fh_len
, &nvattr
, &xid
, rq
.r_auth
, NG_MARKROOT
, npp
);
2525 if (nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_ACL
)
2526 vfs_setextendedsecurity(nmp
->nm_mountp
);
2528 /* adjust I/O sizes to server limits */
2529 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXREAD
) && (nmp
->nm_fsattr
.nfsa_maxread
> 0)) {
2530 if (nmp
->nm_fsattr
.nfsa_maxread
< (uint64_t)nmp
->nm_rsize
) {
2531 nmp
->nm_rsize
= nmp
->nm_fsattr
.nfsa_maxread
& ~(NFS_FABLKSIZE
- 1);
2532 if (nmp
->nm_rsize
== 0)
2533 nmp
->nm_rsize
= nmp
->nm_fsattr
.nfsa_maxread
;
2536 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXWRITE
) && (nmp
->nm_fsattr
.nfsa_maxwrite
> 0)) {
2537 if (nmp
->nm_fsattr
.nfsa_maxwrite
< (uint64_t)nmp
->nm_wsize
) {
2538 nmp
->nm_wsize
= nmp
->nm_fsattr
.nfsa_maxwrite
& ~(NFS_FABLKSIZE
- 1);
2539 if (nmp
->nm_wsize
== 0)
2540 nmp
->nm_wsize
= nmp
->nm_fsattr
.nfsa_maxwrite
;
2544 /* set up lease renew timer */
2545 nmp
->nm_renew_timer
= thread_call_allocate(nfs4_renew_timer
, nmp
);
2546 interval
= nmp
->nm_fsattr
.nfsa_lease
/ 2;
2549 nfs_interval_timer_start(nmp
->nm_renew_timer
, interval
* 1000);
2552 if (fspath
.np_components
) {
2553 for (comp
=0; comp
< fspath
.np_compcount
; comp
++)
2554 if (fspath
.np_components
[comp
])
2555 FREE(fspath
.np_components
[comp
], M_TEMP
);
2556 FREE(fspath
.np_components
, M_TEMP
);
2558 NVATTR_CLEANUP(&nvattr
);
2559 nfs_fs_locations_cleanup(&nfsls
);
2561 nfs_node_unlock(*npp
);
2562 nfsm_chain_cleanup(&nmreq
);
2563 nfsm_chain_cleanup(&nmrep
);
2568 * Thread to handle initial NFS mount connection.
2571 nfs_mount_connect_thread(void *arg
, __unused wait_result_t wr
)
2573 struct nfsmount
*nmp
= arg
;
2574 int error
= 0, savederror
= 0, slpflag
= (NMFLAG(nmp
, INTR
) ? PCATCH
: 0);
2575 int done
= 0, timeo
, tries
, maxtries
;
2577 if (NM_OMFLAG(nmp
, MNTQUICK
)) {
2585 for (tries
= 0; tries
< maxtries
; tries
++) {
2586 error
= nfs_connect(nmp
, 1, timeo
);
2603 /* just keep retrying on any of these errors */
2607 /* looks like we got an answer... */
2612 /* save the best error */
2613 if (nfs_connect_error_class(error
) >= nfs_connect_error_class(savederror
))
2620 /* pause before next attempt */
2621 if ((error
= nfs_sigintr(nmp
, NULL
, current_thread(), 0)))
2623 error
= tsleep(nmp
, PSOCK
|slpflag
, "nfs_mount_connect_retry", 2*hz
);
2624 if (error
&& (error
!= EWOULDBLOCK
))
2629 /* update status of mount connect */
2630 lck_mtx_lock(&nmp
->nm_lock
);
2631 if (!nmp
->nm_mounterror
)
2632 nmp
->nm_mounterror
= error
;
2633 nmp
->nm_state
&= ~NFSSTA_MOUNT_THREAD
;
2634 lck_mtx_unlock(&nmp
->nm_lock
);
2635 wakeup(&nmp
->nm_nss
);
2639 nfs_mount_connect(struct nfsmount
*nmp
)
2641 int error
= 0, slpflag
;
2643 struct timespec ts
= { 2, 0 };
2646 * Set up the socket. Perform initial search for a location/server/address to
2647 * connect to and negotiate any unspecified mount parameters. This work is
2648 * done on a kernel thread to satisfy reserved port usage needs.
2650 slpflag
= NMFLAG(nmp
, INTR
) ? PCATCH
: 0;
2651 lck_mtx_lock(&nmp
->nm_lock
);
2652 /* set flag that the thread is running */
2653 nmp
->nm_state
|= NFSSTA_MOUNT_THREAD
;
2654 if (kernel_thread_start(nfs_mount_connect_thread
, nmp
, &thd
) != KERN_SUCCESS
) {
2655 nmp
->nm_state
&= ~NFSSTA_MOUNT_THREAD
;
2656 nmp
->nm_mounterror
= EIO
;
2657 printf("nfs mount %s start socket connect thread failed\n", vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
);
2659 thread_deallocate(thd
);
2662 /* wait until mount connect thread is finished/gone */
2663 while (nmp
->nm_state
& NFSSTA_MOUNT_THREAD
) {
2664 error
= msleep(&nmp
->nm_nss
, &nmp
->nm_lock
, slpflag
|PSOCK
, "nfsconnectthread", &ts
);
2665 if ((error
&& (error
!= EWOULDBLOCK
)) || ((error
= nfs_sigintr(nmp
, NULL
, current_thread(), 1)))) {
2667 if (!nmp
->nm_mounterror
)
2668 nmp
->nm_mounterror
= error
;
2669 /* signal the thread that we are aborting */
2670 nmp
->nm_sockflags
|= NMSOCK_UNMOUNT
;
2672 wakeup(nmp
->nm_nss
);
2673 /* and continue waiting on it to finish */
2677 lck_mtx_unlock(&nmp
->nm_lock
);
2679 /* grab mount connect status */
2680 error
= nmp
->nm_mounterror
;
2685 /* Table of maximum minor version for a given version */
2686 uint32_t maxminorverstab
[] = {
2687 0, /* Version 0 (does not exist) */
2688 0, /* Version 1 (does not exist) */
2694 #define NFS_MAX_SUPPORTED_VERSION ((long)(sizeof (maxminorverstab) / sizeof (uint32_t) - 1))
2695 #define NFS_MAX_SUPPORTED_MINOR_VERSION(v) ((long)(maxminorverstab[(v)]))
2697 #define DEFAULT_NFS_MIN_VERS VER2PVER(2, 0)
2698 #define DEFAULT_NFS_MAX_VERS VER2PVER(3, 0)
2701 * Common code to mount an NFS file system.
2710 struct nfsmount
*nmp
;
2713 struct vfsstatfs
*sbp
;
2715 uint32_t i
, val
, maxio
, iosize
, len
;
2717 uint32_t *mflags_mask
;
2719 uint32_t argslength
, attrslength
;
2720 struct nfs_location_index firstloc
= { NLI_VALID
, 0, 0, 0 };
2721 static const struct nfs_etype nfs_default_etypes
= {
2722 .count
= NFS_MAX_ETYPES
,
2723 .selected
= NFS_MAX_ETYPES
,
2724 .etypes
= { NFS_AES256_CTS_HMAC_SHA1_96
,
2725 NFS_AES128_CTS_HMAC_SHA1_96
,
2726 NFS_DES3_CBC_SHA1_KD
2729 /* make sure mbuf constants are set up */
2730 if (!nfs_mbuf_mhlen
)
2733 if (vfs_flags(mp
) & MNT_UPDATE
) {
2735 /* update paths, file handles, etc, here XXX */
2739 /* allocate an NFS mount structure for this mount */
2740 MALLOC_ZONE(nmp
, struct nfsmount
*,
2741 sizeof (struct nfsmount
), M_NFSMNT
, M_WAITOK
);
2746 bzero((caddr_t
)nmp
, sizeof (struct nfsmount
));
2747 lck_mtx_init(&nmp
->nm_lock
, nfs_mount_grp
, LCK_ATTR_NULL
);
2748 TAILQ_INIT(&nmp
->nm_resendq
);
2749 TAILQ_INIT(&nmp
->nm_iodq
);
2750 TAILQ_INIT(&nmp
->nm_gsscl
);
2751 LIST_INIT(&nmp
->nm_monlist
);
2752 vfs_setfsprivate(mp
, nmp
);
2754 nmp
->nm_mountp
= mp
;
2755 vfs_setauthopaque(mp
);
2757 * Disable cache_lookup_path for NFS. NFS lookup always needs
2758 * to be called to check if the directory attribute cache is
2759 * valid and possibly purge the directory before calling
2762 vfs_setauthcache_ttl(mp
, 0);
2764 nfs_nhinit_finish();
2766 nmp
->nm_args
= xdrbuf
;
2768 /* set up defaults */
2771 nmp
->nm_min_vers
= DEFAULT_NFS_MIN_VERS
;
2772 nmp
->nm_max_vers
= DEFAULT_NFS_MAX_VERS
;
2773 nmp
->nm_timeo
= NFS_TIMEO
;
2774 nmp
->nm_retry
= NFS_RETRANS
;
2776 nmp
->nm_sofamily
= 0;
2777 nmp
->nm_nfsport
= 0;
2778 nmp
->nm_wsize
= NFS_WSIZE
;
2779 nmp
->nm_rsize
= NFS_RSIZE
;
2780 nmp
->nm_readdirsize
= NFS_READDIRSIZE
;
2781 nmp
->nm_numgrps
= NFS_MAXGRPS
;
2782 nmp
->nm_readahead
= NFS_DEFRAHEAD
;
2783 nmp
->nm_tprintf_delay
= nfs_tprintf_delay
;
2784 if (nmp
->nm_tprintf_delay
< 0)
2785 nmp
->nm_tprintf_delay
= 0;
2786 nmp
->nm_tprintf_initial_delay
= nfs_tprintf_initial_delay
;
2787 if (nmp
->nm_tprintf_initial_delay
< 0)
2788 nmp
->nm_tprintf_initial_delay
= 0;
2789 nmp
->nm_acregmin
= NFS_MINATTRTIMO
;
2790 nmp
->nm_acregmax
= NFS_MAXATTRTIMO
;
2791 nmp
->nm_acdirmin
= NFS_MINDIRATTRTIMO
;
2792 nmp
->nm_acdirmax
= NFS_MAXDIRATTRTIMO
;
2793 nmp
->nm_etype
= nfs_default_etypes
;
2794 nmp
->nm_auth
= RPCAUTH_SYS
;
2795 nmp
->nm_iodlink
.tqe_next
= NFSNOLIST
;
2796 nmp
->nm_deadtimeout
= 0;
2797 nmp
->nm_curdeadtimeout
= 0;
2798 NFS_BITMAP_SET(nmp
->nm_flags
, NFS_MFLAG_NOACL
);
2799 nmp
->nm_realm
= NULL
;
2800 nmp
->nm_principal
= NULL
;
2801 nmp
->nm_sprinc
= NULL
;
2804 mattrs
= nmp
->nm_mattrs
;
2805 mflags
= nmp
->nm_mflags
;
2806 mflags_mask
= nmp
->nm_mflags_mask
;
2808 /* set up NFS mount with args */
2809 xb_init_buffer(&xb
, xdrbuf
, 2*XDRWORD
);
2810 xb_get_32(error
, &xb
, val
); /* version */
2811 xb_get_32(error
, &xb
, argslength
); /* args length */
2813 xb_init_buffer(&xb
, xdrbuf
, argslength
); /* restart parsing with actual buffer length */
2814 xb_get_32(error
, &xb
, val
); /* version */
2815 xb_get_32(error
, &xb
, argslength
); /* args length */
2816 xb_get_32(error
, &xb
, val
); /* XDR args version */
2817 if (val
!= NFS_XDRARGS_VERSION_0
|| argslength
< ((4 + NFS_MATTR_BITMAP_LEN
+ 1) * XDRWORD
)) {
2820 len
= NFS_MATTR_BITMAP_LEN
;
2821 xb_get_bitmap(error
, &xb
, mattrs
, len
); /* mount attribute bitmap */
2823 xb_get_32(error
, &xb
, attrslength
); /* attrs length */
2824 if (!error
&& (attrslength
> (argslength
- ((4+NFS_MATTR_BITMAP_LEN
+1)*XDRWORD
))))
2827 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_FLAGS
)) {
2828 len
= NFS_MFLAG_BITMAP_LEN
;
2829 xb_get_bitmap(error
, &xb
, mflags_mask
, len
); /* mount flag mask */
2830 len
= NFS_MFLAG_BITMAP_LEN
;
2831 xb_get_bitmap(error
, &xb
, mflags
, len
); /* mount flag values */
2833 /* clear all mask bits and OR in all the ones that are set */
2834 nmp
->nm_flags
[0] &= ~mflags_mask
[0];
2835 nmp
->nm_flags
[0] |= (mflags_mask
[0] & mflags
[0]);
2838 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_VERSION
)) {
2839 /* Can't specify a single version and a range */
2840 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_VERSION_RANGE
))
2842 xb_get_32(error
, &xb
, nmp
->nm_vers
);
2843 if (nmp
->nm_vers
> NFS_MAX_SUPPORTED_VERSION
||
2844 nmp
->nm_vers
< NFS_VER2
)
2846 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_MINOR_VERSION
))
2847 xb_get_32(error
, &xb
, nmp
->nm_minor_vers
);
2849 nmp
->nm_minor_vers
= maxminorverstab
[nmp
->nm_vers
];
2850 if (nmp
->nm_minor_vers
> maxminorverstab
[nmp
->nm_vers
])
2852 nmp
->nm_max_vers
= nmp
->nm_min_vers
=
2853 VER2PVER(nmp
->nm_vers
, nmp
->nm_minor_vers
);
2855 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_MINOR_VERSION
)) {
2856 /* should have also gotten NFS version (and already gotten minor version) */
2857 if (!NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_VERSION
))
2860 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_VERSION_RANGE
)) {
2861 xb_get_32(error
, &xb
, nmp
->nm_min_vers
);
2862 xb_get_32(error
, &xb
, nmp
->nm_max_vers
);
2863 if ((nmp
->nm_min_vers
> nmp
->nm_max_vers
) ||
2864 (PVER2MAJOR(nmp
->nm_max_vers
) > NFS_MAX_SUPPORTED_VERSION
) ||
2865 (PVER2MINOR(nmp
->nm_min_vers
) > maxminorverstab
[PVER2MAJOR(nmp
->nm_min_vers
)]) ||
2866 (PVER2MINOR(nmp
->nm_max_vers
) > maxminorverstab
[PVER2MAJOR(nmp
->nm_max_vers
)]))
2869 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READ_SIZE
))
2870 xb_get_32(error
, &xb
, nmp
->nm_rsize
);
2871 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_WRITE_SIZE
))
2872 xb_get_32(error
, &xb
, nmp
->nm_wsize
);
2873 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READDIR_SIZE
))
2874 xb_get_32(error
, &xb
, nmp
->nm_readdirsize
);
2875 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READAHEAD
))
2876 xb_get_32(error
, &xb
, nmp
->nm_readahead
);
2877 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MIN
)) {
2878 xb_get_32(error
, &xb
, nmp
->nm_acregmin
);
2879 xb_skip(error
, &xb
, XDRWORD
);
2881 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MAX
)) {
2882 xb_get_32(error
, &xb
, nmp
->nm_acregmax
);
2883 xb_skip(error
, &xb
, XDRWORD
);
2885 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MIN
)) {
2886 xb_get_32(error
, &xb
, nmp
->nm_acdirmin
);
2887 xb_skip(error
, &xb
, XDRWORD
);
2889 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MAX
)) {
2890 xb_get_32(error
, &xb
, nmp
->nm_acdirmax
);
2891 xb_skip(error
, &xb
, XDRWORD
);
2894 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_LOCK_MODE
)) {
2895 xb_get_32(error
, &xb
, val
);
2897 case NFS_LOCK_MODE_DISABLED
:
2898 case NFS_LOCK_MODE_LOCAL
:
2899 if (nmp
->nm_vers
>= NFS_VER4
) {
2900 /* disabled/local lock mode only allowed on v2/v3 */
2905 case NFS_LOCK_MODE_ENABLED
:
2906 nmp
->nm_lockmode
= val
;
2913 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SECURITY
)) {
2915 xb_get_32(error
, &xb
, seccnt
);
2916 if (!error
&& ((seccnt
< 1) || (seccnt
> NX_MAX_SEC_FLAVORS
)))
2919 nmp
->nm_sec
.count
= seccnt
;
2920 for (i
=0; i
< seccnt
; i
++) {
2921 xb_get_32(error
, &xb
, nmp
->nm_sec
.flavors
[i
]);
2922 /* Check for valid security flavor */
2923 switch (nmp
->nm_sec
.flavors
[i
]) {
2934 /* start with the first flavor */
2935 nmp
->nm_auth
= nmp
->nm_sec
.flavors
[0];
2937 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_KERB_ETYPE
)) {
2939 xb_get_32(error
, &xb
, etypecnt
);
2940 if (!error
&& ((etypecnt
< 1) || (etypecnt
> NFS_MAX_ETYPES
)))
2943 nmp
->nm_etype
.count
= etypecnt
;
2944 xb_get_32(error
, &xb
, nmp
->nm_etype
.selected
);
2947 nmp
->nm_etype
.selected
= etypecnt
; /* Nothing is selected yet, so set selected to count */
2948 for (i
=0; i
< etypecnt
; i
++) {
2949 xb_get_32(error
, &xb
, nmp
->nm_etype
.etypes
[i
]);
2950 /* Check for valid encryption type */
2951 switch (nmp
->nm_etype
.etypes
[i
]) {
2952 case NFS_DES3_CBC_SHA1_KD
:
2953 case NFS_AES128_CTS_HMAC_SHA1_96
:
2954 case NFS_AES256_CTS_HMAC_SHA1_96
:
2962 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MAX_GROUP_LIST
))
2963 xb_get_32(error
, &xb
, nmp
->nm_numgrps
);
2964 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SOCKET_TYPE
)) {
2967 xb_get_32(error
, &xb
, val
);
2968 if (!error
&& ((val
< 3) || (val
> 5)))
2971 error
= xb_get_bytes(&xb
, sotype
, val
, 0);
2974 if (!strcmp(sotype
, "tcp")) {
2975 nmp
->nm_sotype
= SOCK_STREAM
;
2976 } else if (!strcmp(sotype
, "udp")) {
2977 nmp
->nm_sotype
= SOCK_DGRAM
;
2978 } else if (!strcmp(sotype
, "tcp4")) {
2979 nmp
->nm_sotype
= SOCK_STREAM
;
2980 nmp
->nm_sofamily
= AF_INET
;
2981 } else if (!strcmp(sotype
, "udp4")) {
2982 nmp
->nm_sotype
= SOCK_DGRAM
;
2983 nmp
->nm_sofamily
= AF_INET
;
2984 } else if (!strcmp(sotype
, "tcp6")) {
2985 nmp
->nm_sotype
= SOCK_STREAM
;
2986 nmp
->nm_sofamily
= AF_INET6
;
2987 } else if (!strcmp(sotype
, "udp6")) {
2988 nmp
->nm_sotype
= SOCK_DGRAM
;
2989 nmp
->nm_sofamily
= AF_INET6
;
2990 } else if (!strcmp(sotype
, "inet4")) {
2991 nmp
->nm_sofamily
= AF_INET
;
2992 } else if (!strcmp(sotype
, "inet6")) {
2993 nmp
->nm_sofamily
= AF_INET6
;
2994 } else if (!strcmp(sotype
, "inet")) {
2995 nmp
->nm_sofamily
= 0; /* ok */
2999 if (!error
&& (nmp
->nm_vers
>= NFS_VER4
) && nmp
->nm_sotype
&&
3000 (nmp
->nm_sotype
!= SOCK_STREAM
))
3001 error
= EINVAL
; /* NFSv4 is only allowed over TCP. */
3004 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_PORT
))
3005 xb_get_32(error
, &xb
, nmp
->nm_nfsport
);
3006 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MOUNT_PORT
))
3007 xb_get_32(error
, &xb
, nmp
->nm_mountport
);
3008 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_REQUEST_TIMEOUT
)) {
3009 /* convert from time to 0.1s units */
3010 xb_get_32(error
, &xb
, nmp
->nm_timeo
);
3011 xb_get_32(error
, &xb
, val
);
3013 if (val
>= 1000000000)
3016 nmp
->nm_timeo
*= 10;
3017 nmp
->nm_timeo
+= (val
+100000000-1)/100000000;
3018 /* now convert to ticks */
3019 nmp
->nm_timeo
= (nmp
->nm_timeo
* NFS_HZ
+ 5) / 10;
3021 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SOFT_RETRY_COUNT
)) {
3022 xb_get_32(error
, &xb
, val
);
3023 if (!error
&& (val
> 1))
3024 nmp
->nm_retry
= val
;
3026 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_DEAD_TIMEOUT
)) {
3027 xb_get_32(error
, &xb
, nmp
->nm_deadtimeout
);
3028 xb_skip(error
, &xb
, XDRWORD
);
3030 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_FH
)) {
3032 MALLOC(nmp
->nm_fh
, fhandle_t
*, sizeof(fhandle_t
), M_TEMP
, M_WAITOK
|M_ZERO
);
3035 xb_get_32(error
, &xb
, nmp
->nm_fh
->fh_len
);
3037 if ((size_t)nmp
->nm_fh
->fh_len
> sizeof(nmp
->nm_fh
->fh_data
))
3040 error
= xb_get_bytes(&xb
, (char*)&nmp
->nm_fh
->fh_data
[0], nmp
->nm_fh
->fh_len
, 0);
3043 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_FS_LOCATIONS
)) {
3044 uint32_t loc
, serv
, addr
, comp
;
3045 struct nfs_fs_location
*fsl
;
3046 struct nfs_fs_server
*fss
;
3047 struct nfs_fs_path
*fsp
;
3049 xb_get_32(error
, &xb
, nmp
->nm_locations
.nl_numlocs
); /* fs location count */
3050 /* sanity check location count */
3051 if (!error
&& ((nmp
->nm_locations
.nl_numlocs
< 1) || (nmp
->nm_locations
.nl_numlocs
> 256)))
3054 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
);
3055 if (!nmp
->nm_locations
.nl_locations
)
3057 for (loc
= 0; loc
< nmp
->nm_locations
.nl_numlocs
; loc
++) {
3059 MALLOC(fsl
, struct nfs_fs_location
*, sizeof(struct nfs_fs_location
), M_TEMP
, M_WAITOK
|M_ZERO
);
3062 nmp
->nm_locations
.nl_locations
[loc
] = fsl
;
3063 xb_get_32(error
, &xb
, fsl
->nl_servcount
); /* server count */
3064 /* sanity check server count */
3065 if (!error
&& ((fsl
->nl_servcount
< 1) || (fsl
->nl_servcount
> 256)))
3068 MALLOC(fsl
->nl_servers
, struct nfs_fs_server
**, fsl
->nl_servcount
* sizeof(struct nfs_fs_server
*), M_TEMP
, M_WAITOK
|M_ZERO
);
3069 if (!fsl
->nl_servers
)
3071 for (serv
= 0; serv
< fsl
->nl_servcount
; serv
++) {
3073 MALLOC(fss
, struct nfs_fs_server
*, sizeof(struct nfs_fs_server
), M_TEMP
, M_WAITOK
|M_ZERO
);
3076 fsl
->nl_servers
[serv
] = fss
;
3077 xb_get_32(error
, &xb
, val
); /* server name length */
3078 /* sanity check server name length */
3079 if (!error
&& ((val
< 1) || (val
> MAXPATHLEN
)))
3082 MALLOC(fss
->ns_name
, char *, val
+1, M_TEMP
, M_WAITOK
|M_ZERO
);
3086 error
= xb_get_bytes(&xb
, fss
->ns_name
, val
, 0); /* server name */
3087 xb_get_32(error
, &xb
, fss
->ns_addrcount
); /* address count */
3088 /* sanity check address count (OK to be zero) */
3089 if (!error
&& (fss
->ns_addrcount
> 256))
3092 if (fss
->ns_addrcount
> 0) {
3093 MALLOC(fss
->ns_addresses
, char **, fss
->ns_addrcount
* sizeof(char *), M_TEMP
, M_WAITOK
|M_ZERO
);
3094 if (!fss
->ns_addresses
)
3096 for (addr
= 0; addr
< fss
->ns_addrcount
; addr
++) {
3097 xb_get_32(error
, &xb
, val
); /* address length */
3098 /* sanity check address length */
3099 if (!error
&& ((val
< 1) || (val
> 128)))
3102 MALLOC(fss
->ns_addresses
[addr
], char *, val
+1, M_TEMP
, M_WAITOK
|M_ZERO
);
3103 if (!fss
->ns_addresses
[addr
])
3106 error
= xb_get_bytes(&xb
, fss
->ns_addresses
[addr
], val
, 0); /* address */
3109 xb_get_32(error
, &xb
, val
); /* server info length */
3110 xb_skip(error
, &xb
, val
); /* skip server info */
3113 fsp
= &fsl
->nl_path
;
3114 xb_get_32(error
, &xb
, fsp
->np_compcount
); /* component count */
3115 /* sanity check component count */
3116 if (!error
&& (fsp
->np_compcount
> MAXPATHLEN
))
3119 if (fsp
->np_compcount
) {
3120 MALLOC(fsp
->np_components
, char **, fsp
->np_compcount
* sizeof(char*), M_TEMP
, M_WAITOK
|M_ZERO
);
3121 if (!fsp
->np_components
)
3124 for (comp
= 0; comp
< fsp
->np_compcount
; comp
++) {
3125 xb_get_32(error
, &xb
, val
); /* component length */
3126 /* sanity check component length */
3127 if (!error
&& (val
== 0)) {
3129 * Apparently some people think a path with zero components should
3130 * be encoded with one zero-length component. So, just ignore any
3131 * zero length components.
3134 fsp
->np_compcount
--;
3135 if (fsp
->np_compcount
== 0) {
3136 FREE(fsp
->np_components
, M_TEMP
);
3137 fsp
->np_components
= NULL
;
3141 if (!error
&& ((val
< 1) || (val
> MAXPATHLEN
)))
3144 MALLOC(fsp
->np_components
[comp
], char *, val
+1, M_TEMP
, M_WAITOK
|M_ZERO
);
3145 if (!fsp
->np_components
[comp
])
3148 error
= xb_get_bytes(&xb
, fsp
->np_components
[comp
], val
, 0); /* component */
3150 xb_get_32(error
, &xb
, val
); /* fs location info length */
3151 xb_skip(error
, &xb
, val
); /* skip fs location info */
3154 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MNTFLAGS
))
3155 xb_skip(error
, &xb
, XDRWORD
);
3156 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MNTFROM
)) {
3157 xb_get_32(error
, &xb
, len
);
3160 if (val
>= sizeof(vfs_statfs(mp
)->f_mntfromname
))
3161 val
= sizeof(vfs_statfs(mp
)->f_mntfromname
) - 1;
3162 error
= xb_get_bytes(&xb
, vfs_statfs(mp
)->f_mntfromname
, val
, 0);
3163 if ((len
- val
) > 0)
3164 xb_skip(error
, &xb
, len
- val
);
3166 vfs_statfs(mp
)->f_mntfromname
[val
] = '\0';
3170 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_REALM
)) {
3171 xb_get_32(error
, &xb
, len
);
3172 if (!error
&& ((len
< 1) || (len
> MAXPATHLEN
)))
3175 /* allocate an extra byte for a leading '@' if its not already prepended to the realm */
3176 MALLOC(nmp
->nm_realm
, char *, len
+2, M_TEMP
, M_WAITOK
|M_ZERO
);
3180 error
= xb_get_bytes(&xb
, nmp
->nm_realm
, len
, 0);
3181 if (error
== 0 && *nmp
->nm_realm
!= '@') {
3182 bcopy(nmp
->nm_realm
, &nmp
->nm_realm
[1], len
);
3183 nmp
->nm_realm
[0] = '@';
3188 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_PRINCIPAL
)) {
3189 xb_get_32(error
, &xb
, len
);
3190 if (!error
&& ((len
< 1) || (len
> MAXPATHLEN
)))
3193 MALLOC(nmp
->nm_principal
, char *, len
+1, M_TEMP
, M_WAITOK
|M_ZERO
);
3194 if (!nmp
->nm_principal
)
3197 error
= xb_get_bytes(&xb
, nmp
->nm_principal
, len
, 0);
3201 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SVCPRINCIPAL
)) {
3202 xb_get_32(error
, &xb
, len
);
3203 if (!error
&& ((len
< 1) || (len
> MAXPATHLEN
)))
3206 MALLOC(nmp
->nm_sprinc
, char *, len
+1, M_TEMP
, M_WAITOK
|M_ZERO
);
3207 if (!nmp
->nm_sprinc
)
3210 error
= xb_get_bytes(&xb
, nmp
->nm_sprinc
, len
, 0);
3215 * Sanity check/finalize settings.
3218 if (nmp
->nm_timeo
< NFS_MINTIMEO
)
3219 nmp
->nm_timeo
= NFS_MINTIMEO
;
3220 else if (nmp
->nm_timeo
> NFS_MAXTIMEO
)
3221 nmp
->nm_timeo
= NFS_MAXTIMEO
;
3222 if (nmp
->nm_retry
> NFS_MAXREXMIT
)
3223 nmp
->nm_retry
= NFS_MAXREXMIT
;
3225 if (nmp
->nm_numgrps
> NFS_MAXGRPS
)
3226 nmp
->nm_numgrps
= NFS_MAXGRPS
;
3227 if (nmp
->nm_readahead
> NFS_MAXRAHEAD
)
3228 nmp
->nm_readahead
= NFS_MAXRAHEAD
;
3229 if (nmp
->nm_acregmin
> nmp
->nm_acregmax
)
3230 nmp
->nm_acregmin
= nmp
->nm_acregmax
;
3231 if (nmp
->nm_acdirmin
> nmp
->nm_acdirmax
)
3232 nmp
->nm_acdirmin
= nmp
->nm_acdirmax
;
3234 /* need at least one fs location */
3235 if (nmp
->nm_locations
.nl_numlocs
< 1)
3239 /* init mount's mntfromname to first location */
3240 if (!NM_OMATTR_GIVEN(nmp
, MNTFROM
))
3241 nfs_location_mntfromname(&nmp
->nm_locations
, firstloc
,
3242 vfs_statfs(mp
)->f_mntfromname
, sizeof(vfs_statfs(mp
)->f_mntfromname
), 0);
3244 /* Need to save the mounting credential for v4. */
3245 nmp
->nm_mcred
= vfs_context_ucred(ctx
);
3246 if (IS_VALID_CRED(nmp
->nm_mcred
))
3247 kauth_cred_ref(nmp
->nm_mcred
);
3250 * If a reserved port is required, check for that privilege.
3251 * (Note that mirror mounts are exempt because the privilege was
3252 * already checked for the original mount.)
3254 if (NMFLAG(nmp
, RESVPORT
) && !vfs_iskernelmount(mp
))
3255 error
= priv_check_cred(nmp
->nm_mcred
, PRIV_NETINET_RESERVEDPORT
, 0);
3258 /* do mount's initial socket connection */
3259 error
= nfs_mount_connect(nmp
);
3262 /* set up the version-specific function tables */
3263 if (nmp
->nm_vers
< NFS_VER4
)
3264 nmp
->nm_funcs
= &nfs3_funcs
;
3266 nmp
->nm_funcs
= &nfs4_funcs
;
3268 /* sanity check settings now that version/connection is set */
3269 if (nmp
->nm_vers
== NFS_VER2
) /* ignore RDIRPLUS on NFSv2 */
3270 NFS_BITMAP_CLR(nmp
->nm_flags
, NFS_MFLAG_RDIRPLUS
);
3271 if (nmp
->nm_vers
>= NFS_VER4
) {
3272 if (NFS_BITMAP_ISSET(nmp
->nm_flags
, NFS_MFLAG_ACLONLY
)) /* aclonly trumps noacl */
3273 NFS_BITMAP_CLR(nmp
->nm_flags
, NFS_MFLAG_NOACL
);
3274 NFS_BITMAP_CLR(nmp
->nm_flags
, NFS_MFLAG_CALLUMNT
);
3275 if (nmp
->nm_lockmode
!= NFS_LOCK_MODE_ENABLED
)
3276 error
= EINVAL
; /* disabled/local lock mode only allowed on v2/v3 */
3278 /* ignore these if not v4 */
3279 NFS_BITMAP_CLR(nmp
->nm_flags
, NFS_MFLAG_NOCALLBACK
);
3280 NFS_BITMAP_CLR(nmp
->nm_flags
, NFS_MFLAG_NAMEDATTR
);
3281 NFS_BITMAP_CLR(nmp
->nm_flags
, NFS_MFLAG_NOACL
);
3282 NFS_BITMAP_CLR(nmp
->nm_flags
, NFS_MFLAG_ACLONLY
);
3286 if (nmp
->nm_sotype
== SOCK_DGRAM
) {
3287 /* I/O size defaults for UDP are different */
3288 if (!NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READ_SIZE
))
3289 nmp
->nm_rsize
= NFS_DGRAM_RSIZE
;
3290 if (!NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_WRITE_SIZE
))
3291 nmp
->nm_wsize
= NFS_DGRAM_WSIZE
;
3294 /* round down I/O sizes to multiple of NFS_FABLKSIZE */
3295 nmp
->nm_rsize
&= ~(NFS_FABLKSIZE
- 1);
3296 if (nmp
->nm_rsize
<= 0)
3297 nmp
->nm_rsize
= NFS_FABLKSIZE
;
3298 nmp
->nm_wsize
&= ~(NFS_FABLKSIZE
- 1);
3299 if (nmp
->nm_wsize
<= 0)
3300 nmp
->nm_wsize
= NFS_FABLKSIZE
;
3302 /* and limit I/O sizes to maximum allowed */
3303 maxio
= (nmp
->nm_vers
== NFS_VER2
) ? NFS_V2MAXDATA
:
3304 (nmp
->nm_sotype
== SOCK_DGRAM
) ? NFS_MAXDGRAMDATA
: NFS_MAXDATA
;
3305 if (maxio
> NFS_MAXBSIZE
)
3306 maxio
= NFS_MAXBSIZE
;
3307 if (nmp
->nm_rsize
> maxio
)
3308 nmp
->nm_rsize
= maxio
;
3309 if (nmp
->nm_wsize
> maxio
)
3310 nmp
->nm_wsize
= maxio
;
3312 if (nmp
->nm_readdirsize
> maxio
)
3313 nmp
->nm_readdirsize
= maxio
;
3314 if (nmp
->nm_readdirsize
> nmp
->nm_rsize
)
3315 nmp
->nm_readdirsize
= nmp
->nm_rsize
;
3317 /* Set up the sockets and related info */
3318 if (nmp
->nm_sotype
== SOCK_DGRAM
)
3319 TAILQ_INIT(&nmp
->nm_cwndq
);
3322 * Get the root node/attributes from the NFS server and
3323 * do any basic, version-specific setup.
3325 error
= nmp
->nm_funcs
->nf_mount(nmp
, ctx
, &np
);
3329 * A reference count is needed on the node representing the
3330 * remote root. If this object is not persistent, then backward
3331 * traversals of the mount point (i.e. "..") will not work if
3332 * the node gets flushed out of the cache.
3336 /* get usecount and drop iocount */
3337 error
= vnode_ref(*vpp
);
3340 vnode_recycle(*vpp
);
3345 * Do statfs to ensure static info gets set to reasonable values.
3347 if ((error
= nmp
->nm_funcs
->nf_update_statfs(nmp
, ctx
))) {
3348 int error2
= vnode_getwithref(*vpp
);
3352 vnode_recycle(*vpp
);
3355 sbp
= vfs_statfs(mp
);
3356 sbp
->f_bsize
= nmp
->nm_fsattr
.nfsa_bsize
;
3357 sbp
->f_blocks
= nmp
->nm_fsattr
.nfsa_space_total
/ sbp
->f_bsize
;
3358 sbp
->f_bfree
= nmp
->nm_fsattr
.nfsa_space_free
/ sbp
->f_bsize
;
3359 sbp
->f_bavail
= nmp
->nm_fsattr
.nfsa_space_avail
/ sbp
->f_bsize
;
3360 sbp
->f_bused
= (nmp
->nm_fsattr
.nfsa_space_total
/ sbp
->f_bsize
) -
3361 (nmp
->nm_fsattr
.nfsa_space_free
/ sbp
->f_bsize
);
3362 sbp
->f_files
= nmp
->nm_fsattr
.nfsa_files_total
;
3363 sbp
->f_ffree
= nmp
->nm_fsattr
.nfsa_files_free
;
3364 sbp
->f_iosize
= nfs_iosize
;
3367 * Calculate the size used for I/O buffers. Use the larger
3368 * of the two sizes to minimise NFS requests but make sure
3369 * that it is at least one VM page to avoid wasting buffer
3370 * space and to allow easy mmapping of I/O buffers.
3371 * The read/write RPC calls handle the splitting up of
3372 * buffers into multiple requests if the buffer size is
3373 * larger than the I/O size.
3375 #ifndef CONFIG_EMBEDDED
3376 iosize
= max(nmp
->nm_rsize
, nmp
->nm_wsize
);
3377 if (iosize
< PAGE_SIZE
)
3382 nmp
->nm_biosize
= trunc_page_32(iosize
);
3384 /* For NFSv3 and greater, there is a (relatively) reliable ACCESS call. */
3385 if (nmp
->nm_vers
> NFS_VER2
)
3386 vfs_setauthopaqueaccess(mp
);
3388 switch (nmp
->nm_lockmode
) {
3389 case NFS_LOCK_MODE_DISABLED
:
3391 case NFS_LOCK_MODE_LOCAL
:
3392 vfs_setlocklocal(nmp
->nm_mountp
);
3394 case NFS_LOCK_MODE_ENABLED
:
3396 if (nmp
->nm_vers
<= NFS_VER3
)
3397 nfs_lockd_mount_register(nmp
);
3402 lck_mtx_lock(&nmp
->nm_lock
);
3403 nmp
->nm_state
|= NFSSTA_MOUNTED
;
3404 lck_mtx_unlock(&nmp
->nm_lock
);
3407 nfs_mount_drain_and_cleanup(nmp
);
3414 * We've detected a file system boundary on the server and
3415 * need to mount a new file system so that our file systems
3416 * MIRROR the file systems on the server.
3418 * Build the mount arguments for the new mount and call kernel_mount().
3421 nfs_mirror_mount_domount(vnode_t dvp
, vnode_t vp
, vfs_context_t ctx
)
3423 nfsnode_t np
= VTONFS(vp
);
3424 nfsnode_t dnp
= VTONFS(dvp
);
3425 struct nfsmount
*nmp
= NFSTONMP(np
);
3426 char fstype
[MFSTYPENAMELEN
], *mntfromname
= NULL
, *path
= NULL
, *relpath
, *p
, *cp
;
3427 int error
= 0, pathbuflen
= MAXPATHLEN
, i
, mntflags
= 0, referral
, skipcopy
= 0;
3429 struct xdrbuf xb
, xbnew
;
3430 uint32_t mattrs
[NFS_MATTR_BITMAP_LEN
];
3431 uint32_t newmattrs
[NFS_MATTR_BITMAP_LEN
];
3432 uint32_t newmflags
[NFS_MFLAG_BITMAP_LEN
];
3433 uint32_t newmflags_mask
[NFS_MFLAG_BITMAP_LEN
];
3434 uint32_t argslength
= 0, val
, count
, mlen
, mlen2
, rlen
, relpathcomps
;
3435 uint32_t argslength_offset
, attrslength_offset
, end_offset
;
3436 uint32_t numlocs
, loc
, numserv
, serv
, numaddr
, addr
, numcomp
, comp
;
3438 struct nfs_fs_locations nfsls
;
3440 referral
= (np
->n_vattr
.nva_flags
& NFS_FFLAG_TRIGGER_REFERRAL
);
3442 bzero(&nfsls
, sizeof(nfsls
));
3446 if (!nmp
|| (nmp
->nm_state
& (NFSSTA_FORCE
|NFSSTA_DEAD
)))
3449 /* allocate a couple path buffers we need */
3450 MALLOC_ZONE(mntfromname
, char *, pathbuflen
, M_NAMEI
, M_WAITOK
);
3455 MALLOC_ZONE(path
, char *, pathbuflen
, M_NAMEI
, M_WAITOK
);
3461 /* get the path for the directory being mounted on */
3462 error
= vn_getpath(vp
, path
, &pathbuflen
);
3469 * Set up the mntfromname for the new mount based on the
3470 * current mount's mntfromname and the directory's path
3471 * relative to the current mount's mntonname.
3472 * Set up relpath to point at the relative path on the current mount.
3473 * Also, count the number of components in relpath.
3474 * We'll be adding those to each fs location path in the new args.
3476 nlen
= strlcpy(mntfromname
, vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
, MAXPATHLEN
);
3477 if ((nlen
> 0) && (mntfromname
[nlen
-1] == '/')) { /* avoid double '/' in new name */
3478 mntfromname
[nlen
-1] = '\0';
3481 relpath
= mntfromname
+ nlen
;
3482 nlen
= strlcat(mntfromname
, path
+ strlen(vfs_statfs(nmp
->nm_mountp
)->f_mntonname
), MAXPATHLEN
);
3483 if (nlen
>= MAXPATHLEN
) {
3484 error
= ENAMETOOLONG
;
3487 /* count the number of components in relpath */
3489 while (*p
&& (*p
== '/'))
3494 while (*p
&& (*p
!= '/'))
3496 while (*p
&& (*p
== '/'))
3500 /* grab a copy of the file system type */
3501 vfs_name(vnode_mount(vp
), fstype
);
3503 /* for referrals, fetch the fs locations */
3505 const char *vname
= vnode_getname(NFSTOV(np
));
3509 error
= nfs4_get_fs_locations(nmp
, dnp
, NULL
, 0, vname
, ctx
, &nfsls
);
3510 vnode_putname(vname
);
3511 if (!error
&& (nfsls
.nl_numlocs
< 1))
3517 /* set up NFS mount args based on current mount args */
3519 #define xb_copy_32(E, XBSRC, XBDST, V) \
3522 xb_get_32((E), (XBSRC), (V)); \
3523 if (skipcopy) break; \
3524 xb_add_32((E), (XBDST), (V)); \
3526 #define xb_copy_opaque(E, XBSRC, XBDST) \
3528 uint32_t __count, __val; \
3529 xb_copy_32((E), (XBSRC), (XBDST), __count); \
3531 __count = nfsm_rndup(__count); \
3532 __count /= XDRWORD; \
3533 while (__count-- > 0) \
3534 xb_copy_32((E), (XBSRC), (XBDST), __val); \
3537 xb_init_buffer(&xb
, nmp
->nm_args
, 2*XDRWORD
);
3538 xb_get_32(error
, &xb
, val
); /* version */
3539 xb_get_32(error
, &xb
, argslength
); /* args length */
3540 xb_init_buffer(&xb
, nmp
->nm_args
, argslength
);
3542 xb_init_buffer(&xbnew
, NULL
, 0);
3543 xb_copy_32(error
, &xb
, &xbnew
, val
); /* version */
3544 argslength_offset
= xb_offset(&xbnew
);
3545 xb_copy_32(error
, &xb
, &xbnew
, val
); /* args length */
3546 xb_copy_32(error
, &xb
, &xbnew
, val
); /* XDR args version */
3547 count
= NFS_MATTR_BITMAP_LEN
;
3548 xb_get_bitmap(error
, &xb
, mattrs
, count
); /* mount attribute bitmap */
3550 for (i
= 0; i
< NFS_MATTR_BITMAP_LEN
; i
++)
3551 newmattrs
[i
] = mattrs
[i
];
3553 NFS_BITMAP_SET(newmattrs
, NFS_MATTR_FS_LOCATIONS
);
3555 NFS_BITMAP_SET(newmattrs
, NFS_MATTR_FH
);
3556 NFS_BITMAP_SET(newmattrs
, NFS_MATTR_FLAGS
);
3557 NFS_BITMAP_SET(newmattrs
, NFS_MATTR_MNTFLAGS
);
3558 NFS_BITMAP_CLR(newmattrs
, NFS_MATTR_MNTFROM
);
3559 xb_add_bitmap(error
, &xbnew
, newmattrs
, NFS_MATTR_BITMAP_LEN
);
3560 attrslength_offset
= xb_offset(&xbnew
);
3561 xb_copy_32(error
, &xb
, &xbnew
, val
); /* attrs length */
3562 NFS_BITMAP_ZERO(newmflags_mask
, NFS_MFLAG_BITMAP_LEN
);
3563 NFS_BITMAP_ZERO(newmflags
, NFS_MFLAG_BITMAP_LEN
);
3564 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_FLAGS
)) {
3565 count
= NFS_MFLAG_BITMAP_LEN
;
3566 xb_get_bitmap(error
, &xb
, newmflags_mask
, count
); /* mount flag mask bitmap */
3567 count
= NFS_MFLAG_BITMAP_LEN
;
3568 xb_get_bitmap(error
, &xb
, newmflags
, count
); /* mount flag bitmap */
3570 NFS_BITMAP_SET(newmflags_mask
, NFS_MFLAG_EPHEMERAL
);
3571 NFS_BITMAP_SET(newmflags
, NFS_MFLAG_EPHEMERAL
);
3572 xb_add_bitmap(error
, &xbnew
, newmflags_mask
, NFS_MFLAG_BITMAP_LEN
);
3573 xb_add_bitmap(error
, &xbnew
, newmflags
, NFS_MFLAG_BITMAP_LEN
);
3574 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_VERSION
))
3575 xb_copy_32(error
, &xb
, &xbnew
, val
);
3576 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_MINOR_VERSION
))
3577 xb_copy_32(error
, &xb
, &xbnew
, val
);
3578 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_VERSION_RANGE
)) {
3579 xb_copy_32(error
, &xb
, &xbnew
, val
);
3580 xb_copy_32(error
, &xb
, &xbnew
, val
);
3582 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READ_SIZE
))
3583 xb_copy_32(error
, &xb
, &xbnew
, val
);
3584 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_WRITE_SIZE
))
3585 xb_copy_32(error
, &xb
, &xbnew
, val
);
3586 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READDIR_SIZE
))
3587 xb_copy_32(error
, &xb
, &xbnew
, val
);
3588 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READAHEAD
))
3589 xb_copy_32(error
, &xb
, &xbnew
, val
);
3590 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MIN
)) {
3591 xb_copy_32(error
, &xb
, &xbnew
, val
);
3592 xb_copy_32(error
, &xb
, &xbnew
, val
);
3594 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MAX
)) {
3595 xb_copy_32(error
, &xb
, &xbnew
, val
);
3596 xb_copy_32(error
, &xb
, &xbnew
, val
);
3598 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MIN
)) {
3599 xb_copy_32(error
, &xb
, &xbnew
, val
);
3600 xb_copy_32(error
, &xb
, &xbnew
, val
);
3602 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MAX
)) {
3603 xb_copy_32(error
, &xb
, &xbnew
, val
);
3604 xb_copy_32(error
, &xb
, &xbnew
, val
);
3606 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_LOCK_MODE
))
3607 xb_copy_32(error
, &xb
, &xbnew
, val
);
3608 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SECURITY
)) {
3609 xb_copy_32(error
, &xb
, &xbnew
, count
);
3610 while (!error
&& (count
-- > 0))
3611 xb_copy_32(error
, &xb
, &xbnew
, val
);
3613 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_KERB_ETYPE
)) {
3614 xb_copy_32(error
, &xb
, &xbnew
, count
);
3615 xb_add_32(error
, &xbnew
, -1);
3616 while (!error
&& (count
-- > 0))
3617 xb_copy_32(error
, &xb
, &xbnew
, val
);
3619 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MAX_GROUP_LIST
))
3620 xb_copy_32(error
, &xb
, &xbnew
, val
);
3621 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SOCKET_TYPE
))
3622 xb_copy_opaque(error
, &xb
, &xbnew
);
3623 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_PORT
))
3624 xb_copy_32(error
, &xb
, &xbnew
, val
);
3625 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MOUNT_PORT
))
3626 xb_copy_32(error
, &xb
, &xbnew
, val
);
3627 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_REQUEST_TIMEOUT
)) {
3628 xb_copy_32(error
, &xb
, &xbnew
, val
);
3629 xb_copy_32(error
, &xb
, &xbnew
, val
);
3631 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SOFT_RETRY_COUNT
))
3632 xb_copy_32(error
, &xb
, &xbnew
, val
);
3633 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_DEAD_TIMEOUT
)) {
3634 xb_copy_32(error
, &xb
, &xbnew
, val
);
3635 xb_copy_32(error
, &xb
, &xbnew
, val
);
3637 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_FH
)) {
3638 xb_get_32(error
, &xb
, count
);
3639 xb_skip(error
, &xb
, count
);
3642 /* set the initial file handle to the directory's file handle */
3643 xb_add_fh(error
, &xbnew
, np
->n_fhp
, np
->n_fhsize
);
3645 /* copy/extend/skip fs locations */
3646 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_FS_LOCATIONS
)) {
3647 numlocs
= numserv
= numaddr
= numcomp
= 0;
3648 if (referral
) /* don't copy the fs locations for a referral */
3650 xb_copy_32(error
, &xb
, &xbnew
, numlocs
); /* location count */
3651 for (loc
= 0; !error
&& (loc
< numlocs
); loc
++) {
3652 xb_copy_32(error
, &xb
, &xbnew
, numserv
); /* server count */
3653 for (serv
= 0; !error
&& (serv
< numserv
); serv
++) {
3654 xb_copy_opaque(error
, &xb
, &xbnew
); /* server name */
3655 xb_copy_32(error
, &xb
, &xbnew
, numaddr
); /* address count */
3656 for (addr
= 0; !error
&& (addr
< numaddr
); addr
++)
3657 xb_copy_opaque(error
, &xb
, &xbnew
); /* address */
3658 xb_copy_opaque(error
, &xb
, &xbnew
); /* server info */
3661 xb_get_32(error
, &xb
, numcomp
); /* component count */
3663 xb_add_32(error
, &xbnew
, numcomp
+relpathcomps
); /* new component count */
3664 for (comp
= 0; !error
&& (comp
< numcomp
); comp
++)
3665 xb_copy_opaque(error
, &xb
, &xbnew
); /* component */
3666 /* add additional components */
3667 for (comp
= 0; !skipcopy
&& !error
&& (comp
< relpathcomps
); comp
++) {
3669 while (*p
&& (*p
== '/'))
3671 while (*p
&& !error
) {
3673 while (*p
&& (*p
!= '/'))
3675 xb_add_string(error
, &xbnew
, cp
, (p
- cp
)); /* component */
3676 while (*p
&& (*p
== '/'))
3680 xb_copy_opaque(error
, &xb
, &xbnew
); /* fs location info */
3686 /* add referral's fs locations */
3687 xb_add_32(error
, &xbnew
, nfsls
.nl_numlocs
); /* FS_LOCATIONS */
3688 for (loc
= 0; !error
&& (loc
< nfsls
.nl_numlocs
); loc
++) {
3689 xb_add_32(error
, &xbnew
, nfsls
.nl_locations
[loc
]->nl_servcount
);
3690 for (serv
= 0; !error
&& (serv
< nfsls
.nl_locations
[loc
]->nl_servcount
); serv
++) {
3691 xb_add_string(error
, &xbnew
, nfsls
.nl_locations
[loc
]->nl_servers
[serv
]->ns_name
,
3692 strlen(nfsls
.nl_locations
[loc
]->nl_servers
[serv
]->ns_name
));
3693 xb_add_32(error
, &xbnew
, nfsls
.nl_locations
[loc
]->nl_servers
[serv
]->ns_addrcount
);
3694 for (addr
= 0; !error
&& (addr
< nfsls
.nl_locations
[loc
]->nl_servers
[serv
]->ns_addrcount
); addr
++)
3695 xb_add_string(error
, &xbnew
, nfsls
.nl_locations
[loc
]->nl_servers
[serv
]->ns_addresses
[addr
],
3696 strlen(nfsls
.nl_locations
[loc
]->nl_servers
[serv
]->ns_addresses
[addr
]));
3697 xb_add_32(error
, &xbnew
, 0); /* empty server info */
3699 xb_add_32(error
, &xbnew
, nfsls
.nl_locations
[loc
]->nl_path
.np_compcount
);
3700 for (comp
= 0; !error
&& (comp
< nfsls
.nl_locations
[loc
]->nl_path
.np_compcount
); comp
++)
3701 xb_add_string(error
, &xbnew
, nfsls
.nl_locations
[loc
]->nl_path
.np_components
[comp
],
3702 strlen(nfsls
.nl_locations
[loc
]->nl_path
.np_components
[comp
]));
3703 xb_add_32(error
, &xbnew
, 0); /* empty fs location info */
3706 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MNTFLAGS
))
3707 xb_get_32(error
, &xb
, mntflags
);
3709 * We add the following mount flags to the ones for the mounted-on mount:
3710 * MNT_DONTBROWSE - to keep the mount from showing up as a separate volume
3711 * MNT_AUTOMOUNTED - to keep DiskArb from retriggering the mount after
3712 * an unmount (looking for /.autodiskmounted)
3714 mntflags
|= (MNT_AUTOMOUNTED
| MNT_DONTBROWSE
);
3715 xb_add_32(error
, &xbnew
, mntflags
);
3716 if (!referral
&& NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MNTFROM
)) {
3717 /* copy mntfrom string and add relpath */
3718 rlen
= strlen(relpath
);
3719 xb_get_32(error
, &xb
, mlen
);
3721 mlen2
= mlen
+ ((relpath
[0] != '/') ? 1 : 0) + rlen
;
3722 xb_add_32(error
, &xbnew
, mlen2
);
3723 count
= mlen
/XDRWORD
;
3724 /* copy the original string */
3726 xb_copy_32(error
, &xb
, &xbnew
, val
);
3727 if (!error
&& (mlen
% XDRWORD
)) {
3728 error
= xb_get_bytes(&xb
, buf
, mlen%XDRWORD
, 0);
3730 error
= xb_add_bytes(&xbnew
, buf
, mlen%XDRWORD
, 1);
3732 /* insert a '/' if the relative path doesn't start with one */
3733 if (!error
&& (relpath
[0] != '/')) {
3735 error
= xb_add_bytes(&xbnew
, buf
, 1, 1);
3737 /* add the additional relative path */
3739 error
= xb_add_bytes(&xbnew
, relpath
, rlen
, 1);
3740 /* make sure the resulting string has the right number of pad bytes */
3741 if (!error
&& (mlen2
!= nfsm_rndup(mlen2
))) {
3742 bzero(buf
, sizeof(buf
));
3743 count
= nfsm_rndup(mlen2
) - mlen2
;
3744 error
= xb_add_bytes(&xbnew
, buf
, count
, 1);
3747 xb_build_done(error
, &xbnew
);
3749 /* update opaque counts */
3750 end_offset
= xb_offset(&xbnew
);
3752 error
= xb_seek(&xbnew
, argslength_offset
);
3753 argslength
= end_offset
- argslength_offset
+ XDRWORD
/*version*/;
3754 xb_add_32(error
, &xbnew
, argslength
);
3757 error
= xb_seek(&xbnew
, attrslength_offset
);
3758 xb_add_32(error
, &xbnew
, end_offset
- attrslength_offset
- XDRWORD
/*don't include length field*/);
3763 * For kernel_mount() call, use the existing mount flags (instead of the
3764 * original flags) because flags like MNT_NOSUID and MNT_NODEV may have
3765 * been silently enforced.
3767 mntflags
= vnode_vfsvisflags(vp
);
3768 mntflags
|= (MNT_AUTOMOUNTED
| MNT_DONTBROWSE
);
3771 error
= kernel_mount(fstype
, dvp
, vp
, path
, xb_buffer_base(&xbnew
), argslength
,
3772 mntflags
, KERNEL_MOUNT_PERMIT_UNMOUNT
| KERNEL_MOUNT_NOAUTH
, ctx
);
3776 printf("nfs: mirror mount of %s on %s failed (%d)\n",
3777 mntfromname
, path
, error
);
3781 nfs_fs_locations_cleanup(&nfsls
);
3783 FREE_ZONE(path
, MAXPATHLEN
, M_NAMEI
);
3785 FREE_ZONE(mntfromname
, MAXPATHLEN
, M_NAMEI
);
3787 nfs_ephemeral_mount_harvester_start();
3792 * trigger vnode functions
3796 nfs_mirror_mount_trigger_resolve(
3798 const struct componentname
*cnp
,
3799 enum path_operation pop
,
3801 __unused
void *data
,
3804 nfsnode_t np
= VTONFS(vp
);
3805 vnode_t pvp
= NULLVP
;
3807 resolver_result_t result
;
3810 * We have a trigger node that doesn't have anything mounted on it yet.
3811 * We'll do the mount if either:
3812 * (a) this isn't the last component of the path OR
3813 * (b) this is an op that looks like it should trigger the mount.
3815 if (cnp
->cn_flags
& ISLASTCN
) {
3833 /* don't perform the mount for these operations */
3834 result
= vfs_resolver_result(np
->n_trigseq
, RESOLVER_NOCHANGE
, 0);
3835 #ifdef NFS_TRIGGER_DEBUG
3836 NP(np
, "nfs trigger RESOLVE: no change, last %d nameiop %d, seq %d",
3837 (cnp
->cn_flags
& ISLASTCN
) ? 1 : 0, cnp
->cn_nameiop
, np
->n_trigseq
);
3848 case OP_EXCHANGEDATA
:
3852 case OP_REMOVEXATTR
:
3854 /* go ahead and do the mount */
3859 if (vnode_mountedhere(vp
) != NULL
) {
3861 * Um... there's already something mounted.
3862 * Been there. Done that. Let's just say it succeeded.
3868 if ((error
= nfs_node_set_busy(np
, vfs_context_thread(ctx
)))) {
3869 result
= vfs_resolver_result(np
->n_trigseq
, RESOLVER_ERROR
, error
);
3870 #ifdef NFS_TRIGGER_DEBUG
3871 NP(np
, "nfs trigger RESOLVE: busy error %d, last %d nameiop %d, seq %d",
3872 error
, (cnp
->cn_flags
& ISLASTCN
) ? 1 : 0, cnp
->cn_nameiop
, np
->n_trigseq
);
3877 pvp
= vnode_getparent(vp
);
3881 error
= nfs_mirror_mount_domount(pvp
, vp
, ctx
);
3885 result
= vfs_resolver_result(np
->n_trigseq
, error
? RESOLVER_ERROR
: RESOLVER_RESOLVED
, error
);
3886 #ifdef NFS_TRIGGER_DEBUG
3887 NP(np
, "nfs trigger RESOLVE: %s %d, last %d nameiop %d, seq %d",
3888 error
? "error" : "resolved", error
,
3889 (cnp
->cn_flags
& ISLASTCN
) ? 1 : 0, cnp
->cn_nameiop
, np
->n_trigseq
);
3894 nfs_node_clear_busy(np
);
3899 nfs_mirror_mount_trigger_unresolve(
3902 __unused
void *data
,
3905 nfsnode_t np
= VTONFS(vp
);
3908 resolver_result_t result
;
3910 if ((error
= nfs_node_set_busy(np
, vfs_context_thread(ctx
)))) {
3911 result
= vfs_resolver_result(np
->n_trigseq
, RESOLVER_ERROR
, error
);
3912 #ifdef NFS_TRIGGER_DEBUG
3913 NP(np
, "nfs trigger UNRESOLVE: busy error %d, seq %d", error
, np
->n_trigseq
);
3918 mp
= vnode_mountedhere(vp
);
3922 error
= vfs_unmountbyfsid(&(vfs_statfs(mp
)->f_fsid
), flags
, ctx
);
3925 result
= vfs_resolver_result(np
->n_trigseq
, error
? RESOLVER_ERROR
: RESOLVER_UNRESOLVED
, error
);
3926 #ifdef NFS_TRIGGER_DEBUG
3927 NP(np
, "nfs trigger UNRESOLVE: %s %d, seq %d",
3928 error
? "error" : "unresolved", error
, np
->n_trigseq
);
3930 nfs_node_clear_busy(np
);
3935 nfs_mirror_mount_trigger_rearm(
3938 __unused
void *data
,
3941 nfsnode_t np
= VTONFS(vp
);
3943 resolver_result_t result
;
3945 if ((error
= nfs_node_set_busy(np
, vfs_context_thread(ctx
)))) {
3946 result
= vfs_resolver_result(np
->n_trigseq
, RESOLVER_ERROR
, error
);
3947 #ifdef NFS_TRIGGER_DEBUG
3948 NP(np
, "nfs trigger REARM: busy error %d, seq %d", error
, np
->n_trigseq
);
3954 result
= vfs_resolver_result(np
->n_trigseq
,
3955 vnode_mountedhere(vp
) ? RESOLVER_RESOLVED
: RESOLVER_UNRESOLVED
, 0);
3956 #ifdef NFS_TRIGGER_DEBUG
3957 NP(np
, "nfs trigger REARM: %s, seq %d",
3958 vnode_mountedhere(vp
) ? "resolved" : "unresolved", np
->n_trigseq
);
3960 nfs_node_clear_busy(np
);
3965 * Periodically attempt to unmount ephemeral (mirror) mounts in an attempt to limit
3966 * the number of unused mounts.
3969 #define NFS_EPHEMERAL_MOUNT_HARVEST_INTERVAL 120 /* how often the harvester runs */
3970 struct nfs_ephemeral_mount_harvester_info
{
3971 fsid_t fsid
; /* FSID that we need to try to unmount */
3972 uint32_t mountcount
; /* count of ephemeral mounts seen in scan */
3974 /* various globals for the harvester */
3975 static thread_call_t nfs_ephemeral_mount_harvester_timer
= NULL
;
3976 static int nfs_ephemeral_mount_harvester_on
= 0;
3978 kern_return_t
thread_terminate(thread_t
);
3981 nfs_ephemeral_mount_harvester_callback(mount_t mp
, void *arg
)
3983 struct nfs_ephemeral_mount_harvester_info
*hinfo
= arg
;
3984 struct nfsmount
*nmp
;
3987 if (strcmp(mp
->mnt_vfsstat
.f_fstypename
, "nfs"))
3988 return (VFS_RETURNED
);
3990 if (!nmp
|| !NMFLAG(nmp
, EPHEMERAL
))
3991 return (VFS_RETURNED
);
3992 hinfo
->mountcount
++;
3994 /* avoid unmounting mounts that have been triggered within the last harvest interval */
3996 if ((nmp
->nm_mounttime
>> 32) > ((uint32_t)now
.tv_sec
- NFS_EPHEMERAL_MOUNT_HARVEST_INTERVAL
))
3997 return (VFS_RETURNED
);
3999 if (hinfo
->fsid
.val
[0] || hinfo
->fsid
.val
[1]) {
4000 /* attempt to unmount previously-found ephemeral mount */
4001 vfs_unmountbyfsid(&hinfo
->fsid
, 0, vfs_context_kernel());
4002 hinfo
->fsid
.val
[0] = hinfo
->fsid
.val
[1] = 0;
4006 * We can't call unmount here since we hold a mount iter ref
4007 * on mp so save its fsid for the next call iteration to unmount.
4009 hinfo
->fsid
.val
[0] = mp
->mnt_vfsstat
.f_fsid
.val
[0];
4010 hinfo
->fsid
.val
[1] = mp
->mnt_vfsstat
.f_fsid
.val
[1];
4012 return (VFS_RETURNED
);
4016 * Spawn a thread to do the ephemeral mount harvesting.
4019 nfs_ephemeral_mount_harvester_timer_func(void)
4023 if (kernel_thread_start(nfs_ephemeral_mount_harvester
, NULL
, &thd
) == KERN_SUCCESS
)
4024 thread_deallocate(thd
);
4028 * Iterate all mounts looking for NFS ephemeral mounts to try to unmount.
4031 nfs_ephemeral_mount_harvester(__unused
void *arg
, __unused wait_result_t wr
)
4033 struct nfs_ephemeral_mount_harvester_info hinfo
;
4036 hinfo
.mountcount
= 0;
4037 hinfo
.fsid
.val
[0] = hinfo
.fsid
.val
[1] = 0;
4038 vfs_iterate(VFS_ITERATE_TAIL_FIRST
, nfs_ephemeral_mount_harvester_callback
, &hinfo
);
4039 if (hinfo
.fsid
.val
[0] || hinfo
.fsid
.val
[1]) {
4040 /* attempt to unmount last found ephemeral mount */
4041 vfs_unmountbyfsid(&hinfo
.fsid
, 0, vfs_context_kernel());
4044 lck_mtx_lock(nfs_global_mutex
);
4045 if (!hinfo
.mountcount
) {
4046 /* no more ephemeral mounts - don't need timer */
4047 nfs_ephemeral_mount_harvester_on
= 0;
4049 /* re-arm the timer */
4050 clock_interval_to_deadline(NFS_EPHEMERAL_MOUNT_HARVEST_INTERVAL
, NSEC_PER_SEC
, &deadline
);
4051 thread_call_enter_delayed(nfs_ephemeral_mount_harvester_timer
, deadline
);
4052 nfs_ephemeral_mount_harvester_on
= 1;
4054 lck_mtx_unlock(nfs_global_mutex
);
4057 thread_terminate(current_thread());
4061 * Make sure the NFS ephemeral mount harvester timer is running.
4064 nfs_ephemeral_mount_harvester_start(void)
4068 lck_mtx_lock(nfs_global_mutex
);
4069 if (nfs_ephemeral_mount_harvester_on
) {
4070 lck_mtx_unlock(nfs_global_mutex
);
4073 if (nfs_ephemeral_mount_harvester_timer
== NULL
)
4074 nfs_ephemeral_mount_harvester_timer
= thread_call_allocate((thread_call_func_t
)nfs_ephemeral_mount_harvester_timer_func
, NULL
);
4075 clock_interval_to_deadline(NFS_EPHEMERAL_MOUNT_HARVEST_INTERVAL
, NSEC_PER_SEC
, &deadline
);
4076 thread_call_enter_delayed(nfs_ephemeral_mount_harvester_timer
, deadline
);
4077 nfs_ephemeral_mount_harvester_on
= 1;
4078 lck_mtx_unlock(nfs_global_mutex
);
4084 * Send a MOUNT protocol MOUNT request to the server to get the initial file handle (and security).
4087 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
)
4089 int error
= 0, slen
, mntproto
;
4090 thread_t thd
= vfs_context_thread(ctx
);
4091 kauth_cred_t cred
= vfs_context_ucred(ctx
);
4093 struct nfsm_chain nmreq
, nmrep
;
4095 uint32_t mntvers
, mntport
, val
;
4096 struct sockaddr_storage ss
;
4097 struct sockaddr
*saddr
= (struct sockaddr
*)&ss
;
4099 nfsm_chain_null(&nmreq
);
4100 nfsm_chain_null(&nmrep
);
4102 mntvers
= (nfsvers
== NFS_VER2
) ? RPCMNT_VER1
: RPCMNT_VER3
;
4103 mntproto
= (NM_OMFLAG(nmp
, MNTUDP
) || (sotype
== SOCK_DGRAM
)) ? IPPROTO_UDP
: IPPROTO_TCP
;
4106 bcopy(sa
, saddr
, min(sizeof(ss
), sa
->sa_len
));
4107 if (saddr
->sa_family
== AF_INET
) {
4108 if (nmp
->nm_mountport
)
4109 ((struct sockaddr_in
*)saddr
)->sin_port
= htons(nmp
->nm_mountport
);
4110 mntport
= ntohs(((struct sockaddr_in
*)saddr
)->sin_port
);
4112 if (nmp
->nm_mountport
)
4113 ((struct sockaddr_in6
*)saddr
)->sin6_port
= htons(nmp
->nm_mountport
);
4114 mntport
= ntohs(((struct sockaddr_in6
*)saddr
)->sin6_port
);
4118 error
= nfs_portmap_lookup(nmp
, ctx
, saddr
, NULL
, RPCPROG_MNT
, mntvers
, mntproto
, timeo
);
4120 if (saddr
->sa_family
== AF_INET
)
4121 mntport
= ntohs(((struct sockaddr_in
*)saddr
)->sin_port
);
4123 mntport
= ntohs(((struct sockaddr_in6
*)saddr
)->sin6_port
);
4125 /* if not found and TCP, then retry with UDP */
4126 if (mntproto
== IPPROTO_UDP
) {
4127 error
= EPROGUNAVAIL
;
4130 mntproto
= IPPROTO_UDP
;
4131 bcopy(sa
, saddr
, min(sizeof(ss
), sa
->sa_len
));
4134 nfsmout_if(error
|| !mntport
);
4136 /* MOUNT protocol MOUNT request */
4137 slen
= strlen(path
);
4138 nfsm_chain_build_alloc_init(error
, &nmreq
, NFSX_UNSIGNED
+ nfsm_rndup(slen
));
4139 nfsm_chain_add_name(error
, &nmreq
, path
, slen
, nmp
);
4140 nfsm_chain_build_done(error
, &nmreq
);
4142 error
= nfsm_rpchead2(nmp
, (mntproto
== IPPROTO_UDP
) ? SOCK_DGRAM
: SOCK_STREAM
,
4143 RPCPROG_MNT
, mntvers
, RPCMNT_MOUNT
,
4144 RPCAUTH_SYS
, cred
, NULL
, nmreq
.nmc_mhead
, &xid
, &mreq
);
4146 nmreq
.nmc_mhead
= NULL
;
4147 error
= nfs_aux_request(nmp
, thd
, saddr
, NULL
,
4148 ((mntproto
== IPPROTO_UDP
) ? SOCK_DGRAM
: SOCK_STREAM
),
4149 mreq
, R_XID32(xid
), 1, timeo
, &nmrep
);
4151 nfsm_chain_get_32(error
, &nmrep
, val
);
4154 nfsm_chain_get_fh(error
, &nmrep
, nfsvers
, fh
);
4155 if (!error
&& (nfsvers
> NFS_VER2
)) {
4156 sec
->count
= NX_MAX_SEC_FLAVORS
;
4157 error
= nfsm_chain_get_secinfo(&nmrep
, &sec
->flavors
[0], &sec
->count
);
4160 nfsm_chain_cleanup(&nmreq
);
4161 nfsm_chain_cleanup(&nmrep
);
4167 * Send a MOUNT protocol UNMOUNT request to tell the server we've unmounted it.
4170 nfs3_umount_rpc(struct nfsmount
*nmp
, vfs_context_t ctx
, int timeo
)
4172 int error
= 0, slen
, mntproto
;
4173 thread_t thd
= vfs_context_thread(ctx
);
4174 kauth_cred_t cred
= vfs_context_ucred(ctx
);
4177 struct nfsm_chain nmreq
, nmrep
;
4179 uint32_t mntvers
, mntport
;
4180 struct sockaddr_storage ss
;
4181 struct sockaddr
*saddr
= (struct sockaddr
*)&ss
;
4186 nfsm_chain_null(&nmreq
);
4187 nfsm_chain_null(&nmrep
);
4189 mntvers
= (nmp
->nm_vers
== NFS_VER2
) ? RPCMNT_VER1
: RPCMNT_VER3
;
4190 mntproto
= (NM_OMFLAG(nmp
, MNTUDP
) || (nmp
->nm_sotype
== SOCK_DGRAM
)) ? IPPROTO_UDP
: IPPROTO_TCP
;
4191 mntport
= nmp
->nm_mountport
;
4193 bcopy(nmp
->nm_saddr
, saddr
, min(sizeof(ss
), nmp
->nm_saddr
->sa_len
));
4194 if (saddr
->sa_family
== AF_INET
)
4195 ((struct sockaddr_in
*)saddr
)->sin_port
= htons(mntport
);
4197 ((struct sockaddr_in6
*)saddr
)->sin6_port
= htons(mntport
);
4200 error
= nfs_portmap_lookup(nmp
, ctx
, saddr
, NULL
, RPCPROG_MNT
, mntvers
, mntproto
, timeo
);
4202 if (saddr
->sa_family
== AF_INET
)
4203 mntport
= ntohs(((struct sockaddr_in
*)saddr
)->sin_port
);
4205 mntport
= ntohs(((struct sockaddr_in6
*)saddr
)->sin6_port
);
4206 /* if not found and mntvers > VER1, then retry with VER1 */
4208 if (mntvers
> RPCMNT_VER1
) {
4209 mntvers
= RPCMNT_VER1
;
4210 } else if (mntproto
== IPPROTO_TCP
) {
4211 mntproto
= IPPROTO_UDP
;
4212 mntvers
= (nmp
->nm_vers
== NFS_VER2
) ? RPCMNT_VER1
: RPCMNT_VER3
;
4216 bcopy(nmp
->nm_saddr
, saddr
, min(sizeof(ss
), nmp
->nm_saddr
->sa_len
));
4219 nfsmout_if(!mntport
);
4221 /* MOUNT protocol UNMOUNT request */
4222 path
= &vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
[0];
4223 while (*path
&& (*path
!= '/'))
4225 slen
= strlen(path
);
4226 nfsm_chain_build_alloc_init(error
, &nmreq
, NFSX_UNSIGNED
+ nfsm_rndup(slen
));
4227 nfsm_chain_add_name(error
, &nmreq
, path
, slen
, nmp
);
4228 nfsm_chain_build_done(error
, &nmreq
);
4230 error
= nfsm_rpchead2(nmp
, (mntproto
== IPPROTO_UDP
) ? SOCK_DGRAM
: SOCK_STREAM
,
4231 RPCPROG_MNT
, RPCMNT_VER1
, RPCMNT_UMOUNT
,
4232 RPCAUTH_SYS
, cred
, NULL
, nmreq
.nmc_mhead
, &xid
, &mreq
);
4234 nmreq
.nmc_mhead
= NULL
;
4235 error
= nfs_aux_request(nmp
, thd
, saddr
, NULL
,
4236 ((mntproto
== IPPROTO_UDP
) ? SOCK_DGRAM
: SOCK_STREAM
),
4237 mreq
, R_XID32(xid
), 1, timeo
, &nmrep
);
4239 nfsm_chain_cleanup(&nmreq
);
4240 nfsm_chain_cleanup(&nmrep
);
4244 * unmount system call
4250 __unused vfs_context_t ctx
)
4252 struct nfsmount
*nmp
;
4254 int error
, flags
= 0;
4255 struct timespec ts
= { 1, 0 };
4258 lck_mtx_lock(&nmp
->nm_lock
);
4260 * Set the flag indicating that an unmount attempt is in progress.
4262 nmp
->nm_state
|= NFSSTA_UNMOUNTING
;
4264 * During a force unmount we want to...
4265 * Mark that we are doing a force unmount.
4266 * Make the mountpoint soft.
4268 if (mntflags
& MNT_FORCE
) {
4269 flags
|= FORCECLOSE
;
4270 nmp
->nm_state
|= NFSSTA_FORCE
;
4271 NFS_BITMAP_SET(nmp
->nm_flags
, NFS_MFLAG_SOFT
);
4274 * Wait for any in-progress monitored node scan to complete.
4276 while (nmp
->nm_state
& NFSSTA_MONITOR_SCAN
)
4277 msleep(&nmp
->nm_state
, &nmp
->nm_lock
, PZERO
-1, "nfswaitmonscan", &ts
);
4279 * Goes something like this..
4280 * - Call vflush() to clear out vnodes for this file system,
4281 * except for the swap files. Deal with them in 2nd pass.
4282 * - Decrement reference on the vnode representing remote root.
4283 * - Clean up the NFS mount structure.
4285 vp
= NFSTOV(nmp
->nm_dnp
);
4286 lck_mtx_unlock(&nmp
->nm_lock
);
4289 * vflush will check for busy vnodes on mountpoint.
4290 * Will do the right thing for MNT_FORCE. That is, we should
4291 * not get EBUSY back.
4293 error
= vflush(mp
, vp
, SKIPSWAP
| flags
);
4294 if (mntflags
& MNT_FORCE
) {
4295 error
= vflush(mp
, NULLVP
, flags
); /* locks vp in the process */
4297 if (vnode_isinuse(vp
, 1))
4300 error
= vflush(mp
, vp
, flags
);
4303 lck_mtx_lock(&nmp
->nm_lock
);
4304 nmp
->nm_state
&= ~NFSSTA_UNMOUNTING
;
4305 lck_mtx_unlock(&nmp
->nm_lock
);
4309 lck_mtx_lock(&nmp
->nm_lock
);
4311 lck_mtx_unlock(&nmp
->nm_lock
);
4314 * Release the root vnode reference held by mountnfs()
4316 error
= vnode_get(vp
);
4321 vflush(mp
, NULLVP
, FORCECLOSE
);
4323 /* Wait for all other references to be released and free the mount */
4324 nfs_mount_drain_and_cleanup(nmp
);
4330 * cleanup/destroy NFS fs locations structure
4333 nfs_fs_locations_cleanup(struct nfs_fs_locations
*nfslsp
)
4335 struct nfs_fs_location
*fsl
;
4336 struct nfs_fs_server
*fss
;
4337 struct nfs_fs_path
*fsp
;
4338 uint32_t loc
, serv
, addr
, comp
;
4340 /* free up fs locations */
4341 if (!nfslsp
->nl_numlocs
|| !nfslsp
->nl_locations
)
4344 for (loc
= 0; loc
< nfslsp
->nl_numlocs
; loc
++) {
4345 fsl
= nfslsp
->nl_locations
[loc
];
4348 if ((fsl
->nl_servcount
> 0) && fsl
->nl_servers
) {
4349 for (serv
= 0; serv
< fsl
->nl_servcount
; serv
++) {
4350 fss
= fsl
->nl_servers
[serv
];
4353 if ((fss
->ns_addrcount
> 0) && fss
->ns_addresses
) {
4354 for (addr
= 0; addr
< fss
->ns_addrcount
; addr
++)
4355 FREE(fss
->ns_addresses
[addr
], M_TEMP
);
4356 FREE(fss
->ns_addresses
, M_TEMP
);
4358 FREE(fss
->ns_name
, M_TEMP
);
4361 FREE(fsl
->nl_servers
, M_TEMP
);
4363 fsp
= &fsl
->nl_path
;
4364 if (fsp
->np_compcount
&& fsp
->np_components
) {
4365 for (comp
= 0; comp
< fsp
->np_compcount
; comp
++)
4366 if (fsp
->np_components
[comp
])
4367 FREE(fsp
->np_components
[comp
], M_TEMP
);
4368 FREE(fsp
->np_components
, M_TEMP
);
4372 FREE(nfslsp
->nl_locations
, M_TEMP
);
4373 nfslsp
->nl_numlocs
= 0;
4374 nfslsp
->nl_locations
= NULL
;
4378 nfs_mount_rele(struct nfsmount
*nmp
)
4382 lck_mtx_lock(&nmp
->nm_lock
);
4383 if (nmp
->nm_ref
< 1)
4384 panic("nfs zombie mount underflow\n");
4386 if (nmp
->nm_ref
== 0)
4387 wup
= nmp
->nm_state
& NFSSTA_MOUNT_DRAIN
;
4388 lck_mtx_unlock(&nmp
->nm_lock
);
4390 wakeup(&nmp
->nm_ref
);
4394 nfs_mount_drain_and_cleanup(struct nfsmount
*nmp
)
4396 lck_mtx_lock(&nmp
->nm_lock
);
4397 nmp
->nm_state
|= NFSSTA_MOUNT_DRAIN
;
4398 while (nmp
->nm_ref
> 0) {
4399 msleep(&nmp
->nm_ref
, &nmp
->nm_lock
, PZERO
-1, "nfs_mount_drain", NULL
);
4401 assert(nmp
->nm_ref
== 0);
4402 lck_mtx_unlock(&nmp
->nm_lock
);
4403 nfs_mount_cleanup(nmp
);
4410 nfs_mount_zombie(struct nfsmount
*nmp
, int nm_state_flags
)
4412 struct nfsreq
*req
, *treq
;
4413 struct nfs_reqqhead iodq
, resendq
;
4414 struct timespec ts
= { 1, 0 };
4415 struct nfs_open_owner
*noop
, *nextnoop
;
4419 lck_mtx_lock(&nmp
->nm_lock
);
4420 nmp
->nm_state
|= nm_state_flags
;
4422 lck_mtx_unlock(&nmp
->nm_lock
);
4424 /* stop callbacks */
4425 if ((nmp
->nm_vers
>= NFS_VER4
) && !NMFLAG(nmp
, NOCALLBACK
) && nmp
->nm_cbid
)
4426 nfs4_mount_callback_shutdown(nmp
);
4428 /* Destroy any RPCSEC_GSS contexts */
4429 nfs_gss_clnt_ctx_unmount(nmp
);
4431 /* mark the socket for termination */
4432 lck_mtx_lock(&nmp
->nm_lock
);
4433 nmp
->nm_sockflags
|= NMSOCK_UNMOUNT
;
4435 /* Have the socket thread send the unmount RPC, if requested/appropriate. */
4436 if ((nmp
->nm_vers
< NFS_VER4
) && (nmp
->nm_state
& NFSSTA_MOUNTED
) &&
4437 !(nmp
->nm_state
& (NFSSTA_FORCE
|NFSSTA_DEAD
)) && NMFLAG(nmp
, CALLUMNT
))
4438 nfs_mount_sock_thread_wake(nmp
);
4440 /* wait for the socket thread to terminate */
4441 while (nmp
->nm_sockthd
&& current_thread() != nmp
->nm_sockthd
) {
4442 wakeup(&nmp
->nm_sockthd
);
4443 msleep(&nmp
->nm_sockthd
, &nmp
->nm_lock
, PZERO
-1, "nfswaitsockthd", &ts
);
4445 lck_mtx_unlock(&nmp
->nm_lock
);
4447 /* tear down the socket */
4448 nfs_disconnect(nmp
);
4450 lck_mtx_lock(&nmp
->nm_lock
);
4452 if ((nmp
->nm_vers
>= NFS_VER4
) && !NMFLAG(nmp
, NOCALLBACK
) && nmp
->nm_cbid
) {
4453 /* clear out any pending delegation return requests */
4454 while ((np
= TAILQ_FIRST(&nmp
->nm_dreturnq
))) {
4455 TAILQ_REMOVE(&nmp
->nm_dreturnq
, np
, n_dreturn
);
4456 np
->n_dreturn
.tqe_next
= NFSNOLIST
;
4460 /* cancel any renew timer */
4461 if ((nmp
->nm_vers
>= NFS_VER4
) && nmp
->nm_renew_timer
) {
4462 thread_call_cancel(nmp
->nm_renew_timer
);
4463 thread_call_free(nmp
->nm_renew_timer
);
4464 nmp
->nm_renew_timer
= NULL
;
4467 lck_mtx_unlock(&nmp
->nm_lock
);
4469 if (nmp
->nm_state
& NFSSTA_MOUNTED
)
4470 switch (nmp
->nm_lockmode
) {
4471 case NFS_LOCK_MODE_DISABLED
:
4472 case NFS_LOCK_MODE_LOCAL
:
4474 case NFS_LOCK_MODE_ENABLED
:
4476 if (nmp
->nm_vers
<= NFS_VER3
) {
4477 nfs_lockd_mount_unregister(nmp
);
4478 nmp
->nm_lockmode
= NFS_LOCK_MODE_DISABLED
;
4483 if ((nmp
->nm_vers
>= NFS_VER4
) && nmp
->nm_longid
) {
4484 /* remove/deallocate the client ID data */
4485 lck_mtx_lock(nfs_global_mutex
);
4486 TAILQ_REMOVE(&nfsclientids
, nmp
->nm_longid
, nci_link
);
4487 if (nmp
->nm_longid
->nci_id
)
4488 FREE(nmp
->nm_longid
->nci_id
, M_TEMP
);
4489 FREE(nmp
->nm_longid
, M_TEMP
);
4490 nmp
->nm_longid
= NULL
;
4491 lck_mtx_unlock(nfs_global_mutex
);
4495 * Be sure all requests for this mount are completed
4496 * and removed from the resend queue.
4498 TAILQ_INIT(&resendq
);
4499 lck_mtx_lock(nfs_request_mutex
);
4500 TAILQ_FOREACH(req
, &nfs_reqq
, r_chain
) {
4501 if (req
->r_nmp
== nmp
) {
4502 lck_mtx_lock(&req
->r_mtx
);
4503 if (!req
->r_error
&& req
->r_nmrep
.nmc_mhead
== NULL
)
4505 if (req
->r_flags
& R_RESENDQ
) {
4506 lck_mtx_lock(&nmp
->nm_lock
);
4507 req
->r_flags
&= ~R_RESENDQ
;
4508 if (req
->r_rchain
.tqe_next
!= NFSREQNOLIST
) {
4509 TAILQ_REMOVE(&nmp
->nm_resendq
, req
, r_rchain
);
4511 * Queue up the request so that we can unreference them
4512 * with out holding nfs_request_mutex
4514 TAILQ_INSERT_TAIL(&resendq
, req
, r_rchain
);
4516 lck_mtx_unlock(&nmp
->nm_lock
);
4519 lck_mtx_unlock(&req
->r_mtx
);
4522 lck_mtx_unlock(nfs_request_mutex
);
4524 /* Since we've drop the request mutex we can now safely unreference the request */
4525 TAILQ_FOREACH_SAFE(req
, &resendq
, r_rchain
, treq
) {
4526 TAILQ_REMOVE(&resendq
, req
, r_rchain
);
4527 /* Make sure we don't try and remove again in nfs_request_destroy */
4528 req
->r_rchain
.tqe_next
= NFSREQNOLIST
;
4529 nfs_request_rele(req
);
4533 * Now handle and outstanding async requests. We need to walk the
4534 * request queue again this time with the nfsiod_mutex held. No
4535 * other iods can grab our requests until we've put them on our own
4536 * local iod queue for processing.
4539 lck_mtx_lock(nfs_request_mutex
);
4540 lck_mtx_lock(nfsiod_mutex
);
4541 TAILQ_FOREACH(req
, &nfs_reqq
, r_chain
) {
4542 if (req
->r_nmp
== nmp
) {
4543 lck_mtx_lock(&req
->r_mtx
);
4544 if (req
->r_callback
.rcb_func
4545 && !(req
->r_flags
& R_WAITSENT
) && !(req
->r_flags
& R_IOD
)) {
4547 * Since R_IOD is not set then we need to handle it. If
4548 * we're not on a list add it to our iod queue. Otherwise
4549 * we must already be on nm_iodq which is added to our
4550 * local queue below.
4551 * %%% We should really keep a back pointer to our iod queue
4554 req
->r_flags
|= R_IOD
;
4555 if (req
->r_achain
.tqe_next
== NFSREQNOLIST
) {
4556 TAILQ_INSERT_TAIL(&iodq
, req
, r_achain
);
4559 lck_mtx_unlock(&req
->r_mtx
);
4563 /* finish any async I/O RPCs queued up */
4564 if (nmp
->nm_iodlink
.tqe_next
!= NFSNOLIST
)
4565 TAILQ_REMOVE(&nfsiodmounts
, nmp
, nm_iodlink
);
4566 TAILQ_CONCAT(&iodq
, &nmp
->nm_iodq
, r_achain
);
4567 lck_mtx_unlock(nfsiod_mutex
);
4568 lck_mtx_unlock(nfs_request_mutex
);
4570 TAILQ_FOREACH_SAFE(req
, &iodq
, r_achain
, treq
) {
4571 TAILQ_REMOVE(&iodq
, req
, r_achain
);
4572 req
->r_achain
.tqe_next
= NFSREQNOLIST
;
4573 lck_mtx_lock(&req
->r_mtx
);
4574 docallback
= !(req
->r_flags
& R_WAITSENT
);
4575 lck_mtx_unlock(&req
->r_mtx
);
4577 req
->r_callback
.rcb_func(req
);
4580 /* clean up common state */
4581 lck_mtx_lock(&nmp
->nm_lock
);
4582 while ((np
= LIST_FIRST(&nmp
->nm_monlist
))) {
4583 LIST_REMOVE(np
, n_monlink
);
4584 np
->n_monlink
.le_next
= NFSNOLIST
;
4586 TAILQ_FOREACH_SAFE(noop
, &nmp
->nm_open_owners
, noo_link
, nextnoop
) {
4587 TAILQ_REMOVE(&nmp
->nm_open_owners
, noop
, noo_link
);
4588 noop
->noo_flags
&= ~NFS_OPEN_OWNER_LINK
;
4589 if (noop
->noo_refcnt
)
4591 nfs_open_owner_destroy(noop
);
4593 lck_mtx_unlock(&nmp
->nm_lock
);
4595 /* clean up NFSv4 state */
4596 if (nmp
->nm_vers
>= NFS_VER4
) {
4597 lck_mtx_lock(&nmp
->nm_lock
);
4598 while ((np
= TAILQ_FIRST(&nmp
->nm_delegations
))) {
4599 TAILQ_REMOVE(&nmp
->nm_delegations
, np
, n_dlink
);
4600 np
->n_dlink
.tqe_next
= NFSNOLIST
;
4602 lck_mtx_unlock(&nmp
->nm_lock
);
4605 nfs_mount_rele(nmp
);
4609 * cleanup/destroy an nfsmount
4612 nfs_mount_cleanup(struct nfsmount
*nmp
)
4617 nfs_mount_zombie(nmp
, 0);
4619 NFS_VFS_DBG("Unmounting %s from %s\n",
4620 vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
,
4621 vfs_statfs(nmp
->nm_mountp
)->f_mntonname
);
4622 NFS_VFS_DBG("nfs state = 0x%8.8x\n", nmp
->nm_state
);
4623 NFS_VFS_DBG("nfs socket flags = 0x%8.8x\n", nmp
->nm_sockflags
);
4624 NFS_VFS_DBG("nfs mount ref count is %d\n", nmp
->nm_ref
);
4625 NFS_VFS_DBG("mount ref count is %d\n", nmp
->nm_mountp
->mnt_count
);
4628 vfs_setfsprivate(nmp
->nm_mountp
, NULL
);
4630 lck_mtx_lock(&nmp
->nm_lock
);
4632 panic("Some one has grabbed a ref %d state flags = 0x%8.8x\n", nmp
->nm_ref
, nmp
->nm_state
);
4635 FREE(nmp
->nm_saddr
, M_SONAME
);
4636 if ((nmp
->nm_vers
< NFS_VER4
) && nmp
->nm_rqsaddr
)
4637 FREE(nmp
->nm_rqsaddr
, M_SONAME
);
4639 if (IS_VALID_CRED(nmp
->nm_mcred
))
4640 kauth_cred_unref(&nmp
->nm_mcred
);
4642 nfs_fs_locations_cleanup(&nmp
->nm_locations
);
4645 FREE(nmp
->nm_realm
, M_TEMP
);
4646 if (nmp
->nm_principal
)
4647 FREE(nmp
->nm_principal
, M_TEMP
);
4649 FREE(nmp
->nm_sprinc
, M_TEMP
);
4652 xb_free(nmp
->nm_args
);
4654 lck_mtx_unlock(&nmp
->nm_lock
);
4656 lck_mtx_destroy(&nmp
->nm_lock
, nfs_mount_grp
);
4658 FREE(nmp
->nm_fh
, M_TEMP
);
4659 FREE_ZONE((caddr_t
)nmp
, sizeof (struct nfsmount
), M_NFSMNT
);
4663 * Return root of a filesystem
4666 nfs_vfs_root(mount_t mp
, vnode_t
*vpp
, __unused vfs_context_t ctx
)
4669 struct nfsmount
*nmp
;
4674 if (!nmp
|| !nmp
->nm_dnp
)
4676 vp
= NFSTOV(nmp
->nm_dnp
);
4677 vpid
= vnode_vid(vp
);
4678 while ((error
= vnode_getwithvid(vp
, vpid
))) {
4679 /* vnode_get() may return ENOENT if the dir changes. */
4680 /* If that happens, just try it again, else return the error. */
4681 if ((error
!= ENOENT
) || (vnode_vid(vp
) == vpid
))
4683 vpid
= vnode_vid(vp
);
4690 * Do operations associated with quotas
4695 __unused mount_t mp
,
4698 __unused caddr_t datap
,
4699 __unused vfs_context_t context
)
4706 nfs_sa_getport(struct sockaddr
*sa
, int *error
)
4710 if (sa
->sa_family
== AF_INET6
)
4711 port
= ntohs(((struct sockaddr_in6
*)sa
)->sin6_port
);
4712 else if (sa
->sa_family
== AF_INET
)
4713 port
= ntohs(((struct sockaddr_in
*)sa
)->sin_port
);
4721 nfs_sa_setport(struct sockaddr
*sa
, int port
)
4723 if (sa
->sa_family
== AF_INET6
)
4724 ((struct sockaddr_in6
*)sa
)->sin6_port
= htons(port
);
4725 else if (sa
->sa_family
== AF_INET
)
4726 ((struct sockaddr_in
*)sa
)->sin_port
= htons(port
);
4730 nfs3_getquota(struct nfsmount
*nmp
, vfs_context_t ctx
, uid_t id
, int type
, struct dqblk
*dqb
)
4732 int error
= 0, slen
, timeo
;
4733 int rqport
= 0, rqproto
, rqvers
= (type
== GRPQUOTA
) ? RPCRQUOTA_EXT_VER
: RPCRQUOTA_VER
;
4734 thread_t thd
= vfs_context_thread(ctx
);
4735 kauth_cred_t cred
= vfs_context_ucred(ctx
);
4738 struct nfsm_chain nmreq
, nmrep
;
4740 uint32_t val
= 0, bsize
= 0;
4741 struct sockaddr
*rqsaddr
;
4743 struct timespec ts
= { 1, 0 };
4748 if (NMFLAG(nmp
, NOQUOTA
))
4752 * Allocate an address for rquotad if needed
4754 if (!nmp
->nm_rqsaddr
) {
4757 MALLOC(rqsaddr
, struct sockaddr
*, sizeof(struct sockaddr_storage
), M_SONAME
, M_WAITOK
|M_ZERO
);
4758 bcopy(nmp
->nm_saddr
, rqsaddr
, min(sizeof(struct sockaddr_storage
), nmp
->nm_saddr
->sa_len
));
4759 /* Set the port to zero, will call rpcbind to get the port below */
4760 nfs_sa_setport(rqsaddr
, 0);
4763 lck_mtx_lock(&nmp
->nm_lock
);
4764 if (!nmp
->nm_rqsaddr
) {
4765 nmp
->nm_rqsaddr
= rqsaddr
;
4766 nmp
->nm_rqsaddrstamp
= now
.tv_sec
;
4770 lck_mtx_unlock(&nmp
->nm_lock
);
4772 FREE(rqsaddr
, M_SONAME
);
4775 timeo
= NMFLAG(nmp
, SOFT
) ? 10 : 60;
4776 rqproto
= IPPROTO_UDP
; /* XXX should prefer TCP if mount is TCP */
4778 /* check if we have a recently cached rquota port */
4780 lck_mtx_lock(&nmp
->nm_lock
);
4781 rqsaddr
= nmp
->nm_rqsaddr
;
4782 rqport
= nfs_sa_getport(rqsaddr
, &error
);
4783 while (!error
&& (!rqport
|| ((nmp
->nm_rqsaddrstamp
+ 60) <= (uint32_t)now
.tv_sec
))) {
4784 error
= nfs_sigintr(nmp
, NULL
, thd
, 1);
4786 lck_mtx_unlock(&nmp
->nm_lock
);
4789 if (nmp
->nm_state
& NFSSTA_RQUOTAINPROG
) {
4790 nmp
->nm_state
|= NFSSTA_WANTRQUOTA
;
4791 msleep(&nmp
->nm_rqsaddr
, &nmp
->nm_lock
, PZERO
-1, "nfswaitrquotaaddr", &ts
);
4792 rqport
= nfs_sa_getport(rqsaddr
, &error
);
4795 nmp
->nm_state
|= NFSSTA_RQUOTAINPROG
;
4796 lck_mtx_unlock(&nmp
->nm_lock
);
4798 /* send portmap request to get rquota port */
4799 error
= nfs_portmap_lookup(nmp
, ctx
, rqsaddr
, NULL
, RPCPROG_RQUOTA
, rqvers
, rqproto
, timeo
);
4802 rqport
= nfs_sa_getport(rqsaddr
, &error
);
4808 * We overload PMAPPORT for the port if rquotad is not
4809 * currently registered or up at the server. In the
4810 * while loop above, port will be set and we will defer
4811 * for a bit. Perhaps the service isn't online yet.
4813 * Note that precludes using indirect, but we're not doing
4817 nfs_sa_setport(rqsaddr
, rqport
);
4820 nmp
->nm_rqsaddrstamp
= now
.tv_sec
;
4822 lck_mtx_lock(&nmp
->nm_lock
);
4823 nmp
->nm_state
&= ~NFSSTA_RQUOTAINPROG
;
4824 if (nmp
->nm_state
& NFSSTA_WANTRQUOTA
) {
4825 nmp
->nm_state
&= ~NFSSTA_WANTRQUOTA
;
4826 wakeup(&nmp
->nm_rqsaddr
);
4829 lck_mtx_unlock(&nmp
->nm_lock
);
4833 /* Using PMAPPORT for unavailabe rquota service */
4834 if (rqport
== PMAPPORT
)
4837 /* rquota request */
4838 nfsm_chain_null(&nmreq
);
4839 nfsm_chain_null(&nmrep
);
4840 path
= &vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
[0];
4841 while (*path
&& (*path
!= '/'))
4843 slen
= strlen(path
);
4844 nfsm_chain_build_alloc_init(error
, &nmreq
, 3 * NFSX_UNSIGNED
+ nfsm_rndup(slen
));
4845 nfsm_chain_add_name(error
, &nmreq
, path
, slen
, nmp
);
4846 if (type
== GRPQUOTA
)
4847 nfsm_chain_add_32(error
, &nmreq
, type
);
4848 nfsm_chain_add_32(error
, &nmreq
, id
);
4849 nfsm_chain_build_done(error
, &nmreq
);
4851 error
= nfsm_rpchead2(nmp
, (rqproto
== IPPROTO_UDP
) ? SOCK_DGRAM
: SOCK_STREAM
,
4852 RPCPROG_RQUOTA
, rqvers
, RPCRQUOTA_GET
,
4853 RPCAUTH_SYS
, cred
, NULL
, nmreq
.nmc_mhead
, &xid
, &mreq
);
4855 nmreq
.nmc_mhead
= NULL
;
4856 error
= nfs_aux_request(nmp
, thd
, rqsaddr
, NULL
,
4857 (rqproto
== IPPROTO_UDP
) ? SOCK_DGRAM
: SOCK_STREAM
,
4858 mreq
, R_XID32(xid
), 0, timeo
, &nmrep
);
4861 /* parse rquota response */
4862 nfsm_chain_get_32(error
, &nmrep
, val
);
4863 if (!error
&& (val
!= RQUOTA_STAT_OK
)) {
4864 if (val
== RQUOTA_STAT_NOQUOTA
)
4866 else if (val
== RQUOTA_STAT_EPERM
)
4871 nfsm_chain_get_32(error
, &nmrep
, bsize
);
4872 nfsm_chain_adv(error
, &nmrep
, NFSX_UNSIGNED
);
4873 nfsm_chain_get_32(error
, &nmrep
, val
);
4875 dqb
->dqb_bhardlimit
= (uint64_t)val
* bsize
;
4876 nfsm_chain_get_32(error
, &nmrep
, val
);
4878 dqb
->dqb_bsoftlimit
= (uint64_t)val
* bsize
;
4879 nfsm_chain_get_32(error
, &nmrep
, val
);
4881 dqb
->dqb_curbytes
= (uint64_t)val
* bsize
;
4882 nfsm_chain_get_32(error
, &nmrep
, dqb
->dqb_ihardlimit
);
4883 nfsm_chain_get_32(error
, &nmrep
, dqb
->dqb_isoftlimit
);
4884 nfsm_chain_get_32(error
, &nmrep
, dqb
->dqb_curinodes
);
4885 nfsm_chain_get_32(error
, &nmrep
, dqb
->dqb_btime
);
4886 nfsm_chain_get_32(error
, &nmrep
, dqb
->dqb_itime
);
4890 nfsm_chain_cleanup(&nmreq
);
4891 nfsm_chain_cleanup(&nmrep
);
4896 nfs4_getquota(struct nfsmount
*nmp
, vfs_context_t ctx
, uid_t id
, int type
, struct dqblk
*dqb
)
4899 int error
= 0, status
, nfsvers
, numops
;
4901 struct nfsm_chain nmreq
, nmrep
;
4902 uint32_t bitmap
[NFS_ATTR_BITMAP_LEN
];
4903 thread_t thd
= vfs_context_thread(ctx
);
4904 kauth_cred_t cred
= vfs_context_ucred(ctx
);
4905 struct nfsreq_secinfo_args si
;
4907 if (type
!= USRQUOTA
) /* NFSv4 only supports user quotas */
4910 /* first check that the server supports any of the quota attributes */
4911 if (!NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_QUOTA_AVAIL_HARD
) &&
4912 !NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_QUOTA_AVAIL_SOFT
) &&
4913 !NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_QUOTA_USED
))
4917 * The credential passed to the server needs to have
4918 * an effective uid that matches the given uid.
4920 if (id
!= kauth_cred_getuid(cred
)) {
4921 struct posix_cred temp_pcred
;
4922 posix_cred_t pcred
= posix_cred_get(cred
);
4923 bzero(&temp_pcred
, sizeof(temp_pcred
));
4924 temp_pcred
.cr_uid
= id
;
4925 temp_pcred
.cr_ngroups
= pcred
->cr_ngroups
;
4926 bcopy(pcred
->cr_groups
, temp_pcred
.cr_groups
, sizeof(temp_pcred
.cr_groups
));
4927 cred
= posix_cred_create(&temp_pcred
);
4928 if (!IS_VALID_CRED(cred
))
4931 kauth_cred_ref(cred
);
4934 nfsvers
= nmp
->nm_vers
;
4938 if (error
|| ((error
= vnode_get(NFSTOV(np
))))) {
4939 kauth_cred_unref(&cred
);
4943 NFSREQ_SECINFO_SET(&si
, np
, NULL
, 0, NULL
, 0);
4944 nfsm_chain_null(&nmreq
);
4945 nfsm_chain_null(&nmrep
);
4949 nfsm_chain_build_alloc_init(error
, &nmreq
, 15 * NFSX_UNSIGNED
);
4950 nfsm_chain_add_compound_header(error
, &nmreq
, "quota", nmp
->nm_minor_vers
, numops
);
4952 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
4953 nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, np
->n_fhp
, np
->n_fhsize
);
4955 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
4956 NFS_CLEAR_ATTRIBUTES(bitmap
);
4957 NFS_BITMAP_SET(bitmap
, NFS_FATTR_QUOTA_AVAIL_HARD
);
4958 NFS_BITMAP_SET(bitmap
, NFS_FATTR_QUOTA_AVAIL_SOFT
);
4959 NFS_BITMAP_SET(bitmap
, NFS_FATTR_QUOTA_USED
);
4960 nfsm_chain_add_bitmap_supported(error
, &nmreq
, bitmap
, nmp
, NULL
);
4961 nfsm_chain_build_done(error
, &nmreq
);
4962 nfsm_assert(error
, (numops
== 0), EPROTO
);
4964 error
= nfs_request2(np
, NULL
, &nmreq
, NFSPROC4_COMPOUND
, thd
, cred
, &si
, 0, &nmrep
, &xid
, &status
);
4965 nfsm_chain_skip_tag(error
, &nmrep
);
4966 nfsm_chain_get_32(error
, &nmrep
, numops
);
4967 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
4968 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
4969 nfsm_assert(error
, NFSTONMP(np
), ENXIO
);
4971 error
= nfs4_parsefattr(&nmrep
, NULL
, NULL
, NULL
, dqb
, NULL
);
4973 nfsm_assert(error
, NFSTONMP(np
), ENXIO
);
4975 nfsm_chain_cleanup(&nmreq
);
4976 nfsm_chain_cleanup(&nmrep
);
4977 vnode_put(NFSTOV(np
));
4978 kauth_cred_unref(&cred
);
4983 nfs_vfs_quotactl(mount_t mp
, int cmds
, uid_t uid
, caddr_t datap
, vfs_context_t ctx
)
4985 struct nfsmount
*nmp
;
4986 int cmd
, type
, error
, nfsvers
;
4987 uid_t euid
= kauth_cred_getuid(vfs_context_ucred(ctx
));
4988 struct dqblk
*dqb
= (struct dqblk
*)datap
;
4991 if (nfs_mount_gone(nmp
))
4993 nfsvers
= nmp
->nm_vers
;
4998 /* we can only support Q_GETQUOTA */
4999 cmd
= cmds
>> SUBCMDSHIFT
;
5014 type
= cmds
& SUBCMDMASK
;
5015 if ((u_int
)type
>= MAXQUOTAS
)
5017 if ((uid
!= euid
) && ((error
= vfs_context_suser(ctx
))))
5020 if (vfs_busy(mp
, LK_NOWAIT
))
5022 bzero(dqb
, sizeof(*dqb
));
5023 error
= nmp
->nm_funcs
->nf_getquota(nmp
, ctx
, uid
, type
, dqb
);
5030 * Flush out the buffer cache
5032 int nfs_sync_callout(vnode_t
, void *);
5034 struct nfs_sync_cargs
{
5041 nfs_sync_callout(vnode_t vp
, void *arg
)
5043 struct nfs_sync_cargs
*cargs
= (struct nfs_sync_cargs
*)arg
;
5044 nfsnode_t np
= VTONFS(vp
);
5047 if (np
->n_flag
& NREVOKE
) {
5048 vn_revoke(vp
, REVOKEALL
, cargs
->ctx
);
5049 return (VNODE_RETURNED
);
5052 if (LIST_EMPTY(&np
->n_dirtyblkhd
))
5053 return (VNODE_RETURNED
);
5054 if (np
->n_wrbusy
> 0)
5055 return (VNODE_RETURNED
);
5056 if (np
->n_bflag
& (NBFLUSHINPROG
|NBINVALINPROG
))
5057 return (VNODE_RETURNED
);
5059 error
= nfs_flush(np
, cargs
->waitfor
, vfs_context_thread(cargs
->ctx
), 0);
5061 cargs
->error
= error
;
5063 return (VNODE_RETURNED
);
5067 nfs_vfs_sync(mount_t mp
, int waitfor
, vfs_context_t ctx
)
5069 struct nfs_sync_cargs cargs
;
5071 cargs
.waitfor
= waitfor
;
5075 vnode_iterate(mp
, 0, nfs_sync_callout
, &cargs
);
5077 return (cargs
.error
);
5081 * NFS flat namespace lookup.
5082 * Currently unsupported.
5087 __unused mount_t mp
,
5088 __unused ino64_t ino
,
5089 __unused vnode_t
*vpp
,
5090 __unused vfs_context_t ctx
)
5097 * At this point, this should never happen
5102 __unused mount_t mp
,
5104 __unused
unsigned char *fhp
,
5105 __unused vnode_t
*vpp
,
5106 __unused vfs_context_t ctx
)
5113 * Vnode pointer to File handle, should never happen either
5118 __unused vnode_t vp
,
5119 __unused
int *fhlenp
,
5120 __unused
unsigned char *fhp
,
5121 __unused vfs_context_t ctx
)
5128 * Vfs start routine, a no-op.
5133 __unused mount_t mp
,
5135 __unused vfs_context_t ctx
)
5142 * Build the mount info buffer for NFS_MOUNTINFO.
5145 nfs_mountinfo_assemble(struct nfsmount
*nmp
, struct xdrbuf
*xb
)
5147 struct xdrbuf xbinfo
, xborig
;
5149 uint32_t origargsvers
, origargslength
;
5150 uint32_t infolength_offset
, curargsopaquelength_offset
, curargslength_offset
, attrslength_offset
, curargs_end_offset
, end_offset
;
5151 uint32_t miattrs
[NFS_MIATTR_BITMAP_LEN
];
5152 uint32_t miflags_mask
[NFS_MIFLAG_BITMAP_LEN
];
5153 uint32_t miflags
[NFS_MIFLAG_BITMAP_LEN
];
5154 uint32_t mattrs
[NFS_MATTR_BITMAP_LEN
];
5155 uint32_t mflags_mask
[NFS_MFLAG_BITMAP_LEN
];
5156 uint32_t mflags
[NFS_MFLAG_BITMAP_LEN
];
5157 uint32_t loc
, serv
, addr
, comp
;
5158 int i
, timeo
, error
= 0;
5160 /* set up mount info attr and flag bitmaps */
5161 NFS_BITMAP_ZERO(miattrs
, NFS_MIATTR_BITMAP_LEN
);
5162 NFS_BITMAP_SET(miattrs
, NFS_MIATTR_FLAGS
);
5163 NFS_BITMAP_SET(miattrs
, NFS_MIATTR_ORIG_ARGS
);
5164 NFS_BITMAP_SET(miattrs
, NFS_MIATTR_CUR_ARGS
);
5165 NFS_BITMAP_SET(miattrs
, NFS_MIATTR_CUR_LOC_INDEX
);
5166 NFS_BITMAP_ZERO(miflags_mask
, NFS_MIFLAG_BITMAP_LEN
);
5167 NFS_BITMAP_ZERO(miflags
, NFS_MIFLAG_BITMAP_LEN
);
5168 NFS_BITMAP_SET(miflags_mask
, NFS_MIFLAG_DEAD
);
5169 NFS_BITMAP_SET(miflags_mask
, NFS_MIFLAG_NOTRESP
);
5170 NFS_BITMAP_SET(miflags_mask
, NFS_MIFLAG_RECOVERY
);
5171 if (nmp
->nm_state
& NFSSTA_DEAD
)
5172 NFS_BITMAP_SET(miflags
, NFS_MIFLAG_DEAD
);
5173 if ((nmp
->nm_state
& (NFSSTA_TIMEO
|NFSSTA_JUKEBOXTIMEO
)) ||
5174 ((nmp
->nm_state
& NFSSTA_LOCKTIMEO
) && (nmp
->nm_lockmode
== NFS_LOCK_MODE_ENABLED
)))
5175 NFS_BITMAP_SET(miflags
, NFS_MIFLAG_NOTRESP
);
5176 if (nmp
->nm_state
& NFSSTA_RECOVER
)
5177 NFS_BITMAP_SET(miflags
, NFS_MIFLAG_RECOVERY
);
5179 /* get original mount args length */
5180 xb_init_buffer(&xborig
, nmp
->nm_args
, 2*XDRWORD
);
5181 xb_get_32(error
, &xborig
, origargsvers
); /* version */
5182 xb_get_32(error
, &xborig
, origargslength
); /* args length */
5185 /* set up current mount attributes bitmap */
5186 NFS_BITMAP_ZERO(mattrs
, NFS_MATTR_BITMAP_LEN
);
5187 NFS_BITMAP_SET(mattrs
, NFS_MATTR_FLAGS
);
5188 NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_VERSION
);
5189 if (nmp
->nm_vers
>= NFS_VER4
)
5190 NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_MINOR_VERSION
);
5191 NFS_BITMAP_SET(mattrs
, NFS_MATTR_READ_SIZE
);
5192 NFS_BITMAP_SET(mattrs
, NFS_MATTR_WRITE_SIZE
);
5193 NFS_BITMAP_SET(mattrs
, NFS_MATTR_READDIR_SIZE
);
5194 NFS_BITMAP_SET(mattrs
, NFS_MATTR_READAHEAD
);
5195 NFS_BITMAP_SET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MIN
);
5196 NFS_BITMAP_SET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MAX
);
5197 NFS_BITMAP_SET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MIN
);
5198 NFS_BITMAP_SET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MAX
);
5199 NFS_BITMAP_SET(mattrs
, NFS_MATTR_LOCK_MODE
);
5200 NFS_BITMAP_SET(mattrs
, NFS_MATTR_SECURITY
);
5201 if (nmp
->nm_etype
.selected
< nmp
->nm_etype
.count
)
5202 NFS_BITMAP_SET(mattrs
, NFS_MATTR_KERB_ETYPE
);
5203 NFS_BITMAP_SET(mattrs
, NFS_MATTR_MAX_GROUP_LIST
);
5204 NFS_BITMAP_SET(mattrs
, NFS_MATTR_SOCKET_TYPE
);
5205 NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_PORT
);
5206 if ((nmp
->nm_vers
< NFS_VER4
) && nmp
->nm_mountport
)
5207 NFS_BITMAP_SET(mattrs
, NFS_MATTR_MOUNT_PORT
);
5208 NFS_BITMAP_SET(mattrs
, NFS_MATTR_REQUEST_TIMEOUT
);
5209 if (NMFLAG(nmp
, SOFT
))
5210 NFS_BITMAP_SET(mattrs
, NFS_MATTR_SOFT_RETRY_COUNT
);
5211 if (nmp
->nm_deadtimeout
)
5212 NFS_BITMAP_SET(mattrs
, NFS_MATTR_DEAD_TIMEOUT
);
5214 NFS_BITMAP_SET(mattrs
, NFS_MATTR_FH
);
5215 NFS_BITMAP_SET(mattrs
, NFS_MATTR_FS_LOCATIONS
);
5216 NFS_BITMAP_SET(mattrs
, NFS_MATTR_MNTFLAGS
);
5217 if (origargsvers
< NFS_ARGSVERSION_XDR
)
5218 NFS_BITMAP_SET(mattrs
, NFS_MATTR_MNTFROM
);
5220 NFS_BITMAP_SET(mattrs
, NFS_MATTR_REALM
);
5221 if (nmp
->nm_principal
)
5222 NFS_BITMAP_SET(mattrs
, NFS_MATTR_PRINCIPAL
);
5224 NFS_BITMAP_SET(mattrs
, NFS_MATTR_SVCPRINCIPAL
);
5226 /* set up current mount flags bitmap */
5227 /* first set the flags that we will be setting - either on OR off */
5228 NFS_BITMAP_ZERO(mflags_mask
, NFS_MFLAG_BITMAP_LEN
);
5229 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_SOFT
);
5230 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_INTR
);
5231 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_RESVPORT
);
5232 if (nmp
->nm_sotype
== SOCK_DGRAM
)
5233 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NOCONNECT
);
5234 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_DUMBTIMER
);
5235 if (nmp
->nm_vers
< NFS_VER4
)
5236 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_CALLUMNT
);
5237 if (nmp
->nm_vers
>= NFS_VER3
)
5238 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_RDIRPLUS
);
5239 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NONEGNAMECACHE
);
5240 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_MUTEJUKEBOX
);
5241 if (nmp
->nm_vers
>= NFS_VER4
) {
5242 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_EPHEMERAL
);
5243 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NOCALLBACK
);
5244 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NAMEDATTR
);
5245 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NOACL
);
5246 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_ACLONLY
);
5248 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NFC
);
5249 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NOQUOTA
);
5250 if (nmp
->nm_vers
< NFS_VER4
)
5251 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_MNTUDP
);
5252 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_MNTQUICK
);
5253 /* now set the flags that should be set */
5254 NFS_BITMAP_ZERO(mflags
, NFS_MFLAG_BITMAP_LEN
);
5255 if (NMFLAG(nmp
, SOFT
))
5256 NFS_BITMAP_SET(mflags
, NFS_MFLAG_SOFT
);
5257 if (NMFLAG(nmp
, INTR
))
5258 NFS_BITMAP_SET(mflags
, NFS_MFLAG_INTR
);
5259 if (NMFLAG(nmp
, RESVPORT
))
5260 NFS_BITMAP_SET(mflags
, NFS_MFLAG_RESVPORT
);
5261 if ((nmp
->nm_sotype
== SOCK_DGRAM
) && NMFLAG(nmp
, NOCONNECT
))
5262 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NOCONNECT
);
5263 if (NMFLAG(nmp
, DUMBTIMER
))
5264 NFS_BITMAP_SET(mflags
, NFS_MFLAG_DUMBTIMER
);
5265 if ((nmp
->nm_vers
< NFS_VER4
) && NMFLAG(nmp
, CALLUMNT
))
5266 NFS_BITMAP_SET(mflags
, NFS_MFLAG_CALLUMNT
);
5267 if ((nmp
->nm_vers
>= NFS_VER3
) && NMFLAG(nmp
, RDIRPLUS
))
5268 NFS_BITMAP_SET(mflags
, NFS_MFLAG_RDIRPLUS
);
5269 if (NMFLAG(nmp
, NONEGNAMECACHE
))
5270 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NONEGNAMECACHE
);
5271 if (NMFLAG(nmp
, MUTEJUKEBOX
))
5272 NFS_BITMAP_SET(mflags
, NFS_MFLAG_MUTEJUKEBOX
);
5273 if (nmp
->nm_vers
>= NFS_VER4
) {
5274 if (NMFLAG(nmp
, EPHEMERAL
))
5275 NFS_BITMAP_SET(mflags
, NFS_MFLAG_EPHEMERAL
);
5276 if (NMFLAG(nmp
, NOCALLBACK
))
5277 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NOCALLBACK
);
5278 if (NMFLAG(nmp
, NAMEDATTR
))
5279 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NAMEDATTR
);
5280 if (NMFLAG(nmp
, NOACL
))
5281 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NOACL
);
5282 if (NMFLAG(nmp
, ACLONLY
))
5283 NFS_BITMAP_SET(mflags
, NFS_MFLAG_ACLONLY
);
5285 if (NMFLAG(nmp
, NFC
))
5286 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NFC
);
5287 if (NMFLAG(nmp
, NOQUOTA
) || ((nmp
->nm_vers
>= NFS_VER4
) &&
5288 !NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_QUOTA_AVAIL_HARD
) &&
5289 !NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_QUOTA_AVAIL_SOFT
) &&
5290 !NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_QUOTA_USED
)))
5291 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NOQUOTA
);
5292 if ((nmp
->nm_vers
< NFS_VER4
) && NMFLAG(nmp
, MNTUDP
))
5293 NFS_BITMAP_SET(mflags
, NFS_MFLAG_MNTUDP
);
5294 if (NMFLAG(nmp
, MNTQUICK
))
5295 NFS_BITMAP_SET(mflags
, NFS_MFLAG_MNTQUICK
);
5297 /* assemble info buffer: */
5298 xb_init_buffer(&xbinfo
, NULL
, 0);
5299 xb_add_32(error
, &xbinfo
, NFS_MOUNT_INFO_VERSION
);
5300 infolength_offset
= xb_offset(&xbinfo
);
5301 xb_add_32(error
, &xbinfo
, 0);
5302 xb_add_bitmap(error
, &xbinfo
, miattrs
, NFS_MIATTR_BITMAP_LEN
);
5303 xb_add_bitmap(error
, &xbinfo
, miflags
, NFS_MIFLAG_BITMAP_LEN
);
5304 xb_add_32(error
, &xbinfo
, origargslength
);
5306 error
= xb_add_bytes(&xbinfo
, nmp
->nm_args
, origargslength
, 0);
5308 /* the opaque byte count for the current mount args values: */
5309 curargsopaquelength_offset
= xb_offset(&xbinfo
);
5310 xb_add_32(error
, &xbinfo
, 0);
5312 /* Encode current mount args values */
5313 xb_add_32(error
, &xbinfo
, NFS_ARGSVERSION_XDR
);
5314 curargslength_offset
= xb_offset(&xbinfo
);
5315 xb_add_32(error
, &xbinfo
, 0);
5316 xb_add_32(error
, &xbinfo
, NFS_XDRARGS_VERSION_0
);
5317 xb_add_bitmap(error
, &xbinfo
, mattrs
, NFS_MATTR_BITMAP_LEN
);
5318 attrslength_offset
= xb_offset(&xbinfo
);
5319 xb_add_32(error
, &xbinfo
, 0);
5320 xb_add_bitmap(error
, &xbinfo
, mflags_mask
, NFS_MFLAG_BITMAP_LEN
);
5321 xb_add_bitmap(error
, &xbinfo
, mflags
, NFS_MFLAG_BITMAP_LEN
);
5322 xb_add_32(error
, &xbinfo
, nmp
->nm_vers
); /* NFS_VERSION */
5323 if (nmp
->nm_vers
>= NFS_VER4
)
5324 xb_add_32(error
, &xbinfo
, nmp
->nm_minor_vers
); /* NFS_MINOR_VERSION */
5325 xb_add_32(error
, &xbinfo
, nmp
->nm_rsize
); /* READ_SIZE */
5326 xb_add_32(error
, &xbinfo
, nmp
->nm_wsize
); /* WRITE_SIZE */
5327 xb_add_32(error
, &xbinfo
, nmp
->nm_readdirsize
); /* READDIR_SIZE */
5328 xb_add_32(error
, &xbinfo
, nmp
->nm_readahead
); /* READAHEAD */
5329 xb_add_32(error
, &xbinfo
, nmp
->nm_acregmin
); /* ATTRCACHE_REG_MIN */
5330 xb_add_32(error
, &xbinfo
, 0); /* ATTRCACHE_REG_MIN */
5331 xb_add_32(error
, &xbinfo
, nmp
->nm_acregmax
); /* ATTRCACHE_REG_MAX */
5332 xb_add_32(error
, &xbinfo
, 0); /* ATTRCACHE_REG_MAX */
5333 xb_add_32(error
, &xbinfo
, nmp
->nm_acdirmin
); /* ATTRCACHE_DIR_MIN */
5334 xb_add_32(error
, &xbinfo
, 0); /* ATTRCACHE_DIR_MIN */
5335 xb_add_32(error
, &xbinfo
, nmp
->nm_acdirmax
); /* ATTRCACHE_DIR_MAX */
5336 xb_add_32(error
, &xbinfo
, 0); /* ATTRCACHE_DIR_MAX */
5337 xb_add_32(error
, &xbinfo
, nmp
->nm_lockmode
); /* LOCK_MODE */
5338 if (nmp
->nm_sec
.count
) {
5339 xb_add_32(error
, &xbinfo
, nmp
->nm_sec
.count
); /* SECURITY */
5341 for (i
=0; i
< nmp
->nm_sec
.count
; i
++)
5342 xb_add_32(error
, &xbinfo
, nmp
->nm_sec
.flavors
[i
]);
5343 } else if (nmp
->nm_servsec
.count
) {
5344 xb_add_32(error
, &xbinfo
, nmp
->nm_servsec
.count
); /* SECURITY */
5346 for (i
=0; i
< nmp
->nm_servsec
.count
; i
++)
5347 xb_add_32(error
, &xbinfo
, nmp
->nm_servsec
.flavors
[i
]);
5349 xb_add_32(error
, &xbinfo
, 1); /* SECURITY */
5350 xb_add_32(error
, &xbinfo
, nmp
->nm_auth
);
5352 if (nmp
->nm_etype
.selected
< nmp
->nm_etype
.count
) {
5353 xb_add_32(error
, &xbinfo
, nmp
->nm_etype
.count
);
5354 xb_add_32(error
, &xbinfo
, nmp
->nm_etype
.selected
);
5355 for (uint32_t j
=0; j
< nmp
->nm_etype
.count
; j
++)
5356 xb_add_32(error
, &xbinfo
, nmp
->nm_etype
.etypes
[j
]);
5359 xb_add_32(error
, &xbinfo
, nmp
->nm_numgrps
); /* MAX_GROUP_LIST */
5361 snprintf(sotype
, sizeof(sotype
), "%s%s", (nmp
->nm_sotype
== SOCK_DGRAM
) ? "udp" : "tcp",
5362 nmp
->nm_sofamily
? (nmp
->nm_sofamily
== AF_INET
) ? "4" : "6" : "");
5363 xb_add_string(error
, &xbinfo
, sotype
, strlen(sotype
)); /* SOCKET_TYPE */
5364 xb_add_32(error
, &xbinfo
, ntohs(((struct sockaddr_in
*)nmp
->nm_saddr
)->sin_port
)); /* NFS_PORT */
5365 if ((nmp
->nm_vers
< NFS_VER4
) && nmp
->nm_mountport
)
5366 xb_add_32(error
, &xbinfo
, nmp
->nm_mountport
); /* MOUNT_PORT */
5367 timeo
= (nmp
->nm_timeo
* 10) / NFS_HZ
;
5368 xb_add_32(error
, &xbinfo
, timeo
/10); /* REQUEST_TIMEOUT */
5369 xb_add_32(error
, &xbinfo
, (timeo%10
)*100000000); /* REQUEST_TIMEOUT */
5370 if (NMFLAG(nmp
, SOFT
))
5371 xb_add_32(error
, &xbinfo
, nmp
->nm_retry
); /* SOFT_RETRY_COUNT */
5372 if (nmp
->nm_deadtimeout
) {
5373 xb_add_32(error
, &xbinfo
, nmp
->nm_deadtimeout
); /* DEAD_TIMEOUT */
5374 xb_add_32(error
, &xbinfo
, 0); /* DEAD_TIMEOUT */
5377 xb_add_fh(error
, &xbinfo
, &nmp
->nm_fh
->fh_data
[0], nmp
->nm_fh
->fh_len
); /* FH */
5378 xb_add_32(error
, &xbinfo
, nmp
->nm_locations
.nl_numlocs
); /* FS_LOCATIONS */
5379 for (loc
= 0; !error
&& (loc
< nmp
->nm_locations
.nl_numlocs
); loc
++) {
5380 xb_add_32(error
, &xbinfo
, nmp
->nm_locations
.nl_locations
[loc
]->nl_servcount
);
5381 for (serv
= 0; !error
&& (serv
< nmp
->nm_locations
.nl_locations
[loc
]->nl_servcount
); serv
++) {
5382 xb_add_string(error
, &xbinfo
, nmp
->nm_locations
.nl_locations
[loc
]->nl_servers
[serv
]->ns_name
,
5383 strlen(nmp
->nm_locations
.nl_locations
[loc
]->nl_servers
[serv
]->ns_name
));
5384 xb_add_32(error
, &xbinfo
, nmp
->nm_locations
.nl_locations
[loc
]->nl_servers
[serv
]->ns_addrcount
);
5385 for (addr
= 0; !error
&& (addr
< nmp
->nm_locations
.nl_locations
[loc
]->nl_servers
[serv
]->ns_addrcount
); addr
++)
5386 xb_add_string(error
, &xbinfo
, nmp
->nm_locations
.nl_locations
[loc
]->nl_servers
[serv
]->ns_addresses
[addr
],
5387 strlen(nmp
->nm_locations
.nl_locations
[loc
]->nl_servers
[serv
]->ns_addresses
[addr
]));
5388 xb_add_32(error
, &xbinfo
, 0); /* empty server info */
5390 xb_add_32(error
, &xbinfo
, nmp
->nm_locations
.nl_locations
[loc
]->nl_path
.np_compcount
);
5391 for (comp
= 0; !error
&& (comp
< nmp
->nm_locations
.nl_locations
[loc
]->nl_path
.np_compcount
); comp
++)
5392 xb_add_string(error
, &xbinfo
, nmp
->nm_locations
.nl_locations
[loc
]->nl_path
.np_components
[comp
],
5393 strlen(nmp
->nm_locations
.nl_locations
[loc
]->nl_path
.np_components
[comp
]));
5394 xb_add_32(error
, &xbinfo
, 0); /* empty fs location info */
5396 xb_add_32(error
, &xbinfo
, vfs_flags(nmp
->nm_mountp
)); /* MNTFLAGS */
5397 if (origargsvers
< NFS_ARGSVERSION_XDR
)
5398 xb_add_string(error
, &xbinfo
, vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
,
5399 strlen(vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
)); /* MNTFROM */
5400 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_REALM
))
5401 xb_add_string(error
, &xbinfo
, nmp
->nm_realm
, strlen(nmp
->nm_realm
));
5402 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_PRINCIPAL
))
5403 xb_add_string(error
, &xbinfo
, nmp
->nm_principal
, strlen(nmp
->nm_principal
));
5404 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SVCPRINCIPAL
))
5405 xb_add_string(error
, &xbinfo
, nmp
->nm_sprinc
, strlen(nmp
->nm_sprinc
));
5407 curargs_end_offset
= xb_offset(&xbinfo
);
5409 /* NFS_MIATTR_CUR_LOC_INDEX */
5410 xb_add_32(error
, &xbinfo
, nmp
->nm_locations
.nl_current
.nli_flags
);
5411 xb_add_32(error
, &xbinfo
, nmp
->nm_locations
.nl_current
.nli_loc
);
5412 xb_add_32(error
, &xbinfo
, nmp
->nm_locations
.nl_current
.nli_serv
);
5413 xb_add_32(error
, &xbinfo
, nmp
->nm_locations
.nl_current
.nli_addr
);
5415 xb_build_done(error
, &xbinfo
);
5417 /* update opaque counts */
5418 end_offset
= xb_offset(&xbinfo
);
5420 error
= xb_seek(&xbinfo
, attrslength_offset
);
5421 xb_add_32(error
, &xbinfo
, curargs_end_offset
- attrslength_offset
- XDRWORD
/*don't include length field*/);
5424 error
= xb_seek(&xbinfo
, curargslength_offset
);
5425 xb_add_32(error
, &xbinfo
, curargs_end_offset
- curargslength_offset
+ XDRWORD
/*version*/);
5428 error
= xb_seek(&xbinfo
, curargsopaquelength_offset
);
5429 xb_add_32(error
, &xbinfo
, curargs_end_offset
- curargslength_offset
+ XDRWORD
/*version*/);
5432 error
= xb_seek(&xbinfo
, infolength_offset
);
5433 xb_add_32(error
, &xbinfo
, end_offset
- infolength_offset
+ XDRWORD
/*version*/);
5437 /* copy result xdrbuf to caller */
5440 /* and mark the local copy as not needing cleanup */
5441 xbinfo
.xb_flags
&= ~XB_CLEANUP
;
5443 xb_cleanup(&xbinfo
);
5448 * Do that sysctl thang...
5451 nfs_vfs_sysctl(int *name
, u_int namelen
, user_addr_t oldp
, size_t *oldlenp
,
5452 user_addr_t newp
, size_t newlen
, vfs_context_t ctx
)
5455 #ifndef CONFIG_EMBEDDED
5458 struct sysctl_req
*req
= NULL
;
5459 union union_vfsidctl vc
;
5461 struct nfsmount
*nmp
= NULL
;
5464 boolean_t is_64_bit
;
5467 struct netfs_status
*nsp
= NULL
;
5469 uint pos
, totlen
, count
, numThreads
;
5471 struct nfs_exportfs
*nxfs
;
5472 struct nfs_export
*nx
;
5473 struct nfs_active_user_list
*ulist
;
5474 struct nfs_export_stat_desc stat_desc
= {};
5475 struct nfs_export_stat_rec statrec
;
5476 struct nfs_user_stat_node
*unode
, *unode_next
;
5477 struct nfs_user_stat_desc ustat_desc
= {};
5478 struct nfs_user_stat_user_rec ustat_rec
;
5479 struct nfs_user_stat_path_rec upath_rec
;
5480 uint bytes_avail
, bytes_total
, recs_copied
;
5481 uint numExports
, numRecs
;
5482 #endif /* NFSSERVER */
5485 * All names at this level are terminal.
5488 return (ENOTDIR
); /* overloaded */
5490 is_64_bit
= vfs_context_is64bit(ctx
);
5492 /* common code for "new style" VFS_CTL sysctl, get the mount. */
5495 case VFS_CTL_NOLOCKS
:
5496 case VFS_CTL_NSTATUS
:
5497 #ifndef CONFIG_EMBEDDED
5500 req
= CAST_DOWN(struct sysctl_req
*, oldp
);
5504 error
= SYSCTL_IN(req
, &vc
, is_64_bit
? sizeof(vc
.vc64
):sizeof(vc
.vc32
));
5507 mp
= vfs_getvfs(&vc
.vc32
.vc_fsid
); /* works for 32 and 64 */
5513 bzero(&vq
, sizeof(vq
));
5516 req
->newptr
= vc
.vc64
.vc_ptr
;
5517 req
->newlen
= (size_t)vc
.vc64
.vc_len
;
5519 req
->newptr
= CAST_USER_ADDR_T(vc
.vc32
.vc_ptr
);
5520 req
->newlen
= vc
.vc32
.vc_len
;
5532 *oldlenp
= sizeof nfsstats
;
5536 if (*oldlenp
< sizeof nfsstats
) {
5537 *oldlenp
= sizeof nfsstats
;
5541 error
= copyout(&nfsstats
, oldp
, sizeof nfsstats
);
5545 if (newp
&& newlen
!= sizeof nfsstats
)
5549 return copyin(newp
, &nfsstats
, sizeof nfsstats
);
5552 /* read in the fsid */
5553 if (*oldlenp
< sizeof(fsid
))
5555 if ((error
= copyin(oldp
, &fsid
, sizeof(fsid
))))
5557 /* swizzle it back to host order */
5558 fsid
.val
[0] = ntohl(fsid
.val
[0]);
5559 fsid
.val
[1] = ntohl(fsid
.val
[1]);
5560 /* find mount and make sure it's NFS */
5561 if (((mp
= vfs_getvfs(&fsid
))) == NULL
)
5563 if (strcmp(mp
->mnt_vfsstat
.f_fstypename
, "nfs"))
5565 if (((nmp
= VFSTONFS(mp
))) == NULL
)
5568 if ((error
= nfs_mountinfo_assemble(nmp
, &xb
)))
5570 if (*oldlenp
< xb
.xb_u
.xb_buffer
.xbb_len
)
5573 error
= copyout(xb_buffer_base(&xb
), oldp
, xb
.xb_u
.xb_buffer
.xbb_len
);
5574 *oldlenp
= xb
.xb_u
.xb_buffer
.xbb_len
;
5578 case NFS_EXPORTSTATS
:
5579 /* setup export stat descriptor */
5580 stat_desc
.rec_vers
= NFS_EXPORT_STAT_REC_VERSION
;
5582 if (!nfsrv_is_initialized()) {
5583 stat_desc
.rec_count
= 0;
5584 if (oldp
&& (*oldlenp
>= sizeof(struct nfs_export_stat_desc
)))
5585 error
= copyout(&stat_desc
, oldp
, sizeof(struct nfs_export_stat_desc
));
5586 *oldlenp
= sizeof(struct nfs_export_stat_desc
);
5590 /* Count the number of exported directories */
5591 lck_rw_lock_shared(&nfsrv_export_rwlock
);
5593 LIST_FOREACH(nxfs
, &nfsrv_exports
, nxfs_next
)
5594 LIST_FOREACH(nx
, &nxfs
->nxfs_exports
, nx_next
)
5597 /* update stat descriptor's export record count */
5598 stat_desc
.rec_count
= numExports
;
5600 /* calculate total size of required buffer */
5601 totlen
= sizeof(struct nfs_export_stat_desc
) + (numExports
* sizeof(struct nfs_export_stat_rec
));
5603 /* Check caller's buffer */
5605 lck_rw_done(&nfsrv_export_rwlock
);
5606 /* indicate required buffer len */
5611 /* We require the caller's buffer to be at least large enough to hold the descriptor */
5612 if (*oldlenp
< sizeof(struct nfs_export_stat_desc
)) {
5613 lck_rw_done(&nfsrv_export_rwlock
);
5614 /* indicate required buffer len */
5619 /* indicate required buffer len */
5622 /* check if export table is empty */
5624 lck_rw_done(&nfsrv_export_rwlock
);
5625 error
= copyout(&stat_desc
, oldp
, sizeof(struct nfs_export_stat_desc
));
5629 /* calculate how many actual export stat records fit into caller's buffer */
5630 numRecs
= (*oldlenp
- sizeof(struct nfs_export_stat_desc
)) / sizeof(struct nfs_export_stat_rec
);
5633 /* caller's buffer can only accomodate descriptor */
5634 lck_rw_done(&nfsrv_export_rwlock
);
5635 stat_desc
.rec_count
= 0;
5636 error
= copyout(&stat_desc
, oldp
, sizeof(struct nfs_export_stat_desc
));
5640 /* adjust to actual number of records to copyout to caller's buffer */
5641 if (numRecs
> numExports
)
5642 numRecs
= numExports
;
5644 /* set actual number of records we are returning */
5645 stat_desc
.rec_count
= numRecs
;
5647 /* first copy out the stat descriptor */
5649 error
= copyout(&stat_desc
, oldp
+ pos
, sizeof(struct nfs_export_stat_desc
));
5651 lck_rw_done(&nfsrv_export_rwlock
);
5654 pos
+= sizeof(struct nfs_export_stat_desc
);
5656 /* Loop through exported directories */
5658 LIST_FOREACH(nxfs
, &nfsrv_exports
, nxfs_next
) {
5659 LIST_FOREACH(nx
, &nxfs
->nxfs_exports
, nx_next
) {
5661 if (count
>= numRecs
)
5664 /* build exported filesystem path */
5665 memset(statrec
.path
, 0, sizeof(statrec
.path
));
5666 snprintf(statrec
.path
, sizeof(statrec
.path
), "%s%s%s",
5667 nxfs
->nxfs_path
, ((nxfs
->nxfs_path
[1] && nx
->nx_path
[0]) ? "/" : ""),
5670 /* build the 64-bit export stat counters */
5671 statrec
.ops
= ((uint64_t)nx
->nx_stats
.ops
.hi
<< 32) |
5672 nx
->nx_stats
.ops
.lo
;
5673 statrec
.bytes_read
= ((uint64_t)nx
->nx_stats
.bytes_read
.hi
<< 32) |
5674 nx
->nx_stats
.bytes_read
.lo
;
5675 statrec
.bytes_written
= ((uint64_t)nx
->nx_stats
.bytes_written
.hi
<< 32) |
5676 nx
->nx_stats
.bytes_written
.lo
;
5677 error
= copyout(&statrec
, oldp
+ pos
, sizeof(statrec
));
5679 lck_rw_done(&nfsrv_export_rwlock
);
5682 /* advance buffer position */
5683 pos
+= sizeof(statrec
);
5686 lck_rw_done(&nfsrv_export_rwlock
);
5689 /* init structures used for copying out of kernel */
5690 ustat_desc
.rec_vers
= NFS_USER_STAT_REC_VERSION
;
5691 ustat_rec
.rec_type
= NFS_USER_STAT_USER_REC
;
5692 upath_rec
.rec_type
= NFS_USER_STAT_PATH_REC
;
5694 /* initialize counters */
5695 bytes_total
= sizeof(struct nfs_user_stat_desc
);
5696 bytes_avail
= *oldlenp
;
5699 if (!nfsrv_is_initialized()) /* NFS server not initialized, so no stats */
5702 /* reclaim old expired user nodes */
5703 nfsrv_active_user_list_reclaim();
5705 /* reserve space for the buffer descriptor */
5706 if (bytes_avail
>= sizeof(struct nfs_user_stat_desc
))
5707 bytes_avail
-= sizeof(struct nfs_user_stat_desc
);
5711 /* put buffer position past the buffer descriptor */
5712 pos
= sizeof(struct nfs_user_stat_desc
);
5714 /* Loop through exported directories */
5715 lck_rw_lock_shared(&nfsrv_export_rwlock
);
5716 LIST_FOREACH(nxfs
, &nfsrv_exports
, nxfs_next
) {
5717 LIST_FOREACH(nx
, &nxfs
->nxfs_exports
, nx_next
) {
5719 if (bytes_avail
>= sizeof(struct nfs_user_stat_path_rec
)) {
5720 memset(upath_rec
.path
, 0, sizeof(upath_rec
.path
));
5721 snprintf(upath_rec
.path
, sizeof(upath_rec
.path
), "%s%s%s",
5722 nxfs
->nxfs_path
, ((nxfs
->nxfs_path
[1] && nx
->nx_path
[0]) ? "/" : ""),
5725 error
= copyout(&upath_rec
, oldp
+ pos
, sizeof(struct nfs_user_stat_path_rec
));
5731 pos
+= sizeof(struct nfs_user_stat_path_rec
);
5732 bytes_avail
-= sizeof(struct nfs_user_stat_path_rec
);
5736 /* Caller's buffer is exhausted */
5740 bytes_total
+= sizeof(struct nfs_user_stat_path_rec
);
5742 /* Scan through all user nodes of this export */
5743 ulist
= &nx
->nx_user_list
;
5744 lck_mtx_lock(&ulist
->user_mutex
);
5745 for (unode
= TAILQ_FIRST(&ulist
->user_lru
); unode
; unode
= unode_next
) {
5746 unode_next
= TAILQ_NEXT(unode
, lru_link
);
5748 /* copy out node if there is space */
5749 if (bytes_avail
>= sizeof(struct nfs_user_stat_user_rec
)) {
5750 /* prepare a user stat rec for copying out */
5751 ustat_rec
.uid
= unode
->uid
;
5752 memset(&ustat_rec
.sock
, 0, sizeof(ustat_rec
.sock
));
5753 bcopy(&unode
->sock
, &ustat_rec
.sock
, unode
->sock
.ss_len
);
5754 ustat_rec
.ops
= unode
->ops
;
5755 ustat_rec
.bytes_read
= unode
->bytes_read
;
5756 ustat_rec
.bytes_written
= unode
->bytes_written
;
5757 ustat_rec
.tm_start
= unode
->tm_start
;
5758 ustat_rec
.tm_last
= unode
->tm_last
;
5760 error
= copyout(&ustat_rec
, oldp
+ pos
, sizeof(struct nfs_user_stat_user_rec
));
5764 lck_mtx_unlock(&ulist
->user_mutex
);
5768 pos
+= sizeof(struct nfs_user_stat_user_rec
);
5769 bytes_avail
-= sizeof(struct nfs_user_stat_user_rec
);
5773 /* Caller's buffer is exhausted */
5776 bytes_total
+= sizeof(struct nfs_user_stat_user_rec
);
5778 /* can unlock this export's list now */
5779 lck_mtx_unlock(&ulist
->user_mutex
);
5784 /* unlock the export table */
5785 lck_rw_done(&nfsrv_export_rwlock
);
5788 /* indicate number of actual records copied */
5789 ustat_desc
.rec_count
= recs_copied
;
5792 /* check if there was enough room for the buffer descriptor */
5793 if (*oldlenp
>= sizeof(struct nfs_user_stat_desc
))
5794 error
= copyout(&ustat_desc
, oldp
, sizeof(struct nfs_user_stat_desc
));
5798 /* always indicate required buffer size */
5799 *oldlenp
= bytes_total
;
5804 *oldlenp
= sizeof(nfsrv_user_stat_node_count
);
5808 if (*oldlenp
< sizeof(nfsrv_user_stat_node_count
)) {
5809 *oldlenp
= sizeof(nfsrv_user_stat_node_count
);
5813 if (nfsrv_is_initialized()) {
5814 /* reclaim old expired user nodes */
5815 nfsrv_active_user_list_reclaim();
5818 error
= copyout(&nfsrv_user_stat_node_count
, oldp
, sizeof(nfsrv_user_stat_node_count
));
5820 #endif /* NFSSERVER */
5821 case VFS_CTL_NOLOCKS
:
5822 if (req
->oldptr
!= USER_ADDR_NULL
) {
5823 lck_mtx_lock(&nmp
->nm_lock
);
5824 val
= (nmp
->nm_lockmode
== NFS_LOCK_MODE_DISABLED
) ? 1 : 0;
5825 lck_mtx_unlock(&nmp
->nm_lock
);
5826 error
= SYSCTL_OUT(req
, &val
, sizeof(val
));
5830 if (req
->newptr
!= USER_ADDR_NULL
) {
5831 error
= SYSCTL_IN(req
, &val
, sizeof(val
));
5834 lck_mtx_lock(&nmp
->nm_lock
);
5835 if (nmp
->nm_lockmode
== NFS_LOCK_MODE_LOCAL
) {
5836 /* can't toggle locks when using local locks */
5838 } else if ((nmp
->nm_vers
>= NFS_VER4
) && val
) {
5839 /* can't disable locks for NFSv4 */
5842 if ((nmp
->nm_vers
<= NFS_VER3
) && (nmp
->nm_lockmode
== NFS_LOCK_MODE_ENABLED
))
5843 nfs_lockd_mount_unregister(nmp
);
5844 nmp
->nm_lockmode
= NFS_LOCK_MODE_DISABLED
;
5845 nmp
->nm_state
&= ~NFSSTA_LOCKTIMEO
;
5847 if ((nmp
->nm_vers
<= NFS_VER3
) && (nmp
->nm_lockmode
== NFS_LOCK_MODE_DISABLED
))
5848 nfs_lockd_mount_register(nmp
);
5849 nmp
->nm_lockmode
= NFS_LOCK_MODE_ENABLED
;
5851 lck_mtx_unlock(&nmp
->nm_lock
);
5854 #ifndef CONFIG_EMBEDDED
5856 lck_mtx_lock(&nmp
->nm_lock
);
5857 /* XXX don't allow users to know about/disconnect unresponsive, soft, nobrowse mounts */
5858 softnobrowse
= (NMFLAG(nmp
, SOFT
) && (vfs_flags(nmp
->nm_mountp
) & MNT_DONTBROWSE
));
5859 if (!softnobrowse
&& (nmp
->nm_state
& NFSSTA_TIMEO
))
5860 vq
.vq_flags
|= VQ_NOTRESP
;
5861 if (!softnobrowse
&& (nmp
->nm_state
& NFSSTA_JUKEBOXTIMEO
) && !NMFLAG(nmp
, MUTEJUKEBOX
))
5862 vq
.vq_flags
|= VQ_NOTRESP
;
5863 if (!softnobrowse
&& (nmp
->nm_state
& NFSSTA_LOCKTIMEO
) &&
5864 (nmp
->nm_lockmode
== NFS_LOCK_MODE_ENABLED
))
5865 vq
.vq_flags
|= VQ_NOTRESP
;
5866 if (nmp
->nm_state
& NFSSTA_DEAD
)
5867 vq
.vq_flags
|= VQ_DEAD
;
5868 lck_mtx_unlock(&nmp
->nm_lock
);
5869 error
= SYSCTL_OUT(req
, &vq
, sizeof(vq
));
5873 if (req
->oldptr
!= USER_ADDR_NULL
) {
5874 lck_mtx_lock(&nmp
->nm_lock
);
5875 val
= nmp
->nm_tprintf_initial_delay
;
5876 lck_mtx_unlock(&nmp
->nm_lock
);
5877 error
= SYSCTL_OUT(req
, &val
, sizeof(val
));
5881 if (req
->newptr
!= USER_ADDR_NULL
) {
5882 error
= SYSCTL_IN(req
, &val
, sizeof(val
));
5885 lck_mtx_lock(&nmp
->nm_lock
);
5887 nmp
->nm_tprintf_initial_delay
= 0;
5889 nmp
->nm_tprintf_initial_delay
= val
;
5890 lck_mtx_unlock(&nmp
->nm_lock
);
5893 case VFS_CTL_NSTATUS
:
5895 * Return the status of this mount. This is much more
5896 * information than VFS_CTL_QUERY. In addition to the
5897 * vq_flags return the significant mount options along
5898 * with the list of threads blocked on the mount and
5899 * how long the threads have been waiting.
5902 lck_mtx_lock(nfs_request_mutex
);
5903 lck_mtx_lock(&nmp
->nm_lock
);
5906 * Count the number of requests waiting for a reply.
5907 * Note: there could be multiple requests from the same thread.
5910 TAILQ_FOREACH(rq
, &nfs_reqq
, r_chain
) {
5911 if (rq
->r_nmp
== nmp
)
5915 /* Calculate total size of result buffer */
5916 totlen
= sizeof(struct netfs_status
) + (numThreads
* sizeof(uint64_t));
5918 if (req
->oldptr
== USER_ADDR_NULL
) { // Caller is querying buffer size
5919 lck_mtx_unlock(&nmp
->nm_lock
);
5920 lck_mtx_unlock(nfs_request_mutex
);
5921 return SYSCTL_OUT(req
, NULL
, totlen
);
5923 if (req
->oldlen
< totlen
) { // Check if caller's buffer is big enough
5924 lck_mtx_unlock(&nmp
->nm_lock
);
5925 lck_mtx_unlock(nfs_request_mutex
);
5929 MALLOC(nsp
, struct netfs_status
*, totlen
, M_TEMP
, M_WAITOK
|M_ZERO
);
5931 lck_mtx_unlock(&nmp
->nm_lock
);
5932 lck_mtx_unlock(nfs_request_mutex
);
5935 timeoutmask
= NFSSTA_TIMEO
| NFSSTA_LOCKTIMEO
| NFSSTA_JUKEBOXTIMEO
;
5936 if (nmp
->nm_state
& timeoutmask
)
5937 nsp
->ns_status
|= VQ_NOTRESP
;
5938 if (nmp
->nm_state
& NFSSTA_DEAD
)
5939 nsp
->ns_status
|= VQ_DEAD
;
5941 (void) nfs_mountopts(nmp
, nsp
->ns_mountopts
, sizeof(nsp
->ns_mountopts
));
5942 nsp
->ns_threadcount
= numThreads
;
5945 * Get the thread ids of threads waiting for a reply
5946 * and find the longest wait time.
5948 if (numThreads
> 0) {
5954 sendtime
= now
.tv_sec
;
5955 TAILQ_FOREACH(rq
, &nfs_reqq
, r_chain
) {
5956 if (rq
->r_nmp
== nmp
) {
5957 if (rq
->r_start
< sendtime
)
5958 sendtime
= rq
->r_start
;
5959 // A thread_id of zero is used to represent an async I/O request.
5960 nsp
->ns_threadids
[count
] =
5961 rq
->r_thread
? thread_tid(rq
->r_thread
) : 0;
5962 if (++count
>= numThreads
)
5966 nsp
->ns_waittime
= now
.tv_sec
- sendtime
;
5969 lck_mtx_unlock(&nmp
->nm_lock
);
5970 lck_mtx_unlock(nfs_request_mutex
);
5972 error
= SYSCTL_OUT(req
, nsp
, totlen
);