]> git.saurik.com Git - apple/xnu.git/blob - bsd/nfs/nfs_vfsops.c
xnu-4570.61.1.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 nfsm_chain_get_opaque(error, &nmrep, fh.fh_len, fh.fh_data);
2332 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
2333 if (!error) {
2334 NFS_CLEAR_ATTRIBUTES(nmp->nm_fsattr.nfsa_bitmap);
2335 error = nfs4_parsefattr(&nmrep, &nmp->nm_fsattr, &nvattr, NULL, NULL, &nfsls);
2336 }
2337 nfsm_chain_cleanup(&nmrep);
2338 nfsm_chain_null(&nmreq);
2339 if (error) {
2340 /* LOOKUP succeeded but GETATTR failed? This could be a referral. */
2341 /* Try the lookup again with a getattr for fs_locations. */
2342 nfs_fs_locations_cleanup(&nfsls);
2343 error = nfs4_get_fs_locations(nmp, NULL, dirfh.fh_data, dirfh.fh_len, fspath.np_components[comp], ctx, &nfsls);
2344 if (!error && (nfsls.nl_numlocs < 1))
2345 error = ENOENT;
2346 nfsmout_if(error);
2347 if (++loopcnt > MAXSYMLINKS) {
2348 /* too many symlink/referral redirections */
2349 error = ELOOP;
2350 goto nfsmout;
2351 }
2352 /* tear down the current connection */
2353 nfs_disconnect(nmp);
2354 /* replace fs locations */
2355 nfs_fs_locations_cleanup(&nmp->nm_locations);
2356 nmp->nm_locations = nfsls;
2357 bzero(&nfsls, sizeof(nfsls));
2358 /* initiate a connection using the new fs locations */
2359 error = nfs_mount_connect(nmp);
2360 if (!error && !(nmp->nm_locations.nl_current.nli_flags & NLI_VALID))
2361 error = EIO;
2362 nfsmout_if(error);
2363 /* add new server's remote path to beginning of our path and continue */
2364 nfsp = &nmp->nm_locations.nl_locations[nmp->nm_locations.nl_current.nli_loc]->nl_path;
2365 bzero(&fspath2, sizeof(fspath2));
2366 fspath2.np_compcount = (fspath.np_compcount - comp - 1) + nfsp->np_compcount;
2367 if (fspath2.np_compcount > 0) {
2368 MALLOC(fspath2.np_components, char **, fspath2.np_compcount*sizeof(char*), M_TEMP, M_WAITOK|M_ZERO);
2369 if (!fspath2.np_components) {
2370 error = ENOMEM;
2371 goto nfsmout;
2372 }
2373 for (comp2=0; comp2 < nfsp->np_compcount; comp2++) {
2374 int slen = strlen(nfsp->np_components[comp2]);
2375 MALLOC(fspath2.np_components[comp2], char *, slen+1, M_TEMP, M_WAITOK|M_ZERO);
2376 if (!fspath2.np_components[comp2]) {
2377 /* clean up fspath2, then error out */
2378 while (comp2 > 0) {
2379 comp2--;
2380 FREE(fspath2.np_components[comp2], M_TEMP);
2381 }
2382 FREE(fspath2.np_components, M_TEMP);
2383 error = ENOMEM;
2384 goto nfsmout;
2385 }
2386 strlcpy(fspath2.np_components[comp2], nfsp->np_components[comp2], slen+1);
2387 }
2388 if ((fspath.np_compcount - comp - 1) > 0)
2389 bcopy(&fspath.np_components[comp+1], &fspath2.np_components[nfsp->np_compcount], (fspath.np_compcount - comp - 1)*sizeof(char*));
2390 /* free up unused parts of old path (prior components and component array) */
2391 do {
2392 FREE(fspath.np_components[comp], M_TEMP);
2393 } while (comp-- > 0);
2394 FREE(fspath.np_components, M_TEMP);
2395 /* put new path in place */
2396 fspath = fspath2;
2397 }
2398 /* reset dirfh and component index */
2399 dirfh.fh_len = 0;
2400 comp = 0;
2401 NVATTR_CLEANUP(&nvattr);
2402 if (fspath.np_compcount == 0)
2403 goto nocomponents;
2404 continue;
2405 }
2406 nfsmout_if(error);
2407 /* if file handle is for a symlink, then update the path with the symlink contents */
2408 if (NFS_BITMAP_ISSET(&nvattr.nva_bitmap, NFS_FATTR_TYPE) && (nvattr.nva_type == VLNK)) {
2409 if (++loopcnt > MAXSYMLINKS)
2410 error = ELOOP;
2411 else
2412 error = nfs4_mount_update_path_with_symlink(nmp, &fspath, comp, &dirfh, &depth, &fh, ctx);
2413 nfsmout_if(error);
2414 /* directory file handle is either left the same or reset to root (if link was absolute) */
2415 /* path traversal starts at beginning of the path again */
2416 comp = 0;
2417 NVATTR_CLEANUP(&nvattr);
2418 nfs_fs_locations_cleanup(&nfsls);
2419 continue;
2420 }
2421 NVATTR_CLEANUP(&nvattr);
2422 nfs_fs_locations_cleanup(&nfsls);
2423 /* not a symlink... */
2424 if ((nmp->nm_state & NFSSTA_NEEDSECINFO) && (comp == (fspath.np_compcount-1)) && !isdotdot) {
2425 /* need to get SECINFO for the directory being mounted */
2426 if (dirfh.fh_len == 0)
2427 NFSREQ_SECINFO_SET(&si, NULL, NULL, 0, isdotdot ? NULL : fspath.np_components[comp], 0);
2428 else
2429 NFSREQ_SECINFO_SET(&si, NULL, dirfh.fh_data, dirfh.fh_len, isdotdot ? NULL : fspath.np_components[comp], 0);
2430 sec.count = NX_MAX_SEC_FLAVORS;
2431 error = nfs4_secinfo_rpc(nmp, &si, vfs_context_ucred(ctx), sec.flavors, &sec.count);
2432 /* [sigh] some implementations return "illegal" error for unsupported ops */
2433 if (error == NFSERR_OP_ILLEGAL)
2434 error = 0;
2435 nfsmout_if(error);
2436 /* set our default security flavor to the first in the list */
2437 if (sec.count)
2438 nmp->nm_auth = sec.flavors[0];
2439 nmp->nm_state &= ~NFSSTA_NEEDSECINFO;
2440 }
2441 /* advance directory file handle, component index, & update depth */
2442 dirfh = fh;
2443 comp++;
2444 if (!isdotdot) /* going down the hierarchy */
2445 depth++;
2446 else if (--depth <= 0) /* going up the hierarchy */
2447 dirfh.fh_len = 0; /* clear dirfh when we hit root */
2448 }
2449
2450 gotfh:
2451 /* get attrs for mount point root */
2452 numops = NMFLAG(nmp, NAMEDATTR) ? 3 : 2; // PUTFH + GETATTR + OPENATTR
2453 nfsm_chain_build_alloc_init(error, &nmreq, 25 * NFSX_UNSIGNED);
2454 nfsm_chain_add_compound_header(error, &nmreq, "mount", nmp->nm_minor_vers, numops);
2455 numops--;
2456 nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH);
2457 nfsm_chain_add_fh(error, &nmreq, NFS_VER4, dirfh.fh_data, dirfh.fh_len);
2458 numops--;
2459 nfsm_chain_add_32(error, &nmreq, NFS_OP_GETATTR);
2460 NFS_CLEAR_ATTRIBUTES(bitmap);
2461 NFS4_DEFAULT_ATTRIBUTES(bitmap);
2462 /* if no namedattr support or last component is ".zfs", clear NFS_FATTR_NAMED_ATTR */
2463 if (!NMFLAG(nmp, NAMEDATTR) || ((fspath.np_compcount > 0) && !strcmp(fspath.np_components[fspath.np_compcount-1], ".zfs")))
2464 NFS_BITMAP_CLR(bitmap, NFS_FATTR_NAMED_ATTR);
2465 nfsm_chain_add_bitmap(error, &nmreq, bitmap, NFS_ATTR_BITMAP_LEN);
2466 if (NMFLAG(nmp, NAMEDATTR)) {
2467 numops--;
2468 nfsm_chain_add_32(error, &nmreq, NFS_OP_OPENATTR);
2469 nfsm_chain_add_32(error, &nmreq, 0);
2470 }
2471 nfsm_chain_build_done(error, &nmreq);
2472 nfsm_assert(error, (numops == 0), EPROTO);
2473 nfsmout_if(error);
2474 error = nfs_request_async(NULL, nmp->nm_mountp, &nmreq, NFSPROC4_COMPOUND,
2475 vfs_context_thread(ctx), vfs_context_ucred(ctx), &si, 0, NULL, &req);
2476 if (!error)
2477 error = nfs_request_async_finish(req, &nmrep, &xid, &status);
2478 nfsm_chain_skip_tag(error, &nmrep);
2479 nfsm_chain_get_32(error, &nmrep, numops);
2480 nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
2481 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
2482 nfsmout_if(error);
2483 NFS_CLEAR_ATTRIBUTES(nmp->nm_fsattr.nfsa_bitmap);
2484 error = nfs4_parsefattr(&nmrep, &nmp->nm_fsattr, &nvattr, NULL, NULL, NULL);
2485 nfsmout_if(error);
2486 if (NMFLAG(nmp, NAMEDATTR)) {
2487 nfsm_chain_op_check(error, &nmrep, NFS_OP_OPENATTR);
2488 if (error == ENOENT)
2489 error = 0;
2490 /* [sigh] some implementations return "illegal" error for unsupported ops */
2491 if (error || !NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_supp_attr, NFS_FATTR_NAMED_ATTR)) {
2492 nmp->nm_fsattr.nfsa_flags &= ~NFS_FSFLAG_NAMED_ATTR;
2493 } else {
2494 nmp->nm_fsattr.nfsa_flags |= NFS_FSFLAG_NAMED_ATTR;
2495 }
2496 } else {
2497 nmp->nm_fsattr.nfsa_flags &= ~NFS_FSFLAG_NAMED_ATTR;
2498 }
2499 if (NMFLAG(nmp, NOACL)) /* make sure ACL support is turned off */
2500 nmp->nm_fsattr.nfsa_flags &= ~NFS_FSFLAG_ACL;
2501 if (NMFLAG(nmp, ACLONLY) && !(nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_ACL))
2502 NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_ACLONLY);
2503 if (NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_supp_attr, NFS_FATTR_FH_EXPIRE_TYPE)) {
2504 uint32_t fhtype = ((nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_FHTYPE_MASK) >> NFS_FSFLAG_FHTYPE_SHIFT);
2505 if (fhtype != NFS_FH_PERSISTENT)
2506 printf("nfs: warning: non-persistent file handles! for %s\n", vfs_statfs(nmp->nm_mountp)->f_mntfromname);
2507 }
2508
2509 /* make sure it's a directory */
2510 if (!NFS_BITMAP_ISSET(&nvattr.nva_bitmap, NFS_FATTR_TYPE) || (nvattr.nva_type != VDIR)) {
2511 error = ENOTDIR;
2512 goto nfsmout;
2513 }
2514
2515 /* save the NFS fsid */
2516 nmp->nm_fsid = nvattr.nva_fsid;
2517
2518 /* create the root node */
2519 error = nfs_nget(nmp->nm_mountp, NULL, NULL, dirfh.fh_data, dirfh.fh_len, &nvattr, &xid, rq.r_auth, NG_MARKROOT, npp);
2520 nfsmout_if(error);
2521
2522 if (nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_ACL)
2523 vfs_setextendedsecurity(nmp->nm_mountp);
2524
2525 /* adjust I/O sizes to server limits */
2526 if (NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_MAXREAD) && (nmp->nm_fsattr.nfsa_maxread > 0)) {
2527 if (nmp->nm_fsattr.nfsa_maxread < (uint64_t)nmp->nm_rsize) {
2528 nmp->nm_rsize = nmp->nm_fsattr.nfsa_maxread & ~(NFS_FABLKSIZE - 1);
2529 if (nmp->nm_rsize == 0)
2530 nmp->nm_rsize = nmp->nm_fsattr.nfsa_maxread;
2531 }
2532 }
2533 if (NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_MAXWRITE) && (nmp->nm_fsattr.nfsa_maxwrite > 0)) {
2534 if (nmp->nm_fsattr.nfsa_maxwrite < (uint64_t)nmp->nm_wsize) {
2535 nmp->nm_wsize = nmp->nm_fsattr.nfsa_maxwrite & ~(NFS_FABLKSIZE - 1);
2536 if (nmp->nm_wsize == 0)
2537 nmp->nm_wsize = nmp->nm_fsattr.nfsa_maxwrite;
2538 }
2539 }
2540
2541 /* set up lease renew timer */
2542 nmp->nm_renew_timer = thread_call_allocate(nfs4_renew_timer, nmp);
2543 interval = nmp->nm_fsattr.nfsa_lease / 2;
2544 if (interval < 1)
2545 interval = 1;
2546 nfs_interval_timer_start(nmp->nm_renew_timer, interval * 1000);
2547
2548 nfsmout:
2549 if (fspath.np_components) {
2550 for (comp=0; comp < fspath.np_compcount; comp++)
2551 if (fspath.np_components[comp])
2552 FREE(fspath.np_components[comp], M_TEMP);
2553 FREE(fspath.np_components, M_TEMP);
2554 }
2555 NVATTR_CLEANUP(&nvattr);
2556 nfs_fs_locations_cleanup(&nfsls);
2557 if (*npp)
2558 nfs_node_unlock(*npp);
2559 nfsm_chain_cleanup(&nmreq);
2560 nfsm_chain_cleanup(&nmrep);
2561 return (error);
2562 }
2563
2564 /*
2565 * Thread to handle initial NFS mount connection.
2566 */
2567 void
2568 nfs_mount_connect_thread(void *arg, __unused wait_result_t wr)
2569 {
2570 struct nfsmount *nmp = arg;
2571 int error = 0, savederror = 0, slpflag = (NMFLAG(nmp, INTR) ? PCATCH : 0);
2572 int done = 0, timeo, tries, maxtries;
2573
2574 if (NM_OMFLAG(nmp, MNTQUICK)) {
2575 timeo = 8;
2576 maxtries = 1;
2577 } else {
2578 timeo = 30;
2579 maxtries = 2;
2580 }
2581
2582 for (tries = 0; tries < maxtries; tries++) {
2583 error = nfs_connect(nmp, 1, timeo);
2584 switch (error) {
2585 case ETIMEDOUT:
2586 case EAGAIN:
2587 case EPIPE:
2588 case EADDRNOTAVAIL:
2589 case ENETDOWN:
2590 case ENETUNREACH:
2591 case ENETRESET:
2592 case ECONNABORTED:
2593 case ECONNRESET:
2594 case EISCONN:
2595 case ENOTCONN:
2596 case ESHUTDOWN:
2597 case ECONNREFUSED:
2598 case EHOSTDOWN:
2599 case EHOSTUNREACH:
2600 /* just keep retrying on any of these errors */
2601 break;
2602 case 0:
2603 default:
2604 /* looks like we got an answer... */
2605 done = 1;
2606 break;
2607 }
2608
2609 /* save the best error */
2610 if (nfs_connect_error_class(error) >= nfs_connect_error_class(savederror))
2611 savederror = error;
2612 if (done) {
2613 error = savederror;
2614 break;
2615 }
2616
2617 /* pause before next attempt */
2618 if ((error = nfs_sigintr(nmp, NULL, current_thread(), 0)))
2619 break;
2620 error = tsleep(nmp, PSOCK|slpflag, "nfs_mount_connect_retry", 2*hz);
2621 if (error && (error != EWOULDBLOCK))
2622 break;
2623 error = savederror;
2624 }
2625
2626 /* update status of mount connect */
2627 lck_mtx_lock(&nmp->nm_lock);
2628 if (!nmp->nm_mounterror)
2629 nmp->nm_mounterror = error;
2630 nmp->nm_state &= ~NFSSTA_MOUNT_THREAD;
2631 lck_mtx_unlock(&nmp->nm_lock);
2632 wakeup(&nmp->nm_nss);
2633 }
2634
2635 int
2636 nfs_mount_connect(struct nfsmount *nmp)
2637 {
2638 int error = 0, slpflag;
2639 thread_t thd;
2640 struct timespec ts = { 2, 0 };
2641
2642 /*
2643 * Set up the socket. Perform initial search for a location/server/address to
2644 * connect to and negotiate any unspecified mount parameters. This work is
2645 * done on a kernel thread to satisfy reserved port usage needs.
2646 */
2647 slpflag = NMFLAG(nmp, INTR) ? PCATCH : 0;
2648 lck_mtx_lock(&nmp->nm_lock);
2649 /* set flag that the thread is running */
2650 nmp->nm_state |= NFSSTA_MOUNT_THREAD;
2651 if (kernel_thread_start(nfs_mount_connect_thread, nmp, &thd) != KERN_SUCCESS) {
2652 nmp->nm_state &= ~NFSSTA_MOUNT_THREAD;
2653 nmp->nm_mounterror = EIO;
2654 printf("nfs mount %s start socket connect thread failed\n", vfs_statfs(nmp->nm_mountp)->f_mntfromname);
2655 } else {
2656 thread_deallocate(thd);
2657 }
2658
2659 /* wait until mount connect thread is finished/gone */
2660 while (nmp->nm_state & NFSSTA_MOUNT_THREAD) {
2661 error = msleep(&nmp->nm_nss, &nmp->nm_lock, slpflag|PSOCK, "nfsconnectthread", &ts);
2662 if ((error && (error != EWOULDBLOCK)) || ((error = nfs_sigintr(nmp, NULL, current_thread(), 1)))) {
2663 /* record error */
2664 if (!nmp->nm_mounterror)
2665 nmp->nm_mounterror = error;
2666 /* signal the thread that we are aborting */
2667 nmp->nm_sockflags |= NMSOCK_UNMOUNT;
2668 if (nmp->nm_nss)
2669 wakeup(nmp->nm_nss);
2670 /* and continue waiting on it to finish */
2671 slpflag = 0;
2672 }
2673 }
2674 lck_mtx_unlock(&nmp->nm_lock);
2675
2676 /* grab mount connect status */
2677 error = nmp->nm_mounterror;
2678
2679 return (error);
2680 }
2681
2682 /* Table of maximum minor version for a given version */
2683 uint32_t maxminorverstab[] = {
2684 0, /* Version 0 (does not exist) */
2685 0, /* Version 1 (does not exist) */
2686 0, /* Version 2 */
2687 0, /* Version 3 */
2688 0, /* Version 4 */
2689 };
2690
2691 #define NFS_MAX_SUPPORTED_VERSION ((long)(sizeof (maxminorverstab) / sizeof (uint32_t) - 1))
2692 #define NFS_MAX_SUPPORTED_MINOR_VERSION(v) ((long)(maxminorverstab[(v)]))
2693
2694 #define DEFAULT_NFS_MIN_VERS VER2PVER(2, 0)
2695 #define DEFAULT_NFS_MAX_VERS VER2PVER(3, 0)
2696
2697 /*
2698 * Common code to mount an NFS file system.
2699 */
2700 int
2701 mountnfs(
2702 char *xdrbuf,
2703 mount_t mp,
2704 vfs_context_t ctx,
2705 vnode_t *vpp)
2706 {
2707 struct nfsmount *nmp;
2708 nfsnode_t np;
2709 int error = 0;
2710 struct vfsstatfs *sbp;
2711 struct xdrbuf xb;
2712 uint32_t i, val, maxio, iosize, len;
2713 uint32_t *mattrs;
2714 uint32_t *mflags_mask;
2715 uint32_t *mflags;
2716 uint32_t argslength, attrslength;
2717 struct nfs_location_index firstloc = { NLI_VALID, 0, 0, 0 };
2718 static const struct nfs_etype nfs_default_etypes = {
2719 .count = NFS_MAX_ETYPES,
2720 .selected = NFS_MAX_ETYPES,
2721 .etypes = { NFS_AES256_CTS_HMAC_SHA1_96,
2722 NFS_AES128_CTS_HMAC_SHA1_96,
2723 NFS_DES3_CBC_SHA1_KD
2724 }
2725 };
2726 /* make sure mbuf constants are set up */
2727 if (!nfs_mbuf_mhlen)
2728 nfs_mbuf_init();
2729
2730 if (vfs_flags(mp) & MNT_UPDATE) {
2731 nmp = VFSTONFS(mp);
2732 /* update paths, file handles, etc, here XXX */
2733 xb_free(xdrbuf);
2734 return (0);
2735 } else {
2736 /* allocate an NFS mount structure for this mount */
2737 MALLOC_ZONE(nmp, struct nfsmount *,
2738 sizeof (struct nfsmount), M_NFSMNT, M_WAITOK);
2739 if (!nmp) {
2740 xb_free(xdrbuf);
2741 return (ENOMEM);
2742 }
2743 bzero((caddr_t)nmp, sizeof (struct nfsmount));
2744 lck_mtx_init(&nmp->nm_lock, nfs_mount_grp, LCK_ATTR_NULL);
2745 TAILQ_INIT(&nmp->nm_resendq);
2746 TAILQ_INIT(&nmp->nm_iodq);
2747 TAILQ_INIT(&nmp->nm_gsscl);
2748 LIST_INIT(&nmp->nm_monlist);
2749 vfs_setfsprivate(mp, nmp);
2750 vfs_getnewfsid(mp);
2751 nmp->nm_mountp = mp;
2752 vfs_setauthopaque(mp);
2753 /*
2754 * Disable cache_lookup_path for NFS. NFS lookup always needs
2755 * to be called to check if the directory attribute cache is
2756 * valid and possibly purge the directory before calling
2757 * cache_lookup.
2758 */
2759 vfs_setauthcache_ttl(mp, 0);
2760
2761 nfs_nhinit_finish();
2762
2763 nmp->nm_args = xdrbuf;
2764
2765 /* set up defaults */
2766 nmp->nm_ref = 0;
2767 nmp->nm_vers = 0;
2768 nmp->nm_min_vers = DEFAULT_NFS_MIN_VERS;
2769 nmp->nm_max_vers = DEFAULT_NFS_MAX_VERS;
2770 nmp->nm_timeo = NFS_TIMEO;
2771 nmp->nm_retry = NFS_RETRANS;
2772 nmp->nm_sotype = 0;
2773 nmp->nm_sofamily = 0;
2774 nmp->nm_nfsport = 0;
2775 nmp->nm_wsize = NFS_WSIZE;
2776 nmp->nm_rsize = NFS_RSIZE;
2777 nmp->nm_readdirsize = NFS_READDIRSIZE;
2778 nmp->nm_numgrps = NFS_MAXGRPS;
2779 nmp->nm_readahead = NFS_DEFRAHEAD;
2780 nmp->nm_tprintf_delay = nfs_tprintf_delay;
2781 if (nmp->nm_tprintf_delay < 0)
2782 nmp->nm_tprintf_delay = 0;
2783 nmp->nm_tprintf_initial_delay = nfs_tprintf_initial_delay;
2784 if (nmp->nm_tprintf_initial_delay < 0)
2785 nmp->nm_tprintf_initial_delay = 0;
2786 nmp->nm_acregmin = NFS_MINATTRTIMO;
2787 nmp->nm_acregmax = NFS_MAXATTRTIMO;
2788 nmp->nm_acdirmin = NFS_MINDIRATTRTIMO;
2789 nmp->nm_acdirmax = NFS_MAXDIRATTRTIMO;
2790 nmp->nm_etype = nfs_default_etypes;
2791 nmp->nm_auth = RPCAUTH_SYS;
2792 nmp->nm_iodlink.tqe_next = NFSNOLIST;
2793 nmp->nm_deadtimeout = 0;
2794 nmp->nm_curdeadtimeout = 0;
2795 NFS_BITMAP_SET(nmp->nm_flags, NFS_MFLAG_NOACL);
2796 nmp->nm_realm = NULL;
2797 nmp->nm_principal = NULL;
2798 nmp->nm_sprinc = NULL;
2799 }
2800
2801 mattrs = nmp->nm_mattrs;
2802 mflags = nmp->nm_mflags;
2803 mflags_mask = nmp->nm_mflags_mask;
2804
2805 /* set up NFS mount with args */
2806 xb_init_buffer(&xb, xdrbuf, 2*XDRWORD);
2807 xb_get_32(error, &xb, val); /* version */
2808 xb_get_32(error, &xb, argslength); /* args length */
2809 nfsmerr_if(error);
2810 xb_init_buffer(&xb, xdrbuf, argslength); /* restart parsing with actual buffer length */
2811 xb_get_32(error, &xb, val); /* version */
2812 xb_get_32(error, &xb, argslength); /* args length */
2813 xb_get_32(error, &xb, val); /* XDR args version */
2814 if (val != NFS_XDRARGS_VERSION_0)
2815 error = EINVAL;
2816 len = NFS_MATTR_BITMAP_LEN;
2817 xb_get_bitmap(error, &xb, mattrs, len); /* mount attribute bitmap */
2818 attrslength = 0;
2819 xb_get_32(error, &xb, attrslength); /* attrs length */
2820 if (!error && (attrslength > (argslength - ((4+NFS_MATTR_BITMAP_LEN+1)*XDRWORD))))
2821 error = EINVAL;
2822 nfsmerr_if(error);
2823 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_FLAGS)) {
2824 len = NFS_MFLAG_BITMAP_LEN;
2825 xb_get_bitmap(error, &xb, mflags_mask, len); /* mount flag mask */
2826 len = NFS_MFLAG_BITMAP_LEN;
2827 xb_get_bitmap(error, &xb, mflags, len); /* mount flag values */
2828 if (!error) {
2829 /* clear all mask bits and OR in all the ones that are set */
2830 nmp->nm_flags[0] &= ~mflags_mask[0];
2831 nmp->nm_flags[0] |= (mflags_mask[0] & mflags[0]);
2832 }
2833 }
2834 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_NFS_VERSION)) {
2835 /* Can't specify a single version and a range */
2836 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_NFS_VERSION_RANGE))
2837 error = EINVAL;
2838 xb_get_32(error, &xb, nmp->nm_vers);
2839 if (nmp->nm_vers > NFS_MAX_SUPPORTED_VERSION ||
2840 nmp->nm_vers < NFS_VER2)
2841 error = EINVAL;
2842 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_NFS_MINOR_VERSION))
2843 xb_get_32(error, &xb, nmp->nm_minor_vers);
2844 else
2845 nmp->nm_minor_vers = maxminorverstab[nmp->nm_vers];
2846 if (nmp->nm_minor_vers > maxminorverstab[nmp->nm_vers])
2847 error = EINVAL;
2848 nmp->nm_max_vers = nmp->nm_min_vers =
2849 VER2PVER(nmp->nm_vers, nmp->nm_minor_vers);
2850 }
2851 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_NFS_MINOR_VERSION)) {
2852 /* should have also gotten NFS version (and already gotten minor version) */
2853 if (!NFS_BITMAP_ISSET(mattrs, NFS_MATTR_NFS_VERSION))
2854 error = EINVAL;
2855 }
2856 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_NFS_VERSION_RANGE)) {
2857 xb_get_32(error, &xb, nmp->nm_min_vers);
2858 xb_get_32(error, &xb, nmp->nm_max_vers);
2859 if ((nmp->nm_min_vers > nmp->nm_max_vers) ||
2860 (PVER2MAJOR(nmp->nm_max_vers) > NFS_MAX_SUPPORTED_VERSION) ||
2861 (PVER2MINOR(nmp->nm_min_vers) > maxminorverstab[PVER2MAJOR(nmp->nm_min_vers)]) ||
2862 (PVER2MINOR(nmp->nm_max_vers) > maxminorverstab[PVER2MAJOR(nmp->nm_max_vers)]))
2863 error = EINVAL;
2864 }
2865 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_READ_SIZE))
2866 xb_get_32(error, &xb, nmp->nm_rsize);
2867 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_WRITE_SIZE))
2868 xb_get_32(error, &xb, nmp->nm_wsize);
2869 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_READDIR_SIZE))
2870 xb_get_32(error, &xb, nmp->nm_readdirsize);
2871 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_READAHEAD))
2872 xb_get_32(error, &xb, nmp->nm_readahead);
2873 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_ATTRCACHE_REG_MIN)) {
2874 xb_get_32(error, &xb, nmp->nm_acregmin);
2875 xb_skip(error, &xb, XDRWORD);
2876 }
2877 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_ATTRCACHE_REG_MAX)) {
2878 xb_get_32(error, &xb, nmp->nm_acregmax);
2879 xb_skip(error, &xb, XDRWORD);
2880 }
2881 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_ATTRCACHE_DIR_MIN)) {
2882 xb_get_32(error, &xb, nmp->nm_acdirmin);
2883 xb_skip(error, &xb, XDRWORD);
2884 }
2885 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_ATTRCACHE_DIR_MAX)) {
2886 xb_get_32(error, &xb, nmp->nm_acdirmax);
2887 xb_skip(error, &xb, XDRWORD);
2888 }
2889 nfsmerr_if(error);
2890 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_LOCK_MODE)) {
2891 xb_get_32(error, &xb, val);
2892 switch (val) {
2893 case NFS_LOCK_MODE_DISABLED:
2894 case NFS_LOCK_MODE_LOCAL:
2895 if (nmp->nm_vers >= NFS_VER4) {
2896 /* disabled/local lock mode only allowed on v2/v3 */
2897 error = EINVAL;
2898 break;
2899 }
2900 /* FALLTHROUGH */
2901 case NFS_LOCK_MODE_ENABLED:
2902 nmp->nm_lockmode = val;
2903 break;
2904 default:
2905 error = EINVAL;
2906 }
2907 }
2908 nfsmerr_if(error);
2909 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_SECURITY)) {
2910 uint32_t seccnt;
2911 xb_get_32(error, &xb, seccnt);
2912 if (!error && ((seccnt < 1) || (seccnt > NX_MAX_SEC_FLAVORS)))
2913 error = EINVAL;
2914 nfsmerr_if(error);
2915 nmp->nm_sec.count = seccnt;
2916 for (i=0; i < seccnt; i++) {
2917 xb_get_32(error, &xb, nmp->nm_sec.flavors[i]);
2918 /* Check for valid security flavor */
2919 switch (nmp->nm_sec.flavors[i]) {
2920 case RPCAUTH_NONE:
2921 case RPCAUTH_SYS:
2922 case RPCAUTH_KRB5:
2923 case RPCAUTH_KRB5I:
2924 case RPCAUTH_KRB5P:
2925 break;
2926 default:
2927 error = EINVAL;
2928 }
2929 }
2930 /* start with the first flavor */
2931 nmp->nm_auth = nmp->nm_sec.flavors[0];
2932 }
2933 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_KERB_ETYPE)) {
2934 uint32_t etypecnt;
2935 xb_get_32(error, &xb, etypecnt);
2936 if (!error && ((etypecnt < 1) || (etypecnt > NFS_MAX_ETYPES)))
2937 error = EINVAL;
2938 nfsmerr_if(error);
2939 nmp->nm_etype.count = etypecnt;
2940 xb_get_32(error, &xb, nmp->nm_etype.selected);
2941 nfsmerr_if(error);
2942 if (etypecnt) {
2943 nmp->nm_etype.selected = etypecnt; /* Nothing is selected yet, so set selected to count */
2944 for (i=0; i < etypecnt; i++) {
2945 xb_get_32(error, &xb, nmp->nm_etype.etypes[i]);
2946 /* Check for valid encryption type */
2947 switch (nmp->nm_etype.etypes[i]) {
2948 case NFS_DES3_CBC_SHA1_KD:
2949 case NFS_AES128_CTS_HMAC_SHA1_96:
2950 case NFS_AES256_CTS_HMAC_SHA1_96:
2951 break;
2952 default:
2953 error = EINVAL;
2954 }
2955 }
2956 }
2957 }
2958 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_MAX_GROUP_LIST))
2959 xb_get_32(error, &xb, nmp->nm_numgrps);
2960 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_SOCKET_TYPE)) {
2961 char sotype[6];
2962
2963 xb_get_32(error, &xb, val);
2964 if (!error && ((val < 3) || (val > 5)))
2965 error = EINVAL;
2966 nfsmerr_if(error);
2967 error = xb_get_bytes(&xb, sotype, val, 0);
2968 nfsmerr_if(error);
2969 sotype[val] = '\0';
2970 if (!strcmp(sotype, "tcp")) {
2971 nmp->nm_sotype = SOCK_STREAM;
2972 } else if (!strcmp(sotype, "udp")) {
2973 nmp->nm_sotype = SOCK_DGRAM;
2974 } else if (!strcmp(sotype, "tcp4")) {
2975 nmp->nm_sotype = SOCK_STREAM;
2976 nmp->nm_sofamily = AF_INET;
2977 } else if (!strcmp(sotype, "udp4")) {
2978 nmp->nm_sotype = SOCK_DGRAM;
2979 nmp->nm_sofamily = AF_INET;
2980 } else if (!strcmp(sotype, "tcp6")) {
2981 nmp->nm_sotype = SOCK_STREAM;
2982 nmp->nm_sofamily = AF_INET6;
2983 } else if (!strcmp(sotype, "udp6")) {
2984 nmp->nm_sotype = SOCK_DGRAM;
2985 nmp->nm_sofamily = AF_INET6;
2986 } else if (!strcmp(sotype, "inet4")) {
2987 nmp->nm_sofamily = AF_INET;
2988 } else if (!strcmp(sotype, "inet6")) {
2989 nmp->nm_sofamily = AF_INET6;
2990 } else if (!strcmp(sotype, "inet")) {
2991 nmp->nm_sofamily = 0; /* ok */
2992 } else {
2993 error = EINVAL;
2994 }
2995 if (!error && (nmp->nm_vers >= NFS_VER4) && nmp->nm_sotype &&
2996 (nmp->nm_sotype != SOCK_STREAM))
2997 error = EINVAL; /* NFSv4 is only allowed over TCP. */
2998 nfsmerr_if(error);
2999 }
3000 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_NFS_PORT))
3001 xb_get_32(error, &xb, nmp->nm_nfsport);
3002 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_MOUNT_PORT))
3003 xb_get_32(error, &xb, nmp->nm_mountport);
3004 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_REQUEST_TIMEOUT)) {
3005 /* convert from time to 0.1s units */
3006 xb_get_32(error, &xb, nmp->nm_timeo);
3007 xb_get_32(error, &xb, val);
3008 nfsmerr_if(error);
3009 if (val >= 1000000000)
3010 error = EINVAL;
3011 nfsmerr_if(error);
3012 nmp->nm_timeo *= 10;
3013 nmp->nm_timeo += (val+100000000-1)/100000000;
3014 /* now convert to ticks */
3015 nmp->nm_timeo = (nmp->nm_timeo * NFS_HZ + 5) / 10;
3016 }
3017 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_SOFT_RETRY_COUNT)) {
3018 xb_get_32(error, &xb, val);
3019 if (!error && (val > 1))
3020 nmp->nm_retry = val;
3021 }
3022 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_DEAD_TIMEOUT)) {
3023 xb_get_32(error, &xb, nmp->nm_deadtimeout);
3024 xb_skip(error, &xb, XDRWORD);
3025 }
3026 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_FH)) {
3027 nfsmerr_if(error);
3028 MALLOC(nmp->nm_fh, fhandle_t *, sizeof(fhandle_t), M_TEMP, M_WAITOK|M_ZERO);
3029 if (!nmp->nm_fh)
3030 error = ENOMEM;
3031 xb_get_32(error, &xb, nmp->nm_fh->fh_len);
3032 nfsmerr_if(error);
3033 if (nmp->nm_fh->fh_len < 0 ||
3034 (size_t)nmp->nm_fh->fh_len > sizeof(nmp->nm_fh->fh_data))
3035 error = EINVAL;
3036 else
3037 error = xb_get_bytes(&xb, (char*)&nmp->nm_fh->fh_data[0], nmp->nm_fh->fh_len, 0);
3038 }
3039 nfsmerr_if(error);
3040 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_FS_LOCATIONS)) {
3041 uint32_t loc, serv, addr, comp;
3042 struct nfs_fs_location *fsl;
3043 struct nfs_fs_server *fss;
3044 struct nfs_fs_path *fsp;
3045
3046 xb_get_32(error, &xb, nmp->nm_locations.nl_numlocs); /* fs location count */
3047 /* sanity check location count */
3048 if (!error && ((nmp->nm_locations.nl_numlocs < 1) || (nmp->nm_locations.nl_numlocs > 256)))
3049 error = EINVAL;
3050 nfsmerr_if(error);
3051 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);
3052 if (!nmp->nm_locations.nl_locations)
3053 error = ENOMEM;
3054 for (loc = 0; loc < nmp->nm_locations.nl_numlocs; loc++) {
3055 nfsmerr_if(error);
3056 MALLOC(fsl, struct nfs_fs_location *, sizeof(struct nfs_fs_location), M_TEMP, M_WAITOK|M_ZERO);
3057 if (!fsl)
3058 error = ENOMEM;
3059 nmp->nm_locations.nl_locations[loc] = fsl;
3060 xb_get_32(error, &xb, fsl->nl_servcount); /* server count */
3061 /* sanity check server count */
3062 if (!error && ((fsl->nl_servcount < 1) || (fsl->nl_servcount > 256)))
3063 error = EINVAL;
3064 nfsmerr_if(error);
3065 MALLOC(fsl->nl_servers, struct nfs_fs_server **, fsl->nl_servcount * sizeof(struct nfs_fs_server*), M_TEMP, M_WAITOK|M_ZERO);
3066 if (!fsl->nl_servers)
3067 error = ENOMEM;
3068 for (serv = 0; serv < fsl->nl_servcount; serv++) {
3069 nfsmerr_if(error);
3070 MALLOC(fss, struct nfs_fs_server *, sizeof(struct nfs_fs_server), M_TEMP, M_WAITOK|M_ZERO);
3071 if (!fss)
3072 error = ENOMEM;
3073 fsl->nl_servers[serv] = fss;
3074 xb_get_32(error, &xb, val); /* server name length */
3075 /* sanity check server name length */
3076 if (!error && ((val < 1) || (val > MAXPATHLEN)))
3077 error = EINVAL;
3078 nfsmerr_if(error);
3079 MALLOC(fss->ns_name, char *, val+1, M_TEMP, M_WAITOK|M_ZERO);
3080 if (!fss->ns_name)
3081 error = ENOMEM;
3082 nfsmerr_if(error);
3083 error = xb_get_bytes(&xb, fss->ns_name, val, 0); /* server name */
3084 xb_get_32(error, &xb, fss->ns_addrcount); /* address count */
3085 /* sanity check address count (OK to be zero) */
3086 if (!error && (fss->ns_addrcount > 256))
3087 error = EINVAL;
3088 nfsmerr_if(error);
3089 if (fss->ns_addrcount > 0) {
3090 MALLOC(fss->ns_addresses, char **, fss->ns_addrcount * sizeof(char *), M_TEMP, M_WAITOK|M_ZERO);
3091 if (!fss->ns_addresses)
3092 error = ENOMEM;
3093 for (addr = 0; addr < fss->ns_addrcount; addr++) {
3094 xb_get_32(error, &xb, val); /* address length */
3095 /* sanity check address length */
3096 if (!error && ((val < 1) || (val > 128)))
3097 error = EINVAL;
3098 nfsmerr_if(error);
3099 MALLOC(fss->ns_addresses[addr], char *, val+1, M_TEMP, M_WAITOK|M_ZERO);
3100 if (!fss->ns_addresses[addr])
3101 error = ENOMEM;
3102 nfsmerr_if(error);
3103 error = xb_get_bytes(&xb, fss->ns_addresses[addr], val, 0); /* address */
3104 }
3105 }
3106 xb_get_32(error, &xb, val); /* server info length */
3107 xb_skip(error, &xb, val); /* skip server info */
3108 }
3109 /* get pathname */
3110 fsp = &fsl->nl_path;
3111 xb_get_32(error, &xb, fsp->np_compcount); /* component count */
3112 /* sanity check component count */
3113 if (!error && (fsp->np_compcount > MAXPATHLEN))
3114 error = EINVAL;
3115 nfsmerr_if(error);
3116 if (fsp->np_compcount) {
3117 MALLOC(fsp->np_components, char **, fsp->np_compcount * sizeof(char*), M_TEMP, M_WAITOK|M_ZERO);
3118 if (!fsp->np_components)
3119 error = ENOMEM;
3120 }
3121 for (comp = 0; comp < fsp->np_compcount; comp++) {
3122 xb_get_32(error, &xb, val); /* component length */
3123 /* sanity check component length */
3124 if (!error && (val == 0)) {
3125 /*
3126 * Apparently some people think a path with zero components should
3127 * be encoded with one zero-length component. So, just ignore any
3128 * zero length components.
3129 */
3130 comp--;
3131 fsp->np_compcount--;
3132 if (fsp->np_compcount == 0) {
3133 FREE(fsp->np_components, M_TEMP);
3134 fsp->np_components = NULL;
3135 }
3136 continue;
3137 }
3138 if (!error && ((val < 1) || (val > MAXPATHLEN)))
3139 error = EINVAL;
3140 nfsmerr_if(error);
3141 MALLOC(fsp->np_components[comp], char *, val+1, M_TEMP, M_WAITOK|M_ZERO);
3142 if (!fsp->np_components[comp])
3143 error = ENOMEM;
3144 nfsmerr_if(error);
3145 error = xb_get_bytes(&xb, fsp->np_components[comp], val, 0); /* component */
3146 }
3147 xb_get_32(error, &xb, val); /* fs location info length */
3148 xb_skip(error, &xb, val); /* skip fs location info */
3149 }
3150 }
3151 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_MNTFLAGS))
3152 xb_skip(error, &xb, XDRWORD);
3153 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_MNTFROM)) {
3154 xb_get_32(error, &xb, len);
3155 nfsmerr_if(error);
3156 val = len;
3157 if (val >= sizeof(vfs_statfs(mp)->f_mntfromname))
3158 val = sizeof(vfs_statfs(mp)->f_mntfromname) - 1;
3159 error = xb_get_bytes(&xb, vfs_statfs(mp)->f_mntfromname, val, 0);
3160 if ((len - val) > 0)
3161 xb_skip(error, &xb, len - val);
3162 nfsmerr_if(error);
3163 vfs_statfs(mp)->f_mntfromname[val] = '\0';
3164 }
3165 nfsmerr_if(error);
3166
3167 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_REALM)) {
3168 xb_get_32(error, &xb, len);
3169 if (!error && ((len < 1) || (len > MAXPATHLEN)))
3170 error=EINVAL;
3171 nfsmerr_if(error);
3172 /* allocate an extra byte for a leading '@' if its not already prepended to the realm */
3173 MALLOC(nmp->nm_realm, char *, len+2, M_TEMP, M_WAITOK|M_ZERO);
3174 if (!nmp->nm_realm)
3175 error = ENOMEM;
3176 nfsmerr_if(error);
3177 error = xb_get_bytes(&xb, nmp->nm_realm, len, 0);
3178 if (error == 0 && *nmp->nm_realm != '@') {
3179 bcopy(nmp->nm_realm, &nmp->nm_realm[1], len);
3180 nmp->nm_realm[0] = '@';
3181 }
3182 }
3183 nfsmerr_if(error);
3184
3185 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_PRINCIPAL)) {
3186 xb_get_32(error, &xb, len);
3187 if (!error && ((len < 1) || (len > MAXPATHLEN)))
3188 error=EINVAL;
3189 nfsmerr_if(error);
3190 MALLOC(nmp->nm_principal, char *, len+1, M_TEMP, M_WAITOK|M_ZERO);
3191 if (!nmp->nm_principal)
3192 error = ENOMEM;
3193 nfsmerr_if(error);
3194 error = xb_get_bytes(&xb, nmp->nm_principal, len, 0);
3195 }
3196 nfsmerr_if(error);
3197
3198 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_SVCPRINCIPAL)) {
3199 xb_get_32(error, &xb, len);
3200 if (!error && ((len < 1) || (len > MAXPATHLEN)))
3201 error=EINVAL;
3202 nfsmerr_if(error);
3203 MALLOC(nmp->nm_sprinc, char *, len+1, M_TEMP, M_WAITOK|M_ZERO);
3204 if (!nmp->nm_sprinc)
3205 error = ENOMEM;
3206 nfsmerr_if(error);
3207 error = xb_get_bytes(&xb, nmp->nm_sprinc, len, 0);
3208 }
3209 nfsmerr_if(error);
3210
3211 /*
3212 * Sanity check/finalize settings.
3213 */
3214
3215 if (nmp->nm_timeo < NFS_MINTIMEO)
3216 nmp->nm_timeo = NFS_MINTIMEO;
3217 else if (nmp->nm_timeo > NFS_MAXTIMEO)
3218 nmp->nm_timeo = NFS_MAXTIMEO;
3219 if (nmp->nm_retry > NFS_MAXREXMIT)
3220 nmp->nm_retry = NFS_MAXREXMIT;
3221
3222 if (nmp->nm_numgrps > NFS_MAXGRPS)
3223 nmp->nm_numgrps = NFS_MAXGRPS;
3224 if (nmp->nm_readahead > NFS_MAXRAHEAD)
3225 nmp->nm_readahead = NFS_MAXRAHEAD;
3226 if (nmp->nm_acregmin > nmp->nm_acregmax)
3227 nmp->nm_acregmin = nmp->nm_acregmax;
3228 if (nmp->nm_acdirmin > nmp->nm_acdirmax)
3229 nmp->nm_acdirmin = nmp->nm_acdirmax;
3230
3231 /* need at least one fs location */
3232 if (nmp->nm_locations.nl_numlocs < 1)
3233 error = EINVAL;
3234 nfsmerr_if(error);
3235
3236 /* init mount's mntfromname to first location */
3237 if (!NM_OMATTR_GIVEN(nmp, MNTFROM))
3238 nfs_location_mntfromname(&nmp->nm_locations, firstloc,
3239 vfs_statfs(mp)->f_mntfromname, sizeof(vfs_statfs(mp)->f_mntfromname), 0);
3240
3241 /* Need to save the mounting credential for v4. */
3242 nmp->nm_mcred = vfs_context_ucred(ctx);
3243 if (IS_VALID_CRED(nmp->nm_mcred))
3244 kauth_cred_ref(nmp->nm_mcred);
3245
3246 /*
3247 * If a reserved port is required, check for that privilege.
3248 * (Note that mirror mounts are exempt because the privilege was
3249 * already checked for the original mount.)
3250 */
3251 if (NMFLAG(nmp, RESVPORT) && !vfs_iskernelmount(mp))
3252 error = priv_check_cred(nmp->nm_mcred, PRIV_NETINET_RESERVEDPORT, 0);
3253 nfsmerr_if(error);
3254
3255 /* do mount's initial socket connection */
3256 error = nfs_mount_connect(nmp);
3257 nfsmerr_if(error);
3258
3259 /* set up the version-specific function tables */
3260 if (nmp->nm_vers < NFS_VER4)
3261 nmp->nm_funcs = &nfs3_funcs;
3262 else
3263 nmp->nm_funcs = &nfs4_funcs;
3264
3265 /* sanity check settings now that version/connection is set */
3266 if (nmp->nm_vers == NFS_VER2) /* ignore RDIRPLUS on NFSv2 */
3267 NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_RDIRPLUS);
3268 if (nmp->nm_vers >= NFS_VER4) {
3269 if (NFS_BITMAP_ISSET(nmp->nm_flags, NFS_MFLAG_ACLONLY)) /* aclonly trumps noacl */
3270 NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_NOACL);
3271 NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_CALLUMNT);
3272 if (nmp->nm_lockmode != NFS_LOCK_MODE_ENABLED)
3273 error = EINVAL; /* disabled/local lock mode only allowed on v2/v3 */
3274 } else {
3275 /* ignore these if not v4 */
3276 NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_NOCALLBACK);
3277 NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_NAMEDATTR);
3278 NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_NOACL);
3279 NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_ACLONLY);
3280 }
3281 nfsmerr_if(error);
3282
3283 if (nmp->nm_sotype == SOCK_DGRAM) {
3284 /* I/O size defaults for UDP are different */
3285 if (!NFS_BITMAP_ISSET(mattrs, NFS_MATTR_READ_SIZE))
3286 nmp->nm_rsize = NFS_DGRAM_RSIZE;
3287 if (!NFS_BITMAP_ISSET(mattrs, NFS_MATTR_WRITE_SIZE))
3288 nmp->nm_wsize = NFS_DGRAM_WSIZE;
3289 }
3290
3291 /* round down I/O sizes to multiple of NFS_FABLKSIZE */
3292 nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1);
3293 if (nmp->nm_rsize <= 0)
3294 nmp->nm_rsize = NFS_FABLKSIZE;
3295 nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1);
3296 if (nmp->nm_wsize <= 0)
3297 nmp->nm_wsize = NFS_FABLKSIZE;
3298
3299 /* and limit I/O sizes to maximum allowed */
3300 maxio = (nmp->nm_vers == NFS_VER2) ? NFS_V2MAXDATA :
3301 (nmp->nm_sotype == SOCK_DGRAM) ? NFS_MAXDGRAMDATA : NFS_MAXDATA;
3302 if (maxio > NFS_MAXBSIZE)
3303 maxio = NFS_MAXBSIZE;
3304 if (nmp->nm_rsize > maxio)
3305 nmp->nm_rsize = maxio;
3306 if (nmp->nm_wsize > maxio)
3307 nmp->nm_wsize = maxio;
3308
3309 if (nmp->nm_readdirsize > maxio)
3310 nmp->nm_readdirsize = maxio;
3311 if (nmp->nm_readdirsize > nmp->nm_rsize)
3312 nmp->nm_readdirsize = nmp->nm_rsize;
3313
3314 /* Set up the sockets and related info */
3315 if (nmp->nm_sotype == SOCK_DGRAM)
3316 TAILQ_INIT(&nmp->nm_cwndq);
3317
3318 /*
3319 * Get the root node/attributes from the NFS server and
3320 * do any basic, version-specific setup.
3321 */
3322 error = nmp->nm_funcs->nf_mount(nmp, ctx, &np);
3323 nfsmerr_if(error);
3324
3325 /*
3326 * A reference count is needed on the node representing the
3327 * remote root. If this object is not persistent, then backward
3328 * traversals of the mount point (i.e. "..") will not work if
3329 * the node gets flushed out of the cache.
3330 */
3331 nmp->nm_dnp = np;
3332 *vpp = NFSTOV(np);
3333 /* get usecount and drop iocount */
3334 error = vnode_ref(*vpp);
3335 vnode_put(*vpp);
3336 if (error) {
3337 vnode_recycle(*vpp);
3338 goto nfsmerr;
3339 }
3340
3341 /*
3342 * Do statfs to ensure static info gets set to reasonable values.
3343 */
3344 if ((error = nmp->nm_funcs->nf_update_statfs(nmp, ctx))) {
3345 int error2 = vnode_getwithref(*vpp);
3346 vnode_rele(*vpp);
3347 if (!error2)
3348 vnode_put(*vpp);
3349 vnode_recycle(*vpp);
3350 goto nfsmerr;
3351 }
3352 sbp = vfs_statfs(mp);
3353 sbp->f_bsize = nmp->nm_fsattr.nfsa_bsize;
3354 sbp->f_blocks = nmp->nm_fsattr.nfsa_space_total / sbp->f_bsize;
3355 sbp->f_bfree = nmp->nm_fsattr.nfsa_space_free / sbp->f_bsize;
3356 sbp->f_bavail = nmp->nm_fsattr.nfsa_space_avail / sbp->f_bsize;
3357 sbp->f_bused = (nmp->nm_fsattr.nfsa_space_total / sbp->f_bsize) -
3358 (nmp->nm_fsattr.nfsa_space_free / sbp->f_bsize);
3359 sbp->f_files = nmp->nm_fsattr.nfsa_files_total;
3360 sbp->f_ffree = nmp->nm_fsattr.nfsa_files_free;
3361 sbp->f_iosize = nfs_iosize;
3362
3363 /*
3364 * Calculate the size used for I/O buffers. Use the larger
3365 * of the two sizes to minimise NFS requests but make sure
3366 * that it is at least one VM page to avoid wasting buffer
3367 * space and to allow easy mmapping of I/O buffers.
3368 * The read/write RPC calls handle the splitting up of
3369 * buffers into multiple requests if the buffer size is
3370 * larger than the I/O size.
3371 */
3372 #ifndef CONFIG_EMBEDDED
3373 iosize = max(nmp->nm_rsize, nmp->nm_wsize);
3374 if (iosize < PAGE_SIZE)
3375 iosize = PAGE_SIZE;
3376 #else
3377 iosize = PAGE_SIZE;
3378 #endif
3379 nmp->nm_biosize = trunc_page_32(iosize);
3380
3381 /* For NFSv3 and greater, there is a (relatively) reliable ACCESS call. */
3382 if (nmp->nm_vers > NFS_VER2)
3383 vfs_setauthopaqueaccess(mp);
3384
3385 switch (nmp->nm_lockmode) {
3386 case NFS_LOCK_MODE_DISABLED:
3387 break;
3388 case NFS_LOCK_MODE_LOCAL:
3389 vfs_setlocklocal(nmp->nm_mountp);
3390 break;
3391 case NFS_LOCK_MODE_ENABLED:
3392 default:
3393 if (nmp->nm_vers <= NFS_VER3)
3394 nfs_lockd_mount_register(nmp);
3395 break;
3396 }
3397
3398 /* success! */
3399 lck_mtx_lock(&nmp->nm_lock);
3400 nmp->nm_state |= NFSSTA_MOUNTED;
3401 lck_mtx_unlock(&nmp->nm_lock);
3402 return (0);
3403 nfsmerr:
3404 nfs_mount_drain_and_cleanup(nmp);
3405 return (error);
3406 }
3407
3408 #if CONFIG_TRIGGERS
3409
3410 /*
3411 * We've detected a file system boundary on the server and
3412 * need to mount a new file system so that our file systems
3413 * MIRROR the file systems on the server.
3414 *
3415 * Build the mount arguments for the new mount and call kernel_mount().
3416 */
3417 int
3418 nfs_mirror_mount_domount(vnode_t dvp, vnode_t vp, vfs_context_t ctx)
3419 {
3420 nfsnode_t np = VTONFS(vp);
3421 nfsnode_t dnp = VTONFS(dvp);
3422 struct nfsmount *nmp = NFSTONMP(np);
3423 char fstype[MFSTYPENAMELEN], *mntfromname = NULL, *path = NULL, *relpath, *p, *cp;
3424 int error = 0, pathbuflen = MAXPATHLEN, i, mntflags = 0, referral, skipcopy = 0;
3425 size_t nlen;
3426 struct xdrbuf xb, xbnew;
3427 uint32_t mattrs[NFS_MATTR_BITMAP_LEN];
3428 uint32_t newmattrs[NFS_MATTR_BITMAP_LEN];
3429 uint32_t newmflags[NFS_MFLAG_BITMAP_LEN];
3430 uint32_t newmflags_mask[NFS_MFLAG_BITMAP_LEN];
3431 uint32_t argslength = 0, val, count, mlen, mlen2, rlen, relpathcomps;
3432 uint32_t argslength_offset, attrslength_offset, end_offset;
3433 uint32_t numlocs, loc, numserv, serv, numaddr, addr, numcomp, comp;
3434 char buf[XDRWORD];
3435 struct nfs_fs_locations nfsls;
3436
3437 referral = (np->n_vattr.nva_flags & NFS_FFLAG_TRIGGER_REFERRAL);
3438 if (referral)
3439 bzero(&nfsls, sizeof(nfsls));
3440
3441 xb_init(&xbnew, 0);
3442
3443 if (!nmp || (nmp->nm_state & (NFSSTA_FORCE|NFSSTA_DEAD)))
3444 return (ENXIO);
3445
3446 /* allocate a couple path buffers we need */
3447 MALLOC_ZONE(mntfromname, char *, pathbuflen, M_NAMEI, M_WAITOK);
3448 if (!mntfromname) {
3449 error = ENOMEM;
3450 goto nfsmerr;
3451 }
3452 MALLOC_ZONE(path, char *, pathbuflen, M_NAMEI, M_WAITOK);
3453 if (!path) {
3454 error = ENOMEM;
3455 goto nfsmerr;
3456 }
3457
3458 /* get the path for the directory being mounted on */
3459 error = vn_getpath(vp, path, &pathbuflen);
3460 if (error) {
3461 error = ENOMEM;
3462 goto nfsmerr;
3463 }
3464
3465 /*
3466 * Set up the mntfromname for the new mount based on the
3467 * current mount's mntfromname and the directory's path
3468 * relative to the current mount's mntonname.
3469 * Set up relpath to point at the relative path on the current mount.
3470 * Also, count the number of components in relpath.
3471 * We'll be adding those to each fs location path in the new args.
3472 */
3473 nlen = strlcpy(mntfromname, vfs_statfs(nmp->nm_mountp)->f_mntfromname, MAXPATHLEN);
3474 if ((nlen > 0) && (mntfromname[nlen-1] == '/')) { /* avoid double '/' in new name */
3475 mntfromname[nlen-1] = '\0';
3476 nlen--;
3477 }
3478 relpath = mntfromname + nlen;
3479 nlen = strlcat(mntfromname, path + strlen(vfs_statfs(nmp->nm_mountp)->f_mntonname), MAXPATHLEN);
3480 if (nlen >= MAXPATHLEN) {
3481 error = ENAMETOOLONG;
3482 goto nfsmerr;
3483 }
3484 /* count the number of components in relpath */
3485 p = relpath;
3486 while (*p && (*p == '/'))
3487 p++;
3488 relpathcomps = 0;
3489 while (*p) {
3490 relpathcomps++;
3491 while (*p && (*p != '/'))
3492 p++;
3493 while (*p && (*p == '/'))
3494 p++;
3495 }
3496
3497 /* grab a copy of the file system type */
3498 vfs_name(vnode_mount(vp), fstype);
3499
3500 /* for referrals, fetch the fs locations */
3501 if (referral) {
3502 const char *vname = vnode_getname(NFSTOV(np));
3503 if (!vname) {
3504 error = ENOENT;
3505 } else {
3506 error = nfs4_get_fs_locations(nmp, dnp, NULL, 0, vname, ctx, &nfsls);
3507 vnode_putname(vname);
3508 if (!error && (nfsls.nl_numlocs < 1))
3509 error = ENOENT;
3510 }
3511 nfsmerr_if(error);
3512 }
3513
3514 /* set up NFS mount args based on current mount args */
3515
3516 #define xb_copy_32(E, XBSRC, XBDST, V) \
3517 do { \
3518 if (E) break; \
3519 xb_get_32((E), (XBSRC), (V)); \
3520 if (skipcopy) break; \
3521 xb_add_32((E), (XBDST), (V)); \
3522 } while (0)
3523 #define xb_copy_opaque(E, XBSRC, XBDST) \
3524 do { \
3525 uint32_t __count, __val; \
3526 xb_copy_32((E), (XBSRC), (XBDST), __count); \
3527 if (E) break; \
3528 __count = nfsm_rndup(__count); \
3529 __count /= XDRWORD; \
3530 while (__count-- > 0) \
3531 xb_copy_32((E), (XBSRC), (XBDST), __val); \
3532 } while (0)
3533
3534 xb_init_buffer(&xb, nmp->nm_args, 2*XDRWORD);
3535 xb_get_32(error, &xb, val); /* version */
3536 xb_get_32(error, &xb, argslength); /* args length */
3537 xb_init_buffer(&xb, nmp->nm_args, argslength);
3538
3539 xb_init_buffer(&xbnew, NULL, 0);
3540 xb_copy_32(error, &xb, &xbnew, val); /* version */
3541 argslength_offset = xb_offset(&xbnew);
3542 xb_copy_32(error, &xb, &xbnew, val); /* args length */
3543 xb_copy_32(error, &xb, &xbnew, val); /* XDR args version */
3544 count = NFS_MATTR_BITMAP_LEN;
3545 xb_get_bitmap(error, &xb, mattrs, count); /* mount attribute bitmap */
3546 nfsmerr_if(error);
3547 for (i = 0; i < NFS_MATTR_BITMAP_LEN; i++)
3548 newmattrs[i] = mattrs[i];
3549 if (referral)
3550 NFS_BITMAP_SET(newmattrs, NFS_MATTR_FS_LOCATIONS);
3551 else
3552 NFS_BITMAP_SET(newmattrs, NFS_MATTR_FH);
3553 NFS_BITMAP_SET(newmattrs, NFS_MATTR_FLAGS);
3554 NFS_BITMAP_SET(newmattrs, NFS_MATTR_MNTFLAGS);
3555 NFS_BITMAP_CLR(newmattrs, NFS_MATTR_MNTFROM);
3556 xb_add_bitmap(error, &xbnew, newmattrs, NFS_MATTR_BITMAP_LEN);
3557 attrslength_offset = xb_offset(&xbnew);
3558 xb_copy_32(error, &xb, &xbnew, val); /* attrs length */
3559 NFS_BITMAP_ZERO(newmflags_mask, NFS_MFLAG_BITMAP_LEN);
3560 NFS_BITMAP_ZERO(newmflags, NFS_MFLAG_BITMAP_LEN);
3561 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_FLAGS)) {
3562 count = NFS_MFLAG_BITMAP_LEN;
3563 xb_get_bitmap(error, &xb, newmflags_mask, count); /* mount flag mask bitmap */
3564 count = NFS_MFLAG_BITMAP_LEN;
3565 xb_get_bitmap(error, &xb, newmflags, count); /* mount flag bitmap */
3566 }
3567 NFS_BITMAP_SET(newmflags_mask, NFS_MFLAG_EPHEMERAL);
3568 NFS_BITMAP_SET(newmflags, NFS_MFLAG_EPHEMERAL);
3569 xb_add_bitmap(error, &xbnew, newmflags_mask, NFS_MFLAG_BITMAP_LEN);
3570 xb_add_bitmap(error, &xbnew, newmflags, NFS_MFLAG_BITMAP_LEN);
3571 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_NFS_VERSION))
3572 xb_copy_32(error, &xb, &xbnew, val);
3573 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_NFS_MINOR_VERSION))
3574 xb_copy_32(error, &xb, &xbnew, val);
3575 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_NFS_VERSION_RANGE)) {
3576 xb_copy_32(error, &xb, &xbnew, val);
3577 xb_copy_32(error, &xb, &xbnew, val);
3578 }
3579 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_READ_SIZE))
3580 xb_copy_32(error, &xb, &xbnew, val);
3581 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_WRITE_SIZE))
3582 xb_copy_32(error, &xb, &xbnew, val);
3583 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_READDIR_SIZE))
3584 xb_copy_32(error, &xb, &xbnew, val);
3585 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_READAHEAD))
3586 xb_copy_32(error, &xb, &xbnew, val);
3587 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_ATTRCACHE_REG_MIN)) {
3588 xb_copy_32(error, &xb, &xbnew, val);
3589 xb_copy_32(error, &xb, &xbnew, val);
3590 }
3591 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_ATTRCACHE_REG_MAX)) {
3592 xb_copy_32(error, &xb, &xbnew, val);
3593 xb_copy_32(error, &xb, &xbnew, val);
3594 }
3595 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_ATTRCACHE_DIR_MIN)) {
3596 xb_copy_32(error, &xb, &xbnew, val);
3597 xb_copy_32(error, &xb, &xbnew, val);
3598 }
3599 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_ATTRCACHE_DIR_MAX)) {
3600 xb_copy_32(error, &xb, &xbnew, val);
3601 xb_copy_32(error, &xb, &xbnew, val);
3602 }
3603 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_LOCK_MODE))
3604 xb_copy_32(error, &xb, &xbnew, val);
3605 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_SECURITY)) {
3606 xb_copy_32(error, &xb, &xbnew, count);
3607 while (!error && (count-- > 0))
3608 xb_copy_32(error, &xb, &xbnew, val);
3609 }
3610 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_KERB_ETYPE)) {
3611 xb_copy_32(error, &xb, &xbnew, count);
3612 xb_add_32(error, &xbnew, -1);
3613 while (!error && (count-- > 0))
3614 xb_copy_32(error, &xb, &xbnew, val);
3615 }
3616 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_MAX_GROUP_LIST))
3617 xb_copy_32(error, &xb, &xbnew, val);
3618 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_SOCKET_TYPE))
3619 xb_copy_opaque(error, &xb, &xbnew);
3620 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_NFS_PORT))
3621 xb_copy_32(error, &xb, &xbnew, val);
3622 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_MOUNT_PORT))
3623 xb_copy_32(error, &xb, &xbnew, val);
3624 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_REQUEST_TIMEOUT)) {
3625 xb_copy_32(error, &xb, &xbnew, val);
3626 xb_copy_32(error, &xb, &xbnew, val);
3627 }
3628 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_SOFT_RETRY_COUNT))
3629 xb_copy_32(error, &xb, &xbnew, val);
3630 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_DEAD_TIMEOUT)) {
3631 xb_copy_32(error, &xb, &xbnew, val);
3632 xb_copy_32(error, &xb, &xbnew, val);
3633 }
3634 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_FH)) {
3635 xb_get_32(error, &xb, count);
3636 xb_skip(error, &xb, count);
3637 }
3638 if (!referral) {
3639 /* set the initial file handle to the directory's file handle */
3640 xb_add_fh(error, &xbnew, np->n_fhp, np->n_fhsize);
3641 }
3642 /* copy/extend/skip fs locations */
3643 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_FS_LOCATIONS)) {
3644 numlocs = numserv = numaddr = numcomp = 0;
3645 if (referral) /* don't copy the fs locations for a referral */
3646 skipcopy = 1;
3647 xb_copy_32(error, &xb, &xbnew, numlocs); /* location count */
3648 for (loc = 0; !error && (loc < numlocs); loc++) {
3649 xb_copy_32(error, &xb, &xbnew, numserv); /* server count */
3650 for (serv = 0; !error && (serv < numserv); serv++) {
3651 xb_copy_opaque(error, &xb, &xbnew); /* server name */
3652 xb_copy_32(error, &xb, &xbnew, numaddr); /* address count */
3653 for (addr = 0; !error && (addr < numaddr); addr++)
3654 xb_copy_opaque(error, &xb, &xbnew); /* address */
3655 xb_copy_opaque(error, &xb, &xbnew); /* server info */
3656 }
3657 /* pathname */
3658 xb_get_32(error, &xb, numcomp); /* component count */
3659 if (!skipcopy)
3660 xb_add_32(error, &xbnew, numcomp+relpathcomps); /* new component count */
3661 for (comp = 0; !error && (comp < numcomp); comp++)
3662 xb_copy_opaque(error, &xb, &xbnew); /* component */
3663 /* add additional components */
3664 for (comp = 0; !skipcopy && !error && (comp < relpathcomps); comp++) {
3665 p = relpath;
3666 while (*p && (*p == '/'))
3667 p++;
3668 while (*p && !error) {
3669 cp = p;
3670 while (*p && (*p != '/'))
3671 p++;
3672 xb_add_string(error, &xbnew, cp, (p - cp)); /* component */
3673 while (*p && (*p == '/'))
3674 p++;
3675 }
3676 }
3677 xb_copy_opaque(error, &xb, &xbnew); /* fs location info */
3678 }
3679 if (referral)
3680 skipcopy = 0;
3681 }
3682 if (referral) {
3683 /* add referral's fs locations */
3684 xb_add_32(error, &xbnew, nfsls.nl_numlocs); /* FS_LOCATIONS */
3685 for (loc = 0; !error && (loc < nfsls.nl_numlocs); loc++) {
3686 xb_add_32(error, &xbnew, nfsls.nl_locations[loc]->nl_servcount);
3687 for (serv = 0; !error && (serv < nfsls.nl_locations[loc]->nl_servcount); serv++) {
3688 xb_add_string(error, &xbnew, nfsls.nl_locations[loc]->nl_servers[serv]->ns_name,
3689 strlen(nfsls.nl_locations[loc]->nl_servers[serv]->ns_name));
3690 xb_add_32(error, &xbnew, nfsls.nl_locations[loc]->nl_servers[serv]->ns_addrcount);
3691 for (addr = 0; !error && (addr < nfsls.nl_locations[loc]->nl_servers[serv]->ns_addrcount); addr++)
3692 xb_add_string(error, &xbnew, nfsls.nl_locations[loc]->nl_servers[serv]->ns_addresses[addr],
3693 strlen(nfsls.nl_locations[loc]->nl_servers[serv]->ns_addresses[addr]));
3694 xb_add_32(error, &xbnew, 0); /* empty server info */
3695 }
3696 xb_add_32(error, &xbnew, nfsls.nl_locations[loc]->nl_path.np_compcount);
3697 for (comp = 0; !error && (comp < nfsls.nl_locations[loc]->nl_path.np_compcount); comp++)
3698 xb_add_string(error, &xbnew, nfsls.nl_locations[loc]->nl_path.np_components[comp],
3699 strlen(nfsls.nl_locations[loc]->nl_path.np_components[comp]));
3700 xb_add_32(error, &xbnew, 0); /* empty fs location info */
3701 }
3702 }
3703 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_MNTFLAGS))
3704 xb_get_32(error, &xb, mntflags);
3705 /*
3706 * We add the following mount flags to the ones for the mounted-on mount:
3707 * MNT_DONTBROWSE - to keep the mount from showing up as a separate volume
3708 * MNT_AUTOMOUNTED - to keep DiskArb from retriggering the mount after
3709 * an unmount (looking for /.autodiskmounted)
3710 */
3711 mntflags |= (MNT_AUTOMOUNTED | MNT_DONTBROWSE);
3712 xb_add_32(error, &xbnew, mntflags);
3713 if (!referral && NFS_BITMAP_ISSET(mattrs, NFS_MATTR_MNTFROM)) {
3714 /* copy mntfrom string and add relpath */
3715 rlen = strlen(relpath);
3716 xb_get_32(error, &xb, mlen);
3717 nfsmerr_if(error);
3718 mlen2 = mlen + ((relpath[0] != '/') ? 1 : 0) + rlen;
3719 xb_add_32(error, &xbnew, mlen2);
3720 count = mlen/XDRWORD;
3721 /* copy the original string */
3722 while (count-- > 0)
3723 xb_copy_32(error, &xb, &xbnew, val);
3724 if (!error && (mlen % XDRWORD)) {
3725 error = xb_get_bytes(&xb, buf, mlen%XDRWORD, 0);
3726 if (!error)
3727 error = xb_add_bytes(&xbnew, buf, mlen%XDRWORD, 1);
3728 }
3729 /* insert a '/' if the relative path doesn't start with one */
3730 if (!error && (relpath[0] != '/')) {
3731 buf[0] = '/';
3732 error = xb_add_bytes(&xbnew, buf, 1, 1);
3733 }
3734 /* add the additional relative path */
3735 if (!error)
3736 error = xb_add_bytes(&xbnew, relpath, rlen, 1);
3737 /* make sure the resulting string has the right number of pad bytes */
3738 if (!error && (mlen2 != nfsm_rndup(mlen2))) {
3739 bzero(buf, sizeof(buf));
3740 count = nfsm_rndup(mlen2) - mlen2;
3741 error = xb_add_bytes(&xbnew, buf, count, 1);
3742 }
3743 }
3744 xb_build_done(error, &xbnew);
3745
3746 /* update opaque counts */
3747 end_offset = xb_offset(&xbnew);
3748 if (!error) {
3749 error = xb_seek(&xbnew, argslength_offset);
3750 argslength = end_offset - argslength_offset + XDRWORD/*version*/;
3751 xb_add_32(error, &xbnew, argslength);
3752 }
3753 if (!error) {
3754 error = xb_seek(&xbnew, attrslength_offset);
3755 xb_add_32(error, &xbnew, end_offset - attrslength_offset - XDRWORD/*don't include length field*/);
3756 }
3757 nfsmerr_if(error);
3758
3759 /*
3760 * For kernel_mount() call, use the existing mount flags (instead of the
3761 * original flags) because flags like MNT_NOSUID and MNT_NODEV may have
3762 * been silently enforced.
3763 */
3764 mntflags = vnode_vfsvisflags(vp);
3765 mntflags |= (MNT_AUTOMOUNTED | MNT_DONTBROWSE);
3766
3767 /* do the mount */
3768 error = kernel_mount(fstype, dvp, vp, path, xb_buffer_base(&xbnew), argslength,
3769 mntflags, KERNEL_MOUNT_PERMIT_UNMOUNT | KERNEL_MOUNT_NOAUTH, ctx);
3770
3771 nfsmerr:
3772 if (error)
3773 printf("nfs: mirror mount of %s on %s failed (%d)\n",
3774 mntfromname, path, error);
3775 /* clean up */
3776 xb_cleanup(&xbnew);
3777 if (referral)
3778 nfs_fs_locations_cleanup(&nfsls);
3779 if (path)
3780 FREE_ZONE(path, MAXPATHLEN, M_NAMEI);
3781 if (mntfromname)
3782 FREE_ZONE(mntfromname, MAXPATHLEN, M_NAMEI);
3783 if (!error)
3784 nfs_ephemeral_mount_harvester_start();
3785 return (error);
3786 }
3787
3788 /*
3789 * trigger vnode functions
3790 */
3791
3792 resolver_result_t
3793 nfs_mirror_mount_trigger_resolve(
3794 vnode_t vp,
3795 const struct componentname *cnp,
3796 enum path_operation pop,
3797 __unused int flags,
3798 __unused void *data,
3799 vfs_context_t ctx)
3800 {
3801 nfsnode_t np = VTONFS(vp);
3802 vnode_t pvp = NULLVP;
3803 int error = 0;
3804 resolver_result_t result;
3805
3806 /*
3807 * We have a trigger node that doesn't have anything mounted on it yet.
3808 * We'll do the mount if either:
3809 * (a) this isn't the last component of the path OR
3810 * (b) this is an op that looks like it should trigger the mount.
3811 */
3812 if (cnp->cn_flags & ISLASTCN) {
3813 switch (pop) {
3814 case OP_MOUNT:
3815 case OP_UNMOUNT:
3816 case OP_STATFS:
3817 case OP_LINK:
3818 case OP_UNLINK:
3819 case OP_RENAME:
3820 case OP_MKNOD:
3821 case OP_MKFIFO:
3822 case OP_SYMLINK:
3823 case OP_ACCESS:
3824 case OP_GETATTR:
3825 case OP_MKDIR:
3826 case OP_RMDIR:
3827 case OP_REVOKE:
3828 case OP_GETXATTR:
3829 case OP_LISTXATTR:
3830 /* don't perform the mount for these operations */
3831 result = vfs_resolver_result(np->n_trigseq, RESOLVER_NOCHANGE, 0);
3832 #ifdef NFS_TRIGGER_DEBUG
3833 NP(np, "nfs trigger RESOLVE: no change, last %d nameiop %d, seq %d",
3834 (cnp->cn_flags & ISLASTCN) ? 1 : 0, cnp->cn_nameiop, np->n_trigseq);
3835 #endif
3836 return (result);
3837 case OP_OPEN:
3838 case OP_CHDIR:
3839 case OP_CHROOT:
3840 case OP_TRUNCATE:
3841 case OP_COPYFILE:
3842 case OP_PATHCONF:
3843 case OP_READLINK:
3844 case OP_SETATTR:
3845 case OP_EXCHANGEDATA:
3846 case OP_SEARCHFS:
3847 case OP_FSCTL:
3848 case OP_SETXATTR:
3849 case OP_REMOVEXATTR:
3850 default:
3851 /* go ahead and do the mount */
3852 break;
3853 }
3854 }
3855
3856 if (vnode_mountedhere(vp) != NULL) {
3857 /*
3858 * Um... there's already something mounted.
3859 * Been there. Done that. Let's just say it succeeded.
3860 */
3861 error = 0;
3862 goto skipmount;
3863 }
3864
3865 if ((error = nfs_node_set_busy(np, vfs_context_thread(ctx)))) {
3866 result = vfs_resolver_result(np->n_trigseq, RESOLVER_ERROR, error);
3867 #ifdef NFS_TRIGGER_DEBUG
3868 NP(np, "nfs trigger RESOLVE: busy error %d, last %d nameiop %d, seq %d",
3869 error, (cnp->cn_flags & ISLASTCN) ? 1 : 0, cnp->cn_nameiop, np->n_trigseq);
3870 #endif
3871 return (result);
3872 }
3873
3874 pvp = vnode_getparent(vp);
3875 if (pvp == NULLVP)
3876 error = EINVAL;
3877 if (!error)
3878 error = nfs_mirror_mount_domount(pvp, vp, ctx);
3879 skipmount:
3880 if (!error)
3881 np->n_trigseq++;
3882 result = vfs_resolver_result(np->n_trigseq, error ? RESOLVER_ERROR : RESOLVER_RESOLVED, error);
3883 #ifdef NFS_TRIGGER_DEBUG
3884 NP(np, "nfs trigger RESOLVE: %s %d, last %d nameiop %d, seq %d",
3885 error ? "error" : "resolved", error,
3886 (cnp->cn_flags & ISLASTCN) ? 1 : 0, cnp->cn_nameiop, np->n_trigseq);
3887 #endif
3888
3889 if (pvp != NULLVP)
3890 vnode_put(pvp);
3891 nfs_node_clear_busy(np);
3892 return (result);
3893 }
3894
3895 resolver_result_t
3896 nfs_mirror_mount_trigger_unresolve(
3897 vnode_t vp,
3898 int flags,
3899 __unused void *data,
3900 vfs_context_t ctx)
3901 {
3902 nfsnode_t np = VTONFS(vp);
3903 mount_t mp;
3904 int error;
3905 resolver_result_t result;
3906
3907 if ((error = nfs_node_set_busy(np, vfs_context_thread(ctx)))) {
3908 result = vfs_resolver_result(np->n_trigseq, RESOLVER_ERROR, error);
3909 #ifdef NFS_TRIGGER_DEBUG
3910 NP(np, "nfs trigger UNRESOLVE: busy error %d, seq %d", error, np->n_trigseq);
3911 #endif
3912 return (result);
3913 }
3914
3915 mp = vnode_mountedhere(vp);
3916 if (!mp)
3917 error = EINVAL;
3918 if (!error)
3919 error = vfs_unmountbyfsid(&(vfs_statfs(mp)->f_fsid), flags, ctx);
3920 if (!error)
3921 np->n_trigseq++;
3922 result = vfs_resolver_result(np->n_trigseq, error ? RESOLVER_ERROR : RESOLVER_UNRESOLVED, error);
3923 #ifdef NFS_TRIGGER_DEBUG
3924 NP(np, "nfs trigger UNRESOLVE: %s %d, seq %d",
3925 error ? "error" : "unresolved", error, np->n_trigseq);
3926 #endif
3927 nfs_node_clear_busy(np);
3928 return (result);
3929 }
3930
3931 resolver_result_t
3932 nfs_mirror_mount_trigger_rearm(
3933 vnode_t vp,
3934 __unused int flags,
3935 __unused void *data,
3936 vfs_context_t ctx)
3937 {
3938 nfsnode_t np = VTONFS(vp);
3939 int error;
3940 resolver_result_t result;
3941
3942 if ((error = nfs_node_set_busy(np, vfs_context_thread(ctx)))) {
3943 result = vfs_resolver_result(np->n_trigseq, RESOLVER_ERROR, error);
3944 #ifdef NFS_TRIGGER_DEBUG
3945 NP(np, "nfs trigger REARM: busy error %d, seq %d", error, np->n_trigseq);
3946 #endif
3947 return (result);
3948 }
3949
3950 np->n_trigseq++;
3951 result = vfs_resolver_result(np->n_trigseq,
3952 vnode_mountedhere(vp) ? RESOLVER_RESOLVED : RESOLVER_UNRESOLVED, 0);
3953 #ifdef NFS_TRIGGER_DEBUG
3954 NP(np, "nfs trigger REARM: %s, seq %d",
3955 vnode_mountedhere(vp) ? "resolved" : "unresolved", np->n_trigseq);
3956 #endif
3957 nfs_node_clear_busy(np);
3958 return (result);
3959 }
3960
3961 /*
3962 * Periodically attempt to unmount ephemeral (mirror) mounts in an attempt to limit
3963 * the number of unused mounts.
3964 */
3965
3966 #define NFS_EPHEMERAL_MOUNT_HARVEST_INTERVAL 120 /* how often the harvester runs */
3967 struct nfs_ephemeral_mount_harvester_info {
3968 fsid_t fsid; /* FSID that we need to try to unmount */
3969 uint32_t mountcount; /* count of ephemeral mounts seen in scan */
3970 };
3971 /* various globals for the harvester */
3972 static thread_call_t nfs_ephemeral_mount_harvester_timer = NULL;
3973 static int nfs_ephemeral_mount_harvester_on = 0;
3974
3975 kern_return_t thread_terminate(thread_t);
3976
3977 static int
3978 nfs_ephemeral_mount_harvester_callback(mount_t mp, void *arg)
3979 {
3980 struct nfs_ephemeral_mount_harvester_info *hinfo = arg;
3981 struct nfsmount *nmp;
3982 struct timeval now;
3983
3984 if (strcmp(mp->mnt_vfsstat.f_fstypename, "nfs"))
3985 return (VFS_RETURNED);
3986 nmp = VFSTONFS(mp);
3987 if (!nmp || !NMFLAG(nmp, EPHEMERAL))
3988 return (VFS_RETURNED);
3989 hinfo->mountcount++;
3990
3991 /* avoid unmounting mounts that have been triggered within the last harvest interval */
3992 microtime(&now);
3993 if ((nmp->nm_mounttime >> 32) > ((uint32_t)now.tv_sec - NFS_EPHEMERAL_MOUNT_HARVEST_INTERVAL))
3994 return (VFS_RETURNED);
3995
3996 if (hinfo->fsid.val[0] || hinfo->fsid.val[1]) {
3997 /* attempt to unmount previously-found ephemeral mount */
3998 vfs_unmountbyfsid(&hinfo->fsid, 0, vfs_context_kernel());
3999 hinfo->fsid.val[0] = hinfo->fsid.val[1] = 0;
4000 }
4001
4002 /*
4003 * We can't call unmount here since we hold a mount iter ref
4004 * on mp so save its fsid for the next call iteration to unmount.
4005 */
4006 hinfo->fsid.val[0] = mp->mnt_vfsstat.f_fsid.val[0];
4007 hinfo->fsid.val[1] = mp->mnt_vfsstat.f_fsid.val[1];
4008
4009 return (VFS_RETURNED);
4010 }
4011
4012 /*
4013 * Spawn a thread to do the ephemeral mount harvesting.
4014 */
4015 static void
4016 nfs_ephemeral_mount_harvester_timer_func(void)
4017 {
4018 thread_t thd;
4019
4020 if (kernel_thread_start(nfs_ephemeral_mount_harvester, NULL, &thd) == KERN_SUCCESS)
4021 thread_deallocate(thd);
4022 }
4023
4024 /*
4025 * Iterate all mounts looking for NFS ephemeral mounts to try to unmount.
4026 */
4027 void
4028 nfs_ephemeral_mount_harvester(__unused void *arg, __unused wait_result_t wr)
4029 {
4030 struct nfs_ephemeral_mount_harvester_info hinfo;
4031 uint64_t deadline;
4032
4033 hinfo.mountcount = 0;
4034 hinfo.fsid.val[0] = hinfo.fsid.val[1] = 0;
4035 vfs_iterate(VFS_ITERATE_TAIL_FIRST, nfs_ephemeral_mount_harvester_callback, &hinfo);
4036 if (hinfo.fsid.val[0] || hinfo.fsid.val[1]) {
4037 /* attempt to unmount last found ephemeral mount */
4038 vfs_unmountbyfsid(&hinfo.fsid, 0, vfs_context_kernel());
4039 }
4040
4041 lck_mtx_lock(nfs_global_mutex);
4042 if (!hinfo.mountcount) {
4043 /* no more ephemeral mounts - don't need timer */
4044 nfs_ephemeral_mount_harvester_on = 0;
4045 } else {
4046 /* re-arm the timer */
4047 clock_interval_to_deadline(NFS_EPHEMERAL_MOUNT_HARVEST_INTERVAL, NSEC_PER_SEC, &deadline);
4048 thread_call_enter_delayed(nfs_ephemeral_mount_harvester_timer, deadline);
4049 nfs_ephemeral_mount_harvester_on = 1;
4050 }
4051 lck_mtx_unlock(nfs_global_mutex);
4052
4053 /* thread done */
4054 thread_terminate(current_thread());
4055 }
4056
4057 /*
4058 * Make sure the NFS ephemeral mount harvester timer is running.
4059 */
4060 void
4061 nfs_ephemeral_mount_harvester_start(void)
4062 {
4063 uint64_t deadline;
4064
4065 lck_mtx_lock(nfs_global_mutex);
4066 if (nfs_ephemeral_mount_harvester_on) {
4067 lck_mtx_unlock(nfs_global_mutex);
4068 return;
4069 }
4070 if (nfs_ephemeral_mount_harvester_timer == NULL)
4071 nfs_ephemeral_mount_harvester_timer = thread_call_allocate((thread_call_func_t)nfs_ephemeral_mount_harvester_timer_func, NULL);
4072 clock_interval_to_deadline(NFS_EPHEMERAL_MOUNT_HARVEST_INTERVAL, NSEC_PER_SEC, &deadline);
4073 thread_call_enter_delayed(nfs_ephemeral_mount_harvester_timer, deadline);
4074 nfs_ephemeral_mount_harvester_on = 1;
4075 lck_mtx_unlock(nfs_global_mutex);
4076 }
4077
4078 #endif
4079
4080 /*
4081 * Send a MOUNT protocol MOUNT request to the server to get the initial file handle (and security).
4082 */
4083 int
4084 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)
4085 {
4086 int error = 0, slen, mntproto;
4087 thread_t thd = vfs_context_thread(ctx);
4088 kauth_cred_t cred = vfs_context_ucred(ctx);
4089 uint64_t xid = 0;
4090 struct nfsm_chain nmreq, nmrep;
4091 mbuf_t mreq;
4092 uint32_t mntvers, mntport, val;
4093 struct sockaddr_storage ss;
4094 struct sockaddr *saddr = (struct sockaddr*)&ss;
4095
4096 nfsm_chain_null(&nmreq);
4097 nfsm_chain_null(&nmrep);
4098
4099 mntvers = (nfsvers == NFS_VER2) ? RPCMNT_VER1 : RPCMNT_VER3;
4100 mntproto = (NM_OMFLAG(nmp, MNTUDP) || (sotype == SOCK_DGRAM)) ? IPPROTO_UDP : IPPROTO_TCP;
4101 sec->count = 0;
4102
4103 bcopy(sa, saddr, min(sizeof(ss), sa->sa_len));
4104 if (saddr->sa_family == AF_INET) {
4105 if (nmp->nm_mountport)
4106 ((struct sockaddr_in*)saddr)->sin_port = htons(nmp->nm_mountport);
4107 mntport = ntohs(((struct sockaddr_in*)saddr)->sin_port);
4108 } else {
4109 if (nmp->nm_mountport)
4110 ((struct sockaddr_in6*)saddr)->sin6_port = htons(nmp->nm_mountport);
4111 mntport = ntohs(((struct sockaddr_in6*)saddr)->sin6_port);
4112 }
4113
4114 while (!mntport) {
4115 error = nfs_portmap_lookup(nmp, ctx, saddr, NULL, RPCPROG_MNT, mntvers, mntproto, timeo);
4116 nfsmout_if(error);
4117 if (saddr->sa_family == AF_INET)
4118 mntport = ntohs(((struct sockaddr_in*)saddr)->sin_port);
4119 else
4120 mntport = ntohs(((struct sockaddr_in6*)saddr)->sin6_port);
4121 if (!mntport) {
4122 /* if not found and TCP, then retry with UDP */
4123 if (mntproto == IPPROTO_UDP) {
4124 error = EPROGUNAVAIL;
4125 break;
4126 }
4127 mntproto = IPPROTO_UDP;
4128 bcopy(sa, saddr, min(sizeof(ss), sa->sa_len));
4129 }
4130 }
4131 nfsmout_if(error || !mntport);
4132
4133 /* MOUNT protocol MOUNT request */
4134 slen = strlen(path);
4135 nfsm_chain_build_alloc_init(error, &nmreq, NFSX_UNSIGNED + nfsm_rndup(slen));
4136 nfsm_chain_add_name(error, &nmreq, path, slen, nmp);
4137 nfsm_chain_build_done(error, &nmreq);
4138 nfsmout_if(error);
4139 error = nfsm_rpchead2(nmp, (mntproto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM,
4140 RPCPROG_MNT, mntvers, RPCMNT_MOUNT,
4141 RPCAUTH_SYS, cred, NULL, nmreq.nmc_mhead, &xid, &mreq);
4142 nfsmout_if(error);
4143 nmreq.nmc_mhead = NULL;
4144 error = nfs_aux_request(nmp, thd, saddr, NULL,
4145 ((mntproto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM),
4146 mreq, R_XID32(xid), 1, timeo, &nmrep);
4147 nfsmout_if(error);
4148 nfsm_chain_get_32(error, &nmrep, val);
4149 if (!error && val)
4150 error = val;
4151 nfsm_chain_get_fh(error, &nmrep, nfsvers, fh);
4152 if (!error && (nfsvers > NFS_VER2)) {
4153 sec->count = NX_MAX_SEC_FLAVORS;
4154 error = nfsm_chain_get_secinfo(&nmrep, &sec->flavors[0], &sec->count);
4155 }
4156 nfsmout:
4157 nfsm_chain_cleanup(&nmreq);
4158 nfsm_chain_cleanup(&nmrep);
4159 return (error);
4160 }
4161
4162
4163 /*
4164 * Send a MOUNT protocol UNMOUNT request to tell the server we've unmounted it.
4165 */
4166 void
4167 nfs3_umount_rpc(struct nfsmount *nmp, vfs_context_t ctx, int timeo)
4168 {
4169 int error = 0, slen, mntproto;
4170 thread_t thd = vfs_context_thread(ctx);
4171 kauth_cred_t cred = vfs_context_ucred(ctx);
4172 char *path;
4173 uint64_t xid = 0;
4174 struct nfsm_chain nmreq, nmrep;
4175 mbuf_t mreq;
4176 uint32_t mntvers, mntport;
4177 struct sockaddr_storage ss;
4178 struct sockaddr *saddr = (struct sockaddr*)&ss;
4179
4180 if (!nmp->nm_saddr)
4181 return;
4182
4183 nfsm_chain_null(&nmreq);
4184 nfsm_chain_null(&nmrep);
4185
4186 mntvers = (nmp->nm_vers == NFS_VER2) ? RPCMNT_VER1 : RPCMNT_VER3;
4187 mntproto = (NM_OMFLAG(nmp, MNTUDP) || (nmp->nm_sotype == SOCK_DGRAM)) ? IPPROTO_UDP : IPPROTO_TCP;
4188 mntport = nmp->nm_mountport;
4189
4190 bcopy(nmp->nm_saddr, saddr, min(sizeof(ss), nmp->nm_saddr->sa_len));
4191 if (saddr->sa_family == AF_INET)
4192 ((struct sockaddr_in*)saddr)->sin_port = htons(mntport);
4193 else
4194 ((struct sockaddr_in6*)saddr)->sin6_port = htons(mntport);
4195
4196 while (!mntport) {
4197 error = nfs_portmap_lookup(nmp, ctx, saddr, NULL, RPCPROG_MNT, mntvers, mntproto, timeo);
4198 nfsmout_if(error);
4199 if (saddr->sa_family == AF_INET)
4200 mntport = ntohs(((struct sockaddr_in*)saddr)->sin_port);
4201 else
4202 mntport = ntohs(((struct sockaddr_in6*)saddr)->sin6_port);
4203 /* if not found and mntvers > VER1, then retry with VER1 */
4204 if (!mntport) {
4205 if (mntvers > RPCMNT_VER1) {
4206 mntvers = RPCMNT_VER1;
4207 } else if (mntproto == IPPROTO_TCP) {
4208 mntproto = IPPROTO_UDP;
4209 mntvers = (nmp->nm_vers == NFS_VER2) ? RPCMNT_VER1 : RPCMNT_VER3;
4210 } else {
4211 break;
4212 }
4213 bcopy(nmp->nm_saddr, saddr, min(sizeof(ss), nmp->nm_saddr->sa_len));
4214 }
4215 }
4216 nfsmout_if(!mntport);
4217
4218 /* MOUNT protocol UNMOUNT request */
4219 path = &vfs_statfs(nmp->nm_mountp)->f_mntfromname[0];
4220 while (*path && (*path != '/'))
4221 path++;
4222 slen = strlen(path);
4223 nfsm_chain_build_alloc_init(error, &nmreq, NFSX_UNSIGNED + nfsm_rndup(slen));
4224 nfsm_chain_add_name(error, &nmreq, path, slen, nmp);
4225 nfsm_chain_build_done(error, &nmreq);
4226 nfsmout_if(error);
4227 error = nfsm_rpchead2(nmp, (mntproto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM,
4228 RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMOUNT,
4229 RPCAUTH_SYS, cred, NULL, nmreq.nmc_mhead, &xid, &mreq);
4230 nfsmout_if(error);
4231 nmreq.nmc_mhead = NULL;
4232 error = nfs_aux_request(nmp, thd, saddr, NULL,
4233 ((mntproto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM),
4234 mreq, R_XID32(xid), 1, timeo, &nmrep);
4235 nfsmout:
4236 nfsm_chain_cleanup(&nmreq);
4237 nfsm_chain_cleanup(&nmrep);
4238 }
4239
4240 /*
4241 * unmount system call
4242 */
4243 int
4244 nfs_vfs_unmount(
4245 mount_t mp,
4246 int mntflags,
4247 __unused vfs_context_t ctx)
4248 {
4249 struct nfsmount *nmp;
4250 vnode_t vp;
4251 int error, flags = 0;
4252 struct timespec ts = { 1, 0 };
4253
4254 nmp = VFSTONFS(mp);
4255 lck_mtx_lock(&nmp->nm_lock);
4256 /*
4257 * Set the flag indicating that an unmount attempt is in progress.
4258 */
4259 nmp->nm_state |= NFSSTA_UNMOUNTING;
4260 /*
4261 * During a force unmount we want to...
4262 * Mark that we are doing a force unmount.
4263 * Make the mountpoint soft.
4264 */
4265 if (mntflags & MNT_FORCE) {
4266 flags |= FORCECLOSE;
4267 nmp->nm_state |= NFSSTA_FORCE;
4268 NFS_BITMAP_SET(nmp->nm_flags, NFS_MFLAG_SOFT);
4269 }
4270 /*
4271 * Wait for any in-progress monitored node scan to complete.
4272 */
4273 while (nmp->nm_state & NFSSTA_MONITOR_SCAN)
4274 msleep(&nmp->nm_state, &nmp->nm_lock, PZERO-1, "nfswaitmonscan", &ts);
4275 /*
4276 * Goes something like this..
4277 * - Call vflush() to clear out vnodes for this file system,
4278 * except for the swap files. Deal with them in 2nd pass.
4279 * - Decrement reference on the vnode representing remote root.
4280 * - Clean up the NFS mount structure.
4281 */
4282 vp = NFSTOV(nmp->nm_dnp);
4283 lck_mtx_unlock(&nmp->nm_lock);
4284
4285 /*
4286 * vflush will check for busy vnodes on mountpoint.
4287 * Will do the right thing for MNT_FORCE. That is, we should
4288 * not get EBUSY back.
4289 */
4290 error = vflush(mp, vp, SKIPSWAP | flags);
4291 if (mntflags & MNT_FORCE) {
4292 error = vflush(mp, NULLVP, flags); /* locks vp in the process */
4293 } else {
4294 if (vnode_isinuse(vp, 1))
4295 error = EBUSY;
4296 else
4297 error = vflush(mp, vp, flags);
4298 }
4299 if (error) {
4300 lck_mtx_lock(&nmp->nm_lock);
4301 nmp->nm_state &= ~NFSSTA_UNMOUNTING;
4302 lck_mtx_unlock(&nmp->nm_lock);
4303 return (error);
4304 }
4305
4306 lck_mtx_lock(&nmp->nm_lock);
4307 nmp->nm_dnp = NULL;
4308 lck_mtx_unlock(&nmp->nm_lock);
4309
4310 /*
4311 * Release the root vnode reference held by mountnfs()
4312 */
4313 error = vnode_get(vp);
4314 vnode_rele(vp);
4315 if (!error)
4316 vnode_put(vp);
4317
4318 vflush(mp, NULLVP, FORCECLOSE);
4319
4320 /* Wait for all other references to be released and free the mount */
4321 nfs_mount_drain_and_cleanup(nmp);
4322
4323 return (0);
4324 }
4325
4326 /*
4327 * cleanup/destroy NFS fs locations structure
4328 */
4329 void
4330 nfs_fs_locations_cleanup(struct nfs_fs_locations *nfslsp)
4331 {
4332 struct nfs_fs_location *fsl;
4333 struct nfs_fs_server *fss;
4334 struct nfs_fs_path *fsp;
4335 uint32_t loc, serv, addr, comp;
4336
4337 /* free up fs locations */
4338 if (!nfslsp->nl_numlocs || !nfslsp->nl_locations)
4339 return;
4340
4341 for (loc = 0; loc < nfslsp->nl_numlocs; loc++) {
4342 fsl = nfslsp->nl_locations[loc];
4343 if (!fsl)
4344 continue;
4345 if ((fsl->nl_servcount > 0) && fsl->nl_servers) {
4346 for (serv = 0; serv < fsl->nl_servcount; serv++) {
4347 fss = fsl->nl_servers[serv];
4348 if (!fss)
4349 continue;
4350 if ((fss->ns_addrcount > 0) && fss->ns_addresses) {
4351 for (addr = 0; addr < fss->ns_addrcount; addr++)
4352 FREE(fss->ns_addresses[addr], M_TEMP);
4353 FREE(fss->ns_addresses, M_TEMP);
4354 }
4355 FREE(fss->ns_name, M_TEMP);
4356 FREE(fss, M_TEMP);
4357 }
4358 FREE(fsl->nl_servers, M_TEMP);
4359 }
4360 fsp = &fsl->nl_path;
4361 if (fsp->np_compcount && fsp->np_components) {
4362 for (comp = 0; comp < fsp->np_compcount; comp++)
4363 if (fsp->np_components[comp])
4364 FREE(fsp->np_components[comp], M_TEMP);
4365 FREE(fsp->np_components, M_TEMP);
4366 }
4367 FREE(fsl, M_TEMP);
4368 }
4369 FREE(nfslsp->nl_locations, M_TEMP);
4370 nfslsp->nl_numlocs = 0;
4371 nfslsp->nl_locations = NULL;
4372 }
4373
4374 void
4375 nfs_mount_rele(struct nfsmount *nmp)
4376 {
4377 int wup = 0;
4378
4379 lck_mtx_lock(&nmp->nm_lock);
4380 if (nmp->nm_ref < 1)
4381 panic("nfs zombie mount underflow\n");
4382 nmp->nm_ref--;
4383 if (nmp->nm_ref == 0)
4384 wup = nmp->nm_state & NFSSTA_MOUNT_DRAIN;
4385 lck_mtx_unlock(&nmp->nm_lock);
4386 if (wup)
4387 wakeup(&nmp->nm_ref);
4388 }
4389
4390 void
4391 nfs_mount_drain_and_cleanup(struct nfsmount *nmp)
4392 {
4393 lck_mtx_lock(&nmp->nm_lock);
4394 nmp->nm_state |= NFSSTA_MOUNT_DRAIN;
4395 while (nmp->nm_ref > 0) {
4396 msleep(&nmp->nm_ref, &nmp->nm_lock, PZERO-1, "nfs_mount_drain", NULL);
4397 }
4398 assert(nmp->nm_ref == 0);
4399 lck_mtx_unlock(&nmp->nm_lock);
4400 nfs_mount_cleanup(nmp);
4401 }
4402
4403 /*
4404 * nfs_mount_zombie
4405 */
4406 void
4407 nfs_mount_zombie(struct nfsmount *nmp, int nm_state_flags)
4408 {
4409 struct nfsreq *req, *treq;
4410 struct nfs_reqqhead iodq, resendq;
4411 struct timespec ts = { 1, 0 };
4412 struct nfs_open_owner *noop, *nextnoop;
4413 nfsnode_t np;
4414 int docallback;
4415
4416 lck_mtx_lock(&nmp->nm_lock);
4417 nmp->nm_state |= nm_state_flags;
4418 nmp->nm_ref++;
4419 lck_mtx_unlock(&nmp->nm_lock);
4420
4421 /* stop callbacks */
4422 if ((nmp->nm_vers >= NFS_VER4) && !NMFLAG(nmp, NOCALLBACK) && nmp->nm_cbid)
4423 nfs4_mount_callback_shutdown(nmp);
4424
4425 /* Destroy any RPCSEC_GSS contexts */
4426 nfs_gss_clnt_ctx_unmount(nmp);
4427
4428 /* mark the socket for termination */
4429 lck_mtx_lock(&nmp->nm_lock);
4430 nmp->nm_sockflags |= NMSOCK_UNMOUNT;
4431
4432 /* Have the socket thread send the unmount RPC, if requested/appropriate. */
4433 if ((nmp->nm_vers < NFS_VER4) && (nmp->nm_state & NFSSTA_MOUNTED) &&
4434 !(nmp->nm_state & (NFSSTA_FORCE|NFSSTA_DEAD)) && NMFLAG(nmp, CALLUMNT))
4435 nfs_mount_sock_thread_wake(nmp);
4436
4437 /* wait for the socket thread to terminate */
4438 while (nmp->nm_sockthd && current_thread() != nmp->nm_sockthd) {
4439 wakeup(&nmp->nm_sockthd);
4440 msleep(&nmp->nm_sockthd, &nmp->nm_lock, PZERO-1, "nfswaitsockthd", &ts);
4441 }
4442 lck_mtx_unlock(&nmp->nm_lock);
4443
4444 /* tear down the socket */
4445 nfs_disconnect(nmp);
4446
4447 lck_mtx_lock(&nmp->nm_lock);
4448
4449 if ((nmp->nm_vers >= NFS_VER4) && !NMFLAG(nmp, NOCALLBACK) && nmp->nm_cbid) {
4450 /* clear out any pending delegation return requests */
4451 while ((np = TAILQ_FIRST(&nmp->nm_dreturnq))) {
4452 TAILQ_REMOVE(&nmp->nm_dreturnq, np, n_dreturn);
4453 np->n_dreturn.tqe_next = NFSNOLIST;
4454 }
4455 }
4456
4457 /* cancel any renew timer */
4458 if ((nmp->nm_vers >= NFS_VER4) && nmp->nm_renew_timer) {
4459 thread_call_cancel(nmp->nm_renew_timer);
4460 thread_call_free(nmp->nm_renew_timer);
4461 nmp->nm_renew_timer = NULL;
4462 }
4463
4464 lck_mtx_unlock(&nmp->nm_lock);
4465
4466 if (nmp->nm_state & NFSSTA_MOUNTED)
4467 switch (nmp->nm_lockmode) {
4468 case NFS_LOCK_MODE_DISABLED:
4469 case NFS_LOCK_MODE_LOCAL:
4470 break;
4471 case NFS_LOCK_MODE_ENABLED:
4472 default:
4473 if (nmp->nm_vers <= NFS_VER3) {
4474 nfs_lockd_mount_unregister(nmp);
4475 nmp->nm_lockmode = NFS_LOCK_MODE_DISABLED;
4476 }
4477 break;
4478 }
4479
4480 if ((nmp->nm_vers >= NFS_VER4) && nmp->nm_longid) {
4481 /* remove/deallocate the client ID data */
4482 lck_mtx_lock(nfs_global_mutex);
4483 TAILQ_REMOVE(&nfsclientids, nmp->nm_longid, nci_link);
4484 if (nmp->nm_longid->nci_id)
4485 FREE(nmp->nm_longid->nci_id, M_TEMP);
4486 FREE(nmp->nm_longid, M_TEMP);
4487 nmp->nm_longid = NULL;
4488 lck_mtx_unlock(nfs_global_mutex);
4489 }
4490
4491 /*
4492 * Be sure all requests for this mount are completed
4493 * and removed from the resend queue.
4494 */
4495 TAILQ_INIT(&resendq);
4496 lck_mtx_lock(nfs_request_mutex);
4497 TAILQ_FOREACH(req, &nfs_reqq, r_chain) {
4498 if (req->r_nmp == nmp) {
4499 lck_mtx_lock(&req->r_mtx);
4500 if (!req->r_error && req->r_nmrep.nmc_mhead == NULL)
4501 req->r_error = EIO;
4502 if (req->r_flags & R_RESENDQ) {
4503 lck_mtx_lock(&nmp->nm_lock);
4504 req->r_flags &= ~R_RESENDQ;
4505 if (req->r_rchain.tqe_next != NFSREQNOLIST) {
4506 TAILQ_REMOVE(&nmp->nm_resendq, req, r_rchain);
4507 /*
4508 * Queue up the request so that we can unreference them
4509 * with out holding nfs_request_mutex
4510 */
4511 TAILQ_INSERT_TAIL(&resendq, req, r_rchain);
4512 }
4513 lck_mtx_unlock(&nmp->nm_lock);
4514 }
4515 wakeup(req);
4516 lck_mtx_unlock(&req->r_mtx);
4517 }
4518 }
4519 lck_mtx_unlock(nfs_request_mutex);
4520
4521 /* Since we've drop the request mutex we can now safely unreference the request */
4522 TAILQ_FOREACH_SAFE(req, &resendq, r_rchain, treq) {
4523 TAILQ_REMOVE(&resendq, req, r_rchain);
4524 nfs_request_rele(req);
4525 }
4526
4527 /*
4528 * Now handle and outstanding async requests. We need to walk the
4529 * request queue again this time with the nfsiod_mutex held. No
4530 * other iods can grab our requests until we've put them on our own
4531 * local iod queue for processing.
4532 */
4533 TAILQ_INIT(&iodq);
4534 lck_mtx_lock(nfs_request_mutex);
4535 lck_mtx_lock(nfsiod_mutex);
4536 TAILQ_FOREACH(req, &nfs_reqq, r_chain) {
4537 if (req->r_nmp == nmp) {
4538 lck_mtx_lock(&req->r_mtx);
4539 if (req->r_callback.rcb_func
4540 && !(req->r_flags & R_WAITSENT) && !(req->r_flags & R_IOD)) {
4541 /*
4542 * Since R_IOD is not set then we need to handle it. If
4543 * we're not on a list add it to our iod queue. Otherwise
4544 * we must already be on nm_iodq which is added to our
4545 * local queue below.
4546 * %%% We should really keep a back pointer to our iod queue
4547 * that we're on.
4548 */
4549 req->r_flags |= R_IOD;
4550 if (req->r_achain.tqe_next == NFSREQNOLIST) {
4551 TAILQ_INSERT_TAIL(&iodq, req, r_achain);
4552 }
4553 }
4554 lck_mtx_unlock(&req->r_mtx);
4555 }
4556 }
4557
4558 /* finish any async I/O RPCs queued up */
4559 if (nmp->nm_iodlink.tqe_next != NFSNOLIST)
4560 TAILQ_REMOVE(&nfsiodmounts, nmp, nm_iodlink);
4561 TAILQ_CONCAT(&iodq, &nmp->nm_iodq, r_achain);
4562 lck_mtx_unlock(nfsiod_mutex);
4563 lck_mtx_unlock(nfs_request_mutex);
4564
4565 TAILQ_FOREACH_SAFE(req, &iodq, r_achain, treq) {
4566 TAILQ_REMOVE(&iodq, req, r_achain);
4567 req->r_achain.tqe_next = NFSREQNOLIST;
4568 lck_mtx_lock(&req->r_mtx);
4569 docallback = !(req->r_flags & R_WAITSENT);
4570 lck_mtx_unlock(&req->r_mtx);
4571 if (docallback)
4572 req->r_callback.rcb_func(req);
4573 }
4574
4575 /* clean up common state */
4576 lck_mtx_lock(&nmp->nm_lock);
4577 while ((np = LIST_FIRST(&nmp->nm_monlist))) {
4578 LIST_REMOVE(np, n_monlink);
4579 np->n_monlink.le_next = NFSNOLIST;
4580 }
4581 TAILQ_FOREACH_SAFE(noop, &nmp->nm_open_owners, noo_link, nextnoop) {
4582 TAILQ_REMOVE(&nmp->nm_open_owners, noop, noo_link);
4583 noop->noo_flags &= ~NFS_OPEN_OWNER_LINK;
4584 if (noop->noo_refcnt)
4585 continue;
4586 nfs_open_owner_destroy(noop);
4587 }
4588 lck_mtx_unlock(&nmp->nm_lock);
4589
4590 /* clean up NFSv4 state */
4591 if (nmp->nm_vers >= NFS_VER4) {
4592 lck_mtx_lock(&nmp->nm_lock);
4593 while ((np = TAILQ_FIRST(&nmp->nm_delegations))) {
4594 TAILQ_REMOVE(&nmp->nm_delegations, np, n_dlink);
4595 np->n_dlink.tqe_next = NFSNOLIST;
4596 }
4597 lck_mtx_unlock(&nmp->nm_lock);
4598 }
4599
4600 nfs_mount_rele(nmp);
4601 }
4602
4603 /*
4604 * cleanup/destroy an nfsmount
4605 */
4606 void
4607 nfs_mount_cleanup(struct nfsmount *nmp)
4608 {
4609 if (!nmp)
4610 return;
4611
4612 nfs_mount_zombie(nmp, 0);
4613
4614 NFS_VFS_DBG("Unmounting %s from %s\n",
4615 vfs_statfs(nmp->nm_mountp)->f_mntfromname,
4616 vfs_statfs(nmp->nm_mountp)->f_mntonname);
4617 NFS_VFS_DBG("nfs state = 0x%8.8x\n", nmp->nm_state);
4618 NFS_VFS_DBG("nfs socket flags = 0x%8.8x\n", nmp->nm_sockflags);
4619 NFS_VFS_DBG("nfs mount ref count is %d\n", nmp->nm_ref);
4620 NFS_VFS_DBG("mount ref count is %d\n", nmp->nm_mountp->mnt_count);
4621
4622 if (nmp->nm_mountp)
4623 vfs_setfsprivate(nmp->nm_mountp, NULL);
4624
4625 lck_mtx_lock(&nmp->nm_lock);
4626 if (nmp->nm_ref)
4627 panic("Some one has grabbed a ref %d state flags = 0x%8.8x\n", nmp->nm_ref, nmp->nm_state);
4628
4629 if (nmp->nm_saddr)
4630 FREE(nmp->nm_saddr, M_SONAME);
4631 if ((nmp->nm_vers < NFS_VER4) && nmp->nm_rqsaddr)
4632 FREE(nmp->nm_rqsaddr, M_SONAME);
4633
4634 if (IS_VALID_CRED(nmp->nm_mcred))
4635 kauth_cred_unref(&nmp->nm_mcred);
4636
4637 nfs_fs_locations_cleanup(&nmp->nm_locations);
4638
4639 if (nmp->nm_realm)
4640 FREE(nmp->nm_realm, M_TEMP);
4641 if (nmp->nm_principal)
4642 FREE(nmp->nm_principal, M_TEMP);
4643 if (nmp->nm_sprinc)
4644 FREE(nmp->nm_sprinc, M_TEMP);
4645
4646 if (nmp->nm_args)
4647 xb_free(nmp->nm_args);
4648
4649 lck_mtx_unlock(&nmp->nm_lock);
4650
4651 lck_mtx_destroy(&nmp->nm_lock, nfs_mount_grp);
4652 if (nmp->nm_fh)
4653 FREE(nmp->nm_fh, M_TEMP);
4654 FREE_ZONE((caddr_t)nmp, sizeof (struct nfsmount), M_NFSMNT);
4655 }
4656
4657 /*
4658 * Return root of a filesystem
4659 */
4660 int
4661 nfs_vfs_root(mount_t mp, vnode_t *vpp, __unused vfs_context_t ctx)
4662 {
4663 vnode_t vp;
4664 struct nfsmount *nmp;
4665 int error;
4666 u_int32_t vpid;
4667
4668 nmp = VFSTONFS(mp);
4669 if (!nmp || !nmp->nm_dnp)
4670 return (ENXIO);
4671 vp = NFSTOV(nmp->nm_dnp);
4672 vpid = vnode_vid(vp);
4673 while ((error = vnode_getwithvid(vp, vpid))) {
4674 /* vnode_get() may return ENOENT if the dir changes. */
4675 /* If that happens, just try it again, else return the error. */
4676 if ((error != ENOENT) || (vnode_vid(vp) == vpid))
4677 return (error);
4678 vpid = vnode_vid(vp);
4679 }
4680 *vpp = vp;
4681 return (0);
4682 }
4683
4684 /*
4685 * Do operations associated with quotas
4686 */
4687 #if !QUOTA
4688 int
4689 nfs_vfs_quotactl(
4690 __unused mount_t mp,
4691 __unused int cmds,
4692 __unused uid_t uid,
4693 __unused caddr_t datap,
4694 __unused vfs_context_t context)
4695 {
4696 return (ENOTSUP);
4697 }
4698 #else
4699
4700 static int
4701 nfs_sa_getport(struct sockaddr *sa, int *error)
4702 {
4703 int port = 0;
4704
4705 if (sa->sa_family == AF_INET6)
4706 port = ntohs(((struct sockaddr_in6*)sa)->sin6_port);
4707 else if (sa->sa_family == AF_INET)
4708 port = ntohs(((struct sockaddr_in*)sa)->sin_port);
4709 else if (error)
4710 *error = EIO;
4711
4712 return port;
4713 }
4714
4715 static void
4716 nfs_sa_setport(struct sockaddr *sa, int port)
4717 {
4718 if (sa->sa_family == AF_INET6)
4719 ((struct sockaddr_in6*)sa)->sin6_port = htons(port);
4720 else if (sa->sa_family == AF_INET)
4721 ((struct sockaddr_in*)sa)->sin_port = htons(port);
4722 }
4723
4724 int
4725 nfs3_getquota(struct nfsmount *nmp, vfs_context_t ctx, uid_t id, int type, struct dqblk *dqb)
4726 {
4727 int error = 0, slen, timeo;
4728 int rqport = 0, rqproto, rqvers = (type == GRPQUOTA) ? RPCRQUOTA_EXT_VER : RPCRQUOTA_VER;
4729 thread_t thd = vfs_context_thread(ctx);
4730 kauth_cred_t cred = vfs_context_ucred(ctx);
4731 char *path;
4732 uint64_t xid = 0;
4733 struct nfsm_chain nmreq, nmrep;
4734 mbuf_t mreq;
4735 uint32_t val = 0, bsize = 0;
4736 struct sockaddr *rqsaddr;
4737 struct timeval now;
4738 struct timespec ts = { 1, 0 };
4739
4740 if (!nmp->nm_saddr)
4741 return (ENXIO);
4742
4743 if (NMFLAG(nmp, NOQUOTA))
4744 return (ENOTSUP);
4745
4746 /*
4747 * Allocate an address for rquotad if needed
4748 */
4749 if (!nmp->nm_rqsaddr) {
4750 int need_free = 0;
4751
4752 MALLOC(rqsaddr, struct sockaddr *, sizeof(struct sockaddr_storage), M_SONAME, M_WAITOK|M_ZERO);
4753 bcopy(nmp->nm_saddr, rqsaddr, min(sizeof(struct sockaddr_storage), nmp->nm_saddr->sa_len));
4754 /* Set the port to zero, will call rpcbind to get the port below */
4755 nfs_sa_setport(rqsaddr, 0);
4756 microuptime(&now);
4757
4758 lck_mtx_lock(&nmp->nm_lock);
4759 if (!nmp->nm_rqsaddr) {
4760 nmp->nm_rqsaddr = rqsaddr;
4761 nmp->nm_rqsaddrstamp = now.tv_sec;
4762 } else {
4763 need_free = 1;
4764 }
4765 lck_mtx_unlock(&nmp->nm_lock);
4766 if (need_free)
4767 FREE(rqsaddr, M_SONAME);
4768 }
4769
4770 timeo = NMFLAG(nmp, SOFT) ? 10 : 60;
4771 rqproto = IPPROTO_UDP; /* XXX should prefer TCP if mount is TCP */
4772
4773 /* check if we have a recently cached rquota port */
4774 microuptime(&now);
4775 lck_mtx_lock(&nmp->nm_lock);
4776 rqsaddr = nmp->nm_rqsaddr;
4777 rqport = nfs_sa_getport(rqsaddr, &error);
4778 while (!error && (!rqport || ((nmp->nm_rqsaddrstamp + 60) <= (uint32_t)now.tv_sec))) {
4779 error = nfs_sigintr(nmp, NULL, thd, 1);
4780 if (error) {
4781 lck_mtx_unlock(&nmp->nm_lock);
4782 return (error);
4783 }
4784 if (nmp->nm_state & NFSSTA_RQUOTAINPROG) {
4785 nmp->nm_state |= NFSSTA_WANTRQUOTA;
4786 msleep(&nmp->nm_rqsaddr, &nmp->nm_lock, PZERO-1, "nfswaitrquotaaddr", &ts);
4787 rqport = nfs_sa_getport(rqsaddr, &error);
4788 continue;
4789 }
4790 nmp->nm_state |= NFSSTA_RQUOTAINPROG;
4791 lck_mtx_unlock(&nmp->nm_lock);
4792
4793 /* send portmap request to get rquota port */
4794 error = nfs_portmap_lookup(nmp, ctx, rqsaddr, NULL, RPCPROG_RQUOTA, rqvers, rqproto, timeo);
4795 if (error)
4796 goto out;
4797 rqport = nfs_sa_getport(rqsaddr, &error);
4798 if (error)
4799 goto out;
4800
4801 if (!rqport) {
4802 /*
4803 * We overload PMAPPORT for the port if rquotad is not
4804 * currently registered or up at the server. In the
4805 * while loop above, port will be set and we will defer
4806 * for a bit. Perhaps the service isn't online yet.
4807 *
4808 * Note that precludes using indirect, but we're not doing
4809 * that here.
4810 */
4811 rqport = PMAPPORT;
4812 nfs_sa_setport(rqsaddr, rqport);
4813 }
4814 microuptime(&now);
4815 nmp->nm_rqsaddrstamp = now.tv_sec;
4816 out:
4817 lck_mtx_lock(&nmp->nm_lock);
4818 nmp->nm_state &= ~NFSSTA_RQUOTAINPROG;
4819 if (nmp->nm_state & NFSSTA_WANTRQUOTA) {
4820 nmp->nm_state &= ~NFSSTA_WANTRQUOTA;
4821 wakeup(&nmp->nm_rqsaddr);
4822 }
4823 }
4824 lck_mtx_unlock(&nmp->nm_lock);
4825 if (error)
4826 return (error);
4827
4828 /* Using PMAPPORT for unavailabe rquota service */
4829 if (rqport == PMAPPORT)
4830 return (ENOTSUP);
4831
4832 /* rquota request */
4833 nfsm_chain_null(&nmreq);
4834 nfsm_chain_null(&nmrep);
4835 path = &vfs_statfs(nmp->nm_mountp)->f_mntfromname[0];
4836 while (*path && (*path != '/'))
4837 path++;
4838 slen = strlen(path);
4839 nfsm_chain_build_alloc_init(error, &nmreq, 3 * NFSX_UNSIGNED + nfsm_rndup(slen));
4840 nfsm_chain_add_name(error, &nmreq, path, slen, nmp);
4841 if (type == GRPQUOTA)
4842 nfsm_chain_add_32(error, &nmreq, type);
4843 nfsm_chain_add_32(error, &nmreq, id);
4844 nfsm_chain_build_done(error, &nmreq);
4845 nfsmout_if(error);
4846 error = nfsm_rpchead2(nmp, (rqproto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM,
4847 RPCPROG_RQUOTA, rqvers, RPCRQUOTA_GET,
4848 RPCAUTH_SYS, cred, NULL, nmreq.nmc_mhead, &xid, &mreq);
4849 nfsmout_if(error);
4850 nmreq.nmc_mhead = NULL;
4851 error = nfs_aux_request(nmp, thd, rqsaddr, NULL,
4852 (rqproto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM,
4853 mreq, R_XID32(xid), 0, timeo, &nmrep);
4854 nfsmout_if(error);
4855
4856 /* parse rquota response */
4857 nfsm_chain_get_32(error, &nmrep, val);
4858 if (!error && (val != RQUOTA_STAT_OK)) {
4859 if (val == RQUOTA_STAT_NOQUOTA)
4860 error = ENOENT;
4861 else if (val == RQUOTA_STAT_EPERM)
4862 error = EPERM;
4863 else
4864 error = EIO;
4865 }
4866 nfsm_chain_get_32(error, &nmrep, bsize);
4867 nfsm_chain_adv(error, &nmrep, NFSX_UNSIGNED);
4868 nfsm_chain_get_32(error, &nmrep, val);
4869 nfsmout_if(error);
4870 dqb->dqb_bhardlimit = (uint64_t)val * bsize;
4871 nfsm_chain_get_32(error, &nmrep, val);
4872 nfsmout_if(error);
4873 dqb->dqb_bsoftlimit = (uint64_t)val * bsize;
4874 nfsm_chain_get_32(error, &nmrep, val);
4875 nfsmout_if(error);
4876 dqb->dqb_curbytes = (uint64_t)val * bsize;
4877 nfsm_chain_get_32(error, &nmrep, dqb->dqb_ihardlimit);
4878 nfsm_chain_get_32(error, &nmrep, dqb->dqb_isoftlimit);
4879 nfsm_chain_get_32(error, &nmrep, dqb->dqb_curinodes);
4880 nfsm_chain_get_32(error, &nmrep, dqb->dqb_btime);
4881 nfsm_chain_get_32(error, &nmrep, dqb->dqb_itime);
4882 nfsmout_if(error);
4883 dqb->dqb_id = id;
4884 nfsmout:
4885 nfsm_chain_cleanup(&nmreq);
4886 nfsm_chain_cleanup(&nmrep);
4887 return (error);
4888 }
4889
4890 int
4891 nfs4_getquota(struct nfsmount *nmp, vfs_context_t ctx, uid_t id, int type, struct dqblk *dqb)
4892 {
4893 nfsnode_t np;
4894 int error = 0, status, nfsvers, numops;
4895 u_int64_t xid;
4896 struct nfsm_chain nmreq, nmrep;
4897 uint32_t bitmap[NFS_ATTR_BITMAP_LEN];
4898 thread_t thd = vfs_context_thread(ctx);
4899 kauth_cred_t cred = vfs_context_ucred(ctx);
4900 struct nfsreq_secinfo_args si;
4901
4902 if (type != USRQUOTA) /* NFSv4 only supports user quotas */
4903 return (ENOTSUP);
4904
4905 /* first check that the server supports any of the quota attributes */
4906 if (!NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_supp_attr, NFS_FATTR_QUOTA_AVAIL_HARD) &&
4907 !NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_supp_attr, NFS_FATTR_QUOTA_AVAIL_SOFT) &&
4908 !NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_supp_attr, NFS_FATTR_QUOTA_USED))
4909 return (ENOTSUP);
4910
4911 /*
4912 * The credential passed to the server needs to have
4913 * an effective uid that matches the given uid.
4914 */
4915 if (id != kauth_cred_getuid(cred)) {
4916 struct posix_cred temp_pcred;
4917 posix_cred_t pcred = posix_cred_get(cred);
4918 bzero(&temp_pcred, sizeof(temp_pcred));
4919 temp_pcred.cr_uid = id;
4920 temp_pcred.cr_ngroups = pcred->cr_ngroups;
4921 bcopy(pcred->cr_groups, temp_pcred.cr_groups, sizeof(temp_pcred.cr_groups));
4922 cred = posix_cred_create(&temp_pcred);
4923 if (!IS_VALID_CRED(cred))
4924 return (ENOMEM);
4925 } else {
4926 kauth_cred_ref(cred);
4927 }
4928
4929 nfsvers = nmp->nm_vers;
4930 np = nmp->nm_dnp;
4931 if (!np)
4932 error = ENXIO;
4933 if (error || ((error = vnode_get(NFSTOV(np))))) {
4934 kauth_cred_unref(&cred);
4935 return(error);
4936 }
4937
4938 NFSREQ_SECINFO_SET(&si, np, NULL, 0, NULL, 0);
4939 nfsm_chain_null(&nmreq);
4940 nfsm_chain_null(&nmrep);
4941
4942 // PUTFH + GETATTR
4943 numops = 2;
4944 nfsm_chain_build_alloc_init(error, &nmreq, 15 * NFSX_UNSIGNED);
4945 nfsm_chain_add_compound_header(error, &nmreq, "quota", nmp->nm_minor_vers, numops);
4946 numops--;
4947 nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH);
4948 nfsm_chain_add_fh(error, &nmreq, nfsvers, np->n_fhp, np->n_fhsize);
4949 numops--;
4950 nfsm_chain_add_32(error, &nmreq, NFS_OP_GETATTR);
4951 NFS_CLEAR_ATTRIBUTES(bitmap);
4952 NFS_BITMAP_SET(bitmap, NFS_FATTR_QUOTA_AVAIL_HARD);
4953 NFS_BITMAP_SET(bitmap, NFS_FATTR_QUOTA_AVAIL_SOFT);
4954 NFS_BITMAP_SET(bitmap, NFS_FATTR_QUOTA_USED);
4955 nfsm_chain_add_bitmap_supported(error, &nmreq, bitmap, nmp, NULL);
4956 nfsm_chain_build_done(error, &nmreq);
4957 nfsm_assert(error, (numops == 0), EPROTO);
4958 nfsmout_if(error);
4959 error = nfs_request2(np, NULL, &nmreq, NFSPROC4_COMPOUND, thd, cred, &si, 0, &nmrep, &xid, &status);
4960 nfsm_chain_skip_tag(error, &nmrep);
4961 nfsm_chain_get_32(error, &nmrep, numops);
4962 nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
4963 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
4964 nfsm_assert(error, NFSTONMP(np), ENXIO);
4965 nfsmout_if(error);
4966 error = nfs4_parsefattr(&nmrep, NULL, NULL, NULL, dqb, NULL);
4967 nfsmout_if(error);
4968 nfsm_assert(error, NFSTONMP(np), ENXIO);
4969 nfsmout:
4970 nfsm_chain_cleanup(&nmreq);
4971 nfsm_chain_cleanup(&nmrep);
4972 vnode_put(NFSTOV(np));
4973 kauth_cred_unref(&cred);
4974 return (error);
4975 }
4976
4977 int
4978 nfs_vfs_quotactl(mount_t mp, int cmds, uid_t uid, caddr_t datap, vfs_context_t ctx)
4979 {
4980 struct nfsmount *nmp;
4981 int cmd, type, error, nfsvers;
4982 uid_t euid = kauth_cred_getuid(vfs_context_ucred(ctx));
4983 struct dqblk *dqb = (struct dqblk*)datap;
4984
4985 nmp = VFSTONFS(mp);
4986 if (nfs_mount_gone(nmp))
4987 return (ENXIO);
4988 nfsvers = nmp->nm_vers;
4989
4990 if (uid == ~0U)
4991 uid = euid;
4992
4993 /* we can only support Q_GETQUOTA */
4994 cmd = cmds >> SUBCMDSHIFT;
4995 switch (cmd) {
4996 case Q_GETQUOTA:
4997 break;
4998 case Q_QUOTAON:
4999 case Q_QUOTAOFF:
5000 case Q_SETQUOTA:
5001 case Q_SETUSE:
5002 case Q_SYNC:
5003 case Q_QUOTASTAT:
5004 return (ENOTSUP);
5005 default:
5006 return (EINVAL);
5007 }
5008
5009 type = cmds & SUBCMDMASK;
5010 if ((u_int)type >= MAXQUOTAS)
5011 return (EINVAL);
5012 if ((uid != euid) && ((error = vfs_context_suser(ctx))))
5013 return (error);
5014
5015 if (vfs_busy(mp, LK_NOWAIT))
5016 return (0);
5017 bzero(dqb, sizeof(*dqb));
5018 error = nmp->nm_funcs->nf_getquota(nmp, ctx, uid, type, dqb);
5019 vfs_unbusy(mp);
5020 return (error);
5021 }
5022 #endif
5023
5024 /*
5025 * Flush out the buffer cache
5026 */
5027 int nfs_sync_callout(vnode_t, void *);
5028
5029 struct nfs_sync_cargs {
5030 vfs_context_t ctx;
5031 int waitfor;
5032 int error;
5033 };
5034
5035 int
5036 nfs_sync_callout(vnode_t vp, void *arg)
5037 {
5038 struct nfs_sync_cargs *cargs = (struct nfs_sync_cargs*)arg;
5039 nfsnode_t np = VTONFS(vp);
5040 int error;
5041
5042 if (np->n_flag & NREVOKE) {
5043 vn_revoke(vp, REVOKEALL, cargs->ctx);
5044 return (VNODE_RETURNED);
5045 }
5046
5047 if (LIST_EMPTY(&np->n_dirtyblkhd))
5048 return (VNODE_RETURNED);
5049 if (np->n_wrbusy > 0)
5050 return (VNODE_RETURNED);
5051 if (np->n_bflag & (NBFLUSHINPROG|NBINVALINPROG))
5052 return (VNODE_RETURNED);
5053
5054 error = nfs_flush(np, cargs->waitfor, vfs_context_thread(cargs->ctx), 0);
5055 if (error)
5056 cargs->error = error;
5057
5058 return (VNODE_RETURNED);
5059 }
5060
5061 int
5062 nfs_vfs_sync(mount_t mp, int waitfor, vfs_context_t ctx)
5063 {
5064 struct nfs_sync_cargs cargs;
5065
5066 cargs.waitfor = waitfor;
5067 cargs.ctx = ctx;
5068 cargs.error = 0;
5069
5070 vnode_iterate(mp, 0, nfs_sync_callout, &cargs);
5071
5072 return (cargs.error);
5073 }
5074
5075 /*
5076 * NFS flat namespace lookup.
5077 * Currently unsupported.
5078 */
5079 /*ARGSUSED*/
5080 int
5081 nfs_vfs_vget(
5082 __unused mount_t mp,
5083 __unused ino64_t ino,
5084 __unused vnode_t *vpp,
5085 __unused vfs_context_t ctx)
5086 {
5087
5088 return (ENOTSUP);
5089 }
5090
5091 /*
5092 * At this point, this should never happen
5093 */
5094 /*ARGSUSED*/
5095 int
5096 nfs_vfs_fhtovp(
5097 __unused mount_t mp,
5098 __unused int fhlen,
5099 __unused unsigned char *fhp,
5100 __unused vnode_t *vpp,
5101 __unused vfs_context_t ctx)
5102 {
5103
5104 return (ENOTSUP);
5105 }
5106
5107 /*
5108 * Vnode pointer to File handle, should never happen either
5109 */
5110 /*ARGSUSED*/
5111 int
5112 nfs_vfs_vptofh(
5113 __unused vnode_t vp,
5114 __unused int *fhlenp,
5115 __unused unsigned char *fhp,
5116 __unused vfs_context_t ctx)
5117 {
5118
5119 return (ENOTSUP);
5120 }
5121
5122 /*
5123 * Vfs start routine, a no-op.
5124 */
5125 /*ARGSUSED*/
5126 int
5127 nfs_vfs_start(
5128 __unused mount_t mp,
5129 __unused int flags,
5130 __unused vfs_context_t ctx)
5131 {
5132
5133 return (0);
5134 }
5135
5136 /*
5137 * Build the mount info buffer for NFS_MOUNTINFO.
5138 */
5139 int
5140 nfs_mountinfo_assemble(struct nfsmount *nmp, struct xdrbuf *xb)
5141 {
5142 struct xdrbuf xbinfo, xborig;
5143 char sotype[6];
5144 uint32_t origargsvers, origargslength;
5145 uint32_t infolength_offset, curargsopaquelength_offset, curargslength_offset, attrslength_offset, curargs_end_offset, end_offset;
5146 uint32_t miattrs[NFS_MIATTR_BITMAP_LEN];
5147 uint32_t miflags_mask[NFS_MIFLAG_BITMAP_LEN];
5148 uint32_t miflags[NFS_MIFLAG_BITMAP_LEN];
5149 uint32_t mattrs[NFS_MATTR_BITMAP_LEN];
5150 uint32_t mflags_mask[NFS_MFLAG_BITMAP_LEN];
5151 uint32_t mflags[NFS_MFLAG_BITMAP_LEN];
5152 uint32_t loc, serv, addr, comp;
5153 int i, timeo, error = 0;
5154
5155 /* set up mount info attr and flag bitmaps */
5156 NFS_BITMAP_ZERO(miattrs, NFS_MIATTR_BITMAP_LEN);
5157 NFS_BITMAP_SET(miattrs, NFS_MIATTR_FLAGS);
5158 NFS_BITMAP_SET(miattrs, NFS_MIATTR_ORIG_ARGS);
5159 NFS_BITMAP_SET(miattrs, NFS_MIATTR_CUR_ARGS);
5160 NFS_BITMAP_SET(miattrs, NFS_MIATTR_CUR_LOC_INDEX);
5161 NFS_BITMAP_ZERO(miflags_mask, NFS_MIFLAG_BITMAP_LEN);
5162 NFS_BITMAP_ZERO(miflags, NFS_MIFLAG_BITMAP_LEN);
5163 NFS_BITMAP_SET(miflags_mask, NFS_MIFLAG_DEAD);
5164 NFS_BITMAP_SET(miflags_mask, NFS_MIFLAG_NOTRESP);
5165 NFS_BITMAP_SET(miflags_mask, NFS_MIFLAG_RECOVERY);
5166 if (nmp->nm_state & NFSSTA_DEAD)
5167 NFS_BITMAP_SET(miflags, NFS_MIFLAG_DEAD);
5168 if ((nmp->nm_state & (NFSSTA_TIMEO|NFSSTA_JUKEBOXTIMEO)) ||
5169 ((nmp->nm_state & NFSSTA_LOCKTIMEO) && (nmp->nm_lockmode == NFS_LOCK_MODE_ENABLED)))
5170 NFS_BITMAP_SET(miflags, NFS_MIFLAG_NOTRESP);
5171 if (nmp->nm_state & NFSSTA_RECOVER)
5172 NFS_BITMAP_SET(miflags, NFS_MIFLAG_RECOVERY);
5173
5174 /* get original mount args length */
5175 xb_init_buffer(&xborig, nmp->nm_args, 2*XDRWORD);
5176 xb_get_32(error, &xborig, origargsvers); /* version */
5177 xb_get_32(error, &xborig, origargslength); /* args length */
5178 nfsmerr_if(error);
5179
5180 /* set up current mount attributes bitmap */
5181 NFS_BITMAP_ZERO(mattrs, NFS_MATTR_BITMAP_LEN);
5182 NFS_BITMAP_SET(mattrs, NFS_MATTR_FLAGS);
5183 NFS_BITMAP_SET(mattrs, NFS_MATTR_NFS_VERSION);
5184 if (nmp->nm_vers >= NFS_VER4)
5185 NFS_BITMAP_SET(mattrs, NFS_MATTR_NFS_MINOR_VERSION);
5186 NFS_BITMAP_SET(mattrs, NFS_MATTR_READ_SIZE);
5187 NFS_BITMAP_SET(mattrs, NFS_MATTR_WRITE_SIZE);
5188 NFS_BITMAP_SET(mattrs, NFS_MATTR_READDIR_SIZE);
5189 NFS_BITMAP_SET(mattrs, NFS_MATTR_READAHEAD);
5190 NFS_BITMAP_SET(mattrs, NFS_MATTR_ATTRCACHE_REG_MIN);
5191 NFS_BITMAP_SET(mattrs, NFS_MATTR_ATTRCACHE_REG_MAX);
5192 NFS_BITMAP_SET(mattrs, NFS_MATTR_ATTRCACHE_DIR_MIN);
5193 NFS_BITMAP_SET(mattrs, NFS_MATTR_ATTRCACHE_DIR_MAX);
5194 NFS_BITMAP_SET(mattrs, NFS_MATTR_LOCK_MODE);
5195 NFS_BITMAP_SET(mattrs, NFS_MATTR_SECURITY);
5196 if (nmp->nm_etype.selected < nmp->nm_etype.count)
5197 NFS_BITMAP_SET(mattrs, NFS_MATTR_KERB_ETYPE);
5198 NFS_BITMAP_SET(mattrs, NFS_MATTR_MAX_GROUP_LIST);
5199 NFS_BITMAP_SET(mattrs, NFS_MATTR_SOCKET_TYPE);
5200 NFS_BITMAP_SET(mattrs, NFS_MATTR_NFS_PORT);
5201 if ((nmp->nm_vers < NFS_VER4) && nmp->nm_mountport)
5202 NFS_BITMAP_SET(mattrs, NFS_MATTR_MOUNT_PORT);
5203 NFS_BITMAP_SET(mattrs, NFS_MATTR_REQUEST_TIMEOUT);
5204 if (NMFLAG(nmp, SOFT))
5205 NFS_BITMAP_SET(mattrs, NFS_MATTR_SOFT_RETRY_COUNT);
5206 if (nmp->nm_deadtimeout)
5207 NFS_BITMAP_SET(mattrs, NFS_MATTR_DEAD_TIMEOUT);
5208 if (nmp->nm_fh)
5209 NFS_BITMAP_SET(mattrs, NFS_MATTR_FH);
5210 NFS_BITMAP_SET(mattrs, NFS_MATTR_FS_LOCATIONS);
5211 NFS_BITMAP_SET(mattrs, NFS_MATTR_MNTFLAGS);
5212 if (origargsvers < NFS_ARGSVERSION_XDR)
5213 NFS_BITMAP_SET(mattrs, NFS_MATTR_MNTFROM);
5214 if (nmp->nm_realm)
5215 NFS_BITMAP_SET(mattrs, NFS_MATTR_REALM);
5216 if (nmp->nm_principal)
5217 NFS_BITMAP_SET(mattrs, NFS_MATTR_PRINCIPAL);
5218 if (nmp->nm_sprinc)
5219 NFS_BITMAP_SET(mattrs, NFS_MATTR_SVCPRINCIPAL);
5220
5221 /* set up current mount flags bitmap */
5222 /* first set the flags that we will be setting - either on OR off */
5223 NFS_BITMAP_ZERO(mflags_mask, NFS_MFLAG_BITMAP_LEN);
5224 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_SOFT);
5225 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_INTR);
5226 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_RESVPORT);
5227 if (nmp->nm_sotype == SOCK_DGRAM)
5228 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_NOCONNECT);
5229 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_DUMBTIMER);
5230 if (nmp->nm_vers < NFS_VER4)
5231 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_CALLUMNT);
5232 if (nmp->nm_vers >= NFS_VER3)
5233 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_RDIRPLUS);
5234 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_NONEGNAMECACHE);
5235 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_MUTEJUKEBOX);
5236 if (nmp->nm_vers >= NFS_VER4) {
5237 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_EPHEMERAL);
5238 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_NOCALLBACK);
5239 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_NAMEDATTR);
5240 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_NOACL);
5241 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_ACLONLY);
5242 }
5243 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_NFC);
5244 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_NOQUOTA);
5245 if (nmp->nm_vers < NFS_VER4)
5246 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_MNTUDP);
5247 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_MNTQUICK);
5248 /* now set the flags that should be set */
5249 NFS_BITMAP_ZERO(mflags, NFS_MFLAG_BITMAP_LEN);
5250 if (NMFLAG(nmp, SOFT))
5251 NFS_BITMAP_SET(mflags, NFS_MFLAG_SOFT);
5252 if (NMFLAG(nmp, INTR))
5253 NFS_BITMAP_SET(mflags, NFS_MFLAG_INTR);
5254 if (NMFLAG(nmp, RESVPORT))
5255 NFS_BITMAP_SET(mflags, NFS_MFLAG_RESVPORT);
5256 if ((nmp->nm_sotype == SOCK_DGRAM) && NMFLAG(nmp, NOCONNECT))
5257 NFS_BITMAP_SET(mflags, NFS_MFLAG_NOCONNECT);
5258 if (NMFLAG(nmp, DUMBTIMER))
5259 NFS_BITMAP_SET(mflags, NFS_MFLAG_DUMBTIMER);
5260 if ((nmp->nm_vers < NFS_VER4) && NMFLAG(nmp, CALLUMNT))
5261 NFS_BITMAP_SET(mflags, NFS_MFLAG_CALLUMNT);
5262 if ((nmp->nm_vers >= NFS_VER3) && NMFLAG(nmp, RDIRPLUS))
5263 NFS_BITMAP_SET(mflags, NFS_MFLAG_RDIRPLUS);
5264 if (NMFLAG(nmp, NONEGNAMECACHE))
5265 NFS_BITMAP_SET(mflags, NFS_MFLAG_NONEGNAMECACHE);
5266 if (NMFLAG(nmp, MUTEJUKEBOX))
5267 NFS_BITMAP_SET(mflags, NFS_MFLAG_MUTEJUKEBOX);
5268 if (nmp->nm_vers >= NFS_VER4) {
5269 if (NMFLAG(nmp, EPHEMERAL))
5270 NFS_BITMAP_SET(mflags, NFS_MFLAG_EPHEMERAL);
5271 if (NMFLAG(nmp, NOCALLBACK))
5272 NFS_BITMAP_SET(mflags, NFS_MFLAG_NOCALLBACK);
5273 if (NMFLAG(nmp, NAMEDATTR))
5274 NFS_BITMAP_SET(mflags, NFS_MFLAG_NAMEDATTR);
5275 if (NMFLAG(nmp, NOACL))
5276 NFS_BITMAP_SET(mflags, NFS_MFLAG_NOACL);
5277 if (NMFLAG(nmp, ACLONLY))
5278 NFS_BITMAP_SET(mflags, NFS_MFLAG_ACLONLY);
5279 }
5280 if (NMFLAG(nmp, NFC))
5281 NFS_BITMAP_SET(mflags, NFS_MFLAG_NFC);
5282 if (NMFLAG(nmp, NOQUOTA) || ((nmp->nm_vers >= NFS_VER4) &&
5283 !NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_supp_attr, NFS_FATTR_QUOTA_AVAIL_HARD) &&
5284 !NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_supp_attr, NFS_FATTR_QUOTA_AVAIL_SOFT) &&
5285 !NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_supp_attr, NFS_FATTR_QUOTA_USED)))
5286 NFS_BITMAP_SET(mflags, NFS_MFLAG_NOQUOTA);
5287 if ((nmp->nm_vers < NFS_VER4) && NMFLAG(nmp, MNTUDP))
5288 NFS_BITMAP_SET(mflags, NFS_MFLAG_MNTUDP);
5289 if (NMFLAG(nmp, MNTQUICK))
5290 NFS_BITMAP_SET(mflags, NFS_MFLAG_MNTQUICK);
5291
5292 /* assemble info buffer: */
5293 xb_init_buffer(&xbinfo, NULL, 0);
5294 xb_add_32(error, &xbinfo, NFS_MOUNT_INFO_VERSION);
5295 infolength_offset = xb_offset(&xbinfo);
5296 xb_add_32(error, &xbinfo, 0);
5297 xb_add_bitmap(error, &xbinfo, miattrs, NFS_MIATTR_BITMAP_LEN);
5298 xb_add_bitmap(error, &xbinfo, miflags, NFS_MIFLAG_BITMAP_LEN);
5299 xb_add_32(error, &xbinfo, origargslength);
5300 if (!error)
5301 error = xb_add_bytes(&xbinfo, nmp->nm_args, origargslength, 0);
5302
5303 /* the opaque byte count for the current mount args values: */
5304 curargsopaquelength_offset = xb_offset(&xbinfo);
5305 xb_add_32(error, &xbinfo, 0);
5306
5307 /* Encode current mount args values */
5308 xb_add_32(error, &xbinfo, NFS_ARGSVERSION_XDR);
5309 curargslength_offset = xb_offset(&xbinfo);
5310 xb_add_32(error, &xbinfo, 0);
5311 xb_add_32(error, &xbinfo, NFS_XDRARGS_VERSION_0);
5312 xb_add_bitmap(error, &xbinfo, mattrs, NFS_MATTR_BITMAP_LEN);
5313 attrslength_offset = xb_offset(&xbinfo);
5314 xb_add_32(error, &xbinfo, 0);
5315 xb_add_bitmap(error, &xbinfo, mflags_mask, NFS_MFLAG_BITMAP_LEN);
5316 xb_add_bitmap(error, &xbinfo, mflags, NFS_MFLAG_BITMAP_LEN);
5317 xb_add_32(error, &xbinfo, nmp->nm_vers); /* NFS_VERSION */
5318 if (nmp->nm_vers >= NFS_VER4)
5319 xb_add_32(error, &xbinfo, nmp->nm_minor_vers); /* NFS_MINOR_VERSION */
5320 xb_add_32(error, &xbinfo, nmp->nm_rsize); /* READ_SIZE */
5321 xb_add_32(error, &xbinfo, nmp->nm_wsize); /* WRITE_SIZE */
5322 xb_add_32(error, &xbinfo, nmp->nm_readdirsize); /* READDIR_SIZE */
5323 xb_add_32(error, &xbinfo, nmp->nm_readahead); /* READAHEAD */
5324 xb_add_32(error, &xbinfo, nmp->nm_acregmin); /* ATTRCACHE_REG_MIN */
5325 xb_add_32(error, &xbinfo, 0); /* ATTRCACHE_REG_MIN */
5326 xb_add_32(error, &xbinfo, nmp->nm_acregmax); /* ATTRCACHE_REG_MAX */
5327 xb_add_32(error, &xbinfo, 0); /* ATTRCACHE_REG_MAX */
5328 xb_add_32(error, &xbinfo, nmp->nm_acdirmin); /* ATTRCACHE_DIR_MIN */
5329 xb_add_32(error, &xbinfo, 0); /* ATTRCACHE_DIR_MIN */
5330 xb_add_32(error, &xbinfo, nmp->nm_acdirmax); /* ATTRCACHE_DIR_MAX */
5331 xb_add_32(error, &xbinfo, 0); /* ATTRCACHE_DIR_MAX */
5332 xb_add_32(error, &xbinfo, nmp->nm_lockmode); /* LOCK_MODE */
5333 if (nmp->nm_sec.count) {
5334 xb_add_32(error, &xbinfo, nmp->nm_sec.count); /* SECURITY */
5335 nfsmerr_if(error);
5336 for (i=0; i < nmp->nm_sec.count; i++)
5337 xb_add_32(error, &xbinfo, nmp->nm_sec.flavors[i]);
5338 } else if (nmp->nm_servsec.count) {
5339 xb_add_32(error, &xbinfo, nmp->nm_servsec.count); /* SECURITY */
5340 nfsmerr_if(error);
5341 for (i=0; i < nmp->nm_servsec.count; i++)
5342 xb_add_32(error, &xbinfo, nmp->nm_servsec.flavors[i]);
5343 } else {
5344 xb_add_32(error, &xbinfo, 1); /* SECURITY */
5345 xb_add_32(error, &xbinfo, nmp->nm_auth);
5346 }
5347 if (nmp->nm_etype.selected < nmp->nm_etype.count) {
5348 xb_add_32(error, &xbinfo, nmp->nm_etype.count);
5349 xb_add_32(error, &xbinfo, nmp->nm_etype.selected);
5350 for (uint32_t j=0; j < nmp->nm_etype.count; j++)
5351 xb_add_32(error, &xbinfo, nmp->nm_etype.etypes[j]);
5352 nfsmerr_if(error);
5353 }
5354 xb_add_32(error, &xbinfo, nmp->nm_numgrps); /* MAX_GROUP_LIST */
5355 nfsmerr_if(error);
5356 snprintf(sotype, sizeof(sotype), "%s%s", (nmp->nm_sotype == SOCK_DGRAM) ? "udp" : "tcp",
5357 nmp->nm_sofamily ? (nmp->nm_sofamily == AF_INET) ? "4" : "6" : "");
5358 xb_add_string(error, &xbinfo, sotype, strlen(sotype)); /* SOCKET_TYPE */
5359 xb_add_32(error, &xbinfo, ntohs(((struct sockaddr_in*)nmp->nm_saddr)->sin_port)); /* NFS_PORT */
5360 if ((nmp->nm_vers < NFS_VER4) && nmp->nm_mountport)
5361 xb_add_32(error, &xbinfo, nmp->nm_mountport); /* MOUNT_PORT */
5362 timeo = (nmp->nm_timeo * 10) / NFS_HZ;
5363 xb_add_32(error, &xbinfo, timeo/10); /* REQUEST_TIMEOUT */
5364 xb_add_32(error, &xbinfo, (timeo%10)*100000000); /* REQUEST_TIMEOUT */
5365 if (NMFLAG(nmp, SOFT))
5366 xb_add_32(error, &xbinfo, nmp->nm_retry); /* SOFT_RETRY_COUNT */
5367 if (nmp->nm_deadtimeout) {
5368 xb_add_32(error, &xbinfo, nmp->nm_deadtimeout); /* DEAD_TIMEOUT */
5369 xb_add_32(error, &xbinfo, 0); /* DEAD_TIMEOUT */
5370 }
5371 if (nmp->nm_fh)
5372 xb_add_fh(error, &xbinfo, &nmp->nm_fh->fh_data[0], nmp->nm_fh->fh_len); /* FH */
5373 xb_add_32(error, &xbinfo, nmp->nm_locations.nl_numlocs); /* FS_LOCATIONS */
5374 for (loc = 0; !error && (loc < nmp->nm_locations.nl_numlocs); loc++) {
5375 xb_add_32(error, &xbinfo, nmp->nm_locations.nl_locations[loc]->nl_servcount);
5376 for (serv = 0; !error && (serv < nmp->nm_locations.nl_locations[loc]->nl_servcount); serv++) {
5377 xb_add_string(error, &xbinfo, nmp->nm_locations.nl_locations[loc]->nl_servers[serv]->ns_name,
5378 strlen(nmp->nm_locations.nl_locations[loc]->nl_servers[serv]->ns_name));
5379 xb_add_32(error, &xbinfo, nmp->nm_locations.nl_locations[loc]->nl_servers[serv]->ns_addrcount);
5380 for (addr = 0; !error && (addr < nmp->nm_locations.nl_locations[loc]->nl_servers[serv]->ns_addrcount); addr++)
5381 xb_add_string(error, &xbinfo, nmp->nm_locations.nl_locations[loc]->nl_servers[serv]->ns_addresses[addr],
5382 strlen(nmp->nm_locations.nl_locations[loc]->nl_servers[serv]->ns_addresses[addr]));
5383 xb_add_32(error, &xbinfo, 0); /* empty server info */
5384 }
5385 xb_add_32(error, &xbinfo, nmp->nm_locations.nl_locations[loc]->nl_path.np_compcount);
5386 for (comp = 0; !error && (comp < nmp->nm_locations.nl_locations[loc]->nl_path.np_compcount); comp++)
5387 xb_add_string(error, &xbinfo, nmp->nm_locations.nl_locations[loc]->nl_path.np_components[comp],
5388 strlen(nmp->nm_locations.nl_locations[loc]->nl_path.np_components[comp]));
5389 xb_add_32(error, &xbinfo, 0); /* empty fs location info */
5390 }
5391 xb_add_32(error, &xbinfo, vfs_flags(nmp->nm_mountp)); /* MNTFLAGS */
5392 if (origargsvers < NFS_ARGSVERSION_XDR)
5393 xb_add_string(error, &xbinfo, vfs_statfs(nmp->nm_mountp)->f_mntfromname,
5394 strlen(vfs_statfs(nmp->nm_mountp)->f_mntfromname)); /* MNTFROM */
5395 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_REALM))
5396 xb_add_string(error, &xbinfo, nmp->nm_realm, strlen(nmp->nm_realm));
5397 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_PRINCIPAL))
5398 xb_add_string(error, &xbinfo, nmp->nm_principal, strlen(nmp->nm_principal));
5399 if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_SVCPRINCIPAL))
5400 xb_add_string(error, &xbinfo, nmp->nm_sprinc, strlen(nmp->nm_sprinc));
5401
5402 curargs_end_offset = xb_offset(&xbinfo);
5403
5404 /* NFS_MIATTR_CUR_LOC_INDEX */
5405 xb_add_32(error, &xbinfo, nmp->nm_locations.nl_current.nli_flags);
5406 xb_add_32(error, &xbinfo, nmp->nm_locations.nl_current.nli_loc);
5407 xb_add_32(error, &xbinfo, nmp->nm_locations.nl_current.nli_serv);
5408 xb_add_32(error, &xbinfo, nmp->nm_locations.nl_current.nli_addr);
5409
5410 xb_build_done(error, &xbinfo);
5411
5412 /* update opaque counts */
5413 end_offset = xb_offset(&xbinfo);
5414 if (!error) {
5415 error = xb_seek(&xbinfo, attrslength_offset);
5416 xb_add_32(error, &xbinfo, curargs_end_offset - attrslength_offset - XDRWORD/*don't include length field*/);
5417 }
5418 if (!error) {
5419 error = xb_seek(&xbinfo, curargslength_offset);
5420 xb_add_32(error, &xbinfo, curargs_end_offset - curargslength_offset + XDRWORD/*version*/);
5421 }
5422 if (!error) {
5423 error = xb_seek(&xbinfo, curargsopaquelength_offset);
5424 xb_add_32(error, &xbinfo, curargs_end_offset - curargslength_offset + XDRWORD/*version*/);
5425 }
5426 if (!error) {
5427 error = xb_seek(&xbinfo, infolength_offset);
5428 xb_add_32(error, &xbinfo, end_offset - infolength_offset + XDRWORD/*version*/);
5429 }
5430 nfsmerr_if(error);
5431
5432 /* copy result xdrbuf to caller */
5433 *xb = xbinfo;
5434
5435 /* and mark the local copy as not needing cleanup */
5436 xbinfo.xb_flags &= ~XB_CLEANUP;
5437 nfsmerr:
5438 xb_cleanup(&xbinfo);
5439 return (error);
5440 }
5441
5442 /*
5443 * Do that sysctl thang...
5444 */
5445 int
5446 nfs_vfs_sysctl(int *name, u_int namelen, user_addr_t oldp, size_t *oldlenp,
5447 user_addr_t newp, size_t newlen, vfs_context_t ctx)
5448 {
5449 int error = 0, val;
5450 #ifndef CONFIG_EMBEDDED
5451 int softnobrowse;
5452 #endif
5453 struct sysctl_req *req = NULL;
5454 union union_vfsidctl vc;
5455 mount_t mp;
5456 struct nfsmount *nmp = NULL;
5457 struct vfsquery vq;
5458 struct nfsreq *rq;
5459 boolean_t is_64_bit;
5460 fsid_t fsid;
5461 struct xdrbuf xb;
5462 struct netfs_status *nsp = NULL;
5463 int timeoutmask;
5464 uint pos, totlen, count, numThreads;
5465 #if NFSSERVER
5466 struct nfs_exportfs *nxfs;
5467 struct nfs_export *nx;
5468 struct nfs_active_user_list *ulist;
5469 struct nfs_export_stat_desc stat_desc = {};
5470 struct nfs_export_stat_rec statrec;
5471 struct nfs_user_stat_node *unode, *unode_next;
5472 struct nfs_user_stat_desc ustat_desc = {};
5473 struct nfs_user_stat_user_rec ustat_rec;
5474 struct nfs_user_stat_path_rec upath_rec;
5475 uint bytes_avail, bytes_total, recs_copied;
5476 uint numExports, numRecs;
5477 #endif /* NFSSERVER */
5478
5479 /*
5480 * All names at this level are terminal.
5481 */
5482 if (namelen > 1)
5483 return (ENOTDIR); /* overloaded */
5484
5485 is_64_bit = vfs_context_is64bit(ctx);
5486
5487 /* common code for "new style" VFS_CTL sysctl, get the mount. */
5488 switch (name[0]) {
5489 case VFS_CTL_TIMEO:
5490 case VFS_CTL_NOLOCKS:
5491 case VFS_CTL_NSTATUS:
5492 #ifndef CONFIG_EMBEDDED
5493 case VFS_CTL_QUERY:
5494 #endif
5495 req = CAST_DOWN(struct sysctl_req *, oldp);
5496 if (req == NULL) {
5497 return EFAULT;
5498 }
5499 error = SYSCTL_IN(req, &vc, is_64_bit? sizeof(vc.vc64):sizeof(vc.vc32));
5500 if (error)
5501 return (error);
5502 mp = vfs_getvfs(&vc.vc32.vc_fsid); /* works for 32 and 64 */
5503 if (mp == NULL)
5504 return (ENOENT);
5505 nmp = VFSTONFS(mp);
5506 if (!nmp)
5507 return (ENOENT);
5508 bzero(&vq, sizeof(vq));
5509 req->newidx = 0;
5510 if (is_64_bit) {
5511 req->newptr = vc.vc64.vc_ptr;
5512 req->newlen = (size_t)vc.vc64.vc_len;
5513 } else {
5514 req->newptr = CAST_USER_ADDR_T(vc.vc32.vc_ptr);
5515 req->newlen = vc.vc32.vc_len;
5516 }
5517 break;
5518 #if CONFIG_EMBEDDED
5519 case VFS_CTL_QUERY:
5520 return EPERM;
5521 #endif
5522 }
5523
5524 switch(name[0]) {
5525 case NFS_NFSSTATS:
5526 if (!oldp) {
5527 *oldlenp = sizeof nfsstats;
5528 return (0);
5529 }
5530
5531 if (*oldlenp < sizeof nfsstats) {
5532 *oldlenp = sizeof nfsstats;
5533 return (ENOMEM);
5534 }
5535
5536 error = copyout(&nfsstats, oldp, sizeof nfsstats);
5537 if (error)
5538 return (error);
5539
5540 if (newp && newlen != sizeof nfsstats)
5541 return (EINVAL);
5542
5543 if (newp)
5544 return copyin(newp, &nfsstats, sizeof nfsstats);
5545 return (0);
5546 case NFS_MOUNTINFO:
5547 /* read in the fsid */
5548 if (*oldlenp < sizeof(fsid))
5549 return (EINVAL);
5550 if ((error = copyin(oldp, &fsid, sizeof(fsid))))
5551 return (error);
5552 /* swizzle it back to host order */
5553 fsid.val[0] = ntohl(fsid.val[0]);
5554 fsid.val[1] = ntohl(fsid.val[1]);
5555 /* find mount and make sure it's NFS */
5556 if (((mp = vfs_getvfs(&fsid))) == NULL)
5557 return (ENOENT);
5558 if (strcmp(mp->mnt_vfsstat.f_fstypename, "nfs"))
5559 return (EINVAL);
5560 if (((nmp = VFSTONFS(mp))) == NULL)
5561 return (ENOENT);
5562 xb_init(&xb, 0);
5563 if ((error = nfs_mountinfo_assemble(nmp, &xb)))
5564 return (error);
5565 if (*oldlenp < xb.xb_u.xb_buffer.xbb_len)
5566 error = ENOMEM;
5567 else
5568 error = copyout(xb_buffer_base(&xb), oldp, xb.xb_u.xb_buffer.xbb_len);
5569 *oldlenp = xb.xb_u.xb_buffer.xbb_len;
5570 xb_cleanup(&xb);
5571 break;
5572 #if NFSSERVER
5573 case NFS_EXPORTSTATS:
5574 /* setup export stat descriptor */
5575 stat_desc.rec_vers = NFS_EXPORT_STAT_REC_VERSION;
5576
5577 if (!nfsrv_is_initialized()) {
5578 stat_desc.rec_count = 0;
5579 if (oldp && (*oldlenp >= sizeof(struct nfs_export_stat_desc)))
5580 error = copyout(&stat_desc, oldp, sizeof(struct nfs_export_stat_desc));
5581 *oldlenp = sizeof(struct nfs_export_stat_desc);
5582 return (error);
5583 }
5584
5585 /* Count the number of exported directories */
5586 lck_rw_lock_shared(&nfsrv_export_rwlock);
5587 numExports = 0;
5588 LIST_FOREACH(nxfs, &nfsrv_exports, nxfs_next)
5589 LIST_FOREACH(nx, &nxfs->nxfs_exports, nx_next)
5590 numExports += 1;
5591
5592 /* update stat descriptor's export record count */
5593 stat_desc.rec_count = numExports;
5594
5595 /* calculate total size of required buffer */
5596 totlen = sizeof(struct nfs_export_stat_desc) + (numExports * sizeof(struct nfs_export_stat_rec));
5597
5598 /* Check caller's buffer */
5599 if (oldp == 0) {
5600 lck_rw_done(&nfsrv_export_rwlock);
5601 /* indicate required buffer len */
5602 *oldlenp = totlen;
5603 return (0);
5604 }
5605
5606 /* We require the caller's buffer to be at least large enough to hold the descriptor */
5607 if (*oldlenp < sizeof(struct nfs_export_stat_desc)) {
5608 lck_rw_done(&nfsrv_export_rwlock);
5609 /* indicate required buffer len */
5610 *oldlenp = totlen;
5611 return (ENOMEM);
5612 }
5613
5614 /* indicate required buffer len */
5615 *oldlenp = totlen;
5616
5617 /* check if export table is empty */
5618 if (!numExports) {
5619 lck_rw_done(&nfsrv_export_rwlock);
5620 error = copyout(&stat_desc, oldp, sizeof(struct nfs_export_stat_desc));
5621 return (error);
5622 }
5623
5624 /* calculate how many actual export stat records fit into caller's buffer */
5625 numRecs = (*oldlenp - sizeof(struct nfs_export_stat_desc)) / sizeof(struct nfs_export_stat_rec);
5626
5627 if (!numRecs) {
5628 /* caller's buffer can only accomodate descriptor */
5629 lck_rw_done(&nfsrv_export_rwlock);
5630 stat_desc.rec_count = 0;
5631 error = copyout(&stat_desc, oldp, sizeof(struct nfs_export_stat_desc));
5632 return (error);
5633 }
5634
5635 /* adjust to actual number of records to copyout to caller's buffer */
5636 if (numRecs > numExports)
5637 numRecs = numExports;
5638
5639 /* set actual number of records we are returning */
5640 stat_desc.rec_count = numRecs;
5641
5642 /* first copy out the stat descriptor */
5643 pos = 0;
5644 error = copyout(&stat_desc, oldp + pos, sizeof(struct nfs_export_stat_desc));
5645 if (error) {
5646 lck_rw_done(&nfsrv_export_rwlock);
5647 return (error);
5648 }
5649 pos += sizeof(struct nfs_export_stat_desc);
5650
5651 /* Loop through exported directories */
5652 count = 0;
5653 LIST_FOREACH(nxfs, &nfsrv_exports, nxfs_next) {
5654 LIST_FOREACH(nx, &nxfs->nxfs_exports, nx_next) {
5655
5656 if (count >= numRecs)
5657 break;
5658
5659 /* build exported filesystem path */
5660 memset(statrec.path, 0, sizeof(statrec.path));
5661 snprintf(statrec.path, sizeof(statrec.path), "%s%s%s",
5662 nxfs->nxfs_path, ((nxfs->nxfs_path[1] && nx->nx_path[0]) ? "/" : ""),
5663 nx->nx_path);
5664
5665 /* build the 64-bit export stat counters */
5666 statrec.ops = ((uint64_t)nx->nx_stats.ops.hi << 32) |
5667 nx->nx_stats.ops.lo;
5668 statrec.bytes_read = ((uint64_t)nx->nx_stats.bytes_read.hi << 32) |
5669 nx->nx_stats.bytes_read.lo;
5670 statrec.bytes_written = ((uint64_t)nx->nx_stats.bytes_written.hi << 32) |
5671 nx->nx_stats.bytes_written.lo;
5672 error = copyout(&statrec, oldp + pos, sizeof(statrec));
5673 if (error) {
5674 lck_rw_done(&nfsrv_export_rwlock);
5675 return (error);
5676 }
5677 /* advance buffer position */
5678 pos += sizeof(statrec);
5679 }
5680 }
5681 lck_rw_done(&nfsrv_export_rwlock);
5682 break;
5683 case NFS_USERSTATS:
5684 /* init structures used for copying out of kernel */
5685 ustat_desc.rec_vers = NFS_USER_STAT_REC_VERSION;
5686 ustat_rec.rec_type = NFS_USER_STAT_USER_REC;
5687 upath_rec.rec_type = NFS_USER_STAT_PATH_REC;
5688
5689 /* initialize counters */
5690 bytes_total = sizeof(struct nfs_user_stat_desc);
5691 bytes_avail = *oldlenp;
5692 recs_copied = 0;
5693
5694 if (!nfsrv_is_initialized()) /* NFS server not initialized, so no stats */
5695 goto ustat_skip;
5696
5697 /* reclaim old expired user nodes */
5698 nfsrv_active_user_list_reclaim();
5699
5700 /* reserve space for the buffer descriptor */
5701 if (bytes_avail >= sizeof(struct nfs_user_stat_desc))
5702 bytes_avail -= sizeof(struct nfs_user_stat_desc);
5703 else
5704 bytes_avail = 0;
5705
5706 /* put buffer position past the buffer descriptor */
5707 pos = sizeof(struct nfs_user_stat_desc);
5708
5709 /* Loop through exported directories */
5710 lck_rw_lock_shared(&nfsrv_export_rwlock);
5711 LIST_FOREACH(nxfs, &nfsrv_exports, nxfs_next) {
5712 LIST_FOREACH(nx, &nxfs->nxfs_exports, nx_next) {
5713 /* copy out path */
5714 if (bytes_avail >= sizeof(struct nfs_user_stat_path_rec)) {
5715 memset(upath_rec.path, 0, sizeof(upath_rec.path));
5716 snprintf(upath_rec.path, sizeof(upath_rec.path), "%s%s%s",
5717 nxfs->nxfs_path, ((nxfs->nxfs_path[1] && nx->nx_path[0]) ? "/" : ""),
5718 nx->nx_path);
5719
5720 error = copyout(&upath_rec, oldp + pos, sizeof(struct nfs_user_stat_path_rec));
5721 if (error) {
5722 /* punt */
5723 goto ustat_done;
5724 }
5725
5726 pos += sizeof(struct nfs_user_stat_path_rec);
5727 bytes_avail -= sizeof(struct nfs_user_stat_path_rec);
5728 recs_copied++;
5729 }
5730 else {
5731 /* Caller's buffer is exhausted */
5732 bytes_avail = 0;
5733 }
5734
5735 bytes_total += sizeof(struct nfs_user_stat_path_rec);
5736
5737 /* Scan through all user nodes of this export */
5738 ulist = &nx->nx_user_list;
5739 lck_mtx_lock(&ulist->user_mutex);
5740 for (unode = TAILQ_FIRST(&ulist->user_lru); unode; unode = unode_next) {
5741 unode_next = TAILQ_NEXT(unode, lru_link);
5742
5743 /* copy out node if there is space */
5744 if (bytes_avail >= sizeof(struct nfs_user_stat_user_rec)) {
5745 /* prepare a user stat rec for copying out */
5746 ustat_rec.uid = unode->uid;
5747 memset(&ustat_rec.sock, 0, sizeof(ustat_rec.sock));
5748 bcopy(&unode->sock, &ustat_rec.sock, unode->sock.ss_len);
5749 ustat_rec.ops = unode->ops;
5750 ustat_rec.bytes_read = unode->bytes_read;
5751 ustat_rec.bytes_written = unode->bytes_written;
5752 ustat_rec.tm_start = unode->tm_start;
5753 ustat_rec.tm_last = unode->tm_last;
5754
5755 error = copyout(&ustat_rec, oldp + pos, sizeof(struct nfs_user_stat_user_rec));
5756
5757 if (error) {
5758 /* punt */
5759 lck_mtx_unlock(&ulist->user_mutex);
5760 goto ustat_done;
5761 }
5762
5763 pos += sizeof(struct nfs_user_stat_user_rec);
5764 bytes_avail -= sizeof(struct nfs_user_stat_user_rec);
5765 recs_copied++;
5766 }
5767 else {
5768 /* Caller's buffer is exhausted */
5769 bytes_avail = 0;
5770 }
5771 bytes_total += sizeof(struct nfs_user_stat_user_rec);
5772 }
5773 /* can unlock this export's list now */
5774 lck_mtx_unlock(&ulist->user_mutex);
5775 }
5776 }
5777
5778 ustat_done:
5779 /* unlock the export table */
5780 lck_rw_done(&nfsrv_export_rwlock);
5781
5782 ustat_skip:
5783 /* indicate number of actual records copied */
5784 ustat_desc.rec_count = recs_copied;
5785
5786 if (!error) {
5787 /* check if there was enough room for the buffer descriptor */
5788 if (*oldlenp >= sizeof(struct nfs_user_stat_desc))
5789 error = copyout(&ustat_desc, oldp, sizeof(struct nfs_user_stat_desc));
5790 else
5791 error = ENOMEM;
5792
5793 /* always indicate required buffer size */
5794 *oldlenp = bytes_total;
5795 }
5796 break;
5797 case NFS_USERCOUNT:
5798 if (!oldp) {
5799 *oldlenp = sizeof(nfsrv_user_stat_node_count);
5800 return (0);
5801 }
5802
5803 if (*oldlenp < sizeof(nfsrv_user_stat_node_count)) {
5804 *oldlenp = sizeof(nfsrv_user_stat_node_count);
5805 return (ENOMEM);
5806 }
5807
5808 if (nfsrv_is_initialized()) {
5809 /* reclaim old expired user nodes */
5810 nfsrv_active_user_list_reclaim();
5811 }
5812
5813 error = copyout(&nfsrv_user_stat_node_count, oldp, sizeof(nfsrv_user_stat_node_count));
5814 break;
5815 #endif /* NFSSERVER */
5816 case VFS_CTL_NOLOCKS:
5817 if (req->oldptr != USER_ADDR_NULL) {
5818 lck_mtx_lock(&nmp->nm_lock);
5819 val = (nmp->nm_lockmode == NFS_LOCK_MODE_DISABLED) ? 1 : 0;
5820 lck_mtx_unlock(&nmp->nm_lock);
5821 error = SYSCTL_OUT(req, &val, sizeof(val));
5822 if (error)
5823 return (error);
5824 }
5825 if (req->newptr != USER_ADDR_NULL) {
5826 error = SYSCTL_IN(req, &val, sizeof(val));
5827 if (error)
5828 return (error);
5829 lck_mtx_lock(&nmp->nm_lock);
5830 if (nmp->nm_lockmode == NFS_LOCK_MODE_LOCAL) {
5831 /* can't toggle locks when using local locks */
5832 error = EINVAL;
5833 } else if ((nmp->nm_vers >= NFS_VER4) && val) {
5834 /* can't disable locks for NFSv4 */
5835 error = EINVAL;
5836 } else if (val) {
5837 if ((nmp->nm_vers <= NFS_VER3) && (nmp->nm_lockmode == NFS_LOCK_MODE_ENABLED))
5838 nfs_lockd_mount_unregister(nmp);
5839 nmp->nm_lockmode = NFS_LOCK_MODE_DISABLED;
5840 nmp->nm_state &= ~NFSSTA_LOCKTIMEO;
5841 } else {
5842 if ((nmp->nm_vers <= NFS_VER3) && (nmp->nm_lockmode == NFS_LOCK_MODE_DISABLED))
5843 nfs_lockd_mount_register(nmp);
5844 nmp->nm_lockmode = NFS_LOCK_MODE_ENABLED;
5845 }
5846 lck_mtx_unlock(&nmp->nm_lock);
5847 }
5848 break;
5849 #ifndef CONFIG_EMBEDDED
5850 case VFS_CTL_QUERY:
5851 lck_mtx_lock(&nmp->nm_lock);
5852 /* XXX don't allow users to know about/disconnect unresponsive, soft, nobrowse mounts */
5853 softnobrowse = (NMFLAG(nmp, SOFT) && (vfs_flags(nmp->nm_mountp) & MNT_DONTBROWSE));
5854 if (!softnobrowse && (nmp->nm_state & NFSSTA_TIMEO))
5855 vq.vq_flags |= VQ_NOTRESP;
5856 if (!softnobrowse && (nmp->nm_state & NFSSTA_JUKEBOXTIMEO) && !NMFLAG(nmp, MUTEJUKEBOX))
5857 vq.vq_flags |= VQ_NOTRESP;
5858 if (!softnobrowse && (nmp->nm_state & NFSSTA_LOCKTIMEO) &&
5859 (nmp->nm_lockmode == NFS_LOCK_MODE_ENABLED))
5860 vq.vq_flags |= VQ_NOTRESP;
5861 if (nmp->nm_state & NFSSTA_DEAD)
5862 vq.vq_flags |= VQ_DEAD;
5863 lck_mtx_unlock(&nmp->nm_lock);
5864 error = SYSCTL_OUT(req, &vq, sizeof(vq));
5865 break;
5866 #endif
5867 case VFS_CTL_TIMEO:
5868 if (req->oldptr != USER_ADDR_NULL) {
5869 lck_mtx_lock(&nmp->nm_lock);
5870 val = nmp->nm_tprintf_initial_delay;
5871 lck_mtx_unlock(&nmp->nm_lock);
5872 error = SYSCTL_OUT(req, &val, sizeof(val));
5873 if (error)
5874 return (error);
5875 }
5876 if (req->newptr != USER_ADDR_NULL) {
5877 error = SYSCTL_IN(req, &val, sizeof(val));
5878 if (error)
5879 return (error);
5880 lck_mtx_lock(&nmp->nm_lock);
5881 if (val < 0)
5882 nmp->nm_tprintf_initial_delay = 0;
5883 else
5884 nmp->nm_tprintf_initial_delay = val;
5885 lck_mtx_unlock(&nmp->nm_lock);
5886 }
5887 break;
5888 case VFS_CTL_NSTATUS:
5889 /*
5890 * Return the status of this mount. This is much more
5891 * information than VFS_CTL_QUERY. In addition to the
5892 * vq_flags return the significant mount options along
5893 * with the list of threads blocked on the mount and
5894 * how long the threads have been waiting.
5895 */
5896
5897 lck_mtx_lock(nfs_request_mutex);
5898 lck_mtx_lock(&nmp->nm_lock);
5899
5900 /*
5901 * Count the number of requests waiting for a reply.
5902 * Note: there could be multiple requests from the same thread.
5903 */
5904 numThreads = 0;
5905 TAILQ_FOREACH(rq, &nfs_reqq, r_chain) {
5906 if (rq->r_nmp == nmp)
5907 numThreads++;
5908 }
5909
5910 /* Calculate total size of result buffer */
5911 totlen = sizeof(struct netfs_status) + (numThreads * sizeof(uint64_t));
5912
5913 if (req->oldptr == USER_ADDR_NULL) { // Caller is querying buffer size
5914 lck_mtx_unlock(&nmp->nm_lock);
5915 lck_mtx_unlock(nfs_request_mutex);
5916 return SYSCTL_OUT(req, NULL, totlen);
5917 }
5918 if (req->oldlen < totlen) { // Check if caller's buffer is big enough
5919 lck_mtx_unlock(&nmp->nm_lock);
5920 lck_mtx_unlock(nfs_request_mutex);
5921 return (ERANGE);
5922 }
5923
5924 MALLOC(nsp, struct netfs_status *, totlen, M_TEMP, M_WAITOK|M_ZERO);
5925 if (nsp == NULL) {
5926 lck_mtx_unlock(&nmp->nm_lock);
5927 lck_mtx_unlock(nfs_request_mutex);
5928 return (ENOMEM);
5929 }
5930 timeoutmask = NFSSTA_TIMEO | NFSSTA_LOCKTIMEO | NFSSTA_JUKEBOXTIMEO;
5931 if (nmp->nm_state & timeoutmask)
5932 nsp->ns_status |= VQ_NOTRESP;
5933 if (nmp->nm_state & NFSSTA_DEAD)
5934 nsp->ns_status |= VQ_DEAD;
5935
5936 (void) nfs_mountopts(nmp, nsp->ns_mountopts, sizeof(nsp->ns_mountopts));
5937 nsp->ns_threadcount = numThreads;
5938
5939 /*
5940 * Get the thread ids of threads waiting for a reply
5941 * and find the longest wait time.
5942 */
5943 if (numThreads > 0) {
5944 struct timeval now;
5945 time_t sendtime;
5946
5947 microuptime(&now);
5948 count = 0;
5949 sendtime = now.tv_sec;
5950 TAILQ_FOREACH(rq, &nfs_reqq, r_chain) {
5951 if (rq->r_nmp == nmp) {
5952 if (rq->r_start < sendtime)
5953 sendtime = rq->r_start;
5954 // A thread_id of zero is used to represent an async I/O request.
5955 nsp->ns_threadids[count] =
5956 rq->r_thread ? thread_tid(rq->r_thread) : 0;
5957 if (++count >= numThreads)
5958 break;
5959 }
5960 }
5961 nsp->ns_waittime = now.tv_sec - sendtime;
5962 }
5963
5964 lck_mtx_unlock(&nmp->nm_lock);
5965 lck_mtx_unlock(nfs_request_mutex);
5966
5967 error = SYSCTL_OUT(req, nsp, totlen);
5968 FREE(nsp, M_TEMP);
5969 break;
5970 default:
5971 return (ENOTSUP);
5972 }
5973 return (error);
5974 }