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