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