]> git.saurik.com Git - apple/xnu.git/blob - bsd/nfs/nfs_vfsops.c
1ac2b3bd5123c517b0f048ea2140eb615b489c0c
[apple/xnu.git] / bsd / nfs / nfs_vfsops.c
1 /*
2 * Copyright (c) 2000-2017 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
29 /*
30 * Copyright (c) 1989, 1993, 1995
31 * The Regents of the University of California. All rights reserved.
32 *
33 * This code is derived from software contributed to Berkeley by
34 * Rick Macklem at The University of Guelph.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
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.
51 *
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
62 * SUCH DAMAGE.
63 *
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 $
66 */
67 /*
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,
71 * Version 2.0.
72 */
73
74 #include <sys/param.h>
75 #include <sys/systm.h>
76 #include <sys/conf.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>
91 #include <sys/priv.h>
92 #include <libkern/OSAtomic.h>
93
94 #include <sys/vm.h>
95 #include <sys/vmparam.h>
96
97 #if !defined(NO_MOUNT_PRIVATE)
98 #include <sys/filedesc.h>
99 #endif /* NO_MOUNT_PRIVATE */
100
101 #include <net/if.h>
102 #include <net/route.h>
103 #include <netinet/in.h>
104
105 #include <nfs/rpcv2.h>
106 #include <nfs/krpc.h>
107 #include <nfs/nfsproto.h>
108 #include <nfs/nfs.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>
116 #if CONFIG_MACF
117 #include <security/mac_framework.h>
118 #endif
119
120 #include <pexpert/pexpert.h>
121
122 #define NFS_VFS_DBG(...) NFS_DBG(NFS_FAC_VFS, 7, ## __VA_ARGS__)
123
124 /*
125 * NFS client globals
126 */
127
128 int nfs_ticks;
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;
135
136 /* NFS requests */
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 */
144
145 thread_call_t nfs_buf_timer_call;
146
147 /* NFSv4 */
148 lck_grp_t *nfs_open_grp;
149 uint32_t nfs_open_owner_seqnum = 0;
150 uint32_t nfs_lock_owner_seqnum = 0;
151 thread_call_t nfs4_callback_timer_call;
152 int nfs4_callback_timer_on = 0;
153 char nfs4_default_domain[MAXPATHLEN];
154
155 /* nfsiod */
156 lck_grp_t *nfsiod_lck_grp;
157 lck_mtx_t *nfsiod_mutex;
158 struct nfsiodlist nfsiodfree, nfsiodwork;
159 struct nfsiodmountlist nfsiodmounts;
160 int nfsiod_thread_count = 0;
161 int nfsiod_thread_max = NFS_DEFASYNCTHREAD;
162 int nfs_max_async_writes = NFS_DEFMAXASYNCWRITES;
163
164 int nfs_iosize = NFS_IOSIZE;
165 int nfs_access_cache_timeout = NFS_MAXATTRTIMO;
166 int nfs_access_delete = 1; /* too many servers get this wrong - workaround on by default */
167 int nfs_access_dotzfs = 1;
168 int nfs_access_for_getattr = 0;
169 int nfs_allow_async = 0;
170 int nfs_statfs_rate_limit = NFS_DEFSTATFSRATELIMIT;
171 int nfs_lockd_mounts = 0;
172 int nfs_lockd_request_sent = 0;
173 int nfs_idmap_ctrl = NFS_IDMAP_CTRL_USE_IDMAP_SERVICE;
174 int nfs_callback_port = 0;
175
176 int nfs_tprintf_initial_delay = NFS_TPRINTF_INITIAL_DELAY;
177 int nfs_tprintf_delay = NFS_TPRINTF_DELAY;
178
179
180 int mountnfs(char *, mount_t, vfs_context_t, vnode_t *);
181 static int nfs_mount_diskless(struct nfs_dlmount *, const char *, int, vnode_t *, mount_t *, vfs_context_t);
182 #if !defined(NO_MOUNT_PRIVATE)
183 static int nfs_mount_diskless_private(struct nfs_dlmount *, const char *, int, vnode_t *, mount_t *, vfs_context_t);
184 #endif /* NO_MOUNT_PRIVATE */
185 int nfs_mount_connect(struct nfsmount *);
186 void nfs_mount_drain_and_cleanup(struct nfsmount *);
187 void nfs_mount_cleanup(struct nfsmount *);
188 int nfs_mountinfo_assemble(struct nfsmount *, struct xdrbuf *);
189 int nfs4_mount_update_path_with_symlink(struct nfsmount *, struct nfs_fs_path *, uint32_t, fhandle_t *, int *, fhandle_t *, vfs_context_t);
190
191 /*
192 * NFS VFS operations.
193 */
194 int nfs_vfs_mount(mount_t, vnode_t, user_addr_t, vfs_context_t);
195 int nfs_vfs_start(mount_t, int, vfs_context_t);
196 int nfs_vfs_unmount(mount_t, int, vfs_context_t);
197 int nfs_vfs_root(mount_t, vnode_t *, vfs_context_t);
198 int nfs_vfs_quotactl(mount_t, int, uid_t, caddr_t, vfs_context_t);
199 int nfs_vfs_getattr(mount_t, struct vfs_attr *, vfs_context_t);
200 int nfs_vfs_sync(mount_t, int, vfs_context_t);
201 int nfs_vfs_vget(mount_t, ino64_t, vnode_t *, vfs_context_t);
202 int nfs_vfs_vptofh(vnode_t, int *, unsigned char *, vfs_context_t);
203 int nfs_vfs_fhtovp(mount_t, int, unsigned char *, vnode_t *, vfs_context_t);
204 int nfs_vfs_init(struct vfsconf *);
205 int nfs_vfs_sysctl(int *, u_int, user_addr_t, size_t *, user_addr_t, size_t, vfs_context_t);
206
207 const struct vfsops nfs_vfsops = {
208 .vfs_mount = nfs_vfs_mount,
209 .vfs_start = nfs_vfs_start,
210 .vfs_unmount = nfs_vfs_unmount,
211 .vfs_root = nfs_vfs_root,
212 .vfs_quotactl = nfs_vfs_quotactl,
213 .vfs_getattr = nfs_vfs_getattr,
214 .vfs_sync = nfs_vfs_sync,
215 .vfs_vget = nfs_vfs_vget,
216 .vfs_fhtovp = nfs_vfs_fhtovp,
217 .vfs_vptofh = nfs_vfs_vptofh,
218 .vfs_init = nfs_vfs_init,
219 .vfs_sysctl = nfs_vfs_sysctl,
220 // We do not support the remaining VFS ops
221 };
222
223
224 /*
225 * version-specific NFS functions
226 */
227 int nfs3_mount(struct nfsmount *, vfs_context_t, nfsnode_t *);
228 int nfs4_mount(struct nfsmount *, vfs_context_t, nfsnode_t *);
229 int nfs3_fsinfo(struct nfsmount *, nfsnode_t, vfs_context_t);
230 int nfs3_update_statfs(struct nfsmount *, vfs_context_t);
231 int nfs4_update_statfs(struct nfsmount *, vfs_context_t);
232 #if !QUOTA
233 #define nfs3_getquota NULL
234 #define nfs4_getquota NULL
235 #else
236 int nfs3_getquota(struct nfsmount *, vfs_context_t, uid_t, int, struct dqblk *);
237 int nfs4_getquota(struct nfsmount *, vfs_context_t, uid_t, int, struct dqblk *);
238 #endif
239
240 const struct nfs_funcs nfs3_funcs = {
241 nfs3_mount,
242 nfs3_update_statfs,
243 nfs3_getquota,
244 nfs3_access_rpc,
245 nfs3_getattr_rpc,
246 nfs3_setattr_rpc,
247 nfs3_read_rpc_async,
248 nfs3_read_rpc_async_finish,
249 nfs3_readlink_rpc,
250 nfs3_write_rpc_async,
251 nfs3_write_rpc_async_finish,
252 nfs3_commit_rpc,
253 nfs3_lookup_rpc_async,
254 nfs3_lookup_rpc_async_finish,
255 nfs3_remove_rpc,
256 nfs3_rename_rpc,
257 nfs3_setlock_rpc,
258 nfs3_unlock_rpc,
259 nfs3_getlock_rpc
260 };
261 const struct nfs_funcs nfs4_funcs = {
262 nfs4_mount,
263 nfs4_update_statfs,
264 nfs4_getquota,
265 nfs4_access_rpc,
266 nfs4_getattr_rpc,
267 nfs4_setattr_rpc,
268 nfs4_read_rpc_async,
269 nfs4_read_rpc_async_finish,
270 nfs4_readlink_rpc,
271 nfs4_write_rpc_async,
272 nfs4_write_rpc_async_finish,
273 nfs4_commit_rpc,
274 nfs4_lookup_rpc_async,
275 nfs4_lookup_rpc_async_finish,
276 nfs4_remove_rpc,
277 nfs4_rename_rpc,
278 nfs4_setlock_rpc,
279 nfs4_unlock_rpc,
280 nfs4_getlock_rpc
281 };
282
283 /*
284 * Called once to initialize data structures...
285 */
286 int
287 nfs_vfs_init(__unused struct vfsconf *vfsp)
288 {
289 int i;
290
291 /*
292 * Check to see if major data structures haven't bloated.
293 */
294 if (sizeof(struct nfsnode) > NFS_NODEALLOC) {
295 printf("struct nfsnode bloated (> %dbytes)\n", NFS_NODEALLOC);
296 printf("Try reducing NFS_SMALLFH\n");
297 }
298 if (sizeof(struct nfsmount) > NFS_MNTALLOC) {
299 printf("struct nfsmount bloated (> %dbytes)\n", NFS_MNTALLOC);
300 }
301
302 nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
303 if (nfs_ticks < 1) {
304 nfs_ticks = 1;
305 }
306
307 /* init async I/O thread pool state */
308 TAILQ_INIT(&nfsiodfree);
309 TAILQ_INIT(&nfsiodwork);
310 TAILQ_INIT(&nfsiodmounts);
311 nfsiod_lck_grp = lck_grp_alloc_init("nfsiod", LCK_GRP_ATTR_NULL);
312 nfsiod_mutex = lck_mtx_alloc_init(nfsiod_lck_grp, LCK_ATTR_NULL);
313
314 /* init lock groups, etc. */
315 nfs_mount_grp = lck_grp_alloc_init("nfs_mount", LCK_GRP_ATTR_NULL);
316 nfs_open_grp = lck_grp_alloc_init("nfs_open", LCK_GRP_ATTR_NULL);
317 nfs_global_grp = lck_grp_alloc_init("nfs_global", LCK_GRP_ATTR_NULL);
318
319 nfs_global_mutex = lck_mtx_alloc_init(nfs_global_grp, LCK_ATTR_NULL);
320
321 /* init request list mutex */
322 nfs_request_grp = lck_grp_alloc_init("nfs_request", LCK_GRP_ATTR_NULL);
323 nfs_request_mutex = lck_mtx_alloc_init(nfs_request_grp, LCK_ATTR_NULL);
324
325 /* initialize NFS request list */
326 TAILQ_INIT(&nfs_reqq);
327
328 nfs_nbinit(); /* Init the nfsbuf table */
329 nfs_nhinit(); /* Init the nfsnode table */
330 nfs_lockinit(); /* Init the nfs lock state */
331 nfs_gss_init(); /* Init RPCSEC_GSS security */
332
333 /* NFSv4 stuff */
334 NFS4_PER_FS_ATTRIBUTES(nfs_fs_attr_bitmap);
335 NFS4_PER_OBJECT_ATTRIBUTES(nfs_object_attr_bitmap);
336 NFS4_DEFAULT_ATTRIBUTES(nfs_getattr_bitmap);
337 for (i = 0; i < NFS_ATTR_BITMAP_LEN; i++) {
338 nfs_getattr_bitmap[i] &= nfs_object_attr_bitmap[i];
339 }
340 TAILQ_INIT(&nfsclientids);
341
342 /* initialize NFS timer callouts */
343 nfs_request_timer_call = thread_call_allocate(nfs_request_timer, NULL);
344 nfs_buf_timer_call = thread_call_allocate(nfs_buf_timer, NULL);
345 nfs4_callback_timer_call = thread_call_allocate(nfs4_callback_timer, NULL);
346
347 return 0;
348 }
349
350 /*
351 * nfs statfs call
352 */
353 int
354 nfs3_update_statfs(struct nfsmount *nmp, vfs_context_t ctx)
355 {
356 nfsnode_t np;
357 int error = 0, lockerror, status, nfsvers;
358 u_int64_t xid;
359 struct nfsm_chain nmreq, nmrep;
360 uint32_t val = 0;
361
362 nfsvers = nmp->nm_vers;
363 np = nmp->nm_dnp;
364 if (!np) {
365 return ENXIO;
366 }
367 if ((error = vnode_get(NFSTOV(np)))) {
368 return error;
369 }
370
371 nfsm_chain_null(&nmreq);
372 nfsm_chain_null(&nmrep);
373
374 nfsm_chain_build_alloc_init(error, &nmreq, NFSX_FH(nfsvers));
375 nfsm_chain_add_fh(error, &nmreq, nfsvers, np->n_fhp, np->n_fhsize);
376 nfsm_chain_build_done(error, &nmreq);
377 nfsmout_if(error);
378 error = nfs_request2(np, NULL, &nmreq, NFSPROC_FSSTAT, vfs_context_thread(ctx),
379 vfs_context_ucred(ctx), NULL, R_SOFT, &nmrep, &xid, &status);
380 if (error == ETIMEDOUT) {
381 goto nfsmout;
382 }
383 if ((lockerror = nfs_node_lock(np))) {
384 error = lockerror;
385 }
386 if (nfsvers == NFS_VER3) {
387 nfsm_chain_postop_attr_update(error, &nmrep, np, &xid);
388 }
389 if (!lockerror) {
390 nfs_node_unlock(np);
391 }
392 if (!error) {
393 error = status;
394 }
395 nfsm_assert(error, NFSTONMP(np), ENXIO);
396 nfsmout_if(error);
397 lck_mtx_lock(&nmp->nm_lock);
398 NFS_BITMAP_SET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_SPACE_TOTAL);
399 NFS_BITMAP_SET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_SPACE_FREE);
400 NFS_BITMAP_SET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_SPACE_AVAIL);
401 if (nfsvers == NFS_VER3) {
402 NFS_BITMAP_SET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_FILES_AVAIL);
403 NFS_BITMAP_SET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_FILES_TOTAL);
404 NFS_BITMAP_SET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_FILES_FREE);
405 nmp->nm_fsattr.nfsa_bsize = NFS_FABLKSIZE;
406 nfsm_chain_get_64(error, &nmrep, nmp->nm_fsattr.nfsa_space_total);
407 nfsm_chain_get_64(error, &nmrep, nmp->nm_fsattr.nfsa_space_free);
408 nfsm_chain_get_64(error, &nmrep, nmp->nm_fsattr.nfsa_space_avail);
409 nfsm_chain_get_64(error, &nmrep, nmp->nm_fsattr.nfsa_files_total);
410 nfsm_chain_get_64(error, &nmrep, nmp->nm_fsattr.nfsa_files_free);
411 nfsm_chain_get_64(error, &nmrep, nmp->nm_fsattr.nfsa_files_avail);
412 // skip invarsec
413 } else {
414 nfsm_chain_adv(error, &nmrep, NFSX_UNSIGNED); // skip tsize?
415 nfsm_chain_get_32(error, &nmrep, nmp->nm_fsattr.nfsa_bsize);
416 nfsm_chain_get_32(error, &nmrep, val);
417 nfsmout_if(error);
418 if (nmp->nm_fsattr.nfsa_bsize <= 0) {
419 nmp->nm_fsattr.nfsa_bsize = NFS_FABLKSIZE;
420 }
421 nmp->nm_fsattr.nfsa_space_total = (uint64_t)val * nmp->nm_fsattr.nfsa_bsize;
422 nfsm_chain_get_32(error, &nmrep, val);
423 nfsmout_if(error);
424 nmp->nm_fsattr.nfsa_space_free = (uint64_t)val * nmp->nm_fsattr.nfsa_bsize;
425 nfsm_chain_get_32(error, &nmrep, val);
426 nfsmout_if(error);
427 nmp->nm_fsattr.nfsa_space_avail = (uint64_t)val * nmp->nm_fsattr.nfsa_bsize;
428 }
429 lck_mtx_unlock(&nmp->nm_lock);
430 nfsmout:
431 nfsm_chain_cleanup(&nmreq);
432 nfsm_chain_cleanup(&nmrep);
433 vnode_put(NFSTOV(np));
434 return error;
435 }
436
437 int
438 nfs4_update_statfs(struct nfsmount *nmp, vfs_context_t ctx)
439 {
440 nfsnode_t np;
441 int error = 0, lockerror, status, nfsvers, numops;
442 u_int64_t xid;
443 struct nfsm_chain nmreq, nmrep;
444 uint32_t bitmap[NFS_ATTR_BITMAP_LEN];
445 struct nfs_vattr nvattr;
446 struct nfsreq_secinfo_args si;
447
448 nfsvers = nmp->nm_vers;
449 np = nmp->nm_dnp;
450 if (!np) {
451 return ENXIO;
452 }
453 if ((error = vnode_get(NFSTOV(np)))) {
454 return error;
455 }
456
457 NFSREQ_SECINFO_SET(&si, np, NULL, 0, NULL, 0);
458 NVATTR_INIT(&nvattr);
459 nfsm_chain_null(&nmreq);
460 nfsm_chain_null(&nmrep);
461
462 // PUTFH + GETATTR
463 numops = 2;
464 nfsm_chain_build_alloc_init(error, &nmreq, 15 * NFSX_UNSIGNED);
465 nfsm_chain_add_compound_header(error, &nmreq, "statfs", nmp->nm_minor_vers, numops);
466 numops--;
467 nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH);
468 nfsm_chain_add_fh(error, &nmreq, nfsvers, np->n_fhp, np->n_fhsize);
469 numops--;
470 nfsm_chain_add_32(error, &nmreq, NFS_OP_GETATTR);
471 NFS_COPY_ATTRIBUTES(nfs_getattr_bitmap, bitmap);
472 NFS4_STATFS_ATTRIBUTES(bitmap);
473 nfsm_chain_add_bitmap_supported(error, &nmreq, bitmap, nmp, np);
474 nfsm_chain_build_done(error, &nmreq);
475 nfsm_assert(error, (numops == 0), EPROTO);
476 nfsmout_if(error);
477 error = nfs_request2(np, NULL, &nmreq, NFSPROC4_COMPOUND,
478 vfs_context_thread(ctx), vfs_context_ucred(ctx),
479 NULL, R_SOFT, &nmrep, &xid, &status);
480 nfsm_chain_skip_tag(error, &nmrep);
481 nfsm_chain_get_32(error, &nmrep, numops);
482 nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
483 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
484 nfsm_assert(error, NFSTONMP(np), ENXIO);
485 nfsmout_if(error);
486 lck_mtx_lock(&nmp->nm_lock);
487 error = nfs4_parsefattr(&nmrep, &nmp->nm_fsattr, &nvattr, NULL, NULL, NULL);
488 lck_mtx_unlock(&nmp->nm_lock);
489 nfsmout_if(error);
490 if ((lockerror = nfs_node_lock(np))) {
491 error = lockerror;
492 }
493 if (!error) {
494 nfs_loadattrcache(np, &nvattr, &xid, 0);
495 }
496 if (!lockerror) {
497 nfs_node_unlock(np);
498 }
499 nfsm_assert(error, NFSTONMP(np), ENXIO);
500 nfsmout_if(error);
501 nmp->nm_fsattr.nfsa_bsize = NFS_FABLKSIZE;
502 nfsmout:
503 NVATTR_CLEANUP(&nvattr);
504 nfsm_chain_cleanup(&nmreq);
505 nfsm_chain_cleanup(&nmrep);
506 vnode_put(NFSTOV(np));
507 return error;
508 }
509
510 /*
511 * Return an NFS volume name from the mntfrom name.
512 */
513 static void
514 nfs_get_volname(struct mount *mp, char *volname, size_t len)
515 {
516 const char *ptr, *cptr;
517 const char *mntfrom = mp->mnt_vfsstat.f_mntfromname;
518 size_t mflen = strnlen(mntfrom, MAXPATHLEN + 1);
519
520 if (mflen > MAXPATHLEN || mflen == 0) {
521 strlcpy(volname, "Bad volname", len);
522 return;
523 }
524
525 /* Move back over trailing slashes */
526 for (ptr = &mntfrom[mflen - 1]; ptr != mntfrom && *ptr == '/'; ptr--) {
527 mflen--;
528 }
529
530 /* Find first character after the last slash */
531 cptr = ptr = NULL;
532 for (size_t i = 0; i < mflen; i++) {
533 if (mntfrom[i] == '/') {
534 ptr = &mntfrom[i + 1];
535 }
536 /* And the first character after the first colon */
537 else if (cptr == NULL && mntfrom[i] == ':') {
538 cptr = &mntfrom[i + 1];
539 }
540 }
541
542 /*
543 * No slash or nothing after the last slash
544 * use everything past the first colon
545 */
546 if (ptr == NULL || *ptr == '\0') {
547 ptr = cptr;
548 }
549 /* Otherwise use the mntfrom name */
550 if (ptr == NULL) {
551 ptr = mntfrom;
552 }
553
554 mflen = &mntfrom[mflen] - ptr;
555 len = mflen + 1 < len ? mflen + 1 : len;
556
557 strlcpy(volname, ptr, len);
558 }
559
560 /*
561 * The NFS VFS_GETATTR function: "statfs"-type information is retrieved
562 * using the nf_update_statfs() function, and other attributes are cobbled
563 * together from whatever sources we can (getattr, fsinfo, pathconf).
564 */
565 int
566 nfs_vfs_getattr(mount_t mp, struct vfs_attr *fsap, vfs_context_t ctx)
567 {
568 struct nfsmount *nmp;
569 uint32_t bsize;
570 int error = 0, nfsvers;
571
572 nmp = VFSTONFS(mp);
573 if (nfs_mount_gone(nmp)) {
574 return ENXIO;
575 }
576 nfsvers = nmp->nm_vers;
577
578 if (VFSATTR_IS_ACTIVE(fsap, f_bsize) ||
579 VFSATTR_IS_ACTIVE(fsap, f_iosize) ||
580 VFSATTR_IS_ACTIVE(fsap, f_blocks) ||
581 VFSATTR_IS_ACTIVE(fsap, f_bfree) ||
582 VFSATTR_IS_ACTIVE(fsap, f_bavail) ||
583 VFSATTR_IS_ACTIVE(fsap, f_bused) ||
584 VFSATTR_IS_ACTIVE(fsap, f_files) ||
585 VFSATTR_IS_ACTIVE(fsap, f_ffree)) {
586 int statfsrate = nfs_statfs_rate_limit;
587 int refresh = 1;
588
589 /*
590 * Are we rate-limiting statfs RPCs?
591 * (Treat values less than 1 or greater than 1,000,000 as no limit.)
592 */
593 if ((statfsrate > 0) && (statfsrate < 1000000)) {
594 struct timeval now;
595 uint32_t stamp;
596
597 microuptime(&now);
598 lck_mtx_lock(&nmp->nm_lock);
599 stamp = (now.tv_sec * statfsrate) + (now.tv_usec / (1000000 / statfsrate));
600 if (stamp != nmp->nm_fsattrstamp) {
601 refresh = 1;
602 nmp->nm_fsattrstamp = stamp;
603 } else {
604 refresh = 0;
605 }
606 lck_mtx_unlock(&nmp->nm_lock);
607 }
608
609 if (refresh && !nfs_use_cache(nmp)) {
610 error = nmp->nm_funcs->nf_update_statfs(nmp, ctx);
611 }
612 if ((error == ESTALE) || (error == ETIMEDOUT)) {
613 error = 0;
614 }
615 if (error) {
616 return error;
617 }
618
619 lck_mtx_lock(&nmp->nm_lock);
620 VFSATTR_RETURN(fsap, f_iosize, nfs_iosize);
621 VFSATTR_RETURN(fsap, f_bsize, nmp->nm_fsattr.nfsa_bsize);
622 bsize = nmp->nm_fsattr.nfsa_bsize;
623 if (NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_SPACE_TOTAL)) {
624 VFSATTR_RETURN(fsap, f_blocks, nmp->nm_fsattr.nfsa_space_total / bsize);
625 }
626 if (NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_SPACE_FREE)) {
627 VFSATTR_RETURN(fsap, f_bfree, nmp->nm_fsattr.nfsa_space_free / bsize);
628 }
629 if (NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_SPACE_AVAIL)) {
630 VFSATTR_RETURN(fsap, f_bavail, nmp->nm_fsattr.nfsa_space_avail / bsize);
631 }
632 if (NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_SPACE_TOTAL) &&
633 NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_SPACE_FREE)) {
634 VFSATTR_RETURN(fsap, f_bused,
635 (nmp->nm_fsattr.nfsa_space_total / bsize) -
636 (nmp->nm_fsattr.nfsa_space_free / bsize));
637 }
638 if (NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_FILES_TOTAL)) {
639 VFSATTR_RETURN(fsap, f_files, nmp->nm_fsattr.nfsa_files_total);
640 }
641 if (NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_FILES_FREE)) {
642 VFSATTR_RETURN(fsap, f_ffree, nmp->nm_fsattr.nfsa_files_free);
643 }
644 lck_mtx_unlock(&nmp->nm_lock);
645 }
646
647 if (VFSATTR_IS_ACTIVE(fsap, f_vol_name)) {
648 /*%%% IF fail over support is implemented we may need to take nm_lock */
649 nfs_get_volname(mp, fsap->f_vol_name, MAXPATHLEN);
650 VFSATTR_SET_SUPPORTED(fsap, f_vol_name);
651 }
652 if (VFSATTR_IS_ACTIVE(fsap, f_capabilities)) {
653 u_int32_t caps, valid;
654 nfsnode_t np = nmp->nm_dnp;
655
656 nfsm_assert(error, VFSTONFS(mp) && np, ENXIO);
657 if (error) {
658 return error;
659 }
660 lck_mtx_lock(&nmp->nm_lock);
661
662 /*
663 * The capabilities[] array defines what this volume supports.
664 *
665 * The valid[] array defines which bits this code understands
666 * the meaning of (whether the volume has that capability or not).
667 * Any zero bits here means "I don't know what you're asking about"
668 * and the caller cannot tell whether that capability is
669 * present or not.
670 */
671 caps = valid = 0;
672 if (NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_SYMLINK_SUPPORT)) {
673 valid |= VOL_CAP_FMT_SYMBOLICLINKS;
674 if (nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_SYMLINK) {
675 caps |= VOL_CAP_FMT_SYMBOLICLINKS;
676 }
677 }
678 if (NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_LINK_SUPPORT)) {
679 valid |= VOL_CAP_FMT_HARDLINKS;
680 if (nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_LINK) {
681 caps |= VOL_CAP_FMT_HARDLINKS;
682 }
683 }
684 if (NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_CASE_INSENSITIVE)) {
685 valid |= VOL_CAP_FMT_CASE_SENSITIVE;
686 if (!(nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_CASE_INSENSITIVE)) {
687 caps |= VOL_CAP_FMT_CASE_SENSITIVE;
688 }
689 }
690 if (NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_CASE_PRESERVING)) {
691 valid |= VOL_CAP_FMT_CASE_PRESERVING;
692 if (nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_CASE_PRESERVING) {
693 caps |= VOL_CAP_FMT_CASE_PRESERVING;
694 }
695 }
696 /* Note: VOL_CAP_FMT_2TB_FILESIZE is actually used to test for "large file support" */
697 if (NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_MAXFILESIZE)) {
698 /* Is server's max file size at least 4GB? */
699 if (nmp->nm_fsattr.nfsa_maxfilesize >= 0x100000000ULL) {
700 caps |= VOL_CAP_FMT_2TB_FILESIZE;
701 }
702 } else if (nfsvers >= NFS_VER3) {
703 /*
704 * NFSv3 and up supports 64 bits of file size.
705 * So, we'll just assume maxfilesize >= 4GB
706 */
707 caps |= VOL_CAP_FMT_2TB_FILESIZE;
708 }
709 if (nfsvers >= NFS_VER4) {
710 caps |= VOL_CAP_FMT_HIDDEN_FILES;
711 valid |= VOL_CAP_FMT_HIDDEN_FILES;
712 // VOL_CAP_FMT_OPENDENYMODES
713 // caps |= VOL_CAP_FMT_OPENDENYMODES;
714 // valid |= VOL_CAP_FMT_OPENDENYMODES;
715 }
716 // no version of nfs supports immutable files
717 caps |= VOL_CAP_FMT_NO_IMMUTABLE_FILES;
718 valid |= VOL_CAP_FMT_NO_IMMUTABLE_FILES;
719
720 fsap->f_capabilities.capabilities[VOL_CAPABILITIES_FORMAT] =
721 // VOL_CAP_FMT_PERSISTENTOBJECTIDS |
722 // VOL_CAP_FMT_SYMBOLICLINKS |
723 // VOL_CAP_FMT_HARDLINKS |
724 // VOL_CAP_FMT_JOURNAL |
725 // VOL_CAP_FMT_JOURNAL_ACTIVE |
726 // VOL_CAP_FMT_NO_ROOT_TIMES |
727 // VOL_CAP_FMT_SPARSE_FILES |
728 // VOL_CAP_FMT_ZERO_RUNS |
729 // VOL_CAP_FMT_CASE_SENSITIVE |
730 // VOL_CAP_FMT_CASE_PRESERVING |
731 // VOL_CAP_FMT_FAST_STATFS |
732 // VOL_CAP_FMT_2TB_FILESIZE |
733 // VOL_CAP_FMT_OPENDENYMODES |
734 // VOL_CAP_FMT_HIDDEN_FILES |
735 caps;
736 fsap->f_capabilities.valid[VOL_CAPABILITIES_FORMAT] =
737 VOL_CAP_FMT_PERSISTENTOBJECTIDS |
738 // VOL_CAP_FMT_SYMBOLICLINKS |
739 // VOL_CAP_FMT_HARDLINKS |
740 // VOL_CAP_FMT_JOURNAL |
741 // VOL_CAP_FMT_JOURNAL_ACTIVE |
742 // VOL_CAP_FMT_NO_ROOT_TIMES |
743 // VOL_CAP_FMT_SPARSE_FILES |
744 // VOL_CAP_FMT_ZERO_RUNS |
745 // VOL_CAP_FMT_CASE_SENSITIVE |
746 // VOL_CAP_FMT_CASE_PRESERVING |
747 VOL_CAP_FMT_FAST_STATFS |
748 VOL_CAP_FMT_2TB_FILESIZE |
749 // VOL_CAP_FMT_OPENDENYMODES |
750 // VOL_CAP_FMT_HIDDEN_FILES |
751 valid;
752
753 /*
754 * We don't support most of the interfaces.
755 *
756 * We MAY support locking, but we don't have any easy way of probing.
757 * We can tell if there's no lockd running or if locks have been
758 * disabled for a mount, so we can definitely answer NO in that case.
759 * Any attempt to send a request to lockd to test for locking support
760 * may cause the lazily-launched locking daemons to be started
761 * unnecessarily. So we avoid that. However, we do record if we ever
762 * successfully perform a lock operation on a mount point, so if it
763 * looks like lock ops have worked, we do report that we support them.
764 */
765 caps = valid = 0;
766 if (nfsvers >= NFS_VER4) {
767 caps = VOL_CAP_INT_ADVLOCK | VOL_CAP_INT_FLOCK;
768 valid = VOL_CAP_INT_ADVLOCK | VOL_CAP_INT_FLOCK;
769 if (nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_ACL) {
770 caps |= VOL_CAP_INT_EXTENDED_SECURITY;
771 }
772 valid |= VOL_CAP_INT_EXTENDED_SECURITY;
773 if (nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_NAMED_ATTR) {
774 caps |= VOL_CAP_INT_EXTENDED_ATTR;
775 }
776 valid |= VOL_CAP_INT_EXTENDED_ATTR;
777 #if NAMEDSTREAMS
778 if (nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_NAMED_ATTR) {
779 caps |= VOL_CAP_INT_NAMEDSTREAMS;
780 }
781 valid |= VOL_CAP_INT_NAMEDSTREAMS;
782 #endif
783 } else if (nmp->nm_lockmode == NFS_LOCK_MODE_DISABLED) {
784 /* locks disabled on this mount, so they definitely won't work */
785 valid = VOL_CAP_INT_ADVLOCK | VOL_CAP_INT_FLOCK;
786 } else if (nmp->nm_state & NFSSTA_LOCKSWORK) {
787 caps = VOL_CAP_INT_ADVLOCK | VOL_CAP_INT_FLOCK;
788 valid = VOL_CAP_INT_ADVLOCK | VOL_CAP_INT_FLOCK;
789 }
790 fsap->f_capabilities.capabilities[VOL_CAPABILITIES_INTERFACES] =
791 // VOL_CAP_INT_SEARCHFS |
792 // VOL_CAP_INT_ATTRLIST |
793 // VOL_CAP_INT_NFSEXPORT |
794 // VOL_CAP_INT_READDIRATTR |
795 // VOL_CAP_INT_EXCHANGEDATA |
796 // VOL_CAP_INT_COPYFILE |
797 // VOL_CAP_INT_ALLOCATE |
798 // VOL_CAP_INT_VOL_RENAME |
799 // VOL_CAP_INT_ADVLOCK |
800 // VOL_CAP_INT_FLOCK |
801 // VOL_CAP_INT_EXTENDED_SECURITY |
802 // VOL_CAP_INT_USERACCESS |
803 // VOL_CAP_INT_MANLOCK |
804 // VOL_CAP_INT_NAMEDSTREAMS |
805 // VOL_CAP_INT_EXTENDED_ATTR |
806 VOL_CAP_INT_REMOTE_EVENT |
807 caps;
808 fsap->f_capabilities.valid[VOL_CAPABILITIES_INTERFACES] =
809 VOL_CAP_INT_SEARCHFS |
810 VOL_CAP_INT_ATTRLIST |
811 VOL_CAP_INT_NFSEXPORT |
812 VOL_CAP_INT_READDIRATTR |
813 VOL_CAP_INT_EXCHANGEDATA |
814 VOL_CAP_INT_COPYFILE |
815 VOL_CAP_INT_ALLOCATE |
816 VOL_CAP_INT_VOL_RENAME |
817 // VOL_CAP_INT_ADVLOCK |
818 // VOL_CAP_INT_FLOCK |
819 // VOL_CAP_INT_EXTENDED_SECURITY |
820 // VOL_CAP_INT_USERACCESS |
821 // VOL_CAP_INT_MANLOCK |
822 // VOL_CAP_INT_NAMEDSTREAMS |
823 // VOL_CAP_INT_EXTENDED_ATTR |
824 VOL_CAP_INT_REMOTE_EVENT |
825 valid;
826
827 fsap->f_capabilities.capabilities[VOL_CAPABILITIES_RESERVED1] = 0;
828 fsap->f_capabilities.valid[VOL_CAPABILITIES_RESERVED1] = 0;
829
830 fsap->f_capabilities.capabilities[VOL_CAPABILITIES_RESERVED2] = 0;
831 fsap->f_capabilities.valid[VOL_CAPABILITIES_RESERVED2] = 0;
832
833 VFSATTR_SET_SUPPORTED(fsap, f_capabilities);
834 lck_mtx_unlock(&nmp->nm_lock);
835 }
836
837 if (VFSATTR_IS_ACTIVE(fsap, f_attributes)) {
838 fsap->f_attributes.validattr.commonattr = 0;
839 fsap->f_attributes.validattr.volattr =
840 ATTR_VOL_NAME | ATTR_VOL_CAPABILITIES | ATTR_VOL_ATTRIBUTES;
841 fsap->f_attributes.validattr.dirattr = 0;
842 fsap->f_attributes.validattr.fileattr = 0;
843 fsap->f_attributes.validattr.forkattr = 0;
844
845 fsap->f_attributes.nativeattr.commonattr = 0;
846 fsap->f_attributes.nativeattr.volattr =
847 ATTR_VOL_NAME | ATTR_VOL_CAPABILITIES | ATTR_VOL_ATTRIBUTES;
848 fsap->f_attributes.nativeattr.dirattr = 0;
849 fsap->f_attributes.nativeattr.fileattr = 0;
850 fsap->f_attributes.nativeattr.forkattr = 0;
851
852 VFSATTR_SET_SUPPORTED(fsap, f_attributes);
853 }
854
855 return error;
856 }
857
858 /*
859 * nfs version 3 fsinfo rpc call
860 */
861 int
862 nfs3_fsinfo(struct nfsmount *nmp, nfsnode_t np, vfs_context_t ctx)
863 {
864 int error = 0, lockerror, status, nmlocked = 0;
865 u_int64_t xid;
866 uint32_t val, prefsize, maxsize;
867 struct nfsm_chain nmreq, nmrep;
868
869 nfsm_chain_null(&nmreq);
870 nfsm_chain_null(&nmrep);
871
872 nfsm_chain_build_alloc_init(error, &nmreq, NFSX_FH(nmp->nm_vers));
873 nfsm_chain_add_fh(error, &nmreq, nmp->nm_vers, np->n_fhp, np->n_fhsize);
874 nfsm_chain_build_done(error, &nmreq);
875 nfsmout_if(error);
876 error = nfs_request(np, NULL, &nmreq, NFSPROC_FSINFO, ctx, NULL, &nmrep, &xid, &status);
877 if ((lockerror = nfs_node_lock(np))) {
878 error = lockerror;
879 }
880 nfsm_chain_postop_attr_update(error, &nmrep, np, &xid);
881 if (!lockerror) {
882 nfs_node_unlock(np);
883 }
884 if (!error) {
885 error = status;
886 }
887 nfsmout_if(error);
888
889 lck_mtx_lock(&nmp->nm_lock);
890 nmlocked = 1;
891
892 nfsm_chain_get_32(error, &nmrep, maxsize);
893 nfsm_chain_get_32(error, &nmrep, prefsize);
894 nfsmout_if(error);
895 nmp->nm_fsattr.nfsa_maxread = maxsize;
896 if (prefsize < nmp->nm_rsize) {
897 nmp->nm_rsize = (prefsize + NFS_FABLKSIZE - 1) &
898 ~(NFS_FABLKSIZE - 1);
899 }
900 if ((maxsize > 0) && (maxsize < nmp->nm_rsize)) {
901 nmp->nm_rsize = maxsize & ~(NFS_FABLKSIZE - 1);
902 if (nmp->nm_rsize == 0) {
903 nmp->nm_rsize = maxsize;
904 }
905 }
906 nfsm_chain_adv(error, &nmrep, NFSX_UNSIGNED); // skip rtmult
907
908 nfsm_chain_get_32(error, &nmrep, maxsize);
909 nfsm_chain_get_32(error, &nmrep, prefsize);
910 nfsmout_if(error);
911 nmp->nm_fsattr.nfsa_maxwrite = maxsize;
912 if (prefsize < nmp->nm_wsize) {
913 nmp->nm_wsize = (prefsize + NFS_FABLKSIZE - 1) &
914 ~(NFS_FABLKSIZE - 1);
915 }
916 if ((maxsize > 0) && (maxsize < nmp->nm_wsize)) {
917 nmp->nm_wsize = maxsize & ~(NFS_FABLKSIZE - 1);
918 if (nmp->nm_wsize == 0) {
919 nmp->nm_wsize = maxsize;
920 }
921 }
922 nfsm_chain_adv(error, &nmrep, NFSX_UNSIGNED); // skip wtmult
923
924 nfsm_chain_get_32(error, &nmrep, prefsize);
925 nfsmout_if(error);
926 if ((prefsize > 0) && (prefsize < nmp->nm_readdirsize)) {
927 nmp->nm_readdirsize = prefsize;
928 }
929 if ((nmp->nm_fsattr.nfsa_maxread > 0) &&
930 (nmp->nm_fsattr.nfsa_maxread < nmp->nm_readdirsize)) {
931 nmp->nm_readdirsize = nmp->nm_fsattr.nfsa_maxread;
932 }
933
934 nfsm_chain_get_64(error, &nmrep, nmp->nm_fsattr.nfsa_maxfilesize);
935
936 nfsm_chain_adv(error, &nmrep, 2 * NFSX_UNSIGNED); // skip time_delta
937
938 /* convert FS properties to our own flags */
939 nfsm_chain_get_32(error, &nmrep, val);
940 nfsmout_if(error);
941 if (val & NFSV3FSINFO_LINK) {
942 nmp->nm_fsattr.nfsa_flags |= NFS_FSFLAG_LINK;
943 }
944 if (val & NFSV3FSINFO_SYMLINK) {
945 nmp->nm_fsattr.nfsa_flags |= NFS_FSFLAG_SYMLINK;
946 }
947 if (val & NFSV3FSINFO_HOMOGENEOUS) {
948 nmp->nm_fsattr.nfsa_flags |= NFS_FSFLAG_HOMOGENEOUS;
949 }
950 if (val & NFSV3FSINFO_CANSETTIME) {
951 nmp->nm_fsattr.nfsa_flags |= NFS_FSFLAG_SET_TIME;
952 }
953 nmp->nm_state |= NFSSTA_GOTFSINFO;
954 NFS_BITMAP_SET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_MAXREAD);
955 NFS_BITMAP_SET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_MAXWRITE);
956 NFS_BITMAP_SET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_MAXFILESIZE);
957 NFS_BITMAP_SET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_LINK_SUPPORT);
958 NFS_BITMAP_SET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_SYMLINK_SUPPORT);
959 NFS_BITMAP_SET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_HOMOGENEOUS);
960 NFS_BITMAP_SET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_CANSETTIME);
961 nfsmout:
962 if (nmlocked) {
963 lck_mtx_unlock(&nmp->nm_lock);
964 }
965 nfsm_chain_cleanup(&nmreq);
966 nfsm_chain_cleanup(&nmrep);
967 return error;
968 }
969
970 /*
971 * Mount a remote root fs via. nfs. This depends on the info in the
972 * nfs_diskless structure that has been filled in properly by some primary
973 * bootstrap.
974 * It goes something like this:
975 * - do enough of "ifconfig" by calling ifioctl() so that the system
976 * can talk to the server
977 * - If nfs_diskless.mygateway is filled in, use that address as
978 * a default gateway.
979 * - hand craft the swap nfs vnode hanging off a fake mount point
980 * if swdevt[0].sw_dev == NODEV
981 * - build the rootfs mount point and call mountnfs() to do the rest.
982 */
983 int
984 nfs_mountroot(void)
985 {
986 struct nfs_diskless nd;
987 mount_t mp = NULL;
988 vnode_t vp = NULL;
989 vfs_context_t ctx;
990 int error;
991 #if !defined(NO_MOUNT_PRIVATE)
992 mount_t mppriv = NULL;
993 vnode_t vppriv = NULL;
994 #endif /* NO_MOUNT_PRIVATE */
995 int v3, sotype;
996
997 /*
998 * Call nfs_boot_init() to fill in the nfs_diskless struct.
999 * Note: networking must already have been configured before
1000 * we're called.
1001 */
1002 bzero((caddr_t) &nd, sizeof(nd));
1003 error = nfs_boot_init(&nd);
1004 if (error) {
1005 panic("nfs_boot_init: unable to initialize NFS root system information, "
1006 "error %d, check configuration: %s\n", error, PE_boot_args());
1007 }
1008
1009 /*
1010 * Try NFSv3 first, then fallback to NFSv2.
1011 * Likewise, try TCP first, then fall back to UDP.
1012 */
1013 v3 = 1;
1014 sotype = SOCK_STREAM;
1015
1016 tryagain:
1017 error = nfs_boot_getfh(&nd, v3, sotype);
1018 if (error) {
1019 if (error == EHOSTDOWN || error == EHOSTUNREACH) {
1020 if (nd.nd_root.ndm_mntfrom) {
1021 FREE_ZONE(nd.nd_root.ndm_mntfrom,
1022 MAXPATHLEN, M_NAMEI);
1023 }
1024 if (nd.nd_root.ndm_path) {
1025 FREE_ZONE(nd.nd_root.ndm_path,
1026 MAXPATHLEN, M_NAMEI);
1027 }
1028 if (nd.nd_private.ndm_mntfrom) {
1029 FREE_ZONE(nd.nd_private.ndm_mntfrom,
1030 MAXPATHLEN, M_NAMEI);
1031 }
1032 if (nd.nd_private.ndm_path) {
1033 FREE_ZONE(nd.nd_private.ndm_path,
1034 MAXPATHLEN, M_NAMEI);
1035 }
1036 return error;
1037 }
1038 if (v3) {
1039 if (sotype == SOCK_STREAM) {
1040 printf("NFS mount (v3,TCP) failed with error %d, trying UDP...\n", error);
1041 sotype = SOCK_DGRAM;
1042 goto tryagain;
1043 }
1044 printf("NFS mount (v3,UDP) failed with error %d, trying v2...\n", error);
1045 v3 = 0;
1046 sotype = SOCK_STREAM;
1047 goto tryagain;
1048 } else if (sotype == SOCK_STREAM) {
1049 printf("NFS mount (v2,TCP) failed with error %d, trying UDP...\n", error);
1050 sotype = SOCK_DGRAM;
1051 goto tryagain;
1052 } else {
1053 printf("NFS mount (v2,UDP) failed with error %d, giving up...\n", error);
1054 }
1055 switch (error) {
1056 case EPROGUNAVAIL:
1057 panic("NFS mount failed: NFS server mountd not responding, check server configuration: %s", PE_boot_args());
1058 case EACCES:
1059 case EPERM:
1060 panic("NFS mount failed: NFS server refused mount, check server configuration: %s", PE_boot_args());
1061 default:
1062 panic("NFS mount failed with error %d, check configuration: %s", error, PE_boot_args());
1063 }
1064 }
1065
1066 ctx = vfs_context_kernel();
1067
1068 /*
1069 * Create the root mount point.
1070 */
1071 #if !defined(NO_MOUNT_PRIVATE)
1072 {
1073 //PWC hack until we have a real "mount" tool to remount root rw
1074 int rw_root = 0;
1075 int flags = MNT_ROOTFS | MNT_RDONLY;
1076 PE_parse_boot_argn("-rwroot_hack", &rw_root, sizeof(rw_root));
1077 if (rw_root) {
1078 flags = MNT_ROOTFS;
1079 kprintf("-rwroot_hack in effect: mounting root fs read/write\n");
1080 }
1081
1082 if ((error = nfs_mount_diskless(&nd.nd_root, "/", flags, &vp, &mp, ctx)))
1083 #else
1084 if ((error = nfs_mount_diskless(&nd.nd_root, "/", MNT_ROOTFS, &vp, &mp, ctx)))
1085 #endif /* NO_MOUNT_PRIVATE */
1086 {
1087 if (v3) {
1088 if (sotype == SOCK_STREAM) {
1089 printf("NFS root mount (v3,TCP) failed with %d, trying UDP...\n", error);
1090 sotype = SOCK_DGRAM;
1091 goto tryagain;
1092 }
1093 printf("NFS root mount (v3,UDP) failed with %d, trying v2...\n", error);
1094 v3 = 0;
1095 sotype = SOCK_STREAM;
1096 goto tryagain;
1097 } else if (sotype == SOCK_STREAM) {
1098 printf("NFS root mount (v2,TCP) failed with %d, trying UDP...\n", error);
1099 sotype = SOCK_DGRAM;
1100 goto tryagain;
1101 } else {
1102 printf("NFS root mount (v2,UDP) failed with error %d, giving up...\n", error);
1103 }
1104 panic("NFS root mount failed with error %d, check configuration: %s\n", error, PE_boot_args());
1105 }
1106 }
1107 printf("root on %s\n", nd.nd_root.ndm_mntfrom);
1108
1109 vfs_unbusy(mp);
1110 mount_list_add(mp);
1111 rootvp = vp;
1112
1113 #if !defined(NO_MOUNT_PRIVATE)
1114 if (nd.nd_private.ndm_saddr.sin_addr.s_addr) {
1115 error = nfs_mount_diskless_private(&nd.nd_private, "/private",
1116 0, &vppriv, &mppriv, ctx);
1117 if (error) {
1118 panic("NFS /private mount failed with error %d, check configuration: %s\n", error, PE_boot_args());
1119 }
1120 printf("private on %s\n", nd.nd_private.ndm_mntfrom);
1121
1122 vfs_unbusy(mppriv);
1123 mount_list_add(mppriv);
1124 }
1125
1126 #endif /* NO_MOUNT_PRIVATE */
1127
1128 if (nd.nd_root.ndm_mntfrom) {
1129 FREE_ZONE(nd.nd_root.ndm_mntfrom, MAXPATHLEN, M_NAMEI);
1130 }
1131 if (nd.nd_root.ndm_path) {
1132 FREE_ZONE(nd.nd_root.ndm_path, MAXPATHLEN, M_NAMEI);
1133 }
1134 if (nd.nd_private.ndm_mntfrom) {
1135 FREE_ZONE(nd.nd_private.ndm_mntfrom, MAXPATHLEN, M_NAMEI);
1136 }
1137 if (nd.nd_private.ndm_path) {
1138 FREE_ZONE(nd.nd_private.ndm_path, MAXPATHLEN, M_NAMEI);
1139 }
1140
1141 /* Get root attributes (for the time). */
1142 error = nfs_getattr(VTONFS(vp), NULL, ctx, NGA_UNCACHED);
1143 if (error) {
1144 panic("NFS mount: failed to get attributes for root directory, error %d, check server", error);
1145 }
1146 return 0;
1147 }
1148
1149 /*
1150 * Internal version of mount system call for diskless setup.
1151 */
1152 static int
1153 nfs_mount_diskless(
1154 struct nfs_dlmount *ndmntp,
1155 const char *mntname,
1156 int mntflag,
1157 vnode_t *vpp,
1158 mount_t *mpp,
1159 vfs_context_t ctx)
1160 {
1161 mount_t mp;
1162 int error, numcomps;
1163 char *xdrbuf, *p, *cp, *frompath, *endserverp;
1164 char uaddr[MAX_IPv4_STR_LEN];
1165 struct xdrbuf xb;
1166 uint32_t mattrs[NFS_MATTR_BITMAP_LEN];
1167 uint32_t mflags_mask[NFS_MFLAG_BITMAP_LEN];
1168 uint32_t mflags[NFS_MFLAG_BITMAP_LEN];
1169 uint32_t argslength_offset, attrslength_offset, end_offset;
1170
1171 if ((error = vfs_rootmountalloc("nfs", ndmntp->ndm_mntfrom, &mp))) {
1172 printf("nfs_mount_diskless: NFS not configured\n");
1173 return error;
1174 }
1175
1176 mp->mnt_flag |= mntflag;
1177 if (!(mntflag & MNT_RDONLY)) {
1178 mp->mnt_flag &= ~MNT_RDONLY;
1179 }
1180
1181 /* find the server-side path being mounted */
1182 frompath = ndmntp->ndm_mntfrom;
1183 if (*frompath == '[') { /* skip IPv6 literal address */
1184 while (*frompath && (*frompath != ']')) {
1185 frompath++;
1186 }
1187 if (*frompath == ']') {
1188 frompath++;
1189 }
1190 }
1191 while (*frompath && (*frompath != ':')) {
1192 frompath++;
1193 }
1194 endserverp = frompath;
1195 while (*frompath && (*frompath == ':')) {
1196 frompath++;
1197 }
1198 /* count fs location path components */
1199 p = frompath;
1200 while (*p && (*p == '/')) {
1201 p++;
1202 }
1203 numcomps = 0;
1204 while (*p) {
1205 numcomps++;
1206 while (*p && (*p != '/')) {
1207 p++;
1208 }
1209 while (*p && (*p == '/')) {
1210 p++;
1211 }
1212 }
1213
1214 /* convert address to universal address string */
1215 if (inet_ntop(AF_INET, &ndmntp->ndm_saddr.sin_addr, uaddr, sizeof(uaddr)) != uaddr) {
1216 printf("nfs_mount_diskless: bad address\n");
1217 return EINVAL;
1218 }
1219
1220 /* prepare mount attributes */
1221 NFS_BITMAP_ZERO(mattrs, NFS_MATTR_BITMAP_LEN);
1222 NFS_BITMAP_SET(mattrs, NFS_MATTR_NFS_VERSION);
1223 NFS_BITMAP_SET(mattrs, NFS_MATTR_SOCKET_TYPE);
1224 NFS_BITMAP_SET(mattrs, NFS_MATTR_NFS_PORT);
1225 NFS_BITMAP_SET(mattrs, NFS_MATTR_FH);
1226 NFS_BITMAP_SET(mattrs, NFS_MATTR_FS_LOCATIONS);
1227 NFS_BITMAP_SET(mattrs, NFS_MATTR_MNTFLAGS);
1228
1229 /* prepare mount flags */
1230 NFS_BITMAP_ZERO(mflags_mask, NFS_MFLAG_BITMAP_LEN);
1231 NFS_BITMAP_ZERO(mflags, NFS_MFLAG_BITMAP_LEN);
1232 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_RESVPORT);
1233 NFS_BITMAP_SET(mflags, NFS_MFLAG_RESVPORT);
1234
1235 /* build xdr buffer */
1236 xb_init_buffer(&xb, NULL, 0);
1237 xb_add_32(error, &xb, NFS_ARGSVERSION_XDR);
1238 argslength_offset = xb_offset(&xb);
1239 xb_add_32(error, &xb, 0); // args length
1240 xb_add_32(error, &xb, NFS_XDRARGS_VERSION_0);
1241 xb_add_bitmap(error, &xb, mattrs, NFS_MATTR_BITMAP_LEN);
1242 attrslength_offset = xb_offset(&xb);
1243 xb_add_32(error, &xb, 0); // attrs length
1244 xb_add_32(error, &xb, ndmntp->ndm_nfsv3 ? 3 : 2); // NFS version
1245 xb_add_string(error, &xb, ((ndmntp->ndm_sotype == SOCK_DGRAM) ? "udp" : "tcp"), 3);
1246 xb_add_32(error, &xb, ntohs(ndmntp->ndm_saddr.sin_port)); // NFS port
1247 xb_add_fh(error, &xb, &ndmntp->ndm_fh[0], ndmntp->ndm_fhlen);
1248 /* fs location */
1249 xb_add_32(error, &xb, 1); /* fs location count */
1250 xb_add_32(error, &xb, 1); /* server count */
1251 xb_add_string(error, &xb, ndmntp->ndm_mntfrom, (endserverp - ndmntp->ndm_mntfrom)); /* server name */
1252 xb_add_32(error, &xb, 1); /* address count */
1253 xb_add_string(error, &xb, uaddr, strlen(uaddr)); /* address */
1254 xb_add_32(error, &xb, 0); /* empty server info */
1255 xb_add_32(error, &xb, numcomps); /* pathname component count */
1256 p = frompath;
1257 while (*p && (*p == '/')) {
1258 p++;
1259 }
1260 while (*p) {
1261 cp = p;
1262 while (*p && (*p != '/')) {
1263 p++;
1264 }
1265 xb_add_string(error, &xb, cp, (p - cp)); /* component */
1266 if (error) {
1267 break;
1268 }
1269 while (*p && (*p == '/')) {
1270 p++;
1271 }
1272 }
1273 xb_add_32(error, &xb, 0); /* empty fsl info */
1274 xb_add_32(error, &xb, mntflag); /* MNT flags */
1275 xb_build_done(error, &xb);
1276
1277 /* update opaque counts */
1278 end_offset = xb_offset(&xb);
1279 if (!error) {
1280 error = xb_seek(&xb, argslength_offset);
1281 xb_add_32(error, &xb, end_offset - argslength_offset + XDRWORD /*version*/);
1282 }
1283 if (!error) {
1284 error = xb_seek(&xb, attrslength_offset);
1285 xb_add_32(error, &xb, end_offset - attrslength_offset - XDRWORD /*don't include length field*/);
1286 }
1287 if (error) {
1288 printf("nfs_mount_diskless: error %d assembling mount args\n", error);
1289 xb_cleanup(&xb);
1290 return error;
1291 }
1292 /* grab the assembled buffer */
1293 xdrbuf = xb_buffer_base(&xb);
1294 xb.xb_flags &= ~XB_CLEANUP;
1295
1296 /* do the mount */
1297 if ((error = mountnfs(xdrbuf, mp, ctx, vpp))) {
1298 printf("nfs_mountroot: mount %s failed: %d\n", mntname, error);
1299 // XXX vfs_rootmountfailed(mp);
1300 mount_list_lock();
1301 mp->mnt_vtable->vfc_refcount--;
1302 mount_list_unlock();
1303 vfs_unbusy(mp);
1304 mount_lock_destroy(mp);
1305 #if CONFIG_MACF
1306 mac_mount_label_destroy(mp);
1307 #endif
1308 FREE_ZONE(mp, sizeof(struct mount), M_MOUNT);
1309 } else {
1310 *mpp = mp;
1311 }
1312 xb_cleanup(&xb);
1313 return error;
1314 }
1315
1316 #if !defined(NO_MOUNT_PRIVATE)
1317 /*
1318 * Internal version of mount system call to mount "/private"
1319 * separately in diskless setup
1320 */
1321 static int
1322 nfs_mount_diskless_private(
1323 struct nfs_dlmount *ndmntp,
1324 const char *mntname,
1325 int mntflag,
1326 vnode_t *vpp,
1327 mount_t *mpp,
1328 vfs_context_t ctx)
1329 {
1330 mount_t mp;
1331 int error, numcomps;
1332 proc_t procp;
1333 struct vfstable *vfsp;
1334 struct nameidata nd;
1335 vnode_t vp;
1336 char *xdrbuf = NULL, *p, *cp, *frompath, *endserverp;
1337 char uaddr[MAX_IPv4_STR_LEN];
1338 struct xdrbuf xb;
1339 uint32_t mattrs[NFS_MATTR_BITMAP_LEN];
1340 uint32_t mflags_mask[NFS_MFLAG_BITMAP_LEN], mflags[NFS_MFLAG_BITMAP_LEN];
1341 uint32_t argslength_offset, attrslength_offset, end_offset;
1342
1343 procp = current_proc(); /* XXX */
1344 xb_init(&xb, 0);
1345
1346 {
1347 /*
1348 * mimic main()!. Temporarily set up rootvnode and other stuff so
1349 * that namei works. Need to undo this because main() does it, too
1350 */
1351 struct filedesc *fdp; /* pointer to file descriptor state */
1352 fdp = procp->p_fd;
1353 mountlist.tqh_first->mnt_flag |= MNT_ROOTFS;
1354
1355 /* Get the vnode for '/'. Set fdp->fd_cdir to reference it. */
1356 if (VFS_ROOT(mountlist.tqh_first, &rootvnode, NULL)) {
1357 panic("cannot find root vnode");
1358 }
1359 error = vnode_ref(rootvnode);
1360 if (error) {
1361 printf("nfs_mountroot: vnode_ref() failed on root vnode!\n");
1362 goto out;
1363 }
1364 fdp->fd_cdir = rootvnode;
1365 fdp->fd_rdir = NULL;
1366 }
1367
1368 /*
1369 * Get vnode to be covered
1370 */
1371 NDINIT(&nd, LOOKUP, OP_LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE,
1372 CAST_USER_ADDR_T(mntname), ctx);
1373 if ((error = namei(&nd))) {
1374 printf("nfs_mountroot: private namei failed!\n");
1375 goto out;
1376 }
1377 {
1378 /* undo vnode_ref() in mimic main()! */
1379 vnode_rele(rootvnode);
1380 }
1381 nameidone(&nd);
1382 vp = nd.ni_vp;
1383
1384 if ((error = VNOP_FSYNC(vp, MNT_WAIT, ctx)) ||
1385 (error = buf_invalidateblks(vp, BUF_WRITE_DATA, 0, 0))) {
1386 vnode_put(vp);
1387 goto out;
1388 }
1389 if (vnode_vtype(vp) != VDIR) {
1390 vnode_put(vp);
1391 error = ENOTDIR;
1392 goto out;
1393 }
1394 for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) {
1395 if (!strncmp(vfsp->vfc_name, "nfs", sizeof(vfsp->vfc_name))) {
1396 break;
1397 }
1398 }
1399 if (vfsp == NULL) {
1400 printf("nfs_mountroot: private NFS not configured\n");
1401 vnode_put(vp);
1402 error = ENODEV;
1403 goto out;
1404 }
1405 if (vnode_mountedhere(vp) != NULL) {
1406 vnode_put(vp);
1407 error = EBUSY;
1408 goto out;
1409 }
1410
1411 /*
1412 * Allocate and initialize the filesystem.
1413 */
1414 mp = _MALLOC_ZONE((u_int32_t)sizeof(struct mount), M_MOUNT, M_WAITOK);
1415 if (!mp) {
1416 printf("nfs_mountroot: unable to allocate mount structure\n");
1417 vnode_put(vp);
1418 error = ENOMEM;
1419 goto out;
1420 }
1421 bzero((char *)mp, sizeof(struct mount));
1422
1423 /* Initialize the default IO constraints */
1424 mp->mnt_maxreadcnt = mp->mnt_maxwritecnt = MAXPHYS;
1425 mp->mnt_segreadcnt = mp->mnt_segwritecnt = 32;
1426 mp->mnt_ioflags = 0;
1427 mp->mnt_realrootvp = NULLVP;
1428 mp->mnt_authcache_ttl = 0; /* Allways go to our lookup */
1429
1430 mount_lock_init(mp);
1431 TAILQ_INIT(&mp->mnt_vnodelist);
1432 TAILQ_INIT(&mp->mnt_workerqueue);
1433 TAILQ_INIT(&mp->mnt_newvnodes);
1434 (void)vfs_busy(mp, LK_NOWAIT);
1435 TAILQ_INIT(&mp->mnt_vnodelist);
1436 mount_list_lock();
1437 vfsp->vfc_refcount++;
1438 mount_list_unlock();
1439 mp->mnt_vtable = vfsp;
1440 mp->mnt_op = vfsp->vfc_vfsops;
1441 // mp->mnt_stat.f_type = vfsp->vfc_typenum;
1442 mp->mnt_flag = mntflag;
1443 mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK;
1444 strncpy(mp->mnt_vfsstat.f_fstypename, vfsp->vfc_name, MFSNAMELEN - 1);
1445 vp->v_mountedhere = mp;
1446 mp->mnt_vnodecovered = vp;
1447 vp = NULLVP;
1448 mp->mnt_vfsstat.f_owner = kauth_cred_getuid(kauth_cred_get());
1449 (void) copystr(mntname, mp->mnt_vfsstat.f_mntonname, MAXPATHLEN - 1, 0);
1450 (void) copystr(ndmntp->ndm_mntfrom, mp->mnt_vfsstat.f_mntfromname, MAXPATHLEN - 1, 0);
1451 #if CONFIG_MACF
1452 mac_mount_label_init(mp);
1453 mac_mount_label_associate(ctx, mp);
1454 #endif
1455
1456 /* find the server-side path being mounted */
1457 frompath = ndmntp->ndm_mntfrom;
1458 if (*frompath == '[') { /* skip IPv6 literal address */
1459 while (*frompath && (*frompath != ']')) {
1460 frompath++;
1461 }
1462 if (*frompath == ']') {
1463 frompath++;
1464 }
1465 }
1466 while (*frompath && (*frompath != ':')) {
1467 frompath++;
1468 }
1469 endserverp = frompath;
1470 while (*frompath && (*frompath == ':')) {
1471 frompath++;
1472 }
1473 /* count fs location path components */
1474 p = frompath;
1475 while (*p && (*p == '/')) {
1476 p++;
1477 }
1478 numcomps = 0;
1479 while (*p) {
1480 numcomps++;
1481 while (*p && (*p != '/')) {
1482 p++;
1483 }
1484 while (*p && (*p == '/')) {
1485 p++;
1486 }
1487 }
1488
1489 /* convert address to universal address string */
1490 if (inet_ntop(AF_INET, &ndmntp->ndm_saddr.sin_addr, uaddr, sizeof(uaddr)) != uaddr) {
1491 printf("nfs_mountroot: bad address\n");
1492 error = EINVAL;
1493 goto out;
1494 }
1495
1496 /* prepare mount attributes */
1497 NFS_BITMAP_ZERO(mattrs, NFS_MATTR_BITMAP_LEN);
1498 NFS_BITMAP_SET(mattrs, NFS_MATTR_NFS_VERSION);
1499 NFS_BITMAP_SET(mattrs, NFS_MATTR_SOCKET_TYPE);
1500 NFS_BITMAP_SET(mattrs, NFS_MATTR_NFS_PORT);
1501 NFS_BITMAP_SET(mattrs, NFS_MATTR_FH);
1502 NFS_BITMAP_SET(mattrs, NFS_MATTR_FS_LOCATIONS);
1503 NFS_BITMAP_SET(mattrs, NFS_MATTR_MNTFLAGS);
1504
1505 /* prepare mount flags */
1506 NFS_BITMAP_ZERO(mflags_mask, NFS_MFLAG_BITMAP_LEN);
1507 NFS_BITMAP_ZERO(mflags, NFS_MFLAG_BITMAP_LEN);
1508 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_RESVPORT);
1509 NFS_BITMAP_SET(mflags, NFS_MFLAG_RESVPORT);
1510
1511 /* build xdr buffer */
1512 xb_init_buffer(&xb, NULL, 0);
1513 xb_add_32(error, &xb, NFS_ARGSVERSION_XDR);
1514 argslength_offset = xb_offset(&xb);
1515 xb_add_32(error, &xb, 0); // args length
1516 xb_add_32(error, &xb, NFS_XDRARGS_VERSION_0);
1517 xb_add_bitmap(error, &xb, mattrs, NFS_MATTR_BITMAP_LEN);
1518 attrslength_offset = xb_offset(&xb);
1519 xb_add_32(error, &xb, 0); // attrs length
1520 xb_add_32(error, &xb, ndmntp->ndm_nfsv3 ? 3 : 2); // NFS version
1521 xb_add_string(error, &xb, ((ndmntp->ndm_sotype == SOCK_DGRAM) ? "udp" : "tcp"), 3);
1522 xb_add_32(error, &xb, ntohs(ndmntp->ndm_saddr.sin_port)); // NFS port
1523 xb_add_fh(error, &xb, &ndmntp->ndm_fh[0], ndmntp->ndm_fhlen);
1524 /* fs location */
1525 xb_add_32(error, &xb, 1); /* fs location count */
1526 xb_add_32(error, &xb, 1); /* server count */
1527 xb_add_string(error, &xb, ndmntp->ndm_mntfrom, (endserverp - ndmntp->ndm_mntfrom)); /* server name */
1528 xb_add_32(error, &xb, 1); /* address count */
1529 xb_add_string(error, &xb, uaddr, strlen(uaddr)); /* address */
1530 xb_add_32(error, &xb, 0); /* empty server info */
1531 xb_add_32(error, &xb, numcomps); /* pathname component count */
1532 p = frompath;
1533 while (*p && (*p == '/')) {
1534 p++;
1535 }
1536 while (*p) {
1537 cp = p;
1538 while (*p && (*p != '/')) {
1539 p++;
1540 }
1541 xb_add_string(error, &xb, cp, (p - cp)); /* component */
1542 if (error) {
1543 break;
1544 }
1545 while (*p && (*p == '/')) {
1546 p++;
1547 }
1548 }
1549 xb_add_32(error, &xb, 0); /* empty fsl info */
1550 xb_add_32(error, &xb, mntflag); /* MNT flags */
1551 xb_build_done(error, &xb);
1552
1553 /* update opaque counts */
1554 end_offset = xb_offset(&xb);
1555 if (!error) {
1556 error = xb_seek(&xb, argslength_offset);
1557 xb_add_32(error, &xb, end_offset - argslength_offset + XDRWORD /*version*/);
1558 }
1559 if (!error) {
1560 error = xb_seek(&xb, attrslength_offset);
1561 xb_add_32(error, &xb, end_offset - attrslength_offset - XDRWORD /*don't include length field*/);
1562 }
1563 if (error) {
1564 printf("nfs_mountroot: error %d assembling mount args\n", error);
1565 goto out;
1566 }
1567 /* grab the assembled buffer */
1568 xdrbuf = xb_buffer_base(&xb);
1569 xb.xb_flags &= ~XB_CLEANUP;
1570
1571 /* do the mount */
1572 if ((error = mountnfs(xdrbuf, mp, ctx, &vp))) {
1573 printf("nfs_mountroot: mount %s failed: %d\n", mntname, error);
1574 vnode_put(mp->mnt_vnodecovered);
1575 mount_list_lock();
1576 vfsp->vfc_refcount--;
1577 mount_list_unlock();
1578 vfs_unbusy(mp);
1579 mount_lock_destroy(mp);
1580 #if CONFIG_MACF
1581 mac_mount_label_destroy(mp);
1582 #endif
1583 FREE_ZONE(mp, sizeof(struct mount), M_MOUNT);
1584 goto out;
1585 }
1586
1587 *mpp = mp;
1588 *vpp = vp;
1589 out:
1590 xb_cleanup(&xb);
1591 return error;
1592 }
1593 #endif /* NO_MOUNT_PRIVATE */
1594
1595 /*
1596 * Convert old style NFS mount args to XDR.
1597 */
1598 static int
1599 nfs_convert_old_nfs_args(mount_t mp, user_addr_t data, vfs_context_t ctx, int argsversion, int inkernel, char **xdrbufp)
1600 {
1601 int error = 0, args64bit, argsize, numcomps;
1602 struct user_nfs_args args;
1603 struct nfs_args tempargs;
1604 caddr_t argsp;
1605 size_t len;
1606 u_char nfh[NFS4_FHSIZE];
1607 char *mntfrom, *endserverp, *frompath, *p, *cp;
1608 struct sockaddr_storage ss;
1609 void *sinaddr;
1610 char uaddr[MAX_IPv6_STR_LEN];
1611 uint32_t mattrs[NFS_MATTR_BITMAP_LEN];
1612 uint32_t mflags_mask[NFS_MFLAG_BITMAP_LEN], mflags[NFS_MFLAG_BITMAP_LEN];
1613 uint32_t nfsvers, nfslockmode = 0, argslength_offset, attrslength_offset, end_offset;
1614 struct xdrbuf xb;
1615
1616 *xdrbufp = NULL;
1617
1618 /* allocate a temporary buffer for mntfrom */
1619 MALLOC_ZONE(mntfrom, char*, MAXPATHLEN, M_NAMEI, M_WAITOK);
1620 if (!mntfrom) {
1621 return ENOMEM;
1622 }
1623
1624 args64bit = (inkernel || vfs_context_is64bit(ctx));
1625 argsp = args64bit ? (void*)&args : (void*)&tempargs;
1626
1627 argsize = args64bit ? sizeof(args) : sizeof(tempargs);
1628 switch (argsversion) {
1629 case 3:
1630 argsize -= NFS_ARGSVERSION4_INCSIZE;
1631 case 4:
1632 argsize -= NFS_ARGSVERSION5_INCSIZE;
1633 case 5:
1634 argsize -= NFS_ARGSVERSION6_INCSIZE;
1635 case 6:
1636 break;
1637 default:
1638 error = EPROGMISMATCH;
1639 goto nfsmout;
1640 }
1641
1642 /* read in the structure */
1643 if (inkernel) {
1644 bcopy(CAST_DOWN(void *, data), argsp, argsize);
1645 } else {
1646 error = copyin(data, argsp, argsize);
1647 }
1648 nfsmout_if(error);
1649
1650 if (!args64bit) {
1651 args.addrlen = tempargs.addrlen;
1652 args.sotype = tempargs.sotype;
1653 args.proto = tempargs.proto;
1654 args.fhsize = tempargs.fhsize;
1655 args.flags = tempargs.flags;
1656 args.wsize = tempargs.wsize;
1657 args.rsize = tempargs.rsize;
1658 args.readdirsize = tempargs.readdirsize;
1659 args.timeo = tempargs.timeo;
1660 args.retrans = tempargs.retrans;
1661 args.maxgrouplist = tempargs.maxgrouplist;
1662 args.readahead = tempargs.readahead;
1663 args.leaseterm = tempargs.leaseterm;
1664 args.deadthresh = tempargs.deadthresh;
1665 args.addr = CAST_USER_ADDR_T(tempargs.addr);
1666 args.fh = CAST_USER_ADDR_T(tempargs.fh);
1667 args.hostname = CAST_USER_ADDR_T(tempargs.hostname);
1668 if (args.version >= 4) {
1669 args.acregmin = tempargs.acregmin;
1670 args.acregmax = tempargs.acregmax;
1671 args.acdirmin = tempargs.acdirmin;
1672 args.acdirmax = tempargs.acdirmax;
1673 }
1674 if (args.version >= 5) {
1675 args.auth = tempargs.auth;
1676 }
1677 if (args.version >= 6) {
1678 args.deadtimeout = tempargs.deadtimeout;
1679 }
1680 }
1681
1682 if ((args.fhsize < 0) || (args.fhsize > NFS4_FHSIZE)) {
1683 error = EINVAL;
1684 goto nfsmout;
1685 }
1686 if (args.fhsize > 0) {
1687 if (inkernel) {
1688 bcopy(CAST_DOWN(void *, args.fh), (caddr_t)nfh, args.fhsize);
1689 } else {
1690 error = copyin(args.fh, (caddr_t)nfh, args.fhsize);
1691 }
1692 nfsmout_if(error);
1693 }
1694
1695 if (inkernel) {
1696 error = copystr(CAST_DOWN(void *, args.hostname), mntfrom, MAXPATHLEN - 1, &len);
1697 } else {
1698 error = copyinstr(args.hostname, mntfrom, MAXPATHLEN - 1, &len);
1699 }
1700 nfsmout_if(error);
1701 bzero(&mntfrom[len], MAXPATHLEN - len);
1702
1703 /* find the server-side path being mounted */
1704 frompath = mntfrom;
1705 if (*frompath == '[') { /* skip IPv6 literal address */
1706 while (*frompath && (*frompath != ']')) {
1707 frompath++;
1708 }
1709 if (*frompath == ']') {
1710 frompath++;
1711 }
1712 }
1713 while (*frompath && (*frompath != ':')) {
1714 frompath++;
1715 }
1716 endserverp = frompath;
1717 while (*frompath && (*frompath == ':')) {
1718 frompath++;
1719 }
1720 /* count fs location path components */
1721 p = frompath;
1722 while (*p && (*p == '/')) {
1723 p++;
1724 }
1725 numcomps = 0;
1726 while (*p) {
1727 numcomps++;
1728 while (*p && (*p != '/')) {
1729 p++;
1730 }
1731 while (*p && (*p == '/')) {
1732 p++;
1733 }
1734 }
1735
1736 /* copy socket address */
1737 if (inkernel) {
1738 bcopy(CAST_DOWN(void *, args.addr), &ss, args.addrlen);
1739 } else {
1740 if ((size_t)args.addrlen > sizeof(struct sockaddr_storage)) {
1741 error = EINVAL;
1742 } else {
1743 error = copyin(args.addr, &ss, args.addrlen);
1744 }
1745 }
1746 nfsmout_if(error);
1747 ss.ss_len = args.addrlen;
1748
1749 /* convert address to universal address string */
1750 if (ss.ss_family == AF_INET) {
1751 sinaddr = &((struct sockaddr_in*)&ss)->sin_addr;
1752 } else if (ss.ss_family == AF_INET6) {
1753 sinaddr = &((struct sockaddr_in6*)&ss)->sin6_addr;
1754 } else {
1755 sinaddr = NULL;
1756 }
1757 if (!sinaddr || (inet_ntop(ss.ss_family, sinaddr, uaddr, sizeof(uaddr)) != uaddr)) {
1758 error = EINVAL;
1759 goto nfsmout;
1760 }
1761
1762 /* prepare mount flags */
1763 NFS_BITMAP_ZERO(mflags_mask, NFS_MFLAG_BITMAP_LEN);
1764 NFS_BITMAP_ZERO(mflags, NFS_MFLAG_BITMAP_LEN);
1765 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_SOFT);
1766 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_INTR);
1767 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_RESVPORT);
1768 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_NOCONNECT);
1769 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_DUMBTIMER);
1770 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_CALLUMNT);
1771 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_RDIRPLUS);
1772 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_NONEGNAMECACHE);
1773 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_MUTEJUKEBOX);
1774 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_NOQUOTA);
1775 if (args.flags & NFSMNT_SOFT) {
1776 NFS_BITMAP_SET(mflags, NFS_MFLAG_SOFT);
1777 }
1778 if (args.flags & NFSMNT_INT) {
1779 NFS_BITMAP_SET(mflags, NFS_MFLAG_INTR);
1780 }
1781 if (args.flags & NFSMNT_RESVPORT) {
1782 NFS_BITMAP_SET(mflags, NFS_MFLAG_RESVPORT);
1783 }
1784 if (args.flags & NFSMNT_NOCONN) {
1785 NFS_BITMAP_SET(mflags, NFS_MFLAG_NOCONNECT);
1786 }
1787 if (args.flags & NFSMNT_DUMBTIMR) {
1788 NFS_BITMAP_SET(mflags, NFS_MFLAG_DUMBTIMER);
1789 }
1790 if (args.flags & NFSMNT_CALLUMNT) {
1791 NFS_BITMAP_SET(mflags, NFS_MFLAG_CALLUMNT);
1792 }
1793 if (args.flags & NFSMNT_RDIRPLUS) {
1794 NFS_BITMAP_SET(mflags, NFS_MFLAG_RDIRPLUS);
1795 }
1796 if (args.flags & NFSMNT_NONEGNAMECACHE) {
1797 NFS_BITMAP_SET(mflags, NFS_MFLAG_NONEGNAMECACHE);
1798 }
1799 if (args.flags & NFSMNT_MUTEJUKEBOX) {
1800 NFS_BITMAP_SET(mflags, NFS_MFLAG_MUTEJUKEBOX);
1801 }
1802 if (args.flags & NFSMNT_NOQUOTA) {
1803 NFS_BITMAP_SET(mflags, NFS_MFLAG_NOQUOTA);
1804 }
1805
1806 /* prepare mount attributes */
1807 NFS_BITMAP_ZERO(mattrs, NFS_MATTR_BITMAP_LEN);
1808 NFS_BITMAP_SET(mattrs, NFS_MATTR_FLAGS);
1809 NFS_BITMAP_SET(mattrs, NFS_MATTR_NFS_VERSION);
1810 NFS_BITMAP_SET(mattrs, NFS_MATTR_SOCKET_TYPE);
1811 NFS_BITMAP_SET(mattrs, NFS_MATTR_NFS_PORT);
1812 NFS_BITMAP_SET(mattrs, NFS_MATTR_FH);
1813 NFS_BITMAP_SET(mattrs, NFS_MATTR_FS_LOCATIONS);
1814 NFS_BITMAP_SET(mattrs, NFS_MATTR_MNTFLAGS);
1815 NFS_BITMAP_SET(mattrs, NFS_MATTR_MNTFROM);
1816 if (args.flags & NFSMNT_NFSV4) {
1817 nfsvers = 4;
1818 } else if (args.flags & NFSMNT_NFSV3) {
1819 nfsvers = 3;
1820 } else {
1821 nfsvers = 2;
1822 }
1823 if ((args.flags & NFSMNT_RSIZE) && (args.rsize > 0)) {
1824 NFS_BITMAP_SET(mattrs, NFS_MATTR_READ_SIZE);
1825 }
1826 if ((args.flags & NFSMNT_WSIZE) && (args.wsize > 0)) {
1827 NFS_BITMAP_SET(mattrs, NFS_MATTR_WRITE_SIZE);
1828 }
1829 if ((args.flags & NFSMNT_TIMEO) && (args.timeo > 0)) {
1830 NFS_BITMAP_SET(mattrs, NFS_MATTR_REQUEST_TIMEOUT);
1831 }
1832 if ((args.flags & NFSMNT_RETRANS) && (args.retrans > 0)) {
1833 NFS_BITMAP_SET(mattrs, NFS_MATTR_SOFT_RETRY_COUNT);
1834 }
1835 if ((args.flags & NFSMNT_MAXGRPS) && (args.maxgrouplist > 0)) {
1836 NFS_BITMAP_SET(mattrs, NFS_MATTR_MAX_GROUP_LIST);
1837 }
1838 if ((args.flags & NFSMNT_READAHEAD) && (args.readahead > 0)) {
1839 NFS_BITMAP_SET(mattrs, NFS_MATTR_READAHEAD);
1840 }
1841 if ((args.flags & NFSMNT_READDIRSIZE) && (args.readdirsize > 0)) {
1842 NFS_BITMAP_SET(mattrs, NFS_MATTR_READDIR_SIZE);
1843 }
1844 if ((args.flags & NFSMNT_NOLOCKS) ||
1845 (args.flags & NFSMNT_LOCALLOCKS)) {
1846 NFS_BITMAP_SET(mattrs, NFS_MATTR_LOCK_MODE);
1847 if (args.flags & NFSMNT_NOLOCKS) {
1848 nfslockmode = NFS_LOCK_MODE_DISABLED;
1849 } else if (args.flags & NFSMNT_LOCALLOCKS) {
1850 nfslockmode = NFS_LOCK_MODE_LOCAL;
1851 } else {
1852 nfslockmode = NFS_LOCK_MODE_ENABLED;
1853 }
1854 }
1855 if (args.version >= 4) {
1856 if ((args.flags & NFSMNT_ACREGMIN) && (args.acregmin > 0)) {
1857 NFS_BITMAP_SET(mattrs, NFS_MATTR_ATTRCACHE_REG_MIN);
1858 }
1859 if ((args.flags & NFSMNT_ACREGMAX) && (args.acregmax > 0)) {
1860 NFS_BITMAP_SET(mattrs, NFS_MATTR_ATTRCACHE_REG_MAX);
1861 }
1862 if ((args.flags & NFSMNT_ACDIRMIN) && (args.acdirmin > 0)) {
1863 NFS_BITMAP_SET(mattrs, NFS_MATTR_ATTRCACHE_DIR_MIN);
1864 }
1865 if ((args.flags & NFSMNT_ACDIRMAX) && (args.acdirmax > 0)) {
1866 NFS_BITMAP_SET(mattrs, NFS_MATTR_ATTRCACHE_DIR_MAX);
1867 }
1868 }
1869 if (args.version >= 5) {
1870 if ((args.flags & NFSMNT_SECFLAVOR) || (args.flags & NFSMNT_SECSYSOK)) {
1871 NFS_BITMAP_SET(mattrs, NFS_MATTR_SECURITY);
1872 }
1873 }
1874 if (args.version >= 6) {
1875 if ((args.flags & NFSMNT_DEADTIMEOUT) && (args.deadtimeout > 0)) {
1876 NFS_BITMAP_SET(mattrs, NFS_MATTR_DEAD_TIMEOUT);
1877 }
1878 }
1879
1880 /* build xdr buffer */
1881 xb_init_buffer(&xb, NULL, 0);
1882 xb_add_32(error, &xb, args.version);
1883 argslength_offset = xb_offset(&xb);
1884 xb_add_32(error, &xb, 0); // args length
1885 xb_add_32(error, &xb, NFS_XDRARGS_VERSION_0);
1886 xb_add_bitmap(error, &xb, mattrs, NFS_MATTR_BITMAP_LEN);
1887 attrslength_offset = xb_offset(&xb);
1888 xb_add_32(error, &xb, 0); // attrs length
1889 xb_add_bitmap(error, &xb, mflags_mask, NFS_MFLAG_BITMAP_LEN); /* mask */
1890 xb_add_bitmap(error, &xb, mflags, NFS_MFLAG_BITMAP_LEN); /* value */
1891 xb_add_32(error, &xb, nfsvers);
1892 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_READ_SIZE)) {
1893 xb_add_32(error, &xb, args.rsize);
1894 }
1895 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_WRITE_SIZE)) {
1896 xb_add_32(error, &xb, args.wsize);
1897 }
1898 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_READDIR_SIZE)) {
1899 xb_add_32(error, &xb, args.readdirsize);
1900 }
1901 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_READAHEAD)) {
1902 xb_add_32(error, &xb, args.readahead);
1903 }
1904 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_ATTRCACHE_REG_MIN)) {
1905 xb_add_32(error, &xb, args.acregmin);
1906 xb_add_32(error, &xb, 0);
1907 }
1908 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_ATTRCACHE_REG_MAX)) {
1909 xb_add_32(error, &xb, args.acregmax);
1910 xb_add_32(error, &xb, 0);
1911 }
1912 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_ATTRCACHE_DIR_MIN)) {
1913 xb_add_32(error, &xb, args.acdirmin);
1914 xb_add_32(error, &xb, 0);
1915 }
1916 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_ATTRCACHE_DIR_MAX)) {
1917 xb_add_32(error, &xb, args.acdirmax);
1918 xb_add_32(error, &xb, 0);
1919 }
1920 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_LOCK_MODE)) {
1921 xb_add_32(error, &xb, nfslockmode);
1922 }
1923 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_SECURITY)) {
1924 uint32_t flavors[2], i = 0;
1925 if (args.flags & NFSMNT_SECFLAVOR) {
1926 flavors[i++] = args.auth;
1927 }
1928 if ((args.flags & NFSMNT_SECSYSOK) && ((i == 0) || (flavors[0] != RPCAUTH_SYS))) {
1929 flavors[i++] = RPCAUTH_SYS;
1930 }
1931 xb_add_word_array(error, &xb, flavors, i);
1932 }
1933 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_MAX_GROUP_LIST)) {
1934 xb_add_32(error, &xb, args.maxgrouplist);
1935 }
1936 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_SOCKET_TYPE)) {
1937 xb_add_string(error, &xb, ((args.sotype == SOCK_DGRAM) ? "udp" : "tcp"), 3);
1938 }
1939 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_NFS_PORT)) {
1940 xb_add_32(error, &xb, ((ss.ss_family == AF_INET) ?
1941 ntohs(((struct sockaddr_in*)&ss)->sin_port) :
1942 ntohs(((struct sockaddr_in6*)&ss)->sin6_port)));
1943 }
1944 /* NFS_MATTR_MOUNT_PORT (not available in old args) */
1945 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_REQUEST_TIMEOUT)) {
1946 /* convert from .1s increments to time */
1947 xb_add_32(error, &xb, args.timeo / 10);
1948 xb_add_32(error, &xb, (args.timeo % 10) * 100000000);
1949 }
1950 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_SOFT_RETRY_COUNT)) {
1951 xb_add_32(error, &xb, args.retrans);
1952 }
1953 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_DEAD_TIMEOUT)) {
1954 xb_add_32(error, &xb, args.deadtimeout);
1955 xb_add_32(error, &xb, 0);
1956 }
1957 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_FH)) {
1958 xb_add_fh(error, &xb, &nfh[0], args.fhsize);
1959 }
1960 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_FS_LOCATIONS)) {
1961 xb_add_32(error, &xb, 1); /* fs location count */
1962 xb_add_32(error, &xb, 1); /* server count */
1963 xb_add_string(error, &xb, mntfrom, (endserverp - mntfrom)); /* server name */
1964 xb_add_32(error, &xb, 1); /* address count */
1965 xb_add_string(error, &xb, uaddr, strlen(uaddr)); /* address */
1966 xb_add_32(error, &xb, 0); /* empty server info */
1967 xb_add_32(error, &xb, numcomps); /* pathname component count */
1968 nfsmout_if(error);
1969 p = frompath;
1970 while (*p && (*p == '/')) {
1971 p++;
1972 }
1973 while (*p) {
1974 cp = p;
1975 while (*p && (*p != '/')) {
1976 p++;
1977 }
1978 xb_add_string(error, &xb, cp, (p - cp)); /* component */
1979 nfsmout_if(error);
1980 while (*p && (*p == '/')) {
1981 p++;
1982 }
1983 }
1984 xb_add_32(error, &xb, 0); /* empty fsl info */
1985 }
1986 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_MNTFLAGS)) {
1987 xb_add_32(error, &xb, (vfs_flags(mp) & MNT_VISFLAGMASK)); /* VFS MNT_* flags */
1988 }
1989 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_MNTFROM)) {
1990 xb_add_string(error, &xb, mntfrom, strlen(mntfrom)); /* fixed f_mntfromname */
1991 }
1992 xb_build_done(error, &xb);
1993
1994 /* update opaque counts */
1995 end_offset = xb_offset(&xb);
1996 error = xb_seek(&xb, argslength_offset);
1997 xb_add_32(error, &xb, end_offset - argslength_offset + XDRWORD /*version*/);
1998 nfsmout_if(error);
1999 error = xb_seek(&xb, attrslength_offset);
2000 xb_add_32(error, &xb, end_offset - attrslength_offset - XDRWORD /*don't include length field*/);
2001
2002 if (!error) {
2003 /* grab the assembled buffer */
2004 *xdrbufp = xb_buffer_base(&xb);
2005 xb.xb_flags &= ~XB_CLEANUP;
2006 }
2007 nfsmout:
2008 xb_cleanup(&xb);
2009 FREE_ZONE(mntfrom, MAXPATHLEN, M_NAMEI);
2010 return error;
2011 }
2012
2013 /*
2014 * VFS Operations.
2015 *
2016 * mount system call
2017 */
2018 int
2019 nfs_vfs_mount(mount_t mp, vnode_t vp, user_addr_t data, vfs_context_t ctx)
2020 {
2021 int error = 0, inkernel = vfs_iskernelmount(mp);
2022 uint32_t argsversion, argslength;
2023 char *xdrbuf = NULL;
2024
2025 /* read in version */
2026 if (inkernel) {
2027 bcopy(CAST_DOWN(void *, data), &argsversion, sizeof(argsversion));
2028 } else if ((error = copyin(data, &argsversion, sizeof(argsversion)))) {
2029 return error;
2030 }
2031
2032 /* If we have XDR args, then all values in the buffer are in network order */
2033 if (argsversion == htonl(NFS_ARGSVERSION_XDR)) {
2034 argsversion = NFS_ARGSVERSION_XDR;
2035 }
2036
2037 switch (argsversion) {
2038 case 3:
2039 case 4:
2040 case 5:
2041 case 6:
2042 /* convert old-style args to xdr */
2043 error = nfs_convert_old_nfs_args(mp, data, ctx, argsversion, inkernel, &xdrbuf);
2044 break;
2045 case NFS_ARGSVERSION_XDR:
2046 /* copy in xdr buffer */
2047 if (inkernel) {
2048 bcopy(CAST_DOWN(void *, (data + XDRWORD)), &argslength, XDRWORD);
2049 } else {
2050 error = copyin((data + XDRWORD), &argslength, XDRWORD);
2051 }
2052 if (error) {
2053 break;
2054 }
2055 argslength = ntohl(argslength);
2056 /* put a reasonable limit on the size of the XDR args */
2057 if (argslength > 16 * 1024) {
2058 error = E2BIG;
2059 break;
2060 }
2061 /* allocate xdr buffer */
2062 xdrbuf = xb_malloc(xdr_rndup(argslength));
2063 if (!xdrbuf) {
2064 error = ENOMEM;
2065 break;
2066 }
2067 if (inkernel) {
2068 bcopy(CAST_DOWN(void *, data), xdrbuf, argslength);
2069 } else {
2070 error = copyin(data, xdrbuf, argslength);
2071 }
2072 break;
2073 default:
2074 error = EPROGMISMATCH;
2075 }
2076
2077 if (error) {
2078 if (xdrbuf) {
2079 xb_free(xdrbuf);
2080 }
2081 return error;
2082 }
2083 error = mountnfs(xdrbuf, mp, ctx, &vp);
2084 return error;
2085 }
2086
2087 /*
2088 * Common code for mount and mountroot
2089 */
2090
2091 /* Set up an NFSv2/v3 mount */
2092 int
2093 nfs3_mount(
2094 struct nfsmount *nmp,
2095 vfs_context_t ctx,
2096 nfsnode_t *npp)
2097 {
2098 int error = 0;
2099 struct nfs_vattr nvattr;
2100 u_int64_t xid;
2101
2102 *npp = NULL;
2103
2104 if (!nmp->nm_fh) {
2105 return EINVAL;
2106 }
2107
2108 /*
2109 * Get file attributes for the mountpoint. These are needed
2110 * in order to properly create the root vnode.
2111 */
2112 error = nfs3_getattr_rpc(NULL, nmp->nm_mountp, nmp->nm_fh->fh_data, nmp->nm_fh->fh_len, 0,
2113 ctx, &nvattr, &xid);
2114 if (error) {
2115 goto out;
2116 }
2117
2118 error = nfs_nget(nmp->nm_mountp, NULL, NULL, nmp->nm_fh->fh_data, nmp->nm_fh->fh_len,
2119 &nvattr, &xid, RPCAUTH_UNKNOWN, NG_MARKROOT, npp);
2120 if (*npp) {
2121 nfs_node_unlock(*npp);
2122 }
2123 if (error) {
2124 goto out;
2125 }
2126
2127 /*
2128 * Try to make sure we have all the general info from the server.
2129 */
2130 if (nmp->nm_vers == NFS_VER2) {
2131 NFS_BITMAP_SET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_MAXNAME);
2132 nmp->nm_fsattr.nfsa_maxname = NFS_MAXNAMLEN;
2133 } else if (nmp->nm_vers == NFS_VER3) {
2134 /* get the NFSv3 FSINFO */
2135 error = nfs3_fsinfo(nmp, *npp, ctx);
2136 if (error) {
2137 goto out;
2138 }
2139 /* If the server indicates all pathconf info is */
2140 /* the same, grab a copy of that info now */
2141 if (NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_HOMOGENEOUS) &&
2142 (nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_HOMOGENEOUS)) {
2143 struct nfs_fsattr nfsa;
2144 if (!nfs3_pathconf_rpc(*npp, &nfsa, ctx)) {
2145 /* cache a copy of the results */
2146 lck_mtx_lock(&nmp->nm_lock);
2147 nfs3_pathconf_cache(nmp, &nfsa);
2148 lck_mtx_unlock(&nmp->nm_lock);
2149 }
2150 }
2151 }
2152 out:
2153 if (*npp && error) {
2154 vnode_put(NFSTOV(*npp));
2155 vnode_recycle(NFSTOV(*npp));
2156 *npp = NULL;
2157 }
2158 return error;
2159 }
2160
2161 /*
2162 * Update an NFSv4 mount path with the contents of the symlink.
2163 *
2164 * Read the link for the given file handle.
2165 * Insert the link's components into the path.
2166 */
2167 int
2168 nfs4_mount_update_path_with_symlink(struct nfsmount *nmp, struct nfs_fs_path *nfsp, uint32_t curcomp, fhandle_t *dirfhp, int *depthp, fhandle_t *fhp, vfs_context_t ctx)
2169 {
2170 int error = 0, status, numops;
2171 uint32_t len = 0, comp, newcomp, linkcompcount;
2172 u_int64_t xid;
2173 struct nfsm_chain nmreq, nmrep;
2174 struct nfsreq rq, *req = &rq;
2175 struct nfsreq_secinfo_args si;
2176 char *link = NULL, *p, *q, ch;
2177 struct nfs_fs_path nfsp2;
2178
2179 bzero(&nfsp2, sizeof(nfsp2));
2180 if (dirfhp->fh_len) {
2181 NFSREQ_SECINFO_SET(&si, NULL, dirfhp->fh_data, dirfhp->fh_len, nfsp->np_components[curcomp], 0);
2182 } else {
2183 NFSREQ_SECINFO_SET(&si, NULL, NULL, 0, nfsp->np_components[curcomp], 0);
2184 }
2185 nfsm_chain_null(&nmreq);
2186 nfsm_chain_null(&nmrep);
2187
2188 MALLOC_ZONE(link, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
2189 if (!link) {
2190 error = ENOMEM;
2191 }
2192
2193 // PUTFH, READLINK
2194 numops = 2;
2195 nfsm_chain_build_alloc_init(error, &nmreq, 12 * NFSX_UNSIGNED);
2196 nfsm_chain_add_compound_header(error, &nmreq, "readlink", nmp->nm_minor_vers, numops);
2197 numops--;
2198 nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH);
2199 nfsm_chain_add_fh(error, &nmreq, NFS_VER4, fhp->fh_data, fhp->fh_len);
2200 numops--;
2201 nfsm_chain_add_32(error, &nmreq, NFS_OP_READLINK);
2202 nfsm_chain_build_done(error, &nmreq);
2203 nfsm_assert(error, (numops == 0), EPROTO);
2204 nfsmout_if(error);
2205
2206 error = nfs_request_async(NULL, nmp->nm_mountp, &nmreq, NFSPROC4_COMPOUND,
2207 vfs_context_thread(ctx), vfs_context_ucred(ctx), &si, 0, NULL, &req);
2208 if (!error) {
2209 error = nfs_request_async_finish(req, &nmrep, &xid, &status);
2210 }
2211
2212 nfsm_chain_skip_tag(error, &nmrep);
2213 nfsm_chain_get_32(error, &nmrep, numops);
2214 nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
2215 nfsm_chain_op_check(error, &nmrep, NFS_OP_READLINK);
2216 nfsm_chain_get_32(error, &nmrep, len);
2217 nfsmout_if(error);
2218 if (len == 0) {
2219 error = ENOENT;
2220 } else if (len >= MAXPATHLEN) {
2221 len = MAXPATHLEN - 1;
2222 }
2223 nfsm_chain_get_opaque(error, &nmrep, len, link);
2224 nfsmout_if(error);
2225 /* make sure link string is terminated properly */
2226 link[len] = '\0';
2227
2228 /* count the number of components in link */
2229 p = link;
2230 while (*p && (*p == '/')) {
2231 p++;
2232 }
2233 linkcompcount = 0;
2234 while (*p) {
2235 linkcompcount++;
2236 while (*p && (*p != '/')) {
2237 p++;
2238 }
2239 while (*p && (*p == '/')) {
2240 p++;
2241 }
2242 }
2243
2244 /* free up used components */
2245 for (comp = 0; comp <= curcomp; comp++) {
2246 if (nfsp->np_components[comp]) {
2247 FREE(nfsp->np_components[comp], M_TEMP);
2248 nfsp->np_components[comp] = NULL;
2249 }
2250 }
2251
2252 /* set up new path */
2253 nfsp2.np_compcount = nfsp->np_compcount - curcomp - 1 + linkcompcount;
2254 MALLOC(nfsp2.np_components, char **, nfsp2.np_compcount * sizeof(char*), M_TEMP, M_WAITOK | M_ZERO);
2255 if (!nfsp2.np_components) {
2256 error = ENOMEM;
2257 goto nfsmout;
2258 }
2259
2260 /* add link components */
2261 p = link;
2262 while (*p && (*p == '/')) {
2263 p++;
2264 }
2265 for (newcomp = 0; newcomp < linkcompcount; newcomp++) {
2266 /* find end of component */
2267 q = p;
2268 while (*q && (*q != '/')) {
2269 q++;
2270 }
2271 MALLOC(nfsp2.np_components[newcomp], char *, q - p + 1, M_TEMP, M_WAITOK | M_ZERO);
2272 if (!nfsp2.np_components[newcomp]) {
2273 error = ENOMEM;
2274 break;
2275 }
2276 ch = *q;
2277 *q = '\0';
2278 strlcpy(nfsp2.np_components[newcomp], p, q - p + 1);
2279 *q = ch;
2280 p = q;
2281 while (*p && (*p == '/')) {
2282 p++;
2283 }
2284 }
2285 nfsmout_if(error);
2286
2287 /* add remaining components */
2288 for (comp = curcomp + 1; comp < nfsp->np_compcount; comp++, newcomp++) {
2289 nfsp2.np_components[newcomp] = nfsp->np_components[comp];
2290 nfsp->np_components[comp] = NULL;
2291 }
2292
2293 /* move new path into place */
2294 FREE(nfsp->np_components, M_TEMP);
2295 nfsp->np_components = nfsp2.np_components;
2296 nfsp->np_compcount = nfsp2.np_compcount;
2297 nfsp2.np_components = NULL;
2298
2299 /* for absolute link, let the caller now that the next dirfh is root */
2300 if (link[0] == '/') {
2301 dirfhp->fh_len = 0;
2302 *depthp = 0;
2303 }
2304 nfsmout:
2305 if (link) {
2306 FREE_ZONE(link, MAXPATHLEN, M_NAMEI);
2307 }
2308 if (nfsp2.np_components) {
2309 for (comp = 0; comp < nfsp2.np_compcount; comp++) {
2310 if (nfsp2.np_components[comp]) {
2311 FREE(nfsp2.np_components[comp], M_TEMP);
2312 }
2313 }
2314 FREE(nfsp2.np_components, M_TEMP);
2315 }
2316 nfsm_chain_cleanup(&nmreq);
2317 nfsm_chain_cleanup(&nmrep);
2318 return error;
2319 }
2320
2321 /* Set up an NFSv4 mount */
2322 int
2323 nfs4_mount(
2324 struct nfsmount *nmp,
2325 vfs_context_t ctx,
2326 nfsnode_t *npp)
2327 {
2328 struct nfsm_chain nmreq, nmrep;
2329 int error = 0, numops, status, interval, isdotdot, loopcnt = 0, depth = 0;
2330 struct nfs_fs_path fspath, *nfsp, fspath2;
2331 uint32_t bitmap[NFS_ATTR_BITMAP_LEN], comp, comp2;
2332 fhandle_t fh, dirfh;
2333 struct nfs_vattr nvattr;
2334 u_int64_t xid;
2335 struct nfsreq rq, *req = &rq;
2336 struct nfsreq_secinfo_args si;
2337 struct nfs_sec sec;
2338 struct nfs_fs_locations nfsls;
2339
2340 *npp = NULL;
2341 fh.fh_len = dirfh.fh_len = 0;
2342 TAILQ_INIT(&nmp->nm_open_owners);
2343 TAILQ_INIT(&nmp->nm_delegations);
2344 TAILQ_INIT(&nmp->nm_dreturnq);
2345 nmp->nm_stategenid = 1;
2346 NVATTR_INIT(&nvattr);
2347 bzero(&nfsls, sizeof(nfsls));
2348 nfsm_chain_null(&nmreq);
2349 nfsm_chain_null(&nmrep);
2350
2351 /*
2352 * If no security flavors were specified we'll want to default to the server's
2353 * preferred flavor. For NFSv4.0 we need a file handle and name to get that via
2354 * SECINFO, so we'll do that on the last component of the server path we are
2355 * mounting. If we are mounting the server's root, we'll need to defer the
2356 * SECINFO call to the first successful LOOKUP request.
2357 */
2358 if (!nmp->nm_sec.count) {
2359 nmp->nm_state |= NFSSTA_NEEDSECINFO;
2360 }
2361
2362 /* make a copy of the current location's path */
2363 nfsp = &nmp->nm_locations.nl_locations[nmp->nm_locations.nl_current.nli_loc]->nl_path;
2364 bzero(&fspath, sizeof(fspath));
2365 fspath.np_compcount = nfsp->np_compcount;
2366 if (fspath.np_compcount > 0) {
2367 MALLOC(fspath.np_components, char **, fspath.np_compcount * sizeof(char*), M_TEMP, M_WAITOK | M_ZERO);
2368 if (!fspath.np_components) {
2369 error = ENOMEM;
2370 goto nfsmout;
2371 }
2372 for (comp = 0; comp < nfsp->np_compcount; comp++) {
2373 int slen = strlen(nfsp->np_components[comp]);
2374 MALLOC(fspath.np_components[comp], char *, slen + 1, M_TEMP, M_WAITOK | M_ZERO);
2375 if (!fspath.np_components[comp]) {
2376 error = ENOMEM;
2377 break;
2378 }
2379 strlcpy(fspath.np_components[comp], nfsp->np_components[comp], slen + 1);
2380 }
2381 if (error) {
2382 goto nfsmout;
2383 }
2384 }
2385
2386 /* for mirror mounts, we can just use the file handle passed in */
2387 if (nmp->nm_fh) {
2388 dirfh.fh_len = nmp->nm_fh->fh_len;
2389 bcopy(nmp->nm_fh->fh_data, dirfh.fh_data, dirfh.fh_len);
2390 NFSREQ_SECINFO_SET(&si, NULL, dirfh.fh_data, dirfh.fh_len, NULL, 0);
2391 goto gotfh;
2392 }
2393
2394 /* otherwise, we need to get the fh for the directory we are mounting */
2395
2396 /* if no components, just get root */
2397 if (fspath.np_compcount == 0) {
2398 nocomponents:
2399 // PUTROOTFH + GETATTR(FH)
2400 NFSREQ_SECINFO_SET(&si, NULL, NULL, 0, NULL, 0);
2401 numops = 2;
2402 nfsm_chain_build_alloc_init(error, &nmreq, 9 * NFSX_UNSIGNED);
2403 nfsm_chain_add_compound_header(error, &nmreq, "mount", nmp->nm_minor_vers, numops);
2404 numops--;
2405 nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTROOTFH);
2406 numops--;
2407 nfsm_chain_add_32(error, &nmreq, NFS_OP_GETATTR);
2408 NFS_CLEAR_ATTRIBUTES(bitmap);
2409 NFS4_DEFAULT_ATTRIBUTES(bitmap);
2410 NFS_BITMAP_SET(bitmap, NFS_FATTR_FILEHANDLE);
2411 nfsm_chain_add_bitmap(error, &nmreq, bitmap, NFS_ATTR_BITMAP_LEN);
2412 nfsm_chain_build_done(error, &nmreq);
2413 nfsm_assert(error, (numops == 0), EPROTO);
2414 nfsmout_if(error);
2415 error = nfs_request_async(NULL, nmp->nm_mountp, &nmreq, NFSPROC4_COMPOUND,
2416 vfs_context_thread(ctx), vfs_context_ucred(ctx), &si, 0, NULL, &req);
2417 if (!error) {
2418 error = nfs_request_async_finish(req, &nmrep, &xid, &status);
2419 }
2420 nfsm_chain_skip_tag(error, &nmrep);
2421 nfsm_chain_get_32(error, &nmrep, numops);
2422 nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTROOTFH);
2423 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
2424 nfsmout_if(error);
2425 NFS_CLEAR_ATTRIBUTES(nmp->nm_fsattr.nfsa_bitmap);
2426 error = nfs4_parsefattr(&nmrep, &nmp->nm_fsattr, &nvattr, &dirfh, NULL, NULL);
2427 if (!error && !NFS_BITMAP_ISSET(&nvattr.nva_bitmap, NFS_FATTR_FILEHANDLE)) {
2428 printf("nfs: mount didn't return filehandle?\n");
2429 error = EBADRPC;
2430 }
2431 nfsmout_if(error);
2432 nfsm_chain_cleanup(&nmrep);
2433 nfsm_chain_null(&nmreq);
2434 NVATTR_CLEANUP(&nvattr);
2435 goto gotfh;
2436 }
2437
2438 /* look up each path component */
2439 for (comp = 0; comp < fspath.np_compcount;) {
2440 isdotdot = 0;
2441 if (fspath.np_components[comp][0] == '.') {
2442 if (fspath.np_components[comp][1] == '\0') {
2443 /* skip "." */
2444 comp++;
2445 continue;
2446 }
2447 /* treat ".." specially */
2448 if ((fspath.np_components[comp][1] == '.') &&
2449 (fspath.np_components[comp][2] == '\0')) {
2450 isdotdot = 1;
2451 }
2452 if (isdotdot && (dirfh.fh_len == 0)) {
2453 /* ".." in root directory is same as "." */
2454 comp++;
2455 continue;
2456 }
2457 }
2458 // PUT(ROOT)FH + LOOKUP(P) + GETFH + GETATTR
2459 if (dirfh.fh_len == 0) {
2460 NFSREQ_SECINFO_SET(&si, NULL, NULL, 0, isdotdot ? NULL : fspath.np_components[comp], 0);
2461 } else {
2462 NFSREQ_SECINFO_SET(&si, NULL, dirfh.fh_data, dirfh.fh_len, isdotdot ? NULL : fspath.np_components[comp], 0);
2463 }
2464 numops = 4;
2465 nfsm_chain_build_alloc_init(error, &nmreq, 18 * NFSX_UNSIGNED);
2466 nfsm_chain_add_compound_header(error, &nmreq, "mount", nmp->nm_minor_vers, numops);
2467 numops--;
2468 if (dirfh.fh_len) {
2469 nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH);
2470 nfsm_chain_add_fh(error, &nmreq, NFS_VER4, dirfh.fh_data, dirfh.fh_len);
2471 } else {
2472 nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTROOTFH);
2473 }
2474 numops--;
2475 if (isdotdot) {
2476 nfsm_chain_add_32(error, &nmreq, NFS_OP_LOOKUPP);
2477 } else {
2478 nfsm_chain_add_32(error, &nmreq, NFS_OP_LOOKUP);
2479 nfsm_chain_add_name(error, &nmreq,
2480 fspath.np_components[comp], strlen(fspath.np_components[comp]), nmp);
2481 }
2482 numops--;
2483 nfsm_chain_add_32(error, &nmreq, NFS_OP_GETFH);
2484 numops--;
2485 nfsm_chain_add_32(error, &nmreq, NFS_OP_GETATTR);
2486 NFS_CLEAR_ATTRIBUTES(bitmap);
2487 NFS4_DEFAULT_ATTRIBUTES(bitmap);
2488 /* if no namedattr support or component is ".zfs", clear NFS_FATTR_NAMED_ATTR */
2489 if (!NMFLAG(nmp, NAMEDATTR) || !strcmp(fspath.np_components[comp], ".zfs")) {
2490 NFS_BITMAP_CLR(bitmap, NFS_FATTR_NAMED_ATTR);
2491 }
2492 nfsm_chain_add_bitmap(error, &nmreq, bitmap, NFS_ATTR_BITMAP_LEN);
2493 nfsm_chain_build_done(error, &nmreq);
2494 nfsm_assert(error, (numops == 0), EPROTO);
2495 nfsmout_if(error);
2496 error = nfs_request_async(NULL, nmp->nm_mountp, &nmreq, NFSPROC4_COMPOUND,
2497 vfs_context_thread(ctx), vfs_context_ucred(ctx), &si, 0, NULL, &req);
2498 if (!error) {
2499 error = nfs_request_async_finish(req, &nmrep, &xid, &status);
2500 }
2501 nfsm_chain_skip_tag(error, &nmrep);
2502 nfsm_chain_get_32(error, &nmrep, numops);
2503 nfsm_chain_op_check(error, &nmrep, dirfh.fh_len ? NFS_OP_PUTFH : NFS_OP_PUTROOTFH);
2504 nfsm_chain_op_check(error, &nmrep, isdotdot ? NFS_OP_LOOKUPP : NFS_OP_LOOKUP);
2505 nfsmout_if(error);
2506 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETFH);
2507 nfsm_chain_get_32(error, &nmrep, fh.fh_len);
2508 if (fh.fh_len > sizeof(fh.fh_data)) {
2509 error = EBADRPC;
2510 }
2511 nfsmout_if(error);
2512 nfsm_chain_get_opaque(error, &nmrep, fh.fh_len, fh.fh_data);
2513 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
2514 if (!error) {
2515 NFS_CLEAR_ATTRIBUTES(nmp->nm_fsattr.nfsa_bitmap);
2516 error = nfs4_parsefattr(&nmrep, &nmp->nm_fsattr, &nvattr, NULL, NULL, &nfsls);
2517 }
2518 nfsm_chain_cleanup(&nmrep);
2519 nfsm_chain_null(&nmreq);
2520 if (error) {
2521 /* LOOKUP succeeded but GETATTR failed? This could be a referral. */
2522 /* Try the lookup again with a getattr for fs_locations. */
2523 nfs_fs_locations_cleanup(&nfsls);
2524 error = nfs4_get_fs_locations(nmp, NULL, dirfh.fh_data, dirfh.fh_len, fspath.np_components[comp], ctx, &nfsls);
2525 if (!error && (nfsls.nl_numlocs < 1)) {
2526 error = ENOENT;
2527 }
2528 nfsmout_if(error);
2529 if (++loopcnt > MAXSYMLINKS) {
2530 /* too many symlink/referral redirections */
2531 error = ELOOP;
2532 goto nfsmout;
2533 }
2534 /* tear down the current connection */
2535 nfs_disconnect(nmp);
2536 /* replace fs locations */
2537 nfs_fs_locations_cleanup(&nmp->nm_locations);
2538 nmp->nm_locations = nfsls;
2539 bzero(&nfsls, sizeof(nfsls));
2540 /* initiate a connection using the new fs locations */
2541 error = nfs_mount_connect(nmp);
2542 if (!error && !(nmp->nm_locations.nl_current.nli_flags & NLI_VALID)) {
2543 error = EIO;
2544 }
2545 nfsmout_if(error);
2546 /* add new server's remote path to beginning of our path and continue */
2547 nfsp = &nmp->nm_locations.nl_locations[nmp->nm_locations.nl_current.nli_loc]->nl_path;
2548 bzero(&fspath2, sizeof(fspath2));
2549 fspath2.np_compcount = (fspath.np_compcount - comp - 1) + nfsp->np_compcount;
2550 if (fspath2.np_compcount > 0) {
2551 MALLOC(fspath2.np_components, char **, fspath2.np_compcount * sizeof(char*), M_TEMP, M_WAITOK | M_ZERO);
2552 if (!fspath2.np_components) {
2553 error = ENOMEM;
2554 goto nfsmout;
2555 }
2556 for (comp2 = 0; comp2 < nfsp->np_compcount; comp2++) {
2557 int slen = strlen(nfsp->np_components[comp2]);
2558 MALLOC(fspath2.np_components[comp2], char *, slen + 1, M_TEMP, M_WAITOK | M_ZERO);
2559 if (!fspath2.np_components[comp2]) {
2560 /* clean up fspath2, then error out */
2561 while (comp2 > 0) {
2562 comp2--;
2563 FREE(fspath2.np_components[comp2], M_TEMP);
2564 }
2565 FREE(fspath2.np_components, M_TEMP);
2566 error = ENOMEM;
2567 goto nfsmout;
2568 }
2569 strlcpy(fspath2.np_components[comp2], nfsp->np_components[comp2], slen + 1);
2570 }
2571 if ((fspath.np_compcount - comp - 1) > 0) {
2572 bcopy(&fspath.np_components[comp + 1], &fspath2.np_components[nfsp->np_compcount], (fspath.np_compcount - comp - 1) * sizeof(char*));
2573 }
2574 /* free up unused parts of old path (prior components and component array) */
2575 do {
2576 FREE(fspath.np_components[comp], M_TEMP);
2577 } while (comp-- > 0);
2578 FREE(fspath.np_components, M_TEMP);
2579 /* put new path in place */
2580 fspath = fspath2;
2581 }
2582 /* reset dirfh and component index */
2583 dirfh.fh_len = 0;
2584 comp = 0;
2585 NVATTR_CLEANUP(&nvattr);
2586 if (fspath.np_compcount == 0) {
2587 goto nocomponents;
2588 }
2589 continue;
2590 }
2591 nfsmout_if(error);
2592 /* if file handle is for a symlink, then update the path with the symlink contents */
2593 if (NFS_BITMAP_ISSET(&nvattr.nva_bitmap, NFS_FATTR_TYPE) && (nvattr.nva_type == VLNK)) {
2594 if (++loopcnt > MAXSYMLINKS) {
2595 error = ELOOP;
2596 } else {
2597 error = nfs4_mount_update_path_with_symlink(nmp, &fspath, comp, &dirfh, &depth, &fh, ctx);
2598 }
2599 nfsmout_if(error);
2600 /* directory file handle is either left the same or reset to root (if link was absolute) */
2601 /* path traversal starts at beginning of the path again */
2602 comp = 0;
2603 NVATTR_CLEANUP(&nvattr);
2604 nfs_fs_locations_cleanup(&nfsls);
2605 continue;
2606 }
2607 NVATTR_CLEANUP(&nvattr);
2608 nfs_fs_locations_cleanup(&nfsls);
2609 /* not a symlink... */
2610 if ((nmp->nm_state & NFSSTA_NEEDSECINFO) && (comp == (fspath.np_compcount - 1)) && !isdotdot) {
2611 /* need to get SECINFO for the directory being mounted */
2612 if (dirfh.fh_len == 0) {
2613 NFSREQ_SECINFO_SET(&si, NULL, NULL, 0, isdotdot ? NULL : fspath.np_components[comp], 0);
2614 } else {
2615 NFSREQ_SECINFO_SET(&si, NULL, dirfh.fh_data, dirfh.fh_len, isdotdot ? NULL : fspath.np_components[comp], 0);
2616 }
2617 sec.count = NX_MAX_SEC_FLAVORS;
2618 error = nfs4_secinfo_rpc(nmp, &si, vfs_context_ucred(ctx), sec.flavors, &sec.count);
2619 /* [sigh] some implementations return "illegal" error for unsupported ops */
2620 if (error == NFSERR_OP_ILLEGAL) {
2621 error = 0;
2622 }
2623 nfsmout_if(error);
2624 /* set our default security flavor to the first in the list */
2625 if (sec.count) {
2626 nmp->nm_auth = sec.flavors[0];
2627 }
2628 nmp->nm_state &= ~NFSSTA_NEEDSECINFO;
2629 }
2630 /* advance directory file handle, component index, & update depth */
2631 dirfh = fh;
2632 comp++;
2633 if (!isdotdot) { /* going down the hierarchy */
2634 depth++;
2635 } else if (--depth <= 0) { /* going up the hierarchy */
2636 dirfh.fh_len = 0; /* clear dirfh when we hit root */
2637 }
2638 }
2639
2640 gotfh:
2641 /* get attrs for mount point root */
2642 numops = NMFLAG(nmp, NAMEDATTR) ? 3 : 2; // PUTFH + GETATTR + OPENATTR
2643 nfsm_chain_build_alloc_init(error, &nmreq, 25 * NFSX_UNSIGNED);
2644 nfsm_chain_add_compound_header(error, &nmreq, "mount", nmp->nm_minor_vers, numops);
2645 numops--;
2646 nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH);
2647 nfsm_chain_add_fh(error, &nmreq, NFS_VER4, dirfh.fh_data, dirfh.fh_len);
2648 numops--;
2649 nfsm_chain_add_32(error, &nmreq, NFS_OP_GETATTR);
2650 NFS_CLEAR_ATTRIBUTES(bitmap);
2651 NFS4_DEFAULT_ATTRIBUTES(bitmap);
2652 /* if no namedattr support or last component is ".zfs", clear NFS_FATTR_NAMED_ATTR */
2653 if (!NMFLAG(nmp, NAMEDATTR) || ((fspath.np_compcount > 0) && !strcmp(fspath.np_components[fspath.np_compcount - 1], ".zfs"))) {
2654 NFS_BITMAP_CLR(bitmap, NFS_FATTR_NAMED_ATTR);
2655 }
2656 nfsm_chain_add_bitmap(error, &nmreq, bitmap, NFS_ATTR_BITMAP_LEN);
2657 if (NMFLAG(nmp, NAMEDATTR)) {
2658 numops--;
2659 nfsm_chain_add_32(error, &nmreq, NFS_OP_OPENATTR);
2660 nfsm_chain_add_32(error, &nmreq, 0);
2661 }
2662 nfsm_chain_build_done(error, &nmreq);
2663 nfsm_assert(error, (numops == 0), EPROTO);
2664 nfsmout_if(error);
2665 error = nfs_request_async(NULL, nmp->nm_mountp, &nmreq, NFSPROC4_COMPOUND,
2666 vfs_context_thread(ctx), vfs_context_ucred(ctx), &si, 0, NULL, &req);
2667 if (!error) {
2668 error = nfs_request_async_finish(req, &nmrep, &xid, &status);
2669 }
2670 nfsm_chain_skip_tag(error, &nmrep);
2671 nfsm_chain_get_32(error, &nmrep, numops);
2672 nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
2673 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
2674 nfsmout_if(error);
2675 NFS_CLEAR_ATTRIBUTES(nmp->nm_fsattr.nfsa_bitmap);
2676 error = nfs4_parsefattr(&nmrep, &nmp->nm_fsattr, &nvattr, NULL, NULL, NULL);
2677 nfsmout_if(error);
2678 if (NMFLAG(nmp, NAMEDATTR)) {
2679 nfsm_chain_op_check(error, &nmrep, NFS_OP_OPENATTR);
2680 if (error == ENOENT) {
2681 error = 0;
2682 }
2683 /* [sigh] some implementations return "illegal" error for unsupported ops */
2684 if (error || !NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_supp_attr, NFS_FATTR_NAMED_ATTR)) {
2685 nmp->nm_fsattr.nfsa_flags &= ~NFS_FSFLAG_NAMED_ATTR;
2686 } else {
2687 nmp->nm_fsattr.nfsa_flags |= NFS_FSFLAG_NAMED_ATTR;
2688 }
2689 } else {
2690 nmp->nm_fsattr.nfsa_flags &= ~NFS_FSFLAG_NAMED_ATTR;
2691 }
2692 if (NMFLAG(nmp, NOACL)) { /* make sure ACL support is turned off */
2693 nmp->nm_fsattr.nfsa_flags &= ~NFS_FSFLAG_ACL;
2694 }
2695 if (NMFLAG(nmp, ACLONLY) && !(nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_ACL)) {
2696 NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_ACLONLY);
2697 }
2698 if (NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_supp_attr, NFS_FATTR_FH_EXPIRE_TYPE)) {
2699 uint32_t fhtype = ((nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_FHTYPE_MASK) >> NFS_FSFLAG_FHTYPE_SHIFT);
2700 if (fhtype != NFS_FH_PERSISTENT) {
2701 printf("nfs: warning: non-persistent file handles! for %s\n", vfs_statfs(nmp->nm_mountp)->f_mntfromname);
2702 }
2703 }
2704
2705 /* make sure it's a directory */
2706 if (!NFS_BITMAP_ISSET(&nvattr.nva_bitmap, NFS_FATTR_TYPE) || (nvattr.nva_type != VDIR)) {
2707 error = ENOTDIR;
2708 goto nfsmout;
2709 }
2710
2711 /* save the NFS fsid */
2712 nmp->nm_fsid = nvattr.nva_fsid;
2713
2714 /* create the root node */
2715 error = nfs_nget(nmp->nm_mountp, NULL, NULL, dirfh.fh_data, dirfh.fh_len, &nvattr, &xid, rq.r_auth, NG_MARKROOT, npp);
2716 nfsmout_if(error);
2717
2718 if (nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_ACL) {
2719 vfs_setextendedsecurity(nmp->nm_mountp);
2720 }
2721
2722 /* adjust I/O sizes to server limits */
2723 if (NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_MAXREAD) && (nmp->nm_fsattr.nfsa_maxread > 0)) {
2724 if (nmp->nm_fsattr.nfsa_maxread < (uint64_t)nmp->nm_rsize) {
2725 nmp->nm_rsize = nmp->nm_fsattr.nfsa_maxread & ~(NFS_FABLKSIZE - 1);
2726 if (nmp->nm_rsize == 0) {
2727 nmp->nm_rsize = nmp->nm_fsattr.nfsa_maxread;
2728 }
2729 }
2730 }
2731 if (NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_MAXWRITE) && (nmp->nm_fsattr.nfsa_maxwrite > 0)) {
2732 if (nmp->nm_fsattr.nfsa_maxwrite < (uint64_t)nmp->nm_wsize) {
2733 nmp->nm_wsize = nmp->nm_fsattr.nfsa_maxwrite & ~(NFS_FABLKSIZE - 1);
2734 if (nmp->nm_wsize == 0) {
2735 nmp->nm_wsize = nmp->nm_fsattr.nfsa_maxwrite;
2736 }
2737 }
2738 }
2739
2740 /* set up lease renew timer */
2741 nmp->nm_renew_timer = thread_call_allocate(nfs4_renew_timer, nmp);
2742 interval = nmp->nm_fsattr.nfsa_lease / 2;
2743 if (interval < 1) {
2744 interval = 1;
2745 }
2746 nfs_interval_timer_start(nmp->nm_renew_timer, interval * 1000);
2747
2748 nfsmout:
2749 if (fspath.np_components) {
2750 for (comp = 0; comp < fspath.np_compcount; comp++) {
2751 if (fspath.np_components[comp]) {
2752 FREE(fspath.np_components[comp], M_TEMP);
2753 }
2754 }
2755 FREE(fspath.np_components, M_TEMP);
2756 }
2757 NVATTR_CLEANUP(&nvattr);
2758 nfs_fs_locations_cleanup(&nfsls);
2759 if (*npp) {
2760 nfs_node_unlock(*npp);
2761 }
2762 nfsm_chain_cleanup(&nmreq);
2763 nfsm_chain_cleanup(&nmrep);
2764 return error;
2765 }
2766
2767 /*
2768 * Thread to handle initial NFS mount connection.
2769 */
2770 void
2771 nfs_mount_connect_thread(void *arg, __unused wait_result_t wr)
2772 {
2773 struct nfsmount *nmp = arg;
2774 int error = 0, savederror = 0, slpflag = (NMFLAG(nmp, INTR) ? PCATCH : 0);
2775 int done = 0, timeo, tries, maxtries;
2776
2777 if (NM_OMFLAG(nmp, MNTQUICK)) {
2778 timeo = 8;
2779 maxtries = 1;
2780 } else {
2781 timeo = 30;
2782 maxtries = 2;
2783 }
2784
2785 for (tries = 0; tries < maxtries; tries++) {
2786 error = nfs_connect(nmp, 1, timeo);
2787 switch (error) {
2788 case ETIMEDOUT:
2789 case EAGAIN:
2790 case EPIPE:
2791 case EADDRNOTAVAIL:
2792 case ENETDOWN:
2793 case ENETUNREACH:
2794 case ENETRESET:
2795 case ECONNABORTED:
2796 case ECONNRESET:
2797 case EISCONN:
2798 case ENOTCONN:
2799 case ESHUTDOWN:
2800 case ECONNREFUSED:
2801 case EHOSTDOWN:
2802 case EHOSTUNREACH:
2803 /* just keep retrying on any of these errors */
2804 break;
2805 case 0:
2806 default:
2807 /* looks like we got an answer... */
2808 done = 1;
2809 break;
2810 }
2811
2812 /* save the best error */
2813 if (nfs_connect_error_class(error) >= nfs_connect_error_class(savederror)) {
2814 savederror = error;
2815 }
2816 if (done) {
2817 error = savederror;
2818 break;
2819 }
2820
2821 /* pause before next attempt */
2822 if ((error = nfs_sigintr(nmp, NULL, current_thread(), 0))) {
2823 break;
2824 }
2825 error = tsleep(nmp, PSOCK | slpflag, "nfs_mount_connect_retry", 2 * hz);
2826 if (error && (error != EWOULDBLOCK)) {
2827 break;
2828 }
2829 error = savederror;
2830 }
2831
2832 /* update status of mount connect */
2833 lck_mtx_lock(&nmp->nm_lock);
2834 if (!nmp->nm_mounterror) {
2835 nmp->nm_mounterror = error;
2836 }
2837 nmp->nm_state &= ~NFSSTA_MOUNT_THREAD;
2838 lck_mtx_unlock(&nmp->nm_lock);
2839 wakeup(&nmp->nm_nss);
2840 }
2841
2842 int
2843 nfs_mount_connect(struct nfsmount *nmp)
2844 {
2845 int error = 0, slpflag;
2846 thread_t thd;
2847 struct timespec ts = { 2, 0 };
2848
2849 /*
2850 * Set up the socket. Perform initial search for a location/server/address to
2851 * connect to and negotiate any unspecified mount parameters. This work is
2852 * done on a kernel thread to satisfy reserved port usage needs.
2853 */
2854 slpflag = NMFLAG(nmp, INTR) ? PCATCH : 0;
2855 lck_mtx_lock(&nmp->nm_lock);
2856 /* set flag that the thread is running */
2857 nmp->nm_state |= NFSSTA_MOUNT_THREAD;
2858 if (kernel_thread_start(nfs_mount_connect_thread, nmp, &thd) != KERN_SUCCESS) {
2859 nmp->nm_state &= ~NFSSTA_MOUNT_THREAD;
2860 nmp->nm_mounterror = EIO;
2861 printf("nfs mount %s start socket connect thread failed\n", vfs_statfs(nmp->nm_mountp)->f_mntfromname);
2862 } else {
2863 thread_deallocate(thd);
2864 }
2865
2866 /* wait until mount connect thread is finished/gone */
2867 while (nmp->nm_state & NFSSTA_MOUNT_THREAD) {
2868 error = msleep(&nmp->nm_nss, &nmp->nm_lock, slpflag | PSOCK, "nfsconnectthread", &ts);
2869 if ((error && (error != EWOULDBLOCK)) || ((error = nfs_sigintr(nmp, NULL, current_thread(), 1)))) {
2870 /* record error */
2871 if (!nmp->nm_mounterror) {
2872 nmp->nm_mounterror = error;
2873 }
2874 /* signal the thread that we are aborting */
2875 nmp->nm_sockflags |= NMSOCK_UNMOUNT;
2876 if (nmp->nm_nss) {
2877 wakeup(nmp->nm_nss);
2878 }
2879 /* and continue waiting on it to finish */
2880 slpflag = 0;
2881 }
2882 }
2883 lck_mtx_unlock(&nmp->nm_lock);
2884
2885 /* grab mount connect status */
2886 error = nmp->nm_mounterror;
2887
2888 return error;
2889 }
2890
2891 /* Table of maximum minor version for a given version */
2892 uint32_t maxminorverstab[] = {
2893 0, /* Version 0 (does not exist) */
2894 0, /* Version 1 (does not exist) */
2895 0, /* Version 2 */
2896 0, /* Version 3 */
2897 0, /* Version 4 */
2898 };
2899
2900 #define NFS_MAX_SUPPORTED_VERSION ((long)(sizeof (maxminorverstab) / sizeof (uint32_t) - 1))
2901 #define NFS_MAX_SUPPORTED_MINOR_VERSION(v) ((long)(maxminorverstab[(v)]))
2902
2903 #define DEFAULT_NFS_MIN_VERS VER2PVER(2, 0)
2904 #define DEFAULT_NFS_MAX_VERS VER2PVER(3, 0)
2905
2906 /*
2907 * Common code to mount an NFS file system.
2908 */
2909 int
2910 mountnfs(
2911 char *xdrbuf,
2912 mount_t mp,
2913 vfs_context_t ctx,
2914 vnode_t *vpp)
2915 {
2916 struct nfsmount *nmp;
2917 nfsnode_t np;
2918 int error = 0;
2919 struct vfsstatfs *sbp;
2920 struct xdrbuf xb;
2921 uint32_t i, val, maxio, iosize, len;
2922 uint32_t *mattrs;
2923 uint32_t *mflags_mask;
2924 uint32_t *mflags;
2925 uint32_t argslength, attrslength;
2926 struct nfs_location_index firstloc = { NLI_VALID, 0, 0, 0 };
2927 static const struct nfs_etype nfs_default_etypes = {
2928 .count = NFS_MAX_ETYPES,
2929 .selected = NFS_MAX_ETYPES,
2930 .etypes = { NFS_AES256_CTS_HMAC_SHA1_96,
2931 NFS_AES128_CTS_HMAC_SHA1_96,
2932 NFS_DES3_CBC_SHA1_KD}
2933 };
2934 /* make sure mbuf constants are set up */
2935 if (!nfs_mbuf_mhlen) {
2936 nfs_mbuf_init();
2937 }
2938
2939 if (vfs_flags(mp) & MNT_UPDATE) {
2940 nmp = VFSTONFS(mp);
2941 /* update paths, file handles, etc, here XXX */
2942 xb_free(xdrbuf);
2943 return 0;
2944 } else {
2945 /* allocate an NFS mount structure for this mount */
2946 MALLOC_ZONE(nmp, struct nfsmount *,
2947 sizeof(struct nfsmount), M_NFSMNT, M_WAITOK);
2948 if (!nmp) {
2949 xb_free(xdrbuf);
2950 return ENOMEM;
2951 }
2952 bzero((caddr_t)nmp, sizeof(struct nfsmount));
2953 lck_mtx_init(&nmp->nm_lock, nfs_mount_grp, LCK_ATTR_NULL);
2954 TAILQ_INIT(&nmp->nm_resendq);
2955 TAILQ_INIT(&nmp->nm_iodq);
2956 TAILQ_INIT(&nmp->nm_gsscl);
2957 LIST_INIT(&nmp->nm_monlist);
2958 vfs_setfsprivate(mp, nmp);
2959 vfs_getnewfsid(mp);
2960 nmp->nm_mountp = mp;
2961 vfs_setauthopaque(mp);
2962 /*
2963 * Disable cache_lookup_path for NFS. NFS lookup always needs
2964 * to be called to check if the directory attribute cache is
2965 * valid and possibly purge the directory before calling
2966 * cache_lookup.
2967 */
2968 vfs_setauthcache_ttl(mp, 0);
2969
2970 nfs_nhinit_finish();
2971
2972 nmp->nm_args = xdrbuf;
2973
2974 /* set up defaults */
2975 nmp->nm_ref = 0;
2976 nmp->nm_vers = 0;
2977 nmp->nm_min_vers = DEFAULT_NFS_MIN_VERS;
2978 nmp->nm_max_vers = DEFAULT_NFS_MAX_VERS;
2979 nmp->nm_timeo = NFS_TIMEO;
2980 nmp->nm_retry = NFS_RETRANS;
2981 nmp->nm_sotype = 0;
2982 nmp->nm_sofamily = 0;
2983 nmp->nm_nfsport = 0;
2984 nmp->nm_wsize = NFS_WSIZE;
2985 nmp->nm_rsize = NFS_RSIZE;
2986 nmp->nm_readdirsize = NFS_READDIRSIZE;
2987 nmp->nm_numgrps = NFS_MAXGRPS;
2988 nmp->nm_readahead = NFS_DEFRAHEAD;
2989 nmp->nm_tprintf_delay = nfs_tprintf_delay;
2990 if (nmp->nm_tprintf_delay < 0) {
2991 nmp->nm_tprintf_delay = 0;
2992 }
2993 nmp->nm_tprintf_initial_delay = nfs_tprintf_initial_delay;
2994 if (nmp->nm_tprintf_initial_delay < 0) {
2995 nmp->nm_tprintf_initial_delay = 0;
2996 }
2997 nmp->nm_acregmin = NFS_MINATTRTIMO;
2998 nmp->nm_acregmax = NFS_MAXATTRTIMO;
2999 nmp->nm_acdirmin = NFS_MINDIRATTRTIMO;
3000 nmp->nm_acdirmax = NFS_MAXDIRATTRTIMO;
3001 nmp->nm_etype = nfs_default_etypes;
3002 nmp->nm_auth = RPCAUTH_SYS;
3003 nmp->nm_iodlink.tqe_next = NFSNOLIST;
3004 nmp->nm_deadtimeout = 0;
3005 nmp->nm_curdeadtimeout = 0;
3006 NFS_BITMAP_SET(nmp->nm_flags, NFS_MFLAG_NOACL);
3007 nmp->nm_realm = NULL;
3008 nmp->nm_principal = NULL;
3009 nmp->nm_sprinc = NULL;
3010 }
3011
3012 mattrs = nmp->nm_mattrs;
3013 mflags = nmp->nm_mflags;
3014 mflags_mask = nmp->nm_mflags_mask;
3015
3016 /* set up NFS mount with args */
3017 xb_init_buffer(&xb, xdrbuf, 2 * XDRWORD);
3018 xb_get_32(error, &xb, val); /* version */
3019 xb_get_32(error, &xb, argslength); /* args length */
3020 nfsmerr_if(error);
3021 xb_init_buffer(&xb, xdrbuf, argslength); /* restart parsing with actual buffer length */
3022 xb_get_32(error, &xb, val); /* version */
3023 xb_get_32(error, &xb, argslength); /* args length */
3024 xb_get_32(error, &xb, val); /* XDR args version */
3025 if (val != NFS_XDRARGS_VERSION_0 || argslength < ((4 + NFS_MATTR_BITMAP_LEN + 1) * XDRWORD)) {
3026 error = EINVAL;
3027 }
3028 len = NFS_MATTR_BITMAP_LEN;
3029 xb_get_bitmap(error, &xb, mattrs, len); /* mount attribute bitmap */
3030 attrslength = 0;
3031 xb_get_32(error, &xb, attrslength); /* attrs length */
3032 if (!error && (attrslength > (argslength - ((4 + NFS_MATTR_BITMAP_LEN + 1) * XDRWORD)))) {
3033 error = EINVAL;
3034 }
3035 nfsmerr_if(error);
3036 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_FLAGS)) {
3037 len = NFS_MFLAG_BITMAP_LEN;
3038 xb_get_bitmap(error, &xb, mflags_mask, len); /* mount flag mask */
3039 len = NFS_MFLAG_BITMAP_LEN;
3040 xb_get_bitmap(error, &xb, mflags, len); /* mount flag values */
3041 if (!error) {
3042 /* clear all mask bits and OR in all the ones that are set */
3043 nmp->nm_flags[0] &= ~mflags_mask[0];
3044 nmp->nm_flags[0] |= (mflags_mask[0] & mflags[0]);
3045 }
3046 }
3047 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_NFS_VERSION)) {
3048 /* Can't specify a single version and a range */
3049 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_NFS_VERSION_RANGE)) {
3050 error = EINVAL;
3051 }
3052 xb_get_32(error, &xb, nmp->nm_vers);
3053 if (nmp->nm_vers > NFS_MAX_SUPPORTED_VERSION ||
3054 nmp->nm_vers < NFS_VER2) {
3055 error = EINVAL;
3056 }
3057 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_NFS_MINOR_VERSION)) {
3058 xb_get_32(error, &xb, nmp->nm_minor_vers);
3059 } else {
3060 nmp->nm_minor_vers = maxminorverstab[nmp->nm_vers];
3061 }
3062 if (nmp->nm_minor_vers > maxminorverstab[nmp->nm_vers]) {
3063 error = EINVAL;
3064 }
3065 nmp->nm_max_vers = nmp->nm_min_vers =
3066 VER2PVER(nmp->nm_vers, nmp->nm_minor_vers);
3067 }
3068 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_NFS_MINOR_VERSION)) {
3069 /* should have also gotten NFS version (and already gotten minor version) */
3070 if (!NFS_BITMAP_ISSET(mattrs, NFS_MATTR_NFS_VERSION)) {
3071 error = EINVAL;
3072 }
3073 }
3074 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_NFS_VERSION_RANGE)) {
3075 xb_get_32(error, &xb, nmp->nm_min_vers);
3076 xb_get_32(error, &xb, nmp->nm_max_vers);
3077 if ((nmp->nm_min_vers > nmp->nm_max_vers) ||
3078 (PVER2MAJOR(nmp->nm_max_vers) > NFS_MAX_SUPPORTED_VERSION) ||
3079 (PVER2MINOR(nmp->nm_min_vers) > maxminorverstab[PVER2MAJOR(nmp->nm_min_vers)]) ||
3080 (PVER2MINOR(nmp->nm_max_vers) > maxminorverstab[PVER2MAJOR(nmp->nm_max_vers)])) {
3081 error = EINVAL;
3082 }
3083 }
3084 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_READ_SIZE)) {
3085 xb_get_32(error, &xb, nmp->nm_rsize);
3086 }
3087 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_WRITE_SIZE)) {
3088 xb_get_32(error, &xb, nmp->nm_wsize);
3089 }
3090 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_READDIR_SIZE)) {
3091 xb_get_32(error, &xb, nmp->nm_readdirsize);
3092 }
3093 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_READAHEAD)) {
3094 xb_get_32(error, &xb, nmp->nm_readahead);
3095 }
3096 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_ATTRCACHE_REG_MIN)) {
3097 xb_get_32(error, &xb, nmp->nm_acregmin);
3098 xb_skip(error, &xb, XDRWORD);
3099 }
3100 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_ATTRCACHE_REG_MAX)) {
3101 xb_get_32(error, &xb, nmp->nm_acregmax);
3102 xb_skip(error, &xb, XDRWORD);
3103 }
3104 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_ATTRCACHE_DIR_MIN)) {
3105 xb_get_32(error, &xb, nmp->nm_acdirmin);
3106 xb_skip(error, &xb, XDRWORD);
3107 }
3108 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_ATTRCACHE_DIR_MAX)) {
3109 xb_get_32(error, &xb, nmp->nm_acdirmax);
3110 xb_skip(error, &xb, XDRWORD);
3111 }
3112 nfsmerr_if(error);
3113 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_LOCK_MODE)) {
3114 xb_get_32(error, &xb, val);
3115 switch (val) {
3116 case NFS_LOCK_MODE_DISABLED:
3117 case NFS_LOCK_MODE_LOCAL:
3118 if (nmp->nm_vers >= NFS_VER4) {
3119 /* disabled/local lock mode only allowed on v2/v3 */
3120 error = EINVAL;
3121 break;
3122 }
3123 /* FALLTHROUGH */
3124 case NFS_LOCK_MODE_ENABLED:
3125 nmp->nm_lockmode = val;
3126 break;
3127 default:
3128 error = EINVAL;
3129 }
3130 }
3131 nfsmerr_if(error);
3132 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_SECURITY)) {
3133 uint32_t seccnt;
3134 xb_get_32(error, &xb, seccnt);
3135 if (!error && ((seccnt < 1) || (seccnt > NX_MAX_SEC_FLAVORS))) {
3136 error = EINVAL;
3137 }
3138 nfsmerr_if(error);
3139 nmp->nm_sec.count = seccnt;
3140 for (i = 0; i < seccnt; i++) {
3141 xb_get_32(error, &xb, nmp->nm_sec.flavors[i]);
3142 /* Check for valid security flavor */
3143 switch (nmp->nm_sec.flavors[i]) {
3144 case RPCAUTH_NONE:
3145 case RPCAUTH_SYS:
3146 case RPCAUTH_KRB5:
3147 case RPCAUTH_KRB5I:
3148 case RPCAUTH_KRB5P:
3149 break;
3150 default:
3151 error = EINVAL;
3152 }
3153 }
3154 /* start with the first flavor */
3155 nmp->nm_auth = nmp->nm_sec.flavors[0];
3156 }
3157 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_KERB_ETYPE)) {
3158 uint32_t etypecnt;
3159 xb_get_32(error, &xb, etypecnt);
3160 if (!error && ((etypecnt < 1) || (etypecnt > NFS_MAX_ETYPES))) {
3161 error = EINVAL;
3162 }
3163 nfsmerr_if(error);
3164 nmp->nm_etype.count = etypecnt;
3165 xb_get_32(error, &xb, nmp->nm_etype.selected);
3166 nfsmerr_if(error);
3167 if (etypecnt) {
3168 nmp->nm_etype.selected = etypecnt; /* Nothing is selected yet, so set selected to count */
3169 for (i = 0; i < etypecnt; i++) {
3170 xb_get_32(error, &xb, nmp->nm_etype.etypes[i]);
3171 /* Check for valid encryption type */
3172 switch (nmp->nm_etype.etypes[i]) {
3173 case NFS_DES3_CBC_SHA1_KD:
3174 case NFS_AES128_CTS_HMAC_SHA1_96:
3175 case NFS_AES256_CTS_HMAC_SHA1_96:
3176 break;
3177 default:
3178 error = EINVAL;
3179 }
3180 }
3181 }
3182 }
3183 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_MAX_GROUP_LIST)) {
3184 xb_get_32(error, &xb, nmp->nm_numgrps);
3185 }
3186 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_SOCKET_TYPE)) {
3187 char sotype[6];
3188
3189 xb_get_32(error, &xb, val);
3190 if (!error && ((val < 3) || (val > 5))) {
3191 error = EINVAL;
3192 }
3193 nfsmerr_if(error);
3194 error = xb_get_bytes(&xb, sotype, val, 0);
3195 nfsmerr_if(error);
3196 sotype[val] = '\0';
3197 if (!strcmp(sotype, "tcp")) {
3198 nmp->nm_sotype = SOCK_STREAM;
3199 } else if (!strcmp(sotype, "udp")) {
3200 nmp->nm_sotype = SOCK_DGRAM;
3201 } else if (!strcmp(sotype, "tcp4")) {
3202 nmp->nm_sotype = SOCK_STREAM;
3203 nmp->nm_sofamily = AF_INET;
3204 } else if (!strcmp(sotype, "udp4")) {
3205 nmp->nm_sotype = SOCK_DGRAM;
3206 nmp->nm_sofamily = AF_INET;
3207 } else if (!strcmp(sotype, "tcp6")) {
3208 nmp->nm_sotype = SOCK_STREAM;
3209 nmp->nm_sofamily = AF_INET6;
3210 } else if (!strcmp(sotype, "udp6")) {
3211 nmp->nm_sotype = SOCK_DGRAM;
3212 nmp->nm_sofamily = AF_INET6;
3213 } else if (!strcmp(sotype, "inet4")) {
3214 nmp->nm_sofamily = AF_INET;
3215 } else if (!strcmp(sotype, "inet6")) {
3216 nmp->nm_sofamily = AF_INET6;
3217 } else if (!strcmp(sotype, "inet")) {
3218 nmp->nm_sofamily = 0; /* ok */
3219 } else {
3220 error = EINVAL;
3221 }
3222 if (!error && (nmp->nm_vers >= NFS_VER4) && nmp->nm_sotype &&
3223 (nmp->nm_sotype != SOCK_STREAM)) {
3224 error = EINVAL; /* NFSv4 is only allowed over TCP. */
3225 }
3226 nfsmerr_if(error);
3227 }
3228 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_NFS_PORT)) {
3229 xb_get_32(error, &xb, nmp->nm_nfsport);
3230 }
3231 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_MOUNT_PORT)) {
3232 xb_get_32(error, &xb, nmp->nm_mountport);
3233 }
3234 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_REQUEST_TIMEOUT)) {
3235 /* convert from time to 0.1s units */
3236 xb_get_32(error, &xb, nmp->nm_timeo);
3237 xb_get_32(error, &xb, val);
3238 nfsmerr_if(error);
3239 if (val >= 1000000000) {
3240 error = EINVAL;
3241 }
3242 nfsmerr_if(error);
3243 nmp->nm_timeo *= 10;
3244 nmp->nm_timeo += (val + 100000000 - 1) / 100000000;
3245 /* now convert to ticks */
3246 nmp->nm_timeo = (nmp->nm_timeo * NFS_HZ + 5) / 10;
3247 }
3248 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_SOFT_RETRY_COUNT)) {
3249 xb_get_32(error, &xb, val);
3250 if (!error && (val > 1)) {
3251 nmp->nm_retry = val;
3252 }
3253 }
3254 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_DEAD_TIMEOUT)) {
3255 xb_get_32(error, &xb, nmp->nm_deadtimeout);
3256 xb_skip(error, &xb, XDRWORD);
3257 }
3258 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_FH)) {
3259 nfsmerr_if(error);
3260 MALLOC(nmp->nm_fh, fhandle_t *, sizeof(fhandle_t), M_TEMP, M_WAITOK | M_ZERO);
3261 if (!nmp->nm_fh) {
3262 error = ENOMEM;
3263 }
3264 xb_get_32(error, &xb, nmp->nm_fh->fh_len);
3265 nfsmerr_if(error);
3266 if ((size_t)nmp->nm_fh->fh_len > sizeof(nmp->nm_fh->fh_data)) {
3267 error = EINVAL;
3268 } else {
3269 error = xb_get_bytes(&xb, (char*)&nmp->nm_fh->fh_data[0], nmp->nm_fh->fh_len, 0);
3270 }
3271 }
3272 nfsmerr_if(error);
3273 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_FS_LOCATIONS)) {
3274 uint32_t loc, serv, addr, comp;
3275 struct nfs_fs_location *fsl;
3276 struct nfs_fs_server *fss;
3277 struct nfs_fs_path *fsp;
3278
3279 xb_get_32(error, &xb, nmp->nm_locations.nl_numlocs); /* fs location count */
3280 /* sanity check location count */
3281 if (!error && ((nmp->nm_locations.nl_numlocs < 1) || (nmp->nm_locations.nl_numlocs > 256))) {
3282 error = EINVAL;
3283 }
3284 nfsmerr_if(error);
3285 MALLOC(nmp->nm_locations.nl_locations, struct nfs_fs_location **, nmp->nm_locations.nl_numlocs * sizeof(struct nfs_fs_location*), M_TEMP, M_WAITOK | M_ZERO);
3286 if (!nmp->nm_locations.nl_locations) {
3287 error = ENOMEM;
3288 }
3289 for (loc = 0; loc < nmp->nm_locations.nl_numlocs; loc++) {
3290 nfsmerr_if(error);
3291 MALLOC(fsl, struct nfs_fs_location *, sizeof(struct nfs_fs_location), M_TEMP, M_WAITOK | M_ZERO);
3292 if (!fsl) {
3293 error = ENOMEM;
3294 }
3295 nmp->nm_locations.nl_locations[loc] = fsl;
3296 xb_get_32(error, &xb, fsl->nl_servcount); /* server count */
3297 /* sanity check server count */
3298 if (!error && ((fsl->nl_servcount < 1) || (fsl->nl_servcount > 256))) {
3299 error = EINVAL;
3300 }
3301 nfsmerr_if(error);
3302 MALLOC(fsl->nl_servers, struct nfs_fs_server **, fsl->nl_servcount * sizeof(struct nfs_fs_server*), M_TEMP, M_WAITOK | M_ZERO);
3303 if (!fsl->nl_servers) {
3304 error = ENOMEM;
3305 }
3306 for (serv = 0; serv < fsl->nl_servcount; serv++) {
3307 nfsmerr_if(error);
3308 MALLOC(fss, struct nfs_fs_server *, sizeof(struct nfs_fs_server), M_TEMP, M_WAITOK | M_ZERO);
3309 if (!fss) {
3310 error = ENOMEM;
3311 }
3312 fsl->nl_servers[serv] = fss;
3313 xb_get_32(error, &xb, val); /* server name length */
3314 /* sanity check server name length */
3315 if (!error && ((val < 1) || (val > MAXPATHLEN))) {
3316 error = EINVAL;
3317 }
3318 nfsmerr_if(error);
3319 MALLOC(fss->ns_name, char *, val + 1, M_TEMP, M_WAITOK | M_ZERO);
3320 if (!fss->ns_name) {
3321 error = ENOMEM;
3322 }
3323 nfsmerr_if(error);
3324 error = xb_get_bytes(&xb, fss->ns_name, val, 0); /* server name */
3325 xb_get_32(error, &xb, fss->ns_addrcount); /* address count */
3326 /* sanity check address count (OK to be zero) */
3327 if (!error && (fss->ns_addrcount > 256)) {
3328 error = EINVAL;
3329 }
3330 nfsmerr_if(error);
3331 if (fss->ns_addrcount > 0) {
3332 MALLOC(fss->ns_addresses, char **, fss->ns_addrcount * sizeof(char *), M_TEMP, M_WAITOK | M_ZERO);
3333 if (!fss->ns_addresses) {
3334 error = ENOMEM;
3335 }
3336 for (addr = 0; addr < fss->ns_addrcount; addr++) {
3337 xb_get_32(error, &xb, val); /* address length */
3338 /* sanity check address length */
3339 if (!error && ((val < 1) || (val > 128))) {
3340 error = EINVAL;
3341 }
3342 nfsmerr_if(error);
3343 MALLOC(fss->ns_addresses[addr], char *, val + 1, M_TEMP, M_WAITOK | M_ZERO);
3344 if (!fss->ns_addresses[addr]) {
3345 error = ENOMEM;
3346 }
3347 nfsmerr_if(error);
3348 error = xb_get_bytes(&xb, fss->ns_addresses[addr], val, 0); /* address */
3349 }
3350 }
3351 xb_get_32(error, &xb, val); /* server info length */
3352 xb_skip(error, &xb, val); /* skip server info */
3353 }
3354 /* get pathname */
3355 fsp = &fsl->nl_path;
3356 xb_get_32(error, &xb, fsp->np_compcount); /* component count */
3357 /* sanity check component count */
3358 if (!error && (fsp->np_compcount > MAXPATHLEN)) {
3359 error = EINVAL;
3360 }
3361 nfsmerr_if(error);
3362 if (fsp->np_compcount) {
3363 MALLOC(fsp->np_components, char **, fsp->np_compcount * sizeof(char*), M_TEMP, M_WAITOK | M_ZERO);
3364 if (!fsp->np_components) {
3365 error = ENOMEM;
3366 }
3367 }
3368 for (comp = 0; comp < fsp->np_compcount; comp++) {
3369 xb_get_32(error, &xb, val); /* component length */
3370 /* sanity check component length */
3371 if (!error && (val == 0)) {
3372 /*
3373 * Apparently some people think a path with zero components should
3374 * be encoded with one zero-length component. So, just ignore any
3375 * zero length components.
3376 */
3377 comp--;
3378 fsp->np_compcount--;
3379 if (fsp->np_compcount == 0) {
3380 FREE(fsp->np_components, M_TEMP);
3381 fsp->np_components = NULL;
3382 }
3383 continue;
3384 }
3385 if (!error && ((val < 1) || (val > MAXPATHLEN))) {
3386 error = EINVAL;
3387 }
3388 nfsmerr_if(error);
3389 MALLOC(fsp->np_components[comp], char *, val + 1, M_TEMP, M_WAITOK | M_ZERO);
3390 if (!fsp->np_components[comp]) {
3391 error = ENOMEM;
3392 }
3393 nfsmerr_if(error);
3394 error = xb_get_bytes(&xb, fsp->np_components[comp], val, 0); /* component */
3395 }
3396 xb_get_32(error, &xb, val); /* fs location info length */
3397 xb_skip(error, &xb, val); /* skip fs location info */
3398 }
3399 }
3400 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_MNTFLAGS)) {
3401 xb_skip(error, &xb, XDRWORD);
3402 }
3403 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_MNTFROM)) {
3404 xb_get_32(error, &xb, len);
3405 nfsmerr_if(error);
3406 val = len;
3407 if (val >= sizeof(vfs_statfs(mp)->f_mntfromname)) {
3408 val = sizeof(vfs_statfs(mp)->f_mntfromname) - 1;
3409 }
3410 error = xb_get_bytes(&xb, vfs_statfs(mp)->f_mntfromname, val, 0);
3411 if ((len - val) > 0) {
3412 xb_skip(error, &xb, len - val);
3413 }
3414 nfsmerr_if(error);
3415 vfs_statfs(mp)->f_mntfromname[val] = '\0';
3416 }
3417 nfsmerr_if(error);
3418
3419 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_REALM)) {
3420 xb_get_32(error, &xb, len);
3421 if (!error && ((len < 1) || (len > MAXPATHLEN))) {
3422 error = EINVAL;
3423 }
3424 nfsmerr_if(error);
3425 /* allocate an extra byte for a leading '@' if its not already prepended to the realm */
3426 MALLOC(nmp->nm_realm, char *, len + 2, M_TEMP, M_WAITOK | M_ZERO);
3427 if (!nmp->nm_realm) {
3428 error = ENOMEM;
3429 }
3430 nfsmerr_if(error);
3431 error = xb_get_bytes(&xb, nmp->nm_realm, len, 0);
3432 if (error == 0 && *nmp->nm_realm != '@') {
3433 bcopy(nmp->nm_realm, &nmp->nm_realm[1], len);
3434 nmp->nm_realm[0] = '@';
3435 }
3436 }
3437 nfsmerr_if(error);
3438
3439 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_PRINCIPAL)) {
3440 xb_get_32(error, &xb, len);
3441 if (!error && ((len < 1) || (len > MAXPATHLEN))) {
3442 error = EINVAL;
3443 }
3444 nfsmerr_if(error);
3445 MALLOC(nmp->nm_principal, char *, len + 1, M_TEMP, M_WAITOK | M_ZERO);
3446 if (!nmp->nm_principal) {
3447 error = ENOMEM;
3448 }
3449 nfsmerr_if(error);
3450 error = xb_get_bytes(&xb, nmp->nm_principal, len, 0);
3451 }
3452 nfsmerr_if(error);
3453
3454 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_SVCPRINCIPAL)) {
3455 xb_get_32(error, &xb, len);
3456 if (!error && ((len < 1) || (len > MAXPATHLEN))) {
3457 error = EINVAL;
3458 }
3459 nfsmerr_if(error);
3460 MALLOC(nmp->nm_sprinc, char *, len + 1, M_TEMP, M_WAITOK | M_ZERO);
3461 if (!nmp->nm_sprinc) {
3462 error = ENOMEM;
3463 }
3464 nfsmerr_if(error);
3465 error = xb_get_bytes(&xb, nmp->nm_sprinc, len, 0);
3466 }
3467 nfsmerr_if(error);
3468
3469 /*
3470 * Sanity check/finalize settings.
3471 */
3472
3473 if (nmp->nm_timeo < NFS_MINTIMEO) {
3474 nmp->nm_timeo = NFS_MINTIMEO;
3475 } else if (nmp->nm_timeo > NFS_MAXTIMEO) {
3476 nmp->nm_timeo = NFS_MAXTIMEO;
3477 }
3478 if (nmp->nm_retry > NFS_MAXREXMIT) {
3479 nmp->nm_retry = NFS_MAXREXMIT;
3480 }
3481
3482 if (nmp->nm_numgrps > NFS_MAXGRPS) {
3483 nmp->nm_numgrps = NFS_MAXGRPS;
3484 }
3485 if (nmp->nm_readahead > NFS_MAXRAHEAD) {
3486 nmp->nm_readahead = NFS_MAXRAHEAD;
3487 }
3488 if (nmp->nm_acregmin > nmp->nm_acregmax) {
3489 nmp->nm_acregmin = nmp->nm_acregmax;
3490 }
3491 if (nmp->nm_acdirmin > nmp->nm_acdirmax) {
3492 nmp->nm_acdirmin = nmp->nm_acdirmax;
3493 }
3494
3495 /* need at least one fs location */
3496 if (nmp->nm_locations.nl_numlocs < 1) {
3497 error = EINVAL;
3498 }
3499 nfsmerr_if(error);
3500
3501 /* init mount's mntfromname to first location */
3502 if (!NM_OMATTR_GIVEN(nmp, MNTFROM)) {
3503 nfs_location_mntfromname(&nmp->nm_locations, firstloc,
3504 vfs_statfs(mp)->f_mntfromname, sizeof(vfs_statfs(mp)->f_mntfromname), 0);
3505 }
3506
3507 /* Need to save the mounting credential for v4. */
3508 nmp->nm_mcred = vfs_context_ucred(ctx);
3509 if (IS_VALID_CRED(nmp->nm_mcred)) {
3510 kauth_cred_ref(nmp->nm_mcred);
3511 }
3512
3513 /*
3514 * If a reserved port is required, check for that privilege.
3515 * (Note that mirror mounts are exempt because the privilege was
3516 * already checked for the original mount.)
3517 */
3518 if (NMFLAG(nmp, RESVPORT) && !vfs_iskernelmount(mp)) {
3519 error = priv_check_cred(nmp->nm_mcred, PRIV_NETINET_RESERVEDPORT, 0);
3520 }
3521 nfsmerr_if(error);
3522
3523 /* do mount's initial socket connection */
3524 error = nfs_mount_connect(nmp);
3525 nfsmerr_if(error);
3526
3527 /* set up the version-specific function tables */
3528 if (nmp->nm_vers < NFS_VER4) {
3529 nmp->nm_funcs = &nfs3_funcs;
3530 } else {
3531 nmp->nm_funcs = &nfs4_funcs;
3532 }
3533
3534 /* sanity check settings now that version/connection is set */
3535 if (nmp->nm_vers == NFS_VER2) { /* ignore RDIRPLUS on NFSv2 */
3536 NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_RDIRPLUS);
3537 }
3538 if (nmp->nm_vers >= NFS_VER4) {
3539 if (NFS_BITMAP_ISSET(nmp->nm_flags, NFS_MFLAG_ACLONLY)) { /* aclonly trumps noacl */
3540 NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_NOACL);
3541 }
3542 NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_CALLUMNT);
3543 if (nmp->nm_lockmode != NFS_LOCK_MODE_ENABLED) {
3544 error = EINVAL; /* disabled/local lock mode only allowed on v2/v3 */
3545 }
3546 } else {
3547 /* ignore these if not v4 */
3548 NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_NOCALLBACK);
3549 NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_NAMEDATTR);
3550 NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_NOACL);
3551 NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_ACLONLY);
3552 }
3553 nfsmerr_if(error);
3554
3555 if (nmp->nm_sotype == SOCK_DGRAM) {
3556 /* I/O size defaults for UDP are different */
3557 if (!NFS_BITMAP_ISSET(mattrs, NFS_MATTR_READ_SIZE)) {
3558 nmp->nm_rsize = NFS_DGRAM_RSIZE;
3559 }
3560 if (!NFS_BITMAP_ISSET(mattrs, NFS_MATTR_WRITE_SIZE)) {
3561 nmp->nm_wsize = NFS_DGRAM_WSIZE;
3562 }
3563 }
3564
3565 /* round down I/O sizes to multiple of NFS_FABLKSIZE */
3566 nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1);
3567 if (nmp->nm_rsize <= 0) {
3568 nmp->nm_rsize = NFS_FABLKSIZE;
3569 }
3570 nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1);
3571 if (nmp->nm_wsize <= 0) {
3572 nmp->nm_wsize = NFS_FABLKSIZE;
3573 }
3574
3575 /* and limit I/O sizes to maximum allowed */
3576 maxio = (nmp->nm_vers == NFS_VER2) ? NFS_V2MAXDATA :
3577 (nmp->nm_sotype == SOCK_DGRAM) ? NFS_MAXDGRAMDATA : NFS_MAXDATA;
3578 if (maxio > NFS_MAXBSIZE) {
3579 maxio = NFS_MAXBSIZE;
3580 }
3581 if (nmp->nm_rsize > maxio) {
3582 nmp->nm_rsize = maxio;
3583 }
3584 if (nmp->nm_wsize > maxio) {
3585 nmp->nm_wsize = maxio;
3586 }
3587
3588 if (nmp->nm_readdirsize > maxio) {
3589 nmp->nm_readdirsize = maxio;
3590 }
3591 if (nmp->nm_readdirsize > nmp->nm_rsize) {
3592 nmp->nm_readdirsize = nmp->nm_rsize;
3593 }
3594
3595 /* Set up the sockets and related info */
3596 if (nmp->nm_sotype == SOCK_DGRAM) {
3597 TAILQ_INIT(&nmp->nm_cwndq);
3598 }
3599
3600 /*
3601 * Get the root node/attributes from the NFS server and
3602 * do any basic, version-specific setup.
3603 */
3604 error = nmp->nm_funcs->nf_mount(nmp, ctx, &np);
3605 nfsmerr_if(error);
3606
3607 /*
3608 * A reference count is needed on the node representing the
3609 * remote root. If this object is not persistent, then backward
3610 * traversals of the mount point (i.e. "..") will not work if
3611 * the node gets flushed out of the cache.
3612 */
3613 nmp->nm_dnp = np;
3614 *vpp = NFSTOV(np);
3615 /* get usecount and drop iocount */
3616 error = vnode_ref(*vpp);
3617 vnode_put(*vpp);
3618 if (error) {
3619 vnode_recycle(*vpp);
3620 goto nfsmerr;
3621 }
3622
3623 /*
3624 * Do statfs to ensure static info gets set to reasonable values.
3625 */
3626 if ((error = nmp->nm_funcs->nf_update_statfs(nmp, ctx))) {
3627 int error2 = vnode_getwithref(*vpp);
3628 vnode_rele(*vpp);
3629 if (!error2) {
3630 vnode_put(*vpp);
3631 }
3632 vnode_recycle(*vpp);
3633 goto nfsmerr;
3634 }
3635 sbp = vfs_statfs(mp);
3636 sbp->f_bsize = nmp->nm_fsattr.nfsa_bsize;
3637 sbp->f_blocks = nmp->nm_fsattr.nfsa_space_total / sbp->f_bsize;
3638 sbp->f_bfree = nmp->nm_fsattr.nfsa_space_free / sbp->f_bsize;
3639 sbp->f_bavail = nmp->nm_fsattr.nfsa_space_avail / sbp->f_bsize;
3640 sbp->f_bused = (nmp->nm_fsattr.nfsa_space_total / sbp->f_bsize) -
3641 (nmp->nm_fsattr.nfsa_space_free / sbp->f_bsize);
3642 sbp->f_files = nmp->nm_fsattr.nfsa_files_total;
3643 sbp->f_ffree = nmp->nm_fsattr.nfsa_files_free;
3644 sbp->f_iosize = nfs_iosize;
3645
3646 /*
3647 * Calculate the size used for I/O buffers. Use the larger
3648 * of the two sizes to minimise NFS requests but make sure
3649 * that it is at least one VM page to avoid wasting buffer
3650 * space and to allow easy mmapping of I/O buffers.
3651 * The read/write RPC calls handle the splitting up of
3652 * buffers into multiple requests if the buffer size is
3653 * larger than the I/O size.
3654 */
3655 #ifndef CONFIG_EMBEDDED
3656 iosize = max(nmp->nm_rsize, nmp->nm_wsize);
3657 if (iosize < PAGE_SIZE) {
3658 iosize = PAGE_SIZE;
3659 }
3660 #else
3661 iosize = PAGE_SIZE;
3662 #endif
3663 nmp->nm_biosize = trunc_page_32(iosize);
3664
3665 /* For NFSv3 and greater, there is a (relatively) reliable ACCESS call. */
3666 if (nmp->nm_vers > NFS_VER2) {
3667 vfs_setauthopaqueaccess(mp);
3668 }
3669
3670 switch (nmp->nm_lockmode) {
3671 case NFS_LOCK_MODE_DISABLED:
3672 break;
3673 case NFS_LOCK_MODE_LOCAL:
3674 vfs_setlocklocal(nmp->nm_mountp);
3675 break;
3676 case NFS_LOCK_MODE_ENABLED:
3677 default:
3678 if (nmp->nm_vers <= NFS_VER3) {
3679 nfs_lockd_mount_register(nmp);
3680 }
3681 break;
3682 }
3683
3684 /* success! */
3685 lck_mtx_lock(&nmp->nm_lock);
3686 nmp->nm_state |= NFSSTA_MOUNTED;
3687 lck_mtx_unlock(&nmp->nm_lock);
3688 return 0;
3689 nfsmerr:
3690 nfs_mount_drain_and_cleanup(nmp);
3691 return error;
3692 }
3693
3694 #if CONFIG_TRIGGERS
3695
3696 /*
3697 * We've detected a file system boundary on the server and
3698 * need to mount a new file system so that our file systems
3699 * MIRROR the file systems on the server.
3700 *
3701 * Build the mount arguments for the new mount and call kernel_mount().
3702 */
3703 int
3704 nfs_mirror_mount_domount(vnode_t dvp, vnode_t vp, vfs_context_t ctx)
3705 {
3706 nfsnode_t np = VTONFS(vp);
3707 nfsnode_t dnp = VTONFS(dvp);
3708 struct nfsmount *nmp = NFSTONMP(np);
3709 char fstype[MFSTYPENAMELEN], *mntfromname = NULL, *path = NULL, *relpath, *p, *cp;
3710 int error = 0, pathbuflen = MAXPATHLEN, i, mntflags = 0, referral, skipcopy = 0;
3711 size_t nlen;
3712 struct xdrbuf xb, xbnew;
3713 uint32_t mattrs[NFS_MATTR_BITMAP_LEN];
3714 uint32_t newmattrs[NFS_MATTR_BITMAP_LEN];
3715 uint32_t newmflags[NFS_MFLAG_BITMAP_LEN];
3716 uint32_t newmflags_mask[NFS_MFLAG_BITMAP_LEN];
3717 uint32_t argslength = 0, val, count, mlen, mlen2, rlen, relpathcomps;
3718 uint32_t argslength_offset, attrslength_offset, end_offset;
3719 uint32_t numlocs, loc, numserv, serv, numaddr, addr, numcomp, comp;
3720 char buf[XDRWORD];
3721 struct nfs_fs_locations nfsls;
3722
3723 referral = (np->n_vattr.nva_flags & NFS_FFLAG_TRIGGER_REFERRAL);
3724 if (referral) {
3725 bzero(&nfsls, sizeof(nfsls));
3726 }
3727
3728 xb_init(&xbnew, 0);
3729
3730 if (!nmp || (nmp->nm_state & (NFSSTA_FORCE | NFSSTA_DEAD))) {
3731 return ENXIO;
3732 }
3733
3734 /* allocate a couple path buffers we need */
3735 MALLOC_ZONE(mntfromname, char *, pathbuflen, M_NAMEI, M_WAITOK);
3736 if (!mntfromname) {
3737 error = ENOMEM;
3738 goto nfsmerr;
3739 }
3740 MALLOC_ZONE(path, char *, pathbuflen, M_NAMEI, M_WAITOK);
3741 if (!path) {
3742 error = ENOMEM;
3743 goto nfsmerr;
3744 }
3745
3746 /* get the path for the directory being mounted on */
3747 error = vn_getpath(vp, path, &pathbuflen);
3748 if (error) {
3749 error = ENOMEM;
3750 goto nfsmerr;
3751 }
3752
3753 /*
3754 * Set up the mntfromname for the new mount based on the
3755 * current mount's mntfromname and the directory's path
3756 * relative to the current mount's mntonname.
3757 * Set up relpath to point at the relative path on the current mount.
3758 * Also, count the number of components in relpath.
3759 * We'll be adding those to each fs location path in the new args.
3760 */
3761 nlen = strlcpy(mntfromname, vfs_statfs(nmp->nm_mountp)->f_mntfromname, MAXPATHLEN);
3762 if ((nlen > 0) && (mntfromname[nlen - 1] == '/')) { /* avoid double '/' in new name */
3763 mntfromname[nlen - 1] = '\0';
3764 nlen--;
3765 }
3766 relpath = mntfromname + nlen;
3767 nlen = strlcat(mntfromname, path + strlen(vfs_statfs(nmp->nm_mountp)->f_mntonname), MAXPATHLEN);
3768 if (nlen >= MAXPATHLEN) {
3769 error = ENAMETOOLONG;
3770 goto nfsmerr;
3771 }
3772 /* count the number of components in relpath */
3773 p = relpath;
3774 while (*p && (*p == '/')) {
3775 p++;
3776 }
3777 relpathcomps = 0;
3778 while (*p) {
3779 relpathcomps++;
3780 while (*p && (*p != '/')) {
3781 p++;
3782 }
3783 while (*p && (*p == '/')) {
3784 p++;
3785 }
3786 }
3787
3788 /* grab a copy of the file system type */
3789 vfs_name(vnode_mount(vp), fstype);
3790
3791 /* for referrals, fetch the fs locations */
3792 if (referral) {
3793 const char *vname = vnode_getname(NFSTOV(np));
3794 if (!vname) {
3795 error = ENOENT;
3796 } else {
3797 error = nfs4_get_fs_locations(nmp, dnp, NULL, 0, vname, ctx, &nfsls);
3798 vnode_putname(vname);
3799 if (!error && (nfsls.nl_numlocs < 1)) {
3800 error = ENOENT;
3801 }
3802 }
3803 nfsmerr_if(error);
3804 }
3805
3806 /* set up NFS mount args based on current mount args */
3807
3808 #define xb_copy_32(E, XBSRC, XBDST, V) \
3809 do { \
3810 if (E) break; \
3811 xb_get_32((E), (XBSRC), (V)); \
3812 if (skipcopy) break; \
3813 xb_add_32((E), (XBDST), (V)); \
3814 } while (0)
3815 #define xb_copy_opaque(E, XBSRC, XBDST) \
3816 do { \
3817 uint32_t __count, __val; \
3818 xb_copy_32((E), (XBSRC), (XBDST), __count); \
3819 if (E) break; \
3820 __count = nfsm_rndup(__count); \
3821 __count /= XDRWORD; \
3822 while (__count-- > 0) \
3823 xb_copy_32((E), (XBSRC), (XBDST), __val); \
3824 } while (0)
3825
3826 xb_init_buffer(&xb, nmp->nm_args, 2 * XDRWORD);
3827 xb_get_32(error, &xb, val); /* version */
3828 xb_get_32(error, &xb, argslength); /* args length */
3829 xb_init_buffer(&xb, nmp->nm_args, argslength);
3830
3831 xb_init_buffer(&xbnew, NULL, 0);
3832 xb_copy_32(error, &xb, &xbnew, val); /* version */
3833 argslength_offset = xb_offset(&xbnew);
3834 xb_copy_32(error, &xb, &xbnew, val); /* args length */
3835 xb_copy_32(error, &xb, &xbnew, val); /* XDR args version */
3836 count = NFS_MATTR_BITMAP_LEN;
3837 xb_get_bitmap(error, &xb, mattrs, count); /* mount attribute bitmap */
3838 nfsmerr_if(error);
3839 for (i = 0; i < NFS_MATTR_BITMAP_LEN; i++) {
3840 newmattrs[i] = mattrs[i];
3841 }
3842 if (referral) {
3843 NFS_BITMAP_SET(newmattrs, NFS_MATTR_FS_LOCATIONS);
3844 } else {
3845 NFS_BITMAP_SET(newmattrs, NFS_MATTR_FH);
3846 }
3847 NFS_BITMAP_SET(newmattrs, NFS_MATTR_FLAGS);
3848 NFS_BITMAP_SET(newmattrs, NFS_MATTR_MNTFLAGS);
3849 NFS_BITMAP_CLR(newmattrs, NFS_MATTR_MNTFROM);
3850 xb_add_bitmap(error, &xbnew, newmattrs, NFS_MATTR_BITMAP_LEN);
3851 attrslength_offset = xb_offset(&xbnew);
3852 xb_copy_32(error, &xb, &xbnew, val); /* attrs length */
3853 NFS_BITMAP_ZERO(newmflags_mask, NFS_MFLAG_BITMAP_LEN);
3854 NFS_BITMAP_ZERO(newmflags, NFS_MFLAG_BITMAP_LEN);
3855 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_FLAGS)) {
3856 count = NFS_MFLAG_BITMAP_LEN;
3857 xb_get_bitmap(error, &xb, newmflags_mask, count); /* mount flag mask bitmap */
3858 count = NFS_MFLAG_BITMAP_LEN;
3859 xb_get_bitmap(error, &xb, newmflags, count); /* mount flag bitmap */
3860 }
3861 NFS_BITMAP_SET(newmflags_mask, NFS_MFLAG_EPHEMERAL);
3862 NFS_BITMAP_SET(newmflags, NFS_MFLAG_EPHEMERAL);
3863 xb_add_bitmap(error, &xbnew, newmflags_mask, NFS_MFLAG_BITMAP_LEN);
3864 xb_add_bitmap(error, &xbnew, newmflags, NFS_MFLAG_BITMAP_LEN);
3865 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_NFS_VERSION)) {
3866 xb_copy_32(error, &xb, &xbnew, val);
3867 }
3868 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_NFS_MINOR_VERSION)) {
3869 xb_copy_32(error, &xb, &xbnew, val);
3870 }
3871 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_NFS_VERSION_RANGE)) {
3872 xb_copy_32(error, &xb, &xbnew, val);
3873 xb_copy_32(error, &xb, &xbnew, val);
3874 }
3875 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_READ_SIZE)) {
3876 xb_copy_32(error, &xb, &xbnew, val);
3877 }
3878 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_WRITE_SIZE)) {
3879 xb_copy_32(error, &xb, &xbnew, val);
3880 }
3881 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_READDIR_SIZE)) {
3882 xb_copy_32(error, &xb, &xbnew, val);
3883 }
3884 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_READAHEAD)) {
3885 xb_copy_32(error, &xb, &xbnew, val);
3886 }
3887 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_ATTRCACHE_REG_MIN)) {
3888 xb_copy_32(error, &xb, &xbnew, val);
3889 xb_copy_32(error, &xb, &xbnew, val);
3890 }
3891 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_ATTRCACHE_REG_MAX)) {
3892 xb_copy_32(error, &xb, &xbnew, val);
3893 xb_copy_32(error, &xb, &xbnew, val);
3894 }
3895 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_ATTRCACHE_DIR_MIN)) {
3896 xb_copy_32(error, &xb, &xbnew, val);
3897 xb_copy_32(error, &xb, &xbnew, val);
3898 }
3899 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_ATTRCACHE_DIR_MAX)) {
3900 xb_copy_32(error, &xb, &xbnew, val);
3901 xb_copy_32(error, &xb, &xbnew, val);
3902 }
3903 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_LOCK_MODE)) {
3904 xb_copy_32(error, &xb, &xbnew, val);
3905 }
3906 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_SECURITY)) {
3907 xb_copy_32(error, &xb, &xbnew, count);
3908 while (!error && (count-- > 0)) {
3909 xb_copy_32(error, &xb, &xbnew, val);
3910 }
3911 }
3912 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_KERB_ETYPE)) {
3913 xb_copy_32(error, &xb, &xbnew, count);
3914 xb_add_32(error, &xbnew, -1);
3915 while (!error && (count-- > 0)) {
3916 xb_copy_32(error, &xb, &xbnew, val);
3917 }
3918 }
3919 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_MAX_GROUP_LIST)) {
3920 xb_copy_32(error, &xb, &xbnew, val);
3921 }
3922 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_SOCKET_TYPE)) {
3923 xb_copy_opaque(error, &xb, &xbnew);
3924 }
3925 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_NFS_PORT)) {
3926 xb_copy_32(error, &xb, &xbnew, val);
3927 }
3928 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_MOUNT_PORT)) {
3929 xb_copy_32(error, &xb, &xbnew, val);
3930 }
3931 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_REQUEST_TIMEOUT)) {
3932 xb_copy_32(error, &xb, &xbnew, val);
3933 xb_copy_32(error, &xb, &xbnew, val);
3934 }
3935 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_SOFT_RETRY_COUNT)) {
3936 xb_copy_32(error, &xb, &xbnew, val);
3937 }
3938 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_DEAD_TIMEOUT)) {
3939 xb_copy_32(error, &xb, &xbnew, val);
3940 xb_copy_32(error, &xb, &xbnew, val);
3941 }
3942 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_FH)) {
3943 xb_get_32(error, &xb, count);
3944 xb_skip(error, &xb, count);
3945 }
3946 if (!referral) {
3947 /* set the initial file handle to the directory's file handle */
3948 xb_add_fh(error, &xbnew, np->n_fhp, np->n_fhsize);
3949 }
3950 /* copy/extend/skip fs locations */
3951 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_FS_LOCATIONS)) {
3952 numlocs = numserv = numaddr = numcomp = 0;
3953 if (referral) { /* don't copy the fs locations for a referral */
3954 skipcopy = 1;
3955 }
3956 xb_copy_32(error, &xb, &xbnew, numlocs); /* location count */
3957 for (loc = 0; !error && (loc < numlocs); loc++) {
3958 xb_copy_32(error, &xb, &xbnew, numserv); /* server count */
3959 for (serv = 0; !error && (serv < numserv); serv++) {
3960 xb_copy_opaque(error, &xb, &xbnew); /* server name */
3961 xb_copy_32(error, &xb, &xbnew, numaddr); /* address count */
3962 for (addr = 0; !error && (addr < numaddr); addr++) {
3963 xb_copy_opaque(error, &xb, &xbnew); /* address */
3964 }
3965 xb_copy_opaque(error, &xb, &xbnew); /* server info */
3966 }
3967 /* pathname */
3968 xb_get_32(error, &xb, numcomp); /* component count */
3969 if (!skipcopy) {
3970 uint64_t totalcomps = numcomp + relpathcomps;
3971
3972 /* set error to ERANGE in the event of overflow */
3973 if (totalcomps > UINT32_MAX) {
3974 nfsmerr_if((error = ERANGE));
3975 }
3976
3977 xb_add_32(error, &xbnew, (uint32_t) totalcomps); /* new component count */
3978 }
3979 for (comp = 0; !error && (comp < numcomp); comp++) {
3980 xb_copy_opaque(error, &xb, &xbnew); /* component */
3981 }
3982 /* add additional components */
3983 for (comp = 0; !skipcopy && !error && (comp < relpathcomps); comp++) {
3984 p = relpath;
3985 while (*p && (*p == '/')) {
3986 p++;
3987 }
3988 while (*p && !error) {
3989 cp = p;
3990 while (*p && (*p != '/')) {
3991 p++;
3992 }
3993 xb_add_string(error, &xbnew, cp, (p - cp)); /* component */
3994 while (*p && (*p == '/')) {
3995 p++;
3996 }
3997 }
3998 }
3999 xb_copy_opaque(error, &xb, &xbnew); /* fs location info */
4000 }
4001 if (referral) {
4002 skipcopy = 0;
4003 }
4004 }
4005 if (referral) {
4006 /* add referral's fs locations */
4007 xb_add_32(error, &xbnew, nfsls.nl_numlocs); /* FS_LOCATIONS */
4008 for (loc = 0; !error && (loc < nfsls.nl_numlocs); loc++) {
4009 xb_add_32(error, &xbnew, nfsls.nl_locations[loc]->nl_servcount);
4010 for (serv = 0; !error && (serv < nfsls.nl_locations[loc]->nl_servcount); serv++) {
4011 xb_add_string(error, &xbnew, nfsls.nl_locations[loc]->nl_servers[serv]->ns_name,
4012 strlen(nfsls.nl_locations[loc]->nl_servers[serv]->ns_name));
4013 xb_add_32(error, &xbnew, nfsls.nl_locations[loc]->nl_servers[serv]->ns_addrcount);
4014 for (addr = 0; !error && (addr < nfsls.nl_locations[loc]->nl_servers[serv]->ns_addrcount); addr++) {
4015 xb_add_string(error, &xbnew, nfsls.nl_locations[loc]->nl_servers[serv]->ns_addresses[addr],
4016 strlen(nfsls.nl_locations[loc]->nl_servers[serv]->ns_addresses[addr]));
4017 }
4018 xb_add_32(error, &xbnew, 0); /* empty server info */
4019 }
4020 xb_add_32(error, &xbnew, nfsls.nl_locations[loc]->nl_path.np_compcount);
4021 for (comp = 0; !error && (comp < nfsls.nl_locations[loc]->nl_path.np_compcount); comp++) {
4022 xb_add_string(error, &xbnew, nfsls.nl_locations[loc]->nl_path.np_components[comp],
4023 strlen(nfsls.nl_locations[loc]->nl_path.np_components[comp]));
4024 }
4025 xb_add_32(error, &xbnew, 0); /* empty fs location info */
4026 }
4027 }
4028 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_MNTFLAGS)) {
4029 xb_get_32(error, &xb, mntflags);
4030 }
4031 /*
4032 * We add the following mount flags to the ones for the mounted-on mount:
4033 * MNT_DONTBROWSE - to keep the mount from showing up as a separate volume
4034 * MNT_AUTOMOUNTED - to keep DiskArb from retriggering the mount after
4035 * an unmount (looking for /.autodiskmounted)
4036 */
4037 mntflags |= (MNT_AUTOMOUNTED | MNT_DONTBROWSE);
4038 xb_add_32(error, &xbnew, mntflags);
4039 if (!referral && NFS_BITMAP_ISSET(mattrs, NFS_MATTR_MNTFROM)) {
4040 /* copy mntfrom string and add relpath */
4041 rlen = strlen(relpath);
4042 xb_get_32(error, &xb, mlen);
4043 nfsmerr_if(error);
4044 mlen2 = mlen + ((relpath[0] != '/') ? 1 : 0) + rlen;
4045 xb_add_32(error, &xbnew, mlen2);
4046 count = mlen / XDRWORD;
4047 /* copy the original string */
4048 while (count-- > 0) {
4049 xb_copy_32(error, &xb, &xbnew, val);
4050 }
4051 if (!error && (mlen % XDRWORD)) {
4052 error = xb_get_bytes(&xb, buf, mlen % XDRWORD, 0);
4053 if (!error) {
4054 error = xb_add_bytes(&xbnew, buf, mlen % XDRWORD, 1);
4055 }
4056 }
4057 /* insert a '/' if the relative path doesn't start with one */
4058 if (!error && (relpath[0] != '/')) {
4059 buf[0] = '/';
4060 error = xb_add_bytes(&xbnew, buf, 1, 1);
4061 }
4062 /* add the additional relative path */
4063 if (!error) {
4064 error = xb_add_bytes(&xbnew, relpath, rlen, 1);
4065 }
4066 /* make sure the resulting string has the right number of pad bytes */
4067 if (!error && (mlen2 != nfsm_rndup(mlen2))) {
4068 bzero(buf, sizeof(buf));
4069 count = nfsm_rndup(mlen2) - mlen2;
4070 error = xb_add_bytes(&xbnew, buf, count, 1);
4071 }
4072 }
4073 xb_build_done(error, &xbnew);
4074
4075 /* update opaque counts */
4076 end_offset = xb_offset(&xbnew);
4077 if (!error) {
4078 error = xb_seek(&xbnew, argslength_offset);
4079 argslength = end_offset - argslength_offset + XDRWORD /*version*/;
4080 xb_add_32(error, &xbnew, argslength);
4081 }
4082 if (!error) {
4083 error = xb_seek(&xbnew, attrslength_offset);
4084 xb_add_32(error, &xbnew, end_offset - attrslength_offset - XDRWORD /*don't include length field*/);
4085 }
4086 nfsmerr_if(error);
4087
4088 /*
4089 * For kernel_mount() call, use the existing mount flags (instead of the
4090 * original flags) because flags like MNT_NOSUID and MNT_NODEV may have
4091 * been silently enforced.
4092 */
4093 mntflags = vnode_vfsvisflags(vp);
4094 mntflags |= (MNT_AUTOMOUNTED | MNT_DONTBROWSE);
4095
4096 /* do the mount */
4097 error = kernel_mount(fstype, dvp, vp, path, xb_buffer_base(&xbnew), argslength,
4098 mntflags, KERNEL_MOUNT_PERMIT_UNMOUNT | KERNEL_MOUNT_NOAUTH, ctx);
4099
4100 nfsmerr:
4101 if (error) {
4102 printf("nfs: mirror mount of %s on %s failed (%d)\n",
4103 mntfromname, path, error);
4104 }
4105 /* clean up */
4106 xb_cleanup(&xbnew);
4107 if (referral) {
4108 nfs_fs_locations_cleanup(&nfsls);
4109 }
4110 if (path) {
4111 FREE_ZONE(path, MAXPATHLEN, M_NAMEI);
4112 }
4113 if (mntfromname) {
4114 FREE_ZONE(mntfromname, MAXPATHLEN, M_NAMEI);
4115 }
4116 if (!error) {
4117 nfs_ephemeral_mount_harvester_start();
4118 }
4119 return error;
4120 }
4121
4122 /*
4123 * trigger vnode functions
4124 */
4125
4126 resolver_result_t
4127 nfs_mirror_mount_trigger_resolve(
4128 vnode_t vp,
4129 const struct componentname *cnp,
4130 enum path_operation pop,
4131 __unused int flags,
4132 __unused void *data,
4133 vfs_context_t ctx)
4134 {
4135 nfsnode_t np = VTONFS(vp);
4136 vnode_t pvp = NULLVP;
4137 int error = 0;
4138 resolver_result_t result;
4139
4140 /*
4141 * We have a trigger node that doesn't have anything mounted on it yet.
4142 * We'll do the mount if either:
4143 * (a) this isn't the last component of the path OR
4144 * (b) this is an op that looks like it should trigger the mount.
4145 */
4146 if (cnp->cn_flags & ISLASTCN) {
4147 switch (pop) {
4148 case OP_MOUNT:
4149 case OP_UNMOUNT:
4150 case OP_STATFS:
4151 case OP_LINK:
4152 case OP_UNLINK:
4153 case OP_RENAME:
4154 case OP_MKNOD:
4155 case OP_MKFIFO:
4156 case OP_SYMLINK:
4157 case OP_ACCESS:
4158 case OP_GETATTR:
4159 case OP_MKDIR:
4160 case OP_RMDIR:
4161 case OP_REVOKE:
4162 case OP_GETXATTR:
4163 case OP_LISTXATTR:
4164 /* don't perform the mount for these operations */
4165 result = vfs_resolver_result(np->n_trigseq, RESOLVER_NOCHANGE, 0);
4166 #ifdef NFS_TRIGGER_DEBUG
4167 NP(np, "nfs trigger RESOLVE: no change, last %d nameiop %d, seq %d",
4168 (cnp->cn_flags & ISLASTCN) ? 1 : 0, cnp->cn_nameiop, np->n_trigseq);
4169 #endif
4170 return result;
4171 case OP_OPEN:
4172 case OP_CHDIR:
4173 case OP_CHROOT:
4174 case OP_TRUNCATE:
4175 case OP_COPYFILE:
4176 case OP_PATHCONF:
4177 case OP_READLINK:
4178 case OP_SETATTR:
4179 case OP_EXCHANGEDATA:
4180 case OP_SEARCHFS:
4181 case OP_FSCTL:
4182 case OP_SETXATTR:
4183 case OP_REMOVEXATTR:
4184 default:
4185 /* go ahead and do the mount */
4186 break;
4187 }
4188 }
4189
4190 if (vnode_mountedhere(vp) != NULL) {
4191 /*
4192 * Um... there's already something mounted.
4193 * Been there. Done that. Let's just say it succeeded.
4194 */
4195 error = 0;
4196 goto skipmount;
4197 }
4198
4199 if ((error = nfs_node_set_busy(np, vfs_context_thread(ctx)))) {
4200 result = vfs_resolver_result(np->n_trigseq, RESOLVER_ERROR, error);
4201 #ifdef NFS_TRIGGER_DEBUG
4202 NP(np, "nfs trigger RESOLVE: busy error %d, last %d nameiop %d, seq %d",
4203 error, (cnp->cn_flags & ISLASTCN) ? 1 : 0, cnp->cn_nameiop, np->n_trigseq);
4204 #endif
4205 return result;
4206 }
4207
4208 pvp = vnode_getparent(vp);
4209 if (pvp == NULLVP) {
4210 error = EINVAL;
4211 }
4212 if (!error) {
4213 error = nfs_mirror_mount_domount(pvp, vp, ctx);
4214 }
4215 skipmount:
4216 if (!error) {
4217 np->n_trigseq++;
4218 }
4219 result = vfs_resolver_result(np->n_trigseq, error ? RESOLVER_ERROR : RESOLVER_RESOLVED, error);
4220 #ifdef NFS_TRIGGER_DEBUG
4221 NP(np, "nfs trigger RESOLVE: %s %d, last %d nameiop %d, seq %d",
4222 error ? "error" : "resolved", error,
4223 (cnp->cn_flags & ISLASTCN) ? 1 : 0, cnp->cn_nameiop, np->n_trigseq);
4224 #endif
4225
4226 if (pvp != NULLVP) {
4227 vnode_put(pvp);
4228 }
4229 nfs_node_clear_busy(np);
4230 return result;
4231 }
4232
4233 resolver_result_t
4234 nfs_mirror_mount_trigger_unresolve(
4235 vnode_t vp,
4236 int flags,
4237 __unused void *data,
4238 vfs_context_t ctx)
4239 {
4240 nfsnode_t np = VTONFS(vp);
4241 mount_t mp;
4242 int error;
4243 resolver_result_t result;
4244
4245 if ((error = nfs_node_set_busy(np, vfs_context_thread(ctx)))) {
4246 result = vfs_resolver_result(np->n_trigseq, RESOLVER_ERROR, error);
4247 #ifdef NFS_TRIGGER_DEBUG
4248 NP(np, "nfs trigger UNRESOLVE: busy error %d, seq %d", error, np->n_trigseq);
4249 #endif
4250 return result;
4251 }
4252
4253 mp = vnode_mountedhere(vp);
4254 if (!mp) {
4255 error = EINVAL;
4256 }
4257 if (!error) {
4258 error = vfs_unmountbyfsid(&(vfs_statfs(mp)->f_fsid), flags, ctx);
4259 }
4260 if (!error) {
4261 np->n_trigseq++;
4262 }
4263 result = vfs_resolver_result(np->n_trigseq, error ? RESOLVER_ERROR : RESOLVER_UNRESOLVED, error);
4264 #ifdef NFS_TRIGGER_DEBUG
4265 NP(np, "nfs trigger UNRESOLVE: %s %d, seq %d",
4266 error ? "error" : "unresolved", error, np->n_trigseq);
4267 #endif
4268 nfs_node_clear_busy(np);
4269 return result;
4270 }
4271
4272 resolver_result_t
4273 nfs_mirror_mount_trigger_rearm(
4274 vnode_t vp,
4275 __unused int flags,
4276 __unused void *data,
4277 vfs_context_t ctx)
4278 {
4279 nfsnode_t np = VTONFS(vp);
4280 int error;
4281 resolver_result_t result;
4282
4283 if ((error = nfs_node_set_busy(np, vfs_context_thread(ctx)))) {
4284 result = vfs_resolver_result(np->n_trigseq, RESOLVER_ERROR, error);
4285 #ifdef NFS_TRIGGER_DEBUG
4286 NP(np, "nfs trigger REARM: busy error %d, seq %d", error, np->n_trigseq);
4287 #endif
4288 return result;
4289 }
4290
4291 np->n_trigseq++;
4292 result = vfs_resolver_result(np->n_trigseq,
4293 vnode_mountedhere(vp) ? RESOLVER_RESOLVED : RESOLVER_UNRESOLVED, 0);
4294 #ifdef NFS_TRIGGER_DEBUG
4295 NP(np, "nfs trigger REARM: %s, seq %d",
4296 vnode_mountedhere(vp) ? "resolved" : "unresolved", np->n_trigseq);
4297 #endif
4298 nfs_node_clear_busy(np);
4299 return result;
4300 }
4301
4302 /*
4303 * Periodically attempt to unmount ephemeral (mirror) mounts in an attempt to limit
4304 * the number of unused mounts.
4305 */
4306
4307 #define NFS_EPHEMERAL_MOUNT_HARVEST_INTERVAL 120 /* how often the harvester runs */
4308 struct nfs_ephemeral_mount_harvester_info {
4309 fsid_t fsid; /* FSID that we need to try to unmount */
4310 uint32_t mountcount; /* count of ephemeral mounts seen in scan */
4311 };
4312 /* various globals for the harvester */
4313 static thread_call_t nfs_ephemeral_mount_harvester_timer = NULL;
4314 static int nfs_ephemeral_mount_harvester_on = 0;
4315
4316 kern_return_t thread_terminate(thread_t);
4317
4318 static int
4319 nfs_ephemeral_mount_harvester_callback(mount_t mp, void *arg)
4320 {
4321 struct nfs_ephemeral_mount_harvester_info *hinfo = arg;
4322 struct nfsmount *nmp;
4323 struct timeval now;
4324
4325 if (strcmp(mp->mnt_vfsstat.f_fstypename, "nfs")) {
4326 return VFS_RETURNED;
4327 }
4328 nmp = VFSTONFS(mp);
4329 if (!nmp || !NMFLAG(nmp, EPHEMERAL)) {
4330 return VFS_RETURNED;
4331 }
4332 hinfo->mountcount++;
4333
4334 /* avoid unmounting mounts that have been triggered within the last harvest interval */
4335 microtime(&now);
4336 if ((nmp->nm_mounttime >> 32) > ((uint32_t)now.tv_sec - NFS_EPHEMERAL_MOUNT_HARVEST_INTERVAL)) {
4337 return VFS_RETURNED;
4338 }
4339
4340 if (hinfo->fsid.val[0] || hinfo->fsid.val[1]) {
4341 /* attempt to unmount previously-found ephemeral mount */
4342 vfs_unmountbyfsid(&hinfo->fsid, 0, vfs_context_kernel());
4343 hinfo->fsid.val[0] = hinfo->fsid.val[1] = 0;
4344 }
4345
4346 /*
4347 * We can't call unmount here since we hold a mount iter ref
4348 * on mp so save its fsid for the next call iteration to unmount.
4349 */
4350 hinfo->fsid.val[0] = mp->mnt_vfsstat.f_fsid.val[0];
4351 hinfo->fsid.val[1] = mp->mnt_vfsstat.f_fsid.val[1];
4352
4353 return VFS_RETURNED;
4354 }
4355
4356 /*
4357 * Spawn a thread to do the ephemeral mount harvesting.
4358 */
4359 static void
4360 nfs_ephemeral_mount_harvester_timer_func(void)
4361 {
4362 thread_t thd;
4363
4364 if (kernel_thread_start(nfs_ephemeral_mount_harvester, NULL, &thd) == KERN_SUCCESS) {
4365 thread_deallocate(thd);
4366 }
4367 }
4368
4369 /*
4370 * Iterate all mounts looking for NFS ephemeral mounts to try to unmount.
4371 */
4372 void
4373 nfs_ephemeral_mount_harvester(__unused void *arg, __unused wait_result_t wr)
4374 {
4375 struct nfs_ephemeral_mount_harvester_info hinfo;
4376 uint64_t deadline;
4377
4378 hinfo.mountcount = 0;
4379 hinfo.fsid.val[0] = hinfo.fsid.val[1] = 0;
4380 vfs_iterate(VFS_ITERATE_TAIL_FIRST, nfs_ephemeral_mount_harvester_callback, &hinfo);
4381 if (hinfo.fsid.val[0] || hinfo.fsid.val[1]) {
4382 /* attempt to unmount last found ephemeral mount */
4383 vfs_unmountbyfsid(&hinfo.fsid, 0, vfs_context_kernel());
4384 }
4385
4386 lck_mtx_lock(nfs_global_mutex);
4387 if (!hinfo.mountcount) {
4388 /* no more ephemeral mounts - don't need timer */
4389 nfs_ephemeral_mount_harvester_on = 0;
4390 } else {
4391 /* re-arm the timer */
4392 clock_interval_to_deadline(NFS_EPHEMERAL_MOUNT_HARVEST_INTERVAL, NSEC_PER_SEC, &deadline);
4393 thread_call_enter_delayed(nfs_ephemeral_mount_harvester_timer, deadline);
4394 nfs_ephemeral_mount_harvester_on = 1;
4395 }
4396 lck_mtx_unlock(nfs_global_mutex);
4397
4398 /* thread done */
4399 thread_terminate(current_thread());
4400 }
4401
4402 /*
4403 * Make sure the NFS ephemeral mount harvester timer is running.
4404 */
4405 void
4406 nfs_ephemeral_mount_harvester_start(void)
4407 {
4408 uint64_t deadline;
4409
4410 lck_mtx_lock(nfs_global_mutex);
4411 if (nfs_ephemeral_mount_harvester_on) {
4412 lck_mtx_unlock(nfs_global_mutex);
4413 return;
4414 }
4415 if (nfs_ephemeral_mount_harvester_timer == NULL) {
4416 nfs_ephemeral_mount_harvester_timer = thread_call_allocate((thread_call_func_t)nfs_ephemeral_mount_harvester_timer_func, NULL);
4417 }
4418 clock_interval_to_deadline(NFS_EPHEMERAL_MOUNT_HARVEST_INTERVAL, NSEC_PER_SEC, &deadline);
4419 thread_call_enter_delayed(nfs_ephemeral_mount_harvester_timer, deadline);
4420 nfs_ephemeral_mount_harvester_on = 1;
4421 lck_mtx_unlock(nfs_global_mutex);
4422 }
4423
4424 #endif
4425
4426 /*
4427 * Send a MOUNT protocol MOUNT request to the server to get the initial file handle (and security).
4428 */
4429 int
4430 nfs3_mount_rpc(struct nfsmount *nmp, struct sockaddr *sa, int sotype, int nfsvers, char *path, vfs_context_t ctx, int timeo, fhandle_t *fh, struct nfs_sec *sec)
4431 {
4432 int error = 0, slen, mntproto;
4433 thread_t thd = vfs_context_thread(ctx);
4434 kauth_cred_t cred = vfs_context_ucred(ctx);
4435 uint64_t xid = 0;
4436 struct nfsm_chain nmreq, nmrep;
4437 mbuf_t mreq;
4438 uint32_t mntvers, mntport, val;
4439 struct sockaddr_storage ss;
4440 struct sockaddr *saddr = (struct sockaddr*)&ss;
4441
4442 nfsm_chain_null(&nmreq);
4443 nfsm_chain_null(&nmrep);
4444
4445 mntvers = (nfsvers == NFS_VER2) ? RPCMNT_VER1 : RPCMNT_VER3;
4446 mntproto = (NM_OMFLAG(nmp, MNTUDP) || (sotype == SOCK_DGRAM)) ? IPPROTO_UDP : IPPROTO_TCP;
4447 sec->count = 0;
4448
4449 bcopy(sa, saddr, min(sizeof(ss), sa->sa_len));
4450 if (saddr->sa_family == AF_INET) {
4451 if (nmp->nm_mountport) {
4452 ((struct sockaddr_in*)saddr)->sin_port = htons(nmp->nm_mountport);
4453 }
4454 mntport = ntohs(((struct sockaddr_in*)saddr)->sin_port);
4455 } else {
4456 if (nmp->nm_mountport) {
4457 ((struct sockaddr_in6*)saddr)->sin6_port = htons(nmp->nm_mountport);
4458 }
4459 mntport = ntohs(((struct sockaddr_in6*)saddr)->sin6_port);
4460 }
4461
4462 while (!mntport) {
4463 error = nfs_portmap_lookup(nmp, ctx, saddr, NULL, RPCPROG_MNT, mntvers, mntproto, timeo);
4464 nfsmout_if(error);
4465 if (saddr->sa_family == AF_INET) {
4466 mntport = ntohs(((struct sockaddr_in*)saddr)->sin_port);
4467 } else {
4468 mntport = ntohs(((struct sockaddr_in6*)saddr)->sin6_port);
4469 }
4470 if (!mntport) {
4471 /* if not found and TCP, then retry with UDP */
4472 if (mntproto == IPPROTO_UDP) {
4473 error = EPROGUNAVAIL;
4474 break;
4475 }
4476 mntproto = IPPROTO_UDP;
4477 bcopy(sa, saddr, min(sizeof(ss), sa->sa_len));
4478 }
4479 }
4480 nfsmout_if(error || !mntport);
4481
4482 /* MOUNT protocol MOUNT request */
4483 slen = strlen(path);
4484 nfsm_chain_build_alloc_init(error, &nmreq, NFSX_UNSIGNED + nfsm_rndup(slen));
4485 nfsm_chain_add_name(error, &nmreq, path, slen, nmp);
4486 nfsm_chain_build_done(error, &nmreq);
4487 nfsmout_if(error);
4488 error = nfsm_rpchead2(nmp, (mntproto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM,
4489 RPCPROG_MNT, mntvers, RPCMNT_MOUNT,
4490 RPCAUTH_SYS, cred, NULL, nmreq.nmc_mhead, &xid, &mreq);
4491 nfsmout_if(error);
4492 nmreq.nmc_mhead = NULL;
4493 error = nfs_aux_request(nmp, thd, saddr, NULL,
4494 ((mntproto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM),
4495 mreq, R_XID32(xid), 1, timeo, &nmrep);
4496 nfsmout_if(error);
4497 nfsm_chain_get_32(error, &nmrep, val);
4498 if (!error && val) {
4499 error = val;
4500 }
4501 nfsm_chain_get_fh(error, &nmrep, nfsvers, fh);
4502 if (!error && (nfsvers > NFS_VER2)) {
4503 sec->count = NX_MAX_SEC_FLAVORS;
4504 error = nfsm_chain_get_secinfo(&nmrep, &sec->flavors[0], &sec->count);
4505 }
4506 nfsmout:
4507 nfsm_chain_cleanup(&nmreq);
4508 nfsm_chain_cleanup(&nmrep);
4509 return error;
4510 }
4511
4512
4513 /*
4514 * Send a MOUNT protocol UNMOUNT request to tell the server we've unmounted it.
4515 */
4516 void
4517 nfs3_umount_rpc(struct nfsmount *nmp, vfs_context_t ctx, int timeo)
4518 {
4519 int error = 0, slen, mntproto;
4520 thread_t thd = vfs_context_thread(ctx);
4521 kauth_cred_t cred = vfs_context_ucred(ctx);
4522 char *path;
4523 uint64_t xid = 0;
4524 struct nfsm_chain nmreq, nmrep;
4525 mbuf_t mreq;
4526 uint32_t mntvers, mntport;
4527 struct sockaddr_storage ss;
4528 struct sockaddr *saddr = (struct sockaddr*)&ss;
4529
4530 if (!nmp->nm_saddr) {
4531 return;
4532 }
4533
4534 nfsm_chain_null(&nmreq);
4535 nfsm_chain_null(&nmrep);
4536
4537 mntvers = (nmp->nm_vers == NFS_VER2) ? RPCMNT_VER1 : RPCMNT_VER3;
4538 mntproto = (NM_OMFLAG(nmp, MNTUDP) || (nmp->nm_sotype == SOCK_DGRAM)) ? IPPROTO_UDP : IPPROTO_TCP;
4539 mntport = nmp->nm_mountport;
4540
4541 bcopy(nmp->nm_saddr, saddr, min(sizeof(ss), nmp->nm_saddr->sa_len));
4542 if (saddr->sa_family == AF_INET) {
4543 ((struct sockaddr_in*)saddr)->sin_port = htons(mntport);
4544 } else {
4545 ((struct sockaddr_in6*)saddr)->sin6_port = htons(mntport);
4546 }
4547
4548 while (!mntport) {
4549 error = nfs_portmap_lookup(nmp, ctx, saddr, NULL, RPCPROG_MNT, mntvers, mntproto, timeo);
4550 nfsmout_if(error);
4551 if (saddr->sa_family == AF_INET) {
4552 mntport = ntohs(((struct sockaddr_in*)saddr)->sin_port);
4553 } else {
4554 mntport = ntohs(((struct sockaddr_in6*)saddr)->sin6_port);
4555 }
4556 /* if not found and mntvers > VER1, then retry with VER1 */
4557 if (!mntport) {
4558 if (mntvers > RPCMNT_VER1) {
4559 mntvers = RPCMNT_VER1;
4560 } else if (mntproto == IPPROTO_TCP) {
4561 mntproto = IPPROTO_UDP;
4562 mntvers = (nmp->nm_vers == NFS_VER2) ? RPCMNT_VER1 : RPCMNT_VER3;
4563 } else {
4564 break;
4565 }
4566 bcopy(nmp->nm_saddr, saddr, min(sizeof(ss), nmp->nm_saddr->sa_len));
4567 }
4568 }
4569 nfsmout_if(!mntport);
4570
4571 /* MOUNT protocol UNMOUNT request */
4572 path = &vfs_statfs(nmp->nm_mountp)->f_mntfromname[0];
4573 while (*path && (*path != '/')) {
4574 path++;
4575 }
4576 slen = strlen(path);
4577 nfsm_chain_build_alloc_init(error, &nmreq, NFSX_UNSIGNED + nfsm_rndup(slen));
4578 nfsm_chain_add_name(error, &nmreq, path, slen, nmp);
4579 nfsm_chain_build_done(error, &nmreq);
4580 nfsmout_if(error);
4581 error = nfsm_rpchead2(nmp, (mntproto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM,
4582 RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMOUNT,
4583 RPCAUTH_SYS, cred, NULL, nmreq.nmc_mhead, &xid, &mreq);
4584 nfsmout_if(error);
4585 nmreq.nmc_mhead = NULL;
4586 error = nfs_aux_request(nmp, thd, saddr, NULL,
4587 ((mntproto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM),
4588 mreq, R_XID32(xid), 1, timeo, &nmrep);
4589 nfsmout:
4590 nfsm_chain_cleanup(&nmreq);
4591 nfsm_chain_cleanup(&nmrep);
4592 }
4593
4594 /*
4595 * unmount system call
4596 */
4597 int
4598 nfs_vfs_unmount(
4599 mount_t mp,
4600 int mntflags,
4601 __unused vfs_context_t ctx)
4602 {
4603 struct nfsmount *nmp;
4604 vnode_t vp;
4605 int error, flags = 0;
4606 struct timespec ts = { 1, 0 };
4607
4608 nmp = VFSTONFS(mp);
4609 lck_mtx_lock(&nmp->nm_lock);
4610 /*
4611 * Set the flag indicating that an unmount attempt is in progress.
4612 */
4613 nmp->nm_state |= NFSSTA_UNMOUNTING;
4614 /*
4615 * During a force unmount we want to...
4616 * Mark that we are doing a force unmount.
4617 * Make the mountpoint soft.
4618 */
4619 if (mntflags & MNT_FORCE) {
4620 flags |= FORCECLOSE;
4621 nmp->nm_state |= NFSSTA_FORCE;
4622 NFS_BITMAP_SET(nmp->nm_flags, NFS_MFLAG_SOFT);
4623 }
4624 /*
4625 * Wait for any in-progress monitored node scan to complete.
4626 */
4627 while (nmp->nm_state & NFSSTA_MONITOR_SCAN) {
4628 msleep(&nmp->nm_state, &nmp->nm_lock, PZERO - 1, "nfswaitmonscan", &ts);
4629 }
4630 /*
4631 * Goes something like this..
4632 * - Call vflush() to clear out vnodes for this file system,
4633 * except for the swap files. Deal with them in 2nd pass.
4634 * - Decrement reference on the vnode representing remote root.
4635 * - Clean up the NFS mount structure.
4636 */
4637 vp = NFSTOV(nmp->nm_dnp);
4638 lck_mtx_unlock(&nmp->nm_lock);
4639
4640 /*
4641 * vflush will check for busy vnodes on mountpoint.
4642 * Will do the right thing for MNT_FORCE. That is, we should
4643 * not get EBUSY back.
4644 */
4645 error = vflush(mp, vp, SKIPSWAP | flags);
4646 if (mntflags & MNT_FORCE) {
4647 error = vflush(mp, NULLVP, flags); /* locks vp in the process */
4648 } else {
4649 if (vnode_isinuse(vp, 1)) {
4650 error = EBUSY;
4651 } else {
4652 error = vflush(mp, vp, flags);
4653 }
4654 }
4655 if (error) {
4656 lck_mtx_lock(&nmp->nm_lock);
4657 nmp->nm_state &= ~NFSSTA_UNMOUNTING;
4658 lck_mtx_unlock(&nmp->nm_lock);
4659 return error;
4660 }
4661
4662 lck_mtx_lock(&nmp->nm_lock);
4663 nmp->nm_dnp = NULL;
4664 lck_mtx_unlock(&nmp->nm_lock);
4665
4666 /*
4667 * Release the root vnode reference held by mountnfs()
4668 */
4669 error = vnode_get(vp);
4670 vnode_rele(vp);
4671 if (!error) {
4672 vnode_put(vp);
4673 }
4674
4675 vflush(mp, NULLVP, FORCECLOSE);
4676
4677 /* Wait for all other references to be released and free the mount */
4678 nfs_mount_drain_and_cleanup(nmp);
4679
4680 return 0;
4681 }
4682
4683 /*
4684 * cleanup/destroy NFS fs locations structure
4685 */
4686 void
4687 nfs_fs_locations_cleanup(struct nfs_fs_locations *nfslsp)
4688 {
4689 struct nfs_fs_location *fsl;
4690 struct nfs_fs_server *fss;
4691 struct nfs_fs_path *fsp;
4692 uint32_t loc, serv, addr, comp;
4693
4694 /* free up fs locations */
4695 if (!nfslsp->nl_numlocs || !nfslsp->nl_locations) {
4696 return;
4697 }
4698
4699 for (loc = 0; loc < nfslsp->nl_numlocs; loc++) {
4700 fsl = nfslsp->nl_locations[loc];
4701 if (!fsl) {
4702 continue;
4703 }
4704 if ((fsl->nl_servcount > 0) && fsl->nl_servers) {
4705 for (serv = 0; serv < fsl->nl_servcount; serv++) {
4706 fss = fsl->nl_servers[serv];
4707 if (!fss) {
4708 continue;
4709 }
4710 if ((fss->ns_addrcount > 0) && fss->ns_addresses) {
4711 for (addr = 0; addr < fss->ns_addrcount; addr++) {
4712 FREE(fss->ns_addresses[addr], M_TEMP);
4713 }
4714 FREE(fss->ns_addresses, M_TEMP);
4715 }
4716 FREE(fss->ns_name, M_TEMP);
4717 FREE(fss, M_TEMP);
4718 }
4719 FREE(fsl->nl_servers, M_TEMP);
4720 }
4721 fsp = &fsl->nl_path;
4722 if (fsp->np_compcount && fsp->np_components) {
4723 for (comp = 0; comp < fsp->np_compcount; comp++) {
4724 if (fsp->np_components[comp]) {
4725 FREE(fsp->np_components[comp], M_TEMP);
4726 }
4727 }
4728 FREE(fsp->np_components, M_TEMP);
4729 }
4730 FREE(fsl, M_TEMP);
4731 }
4732 FREE(nfslsp->nl_locations, M_TEMP);
4733 nfslsp->nl_numlocs = 0;
4734 nfslsp->nl_locations = NULL;
4735 }
4736
4737 void
4738 nfs_mount_rele(struct nfsmount *nmp)
4739 {
4740 int wup = 0;
4741
4742 lck_mtx_lock(&nmp->nm_lock);
4743 if (nmp->nm_ref < 1) {
4744 panic("nfs zombie mount underflow\n");
4745 }
4746 nmp->nm_ref--;
4747 if (nmp->nm_ref == 0) {
4748 wup = nmp->nm_state & NFSSTA_MOUNT_DRAIN;
4749 }
4750 lck_mtx_unlock(&nmp->nm_lock);
4751 if (wup) {
4752 wakeup(&nmp->nm_ref);
4753 }
4754 }
4755
4756 void
4757 nfs_mount_drain_and_cleanup(struct nfsmount *nmp)
4758 {
4759 lck_mtx_lock(&nmp->nm_lock);
4760 nmp->nm_state |= NFSSTA_MOUNT_DRAIN;
4761 while (nmp->nm_ref > 0) {
4762 msleep(&nmp->nm_ref, &nmp->nm_lock, PZERO - 1, "nfs_mount_drain", NULL);
4763 }
4764 assert(nmp->nm_ref == 0);
4765 lck_mtx_unlock(&nmp->nm_lock);
4766 nfs_mount_cleanup(nmp);
4767 }
4768
4769 /*
4770 * nfs_mount_zombie
4771 */
4772 void
4773 nfs_mount_zombie(struct nfsmount *nmp, int nm_state_flags)
4774 {
4775 struct nfsreq *req, *treq;
4776 struct nfs_reqqhead iodq, resendq;
4777 struct timespec ts = { 1, 0 };
4778 struct nfs_open_owner *noop, *nextnoop;
4779 nfsnode_t np;
4780 int docallback;
4781
4782 lck_mtx_lock(&nmp->nm_lock);
4783 nmp->nm_state |= nm_state_flags;
4784 nmp->nm_ref++;
4785 lck_mtx_unlock(&nmp->nm_lock);
4786
4787 /* stop callbacks */
4788 if ((nmp->nm_vers >= NFS_VER4) && !NMFLAG(nmp, NOCALLBACK) && nmp->nm_cbid) {
4789 nfs4_mount_callback_shutdown(nmp);
4790 }
4791
4792 /* Destroy any RPCSEC_GSS contexts */
4793 nfs_gss_clnt_ctx_unmount(nmp);
4794
4795 /* mark the socket for termination */
4796 lck_mtx_lock(&nmp->nm_lock);
4797 nmp->nm_sockflags |= NMSOCK_UNMOUNT;
4798
4799 /* Have the socket thread send the unmount RPC, if requested/appropriate. */
4800 if ((nmp->nm_vers < NFS_VER4) && (nmp->nm_state & NFSSTA_MOUNTED) &&
4801 !(nmp->nm_state & (NFSSTA_FORCE | NFSSTA_DEAD)) && NMFLAG(nmp, CALLUMNT)) {
4802 nfs_mount_sock_thread_wake(nmp);
4803 }
4804
4805 /* wait for the socket thread to terminate */
4806 while (nmp->nm_sockthd && current_thread() != nmp->nm_sockthd) {
4807 wakeup(&nmp->nm_sockthd);
4808 msleep(&nmp->nm_sockthd, &nmp->nm_lock, PZERO - 1, "nfswaitsockthd", &ts);
4809 }
4810 lck_mtx_unlock(&nmp->nm_lock);
4811
4812 /* tear down the socket */
4813 nfs_disconnect(nmp);
4814
4815 lck_mtx_lock(&nmp->nm_lock);
4816
4817 if ((nmp->nm_vers >= NFS_VER4) && !NMFLAG(nmp, NOCALLBACK) && nmp->nm_cbid) {
4818 /* clear out any pending delegation return requests */
4819 while ((np = TAILQ_FIRST(&nmp->nm_dreturnq))) {
4820 TAILQ_REMOVE(&nmp->nm_dreturnq, np, n_dreturn);
4821 np->n_dreturn.tqe_next = NFSNOLIST;
4822 }
4823 }
4824
4825 /* cancel any renew timer */
4826 if ((nmp->nm_vers >= NFS_VER4) && nmp->nm_renew_timer) {
4827 thread_call_cancel(nmp->nm_renew_timer);
4828 thread_call_free(nmp->nm_renew_timer);
4829 nmp->nm_renew_timer = NULL;
4830 }
4831
4832 lck_mtx_unlock(&nmp->nm_lock);
4833
4834 if (nmp->nm_state & NFSSTA_MOUNTED) {
4835 switch (nmp->nm_lockmode) {
4836 case NFS_LOCK_MODE_DISABLED:
4837 case NFS_LOCK_MODE_LOCAL:
4838 break;
4839 case NFS_LOCK_MODE_ENABLED:
4840 default:
4841 if (nmp->nm_vers <= NFS_VER3) {
4842 nfs_lockd_mount_unregister(nmp);
4843 nmp->nm_lockmode = NFS_LOCK_MODE_DISABLED;
4844 }
4845 break;
4846 }
4847 }
4848
4849 if ((nmp->nm_vers >= NFS_VER4) && nmp->nm_longid) {
4850 /* remove/deallocate the client ID data */
4851 lck_mtx_lock(nfs_global_mutex);
4852 TAILQ_REMOVE(&nfsclientids, nmp->nm_longid, nci_link);
4853 if (nmp->nm_longid->nci_id) {
4854 FREE(nmp->nm_longid->nci_id, M_TEMP);
4855 }
4856 FREE(nmp->nm_longid, M_TEMP);
4857 nmp->nm_longid = NULL;
4858 lck_mtx_unlock(nfs_global_mutex);
4859 }
4860
4861 /*
4862 * Be sure all requests for this mount are completed
4863 * and removed from the resend queue.
4864 */
4865 TAILQ_INIT(&resendq);
4866 lck_mtx_lock(nfs_request_mutex);
4867 TAILQ_FOREACH(req, &nfs_reqq, r_chain) {
4868 if (req->r_nmp == nmp) {
4869 lck_mtx_lock(&req->r_mtx);
4870 if (!req->r_error && req->r_nmrep.nmc_mhead == NULL) {
4871 req->r_error = EIO;
4872 }
4873 if (req->r_flags & R_RESENDQ) {
4874 lck_mtx_lock(&nmp->nm_lock);
4875 req->r_flags &= ~R_RESENDQ;
4876 if (req->r_rchain.tqe_next != NFSREQNOLIST) {
4877 TAILQ_REMOVE(&nmp->nm_resendq, req, r_rchain);
4878 /*
4879 * Queue up the request so that we can unreference them
4880 * with out holding nfs_request_mutex
4881 */
4882 TAILQ_INSERT_TAIL(&resendq, req, r_rchain);
4883 }
4884 lck_mtx_unlock(&nmp->nm_lock);
4885 }
4886 wakeup(req);
4887 lck_mtx_unlock(&req->r_mtx);
4888 }
4889 }
4890 lck_mtx_unlock(nfs_request_mutex);
4891
4892 /* Since we've drop the request mutex we can now safely unreference the request */
4893 TAILQ_FOREACH_SAFE(req, &resendq, r_rchain, treq) {
4894 TAILQ_REMOVE(&resendq, req, r_rchain);
4895 /* Make sure we don't try and remove again in nfs_request_destroy */
4896 req->r_rchain.tqe_next = NFSREQNOLIST;
4897 nfs_request_rele(req);
4898 }
4899
4900 /*
4901 * Now handle and outstanding async requests. We need to walk the
4902 * request queue again this time with the nfsiod_mutex held. No
4903 * other iods can grab our requests until we've put them on our own
4904 * local iod queue for processing.
4905 */
4906 TAILQ_INIT(&iodq);
4907 lck_mtx_lock(nfs_request_mutex);
4908 lck_mtx_lock(nfsiod_mutex);
4909 TAILQ_FOREACH(req, &nfs_reqq, r_chain) {
4910 if (req->r_nmp == nmp) {
4911 lck_mtx_lock(&req->r_mtx);
4912 if (req->r_callback.rcb_func
4913 && !(req->r_flags & R_WAITSENT) && !(req->r_flags & R_IOD)) {
4914 /*
4915 * Since R_IOD is not set then we need to handle it. If
4916 * we're not on a list add it to our iod queue. Otherwise
4917 * we must already be on nm_iodq which is added to our
4918 * local queue below.
4919 * %%% We should really keep a back pointer to our iod queue
4920 * that we're on.
4921 */
4922 req->r_flags |= R_IOD;
4923 if (req->r_achain.tqe_next == NFSREQNOLIST) {
4924 TAILQ_INSERT_TAIL(&iodq, req, r_achain);
4925 }
4926 }
4927 lck_mtx_unlock(&req->r_mtx);
4928 }
4929 }
4930
4931 /* finish any async I/O RPCs queued up */
4932 if (nmp->nm_iodlink.tqe_next != NFSNOLIST) {
4933 TAILQ_REMOVE(&nfsiodmounts, nmp, nm_iodlink);
4934 }
4935 TAILQ_CONCAT(&iodq, &nmp->nm_iodq, r_achain);
4936 lck_mtx_unlock(nfsiod_mutex);
4937 lck_mtx_unlock(nfs_request_mutex);
4938
4939 TAILQ_FOREACH_SAFE(req, &iodq, r_achain, treq) {
4940 TAILQ_REMOVE(&iodq, req, r_achain);
4941 req->r_achain.tqe_next = NFSREQNOLIST;
4942 lck_mtx_lock(&req->r_mtx);
4943 docallback = !(req->r_flags & R_WAITSENT);
4944 lck_mtx_unlock(&req->r_mtx);
4945 if (docallback) {
4946 req->r_callback.rcb_func(req);
4947 }
4948 }
4949
4950 /* clean up common state */
4951 lck_mtx_lock(&nmp->nm_lock);
4952 while ((np = LIST_FIRST(&nmp->nm_monlist))) {
4953 LIST_REMOVE(np, n_monlink);
4954 np->n_monlink.le_next = NFSNOLIST;
4955 }
4956 TAILQ_FOREACH_SAFE(noop, &nmp->nm_open_owners, noo_link, nextnoop) {
4957 os_ref_count_t newcount;
4958
4959 TAILQ_REMOVE(&nmp->nm_open_owners, noop, noo_link);
4960 noop->noo_flags &= ~NFS_OPEN_OWNER_LINK;
4961 newcount = os_ref_release_locked(&noop->noo_refcnt);
4962
4963 if (newcount) {
4964 continue;
4965 }
4966 nfs_open_owner_destroy(noop);
4967 }
4968 lck_mtx_unlock(&nmp->nm_lock);
4969
4970 /* clean up NFSv4 state */
4971 if (nmp->nm_vers >= NFS_VER4) {
4972 lck_mtx_lock(&nmp->nm_lock);
4973 while ((np = TAILQ_FIRST(&nmp->nm_delegations))) {
4974 TAILQ_REMOVE(&nmp->nm_delegations, np, n_dlink);
4975 np->n_dlink.tqe_next = NFSNOLIST;
4976 }
4977 lck_mtx_unlock(&nmp->nm_lock);
4978 }
4979
4980 nfs_mount_rele(nmp);
4981 }
4982
4983 /*
4984 * cleanup/destroy an nfsmount
4985 */
4986 void
4987 nfs_mount_cleanup(struct nfsmount *nmp)
4988 {
4989 if (!nmp) {
4990 return;
4991 }
4992
4993 nfs_mount_zombie(nmp, 0);
4994
4995 NFS_VFS_DBG("Unmounting %s from %s\n",
4996 vfs_statfs(nmp->nm_mountp)->f_mntfromname,
4997 vfs_statfs(nmp->nm_mountp)->f_mntonname);
4998 NFS_VFS_DBG("nfs state = 0x%8.8x\n", nmp->nm_state);
4999 NFS_VFS_DBG("nfs socket flags = 0x%8.8x\n", nmp->nm_sockflags);
5000 NFS_VFS_DBG("nfs mount ref count is %d\n", nmp->nm_ref);
5001 NFS_VFS_DBG("mount ref count is %d\n", nmp->nm_mountp->mnt_count);
5002
5003 if (nmp->nm_mountp) {
5004 vfs_setfsprivate(nmp->nm_mountp, NULL);
5005 }
5006
5007 lck_mtx_lock(&nmp->nm_lock);
5008 if (nmp->nm_ref) {
5009 panic("Some one has grabbed a ref %d state flags = 0x%8.8x\n", nmp->nm_ref, nmp->nm_state);
5010 }
5011
5012 if (nmp->nm_saddr) {
5013 FREE(nmp->nm_saddr, M_SONAME);
5014 }
5015 if ((nmp->nm_vers < NFS_VER4) && nmp->nm_rqsaddr) {
5016 FREE(nmp->nm_rqsaddr, M_SONAME);
5017 }
5018
5019 if (IS_VALID_CRED(nmp->nm_mcred)) {
5020 kauth_cred_unref(&nmp->nm_mcred);
5021 }
5022
5023 nfs_fs_locations_cleanup(&nmp->nm_locations);
5024
5025 if (nmp->nm_realm) {
5026 FREE(nmp->nm_realm, M_TEMP);
5027 }
5028 if (nmp->nm_principal) {
5029 FREE(nmp->nm_principal, M_TEMP);
5030 }
5031 if (nmp->nm_sprinc) {
5032 FREE(nmp->nm_sprinc, M_TEMP);
5033 }
5034
5035 if (nmp->nm_args) {
5036 xb_free(nmp->nm_args);
5037 }
5038
5039 lck_mtx_unlock(&nmp->nm_lock);
5040
5041 lck_mtx_destroy(&nmp->nm_lock, nfs_mount_grp);
5042 if (nmp->nm_fh) {
5043 FREE(nmp->nm_fh, M_TEMP);
5044 }
5045 FREE_ZONE(nmp, sizeof(struct nfsmount), M_NFSMNT);
5046 }
5047
5048 /*
5049 * Return root of a filesystem
5050 */
5051 int
5052 nfs_vfs_root(mount_t mp, vnode_t *vpp, __unused vfs_context_t ctx)
5053 {
5054 vnode_t vp;
5055 struct nfsmount *nmp;
5056 int error;
5057 u_int32_t vpid;
5058
5059 nmp = VFSTONFS(mp);
5060 if (!nmp || !nmp->nm_dnp) {
5061 return ENXIO;
5062 }
5063 vp = NFSTOV(nmp->nm_dnp);
5064 vpid = vnode_vid(vp);
5065 while ((error = vnode_getwithvid(vp, vpid))) {
5066 /* vnode_get() may return ENOENT if the dir changes. */
5067 /* If that happens, just try it again, else return the error. */
5068 if ((error != ENOENT) || (vnode_vid(vp) == vpid)) {
5069 return error;
5070 }
5071 vpid = vnode_vid(vp);
5072 }
5073 *vpp = vp;
5074 return 0;
5075 }
5076
5077 /*
5078 * Do operations associated with quotas
5079 */
5080 #if !QUOTA
5081 int
5082 nfs_vfs_quotactl(
5083 __unused mount_t mp,
5084 __unused int cmds,
5085 __unused uid_t uid,
5086 __unused caddr_t datap,
5087 __unused vfs_context_t context)
5088 {
5089 return ENOTSUP;
5090 }
5091 #else
5092
5093 static int
5094 nfs_sa_getport(struct sockaddr *sa, int *error)
5095 {
5096 int port = 0;
5097
5098 if (sa->sa_family == AF_INET6) {
5099 port = ntohs(((struct sockaddr_in6*)sa)->sin6_port);
5100 } else if (sa->sa_family == AF_INET) {
5101 port = ntohs(((struct sockaddr_in*)sa)->sin_port);
5102 } else if (error) {
5103 *error = EIO;
5104 }
5105
5106 return port;
5107 }
5108
5109 static void
5110 nfs_sa_setport(struct sockaddr *sa, int port)
5111 {
5112 if (sa->sa_family == AF_INET6) {
5113 ((struct sockaddr_in6*)sa)->sin6_port = htons(port);
5114 } else if (sa->sa_family == AF_INET) {
5115 ((struct sockaddr_in*)sa)->sin_port = htons(port);
5116 }
5117 }
5118
5119 int
5120 nfs3_getquota(struct nfsmount *nmp, vfs_context_t ctx, uid_t id, int type, struct dqblk *dqb)
5121 {
5122 int error = 0, slen, timeo;
5123 int rqport = 0, rqproto, rqvers = (type == GRPQUOTA) ? RPCRQUOTA_EXT_VER : RPCRQUOTA_VER;
5124 thread_t thd = vfs_context_thread(ctx);
5125 kauth_cred_t cred = vfs_context_ucred(ctx);
5126 char *path;
5127 uint64_t xid = 0;
5128 struct nfsm_chain nmreq, nmrep;
5129 mbuf_t mreq;
5130 uint32_t val = 0, bsize = 0;
5131 struct sockaddr *rqsaddr;
5132 struct timeval now;
5133 struct timespec ts = { 1, 0 };
5134
5135 if (!nmp->nm_saddr) {
5136 return ENXIO;
5137 }
5138
5139 if (NMFLAG(nmp, NOQUOTA)) {
5140 return ENOTSUP;
5141 }
5142
5143 /*
5144 * Allocate an address for rquotad if needed
5145 */
5146 if (!nmp->nm_rqsaddr) {
5147 int need_free = 0;
5148
5149 MALLOC(rqsaddr, struct sockaddr *, sizeof(struct sockaddr_storage), M_SONAME, M_WAITOK | M_ZERO);
5150 bcopy(nmp->nm_saddr, rqsaddr, min(sizeof(struct sockaddr_storage), nmp->nm_saddr->sa_len));
5151 /* Set the port to zero, will call rpcbind to get the port below */
5152 nfs_sa_setport(rqsaddr, 0);
5153 microuptime(&now);
5154
5155 lck_mtx_lock(&nmp->nm_lock);
5156 if (!nmp->nm_rqsaddr) {
5157 nmp->nm_rqsaddr = rqsaddr;
5158 nmp->nm_rqsaddrstamp = now.tv_sec;
5159 } else {
5160 need_free = 1;
5161 }
5162 lck_mtx_unlock(&nmp->nm_lock);
5163 if (need_free) {
5164 FREE(rqsaddr, M_SONAME);
5165 }
5166 }
5167
5168 timeo = NMFLAG(nmp, SOFT) ? 10 : 60;
5169 rqproto = IPPROTO_UDP; /* XXX should prefer TCP if mount is TCP */
5170
5171 /* check if we have a recently cached rquota port */
5172 microuptime(&now);
5173 lck_mtx_lock(&nmp->nm_lock);
5174 rqsaddr = nmp->nm_rqsaddr;
5175 rqport = nfs_sa_getport(rqsaddr, &error);
5176 while (!error && (!rqport || ((nmp->nm_rqsaddrstamp + 60) <= (uint32_t)now.tv_sec))) {
5177 error = nfs_sigintr(nmp, NULL, thd, 1);
5178 if (error) {
5179 lck_mtx_unlock(&nmp->nm_lock);
5180 return error;
5181 }
5182 if (nmp->nm_state & NFSSTA_RQUOTAINPROG) {
5183 nmp->nm_state |= NFSSTA_WANTRQUOTA;
5184 msleep(&nmp->nm_rqsaddr, &nmp->nm_lock, PZERO - 1, "nfswaitrquotaaddr", &ts);
5185 rqport = nfs_sa_getport(rqsaddr, &error);
5186 continue;
5187 }
5188 nmp->nm_state |= NFSSTA_RQUOTAINPROG;
5189 lck_mtx_unlock(&nmp->nm_lock);
5190
5191 /* send portmap request to get rquota port */
5192 error = nfs_portmap_lookup(nmp, ctx, rqsaddr, NULL, RPCPROG_RQUOTA, rqvers, rqproto, timeo);
5193 if (error) {
5194 goto out;
5195 }
5196 rqport = nfs_sa_getport(rqsaddr, &error);
5197 if (error) {
5198 goto out;
5199 }
5200
5201 if (!rqport) {
5202 /*
5203 * We overload PMAPPORT for the port if rquotad is not
5204 * currently registered or up at the server. In the
5205 * while loop above, port will be set and we will defer
5206 * for a bit. Perhaps the service isn't online yet.
5207 *
5208 * Note that precludes using indirect, but we're not doing
5209 * that here.
5210 */
5211 rqport = PMAPPORT;
5212 nfs_sa_setport(rqsaddr, rqport);
5213 }
5214 microuptime(&now);
5215 nmp->nm_rqsaddrstamp = now.tv_sec;
5216 out:
5217 lck_mtx_lock(&nmp->nm_lock);
5218 nmp->nm_state &= ~NFSSTA_RQUOTAINPROG;
5219 if (nmp->nm_state & NFSSTA_WANTRQUOTA) {
5220 nmp->nm_state &= ~NFSSTA_WANTRQUOTA;
5221 wakeup(&nmp->nm_rqsaddr);
5222 }
5223 }
5224 lck_mtx_unlock(&nmp->nm_lock);
5225 if (error) {
5226 return error;
5227 }
5228
5229 /* Using PMAPPORT for unavailabe rquota service */
5230 if (rqport == PMAPPORT) {
5231 return ENOTSUP;
5232 }
5233
5234 /* rquota request */
5235 nfsm_chain_null(&nmreq);
5236 nfsm_chain_null(&nmrep);
5237 path = &vfs_statfs(nmp->nm_mountp)->f_mntfromname[0];
5238 while (*path && (*path != '/')) {
5239 path++;
5240 }
5241 slen = strlen(path);
5242 nfsm_chain_build_alloc_init(error, &nmreq, 3 * NFSX_UNSIGNED + nfsm_rndup(slen));
5243 nfsm_chain_add_name(error, &nmreq, path, slen, nmp);
5244 if (type == GRPQUOTA) {
5245 nfsm_chain_add_32(error, &nmreq, type);
5246 }
5247 nfsm_chain_add_32(error, &nmreq, id);
5248 nfsm_chain_build_done(error, &nmreq);
5249 nfsmout_if(error);
5250 error = nfsm_rpchead2(nmp, (rqproto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM,
5251 RPCPROG_RQUOTA, rqvers, RPCRQUOTA_GET,
5252 RPCAUTH_SYS, cred, NULL, nmreq.nmc_mhead, &xid, &mreq);
5253 nfsmout_if(error);
5254 nmreq.nmc_mhead = NULL;
5255 error = nfs_aux_request(nmp, thd, rqsaddr, NULL,
5256 (rqproto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM,
5257 mreq, R_XID32(xid), 0, timeo, &nmrep);
5258 nfsmout_if(error);
5259
5260 /* parse rquota response */
5261 nfsm_chain_get_32(error, &nmrep, val);
5262 if (!error && (val != RQUOTA_STAT_OK)) {
5263 if (val == RQUOTA_STAT_NOQUOTA) {
5264 error = ENOENT;
5265 } else if (val == RQUOTA_STAT_EPERM) {
5266 error = EPERM;
5267 } else {
5268 error = EIO;
5269 }
5270 }
5271 nfsm_chain_get_32(error, &nmrep, bsize);
5272 nfsm_chain_adv(error, &nmrep, NFSX_UNSIGNED);
5273 nfsm_chain_get_32(error, &nmrep, val);
5274 nfsmout_if(error);
5275 dqb->dqb_bhardlimit = (uint64_t)val * bsize;
5276 nfsm_chain_get_32(error, &nmrep, val);
5277 nfsmout_if(error);
5278 dqb->dqb_bsoftlimit = (uint64_t)val * bsize;
5279 nfsm_chain_get_32(error, &nmrep, val);
5280 nfsmout_if(error);
5281 dqb->dqb_curbytes = (uint64_t)val * bsize;
5282 nfsm_chain_get_32(error, &nmrep, dqb->dqb_ihardlimit);
5283 nfsm_chain_get_32(error, &nmrep, dqb->dqb_isoftlimit);
5284 nfsm_chain_get_32(error, &nmrep, dqb->dqb_curinodes);
5285 nfsm_chain_get_32(error, &nmrep, dqb->dqb_btime);
5286 nfsm_chain_get_32(error, &nmrep, dqb->dqb_itime);
5287 nfsmout_if(error);
5288 dqb->dqb_id = id;
5289 nfsmout:
5290 nfsm_chain_cleanup(&nmreq);
5291 nfsm_chain_cleanup(&nmrep);
5292 return error;
5293 }
5294
5295 int
5296 nfs4_getquota(struct nfsmount *nmp, vfs_context_t ctx, uid_t id, int type, struct dqblk *dqb)
5297 {
5298 nfsnode_t np;
5299 int error = 0, status, nfsvers, numops;
5300 u_int64_t xid;
5301 struct nfsm_chain nmreq, nmrep;
5302 uint32_t bitmap[NFS_ATTR_BITMAP_LEN];
5303 thread_t thd = vfs_context_thread(ctx);
5304 kauth_cred_t cred = vfs_context_ucred(ctx);
5305 struct nfsreq_secinfo_args si;
5306
5307 if (type != USRQUOTA) { /* NFSv4 only supports user quotas */
5308 return ENOTSUP;
5309 }
5310
5311 /* first check that the server supports any of the quota attributes */
5312 if (!NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_supp_attr, NFS_FATTR_QUOTA_AVAIL_HARD) &&
5313 !NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_supp_attr, NFS_FATTR_QUOTA_AVAIL_SOFT) &&
5314 !NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_supp_attr, NFS_FATTR_QUOTA_USED)) {
5315 return ENOTSUP;
5316 }
5317
5318 /*
5319 * The credential passed to the server needs to have
5320 * an effective uid that matches the given uid.
5321 */
5322 if (id != kauth_cred_getuid(cred)) {
5323 struct posix_cred temp_pcred;
5324 posix_cred_t pcred = posix_cred_get(cred);
5325 bzero(&temp_pcred, sizeof(temp_pcred));
5326 temp_pcred.cr_uid = id;
5327 temp_pcred.cr_ngroups = pcred->cr_ngroups;
5328 bcopy(pcred->cr_groups, temp_pcred.cr_groups, sizeof(temp_pcred.cr_groups));
5329 cred = posix_cred_create(&temp_pcred);
5330 if (!IS_VALID_CRED(cred)) {
5331 return ENOMEM;
5332 }
5333 } else {
5334 kauth_cred_ref(cred);
5335 }
5336
5337 nfsvers = nmp->nm_vers;
5338 np = nmp->nm_dnp;
5339 if (!np) {
5340 error = ENXIO;
5341 }
5342 if (error || ((error = vnode_get(NFSTOV(np))))) {
5343 kauth_cred_unref(&cred);
5344 return error;
5345 }
5346
5347 NFSREQ_SECINFO_SET(&si, np, NULL, 0, NULL, 0);
5348 nfsm_chain_null(&nmreq);
5349 nfsm_chain_null(&nmrep);
5350
5351 // PUTFH + GETATTR
5352 numops = 2;
5353 nfsm_chain_build_alloc_init(error, &nmreq, 15 * NFSX_UNSIGNED);
5354 nfsm_chain_add_compound_header(error, &nmreq, "quota", nmp->nm_minor_vers, numops);
5355 numops--;
5356 nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH);
5357 nfsm_chain_add_fh(error, &nmreq, nfsvers, np->n_fhp, np->n_fhsize);
5358 numops--;
5359 nfsm_chain_add_32(error, &nmreq, NFS_OP_GETATTR);
5360 NFS_CLEAR_ATTRIBUTES(bitmap);
5361 NFS_BITMAP_SET(bitmap, NFS_FATTR_QUOTA_AVAIL_HARD);
5362 NFS_BITMAP_SET(bitmap, NFS_FATTR_QUOTA_AVAIL_SOFT);
5363 NFS_BITMAP_SET(bitmap, NFS_FATTR_QUOTA_USED);
5364 nfsm_chain_add_bitmap_supported(error, &nmreq, bitmap, nmp, NULL);
5365 nfsm_chain_build_done(error, &nmreq);
5366 nfsm_assert(error, (numops == 0), EPROTO);
5367 nfsmout_if(error);
5368 error = nfs_request2(np, NULL, &nmreq, NFSPROC4_COMPOUND, thd, cred, &si, 0, &nmrep, &xid, &status);
5369 nfsm_chain_skip_tag(error, &nmrep);
5370 nfsm_chain_get_32(error, &nmrep, numops);
5371 nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
5372 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
5373 nfsm_assert(error, NFSTONMP(np), ENXIO);
5374 nfsmout_if(error);
5375 error = nfs4_parsefattr(&nmrep, NULL, NULL, NULL, dqb, NULL);
5376 nfsmout_if(error);
5377 nfsm_assert(error, NFSTONMP(np), ENXIO);
5378 nfsmout:
5379 nfsm_chain_cleanup(&nmreq);
5380 nfsm_chain_cleanup(&nmrep);
5381 vnode_put(NFSTOV(np));
5382 kauth_cred_unref(&cred);
5383 return error;
5384 }
5385
5386 int
5387 nfs_vfs_quotactl(mount_t mp, int cmds, uid_t uid, caddr_t datap, vfs_context_t ctx)
5388 {
5389 struct nfsmount *nmp;
5390 int cmd, type, error, nfsvers;
5391 uid_t euid = kauth_cred_getuid(vfs_context_ucred(ctx));
5392 struct dqblk *dqb = (struct dqblk*)datap;
5393
5394 nmp = VFSTONFS(mp);
5395 if (nfs_mount_gone(nmp)) {
5396 return ENXIO;
5397 }
5398 nfsvers = nmp->nm_vers;
5399
5400 if (uid == ~0U) {
5401 uid = euid;
5402 }
5403
5404 /* we can only support Q_GETQUOTA */
5405 cmd = cmds >> SUBCMDSHIFT;
5406 switch (cmd) {
5407 case Q_GETQUOTA:
5408 break;
5409 case Q_QUOTAON:
5410 case Q_QUOTAOFF:
5411 case Q_SETQUOTA:
5412 case Q_SETUSE:
5413 case Q_SYNC:
5414 case Q_QUOTASTAT:
5415 return ENOTSUP;
5416 default:
5417 return EINVAL;
5418 }
5419
5420 type = cmds & SUBCMDMASK;
5421 if ((u_int)type >= MAXQUOTAS) {
5422 return EINVAL;
5423 }
5424 if ((uid != euid) && ((error = vfs_context_suser(ctx)))) {
5425 return error;
5426 }
5427
5428 if (vfs_busy(mp, LK_NOWAIT)) {
5429 return 0;
5430 }
5431 bzero(dqb, sizeof(*dqb));
5432 error = nmp->nm_funcs->nf_getquota(nmp, ctx, uid, type, dqb);
5433 vfs_unbusy(mp);
5434 return error;
5435 }
5436 #endif
5437
5438 /*
5439 * Flush out the buffer cache
5440 */
5441 int nfs_sync_callout(vnode_t, void *);
5442
5443 struct nfs_sync_cargs {
5444 vfs_context_t ctx;
5445 int waitfor;
5446 int error;
5447 };
5448
5449 int
5450 nfs_sync_callout(vnode_t vp, void *arg)
5451 {
5452 struct nfs_sync_cargs *cargs = (struct nfs_sync_cargs*)arg;
5453 nfsnode_t np = VTONFS(vp);
5454 int error;
5455
5456 if (np->n_flag & NREVOKE) {
5457 vn_revoke(vp, REVOKEALL, cargs->ctx);
5458 return VNODE_RETURNED;
5459 }
5460
5461 if (LIST_EMPTY(&np->n_dirtyblkhd)) {
5462 return VNODE_RETURNED;
5463 }
5464 if (np->n_wrbusy > 0) {
5465 return VNODE_RETURNED;
5466 }
5467 if (np->n_bflag & (NBFLUSHINPROG | NBINVALINPROG)) {
5468 return VNODE_RETURNED;
5469 }
5470
5471 error = nfs_flush(np, cargs->waitfor, vfs_context_thread(cargs->ctx), 0);
5472 if (error) {
5473 cargs->error = error;
5474 }
5475
5476 return VNODE_RETURNED;
5477 }
5478
5479 int
5480 nfs_vfs_sync(mount_t mp, int waitfor, vfs_context_t ctx)
5481 {
5482 struct nfs_sync_cargs cargs;
5483
5484 cargs.waitfor = waitfor;
5485 cargs.ctx = ctx;
5486 cargs.error = 0;
5487
5488 vnode_iterate(mp, 0, nfs_sync_callout, &cargs);
5489
5490 return cargs.error;
5491 }
5492
5493 /*
5494 * NFS flat namespace lookup.
5495 * Currently unsupported.
5496 */
5497 /*ARGSUSED*/
5498 int
5499 nfs_vfs_vget(
5500 __unused mount_t mp,
5501 __unused ino64_t ino,
5502 __unused vnode_t *vpp,
5503 __unused vfs_context_t ctx)
5504 {
5505 return ENOTSUP;
5506 }
5507
5508 /*
5509 * At this point, this should never happen
5510 */
5511 /*ARGSUSED*/
5512 int
5513 nfs_vfs_fhtovp(
5514 __unused mount_t mp,
5515 __unused int fhlen,
5516 __unused unsigned char *fhp,
5517 __unused vnode_t *vpp,
5518 __unused vfs_context_t ctx)
5519 {
5520 return ENOTSUP;
5521 }
5522
5523 /*
5524 * Vnode pointer to File handle, should never happen either
5525 */
5526 /*ARGSUSED*/
5527 int
5528 nfs_vfs_vptofh(
5529 __unused vnode_t vp,
5530 __unused int *fhlenp,
5531 __unused unsigned char *fhp,
5532 __unused vfs_context_t ctx)
5533 {
5534 return ENOTSUP;
5535 }
5536
5537 /*
5538 * Vfs start routine, a no-op.
5539 */
5540 /*ARGSUSED*/
5541 int
5542 nfs_vfs_start(
5543 __unused mount_t mp,
5544 __unused int flags,
5545 __unused vfs_context_t ctx)
5546 {
5547 return 0;
5548 }
5549
5550 /*
5551 * Build the mount info buffer for NFS_MOUNTINFO.
5552 */
5553 int
5554 nfs_mountinfo_assemble(struct nfsmount *nmp, struct xdrbuf *xb)
5555 {
5556 struct xdrbuf xbinfo, xborig;
5557 char sotype[6];
5558 uint32_t origargsvers, origargslength;
5559 uint32_t infolength_offset, curargsopaquelength_offset, curargslength_offset, attrslength_offset, curargs_end_offset, end_offset;
5560 uint32_t miattrs[NFS_MIATTR_BITMAP_LEN];
5561 uint32_t miflags_mask[NFS_MIFLAG_BITMAP_LEN];
5562 uint32_t miflags[NFS_MIFLAG_BITMAP_LEN];
5563 uint32_t mattrs[NFS_MATTR_BITMAP_LEN];
5564 uint32_t mflags_mask[NFS_MFLAG_BITMAP_LEN];
5565 uint32_t mflags[NFS_MFLAG_BITMAP_LEN];
5566 uint32_t loc, serv, addr, comp;
5567 int i, timeo, error = 0;
5568
5569 /* set up mount info attr and flag bitmaps */
5570 NFS_BITMAP_ZERO(miattrs, NFS_MIATTR_BITMAP_LEN);
5571 NFS_BITMAP_SET(miattrs, NFS_MIATTR_FLAGS);
5572 NFS_BITMAP_SET(miattrs, NFS_MIATTR_ORIG_ARGS);
5573 NFS_BITMAP_SET(miattrs, NFS_MIATTR_CUR_ARGS);
5574 NFS_BITMAP_SET(miattrs, NFS_MIATTR_CUR_LOC_INDEX);
5575 NFS_BITMAP_ZERO(miflags_mask, NFS_MIFLAG_BITMAP_LEN);
5576 NFS_BITMAP_ZERO(miflags, NFS_MIFLAG_BITMAP_LEN);
5577 NFS_BITMAP_SET(miflags_mask, NFS_MIFLAG_DEAD);
5578 NFS_BITMAP_SET(miflags_mask, NFS_MIFLAG_NOTRESP);
5579 NFS_BITMAP_SET(miflags_mask, NFS_MIFLAG_RECOVERY);
5580 if (nmp->nm_state & NFSSTA_DEAD) {
5581 NFS_BITMAP_SET(miflags, NFS_MIFLAG_DEAD);
5582 }
5583 if ((nmp->nm_state & (NFSSTA_TIMEO | NFSSTA_JUKEBOXTIMEO)) ||
5584 ((nmp->nm_state & NFSSTA_LOCKTIMEO) && (nmp->nm_lockmode == NFS_LOCK_MODE_ENABLED))) {
5585 NFS_BITMAP_SET(miflags, NFS_MIFLAG_NOTRESP);
5586 }
5587 if (nmp->nm_state & NFSSTA_RECOVER) {
5588 NFS_BITMAP_SET(miflags, NFS_MIFLAG_RECOVERY);
5589 }
5590
5591 /* get original mount args length */
5592 xb_init_buffer(&xborig, nmp->nm_args, 2 * XDRWORD);
5593 xb_get_32(error, &xborig, origargsvers); /* version */
5594 xb_get_32(error, &xborig, origargslength); /* args length */
5595 nfsmerr_if(error);
5596
5597 /* set up current mount attributes bitmap */
5598 NFS_BITMAP_ZERO(mattrs, NFS_MATTR_BITMAP_LEN);
5599 NFS_BITMAP_SET(mattrs, NFS_MATTR_FLAGS);
5600 NFS_BITMAP_SET(mattrs, NFS_MATTR_NFS_VERSION);
5601 if (nmp->nm_vers >= NFS_VER4) {
5602 NFS_BITMAP_SET(mattrs, NFS_MATTR_NFS_MINOR_VERSION);
5603 }
5604 NFS_BITMAP_SET(mattrs, NFS_MATTR_READ_SIZE);
5605 NFS_BITMAP_SET(mattrs, NFS_MATTR_WRITE_SIZE);
5606 NFS_BITMAP_SET(mattrs, NFS_MATTR_READDIR_SIZE);
5607 NFS_BITMAP_SET(mattrs, NFS_MATTR_READAHEAD);
5608 NFS_BITMAP_SET(mattrs, NFS_MATTR_ATTRCACHE_REG_MIN);
5609 NFS_BITMAP_SET(mattrs, NFS_MATTR_ATTRCACHE_REG_MAX);
5610 NFS_BITMAP_SET(mattrs, NFS_MATTR_ATTRCACHE_DIR_MIN);
5611 NFS_BITMAP_SET(mattrs, NFS_MATTR_ATTRCACHE_DIR_MAX);
5612 NFS_BITMAP_SET(mattrs, NFS_MATTR_LOCK_MODE);
5613 NFS_BITMAP_SET(mattrs, NFS_MATTR_SECURITY);
5614 if (nmp->nm_etype.selected < nmp->nm_etype.count) {
5615 NFS_BITMAP_SET(mattrs, NFS_MATTR_KERB_ETYPE);
5616 }
5617 NFS_BITMAP_SET(mattrs, NFS_MATTR_MAX_GROUP_LIST);
5618 NFS_BITMAP_SET(mattrs, NFS_MATTR_SOCKET_TYPE);
5619 NFS_BITMAP_SET(mattrs, NFS_MATTR_NFS_PORT);
5620 if ((nmp->nm_vers < NFS_VER4) && nmp->nm_mountport) {
5621 NFS_BITMAP_SET(mattrs, NFS_MATTR_MOUNT_PORT);
5622 }
5623 NFS_BITMAP_SET(mattrs, NFS_MATTR_REQUEST_TIMEOUT);
5624 if (NMFLAG(nmp, SOFT)) {
5625 NFS_BITMAP_SET(mattrs, NFS_MATTR_SOFT_RETRY_COUNT);
5626 }
5627 if (nmp->nm_deadtimeout) {
5628 NFS_BITMAP_SET(mattrs, NFS_MATTR_DEAD_TIMEOUT);
5629 }
5630 if (nmp->nm_fh) {
5631 NFS_BITMAP_SET(mattrs, NFS_MATTR_FH);
5632 }
5633 NFS_BITMAP_SET(mattrs, NFS_MATTR_FS_LOCATIONS);
5634 NFS_BITMAP_SET(mattrs, NFS_MATTR_MNTFLAGS);
5635 if (origargsvers < NFS_ARGSVERSION_XDR) {
5636 NFS_BITMAP_SET(mattrs, NFS_MATTR_MNTFROM);
5637 }
5638 if (nmp->nm_realm) {
5639 NFS_BITMAP_SET(mattrs, NFS_MATTR_REALM);
5640 }
5641 if (nmp->nm_principal) {
5642 NFS_BITMAP_SET(mattrs, NFS_MATTR_PRINCIPAL);
5643 }
5644 if (nmp->nm_sprinc) {
5645 NFS_BITMAP_SET(mattrs, NFS_MATTR_SVCPRINCIPAL);
5646 }
5647
5648 /* set up current mount flags bitmap */
5649 /* first set the flags that we will be setting - either on OR off */
5650 NFS_BITMAP_ZERO(mflags_mask, NFS_MFLAG_BITMAP_LEN);
5651 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_SOFT);
5652 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_INTR);
5653 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_RESVPORT);
5654 if (nmp->nm_sotype == SOCK_DGRAM) {
5655 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_NOCONNECT);
5656 }
5657 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_DUMBTIMER);
5658 if (nmp->nm_vers < NFS_VER4) {
5659 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_CALLUMNT);
5660 }
5661 if (nmp->nm_vers >= NFS_VER3) {
5662 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_RDIRPLUS);
5663 }
5664 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_NONEGNAMECACHE);
5665 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_MUTEJUKEBOX);
5666 if (nmp->nm_vers >= NFS_VER4) {
5667 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_EPHEMERAL);
5668 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_NOCALLBACK);
5669 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_NAMEDATTR);
5670 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_NOACL);
5671 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_ACLONLY);
5672 }
5673 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_NFC);
5674 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_NOQUOTA);
5675 if (nmp->nm_vers < NFS_VER4) {
5676 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_MNTUDP);
5677 }
5678 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_MNTQUICK);
5679 /* now set the flags that should be set */
5680 NFS_BITMAP_ZERO(mflags, NFS_MFLAG_BITMAP_LEN);
5681 if (NMFLAG(nmp, SOFT)) {
5682 NFS_BITMAP_SET(mflags, NFS_MFLAG_SOFT);
5683 }
5684 if (NMFLAG(nmp, INTR)) {
5685 NFS_BITMAP_SET(mflags, NFS_MFLAG_INTR);
5686 }
5687 if (NMFLAG(nmp, RESVPORT)) {
5688 NFS_BITMAP_SET(mflags, NFS_MFLAG_RESVPORT);
5689 }
5690 if ((nmp->nm_sotype == SOCK_DGRAM) && NMFLAG(nmp, NOCONNECT)) {
5691 NFS_BITMAP_SET(mflags, NFS_MFLAG_NOCONNECT);
5692 }
5693 if (NMFLAG(nmp, DUMBTIMER)) {
5694 NFS_BITMAP_SET(mflags, NFS_MFLAG_DUMBTIMER);
5695 }
5696 if ((nmp->nm_vers < NFS_VER4) && NMFLAG(nmp, CALLUMNT)) {
5697 NFS_BITMAP_SET(mflags, NFS_MFLAG_CALLUMNT);
5698 }
5699 if ((nmp->nm_vers >= NFS_VER3) && NMFLAG(nmp, RDIRPLUS)) {
5700 NFS_BITMAP_SET(mflags, NFS_MFLAG_RDIRPLUS);
5701 }
5702 if (NMFLAG(nmp, NONEGNAMECACHE)) {
5703 NFS_BITMAP_SET(mflags, NFS_MFLAG_NONEGNAMECACHE);
5704 }
5705 if (NMFLAG(nmp, MUTEJUKEBOX)) {
5706 NFS_BITMAP_SET(mflags, NFS_MFLAG_MUTEJUKEBOX);
5707 }
5708 if (nmp->nm_vers >= NFS_VER4) {
5709 if (NMFLAG(nmp, EPHEMERAL)) {
5710 NFS_BITMAP_SET(mflags, NFS_MFLAG_EPHEMERAL);
5711 }
5712 if (NMFLAG(nmp, NOCALLBACK)) {
5713 NFS_BITMAP_SET(mflags, NFS_MFLAG_NOCALLBACK);
5714 }
5715 if (NMFLAG(nmp, NAMEDATTR)) {
5716 NFS_BITMAP_SET(mflags, NFS_MFLAG_NAMEDATTR);
5717 }
5718 if (NMFLAG(nmp, NOACL)) {
5719 NFS_BITMAP_SET(mflags, NFS_MFLAG_NOACL);
5720 }
5721 if (NMFLAG(nmp, ACLONLY)) {
5722 NFS_BITMAP_SET(mflags, NFS_MFLAG_ACLONLY);
5723 }
5724 }
5725 if (NMFLAG(nmp, NFC)) {
5726 NFS_BITMAP_SET(mflags, NFS_MFLAG_NFC);
5727 }
5728 if (NMFLAG(nmp, NOQUOTA) || ((nmp->nm_vers >= NFS_VER4) &&
5729 !NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_supp_attr, NFS_FATTR_QUOTA_AVAIL_HARD) &&
5730 !NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_supp_attr, NFS_FATTR_QUOTA_AVAIL_SOFT) &&
5731 !NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_supp_attr, NFS_FATTR_QUOTA_USED))) {
5732 NFS_BITMAP_SET(mflags, NFS_MFLAG_NOQUOTA);
5733 }
5734 if ((nmp->nm_vers < NFS_VER4) && NMFLAG(nmp, MNTUDP)) {
5735 NFS_BITMAP_SET(mflags, NFS_MFLAG_MNTUDP);
5736 }
5737 if (NMFLAG(nmp, MNTQUICK)) {
5738 NFS_BITMAP_SET(mflags, NFS_MFLAG_MNTQUICK);
5739 }
5740
5741 /* assemble info buffer: */
5742 xb_init_buffer(&xbinfo, NULL, 0);
5743 xb_add_32(error, &xbinfo, NFS_MOUNT_INFO_VERSION);
5744 infolength_offset = xb_offset(&xbinfo);
5745 xb_add_32(error, &xbinfo, 0);
5746 xb_add_bitmap(error, &xbinfo, miattrs, NFS_MIATTR_BITMAP_LEN);
5747 xb_add_bitmap(error, &xbinfo, miflags, NFS_MIFLAG_BITMAP_LEN);
5748 xb_add_32(error, &xbinfo, origargslength);
5749 if (!error) {
5750 error = xb_add_bytes(&xbinfo, nmp->nm_args, origargslength, 0);
5751 }
5752
5753 /* the opaque byte count for the current mount args values: */
5754 curargsopaquelength_offset = xb_offset(&xbinfo);
5755 xb_add_32(error, &xbinfo, 0);
5756
5757 /* Encode current mount args values */
5758 xb_add_32(error, &xbinfo, NFS_ARGSVERSION_XDR);
5759 curargslength_offset = xb_offset(&xbinfo);
5760 xb_add_32(error, &xbinfo, 0);
5761 xb_add_32(error, &xbinfo, NFS_XDRARGS_VERSION_0);
5762 xb_add_bitmap(error, &xbinfo, mattrs, NFS_MATTR_BITMAP_LEN);
5763 attrslength_offset = xb_offset(&xbinfo);
5764 xb_add_32(error, &xbinfo, 0);
5765 xb_add_bitmap(error, &xbinfo, mflags_mask, NFS_MFLAG_BITMAP_LEN);
5766 xb_add_bitmap(error, &xbinfo, mflags, NFS_MFLAG_BITMAP_LEN);
5767 xb_add_32(error, &xbinfo, nmp->nm_vers); /* NFS_VERSION */
5768 if (nmp->nm_vers >= NFS_VER4) {
5769 xb_add_32(error, &xbinfo, nmp->nm_minor_vers); /* NFS_MINOR_VERSION */
5770 }
5771 xb_add_32(error, &xbinfo, nmp->nm_rsize); /* READ_SIZE */
5772 xb_add_32(error, &xbinfo, nmp->nm_wsize); /* WRITE_SIZE */
5773 xb_add_32(error, &xbinfo, nmp->nm_readdirsize); /* READDIR_SIZE */
5774 xb_add_32(error, &xbinfo, nmp->nm_readahead); /* READAHEAD */
5775 xb_add_32(error, &xbinfo, nmp->nm_acregmin); /* ATTRCACHE_REG_MIN */
5776 xb_add_32(error, &xbinfo, 0); /* ATTRCACHE_REG_MIN */
5777 xb_add_32(error, &xbinfo, nmp->nm_acregmax); /* ATTRCACHE_REG_MAX */
5778 xb_add_32(error, &xbinfo, 0); /* ATTRCACHE_REG_MAX */
5779 xb_add_32(error, &xbinfo, nmp->nm_acdirmin); /* ATTRCACHE_DIR_MIN */
5780 xb_add_32(error, &xbinfo, 0); /* ATTRCACHE_DIR_MIN */
5781 xb_add_32(error, &xbinfo, nmp->nm_acdirmax); /* ATTRCACHE_DIR_MAX */
5782 xb_add_32(error, &xbinfo, 0); /* ATTRCACHE_DIR_MAX */
5783 xb_add_32(error, &xbinfo, nmp->nm_lockmode); /* LOCK_MODE */
5784 if (nmp->nm_sec.count) {
5785 xb_add_32(error, &xbinfo, nmp->nm_sec.count); /* SECURITY */
5786 nfsmerr_if(error);
5787 for (i = 0; i < nmp->nm_sec.count; i++) {
5788 xb_add_32(error, &xbinfo, nmp->nm_sec.flavors[i]);
5789 }
5790 } else if (nmp->nm_servsec.count) {
5791 xb_add_32(error, &xbinfo, nmp->nm_servsec.count); /* SECURITY */
5792 nfsmerr_if(error);
5793 for (i = 0; i < nmp->nm_servsec.count; i++) {
5794 xb_add_32(error, &xbinfo, nmp->nm_servsec.flavors[i]);
5795 }
5796 } else {
5797 xb_add_32(error, &xbinfo, 1); /* SECURITY */
5798 xb_add_32(error, &xbinfo, nmp->nm_auth);
5799 }
5800 if (nmp->nm_etype.selected < nmp->nm_etype.count) {
5801 xb_add_32(error, &xbinfo, nmp->nm_etype.count);
5802 xb_add_32(error, &xbinfo, nmp->nm_etype.selected);
5803 for (uint32_t j = 0; j < nmp->nm_etype.count; j++) {
5804 xb_add_32(error, &xbinfo, nmp->nm_etype.etypes[j]);
5805 }
5806 nfsmerr_if(error);
5807 }
5808 xb_add_32(error, &xbinfo, nmp->nm_numgrps); /* MAX_GROUP_LIST */
5809 nfsmerr_if(error);
5810 snprintf(sotype, sizeof(sotype), "%s%s", (nmp->nm_sotype == SOCK_DGRAM) ? "udp" : "tcp",
5811 nmp->nm_sofamily ? (nmp->nm_sofamily == AF_INET) ? "4" : "6" : "");
5812 xb_add_string(error, &xbinfo, sotype, strlen(sotype)); /* SOCKET_TYPE */
5813 xb_add_32(error, &xbinfo, ntohs(((struct sockaddr_in*)nmp->nm_saddr)->sin_port)); /* NFS_PORT */
5814 if ((nmp->nm_vers < NFS_VER4) && nmp->nm_mountport) {
5815 xb_add_32(error, &xbinfo, nmp->nm_mountport); /* MOUNT_PORT */
5816 }
5817 timeo = (nmp->nm_timeo * 10) / NFS_HZ;
5818 xb_add_32(error, &xbinfo, timeo / 10); /* REQUEST_TIMEOUT */
5819 xb_add_32(error, &xbinfo, (timeo % 10) * 100000000); /* REQUEST_TIMEOUT */
5820 if (NMFLAG(nmp, SOFT)) {
5821 xb_add_32(error, &xbinfo, nmp->nm_retry); /* SOFT_RETRY_COUNT */
5822 }
5823 if (nmp->nm_deadtimeout) {
5824 xb_add_32(error, &xbinfo, nmp->nm_deadtimeout); /* DEAD_TIMEOUT */
5825 xb_add_32(error, &xbinfo, 0); /* DEAD_TIMEOUT */
5826 }
5827 if (nmp->nm_fh) {
5828 xb_add_fh(error, &xbinfo, &nmp->nm_fh->fh_data[0], nmp->nm_fh->fh_len); /* FH */
5829 }
5830 xb_add_32(error, &xbinfo, nmp->nm_locations.nl_numlocs); /* FS_LOCATIONS */
5831 for (loc = 0; !error && (loc < nmp->nm_locations.nl_numlocs); loc++) {
5832 xb_add_32(error, &xbinfo, nmp->nm_locations.nl_locations[loc]->nl_servcount);
5833 for (serv = 0; !error && (serv < nmp->nm_locations.nl_locations[loc]->nl_servcount); serv++) {
5834 xb_add_string(error, &xbinfo, nmp->nm_locations.nl_locations[loc]->nl_servers[serv]->ns_name,
5835 strlen(nmp->nm_locations.nl_locations[loc]->nl_servers[serv]->ns_name));
5836 xb_add_32(error, &xbinfo, nmp->nm_locations.nl_locations[loc]->nl_servers[serv]->ns_addrcount);
5837 for (addr = 0; !error && (addr < nmp->nm_locations.nl_locations[loc]->nl_servers[serv]->ns_addrcount); addr++) {
5838 xb_add_string(error, &xbinfo, nmp->nm_locations.nl_locations[loc]->nl_servers[serv]->ns_addresses[addr],
5839 strlen(nmp->nm_locations.nl_locations[loc]->nl_servers[serv]->ns_addresses[addr]));
5840 }
5841 xb_add_32(error, &xbinfo, 0); /* empty server info */
5842 }
5843 xb_add_32(error, &xbinfo, nmp->nm_locations.nl_locations[loc]->nl_path.np_compcount);
5844 for (comp = 0; !error && (comp < nmp->nm_locations.nl_locations[loc]->nl_path.np_compcount); comp++) {
5845 xb_add_string(error, &xbinfo, nmp->nm_locations.nl_locations[loc]->nl_path.np_components[comp],
5846 strlen(nmp->nm_locations.nl_locations[loc]->nl_path.np_components[comp]));
5847 }
5848 xb_add_32(error, &xbinfo, 0); /* empty fs location info */
5849 }
5850 xb_add_32(error, &xbinfo, vfs_flags(nmp->nm_mountp)); /* MNTFLAGS */
5851 if (origargsvers < NFS_ARGSVERSION_XDR) {
5852 xb_add_string(error, &xbinfo, vfs_statfs(nmp->nm_mountp)->f_mntfromname,
5853 strlen(vfs_statfs(nmp->nm_mountp)->f_mntfromname)); /* MNTFROM */
5854 }
5855 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_REALM)) {
5856 xb_add_string(error, &xbinfo, nmp->nm_realm, strlen(nmp->nm_realm));
5857 }
5858 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_PRINCIPAL)) {
5859 xb_add_string(error, &xbinfo, nmp->nm_principal, strlen(nmp->nm_principal));
5860 }
5861 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_SVCPRINCIPAL)) {
5862 xb_add_string(error, &xbinfo, nmp->nm_sprinc, strlen(nmp->nm_sprinc));
5863 }
5864
5865 curargs_end_offset = xb_offset(&xbinfo);
5866
5867 /* NFS_MIATTR_CUR_LOC_INDEX */
5868 xb_add_32(error, &xbinfo, nmp->nm_locations.nl_current.nli_flags);
5869 xb_add_32(error, &xbinfo, nmp->nm_locations.nl_current.nli_loc);
5870 xb_add_32(error, &xbinfo, nmp->nm_locations.nl_current.nli_serv);
5871 xb_add_32(error, &xbinfo, nmp->nm_locations.nl_current.nli_addr);
5872
5873 xb_build_done(error, &xbinfo);
5874
5875 /* update opaque counts */
5876 end_offset = xb_offset(&xbinfo);
5877 if (!error) {
5878 error = xb_seek(&xbinfo, attrslength_offset);
5879 xb_add_32(error, &xbinfo, curargs_end_offset - attrslength_offset - XDRWORD /*don't include length field*/);
5880 }
5881 if (!error) {
5882 error = xb_seek(&xbinfo, curargslength_offset);
5883 xb_add_32(error, &xbinfo, curargs_end_offset - curargslength_offset + XDRWORD /*version*/);
5884 }
5885 if (!error) {
5886 error = xb_seek(&xbinfo, curargsopaquelength_offset);
5887 xb_add_32(error, &xbinfo, curargs_end_offset - curargslength_offset + XDRWORD /*version*/);
5888 }
5889 if (!error) {
5890 error = xb_seek(&xbinfo, infolength_offset);
5891 xb_add_32(error, &xbinfo, end_offset - infolength_offset + XDRWORD /*version*/);
5892 }
5893 nfsmerr_if(error);
5894
5895 /* copy result xdrbuf to caller */
5896 *xb = xbinfo;
5897
5898 /* and mark the local copy as not needing cleanup */
5899 xbinfo.xb_flags &= ~XB_CLEANUP;
5900 nfsmerr:
5901 xb_cleanup(&xbinfo);
5902 return error;
5903 }
5904
5905 /*
5906 * Do that sysctl thang...
5907 */
5908 int
5909 nfs_vfs_sysctl(int *name, u_int namelen, user_addr_t oldp, size_t *oldlenp,
5910 user_addr_t newp, size_t newlen, vfs_context_t ctx)
5911 {
5912 int error = 0, val;
5913 #ifndef CONFIG_EMBEDDED
5914 int softnobrowse;
5915 #endif
5916 struct sysctl_req *req = NULL;
5917 union union_vfsidctl vc;
5918 mount_t mp;
5919 struct nfsmount *nmp = NULL;
5920 struct vfsquery vq;
5921 struct nfsreq *rq;
5922 boolean_t is_64_bit;
5923 fsid_t fsid;
5924 struct xdrbuf xb;
5925 struct netfs_status *nsp = NULL;
5926 int timeoutmask;
5927 uint pos, totlen, count, numThreads;
5928 #if NFSSERVER
5929 struct nfs_exportfs *nxfs;
5930 struct nfs_export *nx;
5931 struct nfs_active_user_list *ulist;
5932 struct nfs_export_stat_desc stat_desc = {};
5933 struct nfs_export_stat_rec statrec;
5934 struct nfs_user_stat_node *unode, *unode_next;
5935 struct nfs_user_stat_desc ustat_desc = {};
5936 struct nfs_user_stat_user_rec ustat_rec;
5937 struct nfs_user_stat_path_rec upath_rec;
5938 uint bytes_avail, bytes_total, recs_copied;
5939 uint numExports, numRecs;
5940 #endif /* NFSSERVER */
5941
5942 /*
5943 * All names at this level are terminal.
5944 */
5945 if (namelen > 1) {
5946 return ENOTDIR; /* overloaded */
5947 }
5948 is_64_bit = vfs_context_is64bit(ctx);
5949
5950 /* common code for "new style" VFS_CTL sysctl, get the mount. */
5951 switch (name[0]) {
5952 case VFS_CTL_TIMEO:
5953 case VFS_CTL_NOLOCKS:
5954 case VFS_CTL_NSTATUS:
5955 #ifndef CONFIG_EMBEDDED
5956 case VFS_CTL_QUERY:
5957 #endif
5958 req = CAST_DOWN(struct sysctl_req *, oldp);
5959 if (req == NULL) {
5960 return EFAULT;
5961 }
5962 error = SYSCTL_IN(req, &vc, is_64_bit? sizeof(vc.vc64):sizeof(vc.vc32));
5963 if (error) {
5964 return error;
5965 }
5966 mp = vfs_getvfs(&vc.vc32.vc_fsid); /* works for 32 and 64 */
5967 if (mp == NULL) {
5968 return ENOENT;
5969 }
5970 nmp = VFSTONFS(mp);
5971 if (!nmp) {
5972 return ENOENT;
5973 }
5974 bzero(&vq, sizeof(vq));
5975 req->newidx = 0;
5976 if (is_64_bit) {
5977 req->newptr = vc.vc64.vc_ptr;
5978 req->newlen = (size_t)vc.vc64.vc_len;
5979 } else {
5980 req->newptr = CAST_USER_ADDR_T(vc.vc32.vc_ptr);
5981 req->newlen = vc.vc32.vc_len;
5982 }
5983 break;
5984 #if CONFIG_EMBEDDED
5985 case VFS_CTL_QUERY:
5986 return EPERM;
5987 #endif
5988 }
5989
5990 switch (name[0]) {
5991 case NFS_NFSSTATS:
5992 if (!oldp) {
5993 *oldlenp = sizeof nfsstats;
5994 return 0;
5995 }
5996
5997 if (*oldlenp < sizeof nfsstats) {
5998 *oldlenp = sizeof nfsstats;
5999 return ENOMEM;
6000 }
6001
6002 error = copyout(&nfsstats, oldp, sizeof nfsstats);
6003 if (error) {
6004 return error;
6005 }
6006
6007 if (newp && newlen != sizeof nfsstats) {
6008 return EINVAL;
6009 }
6010
6011 if (newp) {
6012 return copyin(newp, &nfsstats, sizeof nfsstats);
6013 }
6014 return 0;
6015 case NFS_MOUNTINFO:
6016 /* read in the fsid */
6017 if (*oldlenp < sizeof(fsid)) {
6018 return EINVAL;
6019 }
6020 if ((error = copyin(oldp, &fsid, sizeof(fsid)))) {
6021 return error;
6022 }
6023 /* swizzle it back to host order */
6024 fsid.val[0] = ntohl(fsid.val[0]);
6025 fsid.val[1] = ntohl(fsid.val[1]);
6026 /* find mount and make sure it's NFS */
6027 if (((mp = vfs_getvfs(&fsid))) == NULL) {
6028 return ENOENT;
6029 }
6030 if (strcmp(mp->mnt_vfsstat.f_fstypename, "nfs")) {
6031 return EINVAL;
6032 }
6033 if (((nmp = VFSTONFS(mp))) == NULL) {
6034 return ENOENT;
6035 }
6036 xb_init(&xb, 0);
6037 if ((error = nfs_mountinfo_assemble(nmp, &xb))) {
6038 return error;
6039 }
6040 if (*oldlenp < xb.xb_u.xb_buffer.xbb_len) {
6041 error = ENOMEM;
6042 } else {
6043 error = copyout(xb_buffer_base(&xb), oldp, xb.xb_u.xb_buffer.xbb_len);
6044 }
6045 *oldlenp = xb.xb_u.xb_buffer.xbb_len;
6046 xb_cleanup(&xb);
6047 break;
6048 #if NFSSERVER
6049 case NFS_EXPORTSTATS:
6050 /* setup export stat descriptor */
6051 stat_desc.rec_vers = NFS_EXPORT_STAT_REC_VERSION;
6052
6053 if (!nfsrv_is_initialized()) {
6054 stat_desc.rec_count = 0;
6055 if (oldp && (*oldlenp >= sizeof(struct nfs_export_stat_desc))) {
6056 error = copyout(&stat_desc, oldp, sizeof(struct nfs_export_stat_desc));
6057 }
6058 *oldlenp = sizeof(struct nfs_export_stat_desc);
6059 return error;
6060 }
6061
6062 /* Count the number of exported directories */
6063 lck_rw_lock_shared(&nfsrv_export_rwlock);
6064 numExports = 0;
6065 LIST_FOREACH(nxfs, &nfsrv_exports, nxfs_next)
6066 LIST_FOREACH(nx, &nxfs->nxfs_exports, nx_next)
6067 numExports += 1;
6068
6069 /* update stat descriptor's export record count */
6070 stat_desc.rec_count = numExports;
6071
6072 /* calculate total size of required buffer */
6073 totlen = sizeof(struct nfs_export_stat_desc) + (numExports * sizeof(struct nfs_export_stat_rec));
6074
6075 /* Check caller's buffer */
6076 if (oldp == 0) {
6077 lck_rw_done(&nfsrv_export_rwlock);
6078 /* indicate required buffer len */
6079 *oldlenp = totlen;
6080 return 0;
6081 }
6082
6083 /* We require the caller's buffer to be at least large enough to hold the descriptor */
6084 if (*oldlenp < sizeof(struct nfs_export_stat_desc)) {
6085 lck_rw_done(&nfsrv_export_rwlock);
6086 /* indicate required buffer len */
6087 *oldlenp = totlen;
6088 return ENOMEM;
6089 }
6090
6091 /* indicate required buffer len */
6092 *oldlenp = totlen;
6093
6094 /* check if export table is empty */
6095 if (!numExports) {
6096 lck_rw_done(&nfsrv_export_rwlock);
6097 error = copyout(&stat_desc, oldp, sizeof(struct nfs_export_stat_desc));
6098 return error;
6099 }
6100
6101 /* calculate how many actual export stat records fit into caller's buffer */
6102 numRecs = (*oldlenp - sizeof(struct nfs_export_stat_desc)) / sizeof(struct nfs_export_stat_rec);
6103
6104 if (!numRecs) {
6105 /* caller's buffer can only accomodate descriptor */
6106 lck_rw_done(&nfsrv_export_rwlock);
6107 stat_desc.rec_count = 0;
6108 error = copyout(&stat_desc, oldp, sizeof(struct nfs_export_stat_desc));
6109 return error;
6110 }
6111
6112 /* adjust to actual number of records to copyout to caller's buffer */
6113 if (numRecs > numExports) {
6114 numRecs = numExports;
6115 }
6116
6117 /* set actual number of records we are returning */
6118 stat_desc.rec_count = numRecs;
6119
6120 /* first copy out the stat descriptor */
6121 pos = 0;
6122 error = copyout(&stat_desc, oldp + pos, sizeof(struct nfs_export_stat_desc));
6123 if (error) {
6124 lck_rw_done(&nfsrv_export_rwlock);
6125 return error;
6126 }
6127 pos += sizeof(struct nfs_export_stat_desc);
6128
6129 /* Loop through exported directories */
6130 count = 0;
6131 LIST_FOREACH(nxfs, &nfsrv_exports, nxfs_next) {
6132 LIST_FOREACH(nx, &nxfs->nxfs_exports, nx_next) {
6133 if (count >= numRecs) {
6134 break;
6135 }
6136
6137 /* build exported filesystem path */
6138 memset(statrec.path, 0, sizeof(statrec.path));
6139 snprintf(statrec.path, sizeof(statrec.path), "%s%s%s",
6140 nxfs->nxfs_path, ((nxfs->nxfs_path[1] && nx->nx_path[0]) ? "/" : ""),
6141 nx->nx_path);
6142
6143 /* build the 64-bit export stat counters */
6144 statrec.ops = ((uint64_t)nx->nx_stats.ops.hi << 32) |
6145 nx->nx_stats.ops.lo;
6146 statrec.bytes_read = ((uint64_t)nx->nx_stats.bytes_read.hi << 32) |
6147 nx->nx_stats.bytes_read.lo;
6148 statrec.bytes_written = ((uint64_t)nx->nx_stats.bytes_written.hi << 32) |
6149 nx->nx_stats.bytes_written.lo;
6150 error = copyout(&statrec, oldp + pos, sizeof(statrec));
6151 if (error) {
6152 lck_rw_done(&nfsrv_export_rwlock);
6153 return error;
6154 }
6155 /* advance buffer position */
6156 pos += sizeof(statrec);
6157 }
6158 }
6159 lck_rw_done(&nfsrv_export_rwlock);
6160 break;
6161 case NFS_USERSTATS:
6162 /* init structures used for copying out of kernel */
6163 ustat_desc.rec_vers = NFS_USER_STAT_REC_VERSION;
6164 ustat_rec.rec_type = NFS_USER_STAT_USER_REC;
6165 upath_rec.rec_type = NFS_USER_STAT_PATH_REC;
6166
6167 /* initialize counters */
6168 bytes_total = sizeof(struct nfs_user_stat_desc);
6169 bytes_avail = *oldlenp;
6170 recs_copied = 0;
6171
6172 if (!nfsrv_is_initialized()) { /* NFS server not initialized, so no stats */
6173 goto ustat_skip;
6174 }
6175
6176 /* reclaim old expired user nodes */
6177 nfsrv_active_user_list_reclaim();
6178
6179 /* reserve space for the buffer descriptor */
6180 if (bytes_avail >= sizeof(struct nfs_user_stat_desc)) {
6181 bytes_avail -= sizeof(struct nfs_user_stat_desc);
6182 } else {
6183 bytes_avail = 0;
6184 }
6185
6186 /* put buffer position past the buffer descriptor */
6187 pos = sizeof(struct nfs_user_stat_desc);
6188
6189 /* Loop through exported directories */
6190 lck_rw_lock_shared(&nfsrv_export_rwlock);
6191 LIST_FOREACH(nxfs, &nfsrv_exports, nxfs_next) {
6192 LIST_FOREACH(nx, &nxfs->nxfs_exports, nx_next) {
6193 /* copy out path */
6194 if (bytes_avail >= sizeof(struct nfs_user_stat_path_rec)) {
6195 memset(upath_rec.path, 0, sizeof(upath_rec.path));
6196 snprintf(upath_rec.path, sizeof(upath_rec.path), "%s%s%s",
6197 nxfs->nxfs_path, ((nxfs->nxfs_path[1] && nx->nx_path[0]) ? "/" : ""),
6198 nx->nx_path);
6199
6200 error = copyout(&upath_rec, oldp + pos, sizeof(struct nfs_user_stat_path_rec));
6201 if (error) {
6202 /* punt */
6203 goto ustat_done;
6204 }
6205
6206 pos += sizeof(struct nfs_user_stat_path_rec);
6207 bytes_avail -= sizeof(struct nfs_user_stat_path_rec);
6208 recs_copied++;
6209 } else {
6210 /* Caller's buffer is exhausted */
6211 bytes_avail = 0;
6212 }
6213
6214 bytes_total += sizeof(struct nfs_user_stat_path_rec);
6215
6216 /* Scan through all user nodes of this export */
6217 ulist = &nx->nx_user_list;
6218 lck_mtx_lock(&ulist->user_mutex);
6219 for (unode = TAILQ_FIRST(&ulist->user_lru); unode; unode = unode_next) {
6220 unode_next = TAILQ_NEXT(unode, lru_link);
6221
6222 /* copy out node if there is space */
6223 if (bytes_avail >= sizeof(struct nfs_user_stat_user_rec)) {
6224 /* prepare a user stat rec for copying out */
6225 ustat_rec.uid = unode->uid;
6226 memset(&ustat_rec.sock, 0, sizeof(ustat_rec.sock));
6227 bcopy(&unode->sock, &ustat_rec.sock, unode->sock.ss_len);
6228 ustat_rec.ops = unode->ops;
6229 ustat_rec.bytes_read = unode->bytes_read;
6230 ustat_rec.bytes_written = unode->bytes_written;
6231 ustat_rec.tm_start = unode->tm_start;
6232 ustat_rec.tm_last = unode->tm_last;
6233
6234 error = copyout(&ustat_rec, oldp + pos, sizeof(struct nfs_user_stat_user_rec));
6235
6236 if (error) {
6237 /* punt */
6238 lck_mtx_unlock(&ulist->user_mutex);
6239 goto ustat_done;
6240 }
6241
6242 pos += sizeof(struct nfs_user_stat_user_rec);
6243 bytes_avail -= sizeof(struct nfs_user_stat_user_rec);
6244 recs_copied++;
6245 } else {
6246 /* Caller's buffer is exhausted */
6247 bytes_avail = 0;
6248 }
6249 bytes_total += sizeof(struct nfs_user_stat_user_rec);
6250 }
6251 /* can unlock this export's list now */
6252 lck_mtx_unlock(&ulist->user_mutex);
6253 }
6254 }
6255
6256 ustat_done:
6257 /* unlock the export table */
6258 lck_rw_done(&nfsrv_export_rwlock);
6259
6260 ustat_skip:
6261 /* indicate number of actual records copied */
6262 ustat_desc.rec_count = recs_copied;
6263
6264 if (!error) {
6265 /* check if there was enough room for the buffer descriptor */
6266 if (*oldlenp >= sizeof(struct nfs_user_stat_desc)) {
6267 error = copyout(&ustat_desc, oldp, sizeof(struct nfs_user_stat_desc));
6268 } else {
6269 error = ENOMEM;
6270 }
6271
6272 /* always indicate required buffer size */
6273 *oldlenp = bytes_total;
6274 }
6275 break;
6276 case NFS_USERCOUNT:
6277 if (!oldp) {
6278 *oldlenp = sizeof(nfsrv_user_stat_node_count);
6279 return 0;
6280 }
6281
6282 if (*oldlenp < sizeof(nfsrv_user_stat_node_count)) {
6283 *oldlenp = sizeof(nfsrv_user_stat_node_count);
6284 return ENOMEM;
6285 }
6286
6287 if (nfsrv_is_initialized()) {
6288 /* reclaim old expired user nodes */
6289 nfsrv_active_user_list_reclaim();
6290 }
6291
6292 error = copyout(&nfsrv_user_stat_node_count, oldp, sizeof(nfsrv_user_stat_node_count));
6293 break;
6294 #endif /* NFSSERVER */
6295 case VFS_CTL_NOLOCKS:
6296 if (req->oldptr != USER_ADDR_NULL) {
6297 lck_mtx_lock(&nmp->nm_lock);
6298 val = (nmp->nm_lockmode == NFS_LOCK_MODE_DISABLED) ? 1 : 0;
6299 lck_mtx_unlock(&nmp->nm_lock);
6300 error = SYSCTL_OUT(req, &val, sizeof(val));
6301 if (error) {
6302 return error;
6303 }
6304 }
6305 if (req->newptr != USER_ADDR_NULL) {
6306 error = SYSCTL_IN(req, &val, sizeof(val));
6307 if (error) {
6308 return error;
6309 }
6310 lck_mtx_lock(&nmp->nm_lock);
6311 if (nmp->nm_lockmode == NFS_LOCK_MODE_LOCAL) {
6312 /* can't toggle locks when using local locks */
6313 error = EINVAL;
6314 } else if ((nmp->nm_vers >= NFS_VER4) && val) {
6315 /* can't disable locks for NFSv4 */
6316 error = EINVAL;
6317 } else if (val) {
6318 if ((nmp->nm_vers <= NFS_VER3) && (nmp->nm_lockmode == NFS_LOCK_MODE_ENABLED)) {
6319 nfs_lockd_mount_unregister(nmp);
6320 }
6321 nmp->nm_lockmode = NFS_LOCK_MODE_DISABLED;
6322 nmp->nm_state &= ~NFSSTA_LOCKTIMEO;
6323 } else {
6324 if ((nmp->nm_vers <= NFS_VER3) && (nmp->nm_lockmode == NFS_LOCK_MODE_DISABLED)) {
6325 nfs_lockd_mount_register(nmp);
6326 }
6327 nmp->nm_lockmode = NFS_LOCK_MODE_ENABLED;
6328 }
6329 lck_mtx_unlock(&nmp->nm_lock);
6330 }
6331 break;
6332 #ifndef CONFIG_EMBEDDED
6333 case VFS_CTL_QUERY:
6334 lck_mtx_lock(&nmp->nm_lock);
6335 /* XXX don't allow users to know about/disconnect unresponsive, soft, nobrowse mounts */
6336 softnobrowse = (NMFLAG(nmp, SOFT) && (vfs_flags(nmp->nm_mountp) & MNT_DONTBROWSE));
6337 if (!softnobrowse && (nmp->nm_state & NFSSTA_TIMEO)) {
6338 vq.vq_flags |= VQ_NOTRESP;
6339 }
6340 if (!softnobrowse && (nmp->nm_state & NFSSTA_JUKEBOXTIMEO) && !NMFLAG(nmp, MUTEJUKEBOX)) {
6341 vq.vq_flags |= VQ_NOTRESP;
6342 }
6343 if (!softnobrowse && (nmp->nm_state & NFSSTA_LOCKTIMEO) &&
6344 (nmp->nm_lockmode == NFS_LOCK_MODE_ENABLED)) {
6345 vq.vq_flags |= VQ_NOTRESP;
6346 }
6347 if (nmp->nm_state & NFSSTA_DEAD) {
6348 vq.vq_flags |= VQ_DEAD;
6349 }
6350 lck_mtx_unlock(&nmp->nm_lock);
6351 error = SYSCTL_OUT(req, &vq, sizeof(vq));
6352 break;
6353 #endif
6354 case VFS_CTL_TIMEO:
6355 if (req->oldptr != USER_ADDR_NULL) {
6356 lck_mtx_lock(&nmp->nm_lock);
6357 val = nmp->nm_tprintf_initial_delay;
6358 lck_mtx_unlock(&nmp->nm_lock);
6359 error = SYSCTL_OUT(req, &val, sizeof(val));
6360 if (error) {
6361 return error;
6362 }
6363 }
6364 if (req->newptr != USER_ADDR_NULL) {
6365 error = SYSCTL_IN(req, &val, sizeof(val));
6366 if (error) {
6367 return error;
6368 }
6369 lck_mtx_lock(&nmp->nm_lock);
6370 if (val < 0) {
6371 nmp->nm_tprintf_initial_delay = 0;
6372 } else {
6373 nmp->nm_tprintf_initial_delay = val;
6374 }
6375 lck_mtx_unlock(&nmp->nm_lock);
6376 }
6377 break;
6378 case VFS_CTL_NSTATUS:
6379 /*
6380 * Return the status of this mount. This is much more
6381 * information than VFS_CTL_QUERY. In addition to the
6382 * vq_flags return the significant mount options along
6383 * with the list of threads blocked on the mount and
6384 * how long the threads have been waiting.
6385 */
6386
6387 lck_mtx_lock(nfs_request_mutex);
6388 lck_mtx_lock(&nmp->nm_lock);
6389
6390 /*
6391 * Count the number of requests waiting for a reply.
6392 * Note: there could be multiple requests from the same thread.
6393 */
6394 numThreads = 0;
6395 TAILQ_FOREACH(rq, &nfs_reqq, r_chain) {
6396 if (rq->r_nmp == nmp) {
6397 numThreads++;
6398 }
6399 }
6400
6401 /* Calculate total size of result buffer */
6402 totlen = sizeof(struct netfs_status) + (numThreads * sizeof(uint64_t));
6403
6404 if (req->oldptr == USER_ADDR_NULL) { // Caller is querying buffer size
6405 lck_mtx_unlock(&nmp->nm_lock);
6406 lck_mtx_unlock(nfs_request_mutex);
6407 return SYSCTL_OUT(req, NULL, totlen);
6408 }
6409 if (req->oldlen < totlen) { // Check if caller's buffer is big enough
6410 lck_mtx_unlock(&nmp->nm_lock);
6411 lck_mtx_unlock(nfs_request_mutex);
6412 return ERANGE;
6413 }
6414
6415 MALLOC(nsp, struct netfs_status *, totlen, M_TEMP, M_WAITOK | M_ZERO);
6416 if (nsp == NULL) {
6417 lck_mtx_unlock(&nmp->nm_lock);
6418 lck_mtx_unlock(nfs_request_mutex);
6419 return ENOMEM;
6420 }
6421 timeoutmask = NFSSTA_TIMEO | NFSSTA_LOCKTIMEO | NFSSTA_JUKEBOXTIMEO;
6422 if (nmp->nm_state & timeoutmask) {
6423 nsp->ns_status |= VQ_NOTRESP;
6424 }
6425 if (nmp->nm_state & NFSSTA_DEAD) {
6426 nsp->ns_status |= VQ_DEAD;
6427 }
6428
6429 (void) nfs_mountopts(nmp, nsp->ns_mountopts, sizeof(nsp->ns_mountopts));
6430 nsp->ns_threadcount = numThreads;
6431
6432 /*
6433 * Get the thread ids of threads waiting for a reply
6434 * and find the longest wait time.
6435 */
6436 if (numThreads > 0) {
6437 struct timeval now;
6438 time_t sendtime;
6439
6440 microuptime(&now);
6441 count = 0;
6442 sendtime = now.tv_sec;
6443 TAILQ_FOREACH(rq, &nfs_reqq, r_chain) {
6444 if (rq->r_nmp == nmp) {
6445 if (rq->r_start < sendtime) {
6446 sendtime = rq->r_start;
6447 }
6448 // A thread_id of zero is used to represent an async I/O request.
6449 nsp->ns_threadids[count] =
6450 rq->r_thread ? thread_tid(rq->r_thread) : 0;
6451 if (++count >= numThreads) {
6452 break;
6453 }
6454 }
6455 }
6456 nsp->ns_waittime = now.tv_sec - sendtime;
6457 }
6458
6459 lck_mtx_unlock(&nmp->nm_lock);
6460 lck_mtx_unlock(nfs_request_mutex);
6461
6462 error = SYSCTL_OUT(req, nsp, totlen);
6463 FREE(nsp, M_TEMP);
6464 break;
6465 default:
6466 return ENOTSUP;
6467 }
6468 return error;
6469 }