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