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