2 * Copyright (c) 2000-2009 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
30 * Copyright (c) 1989, 1993, 1995
31 * The Regents of the University of California. All rights reserved.
33 * This code is derived from software contributed to Berkeley by
34 * Rick Macklem at The University of Guelph.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
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.
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
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 $
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,
74 #include <sys/param.h>
75 #include <sys/systm.h>
77 #include <sys/ioctl.h>
78 #include <sys/signal.h>
79 #include <sys/proc_internal.h> /* for fs rooting to update rootdir in fdp */
80 #include <sys/kauth.h>
81 #include <sys/vnode_internal.h>
82 #include <sys/malloc.h>
83 #include <sys/kernel.h>
84 #include <sys/sysctl.h>
85 #include <sys/mount_internal.h>
86 #include <sys/kpi_mbuf.h>
87 #include <sys/socket.h>
88 #include <sys/socketvar.h>
89 #include <sys/fcntl.h>
90 #include <sys/quota.h>
91 #include <libkern/OSAtomic.h>
94 #include <sys/vmparam.h>
96 #if !defined(NO_MOUNT_PRIVATE)
97 #include <sys/filedesc.h>
98 #endif /* NO_MOUNT_PRIVATE */
101 #include <net/route.h>
102 #include <netinet/in.h>
104 #include <nfs/rpcv2.h>
105 #include <nfs/krpc.h>
106 #include <nfs/nfsproto.h>
108 #include <nfs/nfsnode.h>
109 #include <nfs/nfs_gss.h>
110 #include <nfs/nfsmount.h>
111 #include <nfs/xdr_subs.h>
112 #include <nfs/nfsm_subs.h>
113 #include <nfs/nfsdiskless.h>
114 #include <nfs/nfs_lock.h>
116 #include <security/mac_framework.h>
119 #include <pexpert/pexpert.h>
126 static lck_grp_t
*nfs_global_grp
, *nfs_mount_grp
;
127 lck_mtx_t
*nfs_global_mutex
;
128 uint32_t nfs_fs_attr_bitmap
[NFS_ATTR_BITMAP_LEN
];
129 uint32_t nfs_object_attr_bitmap
[NFS_ATTR_BITMAP_LEN
];
130 uint32_t nfs_getattr_bitmap
[NFS_ATTR_BITMAP_LEN
];
131 struct nfsclientidlist nfsclientids
;
134 struct nfs_reqqhead nfs_reqq
;
135 lck_grp_t
*nfs_request_grp
;
136 lck_mtx_t
*nfs_request_mutex
;
137 thread_call_t nfs_request_timer_call
;
138 int nfs_request_timer_on
;
139 u_int32_t nfs_xid
= 0;
140 u_int32_t nfs_xidwrap
= 0; /* to build a (non-wrapping) 64 bit xid */
142 thread_call_t nfs_buf_timer_call
;
145 lck_grp_t
*nfs_open_grp
;
146 uint32_t nfs_open_owner_seqnum
= 0;
147 uint32_t nfs_lock_owner_seqnum
= 0;
148 thread_call_t nfs4_callback_timer_call
;
149 int nfs4_callback_timer_on
= 0;
152 lck_grp_t
*nfsiod_lck_grp
;
153 lck_mtx_t
*nfsiod_mutex
;
154 struct nfsiodlist nfsiodfree
, nfsiodwork
;
155 struct nfsiodmountlist nfsiodmounts
;
156 int nfsiod_thread_count
= 0;
157 int nfsiod_thread_max
= NFS_DEFASYNCTHREAD
;
158 int nfs_max_async_writes
= NFS_DEFMAXASYNCWRITES
;
160 int nfs_iosize
= NFS_IOSIZE
;
161 int nfs_access_cache_timeout
= NFS_MAXATTRTIMO
;
162 int nfs_access_delete
= 0;
163 int nfs_allow_async
= 0;
164 int nfs_statfs_rate_limit
= NFS_DEFSTATFSRATELIMIT
;
165 int nfs_lockd_mounts
= 0;
166 int nfs_lockd_request_sent
= 0;
168 int nfs_tprintf_initial_delay
= NFS_TPRINTF_INITIAL_DELAY
;
169 int nfs_tprintf_delay
= NFS_TPRINTF_DELAY
;
172 int mountnfs(struct user_nfs_args
*,mount_t
,mbuf_t
,vfs_context_t
,vnode_t
*);
173 static int nfs_mount_diskless(struct nfs_dlmount
*, const char *, int, vnode_t
*, mount_t
*, vfs_context_t
);
174 #if !defined(NO_MOUNT_PRIVATE)
175 static int nfs_mount_diskless_private(struct nfs_dlmount
*, const char *, int, vnode_t
*, mount_t
*, vfs_context_t
);
176 #endif /* NO_MOUNT_PRIVATE */
179 * NFS VFS operations.
181 int nfs_vfs_mount(mount_t
, vnode_t
, user_addr_t
, vfs_context_t
);
182 int nfs_vfs_start(mount_t
, int, vfs_context_t
);
183 int nfs_vfs_unmount(mount_t
, int, vfs_context_t
);
184 int nfs_vfs_root(mount_t
, vnode_t
*, vfs_context_t
);
185 int nfs_vfs_quotactl(mount_t
, int, uid_t
, caddr_t
, vfs_context_t
);
186 int nfs_vfs_getattr(mount_t
, struct vfs_attr
*, vfs_context_t
);
187 int nfs_vfs_sync(mount_t
, int, vfs_context_t
);
188 int nfs_vfs_vget(mount_t
, ino64_t
, vnode_t
*, vfs_context_t
);
189 int nfs_vfs_vptofh(vnode_t
, int *, unsigned char *, vfs_context_t
);
190 int nfs_vfs_fhtovp(mount_t
, int, unsigned char *, vnode_t
*, vfs_context_t
);
191 int nfs_vfs_init(struct vfsconf
*);
192 int nfs_vfs_sysctl(int *, u_int
, user_addr_t
, size_t *, user_addr_t
, size_t, vfs_context_t
);
194 struct vfsops nfs_vfsops
= {
208 { NULL
, /* reserved */
214 NULL
} /* reserved */
219 * version-specific NFS functions
221 int nfs3_mount(struct nfsmount
*, vfs_context_t
, struct user_nfs_args
*, nfsnode_t
*);
222 int nfs4_mount(struct nfsmount
*, vfs_context_t
, struct user_nfs_args
*, nfsnode_t
*);
223 int nfs3_fsinfo(struct nfsmount
*, nfsnode_t
, vfs_context_t
);
224 int nfs3_update_statfs(struct nfsmount
*, vfs_context_t
);
225 int nfs4_update_statfs(struct nfsmount
*, vfs_context_t
);
227 #define nfs3_getquota NULL
228 #define nfs4_getquota NULL
230 int nfs3_getquota(struct nfsmount
*, vfs_context_t
, uid_t
, int, struct dqblk
*);
231 int nfs4_getquota(struct nfsmount
*, vfs_context_t
, uid_t
, int, struct dqblk
*);
234 struct nfs_funcs nfs3_funcs
= {
242 nfs3_read_rpc_async_finish
,
244 nfs3_write_rpc_async
,
245 nfs3_write_rpc_async_finish
,
247 nfs3_lookup_rpc_async
,
248 nfs3_lookup_rpc_async_finish
,
252 struct nfs_funcs nfs4_funcs
= {
260 nfs4_read_rpc_async_finish
,
262 nfs4_write_rpc_async
,
263 nfs4_write_rpc_async_finish
,
265 nfs4_lookup_rpc_async
,
266 nfs4_lookup_rpc_async_finish
,
272 * Called once to initialize data structures...
275 nfs_vfs_init(__unused
struct vfsconf
*vfsp
)
280 * Check to see if major data structures haven't bloated.
282 if (sizeof (struct nfsnode
) > NFS_NODEALLOC
) {
283 printf("struct nfsnode bloated (> %dbytes)\n", NFS_NODEALLOC
);
284 printf("Try reducing NFS_SMALLFH\n");
286 if (sizeof (struct nfsmount
) > NFS_MNTALLOC
)
287 printf("struct nfsmount bloated (> %dbytes)\n", NFS_MNTALLOC
);
289 nfs_ticks
= (hz
* NFS_TICKINTVL
+ 500) / 1000;
293 /* init async I/O thread pool state */
294 TAILQ_INIT(&nfsiodfree
);
295 TAILQ_INIT(&nfsiodwork
);
296 TAILQ_INIT(&nfsiodmounts
);
297 nfsiod_lck_grp
= lck_grp_alloc_init("nfsiod", LCK_GRP_ATTR_NULL
);
298 nfsiod_mutex
= lck_mtx_alloc_init(nfsiod_lck_grp
, LCK_ATTR_NULL
);
300 /* init lock groups, etc. */
301 nfs_mount_grp
= lck_grp_alloc_init("nfs_mount", LCK_GRP_ATTR_NULL
);
302 nfs_open_grp
= lck_grp_alloc_init("nfs_open", LCK_GRP_ATTR_NULL
);
303 nfs_global_grp
= lck_grp_alloc_init("nfs_global", LCK_GRP_ATTR_NULL
);
305 nfs_global_mutex
= lck_mtx_alloc_init(nfs_global_grp
, LCK_ATTR_NULL
);
307 /* init request list mutex */
308 nfs_request_grp
= lck_grp_alloc_init("nfs_request", LCK_GRP_ATTR_NULL
);
309 nfs_request_mutex
= lck_mtx_alloc_init(nfs_request_grp
, LCK_ATTR_NULL
);
311 /* initialize NFS request list */
312 TAILQ_INIT(&nfs_reqq
);
314 nfs_nbinit(); /* Init the nfsbuf table */
315 nfs_nhinit(); /* Init the nfsnode table */
316 nfs_lockinit(); /* Init the nfs lock state */
317 nfs_gss_init(); /* Init RPCSEC_GSS security */
320 NFS4_PER_FS_ATTRIBUTES(nfs_fs_attr_bitmap
);
321 NFS4_PER_OBJECT_ATTRIBUTES(nfs_object_attr_bitmap
);
322 NFS4_DEFAULT_ATTRIBUTES(nfs_getattr_bitmap
);
323 for (i
=0; i
< NFS_ATTR_BITMAP_LEN
; i
++)
324 nfs_getattr_bitmap
[i
] &= nfs_object_attr_bitmap
[i
];
325 TAILQ_INIT(&nfsclientids
);
327 /* initialize NFS timer callouts */
328 nfs_request_timer_call
= thread_call_allocate(nfs_request_timer
, NULL
);
329 nfs_buf_timer_call
= thread_call_allocate(nfs_buf_timer
, NULL
);
330 nfs4_callback_timer_call
= thread_call_allocate(nfs4_callback_timer
, NULL
);
339 nfs3_update_statfs(struct nfsmount
*nmp
, vfs_context_t ctx
)
342 int error
= 0, lockerror
, status
, nfsvers
;
344 struct nfsm_chain nmreq
, nmrep
;
347 nfsvers
= nmp
->nm_vers
;
351 if ((error
= vnode_get(NFSTOV(np
))))
354 nfsm_chain_null(&nmreq
);
355 nfsm_chain_null(&nmrep
);
357 nfsm_chain_build_alloc_init(error
, &nmreq
, NFSX_FH(nfsvers
));
358 nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, np
->n_fhp
, np
->n_fhsize
);
359 nfsm_chain_build_done(error
, &nmreq
);
361 error
= nfs_request(np
, NULL
, &nmreq
, NFSPROC_FSSTAT
, ctx
,
362 &nmrep
, &xid
, &status
);
363 if ((lockerror
= nfs_node_lock(np
)))
365 if (nfsvers
== NFS_VER3
)
366 nfsm_chain_postop_attr_update(error
, &nmrep
, np
, &xid
);
371 nfsm_assert(error
, NFSTONMP(np
), ENXIO
);
373 lck_mtx_lock(&nmp
->nm_lock
);
374 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_TOTAL
);
375 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_FREE
);
376 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_AVAIL
);
377 if (nfsvers
== NFS_VER3
) {
378 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_FILES_AVAIL
);
379 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_FILES_TOTAL
);
380 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_FILES_FREE
);
381 nmp
->nm_fsattr
.nfsa_bsize
= NFS_FABLKSIZE
;
382 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_space_total
);
383 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_space_free
);
384 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_space_avail
);
385 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_files_total
);
386 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_files_free
);
387 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_files_avail
);
390 nfsm_chain_adv(error
, &nmrep
, NFSX_UNSIGNED
); // skip tsize?
391 nfsm_chain_get_32(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_bsize
);
392 nfsm_chain_get_32(error
, &nmrep
, val
);
394 if (nmp
->nm_fsattr
.nfsa_bsize
<= 0)
395 nmp
->nm_fsattr
.nfsa_bsize
= NFS_FABLKSIZE
;
396 nmp
->nm_fsattr
.nfsa_space_total
= (uint64_t)val
* nmp
->nm_fsattr
.nfsa_bsize
;
397 nfsm_chain_get_32(error
, &nmrep
, val
);
399 nmp
->nm_fsattr
.nfsa_space_free
= (uint64_t)val
* nmp
->nm_fsattr
.nfsa_bsize
;
400 nfsm_chain_get_32(error
, &nmrep
, val
);
402 nmp
->nm_fsattr
.nfsa_space_avail
= (uint64_t)val
* nmp
->nm_fsattr
.nfsa_bsize
;
404 lck_mtx_unlock(&nmp
->nm_lock
);
406 nfsm_chain_cleanup(&nmreq
);
407 nfsm_chain_cleanup(&nmrep
);
408 vnode_put(NFSTOV(np
));
413 nfs4_update_statfs(struct nfsmount
*nmp
, vfs_context_t ctx
)
416 int error
= 0, lockerror
, status
, nfsvers
, numops
;
418 struct nfsm_chain nmreq
, nmrep
;
419 uint32_t bitmap
[NFS_ATTR_BITMAP_LEN
];
420 struct nfs_vattr nvattr
;
422 nfsvers
= nmp
->nm_vers
;
426 if ((error
= vnode_get(NFSTOV(np
))))
429 nfsm_chain_null(&nmreq
);
430 nfsm_chain_null(&nmrep
);
434 nfsm_chain_build_alloc_init(error
, &nmreq
, 15 * NFSX_UNSIGNED
);
435 nfsm_chain_add_compound_header(error
, &nmreq
, "statfs", numops
);
437 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
438 nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, np
->n_fhp
, np
->n_fhsize
);
440 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
441 NFS_COPY_ATTRIBUTES(nfs_getattr_bitmap
, bitmap
);
442 NFS4_STATFS_ATTRIBUTES(bitmap
);
443 nfsm_chain_add_bitmap_masked(error
, &nmreq
, bitmap
,
444 NFS_ATTR_BITMAP_LEN
, nmp
->nm_fsattr
.nfsa_supp_attr
);
445 nfsm_chain_build_done(error
, &nmreq
);
446 nfsm_assert(error
, (numops
== 0), EPROTO
);
448 error
= nfs_request(np
, NULL
, &nmreq
, NFSPROC4_COMPOUND
, ctx
, &nmrep
, &xid
, &status
);
449 nfsm_chain_skip_tag(error
, &nmrep
);
450 nfsm_chain_get_32(error
, &nmrep
, numops
);
451 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
452 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
453 nfsm_assert(error
, NFSTONMP(np
), ENXIO
);
455 lck_mtx_lock(&nmp
->nm_lock
);
456 NFS_CLEAR_ATTRIBUTES(nvattr
.nva_bitmap
);
457 error
= nfs4_parsefattr(&nmrep
, &nmp
->nm_fsattr
, &nvattr
, NULL
, NULL
);
458 lck_mtx_unlock(&nmp
->nm_lock
);
460 if ((lockerror
= nfs_node_lock(np
)))
463 nfs_loadattrcache(np
, &nvattr
, &xid
, 0);
466 nfsm_assert(error
, NFSTONMP(np
), ENXIO
);
468 nmp
->nm_fsattr
.nfsa_bsize
= NFS_FABLKSIZE
;
470 nfsm_chain_cleanup(&nmreq
);
471 nfsm_chain_cleanup(&nmrep
);
472 vnode_put(NFSTOV(np
));
478 * The NFS VFS_GETATTR function: "statfs"-type information is retrieved
479 * using the nf_update_statfs() function, and other attributes are cobbled
480 * together from whatever sources we can (getattr, fsinfo, pathconf).
483 nfs_vfs_getattr(mount_t mp
, struct vfs_attr
*fsap
, vfs_context_t ctx
)
485 struct nfsmount
*nmp
;
487 int error
= 0, nfsvers
;
489 if (!(nmp
= VFSTONFS(mp
)))
491 nfsvers
= nmp
->nm_vers
;
493 if (VFSATTR_IS_ACTIVE(fsap
, f_bsize
) ||
494 VFSATTR_IS_ACTIVE(fsap
, f_iosize
) ||
495 VFSATTR_IS_ACTIVE(fsap
, f_blocks
) ||
496 VFSATTR_IS_ACTIVE(fsap
, f_bfree
) ||
497 VFSATTR_IS_ACTIVE(fsap
, f_bavail
) ||
498 VFSATTR_IS_ACTIVE(fsap
, f_bused
) ||
499 VFSATTR_IS_ACTIVE(fsap
, f_files
) ||
500 VFSATTR_IS_ACTIVE(fsap
, f_ffree
)) {
501 int statfsrate
= nfs_statfs_rate_limit
;
505 * Are we rate-limiting statfs RPCs?
506 * (Treat values less than 1 or greater than 1,000,000 as no limit.)
508 if ((statfsrate
> 0) && (statfsrate
< 1000000)) {
513 lck_mtx_lock(&nmp
->nm_lock
);
514 stamp
= (now
.tv_sec
* statfsrate
) + (now
.tv_usec
/ (1000000/statfsrate
));
515 if (stamp
!= nmp
->nm_fsattrstamp
) {
517 nmp
->nm_fsattrstamp
= stamp
;
521 lck_mtx_unlock(&nmp
->nm_lock
);
525 error
= nmp
->nm_funcs
->nf_update_statfs(nmp
, ctx
);
526 if ((error
== ESTALE
) || (error
== ETIMEDOUT
))
531 lck_mtx_lock(&nmp
->nm_lock
);
532 VFSATTR_RETURN(fsap
, f_iosize
, nfs_iosize
);
533 VFSATTR_RETURN(fsap
, f_bsize
, nmp
->nm_fsattr
.nfsa_bsize
);
534 bsize
= nmp
->nm_fsattr
.nfsa_bsize
;
535 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_TOTAL
))
536 VFSATTR_RETURN(fsap
, f_blocks
, nmp
->nm_fsattr
.nfsa_space_total
/ bsize
);
537 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_FREE
))
538 VFSATTR_RETURN(fsap
, f_bfree
, nmp
->nm_fsattr
.nfsa_space_free
/ bsize
);
539 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_AVAIL
))
540 VFSATTR_RETURN(fsap
, f_bavail
, nmp
->nm_fsattr
.nfsa_space_avail
/ bsize
);
541 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_TOTAL
) &&
542 NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SPACE_FREE
))
543 VFSATTR_RETURN(fsap
, f_bused
,
544 (nmp
->nm_fsattr
.nfsa_space_total
/ bsize
) -
545 (nmp
->nm_fsattr
.nfsa_space_free
/ bsize
));
546 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_FILES_TOTAL
))
547 VFSATTR_RETURN(fsap
, f_files
, nmp
->nm_fsattr
.nfsa_files_total
);
548 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_FILES_FREE
))
549 VFSATTR_RETURN(fsap
, f_ffree
, nmp
->nm_fsattr
.nfsa_files_free
);
550 lck_mtx_unlock(&nmp
->nm_lock
);
553 if (VFSATTR_IS_ACTIVE(fsap
, f_capabilities
)) {
554 u_int32_t caps
, valid
;
555 nfsnode_t np
= nmp
->nm_dnp
;
557 nfsm_assert(error
, VFSTONFS(mp
) && np
, ENXIO
);
560 lck_mtx_lock(&nmp
->nm_lock
);
563 * The capabilities[] array defines what this volume supports.
565 * The valid[] array defines which bits this code understands
566 * the meaning of (whether the volume has that capability or not).
567 * Any zero bits here means "I don't know what you're asking about"
568 * and the caller cannot tell whether that capability is
572 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SYMLINK_SUPPORT
)) {
573 valid
|= VOL_CAP_FMT_SYMBOLICLINKS
;
574 if (nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_SYMLINK
)
575 caps
|= VOL_CAP_FMT_SYMBOLICLINKS
;
577 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_LINK_SUPPORT
)) {
578 valid
|= VOL_CAP_FMT_HARDLINKS
;
579 if (nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_LINK
)
580 caps
|= VOL_CAP_FMT_HARDLINKS
;
582 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_CASE_INSENSITIVE
)) {
583 valid
|= VOL_CAP_FMT_CASE_SENSITIVE
;
584 if (!(nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_CASE_INSENSITIVE
))
585 caps
|= VOL_CAP_FMT_CASE_SENSITIVE
;
587 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_CASE_PRESERVING
)) {
588 valid
|= VOL_CAP_FMT_CASE_PRESERVING
;
589 if (nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_CASE_PRESERVING
)
590 caps
|= VOL_CAP_FMT_CASE_PRESERVING
;
592 /* Note: VOL_CAP_FMT_2TB_FILESIZE is actually used to test for "large file support" */
593 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXFILESIZE
)) {
594 /* Is server's max file size at least 4GB? */
595 if (nmp
->nm_fsattr
.nfsa_maxfilesize
>= 0x100000000ULL
)
596 caps
|= VOL_CAP_FMT_2TB_FILESIZE
;
597 } else if (nfsvers
>= NFS_VER3
) {
599 * NFSv3 and up supports 64 bits of file size.
600 * So, we'll just assume maxfilesize >= 4GB
602 caps
|= VOL_CAP_FMT_2TB_FILESIZE
;
604 if (nfsvers
>= NFS_VER4
) {
605 caps
|= VOL_CAP_FMT_HIDDEN_FILES
;
606 valid
|= VOL_CAP_FMT_HIDDEN_FILES
;
607 // VOL_CAP_FMT_OPENDENYMODES
609 fsap
->f_capabilities
.capabilities
[VOL_CAPABILITIES_FORMAT
] =
610 // VOL_CAP_FMT_PERSISTENTOBJECTIDS |
611 // VOL_CAP_FMT_SYMBOLICLINKS |
612 // VOL_CAP_FMT_HARDLINKS |
613 // VOL_CAP_FMT_JOURNAL |
614 // VOL_CAP_FMT_JOURNAL_ACTIVE |
615 // VOL_CAP_FMT_NO_ROOT_TIMES |
616 // VOL_CAP_FMT_SPARSE_FILES |
617 // VOL_CAP_FMT_ZERO_RUNS |
618 // VOL_CAP_FMT_CASE_SENSITIVE |
619 // VOL_CAP_FMT_CASE_PRESERVING |
620 // VOL_CAP_FMT_FAST_STATFS |
621 // VOL_CAP_FMT_2TB_FILESIZE |
622 // VOL_CAP_FMT_OPENDENYMODES |
623 // VOL_CAP_FMT_HIDDEN_FILES |
625 fsap
->f_capabilities
.valid
[VOL_CAPABILITIES_FORMAT
] =
626 VOL_CAP_FMT_PERSISTENTOBJECTIDS
|
627 // VOL_CAP_FMT_SYMBOLICLINKS |
628 // VOL_CAP_FMT_HARDLINKS |
629 // VOL_CAP_FMT_JOURNAL |
630 // VOL_CAP_FMT_JOURNAL_ACTIVE |
631 // VOL_CAP_FMT_NO_ROOT_TIMES |
632 // VOL_CAP_FMT_SPARSE_FILES |
633 // VOL_CAP_FMT_ZERO_RUNS |
634 // VOL_CAP_FMT_CASE_SENSITIVE |
635 // VOL_CAP_FMT_CASE_PRESERVING |
636 VOL_CAP_FMT_FAST_STATFS
|
637 VOL_CAP_FMT_2TB_FILESIZE
|
638 // VOL_CAP_FMT_OPENDENYMODES |
639 // VOL_CAP_FMT_HIDDEN_FILES |
643 * We don't support most of the interfaces.
645 * We MAY support locking, but we don't have any easy way of probing.
646 * We can tell if there's no lockd running or if locks have been
647 * disabled for a mount, so we can definitely answer NO in that case.
648 * Any attempt to send a request to lockd to test for locking support
649 * may cause the lazily-launched locking daemons to be started
650 * unnecessarily. So we avoid that. However, we do record if we ever
651 * successfully perform a lock operation on a mount point, so if it
652 * looks like lock ops have worked, we do report that we support them.
655 if (nfsvers
>= NFS_VER4
) {
656 caps
= VOL_CAP_INT_ADVLOCK
| VOL_CAP_INT_FLOCK
;
657 valid
= VOL_CAP_INT_ADVLOCK
| VOL_CAP_INT_FLOCK
;
658 // VOL_CAP_INT_EXTENDED_SECURITY
659 // VOL_CAP_INT_NAMEDSTREAMS
660 // VOL_CAP_INT_EXTENDED_ATTR
661 } else if ((nmp
->nm_flag
& NFSMNT_NOLOCKS
)) {
662 /* locks disabled on this mount, so they definitely won't work */
663 valid
= VOL_CAP_INT_ADVLOCK
| VOL_CAP_INT_FLOCK
;
664 } else if (nmp
->nm_state
& NFSSTA_LOCKSWORK
) {
665 caps
= VOL_CAP_INT_ADVLOCK
| VOL_CAP_INT_FLOCK
;
666 valid
= VOL_CAP_INT_ADVLOCK
| VOL_CAP_INT_FLOCK
;
668 fsap
->f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] =
669 // VOL_CAP_INT_SEARCHFS |
670 // VOL_CAP_INT_ATTRLIST |
671 // VOL_CAP_INT_NFSEXPORT |
672 // VOL_CAP_INT_READDIRATTR |
673 // VOL_CAP_INT_EXCHANGEDATA |
674 // VOL_CAP_INT_COPYFILE |
675 // VOL_CAP_INT_ALLOCATE |
676 // VOL_CAP_INT_VOL_RENAME |
677 // VOL_CAP_INT_ADVLOCK |
678 // VOL_CAP_INT_FLOCK |
679 // VOL_CAP_INT_EXTENDED_SECURITY |
680 // VOL_CAP_INT_USERACCESS |
681 // VOL_CAP_INT_MANLOCK |
682 // VOL_CAP_INT_NAMEDSTREAMS |
683 // VOL_CAP_INT_EXTENDED_ATTR |
685 fsap
->f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] =
686 VOL_CAP_INT_SEARCHFS
|
687 VOL_CAP_INT_ATTRLIST
|
688 VOL_CAP_INT_NFSEXPORT
|
689 VOL_CAP_INT_READDIRATTR
|
690 VOL_CAP_INT_EXCHANGEDATA
|
691 VOL_CAP_INT_COPYFILE
|
692 VOL_CAP_INT_ALLOCATE
|
693 VOL_CAP_INT_VOL_RENAME
|
694 // VOL_CAP_INT_ADVLOCK |
695 // VOL_CAP_INT_FLOCK |
696 // VOL_CAP_INT_EXTENDED_SECURITY |
697 // VOL_CAP_INT_USERACCESS |
698 // VOL_CAP_INT_MANLOCK |
699 // VOL_CAP_INT_NAMEDSTREAMS |
700 // VOL_CAP_INT_EXTENDED_ATTR |
703 fsap
->f_capabilities
.capabilities
[VOL_CAPABILITIES_RESERVED1
] = 0;
704 fsap
->f_capabilities
.valid
[VOL_CAPABILITIES_RESERVED1
] = 0;
706 fsap
->f_capabilities
.capabilities
[VOL_CAPABILITIES_RESERVED2
] = 0;
707 fsap
->f_capabilities
.valid
[VOL_CAPABILITIES_RESERVED2
] = 0;
709 VFSATTR_SET_SUPPORTED(fsap
, f_capabilities
);
710 lck_mtx_unlock(&nmp
->nm_lock
);
713 if (VFSATTR_IS_ACTIVE(fsap
, f_attributes
)) {
714 fsap
->f_attributes
.validattr
.commonattr
= 0;
715 fsap
->f_attributes
.validattr
.volattr
=
716 ATTR_VOL_CAPABILITIES
| ATTR_VOL_ATTRIBUTES
;
717 fsap
->f_attributes
.validattr
.dirattr
= 0;
718 fsap
->f_attributes
.validattr
.fileattr
= 0;
719 fsap
->f_attributes
.validattr
.forkattr
= 0;
721 fsap
->f_attributes
.nativeattr
.commonattr
= 0;
722 fsap
->f_attributes
.nativeattr
.volattr
=
723 ATTR_VOL_CAPABILITIES
| ATTR_VOL_ATTRIBUTES
;
724 fsap
->f_attributes
.nativeattr
.dirattr
= 0;
725 fsap
->f_attributes
.nativeattr
.fileattr
= 0;
726 fsap
->f_attributes
.nativeattr
.forkattr
= 0;
728 VFSATTR_SET_SUPPORTED(fsap
, f_attributes
);
735 * nfs version 3 fsinfo rpc call
738 nfs3_fsinfo(struct nfsmount
*nmp
, nfsnode_t np
, vfs_context_t ctx
)
740 int error
= 0, lockerror
, status
, nmlocked
= 0;
742 uint32_t val
, prefsize
, maxsize
;
743 struct nfsm_chain nmreq
, nmrep
;
745 nfsm_chain_null(&nmreq
);
746 nfsm_chain_null(&nmrep
);
748 nfsm_chain_build_alloc_init(error
, &nmreq
, NFSX_FH(nmp
->nm_vers
));
749 nfsm_chain_add_fh(error
, &nmreq
, nmp
->nm_vers
, np
->n_fhp
, np
->n_fhsize
);
750 nfsm_chain_build_done(error
, &nmreq
);
752 error
= nfs_request(np
, NULL
, &nmreq
, NFSPROC_FSINFO
, ctx
,
753 &nmrep
, &xid
, &status
);
754 if ((lockerror
= nfs_node_lock(np
)))
756 nfsm_chain_postop_attr_update(error
, &nmrep
, np
, &xid
);
763 lck_mtx_lock(&nmp
->nm_lock
);
766 nfsm_chain_get_32(error
, &nmrep
, maxsize
);
767 nfsm_chain_get_32(error
, &nmrep
, prefsize
);
769 nmp
->nm_fsattr
.nfsa_maxread
= maxsize
;
770 if (prefsize
< nmp
->nm_rsize
)
771 nmp
->nm_rsize
= (prefsize
+ NFS_FABLKSIZE
- 1) &
772 ~(NFS_FABLKSIZE
- 1);
773 if (maxsize
< nmp
->nm_rsize
) {
774 nmp
->nm_rsize
= maxsize
& ~(NFS_FABLKSIZE
- 1);
775 if (nmp
->nm_rsize
== 0)
776 nmp
->nm_rsize
= maxsize
;
778 nfsm_chain_adv(error
, &nmrep
, NFSX_UNSIGNED
); // skip rtmult
780 nfsm_chain_get_32(error
, &nmrep
, maxsize
);
781 nfsm_chain_get_32(error
, &nmrep
, prefsize
);
783 nmp
->nm_fsattr
.nfsa_maxwrite
= maxsize
;
784 if (prefsize
< nmp
->nm_wsize
)
785 nmp
->nm_wsize
= (prefsize
+ NFS_FABLKSIZE
- 1) &
786 ~(NFS_FABLKSIZE
- 1);
787 if (maxsize
< nmp
->nm_wsize
) {
788 nmp
->nm_wsize
= maxsize
& ~(NFS_FABLKSIZE
- 1);
789 if (nmp
->nm_wsize
== 0)
790 nmp
->nm_wsize
= maxsize
;
792 nfsm_chain_adv(error
, &nmrep
, NFSX_UNSIGNED
); // skip wtmult
794 nfsm_chain_get_32(error
, &nmrep
, prefsize
);
796 if (prefsize
< nmp
->nm_readdirsize
)
797 nmp
->nm_readdirsize
= prefsize
;
798 if (maxsize
< nmp
->nm_readdirsize
)
799 nmp
->nm_readdirsize
= maxsize
;
801 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_fsattr
.nfsa_maxfilesize
);
803 nfsm_chain_adv(error
, &nmrep
, 2 * NFSX_UNSIGNED
); // skip time_delta
805 /* convert FS properties to our own flags */
806 nfsm_chain_get_32(error
, &nmrep
, val
);
808 if (val
& NFSV3FSINFO_LINK
)
809 nmp
->nm_fsattr
.nfsa_flags
|= NFS_FSFLAG_LINK
;
810 if (val
& NFSV3FSINFO_SYMLINK
)
811 nmp
->nm_fsattr
.nfsa_flags
|= NFS_FSFLAG_SYMLINK
;
812 if (val
& NFSV3FSINFO_HOMOGENEOUS
)
813 nmp
->nm_fsattr
.nfsa_flags
|= NFS_FSFLAG_HOMOGENEOUS
;
814 if (val
& NFSV3FSINFO_CANSETTIME
)
815 nmp
->nm_fsattr
.nfsa_flags
|= NFS_FSFLAG_SET_TIME
;
816 nmp
->nm_state
|= NFSSTA_GOTFSINFO
;
817 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXREAD
);
818 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXWRITE
);
819 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXFILESIZE
);
820 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_LINK_SUPPORT
);
821 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_SYMLINK_SUPPORT
);
822 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_HOMOGENEOUS
);
823 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_CANSETTIME
);
826 lck_mtx_unlock(&nmp
->nm_lock
);
827 nfsm_chain_cleanup(&nmreq
);
828 nfsm_chain_cleanup(&nmrep
);
833 * Mount a remote root fs via. nfs. This depends on the info in the
834 * nfs_diskless structure that has been filled in properly by some primary
836 * It goes something like this:
837 * - do enough of "ifconfig" by calling ifioctl() so that the system
838 * can talk to the server
839 * - If nfs_diskless.mygateway is filled in, use that address as
841 * - hand craft the swap nfs vnode hanging off a fake mount point
842 * if swdevt[0].sw_dev == NODEV
843 * - build the rootfs mount point and call mountnfs() to do the rest.
848 struct nfs_diskless nd
;
849 struct nfs_vattr nvattr
;
854 #if !defined(NO_MOUNT_PRIVATE)
855 mount_t mppriv
= NULL
;
856 vnode_t vppriv
= NULL
;
857 #endif /* NO_MOUNT_PRIVATE */
861 * Call nfs_boot_init() to fill in the nfs_diskless struct.
862 * Note: networking must already have been configured before
865 bzero((caddr_t
) &nd
, sizeof(nd
));
866 error
= nfs_boot_init(&nd
);
868 panic("nfs_boot_init failed with %d\n", error
);
872 * Try NFSv3 first, then fallback to NFSv2.
873 * Likewise, try TCP first, then fall back to UDP.
876 sotype
= SOCK_STREAM
;
879 error
= nfs_boot_getfh(&nd
, v3
, sotype
);
881 if (error
== EHOSTDOWN
|| error
== EHOSTUNREACH
) {
882 if (nd
.nd_root
.ndm_mntfrom
)
883 FREE_ZONE(nd
.nd_root
.ndm_mntfrom
,
884 MAXPATHLEN
, M_NAMEI
);
885 if (nd
.nd_root
.ndm_path
)
886 FREE_ZONE(nd
.nd_root
.ndm_path
,
887 MAXPATHLEN
, M_NAMEI
);
888 if (nd
.nd_private
.ndm_mntfrom
)
889 FREE_ZONE(nd
.nd_private
.ndm_mntfrom
,
890 MAXPATHLEN
, M_NAMEI
);
891 if (nd
.nd_private
.ndm_path
)
892 FREE_ZONE(nd
.nd_private
.ndm_path
,
893 MAXPATHLEN
, M_NAMEI
);
897 if (sotype
== SOCK_STREAM
) {
898 printf("nfs_boot_getfh(v3,TCP) failed with %d, trying UDP...\n", error
);
902 printf("nfs_boot_getfh(v3,UDP) failed with %d, trying v2...\n", error
);
904 sotype
= SOCK_STREAM
;
906 } else if (sotype
== SOCK_STREAM
) {
907 printf("nfs_boot_getfh(v2,TCP) failed with %d, trying UDP...\n", error
);
913 panic("nfs_boot_getfh(v2,UDP) failed: NFS server mountd not responding - check server configuration: %s", PE_boot_args());
916 panic("nfs_boot_getfh(v2,UDP) failed: NFS server refused mount - check server configuration: %s", PE_boot_args());
918 panic("nfs_boot_getfh(v2,UDP) failed with %d: %s", error
, PE_boot_args());
922 ctx
= vfs_context_kernel();
925 * Create the root mount point.
927 #if !defined(NO_MOUNT_PRIVATE)
929 //PWC hack until we have a real "mount" tool to remount root rw
931 int flags
= MNT_ROOTFS
|MNT_RDONLY
;
932 PE_parse_boot_argn("-rwroot_hack", &rw_root
, sizeof (rw_root
));
936 kprintf("-rwroot_hack in effect: mounting root fs read/write\n");
939 if ((error
= nfs_mount_diskless(&nd
.nd_root
, "/", flags
, &vp
, &mp
, ctx
)))
941 if ((error
= nfs_mount_diskless(&nd
.nd_root
, "/", MNT_ROOTFS
, &vp
, &mp
, ctx
)))
942 #endif /* NO_MOUNT_PRIVATE */
945 if (sotype
== SOCK_STREAM
) {
946 printf("nfs_mount_diskless(v3,TCP) failed with %d, trying UDP...\n", error
);
950 printf("nfs_mount_diskless(v3,UDP) failed with %d, trying v2...\n", error
);
952 sotype
= SOCK_STREAM
;
954 } else if (sotype
== SOCK_STREAM
) {
955 printf("nfs_mount_diskless(v2,TCP) failed with %d, trying UDP...\n", error
);
959 panic("nfs_mount_diskless(v2,UDP) root failed with %d: %s\n", error
, PE_boot_args());
962 printf("root on %s\n", nd
.nd_root
.ndm_mntfrom
);
968 #if !defined(NO_MOUNT_PRIVATE)
969 if (nd
.nd_private
.ndm_saddr
.sin_addr
.s_addr
) {
970 error
= nfs_mount_diskless_private(&nd
.nd_private
, "/private",
971 0, &vppriv
, &mppriv
, ctx
);
973 panic("nfs_mount_diskless private failed with %d\n", error
);
975 printf("private on %s\n", nd
.nd_private
.ndm_mntfrom
);
978 mount_list_add(mppriv
);
981 #endif /* NO_MOUNT_PRIVATE */
983 if (nd
.nd_root
.ndm_mntfrom
)
984 FREE_ZONE(nd
.nd_root
.ndm_mntfrom
, MAXPATHLEN
, M_NAMEI
);
985 if (nd
.nd_root
.ndm_path
)
986 FREE_ZONE(nd
.nd_root
.ndm_path
, MAXPATHLEN
, M_NAMEI
);
987 if (nd
.nd_private
.ndm_mntfrom
)
988 FREE_ZONE(nd
.nd_private
.ndm_mntfrom
, MAXPATHLEN
, M_NAMEI
);
989 if (nd
.nd_private
.ndm_path
)
990 FREE_ZONE(nd
.nd_private
.ndm_path
, MAXPATHLEN
, M_NAMEI
);
992 /* Get root attributes (for the time). */
993 error
= nfs_getattr(VTONFS(vp
), &nvattr
, ctx
, NGA_UNCACHED
);
994 if (error
) panic("nfs_mountroot: getattr for root");
999 * Internal version of mount system call for diskless setup.
1003 struct nfs_dlmount
*ndmntp
,
1004 const char *mntname
,
1010 struct user_nfs_args args
;
1015 if ((error
= vfs_rootmountalloc("nfs", ndmntp
->ndm_mntfrom
, &mp
))) {
1016 printf("nfs_mount_diskless: NFS not configured");
1020 mp
->mnt_flag
|= mntflag
;
1021 if (!(mntflag
& MNT_RDONLY
))
1022 mp
->mnt_flag
&= ~MNT_RDONLY
;
1024 /* Initialize mount args. */
1025 bzero((caddr_t
) &args
, sizeof(args
));
1026 args
.addr
= CAST_USER_ADDR_T(&ndmntp
->ndm_saddr
);
1027 args
.addrlen
= ndmntp
->ndm_saddr
.sin_len
;
1028 args
.sotype
= ndmntp
->ndm_sotype
;
1029 args
.fh
= CAST_USER_ADDR_T(&ndmntp
->ndm_fh
[0]);
1030 args
.fhsize
= ndmntp
->ndm_fhlen
;
1031 args
.hostname
= CAST_USER_ADDR_T(ndmntp
->ndm_mntfrom
);
1032 args
.flags
= NFSMNT_RESVPORT
;
1033 if (ndmntp
->ndm_nfsv3
)
1034 args
.flags
|= NFSMNT_NFSV3
;
1036 error
= mbuf_get(MBUF_WAITOK
, MBUF_TYPE_SONAME
, &m
);
1038 printf("nfs_mount_diskless: mbuf_get(soname) failed");
1041 mbuf_setlen(m
, ndmntp
->ndm_saddr
.sin_len
);
1042 bcopy(&ndmntp
->ndm_saddr
, mbuf_data(m
), ndmntp
->ndm_saddr
.sin_len
);
1043 if ((error
= mountnfs(&args
, mp
, m
, ctx
, vpp
))) {
1044 printf("nfs_mountroot: mount %s failed: %d\n", mntname
, error
);
1045 // XXX vfs_rootmountfailed(mp);
1047 mp
->mnt_vtable
->vfc_refcount
--;
1048 mount_list_unlock();
1050 mount_lock_destroy(mp
);
1052 mac_mount_label_destroy(mp
);
1054 FREE_ZONE(mp
, sizeof(struct mount
), M_MOUNT
);
1061 #if !defined(NO_MOUNT_PRIVATE)
1063 * Internal version of mount system call to mount "/private"
1064 * separately in diskless setup
1067 nfs_mount_diskless_private(
1068 struct nfs_dlmount
*ndmntp
,
1069 const char *mntname
,
1075 struct user_nfs_args args
;
1080 struct vfstable
*vfsp
;
1081 struct nameidata nd
;
1084 procp
= current_proc(); /* XXX */
1088 * mimic main()!. Temporarily set up rootvnode and other stuff so
1089 * that namei works. Need to undo this because main() does it, too
1091 struct filedesc
*fdp
; /* pointer to file descriptor state */
1093 mountlist
.tqh_first
->mnt_flag
|= MNT_ROOTFS
;
1095 /* Get the vnode for '/'. Set fdp->fd_cdir to reference it. */
1096 if (VFS_ROOT(mountlist
.tqh_first
, &rootvnode
, NULL
))
1097 panic("cannot find root vnode");
1098 error
= vnode_ref(rootvnode
);
1100 printf("nfs_mountroot: vnode_ref() failed on root vnode!\n");
1103 fdp
->fd_cdir
= rootvnode
;
1104 fdp
->fd_rdir
= NULL
;
1108 * Get vnode to be covered
1110 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_SYSSPACE
,
1111 CAST_USER_ADDR_T(mntname
), ctx
);
1112 if ((error
= namei(&nd
))) {
1113 printf("nfs_mountroot: private namei failed!\n");
1117 /* undo vnode_ref() in mimic main()! */
1118 vnode_rele(rootvnode
);
1123 if ((error
= VNOP_FSYNC(vp
, MNT_WAIT
, ctx
)) ||
1124 (error
= buf_invalidateblks(vp
, BUF_WRITE_DATA
, 0, 0))) {
1128 if (vnode_vtype(vp
) != VDIR
) {
1133 for (vfsp
= vfsconf
; vfsp
; vfsp
= vfsp
->vfc_next
)
1134 if (!strncmp(vfsp
->vfc_name
, "nfs", sizeof(vfsp
->vfc_name
)))
1137 printf("nfs_mountroot: private NFS not configured\n");
1142 if (vnode_mountedhere(vp
) != NULL
) {
1149 * Allocate and initialize the filesystem.
1151 mp
= _MALLOC_ZONE((u_int32_t
)sizeof(struct mount
), M_MOUNT
, M_WAITOK
);
1153 printf("nfs_mountroot: unable to allocate mount structure\n");
1158 bzero((char *)mp
, sizeof(struct mount
));
1160 /* Initialize the default IO constraints */
1161 mp
->mnt_maxreadcnt
= mp
->mnt_maxwritecnt
= MAXPHYS
;
1162 mp
->mnt_segreadcnt
= mp
->mnt_segwritecnt
= 32;
1163 mp
->mnt_ioflags
= 0;
1164 mp
->mnt_realrootvp
= NULLVP
;
1165 mp
->mnt_authcache_ttl
= CACHED_LOOKUP_RIGHT_TTL
;
1167 mount_lock_init(mp
);
1168 TAILQ_INIT(&mp
->mnt_vnodelist
);
1169 TAILQ_INIT(&mp
->mnt_workerqueue
);
1170 TAILQ_INIT(&mp
->mnt_newvnodes
);
1171 (void)vfs_busy(mp
, LK_NOWAIT
);
1172 TAILQ_INIT(&mp
->mnt_vnodelist
);
1174 vfsp
->vfc_refcount
++;
1175 mount_list_unlock();
1176 mp
->mnt_vtable
= vfsp
;
1177 mp
->mnt_op
= vfsp
->vfc_vfsops
;
1178 // mp->mnt_stat.f_type = vfsp->vfc_typenum;
1179 mp
->mnt_flag
= mntflag
;
1180 mp
->mnt_flag
|= vfsp
->vfc_flags
& MNT_VISFLAGMASK
;
1181 strncpy(mp
->mnt_vfsstat
.f_fstypename
, vfsp
->vfc_name
, MFSNAMELEN
-1);
1182 vp
->v_mountedhere
= mp
;
1183 mp
->mnt_vnodecovered
= vp
;
1184 mp
->mnt_vfsstat
.f_owner
= kauth_cred_getuid(kauth_cred_get());
1185 (void) copystr(mntname
, mp
->mnt_vfsstat
.f_mntonname
, MAXPATHLEN
- 1, 0);
1186 (void) copystr(ndmntp
->ndm_mntfrom
, mp
->mnt_vfsstat
.f_mntfromname
, MAXPATHLEN
- 1, 0);
1188 mac_mount_label_init(mp
);
1189 mac_mount_label_associate(ctx
, mp
);
1192 /* Initialize mount args. */
1193 bzero((caddr_t
) &args
, sizeof(args
));
1194 args
.addr
= CAST_USER_ADDR_T(&ndmntp
->ndm_saddr
);
1195 args
.addrlen
= ndmntp
->ndm_saddr
.sin_len
;
1196 args
.sotype
= ndmntp
->ndm_sotype
;
1197 args
.fh
= CAST_USER_ADDR_T(ndmntp
->ndm_fh
);
1198 args
.fhsize
= ndmntp
->ndm_fhlen
;
1199 args
.hostname
= CAST_USER_ADDR_T(ndmntp
->ndm_mntfrom
);
1200 args
.flags
= NFSMNT_RESVPORT
;
1201 if (ndmntp
->ndm_nfsv3
)
1202 args
.flags
|= NFSMNT_NFSV3
;
1204 error
= mbuf_get(MBUF_WAITOK
, MBUF_TYPE_SONAME
, &m
);
1206 printf("nfs_mount_diskless_private: mbuf_get(soname) failed");
1209 mbuf_setlen(m
, ndmntp
->ndm_saddr
.sin_len
);
1210 bcopy(&ndmntp
->ndm_saddr
, mbuf_data(m
), ndmntp
->ndm_saddr
.sin_len
);
1211 if ((error
= mountnfs(&args
, mp
, m
, ctx
, &vp
))) {
1212 printf("nfs_mountroot: mount %s failed: %d\n", mntname
, error
);
1214 vfsp
->vfc_refcount
--;
1215 mount_list_unlock();
1217 mount_lock_destroy(mp
);
1219 mac_mount_label_destroy(mp
);
1221 FREE_ZONE(mp
, sizeof (struct mount
), M_MOUNT
);
1230 #endif /* NO_MOUNT_PRIVATE */
1238 nfs_vfs_mount(mount_t mp
, vnode_t vp
, user_addr_t data
, vfs_context_t ctx
)
1240 int error
, argsvers
;
1241 struct user_nfs_args args
;
1242 struct nfs_args tempargs
;
1245 u_char nfh
[NFSX_V3FHMAX
];
1248 error
= copyin(data
, (caddr_t
)&argsvers
, sizeof (argsvers
));
1254 if (vfs_context_is64bit(ctx
))
1255 error
= copyin(data
, (caddr_t
)&args
, sizeof (struct user_nfs_args3
));
1257 error
= copyin(data
, (caddr_t
)&tempargs
, sizeof (struct nfs_args3
));
1260 if (vfs_context_is64bit(ctx
))
1261 error
= copyin(data
, (caddr_t
)&args
, sizeof (struct user_nfs_args4
));
1263 error
= copyin(data
, (caddr_t
)&tempargs
, sizeof (struct nfs_args4
));
1266 if (vfs_context_is64bit(ctx
))
1267 error
= copyin(data
, (caddr_t
)&args
, sizeof (struct user_nfs_args5
));
1269 error
= copyin(data
, (caddr_t
)&tempargs
, sizeof (struct nfs_args5
));
1272 if (vfs_context_is64bit(ctx
))
1273 error
= copyin(data
, (caddr_t
)&args
, sizeof (args
));
1275 error
= copyin(data
, (caddr_t
)&tempargs
, sizeof (tempargs
));
1278 return (EPROGMISMATCH
);
1283 if (!vfs_context_is64bit(ctx
)) {
1284 args
.version
= tempargs
.version
;
1285 args
.addrlen
= tempargs
.addrlen
;
1286 args
.sotype
= tempargs
.sotype
;
1287 args
.proto
= tempargs
.proto
;
1288 args
.fhsize
= tempargs
.fhsize
;
1289 args
.flags
= tempargs
.flags
;
1290 args
.wsize
= tempargs
.wsize
;
1291 args
.rsize
= tempargs
.rsize
;
1292 args
.readdirsize
= tempargs
.readdirsize
;
1293 args
.timeo
= tempargs
.timeo
;
1294 args
.retrans
= tempargs
.retrans
;
1295 args
.maxgrouplist
= tempargs
.maxgrouplist
;
1296 args
.readahead
= tempargs
.readahead
;
1297 args
.leaseterm
= tempargs
.leaseterm
;
1298 args
.deadthresh
= tempargs
.deadthresh
;
1299 args
.addr
= CAST_USER_ADDR_T(tempargs
.addr
);
1300 args
.fh
= CAST_USER_ADDR_T(tempargs
.fh
);
1301 args
.hostname
= CAST_USER_ADDR_T(tempargs
.hostname
);
1302 if (argsvers
>= 4) {
1303 args
.acregmin
= tempargs
.acregmin
;
1304 args
.acregmax
= tempargs
.acregmax
;
1305 args
.acdirmin
= tempargs
.acdirmin
;
1306 args
.acdirmax
= tempargs
.acdirmax
;
1309 args
.auth
= tempargs
.auth
;
1311 args
.deadtimeout
= tempargs
.deadtimeout
;
1314 if (args
.fhsize
< 0 || args
.fhsize
> NFSX_V3FHMAX
)
1316 if (args
.fhsize
> 0) {
1317 error
= copyin(args
.fh
, (caddr_t
)nfh
, args
.fhsize
);
1322 mntfrom
= &vfs_statfs(mp
)->f_mntfromname
[0];
1323 error
= copyinstr(args
.hostname
, mntfrom
, MAXPATHLEN
-1, &len
);
1326 bzero(&mntfrom
[len
], MAXPATHLEN
- len
);
1328 /* sockargs() call must be after above copyin() calls */
1329 error
= sockargs(&nam
, args
.addr
, args
.addrlen
, MBUF_TYPE_SONAME
);
1333 args
.fh
= CAST_USER_ADDR_T(&nfh
[0]);
1334 error
= mountnfs(&args
, mp
, nam
, ctx
, &vp
);
1339 * Common code for mount and mountroot
1344 struct nfsmount
*nmp
,
1346 struct user_nfs_args
*argp
,
1350 struct nfs_vattr nvattr
;
1357 * Get file attributes for the mountpoint. These are needed
1358 * in order to properly create the root vnode.
1360 fhp
= CAST_DOWN(u_char
*, argp
->fh
);
1361 error
= nfs3_getattr_rpc(NULL
, nmp
->nm_mountp
, fhp
, argp
->fhsize
,
1362 ctx
, &nvattr
, &xid
);
1366 error
= nfs_nget(nmp
->nm_mountp
, NULL
, NULL
, fhp
, argp
->fhsize
,
1367 &nvattr
, &xid
, NG_MARKROOT
, npp
);
1369 nfs_node_unlock(*npp
);
1374 * Try to make sure we have all the general info from the server.
1376 if (nmp
->nm_vers
== NFS_VER2
) {
1377 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXNAME
);
1378 nmp
->nm_fsattr
.nfsa_maxname
= NFS_MAXNAMLEN
;
1379 } else if (nmp
->nm_vers
== NFS_VER3
) {
1380 /* get the NFSv3 FSINFO */
1381 error
= nfs3_fsinfo(nmp
, *npp
, ctx
);
1384 /* If the server indicates all pathconf info is */
1385 /* the same, grab a copy of that info now */
1386 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_HOMOGENEOUS
) &&
1387 (nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_HOMOGENEOUS
)) {
1388 struct nfs_fsattr nfsa
;
1389 if (!nfs3_pathconf_rpc(*npp
, &nfsa
, ctx
)) {
1390 /* cache a copy of the results */
1391 lck_mtx_lock(&nmp
->nm_lock
);
1392 nfs3_pathconf_cache(nmp
, &nfsa
);
1393 lck_mtx_unlock(&nmp
->nm_lock
);
1398 if (*npp
&& error
) {
1399 vnode_put(NFSTOV(*npp
));
1400 vnode_recycle(NFSTOV(*npp
));
1408 struct nfsmount
*nmp
,
1410 __unused
struct user_nfs_args
*argp
,
1413 struct nfsm_chain nmreq
, nmrep
;
1414 int error
= 0, numops
, status
, interval
;
1415 char *path
= &vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
[0];
1416 char *name
, *nextname
;
1418 struct nfs_vattr nvattr
;
1423 TAILQ_INIT(&nmp
->nm_open_owners
);
1424 TAILQ_INIT(&nmp
->nm_recallq
);
1425 nmp
->nm_stategenid
= 1;
1427 /* look up path to get fh and attrs for mount point root */
1428 numops
= 2; // PUTROOTFH + LOOKUP* + GETATTR
1429 while (*path
&& (*path
!= '/'))
1433 while (*name
&& (*name
== '/'))
1438 while (*nextname
&& (*nextname
!= '/'))
1443 nfsm_chain_build_alloc_init(error
, &nmreq
, 25 * NFSX_UNSIGNED
);
1444 nfsm_chain_add_compound_header(error
, &nmreq
, "mount", numops
);
1446 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTROOTFH
);
1450 while (*name
&& (*name
== '/'))
1455 while (*nextname
&& (*nextname
!= '/'))
1458 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_LOOKUP
);
1459 nfsm_chain_add_string(error
, &nmreq
, name
, nextname
- name
);
1463 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
1464 NFS4_DEFAULT_ATTRIBUTES(nmp
->nm_fsattr
.nfsa_supp_attr
);
1465 NFS_BITMAP_SET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_FILEHANDLE
);
1466 nfsm_chain_add_bitmap(error
, &nmreq
, nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_ATTR_BITMAP_LEN
);
1467 nfsm_chain_build_done(error
, &nmreq
);
1468 nfsm_assert(error
, (numops
== 0), EPROTO
);
1470 error
= nfs_request(NULL
, nmp
->nm_mountp
, &nmreq
, NFSPROC4_COMPOUND
, ctx
, &nmrep
, &xid
, &status
);
1471 nfsm_chain_skip_tag(error
, &nmrep
);
1472 nfsm_chain_get_32(error
, &nmrep
, numops
);
1473 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTROOTFH
);
1476 while (*name
&& (*name
== '/'))
1481 while (*nextname
&& (*nextname
!= '/'))
1483 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_LOOKUP
);
1486 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
1488 NFS_CLEAR_ATTRIBUTES(nmp
->nm_fsattr
.nfsa_bitmap
);
1489 NFS_CLEAR_ATTRIBUTES(&nvattr
.nva_bitmap
);
1490 error
= nfs4_parsefattr(&nmrep
, &nmp
->nm_fsattr
, &nvattr
, &fh
, NULL
);
1491 if (!error
&& !NFS_BITMAP_ISSET(&nvattr
.nva_bitmap
, NFS_FATTR_FILEHANDLE
)) {
1492 printf("nfs: mount didn't return filehandle?\n");
1497 error
= nfs_nget(nmp
->nm_mountp
, NULL
, NULL
, fh
.fh_data
, fh
.fh_len
, &nvattr
, &xid
, NG_MARKROOT
, npp
);
1500 /* adjust I/O sizes to server limits */
1501 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXREAD
)) {
1502 if (nmp
->nm_fsattr
.nfsa_maxread
< (uint64_t)nmp
->nm_rsize
) {
1503 nmp
->nm_rsize
= nmp
->nm_fsattr
.nfsa_maxread
& ~(NFS_FABLKSIZE
- 1);
1504 if (nmp
->nm_rsize
== 0)
1505 nmp
->nm_rsize
= nmp
->nm_fsattr
.nfsa_maxread
;
1508 if (NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_bitmap
, NFS_FATTR_MAXWRITE
)) {
1509 if (nmp
->nm_fsattr
.nfsa_maxwrite
< (uint64_t)nmp
->nm_wsize
) {
1510 nmp
->nm_wsize
= nmp
->nm_fsattr
.nfsa_maxwrite
& ~(NFS_FABLKSIZE
- 1);
1511 if (nmp
->nm_wsize
== 0)
1512 nmp
->nm_wsize
= nmp
->nm_fsattr
.nfsa_maxwrite
;
1516 /* set up lease renew timer */
1517 nmp
->nm_renew_timer
= thread_call_allocate(nfs4_renew_timer
, nmp
);
1518 interval
= nmp
->nm_fsattr
.nfsa_lease
/ 2;
1521 nfs_interval_timer_start(nmp
->nm_renew_timer
, interval
* 1000);
1525 nfs_node_unlock(*npp
);
1531 struct user_nfs_args
*argp
,
1537 struct nfsmount
*nmp
;
1540 uint32_t maxio
, iosize
;
1541 struct vfsstatfs
*sbp
;
1542 struct timespec ts
= { 1, 0 };
1545 * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes
1546 * no sense in that context.
1548 if (argp
->sotype
== SOCK_STREAM
)
1549 argp
->flags
&= ~NFSMNT_NOCONN
;
1551 if (vfs_flags(mp
) & MNT_UPDATE
) {
1553 /* update paths, file handles, etc, here XXX */
1557 MALLOC_ZONE(nmp
, struct nfsmount
*,
1558 sizeof (struct nfsmount
), M_NFSMNT
, M_WAITOK
);
1563 bzero((caddr_t
)nmp
, sizeof (struct nfsmount
));
1564 lck_mtx_init(&nmp
->nm_lock
, nfs_mount_grp
, LCK_ATTR_NULL
);
1565 TAILQ_INIT(&nmp
->nm_resendq
);
1566 TAILQ_INIT(&nmp
->nm_iodq
);
1567 TAILQ_INIT(&nmp
->nm_gsscl
);
1568 vfs_setfsprivate(mp
, nmp
);
1570 nfs_nhinit_finish();
1572 lck_mtx_lock(&nmp
->nm_lock
);
1574 /* setup defaults */
1575 nmp
->nm_vers
= NFS_VER2
;
1576 nmp
->nm_timeo
= NFS_TIMEO
;
1577 nmp
->nm_retry
= NFS_RETRANS
;
1578 if (argp
->sotype
== SOCK_DGRAM
) {
1579 nmp
->nm_wsize
= NFS_DGRAM_WSIZE
;
1580 nmp
->nm_rsize
= NFS_DGRAM_RSIZE
;
1582 nmp
->nm_wsize
= NFS_WSIZE
;
1583 nmp
->nm_rsize
= NFS_RSIZE
;
1585 nmp
->nm_readdirsize
= NFS_READDIRSIZE
;
1586 nmp
->nm_numgrps
= NFS_MAXGRPS
;
1587 nmp
->nm_readahead
= NFS_DEFRAHEAD
;
1588 nmp
->nm_tprintf_delay
= nfs_tprintf_delay
;
1589 if (nmp
->nm_tprintf_delay
< 0)
1590 nmp
->nm_tprintf_delay
= 0;
1591 nmp
->nm_tprintf_initial_delay
= nfs_tprintf_initial_delay
;
1592 if (nmp
->nm_tprintf_initial_delay
< 0)
1593 nmp
->nm_tprintf_initial_delay
= 0;
1594 nmp
->nm_acregmin
= NFS_MINATTRTIMO
;
1595 nmp
->nm_acregmax
= NFS_MAXATTRTIMO
;
1596 nmp
->nm_acdirmin
= NFS_MINDIRATTRTIMO
;
1597 nmp
->nm_acdirmax
= NFS_MAXDIRATTRTIMO
;
1598 nmp
->nm_auth
= RPCAUTH_SYS
;
1599 nmp
->nm_deadtimeout
= 0;
1602 nmp
->nm_mountp
= mp
;
1603 vfs_setauthopaque(mp
);
1604 nmp
->nm_flag
= argp
->flags
;
1607 if (argp
->flags
& NFSMNT_NFSV4
) {
1608 nmp
->nm_vers
= NFS_VER4
;
1609 /* NFSv4 is only allowed over TCP. */
1610 if (argp
->sotype
!= SOCK_STREAM
) {
1614 } else if (argp
->flags
& NFSMNT_NFSV3
)
1615 nmp
->nm_vers
= NFS_VER3
;
1617 if (nmp
->nm_vers
== NFS_VER2
)
1618 nmp
->nm_flag
&= ~NFSMNT_RDIRPLUS
;
1620 if ((argp
->flags
& NFSMNT_TIMEO
) && argp
->timeo
> 0) {
1621 nmp
->nm_timeo
= (argp
->timeo
* NFS_HZ
+ 5) / 10;
1622 if (nmp
->nm_timeo
< NFS_MINTIMEO
)
1623 nmp
->nm_timeo
= NFS_MINTIMEO
;
1624 else if (nmp
->nm_timeo
> NFS_MAXTIMEO
)
1625 nmp
->nm_timeo
= NFS_MAXTIMEO
;
1628 if ((argp
->flags
& NFSMNT_RETRANS
) && argp
->retrans
> 1) {
1629 nmp
->nm_retry
= argp
->retrans
;
1630 if (nmp
->nm_retry
> NFS_MAXREXMIT
)
1631 nmp
->nm_retry
= NFS_MAXREXMIT
;
1634 if (nmp
->nm_vers
!= NFS_VER2
) {
1635 if (argp
->sotype
== SOCK_DGRAM
)
1636 maxio
= NFS_MAXDGRAMDATA
;
1638 maxio
= NFS_MAXDATA
;
1640 maxio
= NFS_V2MAXDATA
;
1642 if ((argp
->flags
& NFSMNT_WSIZE
) && argp
->wsize
> 0) {
1643 nmp
->nm_wsize
= argp
->wsize
;
1644 /* Round down to multiple of blocksize */
1645 nmp
->nm_wsize
&= ~(NFS_FABLKSIZE
- 1);
1646 if (nmp
->nm_wsize
<= 0)
1647 nmp
->nm_wsize
= NFS_FABLKSIZE
;
1649 if (nmp
->nm_wsize
> maxio
)
1650 nmp
->nm_wsize
= maxio
;
1651 if (nmp
->nm_wsize
> NFS_MAXBSIZE
)
1652 nmp
->nm_wsize
= NFS_MAXBSIZE
;
1654 if ((argp
->flags
& NFSMNT_RSIZE
) && argp
->rsize
> 0) {
1655 nmp
->nm_rsize
= argp
->rsize
;
1656 /* Round down to multiple of blocksize */
1657 nmp
->nm_rsize
&= ~(NFS_FABLKSIZE
- 1);
1658 if (nmp
->nm_rsize
<= 0)
1659 nmp
->nm_rsize
= NFS_FABLKSIZE
;
1661 if (nmp
->nm_rsize
> maxio
)
1662 nmp
->nm_rsize
= maxio
;
1663 if (nmp
->nm_rsize
> NFS_MAXBSIZE
)
1664 nmp
->nm_rsize
= NFS_MAXBSIZE
;
1666 if ((argp
->flags
& NFSMNT_READDIRSIZE
) && argp
->readdirsize
> 0) {
1667 nmp
->nm_readdirsize
= argp
->readdirsize
;
1669 if (nmp
->nm_readdirsize
> maxio
)
1670 nmp
->nm_readdirsize
= maxio
;
1671 if (nmp
->nm_readdirsize
> nmp
->nm_rsize
)
1672 nmp
->nm_readdirsize
= nmp
->nm_rsize
;
1674 if ((argp
->flags
& NFSMNT_MAXGRPS
) && argp
->maxgrouplist
>= 0 &&
1675 argp
->maxgrouplist
<= NFS_MAXGRPS
)
1676 nmp
->nm_numgrps
= argp
->maxgrouplist
;
1677 if ((argp
->flags
& NFSMNT_READAHEAD
) && argp
->readahead
>= 0 &&
1678 argp
->readahead
<= NFS_MAXRAHEAD
)
1679 nmp
->nm_readahead
= argp
->readahead
;
1680 if (argp
->flags
& NFSMNT_READAHEAD
)
1681 nmp
->nm_readahead
= argp
->readahead
;
1682 if (nmp
->nm_readahead
< 0)
1683 nmp
->nm_readahead
= 0;
1684 else if (nmp
->nm_readahead
> NFS_MAXRAHEAD
)
1685 nmp
->nm_readahead
= NFS_MAXRAHEAD
;
1687 if (argp
->version
>= 4) {
1688 if ((argp
->flags
& NFSMNT_ACREGMIN
) && argp
->acregmin
>= 0)
1689 nmp
->nm_acregmin
= argp
->acregmin
;
1690 if ((argp
->flags
& NFSMNT_ACREGMAX
) && argp
->acregmax
>= 0)
1691 nmp
->nm_acregmax
= argp
->acregmax
;
1692 if ((argp
->flags
& NFSMNT_ACDIRMIN
) && argp
->acdirmin
>= 0)
1693 nmp
->nm_acdirmin
= argp
->acdirmin
;
1694 if ((argp
->flags
& NFSMNT_ACDIRMAX
) && argp
->acdirmax
>= 0)
1695 nmp
->nm_acdirmax
= argp
->acdirmax
;
1696 if (nmp
->nm_acregmin
> nmp
->nm_acregmax
)
1697 nmp
->nm_acregmin
= nmp
->nm_acregmax
;
1698 if (nmp
->nm_acdirmin
> nmp
->nm_acdirmax
)
1699 nmp
->nm_acdirmin
= nmp
->nm_acdirmax
;
1701 if (argp
->version
>= 5) {
1702 if (argp
->flags
& NFSMNT_SECFLAVOR
) {
1704 * Check for valid security flavor
1706 switch (argp
->auth
) {
1711 nmp
->nm_auth
= argp
->auth
;
1719 if (argp
->version
>= 6) {
1720 if (argp
->flags
& NFSMNT_DEADTIMEOUT
)
1721 nmp
->nm_deadtimeout
= argp
->deadtimeout
;
1723 if ((nmp
->nm_flag
& NFSMNT_DEADTIMEOUT
) && (nmp
->nm_deadtimeout
<= 0))
1724 nmp
->nm_flag
&= ~NFSMNT_DEADTIMEOUT
;
1726 /* set up the version-specific function tables */
1727 if (nmp
->nm_vers
< NFS_VER4
)
1728 nmp
->nm_funcs
= &nfs3_funcs
;
1730 nmp
->nm_funcs
= &nfs4_funcs
;
1732 /* Set up the sockets and related info */
1733 nmp
->nm_sotype
= argp
->sotype
;
1734 nmp
->nm_soproto
= argp
->proto
;
1735 if (nmp
->nm_sotype
== SOCK_DGRAM
)
1736 TAILQ_INIT(&nmp
->nm_cwndq
);
1738 lck_mtx_unlock(&nmp
->nm_lock
);
1740 /* make sure mbuf constants are set up */
1741 if (!nfs_mbuf_mhlen
)
1744 if (nmp
->nm_vers
>= NFS_VER4
) {
1747 nmp
->nm_mounttime
= ((uint64_t)now
.tv_sec
<< 32) | now
.tv_usec
;
1748 nmp
->nm_mcred
= vfs_context_ucred(ctx
);
1749 if (IS_VALID_CRED(nmp
->nm_mcred
))
1750 kauth_cred_ref(nmp
->nm_mcred
);
1751 nfs4_mount_callback_setup(nmp
);
1754 /* set up the socket */
1755 if ((error
= nfs_connect(nmp
, 1)))
1759 * Get the root node/attributes from the NFS server and
1760 * do any basic, version-specific setup.
1762 error
= nmp
->nm_funcs
->nf_mount(nmp
, ctx
, argp
, &np
);
1767 * A reference count is needed on the node representing the
1768 * remote root. If this object is not persistent, then backward
1769 * traversals of the mount point (i.e. "..") will not work if
1770 * the node gets flushed out of the cache.
1774 /* get usecount and drop iocount */
1775 error
= vnode_ref(*vpp
);
1778 vnode_recycle(*vpp
);
1783 * Do statfs to ensure static info gets set to reasonable values.
1785 if ((error
= nmp
->nm_funcs
->nf_update_statfs(nmp
, ctx
))) {
1786 int error2
= vnode_getwithref(*vpp
);
1790 vnode_recycle(*vpp
);
1793 sbp
= vfs_statfs(mp
);
1794 sbp
->f_bsize
= nmp
->nm_fsattr
.nfsa_bsize
;
1795 sbp
->f_blocks
= nmp
->nm_fsattr
.nfsa_space_total
/ sbp
->f_bsize
;
1796 sbp
->f_bfree
= nmp
->nm_fsattr
.nfsa_space_free
/ sbp
->f_bsize
;
1797 sbp
->f_bavail
= nmp
->nm_fsattr
.nfsa_space_avail
/ sbp
->f_bsize
;
1798 sbp
->f_bused
= (nmp
->nm_fsattr
.nfsa_space_total
/ sbp
->f_bsize
) -
1799 (nmp
->nm_fsattr
.nfsa_space_free
/ sbp
->f_bsize
);
1800 sbp
->f_files
= nmp
->nm_fsattr
.nfsa_files_total
;
1801 sbp
->f_ffree
= nmp
->nm_fsattr
.nfsa_files_free
;
1802 sbp
->f_iosize
= nfs_iosize
;
1805 * Calculate the size used for I/O buffers. Use the larger
1806 * of the two sizes to minimise NFS requests but make sure
1807 * that it is at least one VM page to avoid wasting buffer
1808 * space and to allow easy mmapping of I/O buffers.
1809 * The read/write RPC calls handle the splitting up of
1810 * buffers into multiple requests if the buffer size is
1811 * larger than the I/O size.
1813 iosize
= max(nmp
->nm_rsize
, nmp
->nm_wsize
);
1814 if (iosize
< PAGE_SIZE
)
1816 nmp
->nm_biosize
= trunc_page_32(iosize
);
1819 * V3 mounts give us a (relatively) reliable remote access(2)
1820 * call, so advertise the fact.
1822 * XXX this may not be the best way to go, as the granularity
1823 * offered isn't a good match to our needs.
1825 if (nmp
->nm_vers
!= NFS_VER2
)
1826 vfs_setauthopaqueaccess(mp
);
1828 if (nmp
->nm_flag
& NFSMNT_LOCALLOCKS
)
1829 vfs_setlocklocal(nmp
->nm_mountp
);
1830 if (!(nmp
->nm_flag
& (NFSMNT_NOLOCKS
|NFSMNT_LOCALLOCKS
)))
1831 nfs_lockd_mount_change(1);
1833 lck_mtx_lock(&nmp
->nm_lock
);
1834 nmp
->nm_state
|= NFSSTA_MOUNTED
;
1835 lck_mtx_unlock(&nmp
->nm_lock
);
1838 /* mark the socket for termination */
1839 lck_mtx_lock(&nmp
->nm_lock
);
1840 nmp
->nm_sockflags
|= NMSOCK_UNMOUNT
;
1841 /* wait for any socket poking to complete */
1842 while (nmp
->nm_sockflags
& NMSOCK_POKE
)
1843 msleep(&nmp
->nm_sockflags
, &nmp
->nm_lock
, PZERO
-1, "nfswaitpoke", &ts
);
1844 /* wait for the socket thread to terminate */
1845 while (nmp
->nm_sockthd
) {
1846 wakeup(&nmp
->nm_sockthd
);
1847 msleep(&nmp
->nm_sockthd
, &nmp
->nm_lock
, PZERO
-1, "nfswaitsockthd", &ts
);
1849 /* tear down the socket */
1850 lck_mtx_unlock(&nmp
->nm_lock
);
1851 nfs_disconnect(nmp
);
1852 if (nmp
->nm_vers
>= NFS_VER4
) {
1854 nfs4_mount_callback_shutdown(nmp
);
1855 if (nmp
->nm_renew_timer
) {
1856 thread_call_cancel(nmp
->nm_renew_timer
);
1857 thread_call_free(nmp
->nm_renew_timer
);
1859 if (nmp
->nm_longid
) {
1860 /* remove/deallocate the client ID data */
1861 lck_mtx_lock(nfs_global_mutex
);
1862 TAILQ_REMOVE(&nfsclientids
, nmp
->nm_longid
, nci_link
);
1863 if (nmp
->nm_longid
->nci_id
)
1864 FREE(nmp
->nm_longid
->nci_id
, M_TEMP
);
1865 FREE(nmp
->nm_longid
, M_TEMP
);
1866 lck_mtx_unlock(nfs_global_mutex
);
1868 if (IS_VALID_CRED(nmp
->nm_mcred
))
1869 kauth_cred_unref(&nmp
->nm_mcred
);
1871 lck_mtx_destroy(&nmp
->nm_lock
, nfs_mount_grp
);
1872 FREE_ZONE((caddr_t
)nmp
, sizeof (struct nfsmount
), M_NFSMNT
);
1878 nfs3_umount_rpc(struct nfsmount
*nmp
, vfs_context_t ctx
, int timeo
)
1880 int error
= 0, auth_len
, slen
;
1881 thread_t thd
= vfs_context_thread(ctx
);
1882 kauth_cred_t cred
= vfs_context_ucred(ctx
);
1885 struct nfsm_chain nmreq
, nmrep
;
1887 uint32_t mntport
= 0;
1888 struct sockaddr
*nam
= mbuf_data(nmp
->nm_nam
);
1889 struct sockaddr_in saddr
;
1891 bcopy(nam
, &saddr
, min(sizeof(saddr
), nam
->sa_len
));
1892 auth_len
= ((((cred
->cr_ngroups
- 1) > nmp
->nm_numgrps
) ?
1893 nmp
->nm_numgrps
: (cred
->cr_ngroups
- 1)) << 2) +
1895 nfsm_chain_null(&nmreq
);
1896 nfsm_chain_null(&nmrep
);
1898 /* send portmap request to get mountd port */
1899 saddr
.sin_port
= htons(PMAPPORT
);
1900 nfsm_chain_build_alloc_init(error
, &nmreq
, 4*NFSX_UNSIGNED
);
1901 nfsm_chain_add_32(error
, &nmreq
, RPCPROG_MNT
);
1902 nfsm_chain_add_32(error
, &nmreq
, RPCMNT_VER1
);
1903 nfsm_chain_add_32(error
, &nmreq
, IPPROTO_UDP
);
1904 nfsm_chain_add_32(error
, &nmreq
, 0);
1905 nfsm_chain_build_done(error
, &nmreq
);
1907 error
= nfsm_rpchead2(SOCK_DGRAM
, PMAPPROG
, PMAPVERS
, PMAPPROC_GETPORT
,
1908 RPCAUTH_SYS
, auth_len
, cred
, NULL
, nmreq
.nmc_mhead
, &xid
, &mreq
);
1910 nmreq
.nmc_mhead
= NULL
;
1911 error
= nfs_aux_request(nmp
, thd
, &saddr
, mreq
, R_XID32(xid
), 0, timeo
, &nmrep
);
1914 /* grab mountd port from portmap response */
1915 nfsm_chain_get_32(error
, &nmrep
, mntport
);
1917 nfsm_chain_cleanup(&nmreq
);
1918 nfsm_chain_cleanup(&nmrep
);
1921 /* MOUNT protocol UNMOUNT request */
1922 saddr
.sin_port
= htons(mntport
);
1923 path
= &vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
[0];
1924 while (*path
&& (*path
!= '/'))
1926 slen
= strlen(path
);
1927 nfsm_chain_build_alloc_init(error
, &nmreq
, NFSX_UNSIGNED
+ nfsm_rndup(slen
));
1928 nfsm_chain_add_string(error
, &nmreq
, path
, slen
);
1929 nfsm_chain_build_done(error
, &nmreq
);
1931 error
= nfsm_rpchead2(SOCK_DGRAM
, RPCPROG_MNT
, RPCMNT_VER1
, RPCMNT_UMOUNT
,
1932 RPCAUTH_SYS
, auth_len
, cred
, NULL
, nmreq
.nmc_mhead
, &xid
, &mreq
);
1934 nmreq
.nmc_mhead
= NULL
;
1935 error
= nfs_aux_request(nmp
, thd
, &saddr
, mreq
, R_XID32(xid
), 1, timeo
, &nmrep
);
1937 nfsm_chain_cleanup(&nmreq
);
1938 nfsm_chain_cleanup(&nmrep
);
1942 * unmount system call
1948 __unused vfs_context_t ctx
)
1950 struct nfsmount
*nmp
;
1952 int error
, flags
= 0, docallback
;
1953 struct nfsreq
*req
, *treq
;
1954 struct nfs_reqqhead iodq
;
1955 struct timespec ts
= { 1, 0 };
1956 struct nfs_open_owner
*noop
, *nextnoop
;
1960 lck_mtx_lock(&nmp
->nm_lock
);
1962 * During a force unmount we want to...
1963 * Mark that we are doing a force unmount.
1964 * Make the mountpoint soft.
1966 if (mntflags
& MNT_FORCE
) {
1967 flags
|= FORCECLOSE
;
1968 nmp
->nm_state
|= NFSSTA_FORCE
;
1969 nmp
->nm_flag
|= NFSMNT_SOFT
;
1972 * Goes something like this..
1973 * - Call vflush() to clear out vnodes for this file system,
1974 * except for the swap files. Deal with them in 2nd pass.
1975 * - Decrement reference on the vnode representing remote root.
1976 * - Close the socket
1977 * - Free up the data structures
1979 vp
= NFSTOV(nmp
->nm_dnp
);
1980 lck_mtx_unlock(&nmp
->nm_lock
);
1983 * vflush will check for busy vnodes on mountpoint.
1984 * Will do the right thing for MNT_FORCE. That is, we should
1985 * not get EBUSY back.
1987 error
= vflush(mp
, vp
, SKIPSWAP
| flags
);
1988 if (mntflags
& MNT_FORCE
) {
1989 error
= vflush(mp
, NULLVP
, flags
); /* locks vp in the process */
1991 if (vnode_isinuse(vp
, 1))
1993 error
= vflush(mp
, vp
, flags
);
1998 lck_mtx_lock(&nmp
->nm_lock
);
1999 nmp
->nm_state
&= ~NFSSTA_MOUNTED
;
2001 lck_mtx_unlock(&nmp
->nm_lock
);
2004 * Release the root vnode reference held by mountnfs()
2006 error
= vnode_get(vp
);
2011 vflush(mp
, NULLVP
, FORCECLOSE
);
2014 * Destroy any RPCSEC_GSS contexts
2016 if (!TAILQ_EMPTY(&nmp
->nm_gsscl
))
2017 nfs_gss_clnt_ctx_unmount(nmp
, mntflags
);
2019 /* mark the socket for termination */
2020 lck_mtx_lock(&nmp
->nm_lock
);
2021 nmp
->nm_sockflags
|= NMSOCK_UNMOUNT
;
2023 /* stop callbacks */
2024 if ((nmp
->nm_vers
>= NFS_VER4
) && nmp
->nm_cbid
)
2025 nfs4_mount_callback_shutdown(nmp
);
2027 /* wait for any socket poking to complete */
2028 while (nmp
->nm_sockflags
& NMSOCK_POKE
)
2029 msleep(&nmp
->nm_sockflags
, &nmp
->nm_lock
, PZERO
-1, "nfswaitpoke", &ts
);
2031 /* Have the socket thread send the unmount RPC, if requested/appropriate. */
2032 if ((nmp
->nm_vers
< NFS_VER4
) && !(mntflags
& MNT_FORCE
) && (nmp
->nm_flag
& NFSMNT_CALLUMNT
))
2033 nfs_mount_sock_thread_wake(nmp
);
2035 /* wait for the socket thread to terminate */
2036 while (nmp
->nm_sockthd
) {
2037 wakeup(&nmp
->nm_sockthd
);
2038 msleep(&nmp
->nm_sockthd
, &nmp
->nm_lock
, PZERO
-1, "nfswaitsockthd", &ts
);
2041 lck_mtx_unlock(&nmp
->nm_lock
);
2043 /* tear down the socket */
2044 nfs_disconnect(nmp
);
2046 vfs_setfsprivate(mp
, NULL
);
2048 lck_mtx_lock(&nmp
->nm_lock
);
2050 if ((nmp
->nm_vers
>= NFS_VER4
) && nmp
->nm_cbid
) {
2051 /* clear out any pending recall requests */
2052 while ((np
= TAILQ_FIRST(&nmp
->nm_recallq
))) {
2053 TAILQ_REMOVE(&nmp
->nm_recallq
, np
, n_dlink
);
2054 np
->n_dlink
.tqe_next
= NFSNOLIST
;
2058 /* cancel any renew timer */
2059 if ((nmp
->nm_vers
>= NFS_VER4
) && nmp
->nm_renew_timer
) {
2060 thread_call_cancel(nmp
->nm_renew_timer
);
2061 thread_call_free(nmp
->nm_renew_timer
);
2064 mbuf_freem(nmp
->nm_nam
);
2065 lck_mtx_unlock(&nmp
->nm_lock
);
2067 if ((nmp
->nm_vers
< NFS_VER4
) && !(nmp
->nm_flag
& (NFSMNT_NOLOCKS
|NFSMNT_LOCALLOCKS
)))
2068 nfs_lockd_mount_change(-1);
2070 if ((nmp
->nm_vers
>= NFS_VER4
) && nmp
->nm_longid
) {
2071 /* remove/deallocate the client ID data */
2072 lck_mtx_lock(nfs_global_mutex
);
2073 TAILQ_REMOVE(&nfsclientids
, nmp
->nm_longid
, nci_link
);
2074 if (nmp
->nm_longid
->nci_id
)
2075 FREE(nmp
->nm_longid
->nci_id
, M_TEMP
);
2076 FREE(nmp
->nm_longid
, M_TEMP
);
2077 lck_mtx_unlock(nfs_global_mutex
);
2081 * Loop through outstanding request list and remove dangling
2082 * references to defunct nfsmount struct
2085 lck_mtx_lock(nfs_request_mutex
);
2086 TAILQ_FOREACH(req
, &nfs_reqq
, r_chain
) {
2087 if (req
->r_nmp
== nmp
) {
2088 lck_mtx_lock(&req
->r_mtx
);
2090 lck_mtx_unlock(&req
->r_mtx
);
2091 if (req
->r_callback
.rcb_func
) {
2092 /* async I/O RPC needs to be finished */
2093 lck_mtx_lock(nfsiod_mutex
);
2094 if (req
->r_achain
.tqe_next
== NFSREQNOLIST
)
2095 TAILQ_INSERT_TAIL(&iodq
, req
, r_achain
);
2096 lck_mtx_unlock(nfsiod_mutex
);
2098 lck_mtx_lock(&req
->r_mtx
);
2099 lck_mtx_lock(&nmp
->nm_lock
);
2100 if (req
->r_flags
& R_RESENDQ
) {
2101 if (req
->r_rchain
.tqe_next
!= NFSREQNOLIST
) {
2102 TAILQ_REMOVE(&nmp
->nm_resendq
, req
, r_rchain
);
2103 req
->r_rchain
.tqe_next
= NFSREQNOLIST
;
2105 req
->r_flags
&= ~R_RESENDQ
;
2107 lck_mtx_unlock(&nmp
->nm_lock
);
2108 lck_mtx_unlock(&req
->r_mtx
);
2112 lck_mtx_unlock(nfs_request_mutex
);
2114 /* finish any async I/O RPCs queued up */
2115 lck_mtx_lock(nfsiod_mutex
);
2116 TAILQ_CONCAT(&iodq
, &nmp
->nm_iodq
, r_achain
);
2117 lck_mtx_unlock(nfsiod_mutex
);
2118 TAILQ_FOREACH_SAFE(req
, &iodq
, r_achain
, treq
) {
2119 TAILQ_REMOVE(&iodq
, req
, r_achain
);
2120 req
->r_achain
.tqe_next
= NFSREQNOLIST
;
2121 lck_mtx_lock(&req
->r_mtx
);
2122 req
->r_error
= ENXIO
;
2123 docallback
= !(req
->r_flags
& R_WAITSENT
);
2124 lck_mtx_unlock(&req
->r_mtx
);
2126 req
->r_callback
.rcb_func(req
);
2129 /* clean up open owner list */
2130 if (nmp
->nm_vers
>= NFS_VER4
) {
2131 lck_mtx_lock(&nmp
->nm_lock
);
2132 TAILQ_FOREACH_SAFE(noop
, &nmp
->nm_open_owners
, noo_link
, nextnoop
) {
2133 TAILQ_REMOVE(&nmp
->nm_open_owners
, noop
, noo_link
);
2134 noop
->noo_flags
&= ~NFS_OPEN_OWNER_LINK
;
2135 if (noop
->noo_refcnt
)
2137 nfs_open_owner_destroy(noop
);
2139 lck_mtx_unlock(&nmp
->nm_lock
);
2140 if (IS_VALID_CRED(nmp
->nm_mcred
))
2141 kauth_cred_unref(&nmp
->nm_mcred
);
2144 lck_mtx_destroy(&nmp
->nm_lock
, nfs_mount_grp
);
2145 FREE_ZONE((caddr_t
)nmp
, sizeof (struct nfsmount
), M_NFSMNT
);
2150 * Return root of a filesystem
2153 nfs_vfs_root(mount_t mp
, vnode_t
*vpp
, __unused vfs_context_t ctx
)
2156 struct nfsmount
*nmp
;
2161 if (!nmp
|| !nmp
->nm_dnp
)
2163 vp
= NFSTOV(nmp
->nm_dnp
);
2164 vpid
= vnode_vid(vp
);
2165 while ((error
= vnode_getwithvid(vp
, vpid
))) {
2166 /* vnode_get() may return ENOENT if the dir changes. */
2167 /* If that happens, just try it again, else return the error. */
2168 if ((error
!= ENOENT
) || (vnode_vid(vp
) == vpid
))
2170 vpid
= vnode_vid(vp
);
2177 * Do operations associated with quotas
2182 __unused mount_t mp
,
2185 __unused caddr_t datap
,
2186 __unused vfs_context_t context
)
2193 nfs3_getquota(struct nfsmount
*nmp
, vfs_context_t ctx
, uid_t id
, int type
, struct dqblk
*dqb
)
2195 int error
= 0, auth_len
, slen
, timeo
;
2196 int rqvers
= (type
== GRPQUOTA
) ? RPCRQUOTA_EXT_VER
: RPCRQUOTA_VER
;
2197 thread_t thd
= vfs_context_thread(ctx
);
2198 kauth_cred_t cred
= vfs_context_ucred(ctx
);
2201 struct nfsm_chain nmreq
, nmrep
;
2203 uint32_t val
= 0, bsize
= 0;
2204 struct sockaddr
*nam
= mbuf_data(nmp
->nm_nam
);
2205 struct sockaddr_in saddr
;
2208 bcopy(nam
, &saddr
, min(sizeof(saddr
), nam
->sa_len
));
2209 auth_len
= ((((cred
->cr_ngroups
- 1) > nmp
->nm_numgrps
) ?
2210 nmp
->nm_numgrps
: (cred
->cr_ngroups
- 1)) << 2) +
2212 timeo
= (nmp
->nm_flag
& NFSMNT_SOFT
) ? 10 : 60;
2213 nfsm_chain_null(&nmreq
);
2214 nfsm_chain_null(&nmrep
);
2216 /* check if we have a recently cached rquota port */
2217 if (nmp
->nm_rqport
) {
2219 if ((nmp
->nm_rqportstamp
+ 60) >= (uint32_t)now
.tv_sec
)
2223 /* send portmap request to get rquota port */
2224 saddr
.sin_port
= htons(PMAPPORT
);
2225 nfsm_chain_build_alloc_init(error
, &nmreq
, 4*NFSX_UNSIGNED
);
2226 nfsm_chain_add_32(error
, &nmreq
, RPCPROG_RQUOTA
);
2227 nfsm_chain_add_32(error
, &nmreq
, rqvers
);
2228 nfsm_chain_add_32(error
, &nmreq
, IPPROTO_UDP
);
2229 nfsm_chain_add_32(error
, &nmreq
, 0);
2230 nfsm_chain_build_done(error
, &nmreq
);
2232 error
= nfsm_rpchead2(SOCK_DGRAM
, PMAPPROG
, PMAPVERS
, PMAPPROC_GETPORT
,
2233 RPCAUTH_SYS
, auth_len
, cred
, NULL
, nmreq
.nmc_mhead
, &xid
, &mreq
);
2235 nmreq
.nmc_mhead
= NULL
;
2236 error
= nfs_aux_request(nmp
, thd
, &saddr
, mreq
, R_XID32(xid
), 0, timeo
, &nmrep
);
2239 /* grab rquota port from portmap response */
2240 nfsm_chain_get_32(error
, &nmrep
, val
);
2242 nmp
->nm_rqport
= val
;
2244 nmp
->nm_rqportstamp
= now
.tv_sec
;
2245 nfsm_chain_cleanup(&nmreq
);
2246 nfsm_chain_cleanup(&nmrep
);
2250 /* rquota request */
2251 saddr
.sin_port
= htons(nmp
->nm_rqport
);
2252 path
= &vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
[0];
2253 while (*path
&& (*path
!= '/'))
2255 slen
= strlen(path
);
2256 nfsm_chain_build_alloc_init(error
, &nmreq
, 3 * NFSX_UNSIGNED
+ nfsm_rndup(slen
));
2257 nfsm_chain_add_string(error
, &nmreq
, path
, slen
);
2258 if (type
== GRPQUOTA
)
2259 nfsm_chain_add_32(error
, &nmreq
, type
);
2260 nfsm_chain_add_32(error
, &nmreq
, id
);
2261 nfsm_chain_build_done(error
, &nmreq
);
2263 error
= nfsm_rpchead2(SOCK_DGRAM
, RPCPROG_RQUOTA
, rqvers
, RPCRQUOTA_GET
,
2264 RPCAUTH_SYS
, auth_len
, cred
, NULL
, nmreq
.nmc_mhead
, &xid
, &mreq
);
2266 nmreq
.nmc_mhead
= NULL
;
2267 error
= nfs_aux_request(nmp
, thd
, &saddr
, mreq
, R_XID32(xid
), 0, timeo
, &nmrep
);
2270 /* parse rquota response */
2271 nfsm_chain_get_32(error
, &nmrep
, val
);
2272 if (!error
&& (val
!= RQUOTA_STAT_OK
)) {
2273 if (val
== RQUOTA_STAT_NOQUOTA
)
2275 else if (val
== RQUOTA_STAT_EPERM
)
2280 nfsm_chain_get_32(error
, &nmrep
, bsize
);
2281 nfsm_chain_adv(error
, &nmrep
, NFSX_UNSIGNED
);
2282 nfsm_chain_get_32(error
, &nmrep
, val
);
2284 dqb
->dqb_bhardlimit
= (uint64_t)val
* bsize
;
2285 nfsm_chain_get_32(error
, &nmrep
, val
);
2287 dqb
->dqb_bsoftlimit
= (uint64_t)val
* bsize
;
2288 nfsm_chain_get_32(error
, &nmrep
, val
);
2290 dqb
->dqb_curbytes
= (uint64_t)val
* bsize
;
2291 nfsm_chain_get_32(error
, &nmrep
, dqb
->dqb_ihardlimit
);
2292 nfsm_chain_get_32(error
, &nmrep
, dqb
->dqb_isoftlimit
);
2293 nfsm_chain_get_32(error
, &nmrep
, dqb
->dqb_curinodes
);
2294 nfsm_chain_get_32(error
, &nmrep
, dqb
->dqb_btime
);
2295 nfsm_chain_get_32(error
, &nmrep
, dqb
->dqb_itime
);
2299 nfsm_chain_cleanup(&nmreq
);
2300 nfsm_chain_cleanup(&nmrep
);
2305 nfs4_getquota(struct nfsmount
*nmp
, vfs_context_t ctx
, uid_t id
, int type
, struct dqblk
*dqb
)
2308 int error
= 0, status
, nfsvers
, numops
;
2310 struct nfsm_chain nmreq
, nmrep
;
2311 uint32_t bitmap
[NFS_ATTR_BITMAP_LEN
];
2312 thread_t thd
= vfs_context_thread(ctx
);
2313 kauth_cred_t cred
= vfs_context_ucred(ctx
);
2315 if (type
!= USRQUOTA
) /* NFSv4 only supports user quotas */
2318 /* first check that the server supports any of the quota attributes */
2319 if (!NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_QUOTA_AVAIL_HARD
) &&
2320 !NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_QUOTA_AVAIL_SOFT
) &&
2321 !NFS_BITMAP_ISSET(nmp
->nm_fsattr
.nfsa_supp_attr
, NFS_FATTR_QUOTA_USED
))
2325 * The credential passed to the server needs to have
2326 * an effective uid that matches the given uid.
2328 if (id
!= kauth_cred_getuid(cred
)) {
2329 struct ucred temp_cred
;
2330 bzero(&temp_cred
, sizeof(temp_cred
));
2331 temp_cred
.cr_uid
= id
;
2332 temp_cred
.cr_ngroups
= cred
->cr_ngroups
;
2333 bcopy(cred
->cr_groups
, temp_cred
.cr_groups
, sizeof(temp_cred
.cr_groups
));
2334 cred
= kauth_cred_create(&temp_cred
);
2335 if (!IS_VALID_CRED(cred
))
2338 kauth_cred_ref(cred
);
2341 nfsvers
= nmp
->nm_vers
;
2345 if (error
|| ((error
= vnode_get(NFSTOV(np
))))) {
2346 kauth_cred_unref(&cred
);
2350 nfsm_chain_null(&nmreq
);
2351 nfsm_chain_null(&nmrep
);
2355 nfsm_chain_build_alloc_init(error
, &nmreq
, 15 * NFSX_UNSIGNED
);
2356 nfsm_chain_add_compound_header(error
, &nmreq
, "quota", numops
);
2358 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
2359 nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, np
->n_fhp
, np
->n_fhsize
);
2361 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
2362 NFS_CLEAR_ATTRIBUTES(bitmap
);
2363 NFS_BITMAP_SET(bitmap
, NFS_FATTR_QUOTA_AVAIL_HARD
);
2364 NFS_BITMAP_SET(bitmap
, NFS_FATTR_QUOTA_AVAIL_SOFT
);
2365 NFS_BITMAP_SET(bitmap
, NFS_FATTR_QUOTA_USED
);
2366 nfsm_chain_add_bitmap_masked(error
, &nmreq
, bitmap
,
2367 NFS_ATTR_BITMAP_LEN
, nmp
->nm_fsattr
.nfsa_supp_attr
);
2368 nfsm_chain_build_done(error
, &nmreq
);
2369 nfsm_assert(error
, (numops
== 0), EPROTO
);
2371 error
= nfs_request2(np
, NULL
, &nmreq
, NFSPROC4_COMPOUND
, thd
, cred
, 0, &nmrep
, &xid
, &status
);
2372 nfsm_chain_skip_tag(error
, &nmrep
);
2373 nfsm_chain_get_32(error
, &nmrep
, numops
);
2374 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
2375 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
2376 nfsm_assert(error
, NFSTONMP(np
), ENXIO
);
2378 error
= nfs4_parsefattr(&nmrep
, NULL
, NULL
, NULL
, dqb
);
2380 nfsm_assert(error
, NFSTONMP(np
), ENXIO
);
2382 nfsm_chain_cleanup(&nmreq
);
2383 nfsm_chain_cleanup(&nmrep
);
2384 vnode_put(NFSTOV(np
));
2385 kauth_cred_unref(&cred
);
2390 nfs_vfs_quotactl(mount_t mp
, int cmds
, uid_t uid
, caddr_t datap
, vfs_context_t ctx
)
2392 struct nfsmount
*nmp
;
2393 int cmd
, type
, error
, nfsvers
;
2394 uid_t ruid
= vfs_context_ucred(ctx
)->cr_ruid
;
2395 struct dqblk
*dqb
= (struct dqblk
*)datap
;
2397 if (!(nmp
= VFSTONFS(mp
)))
2399 nfsvers
= nmp
->nm_vers
;
2404 /* we can only support Q_GETQUOTA */
2405 cmd
= cmds
>> SUBCMDSHIFT
;
2420 type
= cmds
& SUBCMDMASK
;
2421 if ((u_int
)type
>= MAXQUOTAS
)
2423 if ((uid
!= ruid
) && ((error
= vfs_context_suser(ctx
))))
2426 if (vfs_busy(mp
, LK_NOWAIT
))
2428 bzero(dqb
, sizeof(*dqb
));
2429 error
= nmp
->nm_funcs
->nf_getquota(nmp
, ctx
, uid
, type
, dqb
);
2436 * Flush out the buffer cache
2438 int nfs_sync_callout(vnode_t
, void *);
2440 struct nfs_sync_cargs
{
2447 nfs_sync_callout(vnode_t vp
, void *arg
)
2449 struct nfs_sync_cargs
*cargs
= (struct nfs_sync_cargs
*)arg
;
2452 if (LIST_EMPTY(&VTONFS(vp
)->n_dirtyblkhd
))
2453 return (VNODE_RETURNED
);
2454 if (VTONFS(vp
)->n_wrbusy
> 0)
2455 return (VNODE_RETURNED
);
2456 if (VTONFS(vp
)->n_bflag
& (NBFLUSHINPROG
|NBINVALINPROG
))
2457 return (VNODE_RETURNED
);
2459 error
= nfs_flush(VTONFS(vp
), cargs
->waitfor
, cargs
->thd
, 0);
2461 cargs
->error
= error
;
2463 return (VNODE_RETURNED
);
2467 nfs_vfs_sync(mount_t mp
, int waitfor
, vfs_context_t ctx
)
2469 struct nfs_sync_cargs cargs
;
2471 cargs
.waitfor
= waitfor
;
2472 cargs
.thd
= vfs_context_thread(ctx
);
2475 vnode_iterate(mp
, 0, nfs_sync_callout
, &cargs
);
2477 return (cargs
.error
);
2481 * NFS flat namespace lookup.
2482 * Currently unsupported.
2487 __unused mount_t mp
,
2488 __unused ino64_t ino
,
2489 __unused vnode_t
*vpp
,
2490 __unused vfs_context_t ctx
)
2497 * At this point, this should never happen
2502 __unused mount_t mp
,
2504 __unused
unsigned char *fhp
,
2505 __unused vnode_t
*vpp
,
2506 __unused vfs_context_t ctx
)
2513 * Vnode pointer to File handle, should never happen either
2518 __unused vnode_t vp
,
2519 __unused
int *fhlenp
,
2520 __unused
unsigned char *fhp
,
2521 __unused vfs_context_t ctx
)
2528 * Vfs start routine, a no-op.
2533 __unused mount_t mp
,
2535 __unused vfs_context_t ctx
)
2542 * Do that sysctl thang...
2545 nfs_vfs_sysctl(int *name
, u_int namelen
, user_addr_t oldp
, size_t *oldlenp
,
2546 user_addr_t newp
, size_t newlen
, vfs_context_t ctx
)
2548 int error
= 0, val
, softnobrowse
;
2549 struct sysctl_req
*req
= NULL
;
2550 union union_vfsidctl vc
;
2552 struct nfsmount
*nmp
= NULL
;
2554 boolean_t is_64_bit
;
2556 struct nfs_exportfs
*nxfs
;
2557 struct nfs_export
*nx
;
2558 struct nfs_active_user_list
*ulist
;
2559 struct nfs_export_stat_desc stat_desc
;
2560 struct nfs_export_stat_rec statrec
;
2561 struct nfs_user_stat_node
*unode
, *unode_next
;
2562 struct nfs_user_stat_desc ustat_desc
;
2563 struct nfs_user_stat_user_rec ustat_rec
;
2564 struct nfs_user_stat_path_rec upath_rec
;
2565 uint bytes_avail
, bytes_total
, recs_copied
;
2566 uint numExports
, totlen
, pos
, numRecs
, count
;
2567 #endif /* NFSSERVER */
2570 * All names at this level are terminal.
2573 return (ENOTDIR
); /* overloaded */
2575 is_64_bit
= vfs_context_is64bit(ctx
);
2577 /* common code for "new style" VFS_CTL sysctl, get the mount. */
2581 case VFS_CTL_NOLOCKS
:
2582 req
= CAST_DOWN(struct sysctl_req
*, oldp
);
2583 error
= SYSCTL_IN(req
, &vc
, is_64_bit
? sizeof(vc
.vc64
):sizeof(vc
.vc32
));
2586 mp
= vfs_getvfs(&vc
.vc32
.vc_fsid
); /* works for 32 and 64 */
2592 bzero(&vq
, sizeof(vq
));
2595 req
->newptr
= vc
.vc64
.vc_ptr
;
2596 req
->newlen
= (size_t)vc
.vc64
.vc_len
;
2598 req
->newptr
= CAST_USER_ADDR_T(vc
.vc32
.vc_ptr
);
2599 req
->newlen
= vc
.vc32
.vc_len
;
2606 *oldlenp
= sizeof nfsstats
;
2610 if (*oldlenp
< sizeof nfsstats
) {
2611 *oldlenp
= sizeof nfsstats
;
2615 error
= copyout(&nfsstats
, oldp
, sizeof nfsstats
);
2619 if (newp
&& newlen
!= sizeof nfsstats
)
2623 return copyin(newp
, &nfsstats
, sizeof nfsstats
);
2626 case NFS_EXPORTSTATS
:
2627 /* setup export stat descriptor */
2628 stat_desc
.rec_vers
= NFS_EXPORT_STAT_REC_VERSION
;
2630 if (!nfsrv_is_initialized()) {
2631 stat_desc
.rec_count
= 0;
2632 if (oldp
&& (*oldlenp
>= sizeof(struct nfs_export_stat_desc
)))
2633 error
= copyout(&stat_desc
, oldp
, sizeof(struct nfs_export_stat_desc
));
2634 *oldlenp
= sizeof(struct nfs_export_stat_desc
);
2638 /* Count the number of exported directories */
2639 lck_rw_lock_shared(&nfsrv_export_rwlock
);
2641 LIST_FOREACH(nxfs
, &nfsrv_exports
, nxfs_next
)
2642 LIST_FOREACH(nx
, &nxfs
->nxfs_exports
, nx_next
)
2645 /* update stat descriptor's export record count */
2646 stat_desc
.rec_count
= numExports
;
2648 /* calculate total size of required buffer */
2649 totlen
= sizeof(struct nfs_export_stat_desc
) + (numExports
* sizeof(struct nfs_export_stat_rec
));
2651 /* Check caller's buffer */
2653 lck_rw_done(&nfsrv_export_rwlock
);
2654 /* indicate required buffer len */
2659 /* We require the caller's buffer to be at least large enough to hold the descriptor */
2660 if (*oldlenp
< sizeof(struct nfs_export_stat_desc
)) {
2661 lck_rw_done(&nfsrv_export_rwlock
);
2662 /* indicate required buffer len */
2667 /* indicate required buffer len */
2670 /* check if export table is empty */
2672 lck_rw_done(&nfsrv_export_rwlock
);
2673 error
= copyout(&stat_desc
, oldp
, sizeof(struct nfs_export_stat_desc
));
2677 /* calculate how many actual export stat records fit into caller's buffer */
2678 numRecs
= (*oldlenp
- sizeof(struct nfs_export_stat_desc
)) / sizeof(struct nfs_export_stat_rec
);
2681 /* caller's buffer can only accomodate descriptor */
2682 lck_rw_done(&nfsrv_export_rwlock
);
2683 stat_desc
.rec_count
= 0;
2684 error
= copyout(&stat_desc
, oldp
, sizeof(struct nfs_export_stat_desc
));
2688 /* adjust to actual number of records to copyout to caller's buffer */
2689 if (numRecs
> numExports
)
2690 numRecs
= numExports
;
2692 /* set actual number of records we are returning */
2693 stat_desc
.rec_count
= numRecs
;
2695 /* first copy out the stat descriptor */
2697 error
= copyout(&stat_desc
, oldp
+ pos
, sizeof(struct nfs_export_stat_desc
));
2699 lck_rw_done(&nfsrv_export_rwlock
);
2702 pos
+= sizeof(struct nfs_export_stat_desc
);
2704 /* Loop through exported directories */
2706 LIST_FOREACH(nxfs
, &nfsrv_exports
, nxfs_next
) {
2707 LIST_FOREACH(nx
, &nxfs
->nxfs_exports
, nx_next
) {
2709 if (count
>= numRecs
)
2712 /* build exported filesystem path */
2713 snprintf(statrec
.path
, sizeof(statrec
.path
), "%s%s%s",
2714 nxfs
->nxfs_path
, ((nxfs
->nxfs_path
[1] && nx
->nx_path
[0]) ? "/" : ""),
2717 /* build the 64-bit export stat counters */
2718 statrec
.ops
= ((uint64_t)nx
->nx_stats
.ops
.hi
<< 32) |
2719 nx
->nx_stats
.ops
.lo
;
2720 statrec
.bytes_read
= ((uint64_t)nx
->nx_stats
.bytes_read
.hi
<< 32) |
2721 nx
->nx_stats
.bytes_read
.lo
;
2722 statrec
.bytes_written
= ((uint64_t)nx
->nx_stats
.bytes_written
.hi
<< 32) |
2723 nx
->nx_stats
.bytes_written
.lo
;
2724 error
= copyout(&statrec
, oldp
+ pos
, sizeof(statrec
));
2726 lck_rw_done(&nfsrv_export_rwlock
);
2729 /* advance buffer position */
2730 pos
+= sizeof(statrec
);
2733 lck_rw_done(&nfsrv_export_rwlock
);
2736 /* init structures used for copying out of kernel */
2737 ustat_desc
.rec_vers
= NFS_USER_STAT_REC_VERSION
;
2738 ustat_rec
.rec_type
= NFS_USER_STAT_USER_REC
;
2739 upath_rec
.rec_type
= NFS_USER_STAT_PATH_REC
;
2741 /* initialize counters */
2742 bytes_total
= sizeof(struct nfs_user_stat_desc
);
2743 bytes_avail
= *oldlenp
;
2746 if (!nfsrv_is_initialized()) /* NFS server not initialized, so no stats */
2749 /* reclaim old expired user nodes */
2750 nfsrv_active_user_list_reclaim();
2752 /* reserve space for the buffer descriptor */
2753 if (bytes_avail
>= sizeof(struct nfs_user_stat_desc
))
2754 bytes_avail
-= sizeof(struct nfs_user_stat_desc
);
2758 /* put buffer position past the buffer descriptor */
2759 pos
= sizeof(struct nfs_user_stat_desc
);
2761 /* Loop through exported directories */
2762 lck_rw_lock_shared(&nfsrv_export_rwlock
);
2763 LIST_FOREACH(nxfs
, &nfsrv_exports
, nxfs_next
) {
2764 LIST_FOREACH(nx
, &nxfs
->nxfs_exports
, nx_next
) {
2766 if (bytes_avail
>= sizeof(struct nfs_user_stat_path_rec
)) {
2767 snprintf(upath_rec
.path
, sizeof(upath_rec
.path
), "%s%s%s",
2768 nxfs
->nxfs_path
, ((nxfs
->nxfs_path
[1] && nx
->nx_path
[0]) ? "/" : ""),
2771 error
= copyout(&upath_rec
, oldp
+ pos
, sizeof(struct nfs_user_stat_path_rec
));
2777 pos
+= sizeof(struct nfs_user_stat_path_rec
);
2778 bytes_avail
-= sizeof(struct nfs_user_stat_path_rec
);
2782 /* Caller's buffer is exhausted */
2786 bytes_total
+= sizeof(struct nfs_user_stat_path_rec
);
2788 /* Scan through all user nodes of this export */
2789 ulist
= &nx
->nx_user_list
;
2790 lck_mtx_lock(&ulist
->user_mutex
);
2791 for (unode
= TAILQ_FIRST(&ulist
->user_lru
); unode
; unode
= unode_next
) {
2792 unode_next
= TAILQ_NEXT(unode
, lru_link
);
2794 /* copy out node if there is space */
2795 if (bytes_avail
>= sizeof(struct nfs_user_stat_user_rec
)) {
2796 /* prepare a user stat rec for copying out */
2797 ustat_rec
.uid
= unode
->uid
;
2798 bcopy(&unode
->sock
, &ustat_rec
.sock
, unode
->sock
.ss_len
);
2799 ustat_rec
.ops
= unode
->ops
;
2800 ustat_rec
.bytes_read
= unode
->bytes_read
;
2801 ustat_rec
.bytes_written
= unode
->bytes_written
;
2802 ustat_rec
.tm_start
= unode
->tm_start
;
2803 ustat_rec
.tm_last
= unode
->tm_last
;
2805 error
= copyout(&ustat_rec
, oldp
+ pos
, sizeof(struct nfs_user_stat_user_rec
));
2809 lck_mtx_unlock(&ulist
->user_mutex
);
2813 pos
+= sizeof(struct nfs_user_stat_user_rec
);
2814 bytes_avail
-= sizeof(struct nfs_user_stat_user_rec
);
2818 /* Caller's buffer is exhausted */
2821 bytes_total
+= sizeof(struct nfs_user_stat_user_rec
);
2823 /* can unlock this export's list now */
2824 lck_mtx_unlock(&ulist
->user_mutex
);
2829 /* unlock the export table */
2830 lck_rw_done(&nfsrv_export_rwlock
);
2833 /* indicate number of actual records copied */
2834 ustat_desc
.rec_count
= recs_copied
;
2837 /* check if there was enough room for the buffer descriptor */
2838 if (*oldlenp
>= sizeof(struct nfs_user_stat_desc
))
2839 error
= copyout(&ustat_desc
, oldp
, sizeof(struct nfs_user_stat_desc
));
2843 /* always indicate required buffer size */
2844 *oldlenp
= bytes_total
;
2849 *oldlenp
= sizeof(nfsrv_user_stat_node_count
);
2853 if (*oldlenp
< sizeof(nfsrv_user_stat_node_count
)) {
2854 *oldlenp
= sizeof(nfsrv_user_stat_node_count
);
2858 if (nfsrv_is_initialized()) {
2859 /* reclaim old expired user nodes */
2860 nfsrv_active_user_list_reclaim();
2863 error
= copyout(&nfsrv_user_stat_node_count
, oldp
, sizeof(nfsrv_user_stat_node_count
));
2865 #endif /* NFSSERVER */
2866 case VFS_CTL_NOLOCKS
:
2867 if (req
->oldptr
!= USER_ADDR_NULL
) {
2868 lck_mtx_lock(&nmp
->nm_lock
);
2869 val
= (nmp
->nm_flag
& NFSMNT_NOLOCKS
) ? 1 : 0;
2870 lck_mtx_unlock(&nmp
->nm_lock
);
2871 error
= SYSCTL_OUT(req
, &val
, sizeof(val
));
2875 if (req
->newptr
!= USER_ADDR_NULL
) {
2876 error
= SYSCTL_IN(req
, &val
, sizeof(val
));
2879 lck_mtx_lock(&nmp
->nm_lock
);
2880 if (nmp
->nm_flag
& NFSMNT_LOCALLOCKS
) {
2881 /* can't toggle locks when using local locks */
2884 if (!(nmp
->nm_flag
& NFSMNT_NOLOCKS
))
2885 nfs_lockd_mount_change(-1);
2886 nmp
->nm_flag
|= NFSMNT_NOLOCKS
;
2887 nmp
->nm_state
&= ~NFSSTA_LOCKTIMEO
;
2889 if (nmp
->nm_flag
& NFSMNT_NOLOCKS
)
2890 nfs_lockd_mount_change(1);
2891 nmp
->nm_flag
&= ~NFSMNT_NOLOCKS
;
2893 lck_mtx_unlock(&nmp
->nm_lock
);
2897 lck_mtx_lock(&nmp
->nm_lock
);
2898 /* XXX don't allow users to know about/disconnect unresponsive, soft, nobrowse mounts */
2899 softnobrowse
= ((nmp
->nm_flag
& NFSMNT_SOFT
) && (vfs_flags(nmp
->nm_mountp
) & MNT_DONTBROWSE
));
2900 if (!softnobrowse
&& (nmp
->nm_state
& NFSSTA_TIMEO
))
2901 vq
.vq_flags
|= VQ_NOTRESP
;
2902 if (!softnobrowse
&& (nmp
->nm_state
& NFSSTA_JUKEBOXTIMEO
) &&
2903 !(nmp
->nm_flag
& NFSMNT_MUTEJUKEBOX
))
2904 vq
.vq_flags
|= VQ_NOTRESP
;
2905 if (!softnobrowse
&& (nmp
->nm_state
& NFSSTA_LOCKTIMEO
) &&
2906 !(nmp
->nm_flag
& (NFSMNT_NOLOCKS
|NFSMNT_LOCALLOCKS
)))
2907 vq
.vq_flags
|= VQ_NOTRESP
;
2908 if (nmp
->nm_state
& NFSSTA_DEAD
)
2909 vq
.vq_flags
|= VQ_DEAD
;
2910 lck_mtx_unlock(&nmp
->nm_lock
);
2911 error
= SYSCTL_OUT(req
, &vq
, sizeof(vq
));
2914 if (req
->oldptr
!= USER_ADDR_NULL
) {
2915 lck_mtx_lock(&nmp
->nm_lock
);
2916 val
= nmp
->nm_tprintf_initial_delay
;
2917 lck_mtx_unlock(&nmp
->nm_lock
);
2918 error
= SYSCTL_OUT(req
, &val
, sizeof(val
));
2922 if (req
->newptr
!= USER_ADDR_NULL
) {
2923 error
= SYSCTL_IN(req
, &val
, sizeof(val
));
2926 lck_mtx_lock(&nmp
->nm_lock
);
2928 nmp
->nm_tprintf_initial_delay
= 0;
2930 nmp
->nm_tprintf_initial_delay
= val
;
2931 lck_mtx_unlock(&nmp
->nm_lock
);