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