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