2 * Copyright (c) 2000-2014 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;
155 lck_grp_t
*nfsiod_lck_grp
;
156 lck_mtx_t
*nfsiod_mutex
;
157 struct nfsiodlist nfsiodfree
, nfsiodwork
;
158 struct nfsiodmountlist nfsiodmounts
;
159 int nfsiod_thread_count
= 0;
160 int nfsiod_thread_max
= NFS_DEFASYNCTHREAD
;
161 int nfs_max_async_writes
= NFS_DEFMAXASYNCWRITES
;
163 int nfs_iosize
= NFS_IOSIZE
;
164 int nfs_access_cache_timeout
= NFS_MAXATTRTIMO
;
165 int nfs_access_delete
= 1; /* too many servers get this wrong - workaround on by default */
166 int nfs_access_dotzfs
= 1;
167 int nfs_access_for_getattr
= 0;
168 int nfs_allow_async
= 0;
169 int nfs_statfs_rate_limit
= NFS_DEFSTATFSRATELIMIT
;
170 int nfs_lockd_mounts
= 0;
171 int nfs_lockd_request_sent
= 0;
172 int nfs_idmap_ctrl
= NFS_IDMAP_CTRL_USE_IDMAP_SERVICE
;
173 int nfs_callback_port
= 0;
175 int nfs_tprintf_initial_delay
= NFS_TPRINTF_INITIAL_DELAY
;
176 int nfs_tprintf_delay
= NFS_TPRINTF_DELAY
;
179 int mountnfs(char *, mount_t
, vfs_context_t
, vnode_t
*);
180 static int nfs_mount_diskless(struct nfs_dlmount
*, const char *, int, vnode_t
*, mount_t
*, vfs_context_t
);
181 #if !defined(NO_MOUNT_PRIVATE)
182 static int nfs_mount_diskless_private(struct nfs_dlmount
*, const char *, int, vnode_t
*, mount_t
*, vfs_context_t
);
183 #endif /* NO_MOUNT_PRIVATE */
184 int nfs_mount_connect(struct nfsmount
*);
185 void nfs_mount_drain_and_cleanup(struct nfsmount
*);
186 void nfs_mount_cleanup(struct nfsmount
*);
187 int nfs_mountinfo_assemble(struct nfsmount
*, struct xdrbuf
*);
188 int nfs4_mount_update_path_with_symlink(struct nfsmount
*, struct nfs_fs_path
*, uint32_t, fhandle_t
*, int *, fhandle_t
*, vfs_context_t
);
191 * NFS VFS operations.
193 int nfs_vfs_mount(mount_t
, vnode_t
, user_addr_t
, vfs_context_t
);
194 int nfs_vfs_start(mount_t
, int, vfs_context_t
);
195 int nfs_vfs_unmount(mount_t
, int, vfs_context_t
);
196 int nfs_vfs_root(mount_t
, vnode_t
*, vfs_context_t
);
197 int nfs_vfs_quotactl(mount_t
, int, uid_t
, caddr_t
, vfs_context_t
);
198 int nfs_vfs_getattr(mount_t
, struct vfs_attr
*, vfs_context_t
);
199 int nfs_vfs_sync(mount_t
, int, vfs_context_t
);
200 int nfs_vfs_vget(mount_t
, ino64_t
, vnode_t
*, vfs_context_t
);
201 int nfs_vfs_vptofh(vnode_t
, int *, unsigned char *, vfs_context_t
);
202 int nfs_vfs_fhtovp(mount_t
, int, unsigned char *, vnode_t
*, vfs_context_t
);
203 int nfs_vfs_init(struct vfsconf
*);
204 int nfs_vfs_sysctl(int *, u_int
, user_addr_t
, size_t *, user_addr_t
, size_t, vfs_context_t
);
206 struct vfsops nfs_vfsops
= {
220 { NULL
, /* reserved */
226 NULL
} /* reserved */
231 * version-specific NFS functions
233 int nfs3_mount(struct nfsmount
*, vfs_context_t
, nfsnode_t
*);
234 int nfs4_mount(struct nfsmount
*, vfs_context_t
, nfsnode_t
*);
235 int nfs3_fsinfo(struct nfsmount
*, nfsnode_t
, vfs_context_t
);
236 int nfs3_update_statfs(struct nfsmount
*, vfs_context_t
);
237 int nfs4_update_statfs(struct nfsmount
*, vfs_context_t
);
239 #define nfs3_getquota NULL
240 #define nfs4_getquota NULL
242 int nfs3_getquota(struct nfsmount
*, vfs_context_t
, uid_t
, int, struct dqblk
*);
243 int nfs4_getquota(struct nfsmount
*, vfs_context_t
, uid_t
, int, struct dqblk
*);
246 struct nfs_funcs nfs3_funcs
= {
254 nfs3_read_rpc_async_finish
,
256 nfs3_write_rpc_async
,
257 nfs3_write_rpc_async_finish
,
259 nfs3_lookup_rpc_async
,
260 nfs3_lookup_rpc_async_finish
,
267 struct nfs_funcs nfs4_funcs
= {
275 nfs4_read_rpc_async_finish
,
277 nfs4_write_rpc_async
,
278 nfs4_write_rpc_async_finish
,
280 nfs4_lookup_rpc_async
,
281 nfs4_lookup_rpc_async_finish
,
290 * Called once to initialize data structures...
293 nfs_vfs_init(__unused
struct vfsconf
*vfsp
)
298 * Check to see if major data structures haven't bloated.
300 if (sizeof (struct nfsnode
) > NFS_NODEALLOC
) {
301 printf("struct nfsnode bloated (> %dbytes)\n", NFS_NODEALLOC
);
302 printf("Try reducing NFS_SMALLFH\n");
304 if (sizeof (struct nfsmount
) > NFS_MNTALLOC
)
305 printf("struct nfsmount bloated (> %dbytes)\n", NFS_MNTALLOC
);
307 nfs_ticks
= (hz
* NFS_TICKINTVL
+ 500) / 1000;
311 /* init async I/O thread pool state */
312 TAILQ_INIT(&nfsiodfree
);
313 TAILQ_INIT(&nfsiodwork
);
314 TAILQ_INIT(&nfsiodmounts
);
315 nfsiod_lck_grp
= lck_grp_alloc_init("nfsiod", LCK_GRP_ATTR_NULL
);
316 nfsiod_mutex
= lck_mtx_alloc_init(nfsiod_lck_grp
, LCK_ATTR_NULL
);
318 /* init lock groups, etc. */
319 nfs_mount_grp
= lck_grp_alloc_init("nfs_mount", LCK_GRP_ATTR_NULL
);
320 nfs_open_grp
= lck_grp_alloc_init("nfs_open", LCK_GRP_ATTR_NULL
);
321 nfs_global_grp
= lck_grp_alloc_init("nfs_global", LCK_GRP_ATTR_NULL
);
323 nfs_global_mutex
= lck_mtx_alloc_init(nfs_global_grp
, LCK_ATTR_NULL
);
325 /* init request list mutex */
326 nfs_request_grp
= lck_grp_alloc_init("nfs_request", LCK_GRP_ATTR_NULL
);
327 nfs_request_mutex
= lck_mtx_alloc_init(nfs_request_grp
, LCK_ATTR_NULL
);
329 /* initialize NFS request list */
330 TAILQ_INIT(&nfs_reqq
);
332 nfs_nbinit(); /* Init the nfsbuf table */
333 nfs_nhinit(); /* Init the nfsnode table */
334 nfs_lockinit(); /* Init the nfs lock state */
335 nfs_gss_init(); /* Init RPCSEC_GSS security */
338 NFS4_PER_FS_ATTRIBUTES(nfs_fs_attr_bitmap
);
339 NFS4_PER_OBJECT_ATTRIBUTES(nfs_object_attr_bitmap
);
340 NFS4_DEFAULT_ATTRIBUTES(nfs_getattr_bitmap
);
341 for (i
=0; i
< NFS_ATTR_BITMAP_LEN
; i
++)
342 nfs_getattr_bitmap
[i
] &= nfs_object_attr_bitmap
[i
];
343 TAILQ_INIT(&nfsclientids
);
345 /* initialize NFS timer callouts */
346 nfs_request_timer_call
= thread_call_allocate(nfs_request_timer
, NULL
);
347 nfs_buf_timer_call
= thread_call_allocate(nfs_buf_timer
, NULL
);
348 nfs4_callback_timer_call
= thread_call_allocate(nfs4_callback_timer
, NULL
);
357 nfs3_update_statfs(struct nfsmount
*nmp
, vfs_context_t ctx
)
360 int error
= 0, lockerror
, status
, nfsvers
;
362 struct nfsm_chain nmreq
, nmrep
;
365 nfsvers
= nmp
->nm_vers
;
369 if ((error
= vnode_get(NFSTOV(np
))))
372 nfsm_chain_null(&nmreq
);
373 nfsm_chain_null(&nmrep
);
375 nfsm_chain_build_alloc_init(error
, &nmreq
, NFSX_FH(nfsvers
));
376 nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, np
->n_fhp
, np
->n_fhsize
);
377 nfsm_chain_build_done(error
, &nmreq
);
379 error
= nfs_request2(np
, NULL
, &nmreq
, NFSPROC_FSSTAT
, vfs_context_thread(ctx
),
380 vfs_context_ucred(ctx
), NULL
, R_SOFT
, &nmrep
, &xid
, &status
);
381 if (error
== ETIMEDOUT
)
383 if ((lockerror
= nfs_node_lock(np
)))
385 if (nfsvers
== NFS_VER3
)
386 nfsm_chain_postop_attr_update(error
, &nmrep
, np
, &xid
);
391 nfsm_assert(error
, NFSTONMP(np
), ENXIO
);
393 lck_mtx_lock(&nmp
->nm_lock
);
394 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_TOTAL
);
395 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_FREE
);
396 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_AVAIL
);
397 if (nfsvers
== NFS_VER3
) {
398 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_FILES_AVAIL
);
399 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_FILES_TOTAL
);
400 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_FILES_FREE
);
401 nmp
->nm_fsattr
.nfsa_bsize
= NFS_FABLKSIZE
;
402 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_space_total
);
403 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_space_free
);
404 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_space_avail
);
405 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_files_total
);
406 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_files_free
);
407 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_files_avail
);
410 nfsm_chain_adv(error
, &nmrep
, NFSX_UNSIGNED
); // skip tsize?
411 nfsm_chain_get_32(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_bsize
);
412 nfsm_chain_get_32(error
, &nmrep
, val
);
414 if (nmp
->nm_fsattr
.nfsa_bsize
<= 0)
415 nmp
->nm_fsattr
.nfsa_bsize
= NFS_FABLKSIZE
;
416 nmp
->nm_fsattr
.nfsa_space_total
= (uint64_t)val
* nmp
->nm_fsattr
.nfsa_bsize
;
417 nfsm_chain_get_32(error
, &nmrep
, val
);
419 nmp
->nm_fsattr
.nfsa_space_free
= (uint64_t)val
* nmp
->nm_fsattr
.nfsa_bsize
;
420 nfsm_chain_get_32(error
, &nmrep
, val
);
422 nmp
->nm_fsattr
.nfsa_space_avail
= (uint64_t)val
* nmp
->nm_fsattr
.nfsa_bsize
;
424 lck_mtx_unlock(&nmp
->nm_lock
);
426 nfsm_chain_cleanup(&nmreq
);
427 nfsm_chain_cleanup(&nmrep
);
428 vnode_put(NFSTOV(np
));
433 nfs4_update_statfs(struct nfsmount
*nmp
, vfs_context_t ctx
)
436 int error
= 0, lockerror
, status
, nfsvers
, numops
;
438 struct nfsm_chain nmreq
, nmrep
;
439 uint32_t bitmap
[NFS_ATTR_BITMAP_LEN
];
440 struct nfs_vattr nvattr
;
441 struct nfsreq_secinfo_args si
;
443 nfsvers
= nmp
->nm_vers
;
447 if ((error
= vnode_get(NFSTOV(np
))))
450 NFSREQ_SECINFO_SET(&si
, np
, NULL
, 0, NULL
, 0);
451 NVATTR_INIT(&nvattr
);
452 nfsm_chain_null(&nmreq
);
453 nfsm_chain_null(&nmrep
);
457 nfsm_chain_build_alloc_init(error
, &nmreq
, 15 * NFSX_UNSIGNED
);
458 nfsm_chain_add_compound_header(error
, &nmreq
, "statfs", numops
);
460 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
461 nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, np
->n_fhp
, np
->n_fhsize
);
463 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
464 NFS_COPY_ATTRIBUTES(nfs_getattr_bitmap
, bitmap
);
465 NFS4_STATFS_ATTRIBUTES(bitmap
);
466 nfsm_chain_add_bitmap_supported(error
, &nmreq
, bitmap
, nmp
, np
);
467 nfsm_chain_build_done(error
, &nmreq
);
468 nfsm_assert(error
, (numops
== 0), EPROTO
);
470 error
= nfs_request2(np
, NULL
, &nmreq
, NFSPROC4_COMPOUND
,
471 vfs_context_thread(ctx
), vfs_context_ucred(ctx
),
472 NULL
, R_SOFT
, &nmrep
, &xid
, &status
);
473 nfsm_chain_skip_tag(error
, &nmrep
);
474 nfsm_chain_get_32(error
, &nmrep
, numops
);
475 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
476 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
477 nfsm_assert(error
, NFSTONMP(np
), ENXIO
);
479 lck_mtx_lock(&nmp
->nm_lock
);
480 error
= nfs4_parsefattr(&nmrep
, &nmp
->nm_fsattr
, &nvattr
, NULL
, NULL
, NULL
);
481 lck_mtx_unlock(&nmp
->nm_lock
);
483 if ((lockerror
= nfs_node_lock(np
)))
486 nfs_loadattrcache(np
, &nvattr
, &xid
, 0);
489 nfsm_assert(error
, NFSTONMP(np
), ENXIO
);
491 nmp
->nm_fsattr
.nfsa_bsize
= NFS_FABLKSIZE
;
493 NVATTR_CLEANUP(&nvattr
);
494 nfsm_chain_cleanup(&nmreq
);
495 nfsm_chain_cleanup(&nmrep
);
496 vnode_put(NFSTOV(np
));
502 * The NFS VFS_GETATTR function: "statfs"-type information is retrieved
503 * using the nf_update_statfs() function, and other attributes are cobbled
504 * together from whatever sources we can (getattr, fsinfo, pathconf).
507 nfs_vfs_getattr(mount_t mp
, struct vfs_attr
*fsap
, vfs_context_t ctx
)
509 struct nfsmount
*nmp
;
511 int error
= 0, nfsvers
;
514 if (nfs_mount_gone(nmp
))
516 nfsvers
= nmp
->nm_vers
;
518 if (VFSATTR_IS_ACTIVE(fsap
, f_bsize
) ||
519 VFSATTR_IS_ACTIVE(fsap
, f_iosize
) ||
520 VFSATTR_IS_ACTIVE(fsap
, f_blocks
) ||
521 VFSATTR_IS_ACTIVE(fsap
, f_bfree
) ||
522 VFSATTR_IS_ACTIVE(fsap
, f_bavail
) ||
523 VFSATTR_IS_ACTIVE(fsap
, f_bused
) ||
524 VFSATTR_IS_ACTIVE(fsap
, f_files
) ||
525 VFSATTR_IS_ACTIVE(fsap
, f_ffree
)) {
526 int statfsrate
= nfs_statfs_rate_limit
;
530 * Are we rate-limiting statfs RPCs?
531 * (Treat values less than 1 or greater than 1,000,000 as no limit.)
533 if ((statfsrate
> 0) && (statfsrate
< 1000000)) {
538 lck_mtx_lock(&nmp
->nm_lock
);
539 stamp
= (now
.tv_sec
* statfsrate
) + (now
.tv_usec
/ (1000000/statfsrate
));
540 if (stamp
!= nmp
->nm_fsattrstamp
) {
542 nmp
->nm_fsattrstamp
= stamp
;
546 lck_mtx_unlock(&nmp
->nm_lock
);
549 if (refresh
&& !nfs_use_cache(nmp
))
550 error
= nmp
->nm_funcs
->nf_update_statfs(nmp
, ctx
);
551 if ((error
== ESTALE
) || (error
== ETIMEDOUT
))
556 lck_mtx_lock(&nmp
->nm_lock
);
557 VFSATTR_RETURN(fsap
, f_iosize
, nfs_iosize
);
558 VFSATTR_RETURN(fsap
, f_bsize
, nmp
->nm_fsattr
.nfsa_bsize
);
559 bsize
= nmp
->nm_fsattr
.nfsa_bsize
;
560 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_TOTAL
))
561 VFSATTR_RETURN(fsap
, f_blocks
, nmp
->nm_fsattr
.nfsa_space_total
/ bsize
);
562 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_FREE
))
563 VFSATTR_RETURN(fsap
, f_bfree
, nmp
->nm_fsattr
.nfsa_space_free
/ bsize
);
564 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_AVAIL
))
565 VFSATTR_RETURN(fsap
, f_bavail
, nmp
->nm_fsattr
.nfsa_space_avail
/ bsize
);
566 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_TOTAL
) &&
567 NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_FREE
))
568 VFSATTR_RETURN(fsap
, f_bused
,
569 (nmp
->nm_fsattr
.nfsa_space_total
/ bsize
) -
570 (nmp
->nm_fsattr
.nfsa_space_free
/ bsize
));
571 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_FILES_TOTAL
))
572 VFSATTR_RETURN(fsap
, f_files
, nmp
->nm_fsattr
.nfsa_files_total
);
573 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_FILES_FREE
))
574 VFSATTR_RETURN(fsap
, f_ffree
, nmp
->nm_fsattr
.nfsa_files_free
);
575 lck_mtx_unlock(&nmp
->nm_lock
);
578 if (VFSATTR_IS_ACTIVE(fsap
, f_capabilities
)) {
579 u_int32_t caps
, valid
;
580 nfsnode_t np
= nmp
->nm_dnp
;
582 nfsm_assert(error
, VFSTONFS(mp
) && np
, ENXIO
);
585 lck_mtx_lock(&nmp
->nm_lock
);
588 * The capabilities[] array defines what this volume supports.
590 * The valid[] array defines which bits this code understands
591 * the meaning of (whether the volume has that capability or not).
592 * Any zero bits here means "I don't know what you're asking about"
593 * and the caller cannot tell whether that capability is
597 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SYMLINK_SUPPORT
)) {
598 valid
|= VOL_CAP_FMT_SYMBOLICLINKS
;
599 if (nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_SYMLINK
)
600 caps
|= VOL_CAP_FMT_SYMBOLICLINKS
;
602 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_LINK_SUPPORT
)) {
603 valid
|= VOL_CAP_FMT_HARDLINKS
;
604 if (nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_LINK
)
605 caps
|= VOL_CAP_FMT_HARDLINKS
;
607 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_CASE_INSENSITIVE
)) {
608 valid
|= VOL_CAP_FMT_CASE_SENSITIVE
;
609 if (!(nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_CASE_INSENSITIVE
))
610 caps
|= VOL_CAP_FMT_CASE_SENSITIVE
;
612 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_CASE_PRESERVING
)) {
613 valid
|= VOL_CAP_FMT_CASE_PRESERVING
;
614 if (nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_CASE_PRESERVING
)
615 caps
|= VOL_CAP_FMT_CASE_PRESERVING
;
617 /* Note: VOL_CAP_FMT_2TB_FILESIZE is actually used to test for "large file support" */
618 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXFILESIZE
)) {
619 /* Is server's max file size at least 4GB? */
620 if (nmp
->nm_fsattr
.nfsa_maxfilesize
>= 0x100000000ULL
)
621 caps
|= VOL_CAP_FMT_2TB_FILESIZE
;
622 } else if (nfsvers
>= NFS_VER3
) {
624 * NFSv3 and up supports 64 bits of file size.
625 * So, we'll just assume maxfilesize >= 4GB
627 caps
|= VOL_CAP_FMT_2TB_FILESIZE
;
629 if (nfsvers
>= NFS_VER4
) {
630 caps
|= VOL_CAP_FMT_HIDDEN_FILES
;
631 valid
|= VOL_CAP_FMT_HIDDEN_FILES
;
632 // VOL_CAP_FMT_OPENDENYMODES
633 // caps |= VOL_CAP_FMT_OPENDENYMODES;
634 // valid |= VOL_CAP_FMT_OPENDENYMODES;
636 fsap
->f_capabilities
.capabilities
[VOL_CAPABILITIES_FORMAT
] =
637 // VOL_CAP_FMT_PERSISTENTOBJECTIDS |
638 // VOL_CAP_FMT_SYMBOLICLINKS |
639 // VOL_CAP_FMT_HARDLINKS |
640 // VOL_CAP_FMT_JOURNAL |
641 // VOL_CAP_FMT_JOURNAL_ACTIVE |
642 // VOL_CAP_FMT_NO_ROOT_TIMES |
643 // VOL_CAP_FMT_SPARSE_FILES |
644 // VOL_CAP_FMT_ZERO_RUNS |
645 // VOL_CAP_FMT_CASE_SENSITIVE |
646 // VOL_CAP_FMT_CASE_PRESERVING |
647 // VOL_CAP_FMT_FAST_STATFS |
648 // VOL_CAP_FMT_2TB_FILESIZE |
649 // VOL_CAP_FMT_OPENDENYMODES |
650 // VOL_CAP_FMT_HIDDEN_FILES |
652 fsap
->f_capabilities
.valid
[VOL_CAPABILITIES_FORMAT
] =
653 VOL_CAP_FMT_PERSISTENTOBJECTIDS
|
654 // VOL_CAP_FMT_SYMBOLICLINKS |
655 // VOL_CAP_FMT_HARDLINKS |
656 // VOL_CAP_FMT_JOURNAL |
657 // VOL_CAP_FMT_JOURNAL_ACTIVE |
658 // VOL_CAP_FMT_NO_ROOT_TIMES |
659 // VOL_CAP_FMT_SPARSE_FILES |
660 // VOL_CAP_FMT_ZERO_RUNS |
661 // VOL_CAP_FMT_CASE_SENSITIVE |
662 // VOL_CAP_FMT_CASE_PRESERVING |
663 VOL_CAP_FMT_FAST_STATFS
|
664 VOL_CAP_FMT_2TB_FILESIZE
|
665 // VOL_CAP_FMT_OPENDENYMODES |
666 // VOL_CAP_FMT_HIDDEN_FILES |
670 * We don't support most of the interfaces.
672 * We MAY support locking, but we don't have any easy way of probing.
673 * We can tell if there's no lockd running or if locks have been
674 * disabled for a mount, so we can definitely answer NO in that case.
675 * Any attempt to send a request to lockd to test for locking support
676 * may cause the lazily-launched locking daemons to be started
677 * unnecessarily. So we avoid that. However, we do record if we ever
678 * successfully perform a lock operation on a mount point, so if it
679 * looks like lock ops have worked, we do report that we support them.
682 if (nfsvers
>= NFS_VER4
) {
683 caps
= VOL_CAP_INT_ADVLOCK
| VOL_CAP_INT_FLOCK
;
684 valid
= VOL_CAP_INT_ADVLOCK
| VOL_CAP_INT_FLOCK
;
685 if (nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_ACL
)
686 caps
|= VOL_CAP_INT_EXTENDED_SECURITY
;
687 valid
|= VOL_CAP_INT_EXTENDED_SECURITY
;
688 if (nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_NAMED_ATTR
)
689 caps
|= VOL_CAP_INT_EXTENDED_ATTR
;
690 valid
|= VOL_CAP_INT_EXTENDED_ATTR
;
692 if (nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_NAMED_ATTR
)
693 caps
|= VOL_CAP_INT_NAMEDSTREAMS
;
694 valid
|= VOL_CAP_INT_NAMEDSTREAMS
;
696 } else if (nmp
->nm_lockmode
== NFS_LOCK_MODE_DISABLED
) {
697 /* locks disabled on this mount, so they definitely won't work */
698 valid
= VOL_CAP_INT_ADVLOCK
| VOL_CAP_INT_FLOCK
;
699 } else if (nmp
->nm_state
& NFSSTA_LOCKSWORK
) {
700 caps
= VOL_CAP_INT_ADVLOCK
| VOL_CAP_INT_FLOCK
;
701 valid
= VOL_CAP_INT_ADVLOCK
| VOL_CAP_INT_FLOCK
;
703 fsap
->f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] =
704 // VOL_CAP_INT_SEARCHFS |
705 // VOL_CAP_INT_ATTRLIST |
706 // VOL_CAP_INT_NFSEXPORT |
707 // VOL_CAP_INT_READDIRATTR |
708 // VOL_CAP_INT_EXCHANGEDATA |
709 // VOL_CAP_INT_COPYFILE |
710 // VOL_CAP_INT_ALLOCATE |
711 // VOL_CAP_INT_VOL_RENAME |
712 // VOL_CAP_INT_ADVLOCK |
713 // VOL_CAP_INT_FLOCK |
714 // VOL_CAP_INT_EXTENDED_SECURITY |
715 // VOL_CAP_INT_USERACCESS |
716 // VOL_CAP_INT_MANLOCK |
717 // VOL_CAP_INT_NAMEDSTREAMS |
718 // VOL_CAP_INT_EXTENDED_ATTR |
719 VOL_CAP_INT_REMOTE_EVENT
|
721 fsap
->f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] =
722 VOL_CAP_INT_SEARCHFS
|
723 VOL_CAP_INT_ATTRLIST
|
724 VOL_CAP_INT_NFSEXPORT
|
725 VOL_CAP_INT_READDIRATTR
|
726 VOL_CAP_INT_EXCHANGEDATA
|
727 VOL_CAP_INT_COPYFILE
|
728 VOL_CAP_INT_ALLOCATE
|
729 VOL_CAP_INT_VOL_RENAME
|
730 // VOL_CAP_INT_ADVLOCK |
731 // VOL_CAP_INT_FLOCK |
732 // VOL_CAP_INT_EXTENDED_SECURITY |
733 // VOL_CAP_INT_USERACCESS |
734 // VOL_CAP_INT_MANLOCK |
735 // VOL_CAP_INT_NAMEDSTREAMS |
736 // VOL_CAP_INT_EXTENDED_ATTR |
737 VOL_CAP_INT_REMOTE_EVENT
|
740 fsap
->f_capabilities
.capabilities
[VOL_CAPABILITIES_RESERVED1
] = 0;
741 fsap
->f_capabilities
.valid
[VOL_CAPABILITIES_RESERVED1
] = 0;
743 fsap
->f_capabilities
.capabilities
[VOL_CAPABILITIES_RESERVED2
] = 0;
744 fsap
->f_capabilities
.valid
[VOL_CAPABILITIES_RESERVED2
] = 0;
746 VFSATTR_SET_SUPPORTED(fsap
, f_capabilities
);
747 lck_mtx_unlock(&nmp
->nm_lock
);
750 if (VFSATTR_IS_ACTIVE(fsap
, f_attributes
)) {
751 fsap
->f_attributes
.validattr
.commonattr
= 0;
752 fsap
->f_attributes
.validattr
.volattr
=
753 ATTR_VOL_CAPABILITIES
| ATTR_VOL_ATTRIBUTES
;
754 fsap
->f_attributes
.validattr
.dirattr
= 0;
755 fsap
->f_attributes
.validattr
.fileattr
= 0;
756 fsap
->f_attributes
.validattr
.forkattr
= 0;
758 fsap
->f_attributes
.nativeattr
.commonattr
= 0;
759 fsap
->f_attributes
.nativeattr
.volattr
=
760 ATTR_VOL_CAPABILITIES
| ATTR_VOL_ATTRIBUTES
;
761 fsap
->f_attributes
.nativeattr
.dirattr
= 0;
762 fsap
->f_attributes
.nativeattr
.fileattr
= 0;
763 fsap
->f_attributes
.nativeattr
.forkattr
= 0;
765 VFSATTR_SET_SUPPORTED(fsap
, f_attributes
);
772 * nfs version 3 fsinfo rpc call
775 nfs3_fsinfo(struct nfsmount
*nmp
, nfsnode_t np
, vfs_context_t ctx
)
777 int error
= 0, lockerror
, status
, nmlocked
= 0;
779 uint32_t val
, prefsize
, maxsize
;
780 struct nfsm_chain nmreq
, nmrep
;
782 nfsm_chain_null(&nmreq
);
783 nfsm_chain_null(&nmrep
);
785 nfsm_chain_build_alloc_init(error
, &nmreq
, NFSX_FH(nmp
->nm_vers
));
786 nfsm_chain_add_fh(error
, &nmreq
, nmp
->nm_vers
, np
->n_fhp
, np
->n_fhsize
);
787 nfsm_chain_build_done(error
, &nmreq
);
789 error
= nfs_request(np
, NULL
, &nmreq
, NFSPROC_FSINFO
, ctx
, NULL
, &nmrep
, &xid
, &status
);
790 if ((lockerror
= nfs_node_lock(np
)))
792 nfsm_chain_postop_attr_update(error
, &nmrep
, np
, &xid
);
799 lck_mtx_lock(&nmp
->nm_lock
);
802 nfsm_chain_get_32(error
, &nmrep
, maxsize
);
803 nfsm_chain_get_32(error
, &nmrep
, prefsize
);
805 nmp
->nm_fsattr
.nfsa_maxread
= maxsize
;
806 if (prefsize
< nmp
->nm_rsize
)
807 nmp
->nm_rsize
= (prefsize
+ NFS_FABLKSIZE
- 1) &
808 ~(NFS_FABLKSIZE
- 1);
809 if ((maxsize
> 0) && (maxsize
< nmp
->nm_rsize
)) {
810 nmp
->nm_rsize
= maxsize
& ~(NFS_FABLKSIZE
- 1);
811 if (nmp
->nm_rsize
== 0)
812 nmp
->nm_rsize
= maxsize
;
814 nfsm_chain_adv(error
, &nmrep
, NFSX_UNSIGNED
); // skip rtmult
816 nfsm_chain_get_32(error
, &nmrep
, maxsize
);
817 nfsm_chain_get_32(error
, &nmrep
, prefsize
);
819 nmp
->nm_fsattr
.nfsa_maxwrite
= maxsize
;
820 if (prefsize
< nmp
->nm_wsize
)
821 nmp
->nm_wsize
= (prefsize
+ NFS_FABLKSIZE
- 1) &
822 ~(NFS_FABLKSIZE
- 1);
823 if ((maxsize
> 0) && (maxsize
< nmp
->nm_wsize
)) {
824 nmp
->nm_wsize
= maxsize
& ~(NFS_FABLKSIZE
- 1);
825 if (nmp
->nm_wsize
== 0)
826 nmp
->nm_wsize
= maxsize
;
828 nfsm_chain_adv(error
, &nmrep
, NFSX_UNSIGNED
); // skip wtmult
830 nfsm_chain_get_32(error
, &nmrep
, prefsize
);
832 if ((prefsize
> 0) && (prefsize
< nmp
->nm_readdirsize
))
833 nmp
->nm_readdirsize
= prefsize
;
834 if ((nmp
->nm_fsattr
.nfsa_maxread
> 0) &&
835 (nmp
->nm_fsattr
.nfsa_maxread
< nmp
->nm_readdirsize
))
836 nmp
->nm_readdirsize
= nmp
->nm_fsattr
.nfsa_maxread
;
838 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_maxfilesize
);
840 nfsm_chain_adv(error
, &nmrep
, 2 * NFSX_UNSIGNED
); // skip time_delta
842 /* convert FS properties to our own flags */
843 nfsm_chain_get_32(error
, &nmrep
, val
);
845 if (val
& NFSV3FSINFO_LINK
)
846 nmp
->nm_fsattr
.nfsa_flags
|= NFS_FSFLAG_LINK
;
847 if (val
& NFSV3FSINFO_SYMLINK
)
848 nmp
->nm_fsattr
.nfsa_flags
|= NFS_FSFLAG_SYMLINK
;
849 if (val
& NFSV3FSINFO_HOMOGENEOUS
)
850 nmp
->nm_fsattr
.nfsa_flags
|= NFS_FSFLAG_HOMOGENEOUS
;
851 if (val
& NFSV3FSINFO_CANSETTIME
)
852 nmp
->nm_fsattr
.nfsa_flags
|= NFS_FSFLAG_SET_TIME
;
853 nmp
->nm_state
|= NFSSTA_GOTFSINFO
;
854 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXREAD
);
855 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXWRITE
);
856 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXFILESIZE
);
857 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_LINK_SUPPORT
);
858 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SYMLINK_SUPPORT
);
859 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_HOMOGENEOUS
);
860 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_CANSETTIME
);
863 lck_mtx_unlock(&nmp
->nm_lock
);
864 nfsm_chain_cleanup(&nmreq
);
865 nfsm_chain_cleanup(&nmrep
);
870 * Mount a remote root fs via. nfs. This depends on the info in the
871 * nfs_diskless structure that has been filled in properly by some primary
873 * It goes something like this:
874 * - do enough of "ifconfig" by calling ifioctl() so that the system
875 * can talk to the server
876 * - If nfs_diskless.mygateway is filled in, use that address as
878 * - hand craft the swap nfs vnode hanging off a fake mount point
879 * if swdevt[0].sw_dev == NODEV
880 * - build the rootfs mount point and call mountnfs() to do the rest.
885 struct nfs_diskless nd
;
890 #if !defined(NO_MOUNT_PRIVATE)
891 mount_t mppriv
= NULL
;
892 vnode_t vppriv
= NULL
;
893 #endif /* NO_MOUNT_PRIVATE */
897 * Call nfs_boot_init() to fill in the nfs_diskless struct.
898 * Note: networking must already have been configured before
901 bzero((caddr_t
) &nd
, sizeof(nd
));
902 error
= nfs_boot_init(&nd
);
904 panic("nfs_boot_init: unable to initialize NFS root system information, "
905 "error %d, check configuration: %s\n", error
, PE_boot_args());
908 * Try NFSv3 first, then fallback to NFSv2.
909 * Likewise, try TCP first, then fall back to UDP.
912 sotype
= SOCK_STREAM
;
915 error
= nfs_boot_getfh(&nd
, v3
, sotype
);
917 if (error
== EHOSTDOWN
|| error
== EHOSTUNREACH
) {
918 if (nd
.nd_root
.ndm_mntfrom
)
919 FREE_ZONE(nd
.nd_root
.ndm_mntfrom
,
920 MAXPATHLEN
, M_NAMEI
);
921 if (nd
.nd_root
.ndm_path
)
922 FREE_ZONE(nd
.nd_root
.ndm_path
,
923 MAXPATHLEN
, M_NAMEI
);
924 if (nd
.nd_private
.ndm_mntfrom
)
925 FREE_ZONE(nd
.nd_private
.ndm_mntfrom
,
926 MAXPATHLEN
, M_NAMEI
);
927 if (nd
.nd_private
.ndm_path
)
928 FREE_ZONE(nd
.nd_private
.ndm_path
,
929 MAXPATHLEN
, M_NAMEI
);
933 if (sotype
== SOCK_STREAM
) {
934 printf("NFS mount (v3,TCP) failed with error %d, trying UDP...\n", error
);
938 printf("NFS mount (v3,UDP) failed with error %d, trying v2...\n", error
);
940 sotype
= SOCK_STREAM
;
942 } else if (sotype
== SOCK_STREAM
) {
943 printf("NFS mount (v2,TCP) failed with error %d, trying UDP...\n", error
);
947 printf("NFS mount (v2,UDP) failed with error %d, giving up...\n", error
);
951 panic("NFS mount failed: NFS server mountd not responding, check server configuration: %s", PE_boot_args());
954 panic("NFS mount failed: NFS server refused mount, check server configuration: %s", PE_boot_args());
956 panic("NFS mount failed with error %d, check configuration: %s", error
, PE_boot_args());
960 ctx
= vfs_context_kernel();
963 * Create the root mount point.
965 #if !defined(NO_MOUNT_PRIVATE)
967 //PWC hack until we have a real "mount" tool to remount root rw
969 int flags
= MNT_ROOTFS
|MNT_RDONLY
;
970 PE_parse_boot_argn("-rwroot_hack", &rw_root
, sizeof (rw_root
));
974 kprintf("-rwroot_hack in effect: mounting root fs read/write\n");
977 if ((error
= nfs_mount_diskless(&nd
.nd_root
, "/", flags
, &vp
, &mp
, ctx
)))
979 if ((error
= nfs_mount_diskless(&nd
.nd_root
, "/", MNT_ROOTFS
, &vp
, &mp
, ctx
)))
980 #endif /* NO_MOUNT_PRIVATE */
983 if (sotype
== SOCK_STREAM
) {
984 printf("NFS root mount (v3,TCP) failed with %d, trying UDP...\n", error
);
988 printf("NFS root mount (v3,UDP) failed with %d, trying v2...\n", error
);
990 sotype
= SOCK_STREAM
;
992 } else if (sotype
== SOCK_STREAM
) {
993 printf("NFS root mount (v2,TCP) failed with %d, trying UDP...\n", error
);
997 printf("NFS root mount (v2,UDP) failed with error %d, giving up...\n", error
);
999 panic("NFS root mount failed with error %d, check configuration: %s\n", error
, PE_boot_args());
1002 printf("root on %s\n", nd
.nd_root
.ndm_mntfrom
);
1008 #if !defined(NO_MOUNT_PRIVATE)
1009 if (nd
.nd_private
.ndm_saddr
.sin_addr
.s_addr
) {
1010 error
= nfs_mount_diskless_private(&nd
.nd_private
, "/private",
1011 0, &vppriv
, &mppriv
, ctx
);
1013 panic("NFS /private mount failed with error %d, check configuration: %s\n", error
, PE_boot_args());
1014 printf("private on %s\n", nd
.nd_private
.ndm_mntfrom
);
1017 mount_list_add(mppriv
);
1020 #endif /* NO_MOUNT_PRIVATE */
1022 if (nd
.nd_root
.ndm_mntfrom
)
1023 FREE_ZONE(nd
.nd_root
.ndm_mntfrom
, MAXPATHLEN
, M_NAMEI
);
1024 if (nd
.nd_root
.ndm_path
)
1025 FREE_ZONE(nd
.nd_root
.ndm_path
, MAXPATHLEN
, M_NAMEI
);
1026 if (nd
.nd_private
.ndm_mntfrom
)
1027 FREE_ZONE(nd
.nd_private
.ndm_mntfrom
, MAXPATHLEN
, M_NAMEI
);
1028 if (nd
.nd_private
.ndm_path
)
1029 FREE_ZONE(nd
.nd_private
.ndm_path
, MAXPATHLEN
, M_NAMEI
);
1031 /* Get root attributes (for the time). */
1032 error
= nfs_getattr(VTONFS(vp
), NULL
, ctx
, NGA_UNCACHED
);
1034 panic("NFS mount: failed to get attributes for root directory, error %d, check server", error
);
1039 * Internal version of mount system call for diskless setup.
1043 struct nfs_dlmount
*ndmntp
,
1044 const char *mntname
,
1051 int error
, numcomps
;
1052 char *xdrbuf
, *p
, *cp
, *frompath
, *endserverp
;
1053 char uaddr
[MAX_IPv4_STR_LEN
];
1055 uint32_t mattrs
[NFS_MATTR_BITMAP_LEN
];
1056 uint32_t mflags_mask
[NFS_MFLAG_BITMAP_LEN
];
1057 uint32_t mflags
[NFS_MFLAG_BITMAP_LEN
];
1058 uint32_t argslength_offset
, attrslength_offset
, end_offset
;
1060 if ((error
= vfs_rootmountalloc("nfs", ndmntp
->ndm_mntfrom
, &mp
))) {
1061 printf("nfs_mount_diskless: NFS not configured\n");
1065 mp
->mnt_flag
|= mntflag
;
1066 if (!(mntflag
& MNT_RDONLY
))
1067 mp
->mnt_flag
&= ~MNT_RDONLY
;
1069 /* find the server-side path being mounted */
1070 frompath
= ndmntp
->ndm_mntfrom
;
1071 if (*frompath
== '[') { /* skip IPv6 literal address */
1072 while (*frompath
&& (*frompath
!= ']'))
1074 if (*frompath
== ']')
1077 while (*frompath
&& (*frompath
!= ':'))
1079 endserverp
= frompath
;
1080 while (*frompath
&& (*frompath
== ':'))
1082 /* count fs location path components */
1084 while (*p
&& (*p
== '/'))
1089 while (*p
&& (*p
!= '/'))
1091 while (*p
&& (*p
== '/'))
1095 /* convert address to universal address string */
1096 if (inet_ntop(AF_INET
, &ndmntp
->ndm_saddr
.sin_addr
, uaddr
, sizeof(uaddr
)) != uaddr
) {
1097 printf("nfs_mount_diskless: bad address\n");
1101 /* prepare mount attributes */
1102 NFS_BITMAP_ZERO(mattrs
, NFS_MATTR_BITMAP_LEN
);
1103 NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_VERSION
);
1104 NFS_BITMAP_SET(mattrs
, NFS_MATTR_SOCKET_TYPE
);
1105 NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_PORT
);
1106 NFS_BITMAP_SET(mattrs
, NFS_MATTR_FH
);
1107 NFS_BITMAP_SET(mattrs
, NFS_MATTR_FS_LOCATIONS
);
1108 NFS_BITMAP_SET(mattrs
, NFS_MATTR_MNTFLAGS
);
1110 /* prepare mount flags */
1111 NFS_BITMAP_ZERO(mflags_mask
, NFS_MFLAG_BITMAP_LEN
);
1112 NFS_BITMAP_ZERO(mflags
, NFS_MFLAG_BITMAP_LEN
);
1113 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_RESVPORT
);
1114 NFS_BITMAP_SET(mflags
, NFS_MFLAG_RESVPORT
);
1116 /* build xdr buffer */
1117 xb_init_buffer(&xb
, NULL
, 0);
1118 xb_add_32(error
, &xb
, NFS_ARGSVERSION_XDR
);
1119 argslength_offset
= xb_offset(&xb
);
1120 xb_add_32(error
, &xb
, 0); // args length
1121 xb_add_32(error
, &xb
, NFS_XDRARGS_VERSION_0
);
1122 xb_add_bitmap(error
, &xb
, mattrs
, NFS_MATTR_BITMAP_LEN
);
1123 attrslength_offset
= xb_offset(&xb
);
1124 xb_add_32(error
, &xb
, 0); // attrs length
1125 xb_add_32(error
, &xb
, ndmntp
->ndm_nfsv3
? 3 : 2); // NFS version
1126 xb_add_string(error
, &xb
, ((ndmntp
->ndm_sotype
== SOCK_DGRAM
) ? "udp" : "tcp"), 3);
1127 xb_add_32(error
, &xb
, ntohs(ndmntp
->ndm_saddr
.sin_port
)); // NFS port
1128 xb_add_fh(error
, &xb
, &ndmntp
->ndm_fh
[0], ndmntp
->ndm_fhlen
);
1130 xb_add_32(error
, &xb
, 1); /* fs location count */
1131 xb_add_32(error
, &xb
, 1); /* server count */
1132 xb_add_string(error
, &xb
, ndmntp
->ndm_mntfrom
, (endserverp
- ndmntp
->ndm_mntfrom
)); /* server name */
1133 xb_add_32(error
, &xb
, 1); /* address count */
1134 xb_add_string(error
, &xb
, uaddr
, strlen(uaddr
)); /* address */
1135 xb_add_32(error
, &xb
, 0); /* empty server info */
1136 xb_add_32(error
, &xb
, numcomps
); /* pathname component count */
1138 while (*p
&& (*p
== '/'))
1142 while (*p
&& (*p
!= '/'))
1144 xb_add_string(error
, &xb
, cp
, (p
- cp
)); /* component */
1147 while (*p
&& (*p
== '/'))
1150 xb_add_32(error
, &xb
, 0); /* empty fsl info */
1151 xb_add_32(error
, &xb
, mntflag
); /* MNT flags */
1152 xb_build_done(error
, &xb
);
1154 /* update opaque counts */
1155 end_offset
= xb_offset(&xb
);
1157 error
= xb_seek(&xb
, argslength_offset
);
1158 xb_add_32(error
, &xb
, end_offset
- argslength_offset
+ XDRWORD
/*version*/);
1161 error
= xb_seek(&xb
, attrslength_offset
);
1162 xb_add_32(error
, &xb
, end_offset
- attrslength_offset
- XDRWORD
/*don't include length field*/);
1165 printf("nfs_mount_diskless: error %d assembling mount args\n", error
);
1169 /* grab the assembled buffer */
1170 xdrbuf
= xb_buffer_base(&xb
);
1171 xb
.xb_flags
&= ~XB_CLEANUP
;
1174 if ((error
= mountnfs(xdrbuf
, mp
, ctx
, vpp
))) {
1175 printf("nfs_mountroot: mount %s failed: %d\n", mntname
, error
);
1176 // XXX vfs_rootmountfailed(mp);
1178 mp
->mnt_vtable
->vfc_refcount
--;
1179 mount_list_unlock();
1181 mount_lock_destroy(mp
);
1183 mac_mount_label_destroy(mp
);
1185 FREE_ZONE(mp
, sizeof(struct mount
), M_MOUNT
);
1193 #if !defined(NO_MOUNT_PRIVATE)
1195 * Internal version of mount system call to mount "/private"
1196 * separately in diskless setup
1199 nfs_mount_diskless_private(
1200 struct nfs_dlmount
*ndmntp
,
1201 const char *mntname
,
1208 int error
, numcomps
;
1210 struct vfstable
*vfsp
;
1211 struct nameidata nd
;
1213 char *xdrbuf
= NULL
, *p
, *cp
, *frompath
, *endserverp
;
1214 char uaddr
[MAX_IPv4_STR_LEN
];
1216 uint32_t mattrs
[NFS_MATTR_BITMAP_LEN
];
1217 uint32_t mflags_mask
[NFS_MFLAG_BITMAP_LEN
], mflags
[NFS_MFLAG_BITMAP_LEN
];
1218 uint32_t argslength_offset
, attrslength_offset
, end_offset
;
1220 procp
= current_proc(); /* XXX */
1225 * mimic main()!. Temporarily set up rootvnode and other stuff so
1226 * that namei works. Need to undo this because main() does it, too
1228 struct filedesc
*fdp
; /* pointer to file descriptor state */
1230 mountlist
.tqh_first
->mnt_flag
|= MNT_ROOTFS
;
1232 /* Get the vnode for '/'. Set fdp->fd_cdir to reference it. */
1233 if (VFS_ROOT(mountlist
.tqh_first
, &rootvnode
, NULL
))
1234 panic("cannot find root vnode");
1235 error
= vnode_ref(rootvnode
);
1237 printf("nfs_mountroot: vnode_ref() failed on root vnode!\n");
1240 fdp
->fd_cdir
= rootvnode
;
1241 fdp
->fd_rdir
= NULL
;
1245 * Get vnode to be covered
1247 NDINIT(&nd
, LOOKUP
, OP_LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_SYSSPACE
,
1248 CAST_USER_ADDR_T(mntname
), ctx
);
1249 if ((error
= namei(&nd
))) {
1250 printf("nfs_mountroot: private namei failed!\n");
1254 /* undo vnode_ref() in mimic main()! */
1255 vnode_rele(rootvnode
);
1260 if ((error
= VNOP_FSYNC(vp
, MNT_WAIT
, ctx
)) ||
1261 (error
= buf_invalidateblks(vp
, BUF_WRITE_DATA
, 0, 0))) {
1265 if (vnode_vtype(vp
) != VDIR
) {
1270 for (vfsp
= vfsconf
; vfsp
; vfsp
= vfsp
->vfc_next
)
1271 if (!strncmp(vfsp
->vfc_name
, "nfs", sizeof(vfsp
->vfc_name
)))
1274 printf("nfs_mountroot: private NFS not configured\n");
1279 if (vnode_mountedhere(vp
) != NULL
) {
1286 * Allocate and initialize the filesystem.
1288 mp
= _MALLOC_ZONE((u_int32_t
)sizeof(struct mount
), M_MOUNT
, M_WAITOK
);
1290 printf("nfs_mountroot: unable to allocate mount structure\n");
1295 bzero((char *)mp
, sizeof(struct mount
));
1297 /* Initialize the default IO constraints */
1298 mp
->mnt_maxreadcnt
= mp
->mnt_maxwritecnt
= MAXPHYS
;
1299 mp
->mnt_segreadcnt
= mp
->mnt_segwritecnt
= 32;
1300 mp
->mnt_ioflags
= 0;
1301 mp
->mnt_realrootvp
= NULLVP
;
1302 mp
->mnt_authcache_ttl
= CACHED_LOOKUP_RIGHT_TTL
;
1304 mount_lock_init(mp
);
1305 TAILQ_INIT(&mp
->mnt_vnodelist
);
1306 TAILQ_INIT(&mp
->mnt_workerqueue
);
1307 TAILQ_INIT(&mp
->mnt_newvnodes
);
1308 (void)vfs_busy(mp
, LK_NOWAIT
);
1309 TAILQ_INIT(&mp
->mnt_vnodelist
);
1311 vfsp
->vfc_refcount
++;
1312 mount_list_unlock();
1313 mp
->mnt_vtable
= vfsp
;
1314 mp
->mnt_op
= vfsp
->vfc_vfsops
;
1315 // mp->mnt_stat.f_type = vfsp->vfc_typenum;
1316 mp
->mnt_flag
= mntflag
;
1317 mp
->mnt_flag
|= vfsp
->vfc_flags
& MNT_VISFLAGMASK
;
1318 strncpy(mp
->mnt_vfsstat
.f_fstypename
, vfsp
->vfc_name
, MFSNAMELEN
-1);
1319 vp
->v_mountedhere
= mp
;
1320 mp
->mnt_vnodecovered
= vp
;
1322 mp
->mnt_vfsstat
.f_owner
= kauth_cred_getuid(kauth_cred_get());
1323 (void) copystr(mntname
, mp
->mnt_vfsstat
.f_mntonname
, MAXPATHLEN
- 1, 0);
1324 (void) copystr(ndmntp
->ndm_mntfrom
, mp
->mnt_vfsstat
.f_mntfromname
, MAXPATHLEN
- 1, 0);
1326 mac_mount_label_init(mp
);
1327 mac_mount_label_associate(ctx
, mp
);
1330 /* find the server-side path being mounted */
1331 frompath
= ndmntp
->ndm_mntfrom
;
1332 if (*frompath
== '[') { /* skip IPv6 literal address */
1333 while (*frompath
&& (*frompath
!= ']'))
1335 if (*frompath
== ']')
1338 while (*frompath
&& (*frompath
!= ':'))
1340 endserverp
= frompath
;
1341 while (*frompath
&& (*frompath
== ':'))
1343 /* count fs location path components */
1345 while (*p
&& (*p
== '/'))
1350 while (*p
&& (*p
!= '/'))
1352 while (*p
&& (*p
== '/'))
1356 /* convert address to universal address string */
1357 if (inet_ntop(AF_INET
, &ndmntp
->ndm_saddr
.sin_addr
, uaddr
, sizeof(uaddr
)) != uaddr
) {
1358 printf("nfs_mountroot: bad address\n");
1363 /* prepare mount attributes */
1364 NFS_BITMAP_ZERO(mattrs
, NFS_MATTR_BITMAP_LEN
);
1365 NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_VERSION
);
1366 NFS_BITMAP_SET(mattrs
, NFS_MATTR_SOCKET_TYPE
);
1367 NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_PORT
);
1368 NFS_BITMAP_SET(mattrs
, NFS_MATTR_FH
);
1369 NFS_BITMAP_SET(mattrs
, NFS_MATTR_FS_LOCATIONS
);
1370 NFS_BITMAP_SET(mattrs
, NFS_MATTR_MNTFLAGS
);
1372 /* prepare mount flags */
1373 NFS_BITMAP_ZERO(mflags_mask
, NFS_MFLAG_BITMAP_LEN
);
1374 NFS_BITMAP_ZERO(mflags
, NFS_MFLAG_BITMAP_LEN
);
1375 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_RESVPORT
);
1376 NFS_BITMAP_SET(mflags
, NFS_MFLAG_RESVPORT
);
1378 /* build xdr buffer */
1379 xb_init_buffer(&xb
, NULL
, 0);
1380 xb_add_32(error
, &xb
, NFS_ARGSVERSION_XDR
);
1381 argslength_offset
= xb_offset(&xb
);
1382 xb_add_32(error
, &xb
, 0); // args length
1383 xb_add_32(error
, &xb
, NFS_XDRARGS_VERSION_0
);
1384 xb_add_bitmap(error
, &xb
, mattrs
, NFS_MATTR_BITMAP_LEN
);
1385 attrslength_offset
= xb_offset(&xb
);
1386 xb_add_32(error
, &xb
, 0); // attrs length
1387 xb_add_32(error
, &xb
, ndmntp
->ndm_nfsv3
? 3 : 2); // NFS version
1388 xb_add_string(error
, &xb
, ((ndmntp
->ndm_sotype
== SOCK_DGRAM
) ? "udp" : "tcp"), 3);
1389 xb_add_32(error
, &xb
, ntohs(ndmntp
->ndm_saddr
.sin_port
)); // NFS port
1390 xb_add_fh(error
, &xb
, &ndmntp
->ndm_fh
[0], ndmntp
->ndm_fhlen
);
1392 xb_add_32(error
, &xb
, 1); /* fs location count */
1393 xb_add_32(error
, &xb
, 1); /* server count */
1394 xb_add_string(error
, &xb
, ndmntp
->ndm_mntfrom
, (endserverp
- ndmntp
->ndm_mntfrom
)); /* server name */
1395 xb_add_32(error
, &xb
, 1); /* address count */
1396 xb_add_string(error
, &xb
, uaddr
, strlen(uaddr
)); /* address */
1397 xb_add_32(error
, &xb
, 0); /* empty server info */
1398 xb_add_32(error
, &xb
, numcomps
); /* pathname component count */
1400 while (*p
&& (*p
== '/'))
1404 while (*p
&& (*p
!= '/'))
1406 xb_add_string(error
, &xb
, cp
, (p
- cp
)); /* component */
1409 while (*p
&& (*p
== '/'))
1412 xb_add_32(error
, &xb
, 0); /* empty fsl info */
1413 xb_add_32(error
, &xb
, mntflag
); /* MNT flags */
1414 xb_build_done(error
, &xb
);
1416 /* update opaque counts */
1417 end_offset
= xb_offset(&xb
);
1419 error
= xb_seek(&xb
, argslength_offset
);
1420 xb_add_32(error
, &xb
, end_offset
- argslength_offset
+ XDRWORD
/*version*/);
1423 error
= xb_seek(&xb
, attrslength_offset
);
1424 xb_add_32(error
, &xb
, end_offset
- attrslength_offset
- XDRWORD
/*don't include length field*/);
1427 printf("nfs_mountroot: error %d assembling mount args\n", error
);
1430 /* grab the assembled buffer */
1431 xdrbuf
= xb_buffer_base(&xb
);
1432 xb
.xb_flags
&= ~XB_CLEANUP
;
1435 if ((error
= mountnfs(xdrbuf
, mp
, ctx
, &vp
))) {
1436 printf("nfs_mountroot: mount %s failed: %d\n", mntname
, error
);
1437 vnode_put(mp
->mnt_vnodecovered
);
1439 vfsp
->vfc_refcount
--;
1440 mount_list_unlock();
1442 mount_lock_destroy(mp
);
1444 mac_mount_label_destroy(mp
);
1446 FREE_ZONE(mp
, sizeof (struct mount
), M_MOUNT
);
1456 #endif /* NO_MOUNT_PRIVATE */
1459 * Convert old style NFS mount args to XDR.
1462 nfs_convert_old_nfs_args(mount_t mp
, user_addr_t data
, vfs_context_t ctx
, int argsversion
, int inkernel
, char **xdrbufp
)
1464 int error
= 0, args64bit
, argsize
, numcomps
;
1465 struct user_nfs_args args
;
1466 struct nfs_args tempargs
;
1469 u_char nfh
[NFS4_FHSIZE
];
1470 char *mntfrom
, *endserverp
, *frompath
, *p
, *cp
;
1471 struct sockaddr_storage ss
;
1473 char uaddr
[MAX_IPv6_STR_LEN
];
1474 uint32_t mattrs
[NFS_MATTR_BITMAP_LEN
];
1475 uint32_t mflags_mask
[NFS_MFLAG_BITMAP_LEN
], mflags
[NFS_MFLAG_BITMAP_LEN
];
1476 uint32_t nfsvers
, nfslockmode
= 0, argslength_offset
, attrslength_offset
, end_offset
;
1481 /* allocate a temporary buffer for mntfrom */
1482 MALLOC_ZONE(mntfrom
, char*, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1486 args64bit
= (inkernel
|| vfs_context_is64bit(ctx
));
1487 argsp
= args64bit
? (void*)&args
: (void*)&tempargs
;
1489 argsize
= args64bit
? sizeof(args
) : sizeof(tempargs
);
1490 switch (argsversion
) {
1492 argsize
-= NFS_ARGSVERSION4_INCSIZE
;
1494 argsize
-= NFS_ARGSVERSION5_INCSIZE
;
1496 argsize
-= NFS_ARGSVERSION6_INCSIZE
;
1500 error
= EPROGMISMATCH
;
1504 /* read in the structure */
1506 bcopy(CAST_DOWN(void *, data
), argsp
, argsize
);
1508 error
= copyin(data
, argsp
, argsize
);
1512 args
.addrlen
= tempargs
.addrlen
;
1513 args
.sotype
= tempargs
.sotype
;
1514 args
.proto
= tempargs
.proto
;
1515 args
.fhsize
= tempargs
.fhsize
;
1516 args
.flags
= tempargs
.flags
;
1517 args
.wsize
= tempargs
.wsize
;
1518 args
.rsize
= tempargs
.rsize
;
1519 args
.readdirsize
= tempargs
.readdirsize
;
1520 args
.timeo
= tempargs
.timeo
;
1521 args
.retrans
= tempargs
.retrans
;
1522 args
.maxgrouplist
= tempargs
.maxgrouplist
;
1523 args
.readahead
= tempargs
.readahead
;
1524 args
.leaseterm
= tempargs
.leaseterm
;
1525 args
.deadthresh
= tempargs
.deadthresh
;
1526 args
.addr
= CAST_USER_ADDR_T(tempargs
.addr
);
1527 args
.fh
= CAST_USER_ADDR_T(tempargs
.fh
);
1528 args
.hostname
= CAST_USER_ADDR_T(tempargs
.hostname
);
1529 if (args
.version
>= 4) {
1530 args
.acregmin
= tempargs
.acregmin
;
1531 args
.acregmax
= tempargs
.acregmax
;
1532 args
.acdirmin
= tempargs
.acdirmin
;
1533 args
.acdirmax
= tempargs
.acdirmax
;
1535 if (args
.version
>= 5)
1536 args
.auth
= tempargs
.auth
;
1537 if (args
.version
>= 6)
1538 args
.deadtimeout
= tempargs
.deadtimeout
;
1541 if ((args
.fhsize
< 0) || (args
.fhsize
> NFS4_FHSIZE
)) {
1545 if (args
.fhsize
> 0) {
1547 bcopy(CAST_DOWN(void *, args
.fh
), (caddr_t
)nfh
, args
.fhsize
);
1549 error
= copyin(args
.fh
, (caddr_t
)nfh
, args
.fhsize
);
1554 error
= copystr(CAST_DOWN(void *, args
.hostname
), mntfrom
, MAXPATHLEN
-1, &len
);
1556 error
= copyinstr(args
.hostname
, mntfrom
, MAXPATHLEN
-1, &len
);
1558 bzero(&mntfrom
[len
], MAXPATHLEN
- len
);
1560 /* find the server-side path being mounted */
1562 if (*frompath
== '[') { /* skip IPv6 literal address */
1563 while (*frompath
&& (*frompath
!= ']'))
1565 if (*frompath
== ']')
1568 while (*frompath
&& (*frompath
!= ':'))
1570 endserverp
= frompath
;
1571 while (*frompath
&& (*frompath
== ':'))
1573 /* count fs location path components */
1575 while (*p
&& (*p
== '/'))
1580 while (*p
&& (*p
!= '/'))
1582 while (*p
&& (*p
== '/'))
1586 /* copy socket address */
1588 bcopy(CAST_DOWN(void *, args
.addr
), &ss
, args
.addrlen
);
1590 if ((size_t)args
.addrlen
> sizeof (struct sockaddr_storage
))
1593 error
= copyin(args
.addr
, &ss
, args
.addrlen
);
1596 ss
.ss_len
= args
.addrlen
;
1598 /* convert address to universal address string */
1599 if (ss
.ss_family
== AF_INET
)
1600 sinaddr
= &((struct sockaddr_in
*)&ss
)->sin_addr
;
1601 else if (ss
.ss_family
== AF_INET6
)
1602 sinaddr
= &((struct sockaddr_in6
*)&ss
)->sin6_addr
;
1605 if (!sinaddr
|| (inet_ntop(ss
.ss_family
, sinaddr
, uaddr
, sizeof(uaddr
)) != uaddr
)) {
1610 /* prepare mount flags */
1611 NFS_BITMAP_ZERO(mflags_mask
, NFS_MFLAG_BITMAP_LEN
);
1612 NFS_BITMAP_ZERO(mflags
, NFS_MFLAG_BITMAP_LEN
);
1613 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_SOFT
);
1614 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_INTR
);
1615 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_RESVPORT
);
1616 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NOCONNECT
);
1617 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_DUMBTIMER
);
1618 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_CALLUMNT
);
1619 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_RDIRPLUS
);
1620 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NONEGNAMECACHE
);
1621 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_MUTEJUKEBOX
);
1622 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NOQUOTA
);
1623 if (args
.flags
& NFSMNT_SOFT
)
1624 NFS_BITMAP_SET(mflags
, NFS_MFLAG_SOFT
);
1625 if (args
.flags
& NFSMNT_INT
)
1626 NFS_BITMAP_SET(mflags
, NFS_MFLAG_INTR
);
1627 if (args
.flags
& NFSMNT_RESVPORT
)
1628 NFS_BITMAP_SET(mflags
, NFS_MFLAG_RESVPORT
);
1629 if (args
.flags
& NFSMNT_NOCONN
)
1630 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NOCONNECT
);
1631 if (args
.flags
& NFSMNT_DUMBTIMR
)
1632 NFS_BITMAP_SET(mflags
, NFS_MFLAG_DUMBTIMER
);
1633 if (args
.flags
& NFSMNT_CALLUMNT
)
1634 NFS_BITMAP_SET(mflags
, NFS_MFLAG_CALLUMNT
);
1635 if (args
.flags
& NFSMNT_RDIRPLUS
)
1636 NFS_BITMAP_SET(mflags
, NFS_MFLAG_RDIRPLUS
);
1637 if (args
.flags
& NFSMNT_NONEGNAMECACHE
)
1638 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NONEGNAMECACHE
);
1639 if (args
.flags
& NFSMNT_MUTEJUKEBOX
)
1640 NFS_BITMAP_SET(mflags
, NFS_MFLAG_MUTEJUKEBOX
);
1641 if (args
.flags
& NFSMNT_NOQUOTA
)
1642 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NOQUOTA
);
1644 /* prepare mount attributes */
1645 NFS_BITMAP_ZERO(mattrs
, NFS_MATTR_BITMAP_LEN
);
1646 NFS_BITMAP_SET(mattrs
, NFS_MATTR_FLAGS
);
1647 NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_VERSION
);
1648 NFS_BITMAP_SET(mattrs
, NFS_MATTR_SOCKET_TYPE
);
1649 NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_PORT
);
1650 NFS_BITMAP_SET(mattrs
, NFS_MATTR_FH
);
1651 NFS_BITMAP_SET(mattrs
, NFS_MATTR_FS_LOCATIONS
);
1652 NFS_BITMAP_SET(mattrs
, NFS_MATTR_MNTFLAGS
);
1653 NFS_BITMAP_SET(mattrs
, NFS_MATTR_MNTFROM
);
1654 if (args
.flags
& NFSMNT_NFSV4
)
1656 else if (args
.flags
& NFSMNT_NFSV3
)
1660 if ((args
.flags
& NFSMNT_RSIZE
) && (args
.rsize
> 0))
1661 NFS_BITMAP_SET(mattrs
, NFS_MATTR_READ_SIZE
);
1662 if ((args
.flags
& NFSMNT_WSIZE
) && (args
.wsize
> 0))
1663 NFS_BITMAP_SET(mattrs
, NFS_MATTR_WRITE_SIZE
);
1664 if ((args
.flags
& NFSMNT_TIMEO
) && (args
.timeo
> 0))
1665 NFS_BITMAP_SET(mattrs
, NFS_MATTR_REQUEST_TIMEOUT
);
1666 if ((args
.flags
& NFSMNT_RETRANS
) && (args
.retrans
> 0))
1667 NFS_BITMAP_SET(mattrs
, NFS_MATTR_SOFT_RETRY_COUNT
);
1668 if ((args
.flags
& NFSMNT_MAXGRPS
) && (args
.maxgrouplist
> 0))
1669 NFS_BITMAP_SET(mattrs
, NFS_MATTR_MAX_GROUP_LIST
);
1670 if ((args
.flags
& NFSMNT_READAHEAD
) && (args
.readahead
> 0))
1671 NFS_BITMAP_SET(mattrs
, NFS_MATTR_READAHEAD
);
1672 if ((args
.flags
& NFSMNT_READDIRSIZE
) && (args
.readdirsize
> 0))
1673 NFS_BITMAP_SET(mattrs
, NFS_MATTR_READDIR_SIZE
);
1674 if ((args
.flags
& NFSMNT_NOLOCKS
) ||
1675 (args
.flags
& NFSMNT_LOCALLOCKS
)) {
1676 NFS_BITMAP_SET(mattrs
, NFS_MATTR_LOCK_MODE
);
1677 if (args
.flags
& NFSMNT_NOLOCKS
)
1678 nfslockmode
= NFS_LOCK_MODE_DISABLED
;
1679 else if (args
.flags
& NFSMNT_LOCALLOCKS
)
1680 nfslockmode
= NFS_LOCK_MODE_LOCAL
;
1682 nfslockmode
= NFS_LOCK_MODE_ENABLED
;
1684 if (args
.version
>= 4) {
1685 if ((args
.flags
& NFSMNT_ACREGMIN
) && (args
.acregmin
> 0))
1686 NFS_BITMAP_SET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MIN
);
1687 if ((args
.flags
& NFSMNT_ACREGMAX
) && (args
.acregmax
> 0))
1688 NFS_BITMAP_SET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MAX
);
1689 if ((args
.flags
& NFSMNT_ACDIRMIN
) && (args
.acdirmin
> 0))
1690 NFS_BITMAP_SET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MIN
);
1691 if ((args
.flags
& NFSMNT_ACDIRMAX
) && (args
.acdirmax
> 0))
1692 NFS_BITMAP_SET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MAX
);
1694 if (args
.version
>= 5) {
1695 if ((args
.flags
& NFSMNT_SECFLAVOR
) || (args
.flags
& NFSMNT_SECSYSOK
))
1696 NFS_BITMAP_SET(mattrs
, NFS_MATTR_SECURITY
);
1698 if (args
.version
>= 6) {
1699 if ((args
.flags
& NFSMNT_DEADTIMEOUT
) && (args
.deadtimeout
> 0))
1700 NFS_BITMAP_SET(mattrs
, NFS_MATTR_DEAD_TIMEOUT
);
1703 /* build xdr buffer */
1704 xb_init_buffer(&xb
, NULL
, 0);
1705 xb_add_32(error
, &xb
, args
.version
);
1706 argslength_offset
= xb_offset(&xb
);
1707 xb_add_32(error
, &xb
, 0); // args length
1708 xb_add_32(error
, &xb
, NFS_XDRARGS_VERSION_0
);
1709 xb_add_bitmap(error
, &xb
, mattrs
, NFS_MATTR_BITMAP_LEN
);
1710 attrslength_offset
= xb_offset(&xb
);
1711 xb_add_32(error
, &xb
, 0); // attrs length
1712 xb_add_bitmap(error
, &xb
, mflags_mask
, NFS_MFLAG_BITMAP_LEN
); /* mask */
1713 xb_add_bitmap(error
, &xb
, mflags
, NFS_MFLAG_BITMAP_LEN
); /* value */
1714 xb_add_32(error
, &xb
, nfsvers
);
1715 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READ_SIZE
))
1716 xb_add_32(error
, &xb
, args
.rsize
);
1717 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_WRITE_SIZE
))
1718 xb_add_32(error
, &xb
, args
.wsize
);
1719 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READDIR_SIZE
))
1720 xb_add_32(error
, &xb
, args
.readdirsize
);
1721 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READAHEAD
))
1722 xb_add_32(error
, &xb
, args
.readahead
);
1723 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MIN
)) {
1724 xb_add_32(error
, &xb
, args
.acregmin
);
1725 xb_add_32(error
, &xb
, 0);
1727 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MAX
)) {
1728 xb_add_32(error
, &xb
, args
.acregmax
);
1729 xb_add_32(error
, &xb
, 0);
1731 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MIN
)) {
1732 xb_add_32(error
, &xb
, args
.acdirmin
);
1733 xb_add_32(error
, &xb
, 0);
1735 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MAX
)) {
1736 xb_add_32(error
, &xb
, args
.acdirmax
);
1737 xb_add_32(error
, &xb
, 0);
1739 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_LOCK_MODE
))
1740 xb_add_32(error
, &xb
, nfslockmode
);
1741 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SECURITY
)) {
1742 uint32_t flavors
[2], i
=0;
1743 if (args
.flags
& NFSMNT_SECFLAVOR
)
1744 flavors
[i
++] = args
.auth
;
1745 if ((args
.flags
& NFSMNT_SECSYSOK
) && ((i
== 0) || (flavors
[0] != RPCAUTH_SYS
)))
1746 flavors
[i
++] = RPCAUTH_SYS
;
1747 xb_add_word_array(error
, &xb
, flavors
, i
);
1749 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MAX_GROUP_LIST
))
1750 xb_add_32(error
, &xb
, args
.maxgrouplist
);
1751 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SOCKET_TYPE
))
1752 xb_add_string(error
, &xb
, ((args
.sotype
== SOCK_DGRAM
) ? "udp" : "tcp"), 3);
1753 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_PORT
))
1754 xb_add_32(error
, &xb
, ((ss
.ss_family
== AF_INET
) ?
1755 ntohs(((struct sockaddr_in
*)&ss
)->sin_port
) :
1756 ntohs(((struct sockaddr_in6
*)&ss
)->sin6_port
)));
1757 /* NFS_MATTR_MOUNT_PORT (not available in old args) */
1758 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_REQUEST_TIMEOUT
)) {
1759 /* convert from .1s increments to time */
1760 xb_add_32(error
, &xb
, args
.timeo
/10);
1761 xb_add_32(error
, &xb
, (args
.timeo%10
)*100000000);
1763 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SOFT_RETRY_COUNT
))
1764 xb_add_32(error
, &xb
, args
.retrans
);
1765 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_DEAD_TIMEOUT
)) {
1766 xb_add_32(error
, &xb
, args
.deadtimeout
);
1767 xb_add_32(error
, &xb
, 0);
1769 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_FH
))
1770 xb_add_fh(error
, &xb
, &nfh
[0], args
.fhsize
);
1771 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_FS_LOCATIONS
)) {
1772 xb_add_32(error
, &xb
, 1); /* fs location count */
1773 xb_add_32(error
, &xb
, 1); /* server count */
1774 xb_add_string(error
, &xb
, mntfrom
, (endserverp
- mntfrom
)); /* server name */
1775 xb_add_32(error
, &xb
, 1); /* address count */
1776 xb_add_string(error
, &xb
, uaddr
, strlen(uaddr
)); /* address */
1777 xb_add_32(error
, &xb
, 0); /* empty server info */
1778 xb_add_32(error
, &xb
, numcomps
); /* pathname component count */
1781 while (*p
&& (*p
== '/'))
1785 while (*p
&& (*p
!= '/'))
1787 xb_add_string(error
, &xb
, cp
, (p
- cp
)); /* component */
1789 while (*p
&& (*p
== '/'))
1792 xb_add_32(error
, &xb
, 0); /* empty fsl info */
1794 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MNTFLAGS
))
1795 xb_add_32(error
, &xb
, (vfs_flags(mp
) & MNT_VISFLAGMASK
)); /* VFS MNT_* flags */
1796 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MNTFROM
))
1797 xb_add_string(error
, &xb
, mntfrom
, strlen(mntfrom
)); /* fixed f_mntfromname */
1798 xb_build_done(error
, &xb
);
1800 /* update opaque counts */
1801 end_offset
= xb_offset(&xb
);
1802 error
= xb_seek(&xb
, argslength_offset
);
1803 xb_add_32(error
, &xb
, end_offset
- argslength_offset
+ XDRWORD
/*version*/);
1805 error
= xb_seek(&xb
, attrslength_offset
);
1806 xb_add_32(error
, &xb
, end_offset
- attrslength_offset
- XDRWORD
/*don't include length field*/);
1809 /* grab the assembled buffer */
1810 *xdrbufp
= xb_buffer_base(&xb
);
1811 xb
.xb_flags
&= ~XB_CLEANUP
;
1815 FREE_ZONE(mntfrom
, MAXPATHLEN
, M_NAMEI
);
1825 nfs_vfs_mount(mount_t mp
, vnode_t vp
, user_addr_t data
, vfs_context_t ctx
)
1827 int error
= 0, inkernel
= vfs_iskernelmount(mp
);
1828 uint32_t argsversion
, argslength
;
1829 char *xdrbuf
= NULL
;
1831 /* read in version */
1833 bcopy(CAST_DOWN(void *, data
), &argsversion
, sizeof(argsversion
));
1834 else if ((error
= copyin(data
, &argsversion
, sizeof(argsversion
))))
1837 /* If we have XDR args, then all values in the buffer are in network order */
1838 if (argsversion
== htonl(NFS_ARGSVERSION_XDR
))
1839 argsversion
= NFS_ARGSVERSION_XDR
;
1841 switch (argsversion
) {
1846 /* convert old-style args to xdr */
1847 error
= nfs_convert_old_nfs_args(mp
, data
, ctx
, argsversion
, inkernel
, &xdrbuf
);
1849 case NFS_ARGSVERSION_XDR
:
1850 /* copy in xdr buffer */
1852 bcopy(CAST_DOWN(void *, (data
+ XDRWORD
)), &argslength
, XDRWORD
);
1854 error
= copyin((data
+ XDRWORD
), &argslength
, XDRWORD
);
1857 argslength
= ntohl(argslength
);
1858 /* put a reasonable limit on the size of the XDR args */
1859 if (argslength
> 16*1024) {
1863 /* allocate xdr buffer */
1864 xdrbuf
= xb_malloc(xdr_rndup(argslength
));
1870 bcopy(CAST_DOWN(void *, data
), xdrbuf
, argslength
);
1872 error
= copyin(data
, xdrbuf
, argslength
);
1875 error
= EPROGMISMATCH
;
1883 error
= mountnfs(xdrbuf
, mp
, ctx
, &vp
);
1888 * Common code for mount and mountroot
1891 /* Set up an NFSv2/v3 mount */
1894 struct nfsmount
*nmp
,
1899 struct nfs_vattr nvattr
;
1908 * Get file attributes for the mountpoint. These are needed
1909 * in order to properly create the root vnode.
1911 error
= nfs3_getattr_rpc(NULL
, nmp
->nm_mountp
, nmp
->nm_fh
->fh_data
, nmp
->nm_fh
->fh_len
, 0,
1912 ctx
, &nvattr
, &xid
);
1916 error
= nfs_nget(nmp
->nm_mountp
, NULL
, NULL
, nmp
->nm_fh
->fh_data
, nmp
->nm_fh
->fh_len
,
1917 &nvattr
, &xid
, RPCAUTH_UNKNOWN
, NG_MARKROOT
, npp
);
1919 nfs_node_unlock(*npp
);
1924 * Try to make sure we have all the general info from the server.
1926 if (nmp
->nm_vers
== NFS_VER2
) {
1927 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXNAME
);
1928 nmp
->nm_fsattr
.nfsa_maxname
= NFS_MAXNAMLEN
;
1929 } else if (nmp
->nm_vers
== NFS_VER3
) {
1930 /* get the NFSv3 FSINFO */
1931 error
= nfs3_fsinfo(nmp
, *npp
, ctx
);
1934 /* If the server indicates all pathconf info is */
1935 /* the same, grab a copy of that info now */
1936 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_HOMOGENEOUS
) &&
1937 (nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_HOMOGENEOUS
)) {
1938 struct nfs_fsattr nfsa
;
1939 if (!nfs3_pathconf_rpc(*npp
, &nfsa
, ctx
)) {
1940 /* cache a copy of the results */
1941 lck_mtx_lock(&nmp
->nm_lock
);
1942 nfs3_pathconf_cache(nmp
, &nfsa
);
1943 lck_mtx_unlock(&nmp
->nm_lock
);
1948 if (*npp
&& error
) {
1949 vnode_put(NFSTOV(*npp
));
1950 vnode_recycle(NFSTOV(*npp
));
1957 * Update an NFSv4 mount path with the contents of the symlink.
1959 * Read the link for the given file handle.
1960 * Insert the link's components into the path.
1963 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
)
1965 int error
= 0, status
, numops
;
1966 uint32_t len
= 0, comp
, newcomp
, linkcompcount
;
1968 struct nfsm_chain nmreq
, nmrep
;
1969 struct nfsreq rq
, *req
= &rq
;
1970 struct nfsreq_secinfo_args si
;
1971 char *link
= NULL
, *p
, *q
, ch
;
1972 struct nfs_fs_path nfsp2
;
1974 bzero(&nfsp2
, sizeof(nfsp2
));
1976 NFSREQ_SECINFO_SET(&si
, NULL
, dirfhp
->fh_data
, dirfhp
->fh_len
, nfsp
->np_components
[curcomp
], 0);
1978 NFSREQ_SECINFO_SET(&si
, NULL
, NULL
, 0, nfsp
->np_components
[curcomp
], 0);
1979 nfsm_chain_null(&nmreq
);
1980 nfsm_chain_null(&nmrep
);
1982 MALLOC_ZONE(link
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1988 nfsm_chain_build_alloc_init(error
, &nmreq
, 12 * NFSX_UNSIGNED
);
1989 nfsm_chain_add_compound_header(error
, &nmreq
, "readlink", numops
);
1991 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
1992 nfsm_chain_add_fh(error
, &nmreq
, NFS_VER4
, fhp
->fh_data
, fhp
->fh_len
);
1994 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_READLINK
);
1995 nfsm_chain_build_done(error
, &nmreq
);
1996 nfsm_assert(error
, (numops
== 0), EPROTO
);
1999 error
= nfs_request_async(NULL
, nmp
->nm_mountp
, &nmreq
, NFSPROC4_COMPOUND
,
2000 vfs_context_thread(ctx
), vfs_context_ucred(ctx
), &si
, 0, NULL
, &req
);
2002 error
= nfs_request_async_finish(req
, &nmrep
, &xid
, &status
);
2004 nfsm_chain_skip_tag(error
, &nmrep
);
2005 nfsm_chain_get_32(error
, &nmrep
, numops
);
2006 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
2007 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_READLINK
);
2008 nfsm_chain_get_32(error
, &nmrep
, len
);
2012 else if (len
>= MAXPATHLEN
)
2013 len
= MAXPATHLEN
- 1;
2014 nfsm_chain_get_opaque(error
, &nmrep
, len
, link
);
2016 /* make sure link string is terminated properly */
2019 /* count the number of components in link */
2021 while (*p
&& (*p
== '/'))
2026 while (*p
&& (*p
!= '/'))
2028 while (*p
&& (*p
== '/'))
2032 /* free up used components */
2033 for (comp
=0; comp
<= curcomp
; comp
++) {
2034 if (nfsp
->np_components
[comp
]) {
2035 FREE(nfsp
->np_components
[comp
], M_TEMP
);
2036 nfsp
->np_components
[comp
] = NULL
;
2040 /* set up new path */
2041 nfsp2
.np_compcount
= nfsp
->np_compcount
- curcomp
- 1 + linkcompcount
;
2042 MALLOC(nfsp2
.np_components
, char **, nfsp2
.np_compcount
*sizeof(char*), M_TEMP
, M_WAITOK
|M_ZERO
);
2043 if (!nfsp2
.np_components
) {
2048 /* add link components */
2050 while (*p
&& (*p
== '/'))
2052 for (newcomp
=0; newcomp
< linkcompcount
; newcomp
++) {
2053 /* find end of component */
2055 while (*q
&& (*q
!= '/'))
2057 MALLOC(nfsp2
.np_components
[newcomp
], char *, q
-p
+1, M_TEMP
, M_WAITOK
|M_ZERO
);
2058 if (!nfsp2
.np_components
[newcomp
]) {
2064 strlcpy(nfsp2
.np_components
[newcomp
], p
, q
-p
+1);
2067 while (*p
&& (*p
== '/'))
2072 /* add remaining components */
2073 for(comp
= curcomp
+ 1; comp
< nfsp
->np_compcount
; comp
++,newcomp
++) {
2074 nfsp2
.np_components
[newcomp
] = nfsp
->np_components
[comp
];
2075 nfsp
->np_components
[comp
] = NULL
;
2078 /* move new path into place */
2079 FREE(nfsp
->np_components
, M_TEMP
);
2080 nfsp
->np_components
= nfsp2
.np_components
;
2081 nfsp
->np_compcount
= nfsp2
.np_compcount
;
2082 nfsp2
.np_components
= NULL
;
2084 /* for absolute link, let the caller now that the next dirfh is root */
2085 if (link
[0] == '/') {
2091 FREE_ZONE(link
, MAXPATHLEN
, M_NAMEI
);
2092 if (nfsp2
.np_components
) {
2093 for (comp
=0; comp
< nfsp2
.np_compcount
; comp
++)
2094 if (nfsp2
.np_components
[comp
])
2095 FREE(nfsp2
.np_components
[comp
], M_TEMP
);
2096 FREE(nfsp2
.np_components
, M_TEMP
);
2098 nfsm_chain_cleanup(&nmreq
);
2099 nfsm_chain_cleanup(&nmrep
);
2103 /* Set up an NFSv4 mount */
2106 struct nfsmount
*nmp
,
2110 struct nfsm_chain nmreq
, nmrep
;
2111 int error
= 0, numops
, status
, interval
, isdotdot
, loopcnt
= 0, depth
= 0;
2112 struct nfs_fs_path fspath
, *nfsp
, fspath2
;
2113 uint32_t bitmap
[NFS_ATTR_BITMAP_LEN
], comp
, comp2
;
2114 fhandle_t fh
, dirfh
;
2115 struct nfs_vattr nvattr
;
2117 struct nfsreq rq
, *req
= &rq
;
2118 struct nfsreq_secinfo_args si
;
2120 struct nfs_fs_locations nfsls
;
2123 fh
.fh_len
= dirfh
.fh_len
= 0;
2124 TAILQ_INIT(&nmp
->nm_open_owners
);
2125 TAILQ_INIT(&nmp
->nm_delegations
);
2126 TAILQ_INIT(&nmp
->nm_dreturnq
);
2127 nmp
->nm_stategenid
= 1;
2128 NVATTR_INIT(&nvattr
);
2129 bzero(&nfsls
, sizeof(nfsls
));
2130 nfsm_chain_null(&nmreq
);
2131 nfsm_chain_null(&nmrep
);
2134 * If no security flavors were specified we'll want to default to the server's
2135 * preferred flavor. For NFSv4.0 we need a file handle and name to get that via
2136 * SECINFO, so we'll do that on the last component of the server path we are
2137 * mounting. If we are mounting the server's root, we'll need to defer the
2138 * SECINFO call to the first successful LOOKUP request.
2140 if (!nmp
->nm_sec
.count
)
2141 nmp
->nm_state
|= NFSSTA_NEEDSECINFO
;
2143 /* make a copy of the current location's path */
2144 nfsp
= &nmp
->nm_locations
.nl_locations
[nmp
->nm_locations
.nl_current
.nli_loc
]->nl_path
;
2145 bzero(&fspath
, sizeof(fspath
));
2146 fspath
.np_compcount
= nfsp
->np_compcount
;
2147 if (fspath
.np_compcount
> 0) {
2148 MALLOC(fspath
.np_components
, char **, fspath
.np_compcount
*sizeof(char*), M_TEMP
, M_WAITOK
|M_ZERO
);
2149 if (!fspath
.np_components
) {
2153 for (comp
=0; comp
< nfsp
->np_compcount
; comp
++) {
2154 int slen
= strlen(nfsp
->np_components
[comp
]);
2155 MALLOC(fspath
.np_components
[comp
], char *, slen
+1, M_TEMP
, M_WAITOK
|M_ZERO
);
2156 if (!fspath
.np_components
[comp
]) {
2160 strlcpy(fspath
.np_components
[comp
], nfsp
->np_components
[comp
], slen
+1);
2166 /* for mirror mounts, we can just use the file handle passed in */
2168 dirfh
.fh_len
= nmp
->nm_fh
->fh_len
;
2169 bcopy(nmp
->nm_fh
->fh_data
, dirfh
.fh_data
, dirfh
.fh_len
);
2170 NFSREQ_SECINFO_SET(&si
, NULL
, dirfh
.fh_data
, dirfh
.fh_len
, NULL
, 0);
2174 /* otherwise, we need to get the fh for the directory we are mounting */
2176 /* if no components, just get root */
2177 if (fspath
.np_compcount
== 0) {
2179 // PUTROOTFH + GETATTR(FH)
2180 NFSREQ_SECINFO_SET(&si
, NULL
, NULL
, 0, NULL
, 0);
2182 nfsm_chain_build_alloc_init(error
, &nmreq
, 9 * NFSX_UNSIGNED
);
2183 nfsm_chain_add_compound_header(error
, &nmreq
, "mount", numops
);
2185 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTROOTFH
);
2187 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
2188 NFS_CLEAR_ATTRIBUTES(bitmap
);
2189 NFS4_DEFAULT_ATTRIBUTES(bitmap
);
2190 NFS_BITMAP_SET(bitmap
, NFS_FATTR_FILEHANDLE
);
2191 nfsm_chain_add_bitmap(error
, &nmreq
, bitmap
, NFS_ATTR_BITMAP_LEN
);
2192 nfsm_chain_build_done(error
, &nmreq
);
2193 nfsm_assert(error
, (numops
== 0), EPROTO
);
2195 error
= nfs_request_async(NULL
, nmp
->nm_mountp
, &nmreq
, NFSPROC4_COMPOUND
,
2196 vfs_context_thread(ctx
), vfs_context_ucred(ctx
), &si
, 0, NULL
, &req
);
2198 error
= nfs_request_async_finish(req
, &nmrep
, &xid
, &status
);
2199 nfsm_chain_skip_tag(error
, &nmrep
);
2200 nfsm_chain_get_32(error
, &nmrep
, numops
);
2201 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTROOTFH
);
2202 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
2204 NFS_CLEAR_ATTRIBUTES(nmp
->nm_fsattr
.nfsa_bitmap
);
2205 error
= nfs4_parsefattr(&nmrep
, &nmp
->nm_fsattr
, &nvattr
, &dirfh
, NULL
, NULL
);
2206 if (!error
&& !NFS_BITMAP_ISSET(&nvattr
.nva_bitmap
, NFS_FATTR_FILEHANDLE
)) {
2207 printf("nfs: mount didn't return filehandle?\n");
2211 nfsm_chain_cleanup(&nmrep
);
2212 nfsm_chain_null(&nmreq
);
2213 NVATTR_CLEANUP(&nvattr
);
2217 /* look up each path component */
2218 for (comp
=0; comp
< fspath
.np_compcount
; ) {
2220 if (fspath
.np_components
[comp
][0] == '.') {
2221 if (fspath
.np_components
[comp
][1] == '\0') {
2226 /* treat ".." specially */
2227 if ((fspath
.np_components
[comp
][1] == '.') &&
2228 (fspath
.np_components
[comp
][2] == '\0'))
2230 if (isdotdot
&& (dirfh
.fh_len
== 0)) {
2231 /* ".." in root directory is same as "." */
2236 // PUT(ROOT)FH + LOOKUP(P) + GETFH + GETATTR
2237 if (dirfh
.fh_len
== 0)
2238 NFSREQ_SECINFO_SET(&si
, NULL
, NULL
, 0, isdotdot
? NULL
: fspath
.np_components
[comp
], 0);
2240 NFSREQ_SECINFO_SET(&si
, NULL
, dirfh
.fh_data
, dirfh
.fh_len
, isdotdot
? NULL
: fspath
.np_components
[comp
], 0);
2242 nfsm_chain_build_alloc_init(error
, &nmreq
, 18 * NFSX_UNSIGNED
);
2243 nfsm_chain_add_compound_header(error
, &nmreq
, "mount", numops
);
2246 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
2247 nfsm_chain_add_fh(error
, &nmreq
, NFS_VER4
, dirfh
.fh_data
, dirfh
.fh_len
);
2249 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTROOTFH
);
2253 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_LOOKUPP
);
2255 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_LOOKUP
);
2256 nfsm_chain_add_name(error
, &nmreq
,
2257 fspath
.np_components
[comp
], strlen(fspath
.np_components
[comp
]), nmp
);
2260 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETFH
);
2262 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
2263 NFS_CLEAR_ATTRIBUTES(bitmap
);
2264 NFS4_DEFAULT_ATTRIBUTES(bitmap
);
2265 /* if no namedattr support or component is ".zfs", clear NFS_FATTR_NAMED_ATTR */
2266 if (NMFLAG(nmp
, NONAMEDATTR
) || !strcmp(fspath
.np_components
[comp
], ".zfs"))
2267 NFS_BITMAP_CLR(bitmap
, NFS_FATTR_NAMED_ATTR
);
2268 nfsm_chain_add_bitmap(error
, &nmreq
, bitmap
, NFS_ATTR_BITMAP_LEN
);
2269 nfsm_chain_build_done(error
, &nmreq
);
2270 nfsm_assert(error
, (numops
== 0), EPROTO
);
2272 error
= nfs_request_async(NULL
, nmp
->nm_mountp
, &nmreq
, NFSPROC4_COMPOUND
,
2273 vfs_context_thread(ctx
), vfs_context_ucred(ctx
), &si
, 0, NULL
, &req
);
2275 error
= nfs_request_async_finish(req
, &nmrep
, &xid
, &status
);
2276 nfsm_chain_skip_tag(error
, &nmrep
);
2277 nfsm_chain_get_32(error
, &nmrep
, numops
);
2278 nfsm_chain_op_check(error
, &nmrep
, dirfh
.fh_len
? NFS_OP_PUTFH
: NFS_OP_PUTROOTFH
);
2279 nfsm_chain_op_check(error
, &nmrep
, isdotdot
? NFS_OP_LOOKUPP
: NFS_OP_LOOKUP
);
2281 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETFH
);
2282 nfsm_chain_get_32(error
, &nmrep
, fh
.fh_len
);
2283 nfsm_chain_get_opaque(error
, &nmrep
, fh
.fh_len
, fh
.fh_data
);
2284 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
2286 NFS_CLEAR_ATTRIBUTES(nmp
->nm_fsattr
.nfsa_bitmap
);
2287 error
= nfs4_parsefattr(&nmrep
, &nmp
->nm_fsattr
, &nvattr
, NULL
, NULL
, &nfsls
);
2289 nfsm_chain_cleanup(&nmrep
);
2290 nfsm_chain_null(&nmreq
);
2292 /* LOOKUP succeeded but GETATTR failed? This could be a referral. */
2293 /* Try the lookup again with a getattr for fs_locations. */
2294 nfs_fs_locations_cleanup(&nfsls
);
2295 error
= nfs4_get_fs_locations(nmp
, NULL
, dirfh
.fh_data
, dirfh
.fh_len
, fspath
.np_components
[comp
], ctx
, &nfsls
);
2296 if (!error
&& (nfsls
.nl_numlocs
< 1))
2299 if (++loopcnt
> MAXSYMLINKS
) {
2300 /* too many symlink/referral redirections */
2304 /* tear down the current connection */
2305 nfs_disconnect(nmp
);
2306 /* replace fs locations */
2307 nfs_fs_locations_cleanup(&nmp
->nm_locations
);
2308 nmp
->nm_locations
= nfsls
;
2309 bzero(&nfsls
, sizeof(nfsls
));
2310 /* initiate a connection using the new fs locations */
2311 error
= nfs_mount_connect(nmp
);
2312 if (!error
&& !(nmp
->nm_locations
.nl_current
.nli_flags
& NLI_VALID
))
2315 /* add new server's remote path to beginning of our path and continue */
2316 nfsp
= &nmp
->nm_locations
.nl_locations
[nmp
->nm_locations
.nl_current
.nli_loc
]->nl_path
;
2317 bzero(&fspath2
, sizeof(fspath2
));
2318 fspath2
.np_compcount
= (fspath
.np_compcount
- comp
- 1) + nfsp
->np_compcount
;
2319 if (fspath2
.np_compcount
> 0) {
2320 MALLOC(fspath2
.np_components
, char **, fspath2
.np_compcount
*sizeof(char*), M_TEMP
, M_WAITOK
|M_ZERO
);
2321 if (!fspath2
.np_components
) {
2325 for (comp2
=0; comp2
< nfsp
->np_compcount
; comp2
++) {
2326 int slen
= strlen(nfsp
->np_components
[comp2
]);
2327 MALLOC(fspath2
.np_components
[comp2
], char *, slen
+1, M_TEMP
, M_WAITOK
|M_ZERO
);
2328 if (!fspath2
.np_components
[comp2
]) {
2329 /* clean up fspath2, then error out */
2332 FREE(fspath2
.np_components
[comp2
], M_TEMP
);
2334 FREE(fspath2
.np_components
, M_TEMP
);
2338 strlcpy(fspath2
.np_components
[comp2
], nfsp
->np_components
[comp2
], slen
+1);
2340 if ((fspath
.np_compcount
- comp
- 1) > 0)
2341 bcopy(&fspath
.np_components
[comp
+1], &fspath2
.np_components
[nfsp
->np_compcount
], (fspath
.np_compcount
- comp
- 1)*sizeof(char*));
2342 /* free up unused parts of old path (prior components and component array) */
2344 FREE(fspath
.np_components
[comp
], M_TEMP
);
2345 } while (comp
-- > 0);
2346 FREE(fspath
.np_components
, M_TEMP
);
2347 /* put new path in place */
2350 /* reset dirfh and component index */
2353 NVATTR_CLEANUP(&nvattr
);
2354 if (fspath
.np_compcount
== 0)
2359 /* if file handle is for a symlink, then update the path with the symlink contents */
2360 if (NFS_BITMAP_ISSET(&nvattr
.nva_bitmap
, NFS_FATTR_TYPE
) && (nvattr
.nva_type
== VLNK
)) {
2361 if (++loopcnt
> MAXSYMLINKS
)
2364 error
= nfs4_mount_update_path_with_symlink(nmp
, &fspath
, comp
, &dirfh
, &depth
, &fh
, ctx
);
2366 /* directory file handle is either left the same or reset to root (if link was absolute) */
2367 /* path traversal starts at beginning of the path again */
2369 NVATTR_CLEANUP(&nvattr
);
2370 nfs_fs_locations_cleanup(&nfsls
);
2373 NVATTR_CLEANUP(&nvattr
);
2374 nfs_fs_locations_cleanup(&nfsls
);
2375 /* not a symlink... */
2376 if ((nmp
->nm_state
& NFSSTA_NEEDSECINFO
) && (comp
== (fspath
.np_compcount
-1)) && !isdotdot
) {
2377 /* need to get SECINFO for the directory being mounted */
2378 if (dirfh
.fh_len
== 0)
2379 NFSREQ_SECINFO_SET(&si
, NULL
, NULL
, 0, isdotdot
? NULL
: fspath
.np_components
[comp
], 0);
2381 NFSREQ_SECINFO_SET(&si
, NULL
, dirfh
.fh_data
, dirfh
.fh_len
, isdotdot
? NULL
: fspath
.np_components
[comp
], 0);
2382 sec
.count
= NX_MAX_SEC_FLAVORS
;
2383 error
= nfs4_secinfo_rpc(nmp
, &si
, vfs_context_ucred(ctx
), sec
.flavors
, &sec
.count
);
2384 /* [sigh] some implementations return "illegal" error for unsupported ops */
2385 if (error
== NFSERR_OP_ILLEGAL
)
2388 /* set our default security flavor to the first in the list */
2390 nmp
->nm_auth
= sec
.flavors
[0];
2391 nmp
->nm_state
&= ~NFSSTA_NEEDSECINFO
;
2393 /* advance directory file handle, component index, & update depth */
2396 if (!isdotdot
) /* going down the hierarchy */
2398 else if (--depth
<= 0) /* going up the hierarchy */
2399 dirfh
.fh_len
= 0; /* clear dirfh when we hit root */
2403 /* get attrs for mount point root */
2404 numops
= NMFLAG(nmp
, NONAMEDATTR
) ? 2 : 3; // PUTFH + GETATTR + OPENATTR
2405 nfsm_chain_build_alloc_init(error
, &nmreq
, 25 * NFSX_UNSIGNED
);
2406 nfsm_chain_add_compound_header(error
, &nmreq
, "mount", numops
);
2408 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
2409 nfsm_chain_add_fh(error
, &nmreq
, NFS_VER4
, dirfh
.fh_data
, dirfh
.fh_len
);
2411 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
2412 NFS_CLEAR_ATTRIBUTES(bitmap
);
2413 NFS4_DEFAULT_ATTRIBUTES(bitmap
);
2414 /* if no namedattr support or last component is ".zfs", clear NFS_FATTR_NAMED_ATTR */
2415 if (NMFLAG(nmp
, NONAMEDATTR
) || ((fspath
.np_compcount
> 0) && !strcmp(fspath
.np_components
[fspath
.np_compcount
-1], ".zfs")))
2416 NFS_BITMAP_CLR(bitmap
, NFS_FATTR_NAMED_ATTR
);
2417 nfsm_chain_add_bitmap(error
, &nmreq
, bitmap
, NFS_ATTR_BITMAP_LEN
);
2418 if (!NMFLAG(nmp
, NONAMEDATTR
)) {
2420 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_OPENATTR
);
2421 nfsm_chain_add_32(error
, &nmreq
, 0);
2423 nfsm_chain_build_done(error
, &nmreq
);
2424 nfsm_assert(error
, (numops
== 0), EPROTO
);
2426 error
= nfs_request_async(NULL
, nmp
->nm_mountp
, &nmreq
, NFSPROC4_COMPOUND
,
2427 vfs_context_thread(ctx
), vfs_context_ucred(ctx
), &si
, 0, NULL
, &req
);
2429 error
= nfs_request_async_finish(req
, &nmrep
, &xid
, &status
);
2430 nfsm_chain_skip_tag(error
, &nmrep
);
2431 nfsm_chain_get_32(error
, &nmrep
, numops
);
2432 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
2433 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
2435 NFS_CLEAR_ATTRIBUTES(nmp
->nm_fsattr
.nfsa_bitmap
);
2436 error
= nfs4_parsefattr(&nmrep
, &nmp
->nm_fsattr
, &nvattr
, NULL
, NULL
, NULL
);
2438 if (!NMFLAG(nmp
, NONAMEDATTR
)) {
2439 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_OPENATTR
);
2440 if (error
== ENOENT
)
2442 /* [sigh] some implementations return "illegal" error for unsupported ops */
2443 if (error
|| !NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_NAMED_ATTR
)) {
2444 nmp
->nm_fsattr
.nfsa_flags
&= ~NFS_FSFLAG_NAMED_ATTR
;
2446 nmp
->nm_fsattr
.nfsa_flags
|= NFS_FSFLAG_NAMED_ATTR
;
2449 nmp
->nm_fsattr
.nfsa_flags
&= ~NFS_FSFLAG_NAMED_ATTR
;
2451 if (NMFLAG(nmp
, NOACL
)) /* make sure ACL support is turned off */
2452 nmp
->nm_fsattr
.nfsa_flags
&= ~NFS_FSFLAG_ACL
;
2453 if (NMFLAG(nmp
, ACLONLY
) && !(nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_ACL
))
2454 NFS_BITMAP_CLR(nmp
->nm_flags
, NFS_MFLAG_ACLONLY
);
2455 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_FH_EXPIRE_TYPE
)) {
2456 uint32_t fhtype
= ((nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_FHTYPE_MASK
) >> NFS_FSFLAG_FHTYPE_SHIFT
);
2457 if (fhtype
!= NFS_FH_PERSISTENT
)
2458 printf("nfs: warning: non-persistent file handles! for %s\n", vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
);
2461 /* make sure it's a directory */
2462 if (!NFS_BITMAP_ISSET(&nvattr
.nva_bitmap
, NFS_FATTR_TYPE
) || (nvattr
.nva_type
!= VDIR
)) {
2467 /* save the NFS fsid */
2468 nmp
->nm_fsid
= nvattr
.nva_fsid
;
2470 /* create the root node */
2471 error
= nfs_nget(nmp
->nm_mountp
, NULL
, NULL
, dirfh
.fh_data
, dirfh
.fh_len
, &nvattr
, &xid
, rq
.r_auth
, NG_MARKROOT
, npp
);
2474 if (nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_ACL
)
2475 vfs_setextendedsecurity(nmp
->nm_mountp
);
2477 /* adjust I/O sizes to server limits */
2478 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXREAD
) && (nmp
->nm_fsattr
.nfsa_maxread
> 0)) {
2479 if (nmp
->nm_fsattr
.nfsa_maxread
< (uint64_t)nmp
->nm_rsize
) {
2480 nmp
->nm_rsize
= nmp
->nm_fsattr
.nfsa_maxread
& ~(NFS_FABLKSIZE
- 1);
2481 if (nmp
->nm_rsize
== 0)
2482 nmp
->nm_rsize
= nmp
->nm_fsattr
.nfsa_maxread
;
2485 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXWRITE
) && (nmp
->nm_fsattr
.nfsa_maxwrite
> 0)) {
2486 if (nmp
->nm_fsattr
.nfsa_maxwrite
< (uint64_t)nmp
->nm_wsize
) {
2487 nmp
->nm_wsize
= nmp
->nm_fsattr
.nfsa_maxwrite
& ~(NFS_FABLKSIZE
- 1);
2488 if (nmp
->nm_wsize
== 0)
2489 nmp
->nm_wsize
= nmp
->nm_fsattr
.nfsa_maxwrite
;
2493 /* set up lease renew timer */
2494 nmp
->nm_renew_timer
= thread_call_allocate(nfs4_renew_timer
, nmp
);
2495 interval
= nmp
->nm_fsattr
.nfsa_lease
/ 2;
2498 nfs_interval_timer_start(nmp
->nm_renew_timer
, interval
* 1000);
2501 if (fspath
.np_components
) {
2502 for (comp
=0; comp
< fspath
.np_compcount
; comp
++)
2503 if (fspath
.np_components
[comp
])
2504 FREE(fspath
.np_components
[comp
], M_TEMP
);
2505 FREE(fspath
.np_components
, M_TEMP
);
2507 NVATTR_CLEANUP(&nvattr
);
2508 nfs_fs_locations_cleanup(&nfsls
);
2510 nfs_node_unlock(*npp
);
2511 nfsm_chain_cleanup(&nmreq
);
2512 nfsm_chain_cleanup(&nmrep
);
2517 * Thread to handle initial NFS mount connection.
2520 nfs_mount_connect_thread(void *arg
, __unused wait_result_t wr
)
2522 struct nfsmount
*nmp
= arg
;
2523 int error
= 0, savederror
= 0, slpflag
= (NMFLAG(nmp
, INTR
) ? PCATCH
: 0);
2524 int done
= 0, timeo
, tries
, maxtries
;
2526 if (NM_OMFLAG(nmp
, MNTQUICK
)) {
2534 for (tries
= 0; tries
< maxtries
; tries
++) {
2535 error
= nfs_connect(nmp
, 1, timeo
);
2552 /* just keep retrying on any of these errors */
2556 /* looks like we got an answer... */
2561 /* save the best error */
2562 if (nfs_connect_error_class(error
) >= nfs_connect_error_class(savederror
))
2569 /* pause before next attempt */
2570 if ((error
= nfs_sigintr(nmp
, NULL
, current_thread(), 0)))
2572 error
= tsleep(nmp
, PSOCK
|slpflag
, "nfs_mount_connect_retry", 2*hz
);
2573 if (error
&& (error
!= EWOULDBLOCK
))
2578 /* update status of mount connect */
2579 lck_mtx_lock(&nmp
->nm_lock
);
2580 if (!nmp
->nm_mounterror
)
2581 nmp
->nm_mounterror
= error
;
2582 nmp
->nm_state
&= ~NFSSTA_MOUNT_THREAD
;
2583 lck_mtx_unlock(&nmp
->nm_lock
);
2584 wakeup(&nmp
->nm_nss
);
2588 nfs_mount_connect(struct nfsmount
*nmp
)
2590 int error
= 0, slpflag
;
2592 struct timespec ts
= { 2, 0 };
2595 * Set up the socket. Perform initial search for a location/server/address to
2596 * connect to and negotiate any unspecified mount parameters. This work is
2597 * done on a kernel thread to satisfy reserved port usage needs.
2599 slpflag
= NMFLAG(nmp
, INTR
) ? PCATCH
: 0;
2600 lck_mtx_lock(&nmp
->nm_lock
);
2601 /* set flag that the thread is running */
2602 nmp
->nm_state
|= NFSSTA_MOUNT_THREAD
;
2603 if (kernel_thread_start(nfs_mount_connect_thread
, nmp
, &thd
) != KERN_SUCCESS
) {
2604 nmp
->nm_state
&= ~NFSSTA_MOUNT_THREAD
;
2605 nmp
->nm_mounterror
= EIO
;
2606 printf("nfs mount %s start socket connect thread failed\n", vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
);
2608 thread_deallocate(thd
);
2611 /* wait until mount connect thread is finished/gone */
2612 while (nmp
->nm_state
& NFSSTA_MOUNT_THREAD
) {
2613 error
= msleep(&nmp
->nm_nss
, &nmp
->nm_lock
, slpflag
|PSOCK
, "nfsconnectthread", &ts
);
2614 if ((error
&& (error
!= EWOULDBLOCK
)) || ((error
= nfs_sigintr(nmp
, NULL
, current_thread(), 1)))) {
2616 if (!nmp
->nm_mounterror
)
2617 nmp
->nm_mounterror
= error
;
2618 /* signal the thread that we are aborting */
2619 nmp
->nm_sockflags
|= NMSOCK_UNMOUNT
;
2621 wakeup(nmp
->nm_nss
);
2622 /* and continue waiting on it to finish */
2626 lck_mtx_unlock(&nmp
->nm_lock
);
2628 /* grab mount connect status */
2629 error
= nmp
->nm_mounterror
;
2635 * Common code to mount an NFS file system.
2644 struct nfsmount
*nmp
;
2647 struct vfsstatfs
*sbp
;
2649 uint32_t i
, val
, vers
= 0, minorvers
, maxio
, iosize
, len
;
2651 uint32_t *mflags_mask
;
2653 uint32_t argslength
, attrslength
;
2654 struct nfs_location_index firstloc
= { NLI_VALID
, 0, 0, 0 };
2656 /* make sure mbuf constants are set up */
2657 if (!nfs_mbuf_mhlen
)
2660 if (vfs_flags(mp
) & MNT_UPDATE
) {
2662 /* update paths, file handles, etc, here XXX */
2666 /* allocate an NFS mount structure for this mount */
2667 MALLOC_ZONE(nmp
, struct nfsmount
*,
2668 sizeof (struct nfsmount
), M_NFSMNT
, M_WAITOK
);
2673 bzero((caddr_t
)nmp
, sizeof (struct nfsmount
));
2674 lck_mtx_init(&nmp
->nm_lock
, nfs_mount_grp
, LCK_ATTR_NULL
);
2675 TAILQ_INIT(&nmp
->nm_resendq
);
2676 TAILQ_INIT(&nmp
->nm_iodq
);
2677 TAILQ_INIT(&nmp
->nm_gsscl
);
2678 TAILQ_INIT(&nmp
->nm_gssnccl
);
2679 LIST_INIT(&nmp
->nm_monlist
);
2680 vfs_setfsprivate(mp
, nmp
);
2682 nmp
->nm_mountp
= mp
;
2683 vfs_setauthopaque(mp
);
2685 nfs_nhinit_finish();
2687 nmp
->nm_args
= xdrbuf
;
2689 /* set up defaults */
2692 nmp
->nm_timeo
= NFS_TIMEO
;
2693 nmp
->nm_retry
= NFS_RETRANS
;
2695 nmp
->nm_sofamily
= 0;
2696 nmp
->nm_nfsport
= 0;
2697 nmp
->nm_wsize
= NFS_WSIZE
;
2698 nmp
->nm_rsize
= NFS_RSIZE
;
2699 nmp
->nm_readdirsize
= NFS_READDIRSIZE
;
2700 nmp
->nm_numgrps
= NFS_MAXGRPS
;
2701 nmp
->nm_readahead
= NFS_DEFRAHEAD
;
2702 nmp
->nm_tprintf_delay
= nfs_tprintf_delay
;
2703 if (nmp
->nm_tprintf_delay
< 0)
2704 nmp
->nm_tprintf_delay
= 0;
2705 nmp
->nm_tprintf_initial_delay
= nfs_tprintf_initial_delay
;
2706 if (nmp
->nm_tprintf_initial_delay
< 0)
2707 nmp
->nm_tprintf_initial_delay
= 0;
2708 nmp
->nm_acregmin
= NFS_MINATTRTIMO
;
2709 nmp
->nm_acregmax
= NFS_MAXATTRTIMO
;
2710 nmp
->nm_acdirmin
= NFS_MINDIRATTRTIMO
;
2711 nmp
->nm_acdirmax
= NFS_MAXDIRATTRTIMO
;
2712 nmp
->nm_auth
= RPCAUTH_SYS
;
2713 nmp
->nm_iodlink
.tqe_next
= NFSNOLIST
;
2714 nmp
->nm_deadtimeout
= 0;
2715 nmp
->nm_curdeadtimeout
= 0;
2716 NFS_BITMAP_SET(nmp
->nm_flags
, NFS_MFLAG_NOACL
);
2717 nmp
->nm_realm
= NULL
;
2718 nmp
->nm_principal
= NULL
;
2719 nmp
->nm_sprinc
= NULL
;
2722 mattrs
= nmp
->nm_mattrs
;
2723 mflags
= nmp
->nm_mflags
;
2724 mflags_mask
= nmp
->nm_mflags_mask
;
2726 /* set up NFS mount with args */
2727 xb_init_buffer(&xb
, xdrbuf
, 2*XDRWORD
);
2728 xb_get_32(error
, &xb
, val
); /* version */
2729 xb_get_32(error
, &xb
, argslength
); /* args length */
2731 xb_init_buffer(&xb
, xdrbuf
, argslength
); /* restart parsing with actual buffer length */
2732 xb_get_32(error
, &xb
, val
); /* version */
2733 xb_get_32(error
, &xb
, argslength
); /* args length */
2734 xb_get_32(error
, &xb
, val
); /* XDR args version */
2735 if (val
!= NFS_XDRARGS_VERSION_0
)
2737 len
= NFS_MATTR_BITMAP_LEN
;
2738 xb_get_bitmap(error
, &xb
, mattrs
, len
); /* mount attribute bitmap */
2740 xb_get_32(error
, &xb
, attrslength
); /* attrs length */
2741 if (!error
&& (attrslength
> (argslength
- ((4+NFS_MATTR_BITMAP_LEN
+1)*XDRWORD
))))
2744 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_FLAGS
)) {
2745 len
= NFS_MFLAG_BITMAP_LEN
;
2746 xb_get_bitmap(error
, &xb
, mflags_mask
, len
); /* mount flag mask */
2747 len
= NFS_MFLAG_BITMAP_LEN
;
2748 xb_get_bitmap(error
, &xb
, mflags
, len
); /* mount flag values */
2750 /* clear all mask bits and OR in all the ones that are set */
2751 nmp
->nm_flags
[0] &= ~mflags_mask
[0];
2752 nmp
->nm_flags
[0] |= (mflags_mask
[0] & mflags
[0]);
2755 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_VERSION
)) {
2756 xb_get_32(error
, &xb
, vers
);
2757 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_MINOR_VERSION
))
2758 xb_get_32(error
, &xb
, minorvers
);
2764 nmp
->nm_vers
= NFS_VER2
;
2767 nmp
->nm_vers
= NFS_VER3
;
2770 switch (minorvers
) {
2772 nmp
->nm_vers
= NFS_VER4
;
2782 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_MINOR_VERSION
)) {
2783 /* should have also gotten NFS version (and already gotten minorvers) */
2784 if (!NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_VERSION
))
2787 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READ_SIZE
))
2788 xb_get_32(error
, &xb
, nmp
->nm_rsize
);
2789 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_WRITE_SIZE
))
2790 xb_get_32(error
, &xb
, nmp
->nm_wsize
);
2791 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READDIR_SIZE
))
2792 xb_get_32(error
, &xb
, nmp
->nm_readdirsize
);
2793 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READAHEAD
))
2794 xb_get_32(error
, &xb
, nmp
->nm_readahead
);
2795 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MIN
)) {
2796 xb_get_32(error
, &xb
, nmp
->nm_acregmin
);
2797 xb_skip(error
, &xb
, XDRWORD
);
2799 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MAX
)) {
2800 xb_get_32(error
, &xb
, nmp
->nm_acregmax
);
2801 xb_skip(error
, &xb
, XDRWORD
);
2803 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MIN
)) {
2804 xb_get_32(error
, &xb
, nmp
->nm_acdirmin
);
2805 xb_skip(error
, &xb
, XDRWORD
);
2807 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MAX
)) {
2808 xb_get_32(error
, &xb
, nmp
->nm_acdirmax
);
2809 xb_skip(error
, &xb
, XDRWORD
);
2812 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_LOCK_MODE
)) {
2813 xb_get_32(error
, &xb
, val
);
2815 case NFS_LOCK_MODE_DISABLED
:
2816 case NFS_LOCK_MODE_LOCAL
:
2817 if (nmp
->nm_vers
>= NFS_VER4
) {
2818 /* disabled/local lock mode only allowed on v2/v3 */
2823 case NFS_LOCK_MODE_ENABLED
:
2824 nmp
->nm_lockmode
= val
;
2831 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SECURITY
)) {
2833 xb_get_32(error
, &xb
, seccnt
);
2834 if (!error
&& ((seccnt
< 1) || (seccnt
> NX_MAX_SEC_FLAVORS
)))
2837 nmp
->nm_sec
.count
= seccnt
;
2838 for (i
=0; i
< seccnt
; i
++) {
2839 xb_get_32(error
, &xb
, nmp
->nm_sec
.flavors
[i
]);
2840 /* Check for valid security flavor */
2841 switch (nmp
->nm_sec
.flavors
[i
]) {
2852 /* start with the first flavor */
2853 nmp
->nm_auth
= nmp
->nm_sec
.flavors
[0];
2855 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MAX_GROUP_LIST
))
2856 xb_get_32(error
, &xb
, nmp
->nm_numgrps
);
2857 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SOCKET_TYPE
)) {
2860 xb_get_32(error
, &xb
, val
);
2861 if (!error
&& ((val
< 3) || (val
> 5)))
2864 error
= xb_get_bytes(&xb
, sotype
, val
, 0);
2867 if (!strcmp(sotype
, "tcp")) {
2868 nmp
->nm_sotype
= SOCK_STREAM
;
2869 } else if (!strcmp(sotype
, "udp")) {
2870 nmp
->nm_sotype
= SOCK_DGRAM
;
2871 } else if (!strcmp(sotype
, "tcp4")) {
2872 nmp
->nm_sotype
= SOCK_STREAM
;
2873 nmp
->nm_sofamily
= AF_INET
;
2874 } else if (!strcmp(sotype
, "udp4")) {
2875 nmp
->nm_sotype
= SOCK_DGRAM
;
2876 nmp
->nm_sofamily
= AF_INET
;
2877 } else if (!strcmp(sotype
, "tcp6")) {
2878 nmp
->nm_sotype
= SOCK_STREAM
;
2879 nmp
->nm_sofamily
= AF_INET6
;
2880 } else if (!strcmp(sotype
, "udp6")) {
2881 nmp
->nm_sotype
= SOCK_DGRAM
;
2882 nmp
->nm_sofamily
= AF_INET6
;
2883 } else if (!strcmp(sotype
, "inet4")) {
2884 nmp
->nm_sofamily
= AF_INET
;
2885 } else if (!strcmp(sotype
, "inet6")) {
2886 nmp
->nm_sofamily
= AF_INET6
;
2887 } else if (!strcmp(sotype
, "inet")) {
2888 nmp
->nm_sofamily
= 0; /* ok */
2892 if (!error
&& (nmp
->nm_vers
>= NFS_VER4
) && nmp
->nm_sotype
&&
2893 (nmp
->nm_sotype
!= SOCK_STREAM
))
2894 error
= EINVAL
; /* NFSv4 is only allowed over TCP. */
2897 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_PORT
))
2898 xb_get_32(error
, &xb
, nmp
->nm_nfsport
);
2899 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MOUNT_PORT
))
2900 xb_get_32(error
, &xb
, nmp
->nm_mountport
);
2901 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_REQUEST_TIMEOUT
)) {
2902 /* convert from time to 0.1s units */
2903 xb_get_32(error
, &xb
, nmp
->nm_timeo
);
2904 xb_get_32(error
, &xb
, val
);
2906 if (val
>= 1000000000)
2909 nmp
->nm_timeo
*= 10;
2910 nmp
->nm_timeo
+= (val
+100000000-1)/100000000;
2911 /* now convert to ticks */
2912 nmp
->nm_timeo
= (nmp
->nm_timeo
* NFS_HZ
+ 5) / 10;
2914 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SOFT_RETRY_COUNT
)) {
2915 xb_get_32(error
, &xb
, val
);
2916 if (!error
&& (val
> 1))
2917 nmp
->nm_retry
= val
;
2919 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_DEAD_TIMEOUT
)) {
2920 xb_get_32(error
, &xb
, nmp
->nm_deadtimeout
);
2921 xb_skip(error
, &xb
, XDRWORD
);
2923 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_FH
)) {
2925 MALLOC(nmp
->nm_fh
, fhandle_t
*, sizeof(fhandle_t
), M_TEMP
, M_WAITOK
|M_ZERO
);
2928 xb_get_32(error
, &xb
, nmp
->nm_fh
->fh_len
);
2930 error
= xb_get_bytes(&xb
, (char*)&nmp
->nm_fh
->fh_data
[0], nmp
->nm_fh
->fh_len
, 0);
2933 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_FS_LOCATIONS
)) {
2934 uint32_t loc
, serv
, addr
, comp
;
2935 struct nfs_fs_location
*fsl
;
2936 struct nfs_fs_server
*fss
;
2937 struct nfs_fs_path
*fsp
;
2939 xb_get_32(error
, &xb
, nmp
->nm_locations
.nl_numlocs
); /* fs location count */
2940 /* sanity check location count */
2941 if (!error
&& ((nmp
->nm_locations
.nl_numlocs
< 1) || (nmp
->nm_locations
.nl_numlocs
> 256)))
2944 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
);
2945 if (!nmp
->nm_locations
.nl_locations
)
2947 for (loc
= 0; loc
< nmp
->nm_locations
.nl_numlocs
; loc
++) {
2949 MALLOC(fsl
, struct nfs_fs_location
*, sizeof(struct nfs_fs_location
), M_TEMP
, M_WAITOK
|M_ZERO
);
2952 nmp
->nm_locations
.nl_locations
[loc
] = fsl
;
2953 xb_get_32(error
, &xb
, fsl
->nl_servcount
); /* server count */
2954 /* sanity check server count */
2955 if (!error
&& ((fsl
->nl_servcount
< 1) || (fsl
->nl_servcount
> 256)))
2958 MALLOC(fsl
->nl_servers
, struct nfs_fs_server
**, fsl
->nl_servcount
* sizeof(struct nfs_fs_server
*), M_TEMP
, M_WAITOK
|M_ZERO
);
2959 if (!fsl
->nl_servers
)
2961 for (serv
= 0; serv
< fsl
->nl_servcount
; serv
++) {
2963 MALLOC(fss
, struct nfs_fs_server
*, sizeof(struct nfs_fs_server
), M_TEMP
, M_WAITOK
|M_ZERO
);
2966 fsl
->nl_servers
[serv
] = fss
;
2967 xb_get_32(error
, &xb
, val
); /* server name length */
2968 /* sanity check server name length */
2969 if (!error
&& ((val
< 1) || (val
> MAXPATHLEN
)))
2972 MALLOC(fss
->ns_name
, char *, val
+1, M_TEMP
, M_WAITOK
|M_ZERO
);
2976 error
= xb_get_bytes(&xb
, fss
->ns_name
, val
, 0); /* server name */
2977 xb_get_32(error
, &xb
, fss
->ns_addrcount
); /* address count */
2978 /* sanity check address count (OK to be zero) */
2979 if (!error
&& (fss
->ns_addrcount
> 256))
2982 if (fss
->ns_addrcount
> 0) {
2983 MALLOC(fss
->ns_addresses
, char **, fss
->ns_addrcount
* sizeof(char *), M_TEMP
, M_WAITOK
|M_ZERO
);
2984 if (!fss
->ns_addresses
)
2986 for (addr
= 0; addr
< fss
->ns_addrcount
; addr
++) {
2987 xb_get_32(error
, &xb
, val
); /* address length */
2988 /* sanity check address length */
2989 if (!error
&& ((val
< 1) || (val
> 128)))
2992 MALLOC(fss
->ns_addresses
[addr
], char *, val
+1, M_TEMP
, M_WAITOK
|M_ZERO
);
2993 if (!fss
->ns_addresses
[addr
])
2996 error
= xb_get_bytes(&xb
, fss
->ns_addresses
[addr
], val
, 0); /* address */
2999 xb_get_32(error
, &xb
, val
); /* server info length */
3000 xb_skip(error
, &xb
, val
); /* skip server info */
3003 fsp
= &fsl
->nl_path
;
3004 xb_get_32(error
, &xb
, fsp
->np_compcount
); /* component count */
3005 /* sanity check component count */
3006 if (!error
&& (fsp
->np_compcount
> MAXPATHLEN
))
3009 if (fsp
->np_compcount
) {
3010 MALLOC(fsp
->np_components
, char **, fsp
->np_compcount
* sizeof(char*), M_TEMP
, M_WAITOK
|M_ZERO
);
3011 if (!fsp
->np_components
)
3014 for (comp
= 0; comp
< fsp
->np_compcount
; comp
++) {
3015 xb_get_32(error
, &xb
, val
); /* component length */
3016 /* sanity check component length */
3017 if (!error
&& (val
== 0)) {
3019 * Apparently some people think a path with zero components should
3020 * be encoded with one zero-length component. So, just ignore any
3021 * zero length components.
3024 fsp
->np_compcount
--;
3025 if (fsp
->np_compcount
== 0) {
3026 FREE(fsp
->np_components
, M_TEMP
);
3027 fsp
->np_components
= NULL
;
3031 if (!error
&& ((val
< 1) || (val
> MAXPATHLEN
)))
3034 MALLOC(fsp
->np_components
[comp
], char *, val
+1, M_TEMP
, M_WAITOK
|M_ZERO
);
3035 if (!fsp
->np_components
[comp
])
3038 error
= xb_get_bytes(&xb
, fsp
->np_components
[comp
], val
, 0); /* component */
3040 xb_get_32(error
, &xb
, val
); /* fs location info length */
3041 xb_skip(error
, &xb
, val
); /* skip fs location info */
3044 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MNTFLAGS
))
3045 xb_skip(error
, &xb
, XDRWORD
);
3046 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MNTFROM
)) {
3047 xb_get_32(error
, &xb
, len
);
3050 if (val
>= sizeof(vfs_statfs(mp
)->f_mntfromname
))
3051 val
= sizeof(vfs_statfs(mp
)->f_mntfromname
) - 1;
3052 error
= xb_get_bytes(&xb
, vfs_statfs(mp
)->f_mntfromname
, val
, 0);
3053 if ((len
- val
) > 0)
3054 xb_skip(error
, &xb
, len
- val
);
3056 vfs_statfs(mp
)->f_mntfromname
[val
] = '\0';
3060 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_REALM
)) {
3061 xb_get_32(error
, &xb
, len
);
3062 if (!error
&& ((len
< 1) || (len
> MAXPATHLEN
)))
3065 /* allocate an extra byte for a leading '@' if its not already prepended to the realm */
3066 MALLOC(nmp
->nm_realm
, char *, len
+2, M_TEMP
, M_WAITOK
|M_ZERO
);
3070 error
= xb_get_bytes(&xb
, nmp
->nm_realm
, len
, 0);
3071 if (error
== 0 && *nmp
->nm_realm
!= '@') {
3072 bcopy(nmp
->nm_realm
, &nmp
->nm_realm
[1], len
);
3073 nmp
->nm_realm
[0] = '@';
3078 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_PRINCIPAL
)) {
3079 xb_get_32(error
, &xb
, len
);
3080 if (!error
&& ((len
< 1) || (len
> MAXPATHLEN
)))
3083 MALLOC(nmp
->nm_principal
, char *, len
+1, M_TEMP
, M_WAITOK
|M_ZERO
);
3084 if (!nmp
->nm_principal
)
3087 error
= xb_get_bytes(&xb
, nmp
->nm_principal
, len
, 0);
3091 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SVCPRINCIPAL
)) {
3092 xb_get_32(error
, &xb
, len
);
3093 if (!error
&& ((len
< 1) || (len
> MAXPATHLEN
)))
3096 MALLOC(nmp
->nm_sprinc
, char *, len
+1, M_TEMP
, M_WAITOK
|M_ZERO
);
3097 if (!nmp
->nm_sprinc
)
3100 error
= xb_get_bytes(&xb
, nmp
->nm_sprinc
, len
, 0);
3105 * Sanity check/finalize settings.
3108 if (nmp
->nm_timeo
< NFS_MINTIMEO
)
3109 nmp
->nm_timeo
= NFS_MINTIMEO
;
3110 else if (nmp
->nm_timeo
> NFS_MAXTIMEO
)
3111 nmp
->nm_timeo
= NFS_MAXTIMEO
;
3112 if (nmp
->nm_retry
> NFS_MAXREXMIT
)
3113 nmp
->nm_retry
= NFS_MAXREXMIT
;
3115 if (nmp
->nm_numgrps
> NFS_MAXGRPS
)
3116 nmp
->nm_numgrps
= NFS_MAXGRPS
;
3117 if (nmp
->nm_readahead
> NFS_MAXRAHEAD
)
3118 nmp
->nm_readahead
= NFS_MAXRAHEAD
;
3119 if (nmp
->nm_acregmin
> nmp
->nm_acregmax
)
3120 nmp
->nm_acregmin
= nmp
->nm_acregmax
;
3121 if (nmp
->nm_acdirmin
> nmp
->nm_acdirmax
)
3122 nmp
->nm_acdirmin
= nmp
->nm_acdirmax
;
3124 /* need at least one fs location */
3125 if (nmp
->nm_locations
.nl_numlocs
< 1)
3129 /* init mount's mntfromname to first location */
3130 if (!NM_OMATTR_GIVEN(nmp
, MNTFROM
))
3131 nfs_location_mntfromname(&nmp
->nm_locations
, firstloc
,
3132 vfs_statfs(mp
)->f_mntfromname
, sizeof(vfs_statfs(mp
)->f_mntfromname
), 0);
3134 /* Need to save the mounting credential for v4. */
3135 nmp
->nm_mcred
= vfs_context_ucred(ctx
);
3136 if (IS_VALID_CRED(nmp
->nm_mcred
))
3137 kauth_cred_ref(nmp
->nm_mcred
);
3140 * If a reserved port is required, check for that privilege.
3141 * (Note that mirror mounts are exempt because the privilege was
3142 * already checked for the original mount.)
3144 if (NMFLAG(nmp
, RESVPORT
) && !vfs_iskernelmount(mp
))
3145 error
= priv_check_cred(nmp
->nm_mcred
, PRIV_NETINET_RESERVEDPORT
, 0);
3148 /* do mount's initial socket connection */
3149 error
= nfs_mount_connect(nmp
);
3152 /* set up the version-specific function tables */
3153 if (nmp
->nm_vers
< NFS_VER4
)
3154 nmp
->nm_funcs
= &nfs3_funcs
;
3156 nmp
->nm_funcs
= &nfs4_funcs
;
3158 /* sanity check settings now that version/connection is set */
3159 if (nmp
->nm_vers
== NFS_VER2
) /* ignore RDIRPLUS on NFSv2 */
3160 NFS_BITMAP_CLR(nmp
->nm_flags
, NFS_MFLAG_RDIRPLUS
);
3161 if (nmp
->nm_vers
>= NFS_VER4
) {
3162 if (NFS_BITMAP_ISSET(nmp
->nm_flags
, NFS_MFLAG_ACLONLY
)) /* aclonly trumps noacl */
3163 NFS_BITMAP_CLR(nmp
->nm_flags
, NFS_MFLAG_NOACL
);
3164 NFS_BITMAP_CLR(nmp
->nm_flags
, NFS_MFLAG_CALLUMNT
);
3165 if (nmp
->nm_lockmode
!= NFS_LOCK_MODE_ENABLED
)
3166 error
= EINVAL
; /* disabled/local lock mode only allowed on v2/v3 */
3168 /* ignore these if not v4 */
3169 NFS_BITMAP_CLR(nmp
->nm_flags
, NFS_MFLAG_NOCALLBACK
);
3170 NFS_BITMAP_CLR(nmp
->nm_flags
, NFS_MFLAG_NONAMEDATTR
);
3171 NFS_BITMAP_CLR(nmp
->nm_flags
, NFS_MFLAG_NOACL
);
3172 NFS_BITMAP_CLR(nmp
->nm_flags
, NFS_MFLAG_ACLONLY
);
3176 if (nmp
->nm_sotype
== SOCK_DGRAM
) {
3177 /* I/O size defaults for UDP are different */
3178 if (!NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READ_SIZE
))
3179 nmp
->nm_rsize
= NFS_DGRAM_RSIZE
;
3180 if (!NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_WRITE_SIZE
))
3181 nmp
->nm_wsize
= NFS_DGRAM_WSIZE
;
3184 /* round down I/O sizes to multiple of NFS_FABLKSIZE */
3185 nmp
->nm_rsize
&= ~(NFS_FABLKSIZE
- 1);
3186 if (nmp
->nm_rsize
<= 0)
3187 nmp
->nm_rsize
= NFS_FABLKSIZE
;
3188 nmp
->nm_wsize
&= ~(NFS_FABLKSIZE
- 1);
3189 if (nmp
->nm_wsize
<= 0)
3190 nmp
->nm_wsize
= NFS_FABLKSIZE
;
3192 /* and limit I/O sizes to maximum allowed */
3193 maxio
= (nmp
->nm_vers
== NFS_VER2
) ? NFS_V2MAXDATA
:
3194 (nmp
->nm_sotype
== SOCK_DGRAM
) ? NFS_MAXDGRAMDATA
: NFS_MAXDATA
;
3195 if (maxio
> NFS_MAXBSIZE
)
3196 maxio
= NFS_MAXBSIZE
;
3197 if (nmp
->nm_rsize
> maxio
)
3198 nmp
->nm_rsize
= maxio
;
3199 if (nmp
->nm_wsize
> maxio
)
3200 nmp
->nm_wsize
= maxio
;
3202 if (nmp
->nm_readdirsize
> maxio
)
3203 nmp
->nm_readdirsize
= maxio
;
3204 if (nmp
->nm_readdirsize
> nmp
->nm_rsize
)
3205 nmp
->nm_readdirsize
= nmp
->nm_rsize
;
3207 /* Set up the sockets and related info */
3208 if (nmp
->nm_sotype
== SOCK_DGRAM
)
3209 TAILQ_INIT(&nmp
->nm_cwndq
);
3212 * Get the root node/attributes from the NFS server and
3213 * do any basic, version-specific setup.
3215 error
= nmp
->nm_funcs
->nf_mount(nmp
, ctx
, &np
);
3219 * A reference count is needed on the node representing the
3220 * remote root. If this object is not persistent, then backward
3221 * traversals of the mount point (i.e. "..") will not work if
3222 * the node gets flushed out of the cache.
3226 /* get usecount and drop iocount */
3227 error
= vnode_ref(*vpp
);
3230 vnode_recycle(*vpp
);
3235 * Do statfs to ensure static info gets set to reasonable values.
3237 if ((error
= nmp
->nm_funcs
->nf_update_statfs(nmp
, ctx
))) {
3238 int error2
= vnode_getwithref(*vpp
);
3242 vnode_recycle(*vpp
);
3245 sbp
= vfs_statfs(mp
);
3246 sbp
->f_bsize
= nmp
->nm_fsattr
.nfsa_bsize
;
3247 sbp
->f_blocks
= nmp
->nm_fsattr
.nfsa_space_total
/ sbp
->f_bsize
;
3248 sbp
->f_bfree
= nmp
->nm_fsattr
.nfsa_space_free
/ sbp
->f_bsize
;
3249 sbp
->f_bavail
= nmp
->nm_fsattr
.nfsa_space_avail
/ sbp
->f_bsize
;
3250 sbp
->f_bused
= (nmp
->nm_fsattr
.nfsa_space_total
/ sbp
->f_bsize
) -
3251 (nmp
->nm_fsattr
.nfsa_space_free
/ sbp
->f_bsize
);
3252 sbp
->f_files
= nmp
->nm_fsattr
.nfsa_files_total
;
3253 sbp
->f_ffree
= nmp
->nm_fsattr
.nfsa_files_free
;
3254 sbp
->f_iosize
= nfs_iosize
;
3257 * Calculate the size used for I/O buffers. Use the larger
3258 * of the two sizes to minimise NFS requests but make sure
3259 * that it is at least one VM page to avoid wasting buffer
3260 * space and to allow easy mmapping of I/O buffers.
3261 * The read/write RPC calls handle the splitting up of
3262 * buffers into multiple requests if the buffer size is
3263 * larger than the I/O size.
3265 iosize
= max(nmp
->nm_rsize
, nmp
->nm_wsize
);
3266 if (iosize
< PAGE_SIZE
)
3268 nmp
->nm_biosize
= trunc_page_32(iosize
);
3270 /* For NFSv3 and greater, there is a (relatively) reliable ACCESS call. */
3271 if (nmp
->nm_vers
> NFS_VER2
)
3272 vfs_setauthopaqueaccess(mp
);
3274 switch (nmp
->nm_lockmode
) {
3275 case NFS_LOCK_MODE_DISABLED
:
3277 case NFS_LOCK_MODE_LOCAL
:
3278 vfs_setlocklocal(nmp
->nm_mountp
);
3280 case NFS_LOCK_MODE_ENABLED
:
3282 if (nmp
->nm_vers
<= NFS_VER3
)
3283 nfs_lockd_mount_register(nmp
);
3288 lck_mtx_lock(&nmp
->nm_lock
);
3289 nmp
->nm_state
|= NFSSTA_MOUNTED
;
3290 lck_mtx_unlock(&nmp
->nm_lock
);
3293 nfs_mount_cleanup(nmp
);
3300 * We've detected a file system boundary on the server and
3301 * need to mount a new file system so that our file systems
3302 * MIRROR the file systems on the server.
3304 * Build the mount arguments for the new mount and call kernel_mount().
3307 nfs_mirror_mount_domount(vnode_t dvp
, vnode_t vp
, vfs_context_t ctx
)
3309 nfsnode_t np
= VTONFS(vp
);
3310 nfsnode_t dnp
= VTONFS(dvp
);
3311 struct nfsmount
*nmp
= NFSTONMP(np
);
3312 char fstype
[MFSTYPENAMELEN
], *mntfromname
= NULL
, *path
= NULL
, *relpath
, *p
, *cp
;
3313 int error
= 0, pathbuflen
= MAXPATHLEN
, i
, mntflags
= 0, referral
, skipcopy
= 0;
3315 struct xdrbuf xb
, xbnew
;
3316 uint32_t mattrs
[NFS_MATTR_BITMAP_LEN
];
3317 uint32_t newmattrs
[NFS_MATTR_BITMAP_LEN
];
3318 uint32_t newmflags
[NFS_MFLAG_BITMAP_LEN
];
3319 uint32_t newmflags_mask
[NFS_MFLAG_BITMAP_LEN
];
3320 uint32_t argslength
= 0, val
, count
, mlen
, mlen2
, rlen
, relpathcomps
;
3321 uint32_t argslength_offset
, attrslength_offset
, end_offset
;
3322 uint32_t numlocs
, loc
, numserv
, serv
, numaddr
, addr
, numcomp
, comp
;
3324 struct nfs_fs_locations nfsls
;
3326 referral
= (np
->n_vattr
.nva_flags
& NFS_FFLAG_TRIGGER_REFERRAL
);
3328 bzero(&nfsls
, sizeof(nfsls
));
3332 if (!nmp
|| (nmp
->nm_state
& (NFSSTA_FORCE
|NFSSTA_DEAD
)))
3335 /* allocate a couple path buffers we need */
3336 MALLOC_ZONE(mntfromname
, char *, pathbuflen
, M_NAMEI
, M_WAITOK
);
3341 MALLOC_ZONE(path
, char *, pathbuflen
, M_NAMEI
, M_WAITOK
);
3347 /* get the path for the directory being mounted on */
3348 error
= vn_getpath(vp
, path
, &pathbuflen
);
3355 * Set up the mntfromname for the new mount based on the
3356 * current mount's mntfromname and the directory's path
3357 * relative to the current mount's mntonname.
3358 * Set up relpath to point at the relative path on the current mount.
3359 * Also, count the number of components in relpath.
3360 * We'll be adding those to each fs location path in the new args.
3362 nlen
= strlcpy(mntfromname
, vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
, MAXPATHLEN
);
3363 if ((nlen
> 0) && (mntfromname
[nlen
-1] == '/')) { /* avoid double '/' in new name */
3364 mntfromname
[nlen
-1] = '\0';
3367 relpath
= mntfromname
+ nlen
;
3368 nlen
= strlcat(mntfromname
, path
+ strlen(vfs_statfs(nmp
->nm_mountp
)->f_mntonname
), MAXPATHLEN
);
3369 if (nlen
>= MAXPATHLEN
) {
3370 error
= ENAMETOOLONG
;
3373 /* count the number of components in relpath */
3375 while (*p
&& (*p
== '/'))
3380 while (*p
&& (*p
!= '/'))
3382 while (*p
&& (*p
== '/'))
3386 /* grab a copy of the file system type */
3387 vfs_name(vnode_mount(vp
), fstype
);
3389 /* for referrals, fetch the fs locations */
3391 const char *vname
= vnode_getname(NFSTOV(np
));
3395 error
= nfs4_get_fs_locations(nmp
, dnp
, NULL
, 0, vname
, ctx
, &nfsls
);
3396 vnode_putname(vname
);
3397 if (!error
&& (nfsls
.nl_numlocs
< 1))
3403 /* set up NFS mount args based on current mount args */
3405 #define xb_copy_32(E, XBSRC, XBDST, V) \
3408 xb_get_32((E), (XBSRC), (V)); \
3409 if (skipcopy) break; \
3410 xb_add_32((E), (XBDST), (V)); \
3412 #define xb_copy_opaque(E, XBSRC, XBDST) \
3414 uint32_t __count, __val; \
3415 xb_copy_32((E), (XBSRC), (XBDST), __count); \
3417 __count = nfsm_rndup(__count); \
3418 __count /= XDRWORD; \
3419 while (__count-- > 0) \
3420 xb_copy_32((E), (XBSRC), (XBDST), __val); \
3423 xb_init_buffer(&xb
, nmp
->nm_args
, 2*XDRWORD
);
3424 xb_get_32(error
, &xb
, val
); /* version */
3425 xb_get_32(error
, &xb
, argslength
); /* args length */
3426 xb_init_buffer(&xb
, nmp
->nm_args
, argslength
);
3428 xb_init_buffer(&xbnew
, NULL
, 0);
3429 xb_copy_32(error
, &xb
, &xbnew
, val
); /* version */
3430 argslength_offset
= xb_offset(&xbnew
);
3431 xb_copy_32(error
, &xb
, &xbnew
, val
); /* args length */
3432 xb_copy_32(error
, &xb
, &xbnew
, val
); /* XDR args version */
3433 count
= NFS_MATTR_BITMAP_LEN
;
3434 xb_get_bitmap(error
, &xb
, mattrs
, count
); /* mount attribute bitmap */
3436 for (i
= 0; i
< NFS_MATTR_BITMAP_LEN
; i
++)
3437 newmattrs
[i
] = mattrs
[i
];
3439 NFS_BITMAP_SET(newmattrs
, NFS_MATTR_FS_LOCATIONS
);
3441 NFS_BITMAP_SET(newmattrs
, NFS_MATTR_FH
);
3442 NFS_BITMAP_SET(newmattrs
, NFS_MATTR_FLAGS
);
3443 NFS_BITMAP_SET(newmattrs
, NFS_MATTR_MNTFLAGS
);
3444 NFS_BITMAP_CLR(newmattrs
, NFS_MATTR_MNTFROM
);
3445 xb_add_bitmap(error
, &xbnew
, newmattrs
, NFS_MATTR_BITMAP_LEN
);
3446 attrslength_offset
= xb_offset(&xbnew
);
3447 xb_copy_32(error
, &xb
, &xbnew
, val
); /* attrs length */
3448 NFS_BITMAP_ZERO(newmflags_mask
, NFS_MFLAG_BITMAP_LEN
);
3449 NFS_BITMAP_ZERO(newmflags
, NFS_MFLAG_BITMAP_LEN
);
3450 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_FLAGS
)) {
3451 count
= NFS_MFLAG_BITMAP_LEN
;
3452 xb_get_bitmap(error
, &xb
, newmflags_mask
, count
); /* mount flag mask bitmap */
3453 count
= NFS_MFLAG_BITMAP_LEN
;
3454 xb_get_bitmap(error
, &xb
, newmflags
, count
); /* mount flag bitmap */
3456 NFS_BITMAP_SET(newmflags_mask
, NFS_MFLAG_EPHEMERAL
);
3457 NFS_BITMAP_SET(newmflags
, NFS_MFLAG_EPHEMERAL
);
3458 xb_add_bitmap(error
, &xbnew
, newmflags_mask
, NFS_MFLAG_BITMAP_LEN
);
3459 xb_add_bitmap(error
, &xbnew
, newmflags
, NFS_MFLAG_BITMAP_LEN
);
3460 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_VERSION
))
3461 xb_copy_32(error
, &xb
, &xbnew
, val
);
3462 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_MINOR_VERSION
))
3463 xb_copy_32(error
, &xb
, &xbnew
, val
);
3464 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READ_SIZE
))
3465 xb_copy_32(error
, &xb
, &xbnew
, val
);
3466 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_WRITE_SIZE
))
3467 xb_copy_32(error
, &xb
, &xbnew
, val
);
3468 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READDIR_SIZE
))
3469 xb_copy_32(error
, &xb
, &xbnew
, val
);
3470 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_READAHEAD
))
3471 xb_copy_32(error
, &xb
, &xbnew
, val
);
3472 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MIN
)) {
3473 xb_copy_32(error
, &xb
, &xbnew
, val
);
3474 xb_copy_32(error
, &xb
, &xbnew
, val
);
3476 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MAX
)) {
3477 xb_copy_32(error
, &xb
, &xbnew
, val
);
3478 xb_copy_32(error
, &xb
, &xbnew
, val
);
3480 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MIN
)) {
3481 xb_copy_32(error
, &xb
, &xbnew
, val
);
3482 xb_copy_32(error
, &xb
, &xbnew
, val
);
3484 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MAX
)) {
3485 xb_copy_32(error
, &xb
, &xbnew
, val
);
3486 xb_copy_32(error
, &xb
, &xbnew
, val
);
3488 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_LOCK_MODE
))
3489 xb_copy_32(error
, &xb
, &xbnew
, val
);
3490 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SECURITY
)) {
3491 xb_copy_32(error
, &xb
, &xbnew
, count
);
3492 while (!error
&& (count
-- > 0))
3493 xb_copy_32(error
, &xb
, &xbnew
, val
);
3495 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MAX_GROUP_LIST
))
3496 xb_copy_32(error
, &xb
, &xbnew
, val
);
3497 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SOCKET_TYPE
))
3498 xb_copy_opaque(error
, &xb
, &xbnew
);
3499 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_NFS_PORT
))
3500 xb_copy_32(error
, &xb
, &xbnew
, val
);
3501 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MOUNT_PORT
))
3502 xb_copy_32(error
, &xb
, &xbnew
, val
);
3503 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_REQUEST_TIMEOUT
)) {
3504 xb_copy_32(error
, &xb
, &xbnew
, val
);
3505 xb_copy_32(error
, &xb
, &xbnew
, val
);
3507 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SOFT_RETRY_COUNT
))
3508 xb_copy_32(error
, &xb
, &xbnew
, val
);
3509 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_DEAD_TIMEOUT
)) {
3510 xb_copy_32(error
, &xb
, &xbnew
, val
);
3511 xb_copy_32(error
, &xb
, &xbnew
, val
);
3513 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_FH
)) {
3514 xb_get_32(error
, &xb
, count
);
3515 xb_skip(error
, &xb
, count
);
3518 /* set the initial file handle to the directory's file handle */
3519 xb_add_fh(error
, &xbnew
, np
->n_fhp
, np
->n_fhsize
);
3521 /* copy/extend/skip fs locations */
3522 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_FS_LOCATIONS
)) {
3523 numlocs
= numserv
= numaddr
= numcomp
= 0;
3524 if (referral
) /* don't copy the fs locations for a referral */
3526 xb_copy_32(error
, &xb
, &xbnew
, numlocs
); /* location count */
3527 for (loc
= 0; !error
&& (loc
< numlocs
); loc
++) {
3528 xb_copy_32(error
, &xb
, &xbnew
, numserv
); /* server count */
3529 for (serv
= 0; !error
&& (serv
< numserv
); serv
++) {
3530 xb_copy_opaque(error
, &xb
, &xbnew
); /* server name */
3531 xb_copy_32(error
, &xb
, &xbnew
, numaddr
); /* address count */
3532 for (addr
= 0; !error
&& (addr
< numaddr
); addr
++)
3533 xb_copy_opaque(error
, &xb
, &xbnew
); /* address */
3534 xb_copy_opaque(error
, &xb
, &xbnew
); /* server info */
3537 xb_get_32(error
, &xb
, numcomp
); /* component count */
3539 xb_add_32(error
, &xbnew
, numcomp
+relpathcomps
); /* new component count */
3540 for (comp
= 0; !error
&& (comp
< numcomp
); comp
++)
3541 xb_copy_opaque(error
, &xb
, &xbnew
); /* component */
3542 /* add additional components */
3543 for (comp
= 0; !skipcopy
&& !error
&& (comp
< relpathcomps
); comp
++) {
3545 while (*p
&& (*p
== '/'))
3547 while (*p
&& !error
) {
3549 while (*p
&& (*p
!= '/'))
3551 xb_add_string(error
, &xbnew
, cp
, (p
- cp
)); /* component */
3552 while (*p
&& (*p
== '/'))
3556 xb_copy_opaque(error
, &xb
, &xbnew
); /* fs location info */
3562 /* add referral's fs locations */
3563 xb_add_32(error
, &xbnew
, nfsls
.nl_numlocs
); /* FS_LOCATIONS */
3564 for (loc
= 0; !error
&& (loc
< nfsls
.nl_numlocs
); loc
++) {
3565 xb_add_32(error
, &xbnew
, nfsls
.nl_locations
[loc
]->nl_servcount
);
3566 for (serv
= 0; !error
&& (serv
< nfsls
.nl_locations
[loc
]->nl_servcount
); serv
++) {
3567 xb_add_string(error
, &xbnew
, nfsls
.nl_locations
[loc
]->nl_servers
[serv
]->ns_name
,
3568 strlen(nfsls
.nl_locations
[loc
]->nl_servers
[serv
]->ns_name
));
3569 xb_add_32(error
, &xbnew
, nfsls
.nl_locations
[loc
]->nl_servers
[serv
]->ns_addrcount
);
3570 for (addr
= 0; !error
&& (addr
< nfsls
.nl_locations
[loc
]->nl_servers
[serv
]->ns_addrcount
); addr
++)
3571 xb_add_string(error
, &xbnew
, nfsls
.nl_locations
[loc
]->nl_servers
[serv
]->ns_addresses
[addr
],
3572 strlen(nfsls
.nl_locations
[loc
]->nl_servers
[serv
]->ns_addresses
[addr
]));
3573 xb_add_32(error
, &xbnew
, 0); /* empty server info */
3575 xb_add_32(error
, &xbnew
, nfsls
.nl_locations
[loc
]->nl_path
.np_compcount
);
3576 for (comp
= 0; !error
&& (comp
< nfsls
.nl_locations
[loc
]->nl_path
.np_compcount
); comp
++)
3577 xb_add_string(error
, &xbnew
, nfsls
.nl_locations
[loc
]->nl_path
.np_components
[comp
],
3578 strlen(nfsls
.nl_locations
[loc
]->nl_path
.np_components
[comp
]));
3579 xb_add_32(error
, &xbnew
, 0); /* empty fs location info */
3582 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MNTFLAGS
))
3583 xb_get_32(error
, &xb
, mntflags
);
3585 * We add the following mount flags to the ones for the mounted-on mount:
3586 * MNT_DONTBROWSE - to keep the mount from showing up as a separate volume
3587 * MNT_AUTOMOUNTED - to keep DiskArb from retriggering the mount after
3588 * an unmount (looking for /.autodiskmounted)
3590 mntflags
|= (MNT_AUTOMOUNTED
| MNT_DONTBROWSE
);
3591 xb_add_32(error
, &xbnew
, mntflags
);
3592 if (!referral
&& NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_MNTFROM
)) {
3593 /* copy mntfrom string and add relpath */
3594 rlen
= strlen(relpath
);
3595 xb_get_32(error
, &xb
, mlen
);
3597 mlen2
= mlen
+ ((relpath
[0] != '/') ? 1 : 0) + rlen
;
3598 xb_add_32(error
, &xbnew
, mlen2
);
3599 count
= mlen
/XDRWORD
;
3600 /* copy the original string */
3602 xb_copy_32(error
, &xb
, &xbnew
, val
);
3603 if (!error
&& (mlen
% XDRWORD
)) {
3604 error
= xb_get_bytes(&xb
, buf
, mlen%XDRWORD
, 0);
3606 error
= xb_add_bytes(&xbnew
, buf
, mlen%XDRWORD
, 1);
3608 /* insert a '/' if the relative path doesn't start with one */
3609 if (!error
&& (relpath
[0] != '/')) {
3611 error
= xb_add_bytes(&xbnew
, buf
, 1, 1);
3613 /* add the additional relative path */
3615 error
= xb_add_bytes(&xbnew
, relpath
, rlen
, 1);
3616 /* make sure the resulting string has the right number of pad bytes */
3617 if (!error
&& (mlen2
!= nfsm_rndup(mlen2
))) {
3618 bzero(buf
, sizeof(buf
));
3619 count
= nfsm_rndup(mlen2
) - mlen2
;
3620 error
= xb_add_bytes(&xbnew
, buf
, count
, 1);
3623 xb_build_done(error
, &xbnew
);
3625 /* update opaque counts */
3626 end_offset
= xb_offset(&xbnew
);
3628 error
= xb_seek(&xbnew
, argslength_offset
);
3629 argslength
= end_offset
- argslength_offset
+ XDRWORD
/*version*/;
3630 xb_add_32(error
, &xbnew
, argslength
);
3633 error
= xb_seek(&xbnew
, attrslength_offset
);
3634 xb_add_32(error
, &xbnew
, end_offset
- attrslength_offset
- XDRWORD
/*don't include length field*/);
3639 * For kernel_mount() call, use the existing mount flags (instead of the
3640 * original flags) because flags like MNT_NOSUID and MNT_NODEV may have
3641 * been silently enforced.
3643 mntflags
= vnode_vfsvisflags(vp
);
3644 mntflags
|= (MNT_AUTOMOUNTED
| MNT_DONTBROWSE
);
3647 error
= kernel_mount(fstype
, dvp
, vp
, path
, xb_buffer_base(&xbnew
), argslength
,
3648 mntflags
, KERNEL_MOUNT_PERMIT_UNMOUNT
| KERNEL_MOUNT_NOAUTH
, ctx
);
3652 printf("nfs: mirror mount of %s on %s failed (%d)\n",
3653 mntfromname
, path
, error
);
3657 nfs_fs_locations_cleanup(&nfsls
);
3659 FREE_ZONE(path
, MAXPATHLEN
, M_NAMEI
);
3661 FREE_ZONE(mntfromname
, MAXPATHLEN
, M_NAMEI
);
3663 nfs_ephemeral_mount_harvester_start();
3668 * trigger vnode functions
3672 nfs_mirror_mount_trigger_resolve(
3674 const struct componentname
*cnp
,
3675 enum path_operation pop
,
3677 __unused
void *data
,
3680 nfsnode_t np
= VTONFS(vp
);
3681 vnode_t pvp
= NULLVP
;
3683 resolver_result_t result
;
3686 * We have a trigger node that doesn't have anything mounted on it yet.
3687 * We'll do the mount if either:
3688 * (a) this isn't the last component of the path OR
3689 * (b) this is an op that looks like it should trigger the mount.
3691 if (cnp
->cn_flags
& ISLASTCN
) {
3709 /* don't perform the mount for these operations */
3710 result
= vfs_resolver_result(np
->n_trigseq
, RESOLVER_NOCHANGE
, 0);
3711 #ifdef NFS_TRIGGER_DEBUG
3712 NP(np
, "nfs trigger RESOLVE: no change, last %d nameiop %d, seq %d",
3713 (cnp
->cn_flags
& ISLASTCN
) ? 1 : 0, cnp
->cn_nameiop
, np
->n_trigseq
);
3724 case OP_EXCHANGEDATA
:
3728 case OP_REMOVEXATTR
:
3730 /* go ahead and do the mount */
3735 if (vnode_mountedhere(vp
) != NULL
) {
3737 * Um... there's already something mounted.
3738 * Been there. Done that. Let's just say it succeeded.
3744 if ((error
= nfs_node_set_busy(np
, vfs_context_thread(ctx
)))) {
3745 result
= vfs_resolver_result(np
->n_trigseq
, RESOLVER_ERROR
, error
);
3746 #ifdef NFS_TRIGGER_DEBUG
3747 NP(np
, "nfs trigger RESOLVE: busy error %d, last %d nameiop %d, seq %d",
3748 error
, (cnp
->cn_flags
& ISLASTCN
) ? 1 : 0, cnp
->cn_nameiop
, np
->n_trigseq
);
3753 pvp
= vnode_getparent(vp
);
3757 error
= nfs_mirror_mount_domount(pvp
, vp
, ctx
);
3761 result
= vfs_resolver_result(np
->n_trigseq
, error
? RESOLVER_ERROR
: RESOLVER_RESOLVED
, error
);
3762 #ifdef NFS_TRIGGER_DEBUG
3763 NP(np
, "nfs trigger RESOLVE: %s %d, last %d nameiop %d, seq %d",
3764 error
? "error" : "resolved", error
,
3765 (cnp
->cn_flags
& ISLASTCN
) ? 1 : 0, cnp
->cn_nameiop
, np
->n_trigseq
);
3770 nfs_node_clear_busy(np
);
3775 nfs_mirror_mount_trigger_unresolve(
3778 __unused
void *data
,
3781 nfsnode_t np
= VTONFS(vp
);
3784 resolver_result_t result
;
3786 if ((error
= nfs_node_set_busy(np
, vfs_context_thread(ctx
)))) {
3787 result
= vfs_resolver_result(np
->n_trigseq
, RESOLVER_ERROR
, error
);
3788 #ifdef NFS_TRIGGER_DEBUG
3789 NP(np
, "nfs trigger UNRESOLVE: busy error %d, seq %d", error
, np
->n_trigseq
);
3794 mp
= vnode_mountedhere(vp
);
3798 error
= vfs_unmountbyfsid(&(vfs_statfs(mp
)->f_fsid
), flags
, ctx
);
3801 result
= vfs_resolver_result(np
->n_trigseq
, error
? RESOLVER_ERROR
: RESOLVER_UNRESOLVED
, error
);
3802 #ifdef NFS_TRIGGER_DEBUG
3803 NP(np
, "nfs trigger UNRESOLVE: %s %d, seq %d",
3804 error
? "error" : "unresolved", error
, np
->n_trigseq
);
3806 nfs_node_clear_busy(np
);
3811 nfs_mirror_mount_trigger_rearm(
3814 __unused
void *data
,
3817 nfsnode_t np
= VTONFS(vp
);
3819 resolver_result_t result
;
3821 if ((error
= nfs_node_set_busy(np
, vfs_context_thread(ctx
)))) {
3822 result
= vfs_resolver_result(np
->n_trigseq
, RESOLVER_ERROR
, error
);
3823 #ifdef NFS_TRIGGER_DEBUG
3824 NP(np
, "nfs trigger REARM: busy error %d, seq %d", error
, np
->n_trigseq
);
3830 result
= vfs_resolver_result(np
->n_trigseq
,
3831 vnode_mountedhere(vp
) ? RESOLVER_RESOLVED
: RESOLVER_UNRESOLVED
, 0);
3832 #ifdef NFS_TRIGGER_DEBUG
3833 NP(np
, "nfs trigger REARM: %s, seq %d",
3834 vnode_mountedhere(vp
) ? "resolved" : "unresolved", np
->n_trigseq
);
3836 nfs_node_clear_busy(np
);
3841 * Periodically attempt to unmount ephemeral (mirror) mounts in an attempt to limit
3842 * the number of unused mounts.
3845 #define NFS_EPHEMERAL_MOUNT_HARVEST_INTERVAL 120 /* how often the harvester runs */
3846 struct nfs_ephemeral_mount_harvester_info
{
3847 fsid_t fsid
; /* FSID that we need to try to unmount */
3848 uint32_t mountcount
; /* count of ephemeral mounts seen in scan */
3850 /* various globals for the harvester */
3851 static thread_call_t nfs_ephemeral_mount_harvester_timer
= NULL
;
3852 static int nfs_ephemeral_mount_harvester_on
= 0;
3854 kern_return_t
thread_terminate(thread_t
);
3857 nfs_ephemeral_mount_harvester_callback(mount_t mp
, void *arg
)
3859 struct nfs_ephemeral_mount_harvester_info
*hinfo
= arg
;
3860 struct nfsmount
*nmp
;
3863 if (strcmp(mp
->mnt_vfsstat
.f_fstypename
, "nfs"))
3864 return (VFS_RETURNED
);
3866 if (!nmp
|| !NMFLAG(nmp
, EPHEMERAL
))
3867 return (VFS_RETURNED
);
3868 hinfo
->mountcount
++;
3870 /* avoid unmounting mounts that have been triggered within the last harvest interval */
3872 if ((nmp
->nm_mounttime
>> 32) > ((uint32_t)now
.tv_sec
- NFS_EPHEMERAL_MOUNT_HARVEST_INTERVAL
))
3873 return (VFS_RETURNED
);
3875 if (hinfo
->fsid
.val
[0] || hinfo
->fsid
.val
[1]) {
3876 /* attempt to unmount previously-found ephemeral mount */
3877 vfs_unmountbyfsid(&hinfo
->fsid
, 0, vfs_context_kernel());
3878 hinfo
->fsid
.val
[0] = hinfo
->fsid
.val
[1] = 0;
3882 * We can't call unmount here since we hold a mount iter ref
3883 * on mp so save its fsid for the next call iteration to unmount.
3885 hinfo
->fsid
.val
[0] = mp
->mnt_vfsstat
.f_fsid
.val
[0];
3886 hinfo
->fsid
.val
[1] = mp
->mnt_vfsstat
.f_fsid
.val
[1];
3888 return (VFS_RETURNED
);
3892 * Spawn a thread to do the ephemeral mount harvesting.
3895 nfs_ephemeral_mount_harvester_timer_func(void)
3899 if (kernel_thread_start(nfs_ephemeral_mount_harvester
, NULL
, &thd
) == KERN_SUCCESS
)
3900 thread_deallocate(thd
);
3904 * Iterate all mounts looking for NFS ephemeral mounts to try to unmount.
3907 nfs_ephemeral_mount_harvester(__unused
void *arg
, __unused wait_result_t wr
)
3909 struct nfs_ephemeral_mount_harvester_info hinfo
;
3912 hinfo
.mountcount
= 0;
3913 hinfo
.fsid
.val
[0] = hinfo
.fsid
.val
[1] = 0;
3914 vfs_iterate(VFS_ITERATE_TAIL_FIRST
, nfs_ephemeral_mount_harvester_callback
, &hinfo
);
3915 if (hinfo
.fsid
.val
[0] || hinfo
.fsid
.val
[1]) {
3916 /* attempt to unmount last found ephemeral mount */
3917 vfs_unmountbyfsid(&hinfo
.fsid
, 0, vfs_context_kernel());
3920 lck_mtx_lock(nfs_global_mutex
);
3921 if (!hinfo
.mountcount
) {
3922 /* no more ephemeral mounts - don't need timer */
3923 nfs_ephemeral_mount_harvester_on
= 0;
3925 /* re-arm the timer */
3926 clock_interval_to_deadline(NFS_EPHEMERAL_MOUNT_HARVEST_INTERVAL
, NSEC_PER_SEC
, &deadline
);
3927 thread_call_enter_delayed(nfs_ephemeral_mount_harvester_timer
, deadline
);
3928 nfs_ephemeral_mount_harvester_on
= 1;
3930 lck_mtx_unlock(nfs_global_mutex
);
3933 thread_terminate(current_thread());
3937 * Make sure the NFS ephemeral mount harvester timer is running.
3940 nfs_ephemeral_mount_harvester_start(void)
3944 lck_mtx_lock(nfs_global_mutex
);
3945 if (nfs_ephemeral_mount_harvester_on
) {
3946 lck_mtx_unlock(nfs_global_mutex
);
3949 if (nfs_ephemeral_mount_harvester_timer
== NULL
)
3950 nfs_ephemeral_mount_harvester_timer
= thread_call_allocate((thread_call_func_t
)nfs_ephemeral_mount_harvester_timer_func
, NULL
);
3951 clock_interval_to_deadline(NFS_EPHEMERAL_MOUNT_HARVEST_INTERVAL
, NSEC_PER_SEC
, &deadline
);
3952 thread_call_enter_delayed(nfs_ephemeral_mount_harvester_timer
, deadline
);
3953 nfs_ephemeral_mount_harvester_on
= 1;
3954 lck_mtx_unlock(nfs_global_mutex
);
3960 * Send a MOUNT protocol MOUNT request to the server to get the initial file handle (and security).
3963 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
)
3965 int error
= 0, slen
, mntproto
;
3966 thread_t thd
= vfs_context_thread(ctx
);
3967 kauth_cred_t cred
= vfs_context_ucred(ctx
);
3969 struct nfsm_chain nmreq
, nmrep
;
3971 uint32_t mntvers
, mntport
, val
;
3972 struct sockaddr_storage ss
;
3973 struct sockaddr
*saddr
= (struct sockaddr
*)&ss
;
3975 nfsm_chain_null(&nmreq
);
3976 nfsm_chain_null(&nmrep
);
3978 mntvers
= (nfsvers
== NFS_VER2
) ? RPCMNT_VER1
: RPCMNT_VER3
;
3979 mntproto
= (NM_OMFLAG(nmp
, MNTUDP
) || (sotype
== SOCK_DGRAM
)) ? IPPROTO_UDP
: IPPROTO_TCP
;
3982 bcopy(sa
, saddr
, min(sizeof(ss
), sa
->sa_len
));
3983 if (saddr
->sa_family
== AF_INET
) {
3984 if (nmp
->nm_mountport
)
3985 ((struct sockaddr_in
*)saddr
)->sin_port
= htons(nmp
->nm_mountport
);
3986 mntport
= ntohs(((struct sockaddr_in
*)saddr
)->sin_port
);
3988 if (nmp
->nm_mountport
)
3989 ((struct sockaddr_in6
*)saddr
)->sin6_port
= htons(nmp
->nm_mountport
);
3990 mntport
= ntohs(((struct sockaddr_in6
*)saddr
)->sin6_port
);
3994 error
= nfs_portmap_lookup(nmp
, ctx
, saddr
, NULL
, RPCPROG_MNT
, mntvers
, mntproto
, timeo
);
3996 if (saddr
->sa_family
== AF_INET
)
3997 mntport
= ntohs(((struct sockaddr_in
*)saddr
)->sin_port
);
3999 mntport
= ntohs(((struct sockaddr_in6
*)saddr
)->sin6_port
);
4001 /* if not found and TCP, then retry with UDP */
4002 if (mntproto
== IPPROTO_UDP
) {
4003 error
= EPROGUNAVAIL
;
4006 mntproto
= IPPROTO_UDP
;
4007 bcopy(sa
, saddr
, min(sizeof(ss
), sa
->sa_len
));
4010 nfsmout_if(error
|| !mntport
);
4012 /* MOUNT protocol MOUNT request */
4013 slen
= strlen(path
);
4014 nfsm_chain_build_alloc_init(error
, &nmreq
, NFSX_UNSIGNED
+ nfsm_rndup(slen
));
4015 nfsm_chain_add_name(error
, &nmreq
, path
, slen
, nmp
);
4016 nfsm_chain_build_done(error
, &nmreq
);
4018 error
= nfsm_rpchead2(nmp
, (mntproto
== IPPROTO_UDP
) ? SOCK_DGRAM
: SOCK_STREAM
,
4019 RPCPROG_MNT
, mntvers
, RPCMNT_MOUNT
,
4020 RPCAUTH_SYS
, cred
, NULL
, nmreq
.nmc_mhead
, &xid
, &mreq
);
4022 nmreq
.nmc_mhead
= NULL
;
4023 error
= nfs_aux_request(nmp
, thd
, saddr
, NULL
,
4024 ((mntproto
== IPPROTO_UDP
) ? SOCK_DGRAM
: SOCK_STREAM
),
4025 mreq
, R_XID32(xid
), 1, timeo
, &nmrep
);
4027 nfsm_chain_get_32(error
, &nmrep
, val
);
4030 nfsm_chain_get_fh(error
, &nmrep
, nfsvers
, fh
);
4031 if (!error
&& (nfsvers
> NFS_VER2
)) {
4032 sec
->count
= NX_MAX_SEC_FLAVORS
;
4033 error
= nfsm_chain_get_secinfo(&nmrep
, &sec
->flavors
[0], &sec
->count
);
4036 nfsm_chain_cleanup(&nmreq
);
4037 nfsm_chain_cleanup(&nmrep
);
4043 * Send a MOUNT protocol UNMOUNT request to tell the server we've unmounted it.
4046 nfs3_umount_rpc(struct nfsmount
*nmp
, vfs_context_t ctx
, int timeo
)
4048 int error
= 0, slen
, mntproto
;
4049 thread_t thd
= vfs_context_thread(ctx
);
4050 kauth_cred_t cred
= vfs_context_ucred(ctx
);
4053 struct nfsm_chain nmreq
, nmrep
;
4055 uint32_t mntvers
, mntport
;
4056 struct sockaddr_storage ss
;
4057 struct sockaddr
*saddr
= (struct sockaddr
*)&ss
;
4062 nfsm_chain_null(&nmreq
);
4063 nfsm_chain_null(&nmrep
);
4065 mntvers
= (nmp
->nm_vers
== NFS_VER2
) ? RPCMNT_VER1
: RPCMNT_VER3
;
4066 mntproto
= (NM_OMFLAG(nmp
, MNTUDP
) || (nmp
->nm_sotype
== SOCK_DGRAM
)) ? IPPROTO_UDP
: IPPROTO_TCP
;
4067 mntport
= nmp
->nm_mountport
;
4069 bcopy(nmp
->nm_saddr
, saddr
, min(sizeof(ss
), nmp
->nm_saddr
->sa_len
));
4070 if (saddr
->sa_family
== AF_INET
)
4071 ((struct sockaddr_in
*)saddr
)->sin_port
= htons(mntport
);
4073 ((struct sockaddr_in6
*)saddr
)->sin6_port
= htons(mntport
);
4076 error
= nfs_portmap_lookup(nmp
, ctx
, saddr
, NULL
, RPCPROG_MNT
, mntvers
, mntproto
, timeo
);
4078 if (saddr
->sa_family
== AF_INET
)
4079 mntport
= ntohs(((struct sockaddr_in
*)saddr
)->sin_port
);
4081 mntport
= ntohs(((struct sockaddr_in6
*)saddr
)->sin6_port
);
4082 /* if not found and mntvers > VER1, then retry with VER1 */
4084 if (mntvers
> RPCMNT_VER1
) {
4085 mntvers
= RPCMNT_VER1
;
4086 } else if (mntproto
== IPPROTO_TCP
) {
4087 mntproto
= IPPROTO_UDP
;
4088 mntvers
= (nmp
->nm_vers
== NFS_VER2
) ? RPCMNT_VER1
: RPCMNT_VER3
;
4092 bcopy(nmp
->nm_saddr
, saddr
, min(sizeof(ss
), nmp
->nm_saddr
->sa_len
));
4095 nfsmout_if(!mntport
);
4097 /* MOUNT protocol UNMOUNT request */
4098 path
= &vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
[0];
4099 while (*path
&& (*path
!= '/'))
4101 slen
= strlen(path
);
4102 nfsm_chain_build_alloc_init(error
, &nmreq
, NFSX_UNSIGNED
+ nfsm_rndup(slen
));
4103 nfsm_chain_add_name(error
, &nmreq
, path
, slen
, nmp
);
4104 nfsm_chain_build_done(error
, &nmreq
);
4106 error
= nfsm_rpchead2(nmp
, (mntproto
== IPPROTO_UDP
) ? SOCK_DGRAM
: SOCK_STREAM
,
4107 RPCPROG_MNT
, RPCMNT_VER1
, RPCMNT_UMOUNT
,
4108 RPCAUTH_SYS
, cred
, NULL
, nmreq
.nmc_mhead
, &xid
, &mreq
);
4110 nmreq
.nmc_mhead
= NULL
;
4111 error
= nfs_aux_request(nmp
, thd
, saddr
, NULL
,
4112 ((mntproto
== IPPROTO_UDP
) ? SOCK_DGRAM
: SOCK_STREAM
),
4113 mreq
, R_XID32(xid
), 1, timeo
, &nmrep
);
4115 nfsm_chain_cleanup(&nmreq
);
4116 nfsm_chain_cleanup(&nmrep
);
4120 * unmount system call
4126 __unused vfs_context_t ctx
)
4128 struct nfsmount
*nmp
;
4130 int error
, flags
= 0;
4131 struct timespec ts
= { 1, 0 };
4134 lck_mtx_lock(&nmp
->nm_lock
);
4136 * Set the flag indicating that an unmount attempt is in progress.
4138 nmp
->nm_state
|= NFSSTA_UNMOUNTING
;
4140 * During a force unmount we want to...
4141 * Mark that we are doing a force unmount.
4142 * Make the mountpoint soft.
4144 if (mntflags
& MNT_FORCE
) {
4145 flags
|= FORCECLOSE
;
4146 nmp
->nm_state
|= NFSSTA_FORCE
;
4147 NFS_BITMAP_SET(nmp
->nm_flags
, NFS_MFLAG_SOFT
);
4150 * Wait for any in-progress monitored node scan to complete.
4152 while (nmp
->nm_state
& NFSSTA_MONITOR_SCAN
)
4153 msleep(&nmp
->nm_state
, &nmp
->nm_lock
, PZERO
-1, "nfswaitmonscan", &ts
);
4155 * Goes something like this..
4156 * - Call vflush() to clear out vnodes for this file system,
4157 * except for the swap files. Deal with them in 2nd pass.
4158 * - Decrement reference on the vnode representing remote root.
4159 * - Clean up the NFS mount structure.
4161 vp
= NFSTOV(nmp
->nm_dnp
);
4162 lck_mtx_unlock(&nmp
->nm_lock
);
4165 * vflush will check for busy vnodes on mountpoint.
4166 * Will do the right thing for MNT_FORCE. That is, we should
4167 * not get EBUSY back.
4169 error
= vflush(mp
, vp
, SKIPSWAP
| flags
);
4170 if (mntflags
& MNT_FORCE
) {
4171 error
= vflush(mp
, NULLVP
, flags
); /* locks vp in the process */
4173 if (vnode_isinuse(vp
, 1))
4176 error
= vflush(mp
, vp
, flags
);
4179 lck_mtx_lock(&nmp
->nm_lock
);
4180 nmp
->nm_state
&= ~NFSSTA_UNMOUNTING
;
4181 lck_mtx_unlock(&nmp
->nm_lock
);
4185 lck_mtx_lock(&nmp
->nm_lock
);
4187 lck_mtx_unlock(&nmp
->nm_lock
);
4190 * Release the root vnode reference held by mountnfs()
4192 error
= vnode_get(vp
);
4197 vflush(mp
, NULLVP
, FORCECLOSE
);
4199 /* Wait for all other references to be released and free the mount */
4200 nfs_mount_drain_and_cleanup(nmp
);
4206 * cleanup/destroy NFS fs locations structure
4209 nfs_fs_locations_cleanup(struct nfs_fs_locations
*nfslsp
)
4211 struct nfs_fs_location
*fsl
;
4212 struct nfs_fs_server
*fss
;
4213 struct nfs_fs_path
*fsp
;
4214 uint32_t loc
, serv
, addr
, comp
;
4216 /* free up fs locations */
4217 if (!nfslsp
->nl_numlocs
|| !nfslsp
->nl_locations
)
4220 for (loc
= 0; loc
< nfslsp
->nl_numlocs
; loc
++) {
4221 fsl
= nfslsp
->nl_locations
[loc
];
4224 if ((fsl
->nl_servcount
> 0) && fsl
->nl_servers
) {
4225 for (serv
= 0; serv
< fsl
->nl_servcount
; serv
++) {
4226 fss
= fsl
->nl_servers
[serv
];
4229 if ((fss
->ns_addrcount
> 0) && fss
->ns_addresses
) {
4230 for (addr
= 0; addr
< fss
->ns_addrcount
; addr
++)
4231 FREE(fss
->ns_addresses
[addr
], M_TEMP
);
4232 FREE(fss
->ns_addresses
, M_TEMP
);
4234 FREE(fss
->ns_name
, M_TEMP
);
4237 FREE(fsl
->nl_servers
, M_TEMP
);
4239 fsp
= &fsl
->nl_path
;
4240 if (fsp
->np_compcount
&& fsp
->np_components
) {
4241 for (comp
= 0; comp
< fsp
->np_compcount
; comp
++)
4242 if (fsp
->np_components
[comp
])
4243 FREE(fsp
->np_components
[comp
], M_TEMP
);
4244 FREE(fsp
->np_components
, M_TEMP
);
4248 FREE(nfslsp
->nl_locations
, M_TEMP
);
4249 nfslsp
->nl_numlocs
= 0;
4250 nfslsp
->nl_locations
= NULL
;
4254 nfs_mount_rele(struct nfsmount
*nmp
)
4258 lck_mtx_lock(&nmp
->nm_lock
);
4259 if (nmp
->nm_ref
< 1)
4260 panic("nfs zombie mount underflow\n");
4262 if (nmp
->nm_ref
== 0)
4263 wup
= nmp
->nm_state
& NFSSTA_MOUNT_DRAIN
;
4264 lck_mtx_unlock(&nmp
->nm_lock
);
4266 wakeup(&nmp
->nm_ref
);
4270 nfs_mount_drain_and_cleanup(struct nfsmount
*nmp
)
4272 lck_mtx_lock(&nmp
->nm_lock
);
4273 nmp
->nm_state
|= NFSSTA_MOUNT_DRAIN
;
4274 while (nmp
->nm_ref
> 0) {
4275 msleep(&nmp
->nm_ref
, &nmp
->nm_lock
, PZERO
-1, "nfs_mount_drain", NULL
);
4277 assert(nmp
->nm_ref
== 0);
4278 lck_mtx_unlock(&nmp
->nm_lock
);
4279 nfs_mount_cleanup(nmp
);
4286 nfs_mount_zombie(struct nfsmount
*nmp
, int nm_state_flags
)
4288 struct nfsreq
*req
, *treq
;
4289 struct nfs_reqqhead iodq
;
4290 struct timespec ts
= { 1, 0 };
4291 struct nfs_open_owner
*noop
, *nextnoop
;
4295 lck_mtx_lock(&nmp
->nm_lock
);
4296 nmp
->nm_state
|= nm_state_flags
;
4298 lck_mtx_unlock(&nmp
->nm_lock
);
4300 /* stop callbacks */
4301 if ((nmp
->nm_vers
>= NFS_VER4
) && !NMFLAG(nmp
, NOCALLBACK
) && nmp
->nm_cbid
)
4302 nfs4_mount_callback_shutdown(nmp
);
4304 /* Destroy any RPCSEC_GSS contexts */
4305 if (!TAILQ_EMPTY(&nmp
->nm_gsscl
))
4306 nfs_gss_clnt_ctx_unmount(nmp
);
4308 /* mark the socket for termination */
4309 lck_mtx_lock(&nmp
->nm_lock
);
4310 nmp
->nm_sockflags
|= NMSOCK_UNMOUNT
;
4312 /* Have the socket thread send the unmount RPC, if requested/appropriate. */
4313 if ((nmp
->nm_vers
< NFS_VER4
) && (nmp
->nm_state
& NFSSTA_MOUNTED
) &&
4314 !(nmp
->nm_state
& (NFSSTA_FORCE
|NFSSTA_DEAD
)) && NMFLAG(nmp
, CALLUMNT
))
4315 nfs_mount_sock_thread_wake(nmp
);
4317 /* wait for the socket thread to terminate */
4318 while (nmp
->nm_sockthd
&& current_thread() != nmp
->nm_sockthd
) {
4319 wakeup(&nmp
->nm_sockthd
);
4320 msleep(&nmp
->nm_sockthd
, &nmp
->nm_lock
, PZERO
-1, "nfswaitsockthd", &ts
);
4322 lck_mtx_unlock(&nmp
->nm_lock
);
4324 /* tear down the socket */
4325 nfs_disconnect(nmp
);
4327 lck_mtx_lock(&nmp
->nm_lock
);
4329 if ((nmp
->nm_vers
>= NFS_VER4
) && !NMFLAG(nmp
, NOCALLBACK
) && nmp
->nm_cbid
) {
4330 /* clear out any pending delegation return requests */
4331 while ((np
= TAILQ_FIRST(&nmp
->nm_dreturnq
))) {
4332 TAILQ_REMOVE(&nmp
->nm_dreturnq
, np
, n_dreturn
);
4333 np
->n_dreturn
.tqe_next
= NFSNOLIST
;
4337 /* cancel any renew timer */
4338 if ((nmp
->nm_vers
>= NFS_VER4
) && nmp
->nm_renew_timer
) {
4339 thread_call_cancel(nmp
->nm_renew_timer
);
4340 thread_call_free(nmp
->nm_renew_timer
);
4343 lck_mtx_unlock(&nmp
->nm_lock
);
4345 if (nmp
->nm_state
& NFSSTA_MOUNTED
)
4346 switch (nmp
->nm_lockmode
) {
4347 case NFS_LOCK_MODE_DISABLED
:
4348 case NFS_LOCK_MODE_LOCAL
:
4350 case NFS_LOCK_MODE_ENABLED
:
4352 if (nmp
->nm_vers
<= NFS_VER3
) {
4353 nfs_lockd_mount_unregister(nmp
);
4354 nmp
->nm_lockmode
= NFS_LOCK_MODE_DISABLED
;
4359 if ((nmp
->nm_vers
>= NFS_VER4
) && nmp
->nm_longid
) {
4360 /* remove/deallocate the client ID data */
4361 lck_mtx_lock(nfs_global_mutex
);
4362 TAILQ_REMOVE(&nfsclientids
, nmp
->nm_longid
, nci_link
);
4363 if (nmp
->nm_longid
->nci_id
)
4364 FREE(nmp
->nm_longid
->nci_id
, M_TEMP
);
4365 FREE(nmp
->nm_longid
, M_TEMP
);
4366 lck_mtx_unlock(nfs_global_mutex
);
4370 * Loop through outstanding request list and remove dangling
4371 * references to defunct nfsmount struct
4374 lck_mtx_lock(nfs_request_mutex
);
4375 TAILQ_FOREACH(req
, &nfs_reqq
, r_chain
) {
4376 if (req
->r_nmp
== nmp
) {
4377 if (req
->r_callback
.rcb_func
&& !(req
->r_flags
& R_WAITSENT
)) {
4378 /* async I/O RPC needs to be finished */
4379 lck_mtx_lock(nfsiod_mutex
);
4380 if (req
->r_achain
.tqe_next
== NFSREQNOLIST
) {
4381 TAILQ_INSERT_TAIL(&iodq
, req
, r_achain
);
4383 lck_mtx_unlock(nfsiod_mutex
);
4388 lck_mtx_unlock(nfs_request_mutex
);
4390 /* finish any async I/O RPCs queued up */
4391 lck_mtx_lock(nfsiod_mutex
);
4392 if (nmp
->nm_iodlink
.tqe_next
!= NFSNOLIST
)
4393 TAILQ_REMOVE(&nfsiodmounts
, nmp
, nm_iodlink
);
4394 TAILQ_CONCAT(&iodq
, &nmp
->nm_iodq
, r_achain
);
4395 lck_mtx_unlock(nfsiod_mutex
);
4396 TAILQ_FOREACH_SAFE(req
, &iodq
, r_achain
, treq
) {
4397 TAILQ_REMOVE(&iodq
, req
, r_achain
);
4398 lck_mtx_lock(nfsiod_mutex
);
4399 req
->r_achain
.tqe_next
= NFSIODCOMPLETING
;
4400 lck_mtx_unlock(nfsiod_mutex
);
4401 lck_mtx_lock(&req
->r_mtx
);
4402 req
->r_error
= ENXIO
;
4403 docallback
= !(req
->r_flags
& R_WAITSENT
);
4404 lck_mtx_unlock(&req
->r_mtx
);
4406 req
->r_callback
.rcb_func(req
);
4409 /* clean up common state */
4410 lck_mtx_lock(&nmp
->nm_lock
);
4411 while ((np
= LIST_FIRST(&nmp
->nm_monlist
))) {
4412 LIST_REMOVE(np
, n_monlink
);
4413 np
->n_monlink
.le_next
= NFSNOLIST
;
4415 TAILQ_FOREACH_SAFE(noop
, &nmp
->nm_open_owners
, noo_link
, nextnoop
) {
4416 TAILQ_REMOVE(&nmp
->nm_open_owners
, noop
, noo_link
);
4417 noop
->noo_flags
&= ~NFS_OPEN_OWNER_LINK
;
4418 if (noop
->noo_refcnt
)
4420 nfs_open_owner_destroy(noop
);
4422 lck_mtx_unlock(&nmp
->nm_lock
);
4424 /* clean up NFSv4 state */
4425 if (nmp
->nm_vers
>= NFS_VER4
) {
4426 lck_mtx_lock(&nmp
->nm_lock
);
4427 while ((np
= TAILQ_FIRST(&nmp
->nm_delegations
))) {
4428 TAILQ_REMOVE(&nmp
->nm_delegations
, np
, n_dlink
);
4429 np
->n_dlink
.tqe_next
= NFSNOLIST
;
4431 lck_mtx_unlock(&nmp
->nm_lock
);
4434 nfs_mount_rele(nmp
);
4438 * cleanup/destroy an nfsmount
4441 nfs_mount_cleanup(struct nfsmount
*nmp
)
4446 nfs_mount_zombie(nmp
, 0);
4448 NFS_VFS_DBG("Unmounting %s from %s\n",
4449 vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
,
4450 vfs_statfs(nmp
->nm_mountp
)->f_mntonname
);
4451 NFS_VFS_DBG("nfs state = %x\n", nmp
->nm_state
);
4452 NFS_VFS_DBG("nfs socket flags = %x\n", nmp
->nm_sockflags
);
4453 NFS_VFS_DBG("nfs mount ref count is %d\n", nmp
->nm_ref
);
4454 NFS_VFS_DBG("mount ref count is %d\n", nmp
->nm_mountp
->mnt_count
);
4457 vfs_setfsprivate(nmp
->nm_mountp
, NULL
);
4459 lck_mtx_lock(&nmp
->nm_lock
);
4461 panic("Some one has grabbed a ref %d\n", nmp
->nm_ref
);
4464 FREE(nmp
->nm_saddr
, M_SONAME
);
4465 if ((nmp
->nm_vers
< NFS_VER4
) && nmp
->nm_rqsaddr
)
4466 FREE(nmp
->nm_rqsaddr
, M_SONAME
);
4468 if (IS_VALID_CRED(nmp
->nm_mcred
))
4469 kauth_cred_unref(&nmp
->nm_mcred
);
4471 nfs_fs_locations_cleanup(&nmp
->nm_locations
);
4474 FREE(nmp
->nm_realm
, M_TEMP
);
4475 if (nmp
->nm_principal
)
4476 FREE(nmp
->nm_principal
, M_TEMP
);
4478 FREE(nmp
->nm_sprinc
, M_TEMP
);
4481 xb_free(nmp
->nm_args
);
4483 lck_mtx_unlock(&nmp
->nm_lock
);
4485 lck_mtx_destroy(&nmp
->nm_lock
, nfs_mount_grp
);
4487 FREE(nmp
->nm_fh
, M_TEMP
);
4488 FREE_ZONE((caddr_t
)nmp
, sizeof (struct nfsmount
), M_NFSMNT
);
4492 * Return root of a filesystem
4495 nfs_vfs_root(mount_t mp
, vnode_t
*vpp
, __unused vfs_context_t ctx
)
4498 struct nfsmount
*nmp
;
4503 if (!nmp
|| !nmp
->nm_dnp
)
4505 vp
= NFSTOV(nmp
->nm_dnp
);
4506 vpid
= vnode_vid(vp
);
4507 while ((error
= vnode_getwithvid(vp
, vpid
))) {
4508 /* vnode_get() may return ENOENT if the dir changes. */
4509 /* If that happens, just try it again, else return the error. */
4510 if ((error
!= ENOENT
) || (vnode_vid(vp
) == vpid
))
4512 vpid
= vnode_vid(vp
);
4519 * Do operations associated with quotas
4524 __unused mount_t mp
,
4527 __unused caddr_t datap
,
4528 __unused vfs_context_t context
)
4535 nfs3_getquota(struct nfsmount
*nmp
, vfs_context_t ctx
, uid_t id
, int type
, struct dqblk
*dqb
)
4537 int error
= 0, slen
, timeo
;
4538 int rqport
= 0, rqproto
, rqvers
= (type
== GRPQUOTA
) ? RPCRQUOTA_EXT_VER
: RPCRQUOTA_VER
;
4539 thread_t thd
= vfs_context_thread(ctx
);
4540 kauth_cred_t cred
= vfs_context_ucred(ctx
);
4543 struct nfsm_chain nmreq
, nmrep
;
4545 uint32_t val
= 0, bsize
= 0;
4546 struct sockaddr
*rqsaddr
;
4552 if (NMFLAG(nmp
, NOQUOTA
))
4555 if (!nmp
->nm_rqsaddr
)
4556 MALLOC(nmp
->nm_rqsaddr
, struct sockaddr
*, sizeof(struct sockaddr_storage
), M_SONAME
, M_WAITOK
|M_ZERO
);
4557 if (!nmp
->nm_rqsaddr
)
4559 rqsaddr
= nmp
->nm_rqsaddr
;
4560 if (rqsaddr
->sa_family
== AF_INET6
)
4561 rqport
= ntohs(((struct sockaddr_in6
*)rqsaddr
)->sin6_port
);
4562 else if (rqsaddr
->sa_family
== AF_INET
)
4563 rqport
= ntohs(((struct sockaddr_in
*)rqsaddr
)->sin_port
);
4565 timeo
= NMFLAG(nmp
, SOFT
) ? 10 : 60;
4566 rqproto
= IPPROTO_UDP
; /* XXX should prefer TCP if mount is TCP */
4568 /* check if we have a recently cached rquota port */
4570 if (!rqport
|| ((nmp
->nm_rqsaddrstamp
+ 60) >= (uint32_t)now
.tv_sec
)) {
4571 /* send portmap request to get rquota port */
4572 bcopy(nmp
->nm_saddr
, rqsaddr
, min(sizeof(struct sockaddr_storage
), nmp
->nm_saddr
->sa_len
));
4573 error
= nfs_portmap_lookup(nmp
, ctx
, rqsaddr
, NULL
, RPCPROG_RQUOTA
, rqvers
, rqproto
, timeo
);
4576 if (rqsaddr
->sa_family
== AF_INET6
)
4577 rqport
= ntohs(((struct sockaddr_in6
*)rqsaddr
)->sin6_port
);
4578 else if (rqsaddr
->sa_family
== AF_INET
)
4579 rqport
= ntohs(((struct sockaddr_in
*)rqsaddr
)->sin_port
);
4585 nmp
->nm_rqsaddrstamp
= now
.tv_sec
;
4588 /* rquota request */
4589 nfsm_chain_null(&nmreq
);
4590 nfsm_chain_null(&nmrep
);
4591 path
= &vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
[0];
4592 while (*path
&& (*path
!= '/'))
4594 slen
= strlen(path
);
4595 nfsm_chain_build_alloc_init(error
, &nmreq
, 3 * NFSX_UNSIGNED
+ nfsm_rndup(slen
));
4596 nfsm_chain_add_name(error
, &nmreq
, path
, slen
, nmp
);
4597 if (type
== GRPQUOTA
)
4598 nfsm_chain_add_32(error
, &nmreq
, type
);
4599 nfsm_chain_add_32(error
, &nmreq
, id
);
4600 nfsm_chain_build_done(error
, &nmreq
);
4602 error
= nfsm_rpchead2(nmp
, (rqproto
== IPPROTO_UDP
) ? SOCK_DGRAM
: SOCK_STREAM
,
4603 RPCPROG_RQUOTA
, rqvers
, RPCRQUOTA_GET
,
4604 RPCAUTH_SYS
, cred
, NULL
, nmreq
.nmc_mhead
, &xid
, &mreq
);
4606 nmreq
.nmc_mhead
= NULL
;
4607 error
= nfs_aux_request(nmp
, thd
, rqsaddr
, NULL
,
4608 (rqproto
== IPPROTO_UDP
) ? SOCK_DGRAM
: SOCK_STREAM
,
4609 mreq
, R_XID32(xid
), 0, timeo
, &nmrep
);
4612 /* parse rquota response */
4613 nfsm_chain_get_32(error
, &nmrep
, val
);
4614 if (!error
&& (val
!= RQUOTA_STAT_OK
)) {
4615 if (val
== RQUOTA_STAT_NOQUOTA
)
4617 else if (val
== RQUOTA_STAT_EPERM
)
4622 nfsm_chain_get_32(error
, &nmrep
, bsize
);
4623 nfsm_chain_adv(error
, &nmrep
, NFSX_UNSIGNED
);
4624 nfsm_chain_get_32(error
, &nmrep
, val
);
4626 dqb
->dqb_bhardlimit
= (uint64_t)val
* bsize
;
4627 nfsm_chain_get_32(error
, &nmrep
, val
);
4629 dqb
->dqb_bsoftlimit
= (uint64_t)val
* bsize
;
4630 nfsm_chain_get_32(error
, &nmrep
, val
);
4632 dqb
->dqb_curbytes
= (uint64_t)val
* bsize
;
4633 nfsm_chain_get_32(error
, &nmrep
, dqb
->dqb_ihardlimit
);
4634 nfsm_chain_get_32(error
, &nmrep
, dqb
->dqb_isoftlimit
);
4635 nfsm_chain_get_32(error
, &nmrep
, dqb
->dqb_curinodes
);
4636 nfsm_chain_get_32(error
, &nmrep
, dqb
->dqb_btime
);
4637 nfsm_chain_get_32(error
, &nmrep
, dqb
->dqb_itime
);
4641 nfsm_chain_cleanup(&nmreq
);
4642 nfsm_chain_cleanup(&nmrep
);
4647 nfs4_getquota(struct nfsmount
*nmp
, vfs_context_t ctx
, uid_t id
, int type
, struct dqblk
*dqb
)
4650 int error
= 0, status
, nfsvers
, numops
;
4652 struct nfsm_chain nmreq
, nmrep
;
4653 uint32_t bitmap
[NFS_ATTR_BITMAP_LEN
];
4654 thread_t thd
= vfs_context_thread(ctx
);
4655 kauth_cred_t cred
= vfs_context_ucred(ctx
);
4656 struct nfsreq_secinfo_args si
;
4658 if (type
!= USRQUOTA
) /* NFSv4 only supports user quotas */
4661 /* first check that the server supports any of the quota attributes */
4662 if (!NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_QUOTA_AVAIL_HARD
) &&
4663 !NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_QUOTA_AVAIL_SOFT
) &&
4664 !NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_QUOTA_USED
))
4668 * The credential passed to the server needs to have
4669 * an effective uid that matches the given uid.
4671 if (id
!= kauth_cred_getuid(cred
)) {
4672 struct posix_cred temp_pcred
;
4673 posix_cred_t pcred
= posix_cred_get(cred
);
4674 bzero(&temp_pcred
, sizeof(temp_pcred
));
4675 temp_pcred
.cr_uid
= id
;
4676 temp_pcred
.cr_ngroups
= pcred
->cr_ngroups
;
4677 bcopy(pcred
->cr_groups
, temp_pcred
.cr_groups
, sizeof(temp_pcred
.cr_groups
));
4678 cred
= posix_cred_create(&temp_pcred
);
4679 if (!IS_VALID_CRED(cred
))
4682 kauth_cred_ref(cred
);
4685 nfsvers
= nmp
->nm_vers
;
4689 if (error
|| ((error
= vnode_get(NFSTOV(np
))))) {
4690 kauth_cred_unref(&cred
);
4694 NFSREQ_SECINFO_SET(&si
, np
, NULL
, 0, NULL
, 0);
4695 nfsm_chain_null(&nmreq
);
4696 nfsm_chain_null(&nmrep
);
4700 nfsm_chain_build_alloc_init(error
, &nmreq
, 15 * NFSX_UNSIGNED
);
4701 nfsm_chain_add_compound_header(error
, &nmreq
, "quota", numops
);
4703 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
4704 nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, np
->n_fhp
, np
->n_fhsize
);
4706 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
4707 NFS_CLEAR_ATTRIBUTES(bitmap
);
4708 NFS_BITMAP_SET(bitmap
, NFS_FATTR_QUOTA_AVAIL_HARD
);
4709 NFS_BITMAP_SET(bitmap
, NFS_FATTR_QUOTA_AVAIL_SOFT
);
4710 NFS_BITMAP_SET(bitmap
, NFS_FATTR_QUOTA_USED
);
4711 nfsm_chain_add_bitmap_supported(error
, &nmreq
, bitmap
, nmp
, NULL
);
4712 nfsm_chain_build_done(error
, &nmreq
);
4713 nfsm_assert(error
, (numops
== 0), EPROTO
);
4715 error
= nfs_request2(np
, NULL
, &nmreq
, NFSPROC4_COMPOUND
, thd
, cred
, &si
, 0, &nmrep
, &xid
, &status
);
4716 nfsm_chain_skip_tag(error
, &nmrep
);
4717 nfsm_chain_get_32(error
, &nmrep
, numops
);
4718 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
4719 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
4720 nfsm_assert(error
, NFSTONMP(np
), ENXIO
);
4722 error
= nfs4_parsefattr(&nmrep
, NULL
, NULL
, NULL
, dqb
, NULL
);
4724 nfsm_assert(error
, NFSTONMP(np
), ENXIO
);
4726 nfsm_chain_cleanup(&nmreq
);
4727 nfsm_chain_cleanup(&nmrep
);
4728 vnode_put(NFSTOV(np
));
4729 kauth_cred_unref(&cred
);
4734 nfs_vfs_quotactl(mount_t mp
, int cmds
, uid_t uid
, caddr_t datap
, vfs_context_t ctx
)
4736 struct nfsmount
*nmp
;
4737 int cmd
, type
, error
, nfsvers
;
4738 uid_t euid
= kauth_cred_getuid(vfs_context_ucred(ctx
));
4739 struct dqblk
*dqb
= (struct dqblk
*)datap
;
4742 if (nfs_mount_gone(nmp
))
4744 nfsvers
= nmp
->nm_vers
;
4749 /* we can only support Q_GETQUOTA */
4750 cmd
= cmds
>> SUBCMDSHIFT
;
4765 type
= cmds
& SUBCMDMASK
;
4766 if ((u_int
)type
>= MAXQUOTAS
)
4768 if ((uid
!= euid
) && ((error
= vfs_context_suser(ctx
))))
4771 if (vfs_busy(mp
, LK_NOWAIT
))
4773 bzero(dqb
, sizeof(*dqb
));
4774 error
= nmp
->nm_funcs
->nf_getquota(nmp
, ctx
, uid
, type
, dqb
);
4781 * Flush out the buffer cache
4783 int nfs_sync_callout(vnode_t
, void *);
4785 struct nfs_sync_cargs
{
4792 nfs_sync_callout(vnode_t vp
, void *arg
)
4794 struct nfs_sync_cargs
*cargs
= (struct nfs_sync_cargs
*)arg
;
4795 nfsnode_t np
= VTONFS(vp
);
4798 if (np
->n_flag
& NREVOKE
) {
4799 vn_revoke(vp
, REVOKEALL
, cargs
->ctx
);
4800 return (VNODE_RETURNED
);
4803 if (LIST_EMPTY(&np
->n_dirtyblkhd
))
4804 return (VNODE_RETURNED
);
4805 if (np
->n_wrbusy
> 0)
4806 return (VNODE_RETURNED
);
4807 if (np
->n_bflag
& (NBFLUSHINPROG
|NBINVALINPROG
))
4808 return (VNODE_RETURNED
);
4810 error
= nfs_flush(np
, cargs
->waitfor
, vfs_context_thread(cargs
->ctx
), 0);
4812 cargs
->error
= error
;
4814 return (VNODE_RETURNED
);
4818 nfs_vfs_sync(mount_t mp
, int waitfor
, vfs_context_t ctx
)
4820 struct nfs_sync_cargs cargs
;
4822 cargs
.waitfor
= waitfor
;
4826 vnode_iterate(mp
, 0, nfs_sync_callout
, &cargs
);
4828 return (cargs
.error
);
4832 * NFS flat namespace lookup.
4833 * Currently unsupported.
4838 __unused mount_t mp
,
4839 __unused ino64_t ino
,
4840 __unused vnode_t
*vpp
,
4841 __unused vfs_context_t ctx
)
4848 * At this point, this should never happen
4853 __unused mount_t mp
,
4855 __unused
unsigned char *fhp
,
4856 __unused vnode_t
*vpp
,
4857 __unused vfs_context_t ctx
)
4864 * Vnode pointer to File handle, should never happen either
4869 __unused vnode_t vp
,
4870 __unused
int *fhlenp
,
4871 __unused
unsigned char *fhp
,
4872 __unused vfs_context_t ctx
)
4879 * Vfs start routine, a no-op.
4884 __unused mount_t mp
,
4886 __unused vfs_context_t ctx
)
4893 * Build the mount info buffer for NFS_MOUNTINFO.
4896 nfs_mountinfo_assemble(struct nfsmount
*nmp
, struct xdrbuf
*xb
)
4898 struct xdrbuf xbinfo
, xborig
;
4900 uint32_t origargsvers
, origargslength
;
4901 uint32_t infolength_offset
, curargsopaquelength_offset
, curargslength_offset
, attrslength_offset
, curargs_end_offset
, end_offset
;
4902 uint32_t miattrs
[NFS_MIATTR_BITMAP_LEN
];
4903 uint32_t miflags_mask
[NFS_MIFLAG_BITMAP_LEN
];
4904 uint32_t miflags
[NFS_MIFLAG_BITMAP_LEN
];
4905 uint32_t mattrs
[NFS_MATTR_BITMAP_LEN
];
4906 uint32_t mflags_mask
[NFS_MFLAG_BITMAP_LEN
];
4907 uint32_t mflags
[NFS_MFLAG_BITMAP_LEN
];
4908 uint32_t loc
, serv
, addr
, comp
;
4909 int i
, timeo
, error
= 0;
4911 /* set up mount info attr and flag bitmaps */
4912 NFS_BITMAP_ZERO(miattrs
, NFS_MIATTR_BITMAP_LEN
);
4913 NFS_BITMAP_SET(miattrs
, NFS_MIATTR_FLAGS
);
4914 NFS_BITMAP_SET(miattrs
, NFS_MIATTR_ORIG_ARGS
);
4915 NFS_BITMAP_SET(miattrs
, NFS_MIATTR_CUR_ARGS
);
4916 NFS_BITMAP_SET(miattrs
, NFS_MIATTR_CUR_LOC_INDEX
);
4917 NFS_BITMAP_ZERO(miflags_mask
, NFS_MIFLAG_BITMAP_LEN
);
4918 NFS_BITMAP_ZERO(miflags
, NFS_MIFLAG_BITMAP_LEN
);
4919 NFS_BITMAP_SET(miflags_mask
, NFS_MIFLAG_DEAD
);
4920 NFS_BITMAP_SET(miflags_mask
, NFS_MIFLAG_NOTRESP
);
4921 NFS_BITMAP_SET(miflags_mask
, NFS_MIFLAG_RECOVERY
);
4922 if (nmp
->nm_state
& NFSSTA_DEAD
)
4923 NFS_BITMAP_SET(miflags
, NFS_MIFLAG_DEAD
);
4924 if ((nmp
->nm_state
& (NFSSTA_TIMEO
|NFSSTA_JUKEBOXTIMEO
)) ||
4925 ((nmp
->nm_state
& NFSSTA_LOCKTIMEO
) && (nmp
->nm_lockmode
== NFS_LOCK_MODE_ENABLED
)))
4926 NFS_BITMAP_SET(miflags
, NFS_MIFLAG_NOTRESP
);
4927 if (nmp
->nm_state
& NFSSTA_RECOVER
)
4928 NFS_BITMAP_SET(miflags
, NFS_MIFLAG_RECOVERY
);
4930 /* get original mount args length */
4931 xb_init_buffer(&xborig
, nmp
->nm_args
, 2*XDRWORD
);
4932 xb_get_32(error
, &xborig
, origargsvers
); /* version */
4933 xb_get_32(error
, &xborig
, origargslength
); /* args length */
4936 /* set up current mount attributes bitmap */
4937 NFS_BITMAP_ZERO(mattrs
, NFS_MATTR_BITMAP_LEN
);
4938 NFS_BITMAP_SET(mattrs
, NFS_MATTR_FLAGS
);
4939 NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_VERSION
);
4940 if (nmp
->nm_vers
>= NFS_VER4
)
4941 NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_MINOR_VERSION
);
4942 NFS_BITMAP_SET(mattrs
, NFS_MATTR_READ_SIZE
);
4943 NFS_BITMAP_SET(mattrs
, NFS_MATTR_WRITE_SIZE
);
4944 NFS_BITMAP_SET(mattrs
, NFS_MATTR_READDIR_SIZE
);
4945 NFS_BITMAP_SET(mattrs
, NFS_MATTR_READAHEAD
);
4946 NFS_BITMAP_SET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MIN
);
4947 NFS_BITMAP_SET(mattrs
, NFS_MATTR_ATTRCACHE_REG_MAX
);
4948 NFS_BITMAP_SET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MIN
);
4949 NFS_BITMAP_SET(mattrs
, NFS_MATTR_ATTRCACHE_DIR_MAX
);
4950 NFS_BITMAP_SET(mattrs
, NFS_MATTR_LOCK_MODE
);
4951 NFS_BITMAP_SET(mattrs
, NFS_MATTR_SECURITY
);
4952 NFS_BITMAP_SET(mattrs
, NFS_MATTR_MAX_GROUP_LIST
);
4953 NFS_BITMAP_SET(mattrs
, NFS_MATTR_SOCKET_TYPE
);
4954 NFS_BITMAP_SET(mattrs
, NFS_MATTR_NFS_PORT
);
4955 if ((nmp
->nm_vers
< NFS_VER4
) && nmp
->nm_mountport
)
4956 NFS_BITMAP_SET(mattrs
, NFS_MATTR_MOUNT_PORT
);
4957 NFS_BITMAP_SET(mattrs
, NFS_MATTR_REQUEST_TIMEOUT
);
4958 if (NMFLAG(nmp
, SOFT
))
4959 NFS_BITMAP_SET(mattrs
, NFS_MATTR_SOFT_RETRY_COUNT
);
4960 if (nmp
->nm_deadtimeout
)
4961 NFS_BITMAP_SET(mattrs
, NFS_MATTR_DEAD_TIMEOUT
);
4963 NFS_BITMAP_SET(mattrs
, NFS_MATTR_FH
);
4964 NFS_BITMAP_SET(mattrs
, NFS_MATTR_FS_LOCATIONS
);
4965 NFS_BITMAP_SET(mattrs
, NFS_MATTR_MNTFLAGS
);
4966 if (origargsvers
< NFS_ARGSVERSION_XDR
)
4967 NFS_BITMAP_SET(mattrs
, NFS_MATTR_MNTFROM
);
4969 NFS_BITMAP_SET(mattrs
, NFS_MATTR_REALM
);
4970 if (nmp
->nm_principal
)
4971 NFS_BITMAP_SET(mattrs
, NFS_MATTR_PRINCIPAL
);
4973 NFS_BITMAP_SET(mattrs
, NFS_MATTR_SVCPRINCIPAL
);
4975 /* set up current mount flags bitmap */
4976 /* first set the flags that we will be setting - either on OR off */
4977 NFS_BITMAP_ZERO(mflags_mask
, NFS_MFLAG_BITMAP_LEN
);
4978 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_SOFT
);
4979 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_INTR
);
4980 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_RESVPORT
);
4981 if (nmp
->nm_sotype
== SOCK_DGRAM
)
4982 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NOCONNECT
);
4983 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_DUMBTIMER
);
4984 if (nmp
->nm_vers
< NFS_VER4
)
4985 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_CALLUMNT
);
4986 if (nmp
->nm_vers
>= NFS_VER3
)
4987 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_RDIRPLUS
);
4988 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NONEGNAMECACHE
);
4989 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_MUTEJUKEBOX
);
4990 if (nmp
->nm_vers
>= NFS_VER4
) {
4991 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_EPHEMERAL
);
4992 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NOCALLBACK
);
4993 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NONAMEDATTR
);
4994 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NOACL
);
4995 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_ACLONLY
);
4997 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NFC
);
4998 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_NOQUOTA
);
4999 if (nmp
->nm_vers
< NFS_VER4
)
5000 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_MNTUDP
);
5001 NFS_BITMAP_SET(mflags_mask
, NFS_MFLAG_MNTQUICK
);
5002 /* now set the flags that should be set */
5003 NFS_BITMAP_ZERO(mflags
, NFS_MFLAG_BITMAP_LEN
);
5004 if (NMFLAG(nmp
, SOFT
))
5005 NFS_BITMAP_SET(mflags
, NFS_MFLAG_SOFT
);
5006 if (NMFLAG(nmp
, INTR
))
5007 NFS_BITMAP_SET(mflags
, NFS_MFLAG_INTR
);
5008 if (NMFLAG(nmp
, RESVPORT
))
5009 NFS_BITMAP_SET(mflags
, NFS_MFLAG_RESVPORT
);
5010 if ((nmp
->nm_sotype
== SOCK_DGRAM
) && NMFLAG(nmp
, NOCONNECT
))
5011 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NOCONNECT
);
5012 if (NMFLAG(nmp
, DUMBTIMER
))
5013 NFS_BITMAP_SET(mflags
, NFS_MFLAG_DUMBTIMER
);
5014 if ((nmp
->nm_vers
< NFS_VER4
) && NMFLAG(nmp
, CALLUMNT
))
5015 NFS_BITMAP_SET(mflags
, NFS_MFLAG_CALLUMNT
);
5016 if ((nmp
->nm_vers
>= NFS_VER3
) && NMFLAG(nmp
, RDIRPLUS
))
5017 NFS_BITMAP_SET(mflags
, NFS_MFLAG_RDIRPLUS
);
5018 if (NMFLAG(nmp
, NONEGNAMECACHE
))
5019 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NONEGNAMECACHE
);
5020 if (NMFLAG(nmp
, MUTEJUKEBOX
))
5021 NFS_BITMAP_SET(mflags
, NFS_MFLAG_MUTEJUKEBOX
);
5022 if (nmp
->nm_vers
>= NFS_VER4
) {
5023 if (NMFLAG(nmp
, EPHEMERAL
))
5024 NFS_BITMAP_SET(mflags
, NFS_MFLAG_EPHEMERAL
);
5025 if (NMFLAG(nmp
, NOCALLBACK
))
5026 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NOCALLBACK
);
5027 if (NMFLAG(nmp
, NONAMEDATTR
))
5028 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NONAMEDATTR
);
5029 if (NMFLAG(nmp
, NOACL
))
5030 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NOACL
);
5031 if (NMFLAG(nmp
, ACLONLY
))
5032 NFS_BITMAP_SET(mflags
, NFS_MFLAG_ACLONLY
);
5034 if (NMFLAG(nmp
, NFC
))
5035 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NFC
);
5036 if (NMFLAG(nmp
, NOQUOTA
) || ((nmp
->nm_vers
>= NFS_VER4
) &&
5037 !NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_QUOTA_AVAIL_HARD
) &&
5038 !NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_QUOTA_AVAIL_SOFT
) &&
5039 !NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_QUOTA_USED
)))
5040 NFS_BITMAP_SET(mflags
, NFS_MFLAG_NOQUOTA
);
5041 if ((nmp
->nm_vers
< NFS_VER4
) && NMFLAG(nmp
, MNTUDP
))
5042 NFS_BITMAP_SET(mflags
, NFS_MFLAG_MNTUDP
);
5043 if (NMFLAG(nmp
, MNTQUICK
))
5044 NFS_BITMAP_SET(mflags
, NFS_MFLAG_MNTQUICK
);
5046 /* assemble info buffer: */
5047 xb_init_buffer(&xbinfo
, NULL
, 0);
5048 xb_add_32(error
, &xbinfo
, NFS_MOUNT_INFO_VERSION
);
5049 infolength_offset
= xb_offset(&xbinfo
);
5050 xb_add_32(error
, &xbinfo
, 0);
5051 xb_add_bitmap(error
, &xbinfo
, miattrs
, NFS_MIATTR_BITMAP_LEN
);
5052 xb_add_bitmap(error
, &xbinfo
, miflags
, NFS_MIFLAG_BITMAP_LEN
);
5053 xb_add_32(error
, &xbinfo
, origargslength
);
5055 error
= xb_add_bytes(&xbinfo
, nmp
->nm_args
, origargslength
, 0);
5057 /* the opaque byte count for the current mount args values: */
5058 curargsopaquelength_offset
= xb_offset(&xbinfo
);
5059 xb_add_32(error
, &xbinfo
, 0);
5061 /* Encode current mount args values */
5062 xb_add_32(error
, &xbinfo
, NFS_ARGSVERSION_XDR
);
5063 curargslength_offset
= xb_offset(&xbinfo
);
5064 xb_add_32(error
, &xbinfo
, 0);
5065 xb_add_32(error
, &xbinfo
, NFS_XDRARGS_VERSION_0
);
5066 xb_add_bitmap(error
, &xbinfo
, mattrs
, NFS_MATTR_BITMAP_LEN
);
5067 attrslength_offset
= xb_offset(&xbinfo
);
5068 xb_add_32(error
, &xbinfo
, 0);
5069 xb_add_bitmap(error
, &xbinfo
, mflags_mask
, NFS_MFLAG_BITMAP_LEN
);
5070 xb_add_bitmap(error
, &xbinfo
, mflags
, NFS_MFLAG_BITMAP_LEN
);
5071 xb_add_32(error
, &xbinfo
, nmp
->nm_vers
); /* NFS_VERSION */
5072 if (nmp
->nm_vers
>= NFS_VER4
)
5073 xb_add_32(error
, &xbinfo
, 0); /* NFS_MINOR_VERSION */
5074 xb_add_32(error
, &xbinfo
, nmp
->nm_rsize
); /* READ_SIZE */
5075 xb_add_32(error
, &xbinfo
, nmp
->nm_wsize
); /* WRITE_SIZE */
5076 xb_add_32(error
, &xbinfo
, nmp
->nm_readdirsize
); /* READDIR_SIZE */
5077 xb_add_32(error
, &xbinfo
, nmp
->nm_readahead
); /* READAHEAD */
5078 xb_add_32(error
, &xbinfo
, nmp
->nm_acregmin
); /* ATTRCACHE_REG_MIN */
5079 xb_add_32(error
, &xbinfo
, 0); /* ATTRCACHE_REG_MIN */
5080 xb_add_32(error
, &xbinfo
, nmp
->nm_acregmax
); /* ATTRCACHE_REG_MAX */
5081 xb_add_32(error
, &xbinfo
, 0); /* ATTRCACHE_REG_MAX */
5082 xb_add_32(error
, &xbinfo
, nmp
->nm_acdirmin
); /* ATTRCACHE_DIR_MIN */
5083 xb_add_32(error
, &xbinfo
, 0); /* ATTRCACHE_DIR_MIN */
5084 xb_add_32(error
, &xbinfo
, nmp
->nm_acdirmax
); /* ATTRCACHE_DIR_MAX */
5085 xb_add_32(error
, &xbinfo
, 0); /* ATTRCACHE_DIR_MAX */
5086 xb_add_32(error
, &xbinfo
, nmp
->nm_lockmode
); /* LOCK_MODE */
5087 if (nmp
->nm_sec
.count
) {
5088 xb_add_32(error
, &xbinfo
, nmp
->nm_sec
.count
); /* SECURITY */
5090 for (i
=0; i
< nmp
->nm_sec
.count
; i
++)
5091 xb_add_32(error
, &xbinfo
, nmp
->nm_sec
.flavors
[i
]);
5092 } else if (nmp
->nm_servsec
.count
) {
5093 xb_add_32(error
, &xbinfo
, nmp
->nm_servsec
.count
); /* SECURITY */
5095 for (i
=0; i
< nmp
->nm_servsec
.count
; i
++)
5096 xb_add_32(error
, &xbinfo
, nmp
->nm_servsec
.flavors
[i
]);
5098 xb_add_32(error
, &xbinfo
, 1); /* SECURITY */
5099 xb_add_32(error
, &xbinfo
, nmp
->nm_auth
);
5101 xb_add_32(error
, &xbinfo
, nmp
->nm_numgrps
); /* MAX_GROUP_LIST */
5103 snprintf(sotype
, sizeof(sotype
), "%s%s", (nmp
->nm_sotype
== SOCK_DGRAM
) ? "udp" : "tcp",
5104 nmp
->nm_sofamily
? (nmp
->nm_sofamily
== AF_INET
) ? "4" : "6" : "");
5105 xb_add_string(error
, &xbinfo
, sotype
, strlen(sotype
)); /* SOCKET_TYPE */
5106 xb_add_32(error
, &xbinfo
, ntohs(((struct sockaddr_in
*)nmp
->nm_saddr
)->sin_port
)); /* NFS_PORT */
5107 if ((nmp
->nm_vers
< NFS_VER4
) && nmp
->nm_mountport
)
5108 xb_add_32(error
, &xbinfo
, nmp
->nm_mountport
); /* MOUNT_PORT */
5109 timeo
= (nmp
->nm_timeo
* 10) / NFS_HZ
;
5110 xb_add_32(error
, &xbinfo
, timeo
/10); /* REQUEST_TIMEOUT */
5111 xb_add_32(error
, &xbinfo
, (timeo%10
)*100000000); /* REQUEST_TIMEOUT */
5112 if (NMFLAG(nmp
, SOFT
))
5113 xb_add_32(error
, &xbinfo
, nmp
->nm_retry
); /* SOFT_RETRY_COUNT */
5114 if (nmp
->nm_deadtimeout
) {
5115 xb_add_32(error
, &xbinfo
, nmp
->nm_deadtimeout
); /* DEAD_TIMEOUT */
5116 xb_add_32(error
, &xbinfo
, 0); /* DEAD_TIMEOUT */
5119 xb_add_fh(error
, &xbinfo
, &nmp
->nm_fh
->fh_data
[0], nmp
->nm_fh
->fh_len
); /* FH */
5120 xb_add_32(error
, &xbinfo
, nmp
->nm_locations
.nl_numlocs
); /* FS_LOCATIONS */
5121 for (loc
= 0; !error
&& (loc
< nmp
->nm_locations
.nl_numlocs
); loc
++) {
5122 xb_add_32(error
, &xbinfo
, nmp
->nm_locations
.nl_locations
[loc
]->nl_servcount
);
5123 for (serv
= 0; !error
&& (serv
< nmp
->nm_locations
.nl_locations
[loc
]->nl_servcount
); serv
++) {
5124 xb_add_string(error
, &xbinfo
, nmp
->nm_locations
.nl_locations
[loc
]->nl_servers
[serv
]->ns_name
,
5125 strlen(nmp
->nm_locations
.nl_locations
[loc
]->nl_servers
[serv
]->ns_name
));
5126 xb_add_32(error
, &xbinfo
, nmp
->nm_locations
.nl_locations
[loc
]->nl_servers
[serv
]->ns_addrcount
);
5127 for (addr
= 0; !error
&& (addr
< nmp
->nm_locations
.nl_locations
[loc
]->nl_servers
[serv
]->ns_addrcount
); addr
++)
5128 xb_add_string(error
, &xbinfo
, nmp
->nm_locations
.nl_locations
[loc
]->nl_servers
[serv
]->ns_addresses
[addr
],
5129 strlen(nmp
->nm_locations
.nl_locations
[loc
]->nl_servers
[serv
]->ns_addresses
[addr
]));
5130 xb_add_32(error
, &xbinfo
, 0); /* empty server info */
5132 xb_add_32(error
, &xbinfo
, nmp
->nm_locations
.nl_locations
[loc
]->nl_path
.np_compcount
);
5133 for (comp
= 0; !error
&& (comp
< nmp
->nm_locations
.nl_locations
[loc
]->nl_path
.np_compcount
); comp
++)
5134 xb_add_string(error
, &xbinfo
, nmp
->nm_locations
.nl_locations
[loc
]->nl_path
.np_components
[comp
],
5135 strlen(nmp
->nm_locations
.nl_locations
[loc
]->nl_path
.np_components
[comp
]));
5136 xb_add_32(error
, &xbinfo
, 0); /* empty fs location info */
5138 xb_add_32(error
, &xbinfo
, vfs_flags(nmp
->nm_mountp
)); /* MNTFLAGS */
5139 if (origargsvers
< NFS_ARGSVERSION_XDR
)
5140 xb_add_string(error
, &xbinfo
, vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
,
5141 strlen(vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
)); /* MNTFROM */
5142 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_REALM
))
5143 xb_add_string(error
, &xbinfo
, nmp
->nm_realm
, strlen(nmp
->nm_realm
));
5144 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_PRINCIPAL
))
5145 xb_add_string(error
, &xbinfo
, nmp
->nm_principal
, strlen(nmp
->nm_principal
));
5146 if (NFS_BITMAP_ISSET(mattrs
, NFS_MATTR_SVCPRINCIPAL
))
5147 xb_add_string(error
, &xbinfo
, nmp
->nm_sprinc
, strlen(nmp
->nm_sprinc
));
5149 curargs_end_offset
= xb_offset(&xbinfo
);
5151 /* NFS_MIATTR_CUR_LOC_INDEX */
5152 xb_add_32(error
, &xbinfo
, nmp
->nm_locations
.nl_current
.nli_flags
);
5153 xb_add_32(error
, &xbinfo
, nmp
->nm_locations
.nl_current
.nli_loc
);
5154 xb_add_32(error
, &xbinfo
, nmp
->nm_locations
.nl_current
.nli_serv
);
5155 xb_add_32(error
, &xbinfo
, nmp
->nm_locations
.nl_current
.nli_addr
);
5157 xb_build_done(error
, &xbinfo
);
5159 /* update opaque counts */
5160 end_offset
= xb_offset(&xbinfo
);
5162 error
= xb_seek(&xbinfo
, attrslength_offset
);
5163 xb_add_32(error
, &xbinfo
, curargs_end_offset
- attrslength_offset
- XDRWORD
/*don't include length field*/);
5166 error
= xb_seek(&xbinfo
, curargslength_offset
);
5167 xb_add_32(error
, &xbinfo
, curargs_end_offset
- curargslength_offset
+ XDRWORD
/*version*/);
5170 error
= xb_seek(&xbinfo
, curargsopaquelength_offset
);
5171 xb_add_32(error
, &xbinfo
, curargs_end_offset
- curargslength_offset
+ XDRWORD
/*version*/);
5174 error
= xb_seek(&xbinfo
, infolength_offset
);
5175 xb_add_32(error
, &xbinfo
, end_offset
- infolength_offset
+ XDRWORD
/*version*/);
5179 /* copy result xdrbuf to caller */
5182 /* and mark the local copy as not needing cleanup */
5183 xbinfo
.xb_flags
&= ~XB_CLEANUP
;
5185 xb_cleanup(&xbinfo
);
5190 * Do that sysctl thang...
5193 nfs_vfs_sysctl(int *name
, u_int namelen
, user_addr_t oldp
, size_t *oldlenp
,
5194 user_addr_t newp
, size_t newlen
, vfs_context_t ctx
)
5198 struct sysctl_req
*req
= NULL
;
5199 union union_vfsidctl vc
;
5201 struct nfsmount
*nmp
= NULL
;
5204 boolean_t is_64_bit
;
5207 struct netfs_status
*nsp
= NULL
;
5209 uint pos
, totlen
, count
, numThreads
;
5211 struct nfs_exportfs
*nxfs
;
5212 struct nfs_export
*nx
;
5213 struct nfs_active_user_list
*ulist
;
5214 struct nfs_export_stat_desc stat_desc
;
5215 struct nfs_export_stat_rec statrec
;
5216 struct nfs_user_stat_node
*unode
, *unode_next
;
5217 struct nfs_user_stat_desc ustat_desc
;
5218 struct nfs_user_stat_user_rec ustat_rec
;
5219 struct nfs_user_stat_path_rec upath_rec
;
5220 uint bytes_avail
, bytes_total
, recs_copied
;
5221 uint numExports
, numRecs
;
5222 #endif /* NFSSERVER */
5225 * All names at this level are terminal.
5228 return (ENOTDIR
); /* overloaded */
5230 is_64_bit
= vfs_context_is64bit(ctx
);
5232 /* common code for "new style" VFS_CTL sysctl, get the mount. */
5235 case VFS_CTL_NOLOCKS
:
5236 case VFS_CTL_NSTATUS
:
5238 req
= CAST_DOWN(struct sysctl_req
*, oldp
);
5242 error
= SYSCTL_IN(req
, &vc
, is_64_bit
? sizeof(vc
.vc64
):sizeof(vc
.vc32
));
5245 mp
= vfs_getvfs(&vc
.vc32
.vc_fsid
); /* works for 32 and 64 */
5251 bzero(&vq
, sizeof(vq
));
5254 req
->newptr
= vc
.vc64
.vc_ptr
;
5255 req
->newlen
= (size_t)vc
.vc64
.vc_len
;
5257 req
->newptr
= CAST_USER_ADDR_T(vc
.vc32
.vc_ptr
);
5258 req
->newlen
= vc
.vc32
.vc_len
;
5266 *oldlenp
= sizeof nfsstats
;
5270 if (*oldlenp
< sizeof nfsstats
) {
5271 *oldlenp
= sizeof nfsstats
;
5275 error
= copyout(&nfsstats
, oldp
, sizeof nfsstats
);
5279 if (newp
&& newlen
!= sizeof nfsstats
)
5283 return copyin(newp
, &nfsstats
, sizeof nfsstats
);
5286 /* read in the fsid */
5287 if (*oldlenp
< sizeof(fsid
))
5289 if ((error
= copyin(oldp
, &fsid
, sizeof(fsid
))))
5291 /* swizzle it back to host order */
5292 fsid
.val
[0] = ntohl(fsid
.val
[0]);
5293 fsid
.val
[1] = ntohl(fsid
.val
[1]);
5294 /* find mount and make sure it's NFS */
5295 if (((mp
= vfs_getvfs(&fsid
))) == NULL
)
5297 if (strcmp(mp
->mnt_vfsstat
.f_fstypename
, "nfs"))
5299 if (((nmp
= VFSTONFS(mp
))) == NULL
)
5302 if ((error
= nfs_mountinfo_assemble(nmp
, &xb
)))
5304 if (*oldlenp
< xb
.xb_u
.xb_buffer
.xbb_len
)
5307 error
= copyout(xb_buffer_base(&xb
), oldp
, xb
.xb_u
.xb_buffer
.xbb_len
);
5308 *oldlenp
= xb
.xb_u
.xb_buffer
.xbb_len
;
5312 case NFS_EXPORTSTATS
:
5313 /* setup export stat descriptor */
5314 stat_desc
.rec_vers
= NFS_EXPORT_STAT_REC_VERSION
;
5316 if (!nfsrv_is_initialized()) {
5317 stat_desc
.rec_count
= 0;
5318 if (oldp
&& (*oldlenp
>= sizeof(struct nfs_export_stat_desc
)))
5319 error
= copyout(&stat_desc
, oldp
, sizeof(struct nfs_export_stat_desc
));
5320 *oldlenp
= sizeof(struct nfs_export_stat_desc
);
5324 /* Count the number of exported directories */
5325 lck_rw_lock_shared(&nfsrv_export_rwlock
);
5327 LIST_FOREACH(nxfs
, &nfsrv_exports
, nxfs_next
)
5328 LIST_FOREACH(nx
, &nxfs
->nxfs_exports
, nx_next
)
5331 /* update stat descriptor's export record count */
5332 stat_desc
.rec_count
= numExports
;
5334 /* calculate total size of required buffer */
5335 totlen
= sizeof(struct nfs_export_stat_desc
) + (numExports
* sizeof(struct nfs_export_stat_rec
));
5337 /* Check caller's buffer */
5339 lck_rw_done(&nfsrv_export_rwlock
);
5340 /* indicate required buffer len */
5345 /* We require the caller's buffer to be at least large enough to hold the descriptor */
5346 if (*oldlenp
< sizeof(struct nfs_export_stat_desc
)) {
5347 lck_rw_done(&nfsrv_export_rwlock
);
5348 /* indicate required buffer len */
5353 /* indicate required buffer len */
5356 /* check if export table is empty */
5358 lck_rw_done(&nfsrv_export_rwlock
);
5359 error
= copyout(&stat_desc
, oldp
, sizeof(struct nfs_export_stat_desc
));
5363 /* calculate how many actual export stat records fit into caller's buffer */
5364 numRecs
= (*oldlenp
- sizeof(struct nfs_export_stat_desc
)) / sizeof(struct nfs_export_stat_rec
);
5367 /* caller's buffer can only accomodate descriptor */
5368 lck_rw_done(&nfsrv_export_rwlock
);
5369 stat_desc
.rec_count
= 0;
5370 error
= copyout(&stat_desc
, oldp
, sizeof(struct nfs_export_stat_desc
));
5374 /* adjust to actual number of records to copyout to caller's buffer */
5375 if (numRecs
> numExports
)
5376 numRecs
= numExports
;
5378 /* set actual number of records we are returning */
5379 stat_desc
.rec_count
= numRecs
;
5381 /* first copy out the stat descriptor */
5383 error
= copyout(&stat_desc
, oldp
+ pos
, sizeof(struct nfs_export_stat_desc
));
5385 lck_rw_done(&nfsrv_export_rwlock
);
5388 pos
+= sizeof(struct nfs_export_stat_desc
);
5390 /* Loop through exported directories */
5392 LIST_FOREACH(nxfs
, &nfsrv_exports
, nxfs_next
) {
5393 LIST_FOREACH(nx
, &nxfs
->nxfs_exports
, nx_next
) {
5395 if (count
>= numRecs
)
5398 /* build exported filesystem path */
5399 snprintf(statrec
.path
, sizeof(statrec
.path
), "%s%s%s",
5400 nxfs
->nxfs_path
, ((nxfs
->nxfs_path
[1] && nx
->nx_path
[0]) ? "/" : ""),
5403 /* build the 64-bit export stat counters */
5404 statrec
.ops
= ((uint64_t)nx
->nx_stats
.ops
.hi
<< 32) |
5405 nx
->nx_stats
.ops
.lo
;
5406 statrec
.bytes_read
= ((uint64_t)nx
->nx_stats
.bytes_read
.hi
<< 32) |
5407 nx
->nx_stats
.bytes_read
.lo
;
5408 statrec
.bytes_written
= ((uint64_t)nx
->nx_stats
.bytes_written
.hi
<< 32) |
5409 nx
->nx_stats
.bytes_written
.lo
;
5410 error
= copyout(&statrec
, oldp
+ pos
, sizeof(statrec
));
5412 lck_rw_done(&nfsrv_export_rwlock
);
5415 /* advance buffer position */
5416 pos
+= sizeof(statrec
);
5419 lck_rw_done(&nfsrv_export_rwlock
);
5422 /* init structures used for copying out of kernel */
5423 ustat_desc
.rec_vers
= NFS_USER_STAT_REC_VERSION
;
5424 ustat_rec
.rec_type
= NFS_USER_STAT_USER_REC
;
5425 upath_rec
.rec_type
= NFS_USER_STAT_PATH_REC
;
5427 /* initialize counters */
5428 bytes_total
= sizeof(struct nfs_user_stat_desc
);
5429 bytes_avail
= *oldlenp
;
5432 if (!nfsrv_is_initialized()) /* NFS server not initialized, so no stats */
5435 /* reclaim old expired user nodes */
5436 nfsrv_active_user_list_reclaim();
5438 /* reserve space for the buffer descriptor */
5439 if (bytes_avail
>= sizeof(struct nfs_user_stat_desc
))
5440 bytes_avail
-= sizeof(struct nfs_user_stat_desc
);
5444 /* put buffer position past the buffer descriptor */
5445 pos
= sizeof(struct nfs_user_stat_desc
);
5447 /* Loop through exported directories */
5448 lck_rw_lock_shared(&nfsrv_export_rwlock
);
5449 LIST_FOREACH(nxfs
, &nfsrv_exports
, nxfs_next
) {
5450 LIST_FOREACH(nx
, &nxfs
->nxfs_exports
, nx_next
) {
5452 if (bytes_avail
>= sizeof(struct nfs_user_stat_path_rec
)) {
5453 snprintf(upath_rec
.path
, sizeof(upath_rec
.path
), "%s%s%s",
5454 nxfs
->nxfs_path
, ((nxfs
->nxfs_path
[1] && nx
->nx_path
[0]) ? "/" : ""),
5457 error
= copyout(&upath_rec
, oldp
+ pos
, sizeof(struct nfs_user_stat_path_rec
));
5463 pos
+= sizeof(struct nfs_user_stat_path_rec
);
5464 bytes_avail
-= sizeof(struct nfs_user_stat_path_rec
);
5468 /* Caller's buffer is exhausted */
5472 bytes_total
+= sizeof(struct nfs_user_stat_path_rec
);
5474 /* Scan through all user nodes of this export */
5475 ulist
= &nx
->nx_user_list
;
5476 lck_mtx_lock(&ulist
->user_mutex
);
5477 for (unode
= TAILQ_FIRST(&ulist
->user_lru
); unode
; unode
= unode_next
) {
5478 unode_next
= TAILQ_NEXT(unode
, lru_link
);
5480 /* copy out node if there is space */
5481 if (bytes_avail
>= sizeof(struct nfs_user_stat_user_rec
)) {
5482 /* prepare a user stat rec for copying out */
5483 ustat_rec
.uid
= unode
->uid
;
5484 bcopy(&unode
->sock
, &ustat_rec
.sock
, unode
->sock
.ss_len
);
5485 ustat_rec
.ops
= unode
->ops
;
5486 ustat_rec
.bytes_read
= unode
->bytes_read
;
5487 ustat_rec
.bytes_written
= unode
->bytes_written
;
5488 ustat_rec
.tm_start
= unode
->tm_start
;
5489 ustat_rec
.tm_last
= unode
->tm_last
;
5491 error
= copyout(&ustat_rec
, oldp
+ pos
, sizeof(struct nfs_user_stat_user_rec
));
5495 lck_mtx_unlock(&ulist
->user_mutex
);
5499 pos
+= sizeof(struct nfs_user_stat_user_rec
);
5500 bytes_avail
-= sizeof(struct nfs_user_stat_user_rec
);
5504 /* Caller's buffer is exhausted */
5507 bytes_total
+= sizeof(struct nfs_user_stat_user_rec
);
5509 /* can unlock this export's list now */
5510 lck_mtx_unlock(&ulist
->user_mutex
);
5515 /* unlock the export table */
5516 lck_rw_done(&nfsrv_export_rwlock
);
5519 /* indicate number of actual records copied */
5520 ustat_desc
.rec_count
= recs_copied
;
5523 /* check if there was enough room for the buffer descriptor */
5524 if (*oldlenp
>= sizeof(struct nfs_user_stat_desc
))
5525 error
= copyout(&ustat_desc
, oldp
, sizeof(struct nfs_user_stat_desc
));
5529 /* always indicate required buffer size */
5530 *oldlenp
= bytes_total
;
5535 *oldlenp
= sizeof(nfsrv_user_stat_node_count
);
5539 if (*oldlenp
< sizeof(nfsrv_user_stat_node_count
)) {
5540 *oldlenp
= sizeof(nfsrv_user_stat_node_count
);
5544 if (nfsrv_is_initialized()) {
5545 /* reclaim old expired user nodes */
5546 nfsrv_active_user_list_reclaim();
5549 error
= copyout(&nfsrv_user_stat_node_count
, oldp
, sizeof(nfsrv_user_stat_node_count
));
5551 #endif /* NFSSERVER */
5552 case VFS_CTL_NOLOCKS
:
5553 if (req
->oldptr
!= USER_ADDR_NULL
) {
5554 lck_mtx_lock(&nmp
->nm_lock
);
5555 val
= (nmp
->nm_lockmode
== NFS_LOCK_MODE_DISABLED
) ? 1 : 0;
5556 lck_mtx_unlock(&nmp
->nm_lock
);
5557 error
= SYSCTL_OUT(req
, &val
, sizeof(val
));
5561 if (req
->newptr
!= USER_ADDR_NULL
) {
5562 error
= SYSCTL_IN(req
, &val
, sizeof(val
));
5565 lck_mtx_lock(&nmp
->nm_lock
);
5566 if (nmp
->nm_lockmode
== NFS_LOCK_MODE_LOCAL
) {
5567 /* can't toggle locks when using local locks */
5569 } else if ((nmp
->nm_vers
>= NFS_VER4
) && val
) {
5570 /* can't disable locks for NFSv4 */
5573 if ((nmp
->nm_vers
<= NFS_VER3
) && (nmp
->nm_lockmode
== NFS_LOCK_MODE_ENABLED
))
5574 nfs_lockd_mount_unregister(nmp
);
5575 nmp
->nm_lockmode
= NFS_LOCK_MODE_DISABLED
;
5576 nmp
->nm_state
&= ~NFSSTA_LOCKTIMEO
;
5578 if ((nmp
->nm_vers
<= NFS_VER3
) && (nmp
->nm_lockmode
== NFS_LOCK_MODE_DISABLED
))
5579 nfs_lockd_mount_register(nmp
);
5580 nmp
->nm_lockmode
= NFS_LOCK_MODE_ENABLED
;
5582 lck_mtx_unlock(&nmp
->nm_lock
);
5586 lck_mtx_lock(&nmp
->nm_lock
);
5587 /* XXX don't allow users to know about/disconnect unresponsive, soft, nobrowse mounts */
5588 softnobrowse
= (NMFLAG(nmp
, SOFT
) && (vfs_flags(nmp
->nm_mountp
) & MNT_DONTBROWSE
));
5589 if (!softnobrowse
&& (nmp
->nm_state
& NFSSTA_TIMEO
))
5590 vq
.vq_flags
|= VQ_NOTRESP
;
5591 if (!softnobrowse
&& (nmp
->nm_state
& NFSSTA_JUKEBOXTIMEO
) && !NMFLAG(nmp
, MUTEJUKEBOX
))
5592 vq
.vq_flags
|= VQ_NOTRESP
;
5593 if (!softnobrowse
&& (nmp
->nm_state
& NFSSTA_LOCKTIMEO
) &&
5594 (nmp
->nm_lockmode
== NFS_LOCK_MODE_ENABLED
))
5595 vq
.vq_flags
|= VQ_NOTRESP
;
5596 if (nmp
->nm_state
& NFSSTA_DEAD
)
5597 vq
.vq_flags
|= VQ_DEAD
;
5598 lck_mtx_unlock(&nmp
->nm_lock
);
5599 error
= SYSCTL_OUT(req
, &vq
, sizeof(vq
));
5602 if (req
->oldptr
!= USER_ADDR_NULL
) {
5603 lck_mtx_lock(&nmp
->nm_lock
);
5604 val
= nmp
->nm_tprintf_initial_delay
;
5605 lck_mtx_unlock(&nmp
->nm_lock
);
5606 error
= SYSCTL_OUT(req
, &val
, sizeof(val
));
5610 if (req
->newptr
!= USER_ADDR_NULL
) {
5611 error
= SYSCTL_IN(req
, &val
, sizeof(val
));
5614 lck_mtx_lock(&nmp
->nm_lock
);
5616 nmp
->nm_tprintf_initial_delay
= 0;
5618 nmp
->nm_tprintf_initial_delay
= val
;
5619 lck_mtx_unlock(&nmp
->nm_lock
);
5622 case VFS_CTL_NSTATUS
:
5624 * Return the status of this mount. This is much more
5625 * information than VFS_CTL_QUERY. In addition to the
5626 * vq_flags return the significant mount options along
5627 * with the list of threads blocked on the mount and
5628 * how long the threads have been waiting.
5631 lck_mtx_lock(nfs_request_mutex
);
5632 lck_mtx_lock(&nmp
->nm_lock
);
5635 * Count the number of requests waiting for a reply.
5636 * Note: there could be multiple requests from the same thread.
5639 TAILQ_FOREACH(rq
, &nfs_reqq
, r_chain
) {
5640 if (rq
->r_nmp
== nmp
)
5644 /* Calculate total size of result buffer */
5645 totlen
= sizeof(struct netfs_status
) + (numThreads
* sizeof(uint64_t));
5647 if (req
->oldptr
== USER_ADDR_NULL
) { // Caller is querying buffer size
5648 lck_mtx_unlock(&nmp
->nm_lock
);
5649 lck_mtx_unlock(nfs_request_mutex
);
5650 return SYSCTL_OUT(req
, NULL
, totlen
);
5652 if (req
->oldlen
< totlen
) { // Check if caller's buffer is big enough
5653 lck_mtx_unlock(&nmp
->nm_lock
);
5654 lck_mtx_unlock(nfs_request_mutex
);
5658 MALLOC(nsp
, struct netfs_status
*, totlen
, M_TEMP
, M_WAITOK
|M_ZERO
);
5660 lck_mtx_unlock(&nmp
->nm_lock
);
5661 lck_mtx_unlock(nfs_request_mutex
);
5664 timeoutmask
= NFSSTA_TIMEO
| NFSSTA_LOCKTIMEO
| NFSSTA_JUKEBOXTIMEO
;
5665 if (nmp
->nm_state
& timeoutmask
)
5666 nsp
->ns_status
|= VQ_NOTRESP
;
5667 if (nmp
->nm_state
& NFSSTA_DEAD
)
5668 nsp
->ns_status
|= VQ_DEAD
;
5670 (void) nfs_mountopts(nmp
, nsp
->ns_mountopts
, sizeof(nsp
->ns_mountopts
));
5671 nsp
->ns_threadcount
= numThreads
;
5674 * Get the thread ids of threads waiting for a reply
5675 * and find the longest wait time.
5677 if (numThreads
> 0) {
5683 sendtime
= now
.tv_sec
;
5684 TAILQ_FOREACH(rq
, &nfs_reqq
, r_chain
) {
5685 if (rq
->r_nmp
== nmp
) {
5686 if (rq
->r_start
< sendtime
)
5687 sendtime
= rq
->r_start
;
5688 // A thread_id of zero is used to represent an async I/O request.
5689 nsp
->ns_threadids
[count
] =
5690 rq
->r_thread
? thread_tid(rq
->r_thread
) : 0;
5691 if (++count
>= numThreads
)
5695 nsp
->ns_waittime
= now
.tv_sec
- sendtime
;
5698 lck_mtx_unlock(&nmp
->nm_lock
);
5699 lck_mtx_unlock(nfs_request_mutex
);
5701 error
= SYSCTL_OUT(req
, nsp
, totlen
);