xref: /freebsd-src/sys/fs/nfsclient/nfs_clvfsops.c (revision 52d895fe63eb22c1265362c54983db6038ebea3c)
19ec7b004SRick Macklem /*-
251369649SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
351369649SPedro F. Giffuni  *
49ec7b004SRick Macklem  * Copyright (c) 1989, 1993, 1995
59ec7b004SRick Macklem  *	The Regents of the University of California.  All rights reserved.
69ec7b004SRick Macklem  *
79ec7b004SRick Macklem  * This code is derived from software contributed to Berkeley by
89ec7b004SRick Macklem  * Rick Macklem at The University of Guelph.
99ec7b004SRick Macklem  *
109ec7b004SRick Macklem  * Redistribution and use in source and binary forms, with or without
119ec7b004SRick Macklem  * modification, are permitted provided that the following conditions
129ec7b004SRick Macklem  * are met:
139ec7b004SRick Macklem  * 1. Redistributions of source code must retain the above copyright
149ec7b004SRick Macklem  *    notice, this list of conditions and the following disclaimer.
159ec7b004SRick Macklem  * 2. Redistributions in binary form must reproduce the above copyright
169ec7b004SRick Macklem  *    notice, this list of conditions and the following disclaimer in the
179ec7b004SRick Macklem  *    documentation and/or other materials provided with the distribution.
18fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
199ec7b004SRick Macklem  *    may be used to endorse or promote products derived from this software
209ec7b004SRick Macklem  *    without specific prior written permission.
219ec7b004SRick Macklem  *
229ec7b004SRick Macklem  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
239ec7b004SRick Macklem  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
249ec7b004SRick Macklem  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
259ec7b004SRick Macklem  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
269ec7b004SRick Macklem  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
279ec7b004SRick Macklem  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
289ec7b004SRick Macklem  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
299ec7b004SRick Macklem  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
309ec7b004SRick Macklem  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
319ec7b004SRick Macklem  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
329ec7b004SRick Macklem  * SUCH DAMAGE.
339ec7b004SRick Macklem  *
349ec7b004SRick Macklem  *	from nfs_vfsops.c	8.12 (Berkeley) 5/20/95
359ec7b004SRick Macklem  */
369ec7b004SRick Macklem 
379ec7b004SRick Macklem #include <sys/cdefs.h>
389ec7b004SRick Macklem #include "opt_bootp.h"
399ec7b004SRick Macklem #include "opt_nfsroot.h"
406e4b6ff8SRick Macklem #include "opt_kern_tls.h"
419ec7b004SRick Macklem 
429ec7b004SRick Macklem #include <sys/param.h>
439ec7b004SRick Macklem #include <sys/systm.h>
449ec7b004SRick Macklem #include <sys/kernel.h>
459ec7b004SRick Macklem #include <sys/bio.h>
469ec7b004SRick Macklem #include <sys/buf.h>
479ec7b004SRick Macklem #include <sys/clock.h>
4876ca6f88SJamie Gritton #include <sys/jail.h>
498e82d541SRick Macklem #include <sys/limits.h>
509ec7b004SRick Macklem #include <sys/lock.h>
519ec7b004SRick Macklem #include <sys/malloc.h>
529ec7b004SRick Macklem #include <sys/mbuf.h>
539ec7b004SRick Macklem #include <sys/mount.h>
549ec7b004SRick Macklem #include <sys/proc.h>
559ec7b004SRick Macklem #include <sys/socket.h>
569ec7b004SRick Macklem #include <sys/socketvar.h>
579ec7b004SRick Macklem #include <sys/sockio.h>
589ec7b004SRick Macklem #include <sys/sysctl.h>
599ec7b004SRick Macklem #include <sys/vnode.h>
609ec7b004SRick Macklem #include <sys/signalvar.h>
619ec7b004SRick Macklem 
629ec7b004SRick Macklem #include <vm/vm.h>
639ec7b004SRick Macklem #include <vm/vm_extern.h>
649ec7b004SRick Macklem #include <vm/uma.h>
659ec7b004SRick Macklem 
669ec7b004SRick Macklem #include <net/if.h>
679ec7b004SRick Macklem #include <net/route.h>
68e1c05fd2SAlexander V. Chernikov #include <net/route/route_ctl.h>
699ec7b004SRick Macklem #include <netinet/in.h>
709ec7b004SRick Macklem 
719ec7b004SRick Macklem #include <fs/nfs/nfsport.h>
729ec7b004SRick Macklem #include <fs/nfsclient/nfsnode.h>
739ec7b004SRick Macklem #include <fs/nfsclient/nfsmount.h>
749ec7b004SRick Macklem #include <fs/nfsclient/nfs.h>
758954032fSRick Macklem #include <nfs/nfsdiskless.h>
769ec7b004SRick Macklem 
776e4b6ff8SRick Macklem #include <rpc/rpcsec_tls.h>
786e4b6ff8SRick Macklem 
79de5b1952SAlexander Leidinger FEATURE(nfscl, "NFSv4 client");
80de5b1952SAlexander Leidinger 
819ec7b004SRick Macklem extern int nfscl_ticks;
829ec7b004SRick Macklem extern struct timeval nfsboottime;
83484c842dSRick Macklem extern int nfsrv_useacl;
841f60bfd8SRick Macklem extern int nfscl_debuglevel;
8564a0e848SRick Macklem extern enum nfsiod_state ncl_iodwant[NFS_MAXASYNCDAEMON];
8664a0e848SRick Macklem extern struct nfsmount *ncl_iodmount[NFS_MAXASYNCDAEMON];
8764a0e848SRick Macklem extern struct mtx ncl_iod_mutex;
881f60bfd8SRick Macklem NFSCLSTATEMUTEX;
8990d2dfabSRick Macklem extern struct mtx nfsrv_dslock_mtx;
909ec7b004SRick Macklem 
9150a220c6SEdward Tomasz Napierala MALLOC_DEFINE(M_NEWNFSREQ, "newnfsclient_req", "NFS request header");
9250a220c6SEdward Tomasz Napierala MALLOC_DEFINE(M_NEWNFSMNT, "newnfsmnt", "NFS mount struct");
939ec7b004SRick Macklem 
941f376590SRick Macklem SYSCTL_DECL(_vfs_nfs);
959ec7b004SRick Macklem static int nfs_ip_paranoia = 1;
961f376590SRick Macklem SYSCTL_INT(_vfs_nfs, OID_AUTO, nfs_ip_paranoia, CTLFLAG_RW,
979ec7b004SRick Macklem     &nfs_ip_paranoia, 0, "");
989ec7b004SRick Macklem static int nfs_tprintf_initial_delay = NFS_TPRINTF_INITIAL_DELAY;
991f376590SRick Macklem SYSCTL_INT(_vfs_nfs, NFS_TPRINTF_INITIAL_DELAY,
1009ec7b004SRick Macklem         downdelayinitial, CTLFLAG_RW, &nfs_tprintf_initial_delay, 0, "");
1019ec7b004SRick Macklem /* how long between console messages "nfs server foo not responding" */
1029ec7b004SRick Macklem static int nfs_tprintf_delay = NFS_TPRINTF_DELAY;
1031f376590SRick Macklem SYSCTL_INT(_vfs_nfs, NFS_TPRINTF_DELAY,
1049ec7b004SRick Macklem         downdelayinterval, CTLFLAG_RW, &nfs_tprintf_delay, 0, "");
10562c23db9SRick Macklem #ifdef NFS_DEBUG
10662c23db9SRick Macklem int nfs_debug;
10762c23db9SRick Macklem SYSCTL_INT(_vfs_nfs, OID_AUTO, debug, CTLFLAG_RW, &nfs_debug, 0,
10862c23db9SRick Macklem     "Toggle debug flag");
10962c23db9SRick Macklem #endif
1109ec7b004SRick Macklem 
1118954032fSRick Macklem static int	nfs_mountroot(struct mount *);
112682eec57SRick Macklem static void	nfs_sec_name(char *, int *);
1139ec7b004SRick Macklem static void	nfs_decode_args(struct mount *mp, struct nfsmount *nmp,
114ca27c028SRick Macklem 		    struct nfs_args *argp, const char *, struct ucred *,
115ca27c028SRick Macklem 		    struct thread *);
1169ec7b004SRick Macklem static int	mountnfs(struct nfs_args *, struct mount *,
117385edc8eSRick Macklem 		    struct sockaddr *, char *, u_char *, int, u_char *, int,
118385edc8eSRick Macklem 		    u_char *, int, struct vnode **, struct ucred *,
1191e0a518dSRick Macklem 		    struct thread *, int, int, int, uint32_t, char *, int);
1204d4f9a37SRick Macklem static void	nfs_getnlminfo(struct vnode *, uint8_t *, size_t *,
12190305aa3SRick Macklem 		    struct sockaddr_storage *, int *, off_t *,
12290305aa3SRick Macklem 		    struct timeval *);
1239ec7b004SRick Macklem static vfs_mount_t nfs_mount;
1249ec7b004SRick Macklem static vfs_cmount_t nfs_cmount;
1259ec7b004SRick Macklem static vfs_unmount_t nfs_unmount;
1269ec7b004SRick Macklem static vfs_root_t nfs_root;
1279ec7b004SRick Macklem static vfs_statfs_t nfs_statfs;
1289ec7b004SRick Macklem static vfs_sync_t nfs_sync;
1299ec7b004SRick Macklem static vfs_sysctl_t nfs_sysctl;
1308fe6bddfSRick Macklem static vfs_purge_t nfs_purge;
1319ec7b004SRick Macklem 
1329ec7b004SRick Macklem /*
1339ec7b004SRick Macklem  * nfs vfs operations.
1349ec7b004SRick Macklem  */
1359ec7b004SRick Macklem static struct vfsops nfs_vfsops = {
1369ec7b004SRick Macklem 	.vfs_init =		ncl_init,
1379ec7b004SRick Macklem 	.vfs_mount =		nfs_mount,
1389ec7b004SRick Macklem 	.vfs_cmount =		nfs_cmount,
139d511f93eSMateusz Guzik 	.vfs_root =		vfs_cache_root,
140d511f93eSMateusz Guzik 	.vfs_cachedroot =	nfs_root,
1419ec7b004SRick Macklem 	.vfs_statfs =		nfs_statfs,
1429ec7b004SRick Macklem 	.vfs_sync =		nfs_sync,
1439ec7b004SRick Macklem 	.vfs_uninit =		ncl_uninit,
1449ec7b004SRick Macklem 	.vfs_unmount =		nfs_unmount,
1459ec7b004SRick Macklem 	.vfs_sysctl =		nfs_sysctl,
1468fe6bddfSRick Macklem 	.vfs_purge =		nfs_purge,
1479ec7b004SRick Macklem };
148cb07628dSRick Macklem /*
149cb07628dSRick Macklem  * This macro declares that the file system type is named "nfs".
150cb07628dSRick Macklem  * It also declares a module name of "nfs" and uses vfs_modevent()
151cb07628dSRick Macklem  * as the event handling function.
152cb07628dSRick Macklem  * The main module declaration is found in sys/fs/nfsclient/nfs_clport.c
153cb07628dSRick Macklem  * for "nfscl" and is needed so that a custom event handling
154cb07628dSRick Macklem  * function gets called.  MODULE_DEPEND() macros are found there.
155cb07628dSRick Macklem  */
156593efaf9SJohn Baldwin VFS_SET(nfs_vfsops, nfs, VFCF_NETWORK | VFCF_SBDRY);
1579ec7b004SRick Macklem 
158afea7465SRick Macklem MODULE_VERSION(nfs, 1);
1599ec7b004SRick Macklem 
1609ec7b004SRick Macklem /*
161541cb7a3SRick Macklem  * This structure is now defined in sys/nfs/nfs_diskless.c so that it
162541cb7a3SRick Macklem  * can be shared by both NFS clients. It is declared here so that it
163541cb7a3SRick Macklem  * will be defined for kernels built without NFS_ROOT, although it
164541cb7a3SRick Macklem  * isn't used in that case.
1659ec7b004SRick Macklem  */
166c15882f0SRick Macklem #if !defined(NFS_ROOT)
167541cb7a3SRick Macklem struct nfs_diskless	nfs_diskless = { { { 0 } } };
168541cb7a3SRick Macklem struct nfsv3_diskless	nfsv3_diskless = { { { 0 } } };
169541cb7a3SRick Macklem int			nfs_diskless_valid = 0;
170541cb7a3SRick Macklem #endif
171541cb7a3SRick Macklem 
1721f376590SRick Macklem SYSCTL_INT(_vfs_nfs, OID_AUTO, diskless_valid, CTLFLAG_RD,
1738954032fSRick Macklem     &nfs_diskless_valid, 0,
174d34b41c9SRick Macklem     "Has the diskless struct been filled correctly");
1759ec7b004SRick Macklem 
1761f376590SRick Macklem SYSCTL_STRING(_vfs_nfs, OID_AUTO, diskless_rootpath, CTLFLAG_RD,
1778954032fSRick Macklem     nfsv3_diskless.root_hostnam, 0, "Path to nfs root");
1789ec7b004SRick Macklem 
1791f376590SRick Macklem SYSCTL_OPAQUE(_vfs_nfs, OID_AUTO, diskless_rootaddr, CTLFLAG_RD,
1808954032fSRick Macklem     &nfsv3_diskless.root_saddr, sizeof(nfsv3_diskless.root_saddr),
181d34b41c9SRick Macklem     "%Ssockaddr_in", "Diskless root nfs address");
1829ec7b004SRick Macklem 
1839ec7b004SRick Macklem void		newnfsargs_ntoh(struct nfs_args *);
1849ec7b004SRick Macklem static int	nfs_mountdiskless(char *,
1859ec7b004SRick Macklem 		    struct sockaddr_in *, struct nfs_args *,
1869ec7b004SRick Macklem 		    struct thread *, struct vnode **, struct mount *);
1879ec7b004SRick Macklem static void	nfs_convert_diskless(void);
1889ec7b004SRick Macklem static void	nfs_convert_oargs(struct nfs_args *args,
1899ec7b004SRick Macklem 		    struct onfs_args *oargs);
1909ec7b004SRick Macklem 
1919ec7b004SRick Macklem int
1929ec7b004SRick Macklem newnfs_iosize(struct nfsmount *nmp)
1939ec7b004SRick Macklem {
1949ec7b004SRick Macklem 	int iosize, maxio;
1959ec7b004SRick Macklem 
1969ec7b004SRick Macklem 	/* First, set the upper limit for iosize */
1979ec7b004SRick Macklem 	if (nmp->nm_flag & NFSMNT_NFSV4) {
1989ec7b004SRick Macklem 		maxio = NFS_MAXBSIZE;
1999ec7b004SRick Macklem 	} else if (nmp->nm_flag & NFSMNT_NFSV3) {
2009ec7b004SRick Macklem 		if (nmp->nm_sotype == SOCK_DGRAM)
2019ec7b004SRick Macklem 			maxio = NFS_MAXDGRAMDATA;
2029ec7b004SRick Macklem 		else
2039ec7b004SRick Macklem 			maxio = NFS_MAXBSIZE;
2049ec7b004SRick Macklem 	} else {
2059ec7b004SRick Macklem 		maxio = NFS_V2MAXDATA;
2069ec7b004SRick Macklem 	}
2079ec7b004SRick Macklem 	if (nmp->nm_rsize > maxio || nmp->nm_rsize == 0)
2089ec7b004SRick Macklem 		nmp->nm_rsize = maxio;
2097cfdc2a7SRick Macklem 	if (nmp->nm_rsize > NFS_MAXBSIZE)
2107cfdc2a7SRick Macklem 		nmp->nm_rsize = NFS_MAXBSIZE;
2119ec7b004SRick Macklem 	if (nmp->nm_readdirsize > maxio || nmp->nm_readdirsize == 0)
2129ec7b004SRick Macklem 		nmp->nm_readdirsize = maxio;
2139ec7b004SRick Macklem 	if (nmp->nm_readdirsize > nmp->nm_rsize)
2149ec7b004SRick Macklem 		nmp->nm_readdirsize = nmp->nm_rsize;
2159ec7b004SRick Macklem 	if (nmp->nm_wsize > maxio || nmp->nm_wsize == 0)
2169ec7b004SRick Macklem 		nmp->nm_wsize = maxio;
2177cfdc2a7SRick Macklem 	if (nmp->nm_wsize > NFS_MAXBSIZE)
2187cfdc2a7SRick Macklem 		nmp->nm_wsize = NFS_MAXBSIZE;
2199ec7b004SRick Macklem 
2209ec7b004SRick Macklem 	/*
2219ec7b004SRick Macklem 	 * Calculate the size used for io buffers.  Use the larger
2229ec7b004SRick Macklem 	 * of the two sizes to minimise nfs requests but make sure
2239ec7b004SRick Macklem 	 * that it is at least one VM page to avoid wasting buffer
224f3153834SRick Macklem 	 * space.  It must also be at least NFS_DIRBLKSIZ, since
225f3153834SRick Macklem 	 * that is the buffer size used for directories.
2269ec7b004SRick Macklem 	 */
2279ec7b004SRick Macklem 	iosize = imax(nmp->nm_rsize, nmp->nm_wsize);
2289ec7b004SRick Macklem 	iosize = imax(iosize, PAGE_SIZE);
229f3153834SRick Macklem 	iosize = imax(iosize, NFS_DIRBLKSIZ);
2309ec7b004SRick Macklem 	nmp->nm_mountp->mnt_stat.f_iosize = iosize;
2319ec7b004SRick Macklem 	return (iosize);
2329ec7b004SRick Macklem }
2339ec7b004SRick Macklem 
2349ec7b004SRick Macklem static void
2359ec7b004SRick Macklem nfs_convert_oargs(struct nfs_args *args, struct onfs_args *oargs)
2369ec7b004SRick Macklem {
2379ec7b004SRick Macklem 
2389ec7b004SRick Macklem 	args->version = NFS_ARGSVERSION;
2399ec7b004SRick Macklem 	args->addr = oargs->addr;
2409ec7b004SRick Macklem 	args->addrlen = oargs->addrlen;
2419ec7b004SRick Macklem 	args->sotype = oargs->sotype;
2429ec7b004SRick Macklem 	args->proto = oargs->proto;
2439ec7b004SRick Macklem 	args->fh = oargs->fh;
2449ec7b004SRick Macklem 	args->fhsize = oargs->fhsize;
2459ec7b004SRick Macklem 	args->flags = oargs->flags;
2469ec7b004SRick Macklem 	args->wsize = oargs->wsize;
2479ec7b004SRick Macklem 	args->rsize = oargs->rsize;
2489ec7b004SRick Macklem 	args->readdirsize = oargs->readdirsize;
2499ec7b004SRick Macklem 	args->timeo = oargs->timeo;
2509ec7b004SRick Macklem 	args->retrans = oargs->retrans;
2519ec7b004SRick Macklem 	args->readahead = oargs->readahead;
2529ec7b004SRick Macklem 	args->hostname = oargs->hostname;
2539ec7b004SRick Macklem }
2549ec7b004SRick Macklem 
2559ec7b004SRick Macklem static void
2569ec7b004SRick Macklem nfs_convert_diskless(void)
2579ec7b004SRick Macklem {
2589ec7b004SRick Macklem 
2598954032fSRick Macklem 	bcopy(&nfs_diskless.myif, &nfsv3_diskless.myif,
2609ec7b004SRick Macklem 		sizeof(struct ifaliasreq));
2618954032fSRick Macklem 	bcopy(&nfs_diskless.mygateway, &nfsv3_diskless.mygateway,
2629ec7b004SRick Macklem 		sizeof(struct sockaddr_in));
2638954032fSRick Macklem 	nfs_convert_oargs(&nfsv3_diskless.root_args,&nfs_diskless.root_args);
2648954032fSRick Macklem 	if (nfsv3_diskless.root_args.flags & NFSMNT_NFSV3) {
2658954032fSRick Macklem 		nfsv3_diskless.root_fhsize = NFSX_MYFH;
2668954032fSRick Macklem 		bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_MYFH);
2679ec7b004SRick Macklem 	} else {
2688954032fSRick Macklem 		nfsv3_diskless.root_fhsize = NFSX_V2FH;
2698954032fSRick Macklem 		bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_V2FH);
2709ec7b004SRick Macklem 	}
2718954032fSRick Macklem 	bcopy(&nfs_diskless.root_saddr,&nfsv3_diskless.root_saddr,
2729ec7b004SRick Macklem 		sizeof(struct sockaddr_in));
2738954032fSRick Macklem 	bcopy(nfs_diskless.root_hostnam, nfsv3_diskless.root_hostnam, MNAMELEN);
2748954032fSRick Macklem 	nfsv3_diskless.root_time = nfs_diskless.root_time;
2758954032fSRick Macklem 	bcopy(nfs_diskless.my_hostnam, nfsv3_diskless.my_hostnam,
2769ec7b004SRick Macklem 		MAXHOSTNAMELEN);
2778954032fSRick Macklem 	nfs_diskless_valid = 3;
2789ec7b004SRick Macklem }
2799ec7b004SRick Macklem 
2809ec7b004SRick Macklem /*
2819ec7b004SRick Macklem  * nfs statfs call
2829ec7b004SRick Macklem  */
2839ec7b004SRick Macklem static int
284dfd233edSAttilio Rao nfs_statfs(struct mount *mp, struct statfs *sbp)
2859ec7b004SRick Macklem {
2869ec7b004SRick Macklem 	struct vnode *vp;
287dfd233edSAttilio Rao 	struct thread *td;
2889ec7b004SRick Macklem 	struct nfsmount *nmp = VFSTONFS(mp);
2899ec7b004SRick Macklem 	struct nfsvattr nfsva;
2909ec7b004SRick Macklem 	struct nfsfsinfo fs;
2919ec7b004SRick Macklem 	struct nfsstatfs sb;
2929ec7b004SRick Macklem 	int error = 0, attrflag, gotfsinfo = 0, ret;
2939ec7b004SRick Macklem 	struct nfsnode *np;
294896516e5SRick Macklem 	char *fakefh;
2959ec7b004SRick Macklem 
296dfd233edSAttilio Rao 	td = curthread;
297dfd233edSAttilio Rao 
2989ec7b004SRick Macklem 	error = vfs_busy(mp, MBF_NOWAIT);
2999ec7b004SRick Macklem 	if (error)
3009ec7b004SRick Macklem 		return (error);
301896516e5SRick Macklem 	if ((nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0) {
302896516e5SRick Macklem 		if (nmp->nm_fhsize == 0) {
303896516e5SRick Macklem 			error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp),
304896516e5SRick Macklem 			    td->td_ucred, td);
305896516e5SRick Macklem 			if (error != 0) {
306896516e5SRick Macklem 				/*
307896516e5SRick Macklem 				 * We cannot do anything yet.  Hopefully what
308896516e5SRick Macklem 				 * is in mnt_stat is sufficient.
309896516e5SRick Macklem 				 */
310896516e5SRick Macklem 				if (sbp != &mp->mnt_stat)
311896516e5SRick Macklem 					*sbp = mp->mnt_stat;
312896516e5SRick Macklem 				strncpy(&sbp->f_fstypename[0],
313896516e5SRick Macklem 				    mp->mnt_vfc->vfc_name, MFSNAMELEN);
314896516e5SRick Macklem 				vfs_unbusy(mp);
315896516e5SRick Macklem 				return (0);
316896516e5SRick Macklem 			}
317896516e5SRick Macklem 		}
318896516e5SRick Macklem 		fakefh = malloc(NFSX_FHMAX + 1, M_TEMP, M_WAITOK | M_ZERO);
319896516e5SRick Macklem 		error = ncl_nget(mp, fakefh, NFSX_FHMAX + 1, &np, LK_EXCLUSIVE);
320896516e5SRick Macklem 		free(fakefh, M_TEMP);
321896516e5SRick Macklem 	} else {
322896516e5SRick Macklem 		error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np,
323896516e5SRick Macklem 		    LK_EXCLUSIVE);
324896516e5SRick Macklem 	}
3259ec7b004SRick Macklem 	if (error) {
3269ec7b004SRick Macklem 		vfs_unbusy(mp);
3279ec7b004SRick Macklem 		return (error);
3289ec7b004SRick Macklem 	}
3299ec7b004SRick Macklem 	vp = NFSTOV(np);
3309ec7b004SRick Macklem 	mtx_lock(&nmp->nm_mtx);
3319ec7b004SRick Macklem 	if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) {
3329ec7b004SRick Macklem 		mtx_unlock(&nmp->nm_mtx);
3339ec7b004SRick Macklem 		error = nfsrpc_fsinfo(vp, &fs, td->td_ucred, td, &nfsva,
3341e70163cSRick Macklem 		    &attrflag);
3359ec7b004SRick Macklem 		if (!error)
3369ec7b004SRick Macklem 			gotfsinfo = 1;
3379ec7b004SRick Macklem 	} else
3389ec7b004SRick Macklem 		mtx_unlock(&nmp->nm_mtx);
3399ec7b004SRick Macklem 	if (!error)
340896516e5SRick Macklem 		error = nfsrpc_statfs(vp, &sb, &fs, NULL, td->td_ucred, td,
341896516e5SRick Macklem 		    &nfsva, &attrflag);
342896516e5SRick Macklem 	if ((nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0 &&
343896516e5SRick Macklem 	    error == NFSERR_WRONGSEC) {
344896516e5SRick Macklem 		/* Cannot get new stats, so return what is in mnt_stat. */
345896516e5SRick Macklem 		if (sbp != &mp->mnt_stat)
346896516e5SRick Macklem 			*sbp = mp->mnt_stat;
347896516e5SRick Macklem 		strncpy(&sbp->f_fstypename[0], mp->mnt_vfc->vfc_name,
348896516e5SRick Macklem 		    MFSNAMELEN);
349896516e5SRick Macklem 		vput(vp);
350896516e5SRick Macklem 		vfs_unbusy(mp);
351896516e5SRick Macklem 		return (0);
352896516e5SRick Macklem 	}
3531f60bfd8SRick Macklem 	if (error != 0)
3541f60bfd8SRick Macklem 		NFSCL_DEBUG(2, "statfs=%d\n", error);
3559ec7b004SRick Macklem 	if (attrflag == 0) {
3569ec7b004SRick Macklem 		ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1,
3571f60bfd8SRick Macklem 		    td->td_ucred, td, &nfsva, NULL, NULL);
3589ec7b004SRick Macklem 		if (ret) {
3599ec7b004SRick Macklem 			/*
3609ec7b004SRick Macklem 			 * Just set default values to get things going.
3619ec7b004SRick Macklem 			 */
3629ec7b004SRick Macklem 			NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr));
3639ec7b004SRick Macklem 			nfsva.na_vattr.va_type = VDIR;
3649ec7b004SRick Macklem 			nfsva.na_vattr.va_mode = 0777;
3659ec7b004SRick Macklem 			nfsva.na_vattr.va_nlink = 100;
3669ec7b004SRick Macklem 			nfsva.na_vattr.va_uid = (uid_t)0;
3679ec7b004SRick Macklem 			nfsva.na_vattr.va_gid = (gid_t)0;
3689ec7b004SRick Macklem 			nfsva.na_vattr.va_fileid = 2;
3699ec7b004SRick Macklem 			nfsva.na_vattr.va_gen = 1;
3709ec7b004SRick Macklem 			nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE;
3719ec7b004SRick Macklem 			nfsva.na_vattr.va_size = 512 * 1024;
3729ec7b004SRick Macklem 		}
3739ec7b004SRick Macklem 	}
3744ad3423bSRick Macklem 	(void) nfscl_loadattrcache(&vp, &nfsva, NULL, 0, 1);
3759ec7b004SRick Macklem 	if (!error) {
3769ec7b004SRick Macklem 	    mtx_lock(&nmp->nm_mtx);
3779ec7b004SRick Macklem 	    if (gotfsinfo || (nmp->nm_flag & NFSMNT_NFSV4))
3789ec7b004SRick Macklem 		nfscl_loadfsinfo(nmp, &fs);
3799ec7b004SRick Macklem 	    nfscl_loadsbinfo(nmp, &sb, sbp);
3809ec7b004SRick Macklem 	    sbp->f_iosize = newnfs_iosize(nmp);
3819ec7b004SRick Macklem 	    mtx_unlock(&nmp->nm_mtx);
3829ec7b004SRick Macklem 	    if (sbp != &mp->mnt_stat) {
3839ec7b004SRick Macklem 		bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
3849ec7b004SRick Macklem 		bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
3859ec7b004SRick Macklem 	    }
3869ec7b004SRick Macklem 	    strncpy(&sbp->f_fstypename[0], mp->mnt_vfc->vfc_name, MFSNAMELEN);
3879ec7b004SRick Macklem 	} else if (NFS_ISV4(vp)) {
3889ec7b004SRick Macklem 		error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0);
3899ec7b004SRick Macklem 	}
3909ec7b004SRick Macklem 	vput(vp);
3919ec7b004SRick Macklem 	vfs_unbusy(mp);
3929ec7b004SRick Macklem 	return (error);
3939ec7b004SRick Macklem }
3949ec7b004SRick Macklem 
3959ec7b004SRick Macklem /*
3969ec7b004SRick Macklem  * nfs version 3 fsinfo rpc call
3979ec7b004SRick Macklem  */
3989ec7b004SRick Macklem int
3999ec7b004SRick Macklem ncl_fsinfo(struct nfsmount *nmp, struct vnode *vp, struct ucred *cred,
4009ec7b004SRick Macklem     struct thread *td)
4019ec7b004SRick Macklem {
4029ec7b004SRick Macklem 	struct nfsfsinfo fs;
4039ec7b004SRick Macklem 	struct nfsvattr nfsva;
4049ec7b004SRick Macklem 	int error, attrflag;
4059ec7b004SRick Macklem 
4061e70163cSRick Macklem 	error = nfsrpc_fsinfo(vp, &fs, cred, td, &nfsva, &attrflag);
4079ec7b004SRick Macklem 	if (!error) {
4089ec7b004SRick Macklem 		if (attrflag)
4094ad3423bSRick Macklem 			(void) nfscl_loadattrcache(&vp, &nfsva, NULL, 0, 1);
4109ec7b004SRick Macklem 		mtx_lock(&nmp->nm_mtx);
4119ec7b004SRick Macklem 		nfscl_loadfsinfo(nmp, &fs);
4129ec7b004SRick Macklem 		mtx_unlock(&nmp->nm_mtx);
4139ec7b004SRick Macklem 	}
4149ec7b004SRick Macklem 	return (error);
4159ec7b004SRick Macklem }
4169ec7b004SRick Macklem 
4179ec7b004SRick Macklem /*
418*52d895feSEd Maste  * Mount a remote root fs via nfs. This depends on the info in the
4198954032fSRick Macklem  * nfs_diskless structure that has been filled in properly by some primary
4209ec7b004SRick Macklem  * bootstrap.
4219ec7b004SRick Macklem  * It goes something like this:
4229ec7b004SRick Macklem  * - do enough of "ifconfig" by calling ifioctl() so that the system
4239ec7b004SRick Macklem  *   can talk to the server
4248954032fSRick Macklem  * - If nfs_diskless.mygateway is filled in, use that address as
4259ec7b004SRick Macklem  *   a default gateway.
4269ec7b004SRick Macklem  * - build the rootfs mount point and call mountnfs() to do the rest.
4279ec7b004SRick Macklem  *
4289ec7b004SRick Macklem  * It is assumed to be safe to read, modify, and write the nfsv3_diskless
4299ec7b004SRick Macklem  * structure, as well as other global NFS client variables here, as
430d34b41c9SRick Macklem  * nfs_mountroot() will be called once in the boot before any other NFS
4319ec7b004SRick Macklem  * client activity occurs.
4329ec7b004SRick Macklem  */
4338954032fSRick Macklem static int
4348954032fSRick Macklem nfs_mountroot(struct mount *mp)
4359ec7b004SRick Macklem {
436d34b41c9SRick Macklem 	struct thread *td = curthread;
4378954032fSRick Macklem 	struct nfsv3_diskless *nd = &nfsv3_diskless;
4389ec7b004SRick Macklem 	struct socket *so;
4399ec7b004SRick Macklem 	struct vnode *vp;
4409ec7b004SRick Macklem 	struct ifreq ir;
44176ca6f88SJamie Gritton 	int error;
4429ec7b004SRick Macklem 	u_long l;
4439ec7b004SRick Macklem 	char buf[128];
4449ec7b004SRick Macklem 	char *cp;
4459ec7b004SRick Macklem 
4469ec7b004SRick Macklem #if defined(BOOTP_NFSROOT) && defined(BOOTP)
447d34b41c9SRick Macklem 	bootpc_init();		/* use bootp to get nfs_diskless filled in */
4489ec7b004SRick Macklem #elif defined(NFS_ROOT)
4499ec7b004SRick Macklem 	nfs_setup_diskless();
4509ec7b004SRick Macklem #endif
4519ec7b004SRick Macklem 
4528954032fSRick Macklem 	if (nfs_diskless_valid == 0)
4539ec7b004SRick Macklem 		return (-1);
4548954032fSRick Macklem 	if (nfs_diskless_valid == 1)
4559ec7b004SRick Macklem 		nfs_convert_diskless();
4569ec7b004SRick Macklem 
4579ec7b004SRick Macklem 	/*
4589ec7b004SRick Macklem 	 * Do enough of ifconfig(8) so that the critical net interface can
4599ec7b004SRick Macklem 	 * talk to the server.
4609ec7b004SRick Macklem 	 */
4619ec7b004SRick Macklem 	error = socreate(nd->myif.ifra_addr.sa_family, &so, nd->root_args.sotype, 0,
4629ec7b004SRick Macklem 	    td->td_ucred, td);
4639ec7b004SRick Macklem 	if (error)
464d34b41c9SRick Macklem 		panic("nfs_mountroot: socreate(%04x): %d",
4659ec7b004SRick Macklem 			nd->myif.ifra_addr.sa_family, error);
4669ec7b004SRick Macklem 
4679ec7b004SRick Macklem #if 0 /* XXX Bad idea */
4689ec7b004SRick Macklem 	/*
4699ec7b004SRick Macklem 	 * We might not have been told the right interface, so we pass
4709ec7b004SRick Macklem 	 * over the first ten interfaces of the same kind, until we get
4719ec7b004SRick Macklem 	 * one of them configured.
4729ec7b004SRick Macklem 	 */
4739ec7b004SRick Macklem 
4749ec7b004SRick Macklem 	for (i = strlen(nd->myif.ifra_name) - 1;
4759ec7b004SRick Macklem 		nd->myif.ifra_name[i] >= '0' &&
4769ec7b004SRick Macklem 		nd->myif.ifra_name[i] <= '9';
4779ec7b004SRick Macklem 		nd->myif.ifra_name[i] ++) {
4789ec7b004SRick Macklem 		error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td);
4799ec7b004SRick Macklem 		if(!error)
4809ec7b004SRick Macklem 			break;
4819ec7b004SRick Macklem 	}
4829ec7b004SRick Macklem #endif
4839ec7b004SRick Macklem 	error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td);
4849ec7b004SRick Macklem 	if (error)
485d34b41c9SRick Macklem 		panic("nfs_mountroot: SIOCAIFADDR: %d", error);
4862be111bfSDavide Italiano 	if ((cp = kern_getenv("boot.netif.mtu")) != NULL) {
4879ec7b004SRick Macklem 		ir.ifr_mtu = strtol(cp, NULL, 10);
4889ec7b004SRick Macklem 		bcopy(nd->myif.ifra_name, ir.ifr_name, IFNAMSIZ);
4899ec7b004SRick Macklem 		freeenv(cp);
4909ec7b004SRick Macklem 		error = ifioctl(so, SIOCSIFMTU, (caddr_t)&ir, td);
4919ec7b004SRick Macklem 		if (error)
492d34b41c9SRick Macklem 			printf("nfs_mountroot: SIOCSIFMTU: %d", error);
4939ec7b004SRick Macklem 	}
4949ec7b004SRick Macklem 	soclose(so);
4959ec7b004SRick Macklem 
4969ec7b004SRick Macklem 	/*
4979ec7b004SRick Macklem 	 * If the gateway field is filled in, set it as the default route.
4989ec7b004SRick Macklem 	 * Note that pxeboot will set a default route of 0 if the route
4999ec7b004SRick Macklem 	 * is not set by the DHCP server.  Check also for a value of 0
5009ec7b004SRick Macklem 	 * to avoid panicking inappropriately in that situation.
5019ec7b004SRick Macklem 	 */
5029ec7b004SRick Macklem 	if (nd->mygateway.sin_len != 0 &&
5039ec7b004SRick Macklem 	    nd->mygateway.sin_addr.s_addr != 0) {
5049ec7b004SRick Macklem 		struct sockaddr_in mask, sin;
5052bbab0afSAlexander V. Chernikov 		struct epoch_tracker et;
506e1c05fd2SAlexander V. Chernikov 		struct rt_addrinfo info;
507e1c05fd2SAlexander V. Chernikov 		struct rib_cmd_info rc;
5089ec7b004SRick Macklem 
5099ec7b004SRick Macklem 		bzero((caddr_t)&mask, sizeof(mask));
5109ec7b004SRick Macklem 		sin = mask;
5119ec7b004SRick Macklem 		sin.sin_family = AF_INET;
5129ec7b004SRick Macklem 		sin.sin_len = sizeof(sin);
513d34b41c9SRick Macklem                 /* XXX MRT use table 0 for this sort of thing */
5142bbab0afSAlexander V. Chernikov 		NET_EPOCH_ENTER(et);
5151fb51a12SBjoern A. Zeeb 		CURVNET_SET(TD_TO_VNET(td));
516e1c05fd2SAlexander V. Chernikov 
517e1c05fd2SAlexander V. Chernikov 		bzero((caddr_t)&info, sizeof(info));
518e1c05fd2SAlexander V. Chernikov 		info.rti_flags = RTF_UP | RTF_GATEWAY;
519e1c05fd2SAlexander V. Chernikov 		info.rti_info[RTAX_DST] = (struct sockaddr *)&sin;
520e1c05fd2SAlexander V. Chernikov 		info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&nd->mygateway;
521e1c05fd2SAlexander V. Chernikov 		info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&mask;
522e1c05fd2SAlexander V. Chernikov 
523e1c05fd2SAlexander V. Chernikov 		error = rib_action(RT_DEFAULT_FIB, RTM_ADD, &info, &rc);
5241fb51a12SBjoern A. Zeeb 		CURVNET_RESTORE();
5252bbab0afSAlexander V. Chernikov 		NET_EPOCH_EXIT(et);
5269ec7b004SRick Macklem 		if (error)
527d34b41c9SRick Macklem 			panic("nfs_mountroot: RTM_ADD: %d", error);
5289ec7b004SRick Macklem 	}
5299ec7b004SRick Macklem 
5309ec7b004SRick Macklem 	/*
5319ec7b004SRick Macklem 	 * Create the rootfs mount point.
5329ec7b004SRick Macklem 	 */
5339ec7b004SRick Macklem 	nd->root_args.fh = nd->root_fh;
5349ec7b004SRick Macklem 	nd->root_args.fhsize = nd->root_fhsize;
5359ec7b004SRick Macklem 	l = ntohl(nd->root_saddr.sin_addr.s_addr);
5369ec7b004SRick Macklem 	snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s",
5379ec7b004SRick Macklem 		(l >> 24) & 0xff, (l >> 16) & 0xff,
5389ec7b004SRick Macklem 		(l >>  8) & 0xff, (l >>  0) & 0xff, nd->root_hostnam);
5399ec7b004SRick Macklem 	printf("NFS ROOT: %s\n", buf);
540d34b41c9SRick Macklem 	nd->root_args.hostname = buf;
5419ec7b004SRick Macklem 	if ((error = nfs_mountdiskless(buf,
5429ec7b004SRick Macklem 	    &nd->root_saddr, &nd->root_args, td, &vp, mp)) != 0) {
5439ec7b004SRick Macklem 		return (error);
5449ec7b004SRick Macklem 	}
5459ec7b004SRick Macklem 
5469ec7b004SRick Macklem 	/*
5479ec7b004SRick Macklem 	 * This is not really an nfs issue, but it is much easier to
5489ec7b004SRick Macklem 	 * set hostname here and then let the "/etc/rc.xxx" files
5499ec7b004SRick Macklem 	 * mount the right /var based upon its preset value.
5509ec7b004SRick Macklem 	 */
55176ca6f88SJamie Gritton 	mtx_lock(&prison0.pr_mtx);
552c1f19219SJamie Gritton 	strlcpy(prison0.pr_hostname, nd->my_hostnam,
553c1f19219SJamie Gritton 	    sizeof(prison0.pr_hostname));
55476ca6f88SJamie Gritton 	mtx_unlock(&prison0.pr_mtx);
5559ec7b004SRick Macklem 	inittodr(ntohl(nd->root_time));
5569ec7b004SRick Macklem 	return (0);
5579ec7b004SRick Macklem }
5589ec7b004SRick Macklem 
5599ec7b004SRick Macklem /*
5609ec7b004SRick Macklem  * Internal version of mount system call for diskless setup.
5619ec7b004SRick Macklem  */
5629ec7b004SRick Macklem static int
5639ec7b004SRick Macklem nfs_mountdiskless(char *path,
5649ec7b004SRick Macklem     struct sockaddr_in *sin, struct nfs_args *args, struct thread *td,
5659ec7b004SRick Macklem     struct vnode **vpp, struct mount *mp)
5669ec7b004SRick Macklem {
5679ec7b004SRick Macklem 	struct sockaddr *nam;
568385edc8eSRick Macklem 	int dirlen, error;
569385edc8eSRick Macklem 	char *dirpath;
5709ec7b004SRick Macklem 
571385edc8eSRick Macklem 	/*
572385edc8eSRick Macklem 	 * Find the directory path in "path", which also has the server's
573385edc8eSRick Macklem 	 * name/ip address in it.
574385edc8eSRick Macklem 	 */
575385edc8eSRick Macklem 	dirpath = strchr(path, ':');
576385edc8eSRick Macklem 	if (dirpath != NULL)
577385edc8eSRick Macklem 		dirlen = strlen(++dirpath);
578385edc8eSRick Macklem 	else
579385edc8eSRick Macklem 		dirlen = 0;
5809ec7b004SRick Macklem 	nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK);
581385edc8eSRick Macklem 	if ((error = mountnfs(args, mp, nam, path, NULL, 0, dirpath, dirlen,
5820b17c7beSJohn Baldwin 	    NULL, 0, vpp, td->td_ucred, td, NFS_DEFAULT_NAMETIMEO,
5831e0a518dSRick Macklem 	    NFS_DEFAULT_NEGNAMETIMEO, 0, 0, NULL, 0)) != 0) {
584d34b41c9SRick Macklem 		printf("nfs_mountroot: mount %s on /: %d\n", path, error);
5859ec7b004SRick Macklem 		return (error);
5869ec7b004SRick Macklem 	}
5879ec7b004SRick Macklem 	return (0);
5889ec7b004SRick Macklem }
5899ec7b004SRick Macklem 
5909ec7b004SRick Macklem static void
591682eec57SRick Macklem nfs_sec_name(char *sec, int *flagsp)
592682eec57SRick Macklem {
593682eec57SRick Macklem 	if (!strcmp(sec, "krb5"))
594682eec57SRick Macklem 		*flagsp |= NFSMNT_KERB;
595682eec57SRick Macklem 	else if (!strcmp(sec, "krb5i"))
596682eec57SRick Macklem 		*flagsp |= (NFSMNT_KERB | NFSMNT_INTEGRITY);
597682eec57SRick Macklem 	else if (!strcmp(sec, "krb5p"))
598682eec57SRick Macklem 		*flagsp |= (NFSMNT_KERB | NFSMNT_PRIVACY);
599682eec57SRick Macklem }
600682eec57SRick Macklem 
601682eec57SRick Macklem static void
6029ec7b004SRick Macklem nfs_decode_args(struct mount *mp, struct nfsmount *nmp, struct nfs_args *argp,
603ca27c028SRick Macklem     const char *hostname, struct ucred *cred, struct thread *td)
6049ec7b004SRick Macklem {
6059ec7b004SRick Macklem 	int adjsock;
606ca27c028SRick Macklem 	char *p;
6079ec7b004SRick Macklem 
6089ec7b004SRick Macklem 	/*
6099ec7b004SRick Macklem 	 * Set read-only flag if requested; otherwise, clear it if this is
6109ec7b004SRick Macklem 	 * an update.  If this is not an update, then either the read-only
6119ec7b004SRick Macklem 	 * flag is already clear, or this is a root mount and it was set
6129ec7b004SRick Macklem 	 * intentionally at some previous point.
6139ec7b004SRick Macklem 	 */
6149ec7b004SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "ro", NULL, NULL) == 0) {
6159ec7b004SRick Macklem 		MNT_ILOCK(mp);
6169ec7b004SRick Macklem 		mp->mnt_flag |= MNT_RDONLY;
6179ec7b004SRick Macklem 		MNT_IUNLOCK(mp);
6189ec7b004SRick Macklem 	} else if (mp->mnt_flag & MNT_UPDATE) {
6199ec7b004SRick Macklem 		MNT_ILOCK(mp);
6209ec7b004SRick Macklem 		mp->mnt_flag &= ~MNT_RDONLY;
6219ec7b004SRick Macklem 		MNT_IUNLOCK(mp);
6229ec7b004SRick Macklem 	}
6239ec7b004SRick Macklem 
6249ec7b004SRick Macklem 	/*
6259ec7b004SRick Macklem 	 * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes
6269ec7b004SRick Macklem 	 * no sense in that context.  Also, set up appropriate retransmit
6279ec7b004SRick Macklem 	 * and soft timeout behavior.
6289ec7b004SRick Macklem 	 */
6299ec7b004SRick Macklem 	if (argp->sotype == SOCK_STREAM) {
6309ec7b004SRick Macklem 		nmp->nm_flag &= ~NFSMNT_NOCONN;
6319ec7b004SRick Macklem 		nmp->nm_timeo = NFS_MAXTIMEO;
6328e82d541SRick Macklem 		if ((argp->flags & NFSMNT_NFSV4) != 0)
6338e82d541SRick Macklem 			nmp->nm_retry = INT_MAX;
6348e82d541SRick Macklem 		else
6358e82d541SRick Macklem 			nmp->nm_retry = NFS_RETRANS_TCP;
6369ec7b004SRick Macklem 	}
6379ec7b004SRick Macklem 
6388e82d541SRick Macklem 	/* Also clear RDIRPLUS if NFSv2, it crashes some servers */
6398e82d541SRick Macklem 	if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) {
6408e82d541SRick Macklem 		argp->flags &= ~NFSMNT_RDIRPLUS;
6419ec7b004SRick Macklem 		nmp->nm_flag &= ~NFSMNT_RDIRPLUS;
6428e82d541SRick Macklem 	}
6439ec7b004SRick Macklem 
644037a2012SRick Macklem 	/* Clear ONEOPENOWN for NFSv2, 3 and 4.0. */
645037a2012SRick Macklem 	if (nmp->nm_minorvers == 0) {
646037a2012SRick Macklem 		argp->flags &= ~NFSMNT_ONEOPENOWN;
647037a2012SRick Macklem 		nmp->nm_flag &= ~NFSMNT_ONEOPENOWN;
648037a2012SRick Macklem 	}
649037a2012SRick Macklem 
6508e82d541SRick Macklem 	/* Re-bind if rsrvd port requested and wasn't on one */
6518e82d541SRick Macklem 	adjsock = !(nmp->nm_flag & NFSMNT_RESVPORT)
6528e82d541SRick Macklem 		  && (argp->flags & NFSMNT_RESVPORT);
6539ec7b004SRick Macklem 	/* Also re-bind if we're switching to/from a connected UDP socket */
6548e82d541SRick Macklem 	adjsock |= ((nmp->nm_flag & NFSMNT_NOCONN) !=
6559ec7b004SRick Macklem 		    (argp->flags & NFSMNT_NOCONN));
6569ec7b004SRick Macklem 
6579ec7b004SRick Macklem 	/* Update flags atomically.  Don't change the lock bits. */
6589ec7b004SRick Macklem 	nmp->nm_flag = argp->flags | nmp->nm_flag;
6599ec7b004SRick Macklem 
6609ec7b004SRick Macklem 	if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
6619ec7b004SRick Macklem 		nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
6629ec7b004SRick Macklem 		if (nmp->nm_timeo < NFS_MINTIMEO)
6639ec7b004SRick Macklem 			nmp->nm_timeo = NFS_MINTIMEO;
6649ec7b004SRick Macklem 		else if (nmp->nm_timeo > NFS_MAXTIMEO)
6659ec7b004SRick Macklem 			nmp->nm_timeo = NFS_MAXTIMEO;
6669ec7b004SRick Macklem 	}
6679ec7b004SRick Macklem 
6689ec7b004SRick Macklem 	if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
6699ec7b004SRick Macklem 		nmp->nm_retry = argp->retrans;
6709ec7b004SRick Macklem 		if (nmp->nm_retry > NFS_MAXREXMIT)
6719ec7b004SRick Macklem 			nmp->nm_retry = NFS_MAXREXMIT;
6729ec7b004SRick Macklem 	}
6739ec7b004SRick Macklem 
6749ec7b004SRick Macklem 	if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
6759ec7b004SRick Macklem 		nmp->nm_wsize = argp->wsize;
6766a30c96cSRick Macklem 		/*
6776a30c96cSRick Macklem 		 * Clip at the power of 2 below the size. There is an
6786a30c96cSRick Macklem 		 * issue (not isolated) that causes intermittent page
6796a30c96cSRick Macklem 		 * faults if this is not done.
6806a30c96cSRick Macklem 		 */
6816a30c96cSRick Macklem 		if (nmp->nm_wsize > NFS_FABLKSIZE)
6826a30c96cSRick Macklem 			nmp->nm_wsize = 1 << (fls(nmp->nm_wsize) - 1);
6836a30c96cSRick Macklem 		else
684fcf121d4SRick Macklem 			nmp->nm_wsize = NFS_FABLKSIZE;
6859ec7b004SRick Macklem 	}
6869ec7b004SRick Macklem 
6879ec7b004SRick Macklem 	if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
6889ec7b004SRick Macklem 		nmp->nm_rsize = argp->rsize;
6896a30c96cSRick Macklem 		/*
6906a30c96cSRick Macklem 		 * Clip at the power of 2 below the size. There is an
6916a30c96cSRick Macklem 		 * issue (not isolated) that causes intermittent page
6926a30c96cSRick Macklem 		 * faults if this is not done.
6936a30c96cSRick Macklem 		 */
6946a30c96cSRick Macklem 		if (nmp->nm_rsize > NFS_FABLKSIZE)
6956a30c96cSRick Macklem 			nmp->nm_rsize = 1 << (fls(nmp->nm_rsize) - 1);
6966a30c96cSRick Macklem 		else
697fcf121d4SRick Macklem 			nmp->nm_rsize = NFS_FABLKSIZE;
6989ec7b004SRick Macklem 	}
6999ec7b004SRick Macklem 
7009ec7b004SRick Macklem 	if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) {
7019ec7b004SRick Macklem 		nmp->nm_readdirsize = argp->readdirsize;
7029ec7b004SRick Macklem 	}
7039ec7b004SRick Macklem 
7049ec7b004SRick Macklem 	if ((argp->flags & NFSMNT_ACREGMIN) && argp->acregmin >= 0)
7059ec7b004SRick Macklem 		nmp->nm_acregmin = argp->acregmin;
7069ec7b004SRick Macklem 	else
7079ec7b004SRick Macklem 		nmp->nm_acregmin = NFS_MINATTRTIMO;
7089ec7b004SRick Macklem 	if ((argp->flags & NFSMNT_ACREGMAX) && argp->acregmax >= 0)
7099ec7b004SRick Macklem 		nmp->nm_acregmax = argp->acregmax;
7109ec7b004SRick Macklem 	else
7119ec7b004SRick Macklem 		nmp->nm_acregmax = NFS_MAXATTRTIMO;
7129ec7b004SRick Macklem 	if ((argp->flags & NFSMNT_ACDIRMIN) && argp->acdirmin >= 0)
7139ec7b004SRick Macklem 		nmp->nm_acdirmin = argp->acdirmin;
7149ec7b004SRick Macklem 	else
7159ec7b004SRick Macklem 		nmp->nm_acdirmin = NFS_MINDIRATTRTIMO;
7169ec7b004SRick Macklem 	if ((argp->flags & NFSMNT_ACDIRMAX) && argp->acdirmax >= 0)
7179ec7b004SRick Macklem 		nmp->nm_acdirmax = argp->acdirmax;
7189ec7b004SRick Macklem 	else
7199ec7b004SRick Macklem 		nmp->nm_acdirmax = NFS_MAXDIRATTRTIMO;
7209ec7b004SRick Macklem 	if (nmp->nm_acdirmin > nmp->nm_acdirmax)
7219ec7b004SRick Macklem 		nmp->nm_acdirmin = nmp->nm_acdirmax;
7229ec7b004SRick Macklem 	if (nmp->nm_acregmin > nmp->nm_acregmax)
7239ec7b004SRick Macklem 		nmp->nm_acregmin = nmp->nm_acregmax;
7249ec7b004SRick Macklem 
7259ec7b004SRick Macklem 	if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0) {
7269ec7b004SRick Macklem 		if (argp->readahead <= NFS_MAXRAHEAD)
7279ec7b004SRick Macklem 			nmp->nm_readahead = argp->readahead;
7289ec7b004SRick Macklem 		else
7299ec7b004SRick Macklem 			nmp->nm_readahead = NFS_MAXRAHEAD;
7309ec7b004SRick Macklem 	}
7319ec7b004SRick Macklem 	if ((argp->flags & NFSMNT_WCOMMITSIZE) && argp->wcommitsize >= 0) {
7329ec7b004SRick Macklem 		if (argp->wcommitsize < nmp->nm_wsize)
7339ec7b004SRick Macklem 			nmp->nm_wcommitsize = nmp->nm_wsize;
7349ec7b004SRick Macklem 		else
7359ec7b004SRick Macklem 			nmp->nm_wcommitsize = argp->wcommitsize;
7369ec7b004SRick Macklem 	}
7379ec7b004SRick Macklem 
7389ec7b004SRick Macklem 	adjsock |= ((nmp->nm_sotype != argp->sotype) ||
7399ec7b004SRick Macklem 		    (nmp->nm_soproto != argp->proto));
7409ec7b004SRick Macklem 
7419ec7b004SRick Macklem 	if (nmp->nm_client != NULL && adjsock) {
7429ec7b004SRick Macklem 		int haslock = 0, error = 0;
7439ec7b004SRick Macklem 
7449ec7b004SRick Macklem 		if (nmp->nm_sotype == SOCK_STREAM) {
7459ec7b004SRick Macklem 			error = newnfs_sndlock(&nmp->nm_sockreq.nr_lock);
7469ec7b004SRick Macklem 			if (!error)
7479ec7b004SRick Macklem 				haslock = 1;
7489ec7b004SRick Macklem 		}
7499ec7b004SRick Macklem 		if (!error) {
7501e0a518dSRick Macklem 		    newnfs_disconnect(nmp, &nmp->nm_sockreq);
7519ec7b004SRick Macklem 		    if (haslock)
7529ec7b004SRick Macklem 			newnfs_sndunlock(&nmp->nm_sockreq.nr_lock);
7539ec7b004SRick Macklem 		    nmp->nm_sotype = argp->sotype;
7549ec7b004SRick Macklem 		    nmp->nm_soproto = argp->proto;
7559ec7b004SRick Macklem 		    if (nmp->nm_sotype == SOCK_DGRAM)
7569ec7b004SRick Macklem 			while (newnfs_connect(nmp, &nmp->nm_sockreq,
7571e0a518dSRick Macklem 			    cred, td, 0, false, &nmp->nm_sockreq.nr_client)) {
7589ec7b004SRick Macklem 				printf("newnfs_args: retrying connect\n");
759c15882f0SRick Macklem 				(void) nfs_catnap(PSOCK, 0, "nfscon");
7609ec7b004SRick Macklem 			}
7619ec7b004SRick Macklem 		}
7629ec7b004SRick Macklem 	} else {
7639ec7b004SRick Macklem 		nmp->nm_sotype = argp->sotype;
7649ec7b004SRick Macklem 		nmp->nm_soproto = argp->proto;
7659ec7b004SRick Macklem 	}
766ca27c028SRick Macklem 
767ca27c028SRick Macklem 	if (hostname != NULL) {
768ca27c028SRick Macklem 		strlcpy(nmp->nm_hostname, hostname,
769ca27c028SRick Macklem 		    sizeof(nmp->nm_hostname));
770ca27c028SRick Macklem 		p = strchr(nmp->nm_hostname, ':');
771ca27c028SRick Macklem 		if (p != NULL)
772ca27c028SRick Macklem 			*p = '\0';
773ca27c028SRick Macklem 	}
7749ec7b004SRick Macklem }
7759ec7b004SRick Macklem 
77661c82720SRick Macklem static const char *nfs_opts[] = { "from", "nfs_args",
7775a06ac35SEdward Tomasz Napierala     "noac", "noatime", "noexec", "suiddir", "nosuid", "nosymfollow", "union",
7789ec7b004SRick Macklem     "noclusterr", "noclusterw", "multilabel", "acls", "force", "update",
779682eec57SRick Macklem     "async", "noconn", "nolockd", "conn", "lockd", "intr", "rdirplus",
780682eec57SRick Macklem     "readdirsize", "soft", "hard", "mntudp", "tcp", "udp", "wsize", "rsize",
7815a06ac35SEdward Tomasz Napierala     "retrans", "actimeo", "acregmin", "acregmax", "acdirmin", "acdirmax",
7825a06ac35SEdward Tomasz Napierala     "resvport", "readahead", "hostname", "timeo", "timeout", "addr", "fh",
7835a06ac35SEdward Tomasz Napierala     "nfsv3", "sec", "principal", "nfsv4", "gssname", "allgssname", "dirpath",
7845a06ac35SEdward Tomasz Napierala     "minorversion", "nametimeo", "negnametimeo", "nocto", "noncontigwr",
7851e0a518dSRick Macklem     "pnfs", "wcommitsize", "oneopenown", "tls", "tlscertname", "nconnect",
786896516e5SRick Macklem     "syskrb5", NULL };
7879ec7b004SRick Macklem 
7889ec7b004SRick Macklem /*
7890d1654c3SEdward Tomasz Napierala  * Parse the "from" mountarg, passed by the generic mount(8) program
7900d1654c3SEdward Tomasz Napierala  * or the mountroot code.  This is used when rerooting into NFS.
7910d1654c3SEdward Tomasz Napierala  *
7920d1654c3SEdward Tomasz Napierala  * Note that the "hostname" is actually a "hostname:/share/path" string.
7930d1654c3SEdward Tomasz Napierala  */
7940d1654c3SEdward Tomasz Napierala static int
7950d1654c3SEdward Tomasz Napierala nfs_mount_parse_from(struct vfsoptlist *opts, char **hostnamep,
7960d1654c3SEdward Tomasz Napierala     struct sockaddr_in **sinp, char *dirpath, size_t dirpathsize, int *dirlenp)
7970d1654c3SEdward Tomasz Napierala {
798599009e2SKonstantin Belousov 	char *nam, *delimp, *hostp, *spec;
7990d1654c3SEdward Tomasz Napierala 	int error, have_bracket = 0, offset, rv, speclen;
8000d1654c3SEdward Tomasz Napierala 	struct sockaddr_in *sin;
8010d1654c3SEdward Tomasz Napierala 	size_t len;
8020d1654c3SEdward Tomasz Napierala 
8030d1654c3SEdward Tomasz Napierala 	error = vfs_getopt(opts, "from", (void **)&spec, &speclen);
8040d1654c3SEdward Tomasz Napierala 	if (error != 0)
8050d1654c3SEdward Tomasz Napierala 		return (error);
806599009e2SKonstantin Belousov 	nam = malloc(MNAMELEN + 1, M_TEMP, M_WAITOK);
8070d1654c3SEdward Tomasz Napierala 
8080d1654c3SEdward Tomasz Napierala 	/*
8090d1654c3SEdward Tomasz Napierala 	 * This part comes from sbin/mount_nfs/mount_nfs.c:getnfsargs().
8100d1654c3SEdward Tomasz Napierala 	 */
8110d1654c3SEdward Tomasz Napierala 	if (*spec == '[' && (delimp = strchr(spec + 1, ']')) != NULL &&
8120d1654c3SEdward Tomasz Napierala 	    *(delimp + 1) == ':') {
8130d1654c3SEdward Tomasz Napierala 		hostp = spec + 1;
8140d1654c3SEdward Tomasz Napierala 		spec = delimp + 2;
8150d1654c3SEdward Tomasz Napierala 		have_bracket = 1;
8160d1654c3SEdward Tomasz Napierala 	} else if ((delimp = strrchr(spec, ':')) != NULL) {
8170d1654c3SEdward Tomasz Napierala 		hostp = spec;
8180d1654c3SEdward Tomasz Napierala 		spec = delimp + 1;
8190d1654c3SEdward Tomasz Napierala 	} else if ((delimp = strrchr(spec, '@')) != NULL) {
8200d1654c3SEdward Tomasz Napierala 		printf("%s: path@server syntax is deprecated, "
8210d1654c3SEdward Tomasz Napierala 		    "use server:path\n", __func__);
8220d1654c3SEdward Tomasz Napierala 		hostp = delimp + 1;
8230d1654c3SEdward Tomasz Napierala 	} else {
8240d1654c3SEdward Tomasz Napierala 		printf("%s: no <host>:<dirpath> nfs-name\n", __func__);
825599009e2SKonstantin Belousov 		free(nam, M_TEMP);
8260d1654c3SEdward Tomasz Napierala 		return (EINVAL);
8270d1654c3SEdward Tomasz Napierala 	}
8280d1654c3SEdward Tomasz Napierala 	*delimp = '\0';
8290d1654c3SEdward Tomasz Napierala 
8300d1654c3SEdward Tomasz Napierala 	/*
8310d1654c3SEdward Tomasz Napierala 	 * If there has been a trailing slash at mounttime it seems
8320d1654c3SEdward Tomasz Napierala 	 * that some mountd implementations fail to remove the mount
8330d1654c3SEdward Tomasz Napierala 	 * entries from their mountlist while unmounting.
8340d1654c3SEdward Tomasz Napierala 	 */
8350d1654c3SEdward Tomasz Napierala 	for (speclen = strlen(spec);
8360d1654c3SEdward Tomasz Napierala 	    speclen > 1 && spec[speclen - 1] == '/';
8370d1654c3SEdward Tomasz Napierala 	    speclen--)
8380d1654c3SEdward Tomasz Napierala 		spec[speclen - 1] = '\0';
8390d1654c3SEdward Tomasz Napierala 	if (strlen(hostp) + strlen(spec) + 1 > MNAMELEN) {
8400d1654c3SEdward Tomasz Napierala 		printf("%s: %s:%s: name too long", __func__, hostp, spec);
841599009e2SKonstantin Belousov 		free(nam, M_TEMP);
8420d1654c3SEdward Tomasz Napierala 		return (EINVAL);
8430d1654c3SEdward Tomasz Napierala 	}
8440d1654c3SEdward Tomasz Napierala 	/* Make both '@' and ':' notations equal */
8450d1654c3SEdward Tomasz Napierala 	if (*hostp != '\0') {
8460d1654c3SEdward Tomasz Napierala 		len = strlen(hostp);
8470d1654c3SEdward Tomasz Napierala 		offset = 0;
8480d1654c3SEdward Tomasz Napierala 		if (have_bracket)
8490d1654c3SEdward Tomasz Napierala 			nam[offset++] = '[';
8500d1654c3SEdward Tomasz Napierala 		memmove(nam + offset, hostp, len);
8510d1654c3SEdward Tomasz Napierala 		if (have_bracket)
8520d1654c3SEdward Tomasz Napierala 			nam[len + offset++] = ']';
8530d1654c3SEdward Tomasz Napierala 		nam[len + offset++] = ':';
8540d1654c3SEdward Tomasz Napierala 		memmove(nam + len + offset, spec, speclen);
8550d1654c3SEdward Tomasz Napierala 		nam[len + speclen + offset] = '\0';
85615634fd6SConrad Meyer 	} else
85715634fd6SConrad Meyer 		nam[0] = '\0';
8580d1654c3SEdward Tomasz Napierala 
8590d1654c3SEdward Tomasz Napierala 	/*
8600d1654c3SEdward Tomasz Napierala 	 * XXX: IPv6
8610d1654c3SEdward Tomasz Napierala 	 */
8620d1654c3SEdward Tomasz Napierala 	sin = malloc(sizeof(*sin), M_SONAME, M_WAITOK);
8630d1654c3SEdward Tomasz Napierala 	rv = inet_pton(AF_INET, hostp, &sin->sin_addr);
8640d1654c3SEdward Tomasz Napierala 	if (rv != 1) {
8650d1654c3SEdward Tomasz Napierala 		printf("%s: cannot parse '%s', inet_pton() returned %d\n",
8660d1654c3SEdward Tomasz Napierala 		    __func__, hostp, rv);
867599009e2SKonstantin Belousov 		free(nam, M_TEMP);
8680d1654c3SEdward Tomasz Napierala 		free(sin, M_SONAME);
8690d1654c3SEdward Tomasz Napierala 		return (EINVAL);
8700d1654c3SEdward Tomasz Napierala 	}
8710d1654c3SEdward Tomasz Napierala 
8720d1654c3SEdward Tomasz Napierala 	sin->sin_len = sizeof(*sin);
8730d1654c3SEdward Tomasz Napierala 	sin->sin_family = AF_INET;
8740d1654c3SEdward Tomasz Napierala 	/*
8750d1654c3SEdward Tomasz Napierala 	 * XXX: hardcoded port number.
8760d1654c3SEdward Tomasz Napierala 	 */
8770d1654c3SEdward Tomasz Napierala 	sin->sin_port = htons(2049);
8780d1654c3SEdward Tomasz Napierala 
8790d1654c3SEdward Tomasz Napierala 	*hostnamep = strdup(nam, M_NEWNFSMNT);
8800d1654c3SEdward Tomasz Napierala 	*sinp = sin;
8810d1654c3SEdward Tomasz Napierala 	strlcpy(dirpath, spec, dirpathsize);
8820d1654c3SEdward Tomasz Napierala 	*dirlenp = strlen(dirpath);
8830d1654c3SEdward Tomasz Napierala 
884599009e2SKonstantin Belousov 	free(nam, M_TEMP);
8850d1654c3SEdward Tomasz Napierala 	return (0);
8860d1654c3SEdward Tomasz Napierala }
8870d1654c3SEdward Tomasz Napierala 
8880d1654c3SEdward Tomasz Napierala /*
8899ec7b004SRick Macklem  * VFS Operations.
8909ec7b004SRick Macklem  *
8919ec7b004SRick Macklem  * mount system call
8929ec7b004SRick Macklem  * It seems a bit dumb to copyinstr() the host and path here and then
8939ec7b004SRick Macklem  * bcopy() them in mountnfs(), but I wanted to detect errors before
894fefbf770SGleb Smirnoff  * doing the getsockaddr() call because getsockaddr() allocates an mbuf and
8959ec7b004SRick Macklem  * an error after that means that I have to release the mbuf.
8969ec7b004SRick Macklem  */
8979ec7b004SRick Macklem /* ARGSUSED */
8989ec7b004SRick Macklem static int
899dfd233edSAttilio Rao nfs_mount(struct mount *mp)
9009ec7b004SRick Macklem {
9019ec7b004SRick Macklem 	struct nfs_args args = {
9029ec7b004SRick Macklem 	    .version = NFS_ARGSVERSION,
9039ec7b004SRick Macklem 	    .addr = NULL,
9049ec7b004SRick Macklem 	    .addrlen = sizeof (struct sockaddr_in),
9059ec7b004SRick Macklem 	    .sotype = SOCK_STREAM,
9069ec7b004SRick Macklem 	    .proto = 0,
9079ec7b004SRick Macklem 	    .fh = NULL,
9089ec7b004SRick Macklem 	    .fhsize = 0,
9098e82d541SRick Macklem 	    .flags = NFSMNT_RESVPORT,
9109ec7b004SRick Macklem 	    .wsize = NFS_WSIZE,
9119ec7b004SRick Macklem 	    .rsize = NFS_RSIZE,
9129ec7b004SRick Macklem 	    .readdirsize = NFS_READDIRSIZE,
9139ec7b004SRick Macklem 	    .timeo = 10,
9149ec7b004SRick Macklem 	    .retrans = NFS_RETRANS,
9159ec7b004SRick Macklem 	    .readahead = NFS_DEFRAHEAD,
9169ec7b004SRick Macklem 	    .wcommitsize = 0,			/* was: NQ_DEFLEASE */
9179ec7b004SRick Macklem 	    .hostname = NULL,
9189ec7b004SRick Macklem 	    .acregmin = NFS_MINATTRTIMO,
9199ec7b004SRick Macklem 	    .acregmax = NFS_MAXATTRTIMO,
9209ec7b004SRick Macklem 	    .acdirmin = NFS_MINDIRATTRTIMO,
9219ec7b004SRick Macklem 	    .acdirmax = NFS_MAXDIRATTRTIMO,
9229ec7b004SRick Macklem 	};
923682eec57SRick Macklem 	int error = 0, ret, len;
924682eec57SRick Macklem 	struct sockaddr *nam = NULL;
9259ec7b004SRick Macklem 	struct vnode *vp;
926dfd233edSAttilio Rao 	struct thread *td;
927599009e2SKonstantin Belousov 	char *hst;
9289ec7b004SRick Macklem 	u_char nfh[NFSX_FHMAX], krbname[100], dirpath[100], srvkrbname[100];
929665b1365SRick Macklem 	char *cp, *opt, *name, *secname, *tlscertname;
9300b17c7beSJohn Baldwin 	int nametimeo = NFS_DEFAULT_NAMETIMEO;
931dd5b5a94SRick Macklem 	int negnametimeo = NFS_DEFAULT_NEGNAMETIMEO;
932a145cf3fSRick Macklem 	int minvers = -1;
9330d1654c3SEdward Tomasz Napierala 	int dirlen, has_nfs_args_opt, has_nfs_from_opt,
9340d1654c3SEdward Tomasz Napierala 	    krbnamelen, srvkrbnamelen;
9358b713a2fSRick Macklem 	size_t hstlen;
9366e4b6ff8SRick Macklem 	uint32_t newflag;
9371e0a518dSRick Macklem 	int aconn = 0;
9389ec7b004SRick Macklem 
93961c82720SRick Macklem 	has_nfs_args_opt = 0;
9400d1654c3SEdward Tomasz Napierala 	has_nfs_from_opt = 0;
9416e4b6ff8SRick Macklem 	newflag = 0;
942665b1365SRick Macklem 	tlscertname = NULL;
943599009e2SKonstantin Belousov 	hst = malloc(MNAMELEN, M_TEMP, M_WAITOK);
9449ec7b004SRick Macklem 	if (vfs_filteropt(mp->mnt_optnew, nfs_opts)) {
9459ec7b004SRick Macklem 		error = EINVAL;
9469ec7b004SRick Macklem 		goto out;
9479ec7b004SRick Macklem 	}
9489ec7b004SRick Macklem 
949dfd233edSAttilio Rao 	td = curthread;
9500d1654c3SEdward Tomasz Napierala 	if ((mp->mnt_flag & (MNT_ROOTFS | MNT_UPDATE)) == MNT_ROOTFS &&
9510d1654c3SEdward Tomasz Napierala 	    nfs_diskless_valid != 0) {
9528954032fSRick Macklem 		error = nfs_mountroot(mp);
9539ec7b004SRick Macklem 		goto out;
9549ec7b004SRick Macklem 	}
9559ec7b004SRick Macklem 
956682eec57SRick Macklem 	nfscl_init();
9579ec7b004SRick Macklem 
95861c82720SRick Macklem 	/*
95961c82720SRick Macklem 	 * The old mount_nfs program passed the struct nfs_args
96061c82720SRick Macklem 	 * from userspace to kernel.  The new mount_nfs program
96161c82720SRick Macklem 	 * passes string options via nmount() from userspace to kernel
96261c82720SRick Macklem 	 * and we populate the struct nfs_args in the kernel.
96361c82720SRick Macklem 	 */
96461c82720SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "nfs_args", NULL, NULL) == 0) {
96561c82720SRick Macklem 		error = vfs_copyopt(mp->mnt_optnew, "nfs_args", &args,
96661c82720SRick Macklem 		    sizeof(args));
96761c82720SRick Macklem 		if (error != 0)
96861c82720SRick Macklem 			goto out;
96961c82720SRick Macklem 
97061c82720SRick Macklem 		if (args.version != NFS_ARGSVERSION) {
97161c82720SRick Macklem 			error = EPROGMISMATCH;
97261c82720SRick Macklem 			goto out;
97361c82720SRick Macklem 		}
97461c82720SRick Macklem 		has_nfs_args_opt = 1;
97561c82720SRick Macklem 	}
97661c82720SRick Macklem 
977682eec57SRick Macklem 	/* Handle the new style options. */
9785a06ac35SEdward Tomasz Napierala 	if (vfs_getopt(mp->mnt_optnew, "noac", NULL, NULL) == 0) {
9795a06ac35SEdward Tomasz Napierala 		args.acdirmin = args.acdirmax =
9805a06ac35SEdward Tomasz Napierala 		    args.acregmin = args.acregmax = 0;
9815a06ac35SEdward Tomasz Napierala 		args.flags |= NFSMNT_ACDIRMIN | NFSMNT_ACDIRMAX |
9825a06ac35SEdward Tomasz Napierala 		    NFSMNT_ACREGMIN | NFSMNT_ACREGMAX;
9835a06ac35SEdward Tomasz Napierala 	}
984682eec57SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "noconn", NULL, NULL) == 0)
985682eec57SRick Macklem 		args.flags |= NFSMNT_NOCONN;
986682eec57SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "conn", NULL, NULL) == 0)
9872fbe0cffSEdward Tomasz Napierala 		args.flags &= ~NFSMNT_NOCONN;
988682eec57SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "nolockd", NULL, NULL) == 0)
989682eec57SRick Macklem 		args.flags |= NFSMNT_NOLOCKD;
990682eec57SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "lockd", NULL, NULL) == 0)
991682eec57SRick Macklem 		args.flags &= ~NFSMNT_NOLOCKD;
992682eec57SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "intr", NULL, NULL) == 0)
993682eec57SRick Macklem 		args.flags |= NFSMNT_INT;
994682eec57SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "rdirplus", NULL, NULL) == 0)
995682eec57SRick Macklem 		args.flags |= NFSMNT_RDIRPLUS;
996682eec57SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "resvport", NULL, NULL) == 0)
997682eec57SRick Macklem 		args.flags |= NFSMNT_RESVPORT;
998682eec57SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "noresvport", NULL, NULL) == 0)
999682eec57SRick Macklem 		args.flags &= ~NFSMNT_RESVPORT;
1000682eec57SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "soft", NULL, NULL) == 0)
1001682eec57SRick Macklem 		args.flags |= NFSMNT_SOFT;
1002682eec57SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "hard", NULL, NULL) == 0)
1003682eec57SRick Macklem 		args.flags &= ~NFSMNT_SOFT;
1004682eec57SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "mntudp", NULL, NULL) == 0)
1005682eec57SRick Macklem 		args.sotype = SOCK_DGRAM;
1006682eec57SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "udp", NULL, NULL) == 0)
1007682eec57SRick Macklem 		args.sotype = SOCK_DGRAM;
1008682eec57SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "tcp", NULL, NULL) == 0)
1009682eec57SRick Macklem 		args.sotype = SOCK_STREAM;
1010682eec57SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "nfsv3", NULL, NULL) == 0)
1011682eec57SRick Macklem 		args.flags |= NFSMNT_NFSV3;
1012682eec57SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "nfsv4", NULL, NULL) == 0) {
1013682eec57SRick Macklem 		args.flags |= NFSMNT_NFSV4;
1014682eec57SRick Macklem 		args.sotype = SOCK_STREAM;
1015682eec57SRick Macklem 	}
1016682eec57SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "allgssname", NULL, NULL) == 0)
1017682eec57SRick Macklem 		args.flags |= NFSMNT_ALLGSSNAME;
1018e2f2b370SRuslan Ermilov 	if (vfs_getopt(mp->mnt_optnew, "nocto", NULL, NULL) == 0)
1019e2f2b370SRuslan Ermilov 		args.flags |= NFSMNT_NOCTO;
1020cf766161SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "noncontigwr", NULL, NULL) == 0)
1021cf766161SRick Macklem 		args.flags |= NFSMNT_NONCONTIGWR;
10221f60bfd8SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "pnfs", NULL, NULL) == 0)
10231f60bfd8SRick Macklem 		args.flags |= NFSMNT_PNFS;
1024037a2012SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "oneopenown", NULL, NULL) == 0)
1025037a2012SRick Macklem 		args.flags |= NFSMNT_ONEOPENOWN;
10266e4b6ff8SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "tls", NULL, NULL) == 0)
10276e4b6ff8SRick Macklem 		newflag |= NFSMNT_TLS;
1028665b1365SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "tlscertname", (void **)&opt, &len) ==
1029665b1365SRick Macklem 	    0) {
1030665b1365SRick Macklem 		/*
1031665b1365SRick Macklem 		 * tlscertname with "key.pem" appended to it forms a file
1032665b1365SRick Macklem 		 * name.  As such, the maximum allowable strlen(tlscertname) is
1033665b1365SRick Macklem 		 * NAME_MAX - 7. However, "len" includes the nul termination
1034665b1365SRick Macklem 		 * byte so it can be up to NAME_MAX - 6.
1035665b1365SRick Macklem 		 */
1036665b1365SRick Macklem 		if (opt == NULL || len <= 1 || len > NAME_MAX - 6) {
1037665b1365SRick Macklem 			vfs_mount_error(mp, "invalid tlscertname");
1038665b1365SRick Macklem 			error = EINVAL;
1039665b1365SRick Macklem 			goto out;
1040665b1365SRick Macklem 		}
1041665b1365SRick Macklem 		tlscertname = malloc(len, M_NEWNFSMNT, M_WAITOK);
1042665b1365SRick Macklem 		strlcpy(tlscertname, opt, len);
1043665b1365SRick Macklem 	}
1044682eec57SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "readdirsize", (void **)&opt, NULL) == 0) {
1045682eec57SRick Macklem 		if (opt == NULL) {
1046682eec57SRick Macklem 			vfs_mount_error(mp, "illegal readdirsize");
1047682eec57SRick Macklem 			error = EINVAL;
10489ec7b004SRick Macklem 			goto out;
10499ec7b004SRick Macklem 		}
1050682eec57SRick Macklem 		ret = sscanf(opt, "%d", &args.readdirsize);
1051682eec57SRick Macklem 		if (ret != 1 || args.readdirsize <= 0) {
1052682eec57SRick Macklem 			vfs_mount_error(mp, "illegal readdirsize: %s",
1053682eec57SRick Macklem 			    opt);
1054682eec57SRick Macklem 			error = EINVAL;
1055682eec57SRick Macklem 			goto out;
1056682eec57SRick Macklem 		}
1057682eec57SRick Macklem 		args.flags |= NFSMNT_READDIRSIZE;
1058682eec57SRick Macklem 	}
1059682eec57SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "readahead", (void **)&opt, NULL) == 0) {
1060682eec57SRick Macklem 		if (opt == NULL) {
1061682eec57SRick Macklem 			vfs_mount_error(mp, "illegal readahead");
1062682eec57SRick Macklem 			error = EINVAL;
1063682eec57SRick Macklem 			goto out;
1064682eec57SRick Macklem 		}
1065682eec57SRick Macklem 		ret = sscanf(opt, "%d", &args.readahead);
1066682eec57SRick Macklem 		if (ret != 1 || args.readahead <= 0) {
1067682eec57SRick Macklem 			vfs_mount_error(mp, "illegal readahead: %s",
1068682eec57SRick Macklem 			    opt);
1069682eec57SRick Macklem 			error = EINVAL;
1070682eec57SRick Macklem 			goto out;
1071682eec57SRick Macklem 		}
1072682eec57SRick Macklem 		args.flags |= NFSMNT_READAHEAD;
1073682eec57SRick Macklem 	}
1074682eec57SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "wsize", (void **)&opt, NULL) == 0) {
1075682eec57SRick Macklem 		if (opt == NULL) {
1076682eec57SRick Macklem 			vfs_mount_error(mp, "illegal wsize");
1077682eec57SRick Macklem 			error = EINVAL;
1078682eec57SRick Macklem 			goto out;
1079682eec57SRick Macklem 		}
1080682eec57SRick Macklem 		ret = sscanf(opt, "%d", &args.wsize);
1081682eec57SRick Macklem 		if (ret != 1 || args.wsize <= 0) {
1082682eec57SRick Macklem 			vfs_mount_error(mp, "illegal wsize: %s",
1083682eec57SRick Macklem 			    opt);
1084682eec57SRick Macklem 			error = EINVAL;
1085682eec57SRick Macklem 			goto out;
1086682eec57SRick Macklem 		}
1087682eec57SRick Macklem 		args.flags |= NFSMNT_WSIZE;
1088682eec57SRick Macklem 	}
1089682eec57SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "rsize", (void **)&opt, NULL) == 0) {
1090682eec57SRick Macklem 		if (opt == NULL) {
1091682eec57SRick Macklem 			vfs_mount_error(mp, "illegal rsize");
1092682eec57SRick Macklem 			error = EINVAL;
1093682eec57SRick Macklem 			goto out;
1094682eec57SRick Macklem 		}
1095682eec57SRick Macklem 		ret = sscanf(opt, "%d", &args.rsize);
1096682eec57SRick Macklem 		if (ret != 1 || args.rsize <= 0) {
1097682eec57SRick Macklem 			vfs_mount_error(mp, "illegal wsize: %s",
1098682eec57SRick Macklem 			    opt);
1099682eec57SRick Macklem 			error = EINVAL;
1100682eec57SRick Macklem 			goto out;
1101682eec57SRick Macklem 		}
1102682eec57SRick Macklem 		args.flags |= NFSMNT_RSIZE;
1103682eec57SRick Macklem 	}
1104682eec57SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "retrans", (void **)&opt, NULL) == 0) {
1105682eec57SRick Macklem 		if (opt == NULL) {
1106682eec57SRick Macklem 			vfs_mount_error(mp, "illegal retrans");
1107682eec57SRick Macklem 			error = EINVAL;
1108682eec57SRick Macklem 			goto out;
1109682eec57SRick Macklem 		}
1110682eec57SRick Macklem 		ret = sscanf(opt, "%d", &args.retrans);
1111682eec57SRick Macklem 		if (ret != 1 || args.retrans <= 0) {
1112682eec57SRick Macklem 			vfs_mount_error(mp, "illegal retrans: %s",
1113682eec57SRick Macklem 			    opt);
1114682eec57SRick Macklem 			error = EINVAL;
1115682eec57SRick Macklem 			goto out;
1116682eec57SRick Macklem 		}
1117682eec57SRick Macklem 		args.flags |= NFSMNT_RETRANS;
1118682eec57SRick Macklem 	}
11195a06ac35SEdward Tomasz Napierala 	if (vfs_getopt(mp->mnt_optnew, "actimeo", (void **)&opt, NULL) == 0) {
11205a06ac35SEdward Tomasz Napierala 		ret = sscanf(opt, "%d", &args.acregmin);
11215a06ac35SEdward Tomasz Napierala 		if (ret != 1 || args.acregmin < 0) {
11225a06ac35SEdward Tomasz Napierala 			vfs_mount_error(mp, "illegal actimeo: %s",
11235a06ac35SEdward Tomasz Napierala 			    opt);
11245a06ac35SEdward Tomasz Napierala 			error = EINVAL;
11255a06ac35SEdward Tomasz Napierala 			goto out;
11265a06ac35SEdward Tomasz Napierala 		}
11275a06ac35SEdward Tomasz Napierala 		args.acdirmin = args.acdirmax = args.acregmax = args.acregmin;
11285a06ac35SEdward Tomasz Napierala 		args.flags |= NFSMNT_ACDIRMIN | NFSMNT_ACDIRMAX |
11295a06ac35SEdward Tomasz Napierala 		    NFSMNT_ACREGMIN | NFSMNT_ACREGMAX;
11305a06ac35SEdward Tomasz Napierala 	}
1131682eec57SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "acregmin", (void **)&opt, NULL) == 0) {
1132682eec57SRick Macklem 		ret = sscanf(opt, "%d", &args.acregmin);
1133682eec57SRick Macklem 		if (ret != 1 || args.acregmin < 0) {
1134682eec57SRick Macklem 			vfs_mount_error(mp, "illegal acregmin: %s",
1135682eec57SRick Macklem 			    opt);
1136682eec57SRick Macklem 			error = EINVAL;
1137682eec57SRick Macklem 			goto out;
1138682eec57SRick Macklem 		}
1139682eec57SRick Macklem 		args.flags |= NFSMNT_ACREGMIN;
1140682eec57SRick Macklem 	}
1141682eec57SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "acregmax", (void **)&opt, NULL) == 0) {
1142682eec57SRick Macklem 		ret = sscanf(opt, "%d", &args.acregmax);
1143682eec57SRick Macklem 		if (ret != 1 || args.acregmax < 0) {
1144682eec57SRick Macklem 			vfs_mount_error(mp, "illegal acregmax: %s",
1145682eec57SRick Macklem 			    opt);
1146682eec57SRick Macklem 			error = EINVAL;
1147682eec57SRick Macklem 			goto out;
1148682eec57SRick Macklem 		}
1149682eec57SRick Macklem 		args.flags |= NFSMNT_ACREGMAX;
1150682eec57SRick Macklem 	}
1151682eec57SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "acdirmin", (void **)&opt, NULL) == 0) {
1152682eec57SRick Macklem 		ret = sscanf(opt, "%d", &args.acdirmin);
1153682eec57SRick Macklem 		if (ret != 1 || args.acdirmin < 0) {
1154682eec57SRick Macklem 			vfs_mount_error(mp, "illegal acdirmin: %s",
1155682eec57SRick Macklem 			    opt);
1156682eec57SRick Macklem 			error = EINVAL;
1157682eec57SRick Macklem 			goto out;
1158682eec57SRick Macklem 		}
1159682eec57SRick Macklem 		args.flags |= NFSMNT_ACDIRMIN;
1160682eec57SRick Macklem 	}
1161682eec57SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "acdirmax", (void **)&opt, NULL) == 0) {
1162682eec57SRick Macklem 		ret = sscanf(opt, "%d", &args.acdirmax);
1163682eec57SRick Macklem 		if (ret != 1 || args.acdirmax < 0) {
1164682eec57SRick Macklem 			vfs_mount_error(mp, "illegal acdirmax: %s",
1165682eec57SRick Macklem 			    opt);
1166682eec57SRick Macklem 			error = EINVAL;
1167682eec57SRick Macklem 			goto out;
1168682eec57SRick Macklem 		}
1169682eec57SRick Macklem 		args.flags |= NFSMNT_ACDIRMAX;
1170682eec57SRick Macklem 	}
1171840fb1c0SJohn Baldwin 	if (vfs_getopt(mp->mnt_optnew, "wcommitsize", (void **)&opt, NULL) == 0) {
1172840fb1c0SJohn Baldwin 		ret = sscanf(opt, "%d", &args.wcommitsize);
1173840fb1c0SJohn Baldwin 		if (ret != 1 || args.wcommitsize < 0) {
1174840fb1c0SJohn Baldwin 			vfs_mount_error(mp, "illegal wcommitsize: %s", opt);
1175840fb1c0SJohn Baldwin 			error = EINVAL;
1176840fb1c0SJohn Baldwin 			goto out;
1177840fb1c0SJohn Baldwin 		}
1178840fb1c0SJohn Baldwin 		args.flags |= NFSMNT_WCOMMITSIZE;
1179840fb1c0SJohn Baldwin 	}
11805a06ac35SEdward Tomasz Napierala 	if (vfs_getopt(mp->mnt_optnew, "timeo", (void **)&opt, NULL) == 0) {
11815a06ac35SEdward Tomasz Napierala 		ret = sscanf(opt, "%d", &args.timeo);
11825a06ac35SEdward Tomasz Napierala 		if (ret != 1 || args.timeo <= 0) {
11835a06ac35SEdward Tomasz Napierala 			vfs_mount_error(mp, "illegal timeo: %s",
11845a06ac35SEdward Tomasz Napierala 			    opt);
11855a06ac35SEdward Tomasz Napierala 			error = EINVAL;
11865a06ac35SEdward Tomasz Napierala 			goto out;
11875a06ac35SEdward Tomasz Napierala 		}
11885a06ac35SEdward Tomasz Napierala 		args.flags |= NFSMNT_TIMEO;
11895a06ac35SEdward Tomasz Napierala 	}
1190682eec57SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "timeout", (void **)&opt, NULL) == 0) {
1191682eec57SRick Macklem 		ret = sscanf(opt, "%d", &args.timeo);
1192682eec57SRick Macklem 		if (ret != 1 || args.timeo <= 0) {
1193682eec57SRick Macklem 			vfs_mount_error(mp, "illegal timeout: %s",
1194682eec57SRick Macklem 			    opt);
1195682eec57SRick Macklem 			error = EINVAL;
1196682eec57SRick Macklem 			goto out;
1197682eec57SRick Macklem 		}
1198682eec57SRick Macklem 		args.flags |= NFSMNT_TIMEO;
1199682eec57SRick Macklem 	}
12000b17c7beSJohn Baldwin 	if (vfs_getopt(mp->mnt_optnew, "nametimeo", (void **)&opt, NULL) == 0) {
12010b17c7beSJohn Baldwin 		ret = sscanf(opt, "%d", &nametimeo);
12020b17c7beSJohn Baldwin 		if (ret != 1 || nametimeo < 0) {
12030b17c7beSJohn Baldwin 			vfs_mount_error(mp, "illegal nametimeo: %s", opt);
12040b17c7beSJohn Baldwin 			error = EINVAL;
12050b17c7beSJohn Baldwin 			goto out;
12060b17c7beSJohn Baldwin 		}
12070b17c7beSJohn Baldwin 	}
1208dd5b5a94SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "negnametimeo", (void **)&opt, NULL)
1209dd5b5a94SRick Macklem 	    == 0) {
1210dd5b5a94SRick Macklem 		ret = sscanf(opt, "%d", &negnametimeo);
1211dd5b5a94SRick Macklem 		if (ret != 1 || negnametimeo < 0) {
1212dd5b5a94SRick Macklem 			vfs_mount_error(mp, "illegal negnametimeo: %s",
1213dd5b5a94SRick Macklem 			    opt);
1214dd5b5a94SRick Macklem 			error = EINVAL;
1215dd5b5a94SRick Macklem 			goto out;
1216dd5b5a94SRick Macklem 		}
1217dd5b5a94SRick Macklem 	}
12181f60bfd8SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "minorversion", (void **)&opt, NULL) ==
12191f60bfd8SRick Macklem 	    0) {
12201f60bfd8SRick Macklem 		ret = sscanf(opt, "%d", &minvers);
1221c057a378SRick Macklem 		if (ret != 1 || minvers < 0 || minvers > 2 ||
12221f60bfd8SRick Macklem 		    (args.flags & NFSMNT_NFSV4) == 0) {
12231f60bfd8SRick Macklem 			vfs_mount_error(mp, "illegal minorversion: %s", opt);
12241f60bfd8SRick Macklem 			error = EINVAL;
12251f60bfd8SRick Macklem 			goto out;
12261f60bfd8SRick Macklem 		}
12271f60bfd8SRick Macklem 	}
12281e0a518dSRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "nconnect", (void **)&opt, NULL) ==
12291e0a518dSRick Macklem 	    0) {
12301e0a518dSRick Macklem 		ret = sscanf(opt, "%d", &aconn);
12311e0a518dSRick Macklem 		if (ret != 1 || aconn < 1 || aconn > NFS_MAXNCONN) {
12321e0a518dSRick Macklem 			vfs_mount_error(mp, "illegal nconnect: %s", opt);
12331e0a518dSRick Macklem 			error = EINVAL;
12341e0a518dSRick Macklem 			goto out;
12351e0a518dSRick Macklem 		}
12361e0a518dSRick Macklem 		/*
12371e0a518dSRick Macklem 		 * Setting nconnect=1 is a no-op, allowed so that
12381e0a518dSRick Macklem 		 * the option can be used in a Linux compatible way.
12391e0a518dSRick Macklem 		 */
12401e0a518dSRick Macklem 		aconn--;
12411e0a518dSRick Macklem 	}
1242896516e5SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "syskrb5", NULL, NULL) == 0)
1243896516e5SRick Macklem 		newflag |= NFSMNT_SYSKRB5;
1244682eec57SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "sec",
1245682eec57SRick Macklem 		(void **) &secname, NULL) == 0)
1246682eec57SRick Macklem 		nfs_sec_name(secname, &args.flags);
12479ec7b004SRick Macklem 
12489ec7b004SRick Macklem 	if (mp->mnt_flag & MNT_UPDATE) {
12499ec7b004SRick Macklem 		struct nfsmount *nmp = VFSTONFS(mp);
12509ec7b004SRick Macklem 
12519ec7b004SRick Macklem 		if (nmp == NULL) {
12529ec7b004SRick Macklem 			error = EIO;
12539ec7b004SRick Macklem 			goto out;
12549ec7b004SRick Macklem 		}
125587b63367SRick Macklem 
125687b63367SRick Macklem 		/*
125787b63367SRick Macklem 		 * If a change from TCP->UDP is done and there are thread(s)
1258a96c9b30SPedro F. Giffuni 		 * that have I/O RPC(s) in progress with a transfer size
125987b63367SRick Macklem 		 * greater than NFS_MAXDGRAMDATA, those thread(s) will be
126087b63367SRick Macklem 		 * hung, retrying the RPC(s) forever. Usually these threads
126187b63367SRick Macklem 		 * will be seen doing an uninterruptible sleep on wait channel
1262c15882f0SRick Macklem 		 * "nfsreq".
126387b63367SRick Macklem 		 */
126487b63367SRick Macklem 		if (args.sotype == SOCK_DGRAM && nmp->nm_sotype == SOCK_STREAM)
126587b63367SRick Macklem 			tprintf(td->td_proc, LOG_WARNING,
126687b63367SRick Macklem 	"Warning: mount -u that changes TCP->UDP can result in hung threads\n");
126787b63367SRick Macklem 
12689ec7b004SRick Macklem 		/*
12699ec7b004SRick Macklem 		 * When doing an update, we can't change version,
1270037a2012SRick Macklem 		 * security, switch lockd strategies, change cookie
1271037a2012SRick Macklem 		 * translation or switch oneopenown.
12729ec7b004SRick Macklem 		 */
12739ec7b004SRick Macklem 		args.flags = (args.flags &
12749ec7b004SRick Macklem 		    ~(NFSMNT_NFSV3 |
12759ec7b004SRick Macklem 		      NFSMNT_NFSV4 |
12769ec7b004SRick Macklem 		      NFSMNT_KERB |
12779ec7b004SRick Macklem 		      NFSMNT_INTEGRITY |
12789ec7b004SRick Macklem 		      NFSMNT_PRIVACY |
1279037a2012SRick Macklem 		      NFSMNT_ONEOPENOWN |
12809ec7b004SRick Macklem 		      NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)) |
12819ec7b004SRick Macklem 		    (nmp->nm_flag &
12829ec7b004SRick Macklem 			(NFSMNT_NFSV3 |
12839ec7b004SRick Macklem 			 NFSMNT_NFSV4 |
12849ec7b004SRick Macklem 			 NFSMNT_KERB |
12859ec7b004SRick Macklem 			 NFSMNT_INTEGRITY |
12869ec7b004SRick Macklem 			 NFSMNT_PRIVACY |
1287037a2012SRick Macklem 			 NFSMNT_ONEOPENOWN |
12889ec7b004SRick Macklem 			 NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/));
1289ca27c028SRick Macklem 		nfs_decode_args(mp, nmp, &args, NULL, td->td_ucred, td);
12909ec7b004SRick Macklem 		goto out;
12919ec7b004SRick Macklem 	}
12929ec7b004SRick Macklem 
12939ec7b004SRick Macklem 	/*
12949ec7b004SRick Macklem 	 * Make the nfs_ip_paranoia sysctl serve as the default connection
12959ec7b004SRick Macklem 	 * or no-connection mode for those protocols that support
12969ec7b004SRick Macklem 	 * no-connection mode (the flag will be cleared later for protocols
12979ec7b004SRick Macklem 	 * that do not support no-connection mode).  This will allow a client
12989ec7b004SRick Macklem 	 * to receive replies from a different IP then the request was
12999ec7b004SRick Macklem 	 * sent to.  Note: default value for nfs_ip_paranoia is 1 (paranoid),
13009ec7b004SRick Macklem 	 * not 0.
13019ec7b004SRick Macklem 	 */
13029ec7b004SRick Macklem 	if (nfs_ip_paranoia == 0)
13039ec7b004SRick Macklem 		args.flags |= NFSMNT_NOCONN;
1304682eec57SRick Macklem 
130561c82720SRick Macklem 	if (has_nfs_args_opt != 0) {
130661c82720SRick Macklem 		/*
130761c82720SRick Macklem 		 * In the 'nfs_args' case, the pointers in the args
130861c82720SRick Macklem 		 * structure are in userland - we copy them in here.
130961c82720SRick Macklem 		 */
131061c82720SRick Macklem 		if (args.fhsize < 0 || args.fhsize > NFSX_V3FHMAX) {
131161c82720SRick Macklem 			vfs_mount_error(mp, "Bad file handle");
131261c82720SRick Macklem 			error = EINVAL;
131361c82720SRick Macklem 			goto out;
131461c82720SRick Macklem 		}
131561c82720SRick Macklem 		error = copyin((caddr_t)args.fh, (caddr_t)nfh,
131661c82720SRick Macklem 		    args.fhsize);
131761c82720SRick Macklem 		if (error != 0)
131861c82720SRick Macklem 			goto out;
13198b713a2fSRick Macklem 		error = copyinstr(args.hostname, hst, MNAMELEN - 1, &hstlen);
132061c82720SRick Macklem 		if (error != 0)
132161c82720SRick Macklem 			goto out;
13228b713a2fSRick Macklem 		bzero(&hst[hstlen], MNAMELEN - hstlen);
132361c82720SRick Macklem 		args.hostname = hst;
1324fefbf770SGleb Smirnoff 		/* getsockaddr() call must be after above copyin() calls */
1325318f0d77SBrooks Davis 		error = getsockaddr(&nam, args.addr, args.addrlen);
132661c82720SRick Macklem 		if (error != 0)
132761c82720SRick Macklem 			goto out;
13280d1654c3SEdward Tomasz Napierala 	} else if (nfs_mount_parse_from(mp->mnt_optnew,
13290d1654c3SEdward Tomasz Napierala 	    &args.hostname, (struct sockaddr_in **)&nam, dirpath,
13300d1654c3SEdward Tomasz Napierala 	    sizeof(dirpath), &dirlen) == 0) {
13310d1654c3SEdward Tomasz Napierala 		has_nfs_from_opt = 1;
13320d1654c3SEdward Tomasz Napierala 		bcopy(args.hostname, hst, MNAMELEN);
13330d1654c3SEdward Tomasz Napierala 		hst[MNAMELEN - 1] = '\0';
13340d1654c3SEdward Tomasz Napierala 
13350d1654c3SEdward Tomasz Napierala 		/*
13360d1654c3SEdward Tomasz Napierala 		 * This only works with NFSv4 for now.
13370d1654c3SEdward Tomasz Napierala 		 */
13380d1654c3SEdward Tomasz Napierala 		args.fhsize = 0;
13390d1654c3SEdward Tomasz Napierala 		args.flags |= NFSMNT_NFSV4;
13400d1654c3SEdward Tomasz Napierala 		args.sotype = SOCK_STREAM;
134161c82720SRick Macklem 	} else {
1342682eec57SRick Macklem 		if (vfs_getopt(mp->mnt_optnew, "fh", (void **)&args.fh,
1343682eec57SRick Macklem 		    &args.fhsize) == 0) {
13445ed9b964SRick Macklem 			if (args.fhsize < 0 || args.fhsize > NFSX_FHMAX) {
1345682eec57SRick Macklem 				vfs_mount_error(mp, "Bad file handle");
13469ec7b004SRick Macklem 				error = EINVAL;
13479ec7b004SRick Macklem 				goto out;
13489ec7b004SRick Macklem 			}
1349682eec57SRick Macklem 			bcopy(args.fh, nfh, args.fhsize);
13509ec7b004SRick Macklem 		} else {
1351682eec57SRick Macklem 			args.fhsize = 0;
1352682eec57SRick Macklem 		}
135361c82720SRick Macklem 		(void) vfs_getopt(mp->mnt_optnew, "hostname",
135461c82720SRick Macklem 		    (void **)&args.hostname, &len);
1355682eec57SRick Macklem 		if (args.hostname == NULL) {
1356682eec57SRick Macklem 			vfs_mount_error(mp, "Invalid hostname");
1357682eec57SRick Macklem 			error = EINVAL;
1358682eec57SRick Macklem 			goto out;
1359682eec57SRick Macklem 		}
1360bd1623deSKonstantin Belousov 		if (len >= MNAMELEN) {
1361bd1623deSKonstantin Belousov 			vfs_mount_error(mp, "Hostname too long");
1362bd1623deSKonstantin Belousov 			error = EINVAL;
1363bd1623deSKonstantin Belousov 			goto out;
1364bd1623deSKonstantin Belousov 		}
1365bd1623deSKonstantin Belousov 		bcopy(args.hostname, hst, len);
1366bd1623deSKonstantin Belousov 		hst[len] = '\0';
136761c82720SRick Macklem 	}
1368682eec57SRick Macklem 
1369682eec57SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "principal", (void **)&name, NULL) == 0)
1370682eec57SRick Macklem 		strlcpy(srvkrbname, name, sizeof (srvkrbname));
13712a3508ebSRick Macklem 	else {
1372682eec57SRick Macklem 		snprintf(srvkrbname, sizeof (srvkrbname), "nfs@%s", hst);
13732a3508ebSRick Macklem 		cp = strchr(srvkrbname, ':');
13742a3508ebSRick Macklem 		if (cp != NULL)
13752a3508ebSRick Macklem 			*cp = '\0';
13762a3508ebSRick Macklem 	}
1377385edc8eSRick Macklem 	srvkrbnamelen = strlen(srvkrbname);
1378682eec57SRick Macklem 
1379682eec57SRick Macklem 	if (vfs_getopt(mp->mnt_optnew, "gssname", (void **)&name, NULL) == 0)
1380682eec57SRick Macklem 		strlcpy(krbname, name, sizeof (krbname));
1381682eec57SRick Macklem 	else
13829ec7b004SRick Macklem 		krbname[0] = '\0';
1383385edc8eSRick Macklem 	krbnamelen = strlen(krbname);
1384682eec57SRick Macklem 
13850d1654c3SEdward Tomasz Napierala 	if (has_nfs_from_opt == 0) {
13860d1654c3SEdward Tomasz Napierala 		if (vfs_getopt(mp->mnt_optnew,
13870d1654c3SEdward Tomasz Napierala 		    "dirpath", (void **)&name, NULL) == 0)
1388682eec57SRick Macklem 			strlcpy(dirpath, name, sizeof (dirpath));
1389682eec57SRick Macklem 		else
13909ec7b004SRick Macklem 			dirpath[0] = '\0';
1391385edc8eSRick Macklem 		dirlen = strlen(dirpath);
13920d1654c3SEdward Tomasz Napierala 	}
1393682eec57SRick Macklem 
13940d1654c3SEdward Tomasz Napierala 	if (has_nfs_args_opt == 0 && has_nfs_from_opt == 0) {
1395b70cddbaSRick Macklem 		if (vfs_getopt(mp->mnt_optnew, "addr",
139661c82720SRick Macklem 		    (void **)&args.addr, &args.addrlen) == 0) {
1397682eec57SRick Macklem 			if (args.addrlen > SOCK_MAXADDRLEN) {
1398682eec57SRick Macklem 				error = ENAMETOOLONG;
13999ec7b004SRick Macklem 				goto out;
14009ec7b004SRick Macklem 			}
1401682eec57SRick Macklem 			nam = malloc(args.addrlen, M_SONAME, M_WAITOK);
1402682eec57SRick Macklem 			bcopy(args.addr, nam, args.addrlen);
1403682eec57SRick Macklem 			nam->sa_len = args.addrlen;
1404b70cddbaSRick Macklem 		} else {
1405b70cddbaSRick Macklem 			vfs_mount_error(mp, "No server address");
1406b70cddbaSRick Macklem 			error = EINVAL;
1407b70cddbaSRick Macklem 			goto out;
1408b70cddbaSRick Macklem 		}
14099ec7b004SRick Macklem 	}
1410682eec57SRick Macklem 
14111e0a518dSRick Macklem 	if (aconn > 0 && (args.sotype != SOCK_STREAM ||
14121e0a518dSRick Macklem 	    (args.flags & NFSMNT_NFSV4) == 0 || minvers == 0)) {
14131e0a518dSRick Macklem 		/*
14141e0a518dSRick Macklem 		 * RFC 5661 requires that an NFSv4.1/4.2 server
14151e0a518dSRick Macklem 		 * send an RPC reply on the same TCP connection
14161e0a518dSRick Macklem 		 * as the one it received the request on.
14171e0a518dSRick Macklem 		 * This property in required for "nconnect" and
14181e0a518dSRick Macklem 		 * might not be the case for NFSv3 or NFSv4.0 servers.
14191e0a518dSRick Macklem 		 */
14201e0a518dSRick Macklem 		vfs_mount_error(mp, "nconnect should only be used "
14211e0a518dSRick Macklem 		    "for NFSv4.1/4.2 mounts");
14221e0a518dSRick Macklem 		error = EINVAL;
14231e0a518dSRick Macklem 		goto out;
14241e0a518dSRick Macklem 	}
14251e0a518dSRick Macklem 
1426896516e5SRick Macklem 	if ((newflag & NFSMNT_SYSKRB5) != 0 &&
1427896516e5SRick Macklem 	    ((args.flags & NFSMNT_NFSV4) == 0 || minvers == 0)) {
1428896516e5SRick Macklem 		/*
1429896516e5SRick Macklem 		 * This option requires the use of SP4_NONE, which
1430896516e5SRick Macklem 		 * is only in NFSv4.1/4.2.
1431896516e5SRick Macklem 		 */
1432896516e5SRick Macklem 		vfs_mount_error(mp, "syskrb5 should only be used "
1433896516e5SRick Macklem 		    "for NFSv4.1/4.2 mounts");
1434896516e5SRick Macklem 		error = EINVAL;
1435896516e5SRick Macklem 		goto out;
1436896516e5SRick Macklem 	}
1437896516e5SRick Macklem 
1438896516e5SRick Macklem 	if ((newflag & NFSMNT_SYSKRB5) != 0 &&
1439896516e5SRick Macklem 	    (args.flags & NFSMNT_KERB) == 0) {
1440896516e5SRick Macklem 		/*
1441896516e5SRick Macklem 		 * This option modifies the behaviour of sec=krb5[ip].
1442896516e5SRick Macklem 		 */
1443896516e5SRick Macklem 		vfs_mount_error(mp, "syskrb5 should only be used "
1444896516e5SRick Macklem 		    "for sec=krb5[ip] mounts");
1445896516e5SRick Macklem 		error = EINVAL;
1446896516e5SRick Macklem 		goto out;
1447896516e5SRick Macklem 	}
1448896516e5SRick Macklem 
1449896516e5SRick Macklem 	if ((newflag & NFSMNT_SYSKRB5) != 0 && krbname[0] != '\0') {
1450896516e5SRick Macklem 		/*
1451896516e5SRick Macklem 		 * This option is used as an alternative to "gssname".
1452896516e5SRick Macklem 		 */
1453896516e5SRick Macklem 		vfs_mount_error(mp, "syskrb5 should not be used "
1454896516e5SRick Macklem 		    "with the gssname option");
1455896516e5SRick Macklem 		error = EINVAL;
1456896516e5SRick Macklem 		goto out;
1457896516e5SRick Macklem 	}
1458896516e5SRick Macklem 
14599ec7b004SRick Macklem 	args.fh = nfh;
1460385edc8eSRick Macklem 	error = mountnfs(&args, mp, nam, hst, krbname, krbnamelen, dirpath,
1461385edc8eSRick Macklem 	    dirlen, srvkrbname, srvkrbnamelen, &vp, td->td_ucred, td,
14621e0a518dSRick Macklem 	    nametimeo, negnametimeo, minvers, newflag, tlscertname, aconn);
14639ec7b004SRick Macklem out:
14649ec7b004SRick Macklem 	if (!error) {
14659ec7b004SRick Macklem 		MNT_ILOCK(mp);
1466dda11d4aSRick Macklem 		mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_NO_IOPF |
1467dda11d4aSRick Macklem 		    MNTK_USES_BCACHE;
1468abc15156SKonstantin Belousov 		if ((VFSTONFS(mp)->nm_flag & NFSMNT_NFSV4) != 0)
1469abc15156SKonstantin Belousov 			mp->mnt_kern_flag |= MNTK_NULL_NOCACHE;
14709ec7b004SRick Macklem 		MNT_IUNLOCK(mp);
14719ec7b004SRick Macklem 	}
1472599009e2SKonstantin Belousov 	free(hst, M_TEMP);
14739ec7b004SRick Macklem 	return (error);
14749ec7b004SRick Macklem }
14759ec7b004SRick Macklem 
14769ec7b004SRick Macklem /*
14779ec7b004SRick Macklem  * VFS Operations.
14789ec7b004SRick Macklem  *
14799ec7b004SRick Macklem  * mount system call
14809ec7b004SRick Macklem  * It seems a bit dumb to copyinstr() the host and path here and then
14819ec7b004SRick Macklem  * bcopy() them in mountnfs(), but I wanted to detect errors before
1482fefbf770SGleb Smirnoff  * doing the getsockaddr() call because getsockaddr() allocates an mbuf and
14839ec7b004SRick Macklem  * an error after that means that I have to release the mbuf.
14849ec7b004SRick Macklem  */
14859ec7b004SRick Macklem /* ARGSUSED */
14869ec7b004SRick Macklem static int
1487cc672d35SKirk McKusick nfs_cmount(struct mntarg *ma, void *data, uint64_t flags)
14889ec7b004SRick Macklem {
14899ec7b004SRick Macklem 	int error;
14909ec7b004SRick Macklem 	struct nfs_args args;
14919ec7b004SRick Macklem 
14929ec7b004SRick Macklem 	error = copyin(data, &args, sizeof (struct nfs_args));
14939ec7b004SRick Macklem 	if (error)
14949ec7b004SRick Macklem 		return error;
14959ec7b004SRick Macklem 
14969ec7b004SRick Macklem 	ma = mount_arg(ma, "nfs_args", &args, sizeof args);
14979ec7b004SRick Macklem 
14989ec7b004SRick Macklem 	error = kernel_mount(ma, flags);
14999ec7b004SRick Macklem 	return (error);
15009ec7b004SRick Macklem }
15019ec7b004SRick Macklem 
15029ec7b004SRick Macklem /*
15039ec7b004SRick Macklem  * Common code for mount and mountroot
15049ec7b004SRick Macklem  */
15059ec7b004SRick Macklem static int
15069ec7b004SRick Macklem mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
1507385edc8eSRick Macklem     char *hst, u_char *krbname, int krbnamelen, u_char *dirpath, int dirlen,
1508385edc8eSRick Macklem     u_char *srvkrbname, int srvkrbnamelen, struct vnode **vpp,
15091f60bfd8SRick Macklem     struct ucred *cred, struct thread *td, int nametimeo, int negnametimeo,
15101e0a518dSRick Macklem     int minvers, uint32_t newflag, char *tlscertname, int aconn)
15119ec7b004SRick Macklem {
15129ec7b004SRick Macklem 	struct nfsmount *nmp;
15139ec7b004SRick Macklem 	struct nfsnode *np;
151480e55695SRick Macklem 	int error, trycnt, ret;
15159ec7b004SRick Macklem 	struct nfsvattr nfsva;
15161f60bfd8SRick Macklem 	struct nfsclclient *clp;
15171f60bfd8SRick Macklem 	struct nfsclds *dsp, *tdsp;
15181f60bfd8SRick Macklem 	uint32_t lease;
1519a145cf3fSRick Macklem 	bool tryminvers;
1520896516e5SRick Macklem 	char *fakefh;
15219ec7b004SRick Macklem 	static u_int64_t clval = 0;
15226e4b6ff8SRick Macklem #ifdef KERN_TLS
15236e4b6ff8SRick Macklem 	u_int maxlen;
15246e4b6ff8SRick Macklem #endif
15259ec7b004SRick Macklem 
15261f60bfd8SRick Macklem 	NFSCL_DEBUG(3, "in mnt\n");
15271f60bfd8SRick Macklem 	clp = NULL;
15289ec7b004SRick Macklem 	if (mp->mnt_flag & MNT_UPDATE) {
15299ec7b004SRick Macklem 		nmp = VFSTONFS(mp);
15309ec7b004SRick Macklem 		printf("%s: MNT_UPDATE is no longer handled here\n", __func__);
1531222daa42SConrad Meyer 		free(nam, M_SONAME);
1532665b1365SRick Macklem 		free(tlscertname, M_NEWNFSMNT);
15339ec7b004SRick Macklem 		return (0);
15349ec7b004SRick Macklem 	} else {
15356e4b6ff8SRick Macklem 		/* NFS-over-TLS requires that rpctls be functioning. */
15366e4b6ff8SRick Macklem 		if ((newflag & NFSMNT_TLS) != 0) {
15376e4b6ff8SRick Macklem 			error = EINVAL;
15386e4b6ff8SRick Macklem #ifdef KERN_TLS
15394cdbb07bSRick Macklem 			/* KERN_TLS is only supported for TCP. */
15404cdbb07bSRick Macklem 			if (argp->sotype == SOCK_STREAM &&
15414cdbb07bSRick Macklem 			    rpctls_getinfo(&maxlen, true, false))
15426e4b6ff8SRick Macklem 				error = 0;
15436e4b6ff8SRick Macklem #endif
15446e4b6ff8SRick Macklem 			if (error != 0) {
15456e4b6ff8SRick Macklem 				free(nam, M_SONAME);
1546665b1365SRick Macklem 				free(tlscertname, M_NEWNFSMNT);
15476e4b6ff8SRick Macklem 				return (error);
15486e4b6ff8SRick Macklem 			}
15496e4b6ff8SRick Macklem 		}
1550222daa42SConrad Meyer 		nmp = malloc(sizeof (struct nfsmount) +
1551385edc8eSRick Macklem 		    krbnamelen + dirlen + srvkrbnamelen + 2,
1552385edc8eSRick Macklem 		    M_NEWNFSMNT, M_WAITOK | M_ZERO);
1553665b1365SRick Macklem 		nmp->nm_tlscertname = tlscertname;
15546e4b6ff8SRick Macklem 		nmp->nm_newflag = newflag;
15559ec7b004SRick Macklem 		TAILQ_INIT(&nmp->nm_bufq);
1556b2fc0141SRick Macklem 		TAILQ_INIT(&nmp->nm_sess);
15579ec7b004SRick Macklem 		if (clval == 0)
15589ec7b004SRick Macklem 			clval = (u_int64_t)nfsboottime.tv_sec;
15599ec7b004SRick Macklem 		nmp->nm_clval = clval++;
1560385edc8eSRick Macklem 		nmp->nm_krbnamelen = krbnamelen;
1561385edc8eSRick Macklem 		nmp->nm_dirpathlen = dirlen;
1562385edc8eSRick Macklem 		nmp->nm_srvkrbnamelen = srvkrbnamelen;
156363bde62eSRick Macklem 		if (td->td_ucred->cr_uid != (uid_t)0) {
15649ec7b004SRick Macklem 			/*
156563bde62eSRick Macklem 			 * nm_uid is used to get KerberosV credentials for
156663bde62eSRick Macklem 			 * the nfsv4 state handling operations if there is
156763bde62eSRick Macklem 			 * no host based principal set. Use the uid of
156863bde62eSRick Macklem 			 * this user if not root, since they are doing the
156963bde62eSRick Macklem 			 * mount. I don't think setting this for root will
157063bde62eSRick Macklem 			 * work, since root normally does not have user
157163bde62eSRick Macklem 			 * credentials in a credentials cache.
15729ec7b004SRick Macklem 			 */
157363bde62eSRick Macklem 			nmp->nm_uid = td->td_ucred->cr_uid;
15749ec7b004SRick Macklem 		} else {
15759ec7b004SRick Macklem 			/*
157663bde62eSRick Macklem 			 * Just set to -1, so it won't be used.
15779ec7b004SRick Macklem 			 */
15789ec7b004SRick Macklem 			nmp->nm_uid = (uid_t)-1;
15799ec7b004SRick Macklem 		}
15809ec7b004SRick Macklem 
15819ec7b004SRick Macklem 		/* Copy and null terminate all the names */
15829ec7b004SRick Macklem 		if (nmp->nm_krbnamelen > 0) {
15839ec7b004SRick Macklem 			bcopy(krbname, nmp->nm_krbname, nmp->nm_krbnamelen);
15849ec7b004SRick Macklem 			nmp->nm_name[nmp->nm_krbnamelen] = '\0';
15859ec7b004SRick Macklem 		}
15869ec7b004SRick Macklem 		if (nmp->nm_dirpathlen > 0) {
15879ec7b004SRick Macklem 			bcopy(dirpath, NFSMNT_DIRPATH(nmp),
15889ec7b004SRick Macklem 			    nmp->nm_dirpathlen);
15899ec7b004SRick Macklem 			nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen
15909ec7b004SRick Macklem 			    + 1] = '\0';
15919ec7b004SRick Macklem 		}
15929ec7b004SRick Macklem 		if (nmp->nm_srvkrbnamelen > 0) {
15939ec7b004SRick Macklem 			bcopy(srvkrbname, NFSMNT_SRVKRBNAME(nmp),
15949ec7b004SRick Macklem 			    nmp->nm_srvkrbnamelen);
15959ec7b004SRick Macklem 			nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen
15969ec7b004SRick Macklem 			    + nmp->nm_srvkrbnamelen + 2] = '\0';
15979ec7b004SRick Macklem 		}
15989ec7b004SRick Macklem 		nmp->nm_sockreq.nr_cred = crhold(cred);
15999ec7b004SRick Macklem 		mtx_init(&nmp->nm_sockreq.nr_mtx, "nfssock", NULL, MTX_DEF);
16009ec7b004SRick Macklem 		mp->mnt_data = nmp;
1601ca27c028SRick Macklem 		nmp->nm_getinfo = nfs_getnlminfo;
160290305aa3SRick Macklem 		nmp->nm_vinvalbuf = ncl_vinvalbuf;
16039ec7b004SRick Macklem 	}
16049ec7b004SRick Macklem 	vfs_getnewfsid(mp);
16059ec7b004SRick Macklem 	nmp->nm_mountp = mp;
16069ec7b004SRick Macklem 	mtx_init(&nmp->nm_mtx, "NFSmount lock", NULL, MTX_DEF | MTX_DUPOK);
160790379d61SRick Macklem 
160890379d61SRick Macklem 	/*
16090b17c7beSJohn Baldwin 	 * Since nfs_decode_args() might optionally set them, these
16100b17c7beSJohn Baldwin 	 * need to be set to defaults before the call, so that the
16110b17c7beSJohn Baldwin 	 * optional settings aren't overwritten.
161290379d61SRick Macklem 	 */
16130b17c7beSJohn Baldwin 	nmp->nm_nametimeo = nametimeo;
1614dd5b5a94SRick Macklem 	nmp->nm_negnametimeo = negnametimeo;
161590379d61SRick Macklem 	nmp->nm_timeo = NFS_TIMEO;
161690379d61SRick Macklem 	nmp->nm_retry = NFS_RETRANS;
161790379d61SRick Macklem 	nmp->nm_readahead = NFS_DEFRAHEAD;
1618afdfc9a4SAlexander Motin 
1619afdfc9a4SAlexander Motin 	/* This is empirical approximation of sqrt(hibufspace) * 256. */
1620afdfc9a4SAlexander Motin 	nmp->nm_wcommitsize = NFS_MAXBSIZE / 256;
1621afdfc9a4SAlexander Motin 	while ((long)nmp->nm_wcommitsize * nmp->nm_wcommitsize < hibufspace)
1622afdfc9a4SAlexander Motin 		nmp->nm_wcommitsize *= 2;
1623afdfc9a4SAlexander Motin 	nmp->nm_wcommitsize *= 256;
1624afdfc9a4SAlexander Motin 
1625a145cf3fSRick Macklem 	tryminvers = false;
1626a145cf3fSRick Macklem 	if ((argp->flags & NFSMNT_NFSV4) != 0) {
1627a145cf3fSRick Macklem 		if (minvers < 0) {
1628a145cf3fSRick Macklem 			tryminvers = true;
1629a145cf3fSRick Macklem 			minvers = NFSV42_MINORVERSION;
1630a145cf3fSRick Macklem 		}
16311f60bfd8SRick Macklem 		nmp->nm_minorvers = minvers;
1632a145cf3fSRick Macklem 	} else
16331f60bfd8SRick Macklem 		nmp->nm_minorvers = 0;
16349ec7b004SRick Macklem 
1635ca27c028SRick Macklem 	nfs_decode_args(mp, nmp, argp, hst, cred, td);
1636682eec57SRick Macklem 
16379ec7b004SRick Macklem 	/*
16389ec7b004SRick Macklem 	 * V2 can only handle 32 bit filesizes.  A 4GB-1 limit may be too
16399ec7b004SRick Macklem 	 * high, depending on whether we end up with negative offsets in
16409ec7b004SRick Macklem 	 * the client or server somewhere.  2GB-1 may be safer.
16419ec7b004SRick Macklem 	 *
16429ec7b004SRick Macklem 	 * For V3, ncl_fsinfo will adjust this as necessary.  Assume maximum
16439ec7b004SRick Macklem 	 * that we can handle until we find out otherwise.
16449ec7b004SRick Macklem 	 */
16459ec7b004SRick Macklem 	if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0)
16469ec7b004SRick Macklem 		nmp->nm_maxfilesize = 0xffffffffLL;
16479ec7b004SRick Macklem 	else
16481dcad8ecSRick Macklem 		nmp->nm_maxfilesize = OFF_MAX;
16499ec7b004SRick Macklem 
16509ec7b004SRick Macklem 	if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) {
16519ec7b004SRick Macklem 		nmp->nm_wsize = NFS_WSIZE;
16529ec7b004SRick Macklem 		nmp->nm_rsize = NFS_RSIZE;
16539ec7b004SRick Macklem 		nmp->nm_readdirsize = NFS_READDIRSIZE;
16549ec7b004SRick Macklem 	}
16559ec7b004SRick Macklem 	nmp->nm_numgrps = NFS_MAXGRPS;
16569ec7b004SRick Macklem 	nmp->nm_tprintf_delay = nfs_tprintf_delay;
16579ec7b004SRick Macklem 	if (nmp->nm_tprintf_delay < 0)
16589ec7b004SRick Macklem 		nmp->nm_tprintf_delay = 0;
16599ec7b004SRick Macklem 	nmp->nm_tprintf_initial_delay = nfs_tprintf_initial_delay;
16609ec7b004SRick Macklem 	if (nmp->nm_tprintf_initial_delay < 0)
16619ec7b004SRick Macklem 		nmp->nm_tprintf_initial_delay = 0;
16629ec7b004SRick Macklem 	nmp->nm_fhsize = argp->fhsize;
16639ec7b004SRick Macklem 	if (nmp->nm_fhsize > 0)
16649ec7b004SRick Macklem 		bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize);
166544de1834SMark Johnston 	strlcpy(mp->mnt_stat.f_mntfromname, hst, MNAMELEN);
16669ec7b004SRick Macklem 	nmp->nm_nam = nam;
16679ec7b004SRick Macklem 	/* Set up the sockets and per-host congestion */
16689ec7b004SRick Macklem 	nmp->nm_sotype = argp->sotype;
16699ec7b004SRick Macklem 	nmp->nm_soproto = argp->proto;
16709ec7b004SRick Macklem 	nmp->nm_sockreq.nr_prog = NFS_PROG;
16719ec7b004SRick Macklem 	if ((argp->flags & NFSMNT_NFSV4))
16729ec7b004SRick Macklem 		nmp->nm_sockreq.nr_vers = NFS_VER4;
16739ec7b004SRick Macklem 	else if ((argp->flags & NFSMNT_NFSV3))
16749ec7b004SRick Macklem 		nmp->nm_sockreq.nr_vers = NFS_VER3;
16759ec7b004SRick Macklem 	else
16769ec7b004SRick Macklem 		nmp->nm_sockreq.nr_vers = NFS_VER2;
16779ec7b004SRick Macklem 
16781e0a518dSRick Macklem 	if ((error = newnfs_connect(nmp, &nmp->nm_sockreq, cred, td, 0, false,
16791e0a518dSRick Macklem 	    &nmp->nm_sockreq.nr_client)))
16809ec7b004SRick Macklem 		goto bad;
1681aed98fa5SRick Macklem 	/* For NFSv4, get the clientid now. */
1682aed98fa5SRick Macklem 	if ((argp->flags & NFSMNT_NFSV4) != 0) {
16831f60bfd8SRick Macklem 		NFSCL_DEBUG(3, "at getcl\n");
1684120b20bdSRick Macklem 		error = nfscl_getcl(mp, cred, td, tryminvers, true, &clp);
16851f60bfd8SRick Macklem 		NFSCL_DEBUG(3, "aft getcl=%d\n", error);
16861f60bfd8SRick Macklem 		if (error != 0)
16871f60bfd8SRick Macklem 			goto bad;
16881e0a518dSRick Macklem 		if (aconn > 0 && nmp->nm_minorvers == 0) {
16891e0a518dSRick Macklem 			vfs_mount_error(mp, "nconnect should only be used "
16901e0a518dSRick Macklem 			    "for NFSv4.1/4.2 mounts");
16911e0a518dSRick Macklem 			error = EINVAL;
16921e0a518dSRick Macklem 			goto bad;
16931e0a518dSRick Macklem 		}
1694896516e5SRick Macklem 		if (NFSHASSYSKRB5(nmp) && nmp->nm_minorvers == 0) {
1695896516e5SRick Macklem 			vfs_mount_error(mp, "syskrb5 should only be used "
1696896516e5SRick Macklem 			    "for NFSv4.1/4.2 mounts");
1697896516e5SRick Macklem 			error = EINVAL;
1698896516e5SRick Macklem 			goto bad;
1699896516e5SRick Macklem 		}
17001f60bfd8SRick Macklem 	}
17011f60bfd8SRick Macklem 
17021f60bfd8SRick Macklem 	if (nmp->nm_fhsize == 0 && (nmp->nm_flag & NFSMNT_NFSV4) &&
17031f60bfd8SRick Macklem 	    nmp->nm_dirpathlen > 0) {
17041f60bfd8SRick Macklem 		NFSCL_DEBUG(3, "in dirp\n");
17051f60bfd8SRick Macklem 		/*
17061f60bfd8SRick Macklem 		 * If the fhsize on the mount point == 0 for V4, the mount
17071f60bfd8SRick Macklem 		 * path needs to be looked up.
17081f60bfd8SRick Macklem 		 */
17091f60bfd8SRick Macklem 		trycnt = 3;
17101f60bfd8SRick Macklem 		do {
17111f60bfd8SRick Macklem 			error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp),
17121f60bfd8SRick Macklem 			    cred, td);
17131f60bfd8SRick Macklem 			NFSCL_DEBUG(3, "aft dirp=%d\n", error);
1714896516e5SRick Macklem 			if (error != 0 && (!NFSHASSYSKRB5(nmp) ||
1715896516e5SRick Macklem 			    error != NFSERR_WRONGSEC))
17161f60bfd8SRick Macklem 				(void) nfs_catnap(PZERO, error, "nfsgetdirp");
1717896516e5SRick Macklem 		} while (error != 0 && --trycnt > 0 &&
1718896516e5SRick Macklem 		    (!NFSHASSYSKRB5(nmp) || error != NFSERR_WRONGSEC));
1719896516e5SRick Macklem 		if (error != 0 && (!NFSHASSYSKRB5(nmp) ||
1720896516e5SRick Macklem 		    error != NFSERR_WRONGSEC))
17211f60bfd8SRick Macklem 			goto bad;
17221f60bfd8SRick Macklem 	}
17239ec7b004SRick Macklem 
17249ec7b004SRick Macklem 	/*
17259ec7b004SRick Macklem 	 * A reference count is needed on the nfsnode representing the
17269ec7b004SRick Macklem 	 * remote root.  If this object is not persistent, then backward
17279ec7b004SRick Macklem 	 * traversals of the mount point (i.e. "..") will not work if
17289ec7b004SRick Macklem 	 * the nfsnode gets flushed out of the cache. Ufs does not have
17299ec7b004SRick Macklem 	 * this problem, because one can identify root inodes by their
17301dc349abSEd Maste 	 * number == UFS_ROOTINO (2).
1731896516e5SRick Macklem 	 * For the "syskrb5" mount, the file handle might not have
1732896516e5SRick Macklem 	 * been acquired.  As such, use a "fake" file handle which
1733896516e5SRick Macklem 	 * can never be returned by a server for the root vnode.
17349ec7b004SRick Macklem 	 */
1735896516e5SRick Macklem 	if (nmp->nm_fhsize > 0 || NFSHASSYSKRB5(nmp)) {
173680e55695SRick Macklem 		/*
173780e55695SRick Macklem 		 * Set f_iosize to NFS_DIRBLKSIZ so that bo_bsize gets set
173880e55695SRick Macklem 		 * non-zero for the root vnode. f_iosize will be set correctly
173980e55695SRick Macklem 		 * by nfs_statfs() before any I/O occurs.
174080e55695SRick Macklem 		 */
174180e55695SRick Macklem 		mp->mnt_stat.f_iosize = NFS_DIRBLKSIZ;
1742896516e5SRick Macklem 		if (nmp->nm_fhsize == 0) {
1743896516e5SRick Macklem 			fakefh = malloc(NFSX_FHMAX + 1, M_TEMP, M_WAITOK |
1744896516e5SRick Macklem 			    M_ZERO);
1745896516e5SRick Macklem 			error = ncl_nget(mp, fakefh, NFSX_FHMAX + 1, &np,
1746896516e5SRick Macklem 			    LK_EXCLUSIVE);
1747896516e5SRick Macklem 			free(fakefh, M_TEMP);
1748896516e5SRick Macklem 			nmp->nm_privflag |= NFSMNTP_FAKEROOTFH;
1749896516e5SRick Macklem 		} else
17504b3a38ecSRick Macklem 			error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np,
17514b3a38ecSRick Macklem 			    LK_EXCLUSIVE);
17529ec7b004SRick Macklem 		if (error)
17539ec7b004SRick Macklem 			goto bad;
17549ec7b004SRick Macklem 		*vpp = NFSTOV(np);
17559ec7b004SRick Macklem 
17569ec7b004SRick Macklem 		/*
17579ec7b004SRick Macklem 		 * Get file attributes and transfer parameters for the
17589ec7b004SRick Macklem 		 * mountpoint.  This has the side effect of filling in
17599ec7b004SRick Macklem 		 * (*vpp)->v_type with the correct value.
17609ec7b004SRick Macklem 		 */
1761896516e5SRick Macklem 		ret = ENXIO;
1762896516e5SRick Macklem 		if (nmp->nm_fhsize > 0)
1763896516e5SRick Macklem 			ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh,
1764896516e5SRick Macklem 			    nmp->nm_fhsize, 1, cred, td, &nfsva, NULL, &lease);
17659ec7b004SRick Macklem 		if (ret) {
17669ec7b004SRick Macklem 			/*
17679ec7b004SRick Macklem 			 * Just set default values to get things going.
17689ec7b004SRick Macklem 			 */
17699ec7b004SRick Macklem 			NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr));
17709ec7b004SRick Macklem 			nfsva.na_vattr.va_type = VDIR;
17719ec7b004SRick Macklem 			nfsva.na_vattr.va_mode = 0777;
17729ec7b004SRick Macklem 			nfsva.na_vattr.va_nlink = 100;
17739ec7b004SRick Macklem 			nfsva.na_vattr.va_uid = (uid_t)0;
17749ec7b004SRick Macklem 			nfsva.na_vattr.va_gid = (gid_t)0;
17759ec7b004SRick Macklem 			nfsva.na_vattr.va_fileid = 2;
17769ec7b004SRick Macklem 			nfsva.na_vattr.va_gen = 1;
17779ec7b004SRick Macklem 			nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE;
17789ec7b004SRick Macklem 			nfsva.na_vattr.va_size = 512 * 1024;
1779896516e5SRick Macklem 			lease = 20;
17809ec7b004SRick Macklem 		}
17814ad3423bSRick Macklem 		(void) nfscl_loadattrcache(vpp, &nfsva, NULL, 0, 1);
1782aed98fa5SRick Macklem 		if ((argp->flags & NFSMNT_NFSV4) != 0) {
17831f60bfd8SRick Macklem 			NFSCL_DEBUG(3, "lease=%d\n", (int)lease);
17841f60bfd8SRick Macklem 			NFSLOCKCLSTATE();
17851f60bfd8SRick Macklem 			clp->nfsc_renew = NFSCL_RENEW(lease);
17861f60bfd8SRick Macklem 			clp->nfsc_expire = NFSD_MONOSEC + clp->nfsc_renew;
17871f60bfd8SRick Macklem 			clp->nfsc_clientidrev++;
17881f60bfd8SRick Macklem 			if (clp->nfsc_clientidrev == 0)
17891f60bfd8SRick Macklem 				clp->nfsc_clientidrev++;
17901f60bfd8SRick Macklem 			NFSUNLOCKCLSTATE();
17911f60bfd8SRick Macklem 			/*
17921f60bfd8SRick Macklem 			 * Mount will succeed, so the renew thread can be
17931f60bfd8SRick Macklem 			 * started now.
17941f60bfd8SRick Macklem 			 */
17951f60bfd8SRick Macklem 			nfscl_start_renewthread(clp);
17961f60bfd8SRick Macklem 			nfscl_clientrelease(clp);
17971f60bfd8SRick Macklem 		}
17989ec7b004SRick Macklem 		if (argp->flags & NFSMNT_NFSV3)
17999ec7b004SRick Macklem 			ncl_fsinfo(nmp, *vpp, cred, td);
18009ec7b004SRick Macklem 
1801484c842dSRick Macklem 		/* Mark if the mount point supports NFSv4 ACLs. */
1802484c842dSRick Macklem 		if ((argp->flags & NFSMNT_NFSV4) != 0 && nfsrv_useacl != 0 &&
1803484c842dSRick Macklem 		    ret == 0 &&
1804484c842dSRick Macklem 		    NFSISSET_ATTRBIT(&nfsva.na_suppattr, NFSATTRBIT_ACL)) {
1805484c842dSRick Macklem 			MNT_ILOCK(mp);
1806484c842dSRick Macklem 			mp->mnt_flag |= MNT_NFS4ACLS;
1807484c842dSRick Macklem 			MNT_IUNLOCK(mp);
1808484c842dSRick Macklem 		}
1809484c842dSRick Macklem 
18101e0a518dSRick Macklem 		/* Can now allow additional connections. */
18111e0a518dSRick Macklem 		if (aconn > 0)
18121e0a518dSRick Macklem 			nmp->nm_aconnect = aconn;
18131e0a518dSRick Macklem 
18149ec7b004SRick Macklem 		/*
18159ec7b004SRick Macklem 		 * Lose the lock but keep the ref.
18169ec7b004SRick Macklem 		 */
1817b249ce48SMateusz Guzik 		NFSVOPUNLOCK(*vpp);
1818d511f93eSMateusz Guzik 		vfs_cache_root_set(mp, *vpp);
18199ec7b004SRick Macklem 		return (0);
18209ec7b004SRick Macklem 	}
18219ec7b004SRick Macklem 	error = EIO;
18229ec7b004SRick Macklem 
18239ec7b004SRick Macklem bad:
18241f60bfd8SRick Macklem 	if (clp != NULL)
18251f60bfd8SRick Macklem 		nfscl_clientrelease(clp);
18261e0a518dSRick Macklem 	newnfs_disconnect(NULL, &nmp->nm_sockreq);
18279ec7b004SRick Macklem 	crfree(nmp->nm_sockreq.nr_cred);
182888a2437aSRick Macklem 	if (nmp->nm_sockreq.nr_auth != NULL)
182988a2437aSRick Macklem 		AUTH_DESTROY(nmp->nm_sockreq.nr_auth);
18309ec7b004SRick Macklem 	mtx_destroy(&nmp->nm_sockreq.nr_mtx);
18319ec7b004SRick Macklem 	mtx_destroy(&nmp->nm_mtx);
18321f60bfd8SRick Macklem 	if (nmp->nm_clp != NULL) {
18331f60bfd8SRick Macklem 		NFSLOCKCLSTATE();
18341f60bfd8SRick Macklem 		LIST_REMOVE(nmp->nm_clp, nfsc_list);
18351f60bfd8SRick Macklem 		NFSUNLOCKCLSTATE();
18361f60bfd8SRick Macklem 		free(nmp->nm_clp, M_NFSCLCLIENT);
18371f60bfd8SRick Macklem 	}
1838c20a7210SRick Macklem 	TAILQ_FOREACH_SAFE(dsp, &nmp->nm_sess, nfsclds_list, tdsp) {
1839c20a7210SRick Macklem 		if (dsp != TAILQ_FIRST(&nmp->nm_sess) &&
1840c20a7210SRick Macklem 		    dsp->nfsclds_sockp != NULL)
18411e0a518dSRick Macklem 			newnfs_disconnect(NULL, dsp->nfsclds_sockp);
18421f60bfd8SRick Macklem 		nfscl_freenfsclds(dsp);
1843c20a7210SRick Macklem 	}
1844665b1365SRick Macklem 	free(nmp->nm_tlscertname, M_NEWNFSMNT);
1845222daa42SConrad Meyer 	free(nmp, M_NEWNFSMNT);
1846222daa42SConrad Meyer 	free(nam, M_SONAME);
18479ec7b004SRick Macklem 	return (error);
18489ec7b004SRick Macklem }
18499ec7b004SRick Macklem 
18509ec7b004SRick Macklem /*
18519ec7b004SRick Macklem  * unmount system call
18529ec7b004SRick Macklem  */
18539ec7b004SRick Macklem static int
1854dfd233edSAttilio Rao nfs_unmount(struct mount *mp, int mntflags)
18559ec7b004SRick Macklem {
1856dfd233edSAttilio Rao 	struct thread *td;
18579ec7b004SRick Macklem 	struct nfsmount *nmp;
185864a0e848SRick Macklem 	int error, flags = 0, i, trycnt = 0;
18591f60bfd8SRick Macklem 	struct nfsclds *dsp, *tdsp;
186044122258SRick Macklem 	struct nfscldeleg *dp, *ndp;
186144122258SRick Macklem 	struct nfscldeleghead dh;
18629ec7b004SRick Macklem 
1863dfd233edSAttilio Rao 	td = curthread;
186444122258SRick Macklem 	TAILQ_INIT(&dh);
1865dfd233edSAttilio Rao 
18669ec7b004SRick Macklem 	if (mntflags & MNT_FORCE)
18679ec7b004SRick Macklem 		flags |= FORCECLOSE;
18689ec7b004SRick Macklem 	nmp = VFSTONFS(mp);
186990d2dfabSRick Macklem 	error = 0;
18709ec7b004SRick Macklem 	/*
18719ec7b004SRick Macklem 	 * Goes something like this..
18729ec7b004SRick Macklem 	 * - Call vflush() to clear out vnodes for this filesystem
18739ec7b004SRick Macklem 	 * - Close the socket
18749ec7b004SRick Macklem 	 * - Free up the data structures
18759ec7b004SRick Macklem 	 */
18769ec7b004SRick Macklem 	/* In the forced case, cancel any outstanding requests. */
18779ec7b004SRick Macklem 	if (mntflags & MNT_FORCE) {
187890d2dfabSRick Macklem 		NFSDDSLOCK();
187990d2dfabSRick Macklem 		if (nfsv4_findmirror(nmp) != NULL)
188090d2dfabSRick Macklem 			error = ENXIO;
188190d2dfabSRick Macklem 		NFSDDSUNLOCK();
188290d2dfabSRick Macklem 		if (error)
188390d2dfabSRick Macklem 			goto out;
18849ec7b004SRick Macklem 		error = newnfs_nmcancelreqs(nmp);
18859ec7b004SRick Macklem 		if (error)
18869ec7b004SRick Macklem 			goto out;
18879ec7b004SRick Macklem 		/* For a forced close, get rid of the renew thread now */
188844122258SRick Macklem 		nfscl_umount(nmp, td, &dh);
18899ec7b004SRick Macklem 	}
18909ec7b004SRick Macklem 	/* We hold 1 extra ref on the root vnode; see comment in mountnfs(). */
18919ec7b004SRick Macklem 	do {
18929ec7b004SRick Macklem 		error = vflush(mp, 1, flags, td);
18939ec7b004SRick Macklem 		if ((mntflags & MNT_FORCE) && error != 0 && ++trycnt < 30)
189423f929dfSRick Macklem 			(void) nfs_catnap(PSOCK, error, "newndm");
18959ec7b004SRick Macklem 	} while ((mntflags & MNT_FORCE) && error != 0 && trycnt < 30);
18969ec7b004SRick Macklem 	if (error)
18979ec7b004SRick Macklem 		goto out;
18989ec7b004SRick Macklem 
18999ec7b004SRick Macklem 	/*
19009ec7b004SRick Macklem 	 * We are now committed to the unmount.
19019ec7b004SRick Macklem 	 */
19029ec7b004SRick Macklem 	if ((mntflags & MNT_FORCE) == 0)
190344122258SRick Macklem 		nfscl_umount(nmp, td, NULL);
190447cbff34SRick Macklem 	else {
190547cbff34SRick Macklem 		mtx_lock(&nmp->nm_mtx);
190647cbff34SRick Macklem 		nmp->nm_privflag |= NFSMNTP_FORCEDISM;
190747cbff34SRick Macklem 		mtx_unlock(&nmp->nm_mtx);
190847cbff34SRick Macklem 	}
190964a0e848SRick Macklem 	/* Make sure no nfsiods are assigned to this mount. */
1910b662b41eSRick Macklem 	NFSLOCKIOD();
191164a0e848SRick Macklem 	for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
191264a0e848SRick Macklem 		if (ncl_iodmount[i] == nmp) {
191364a0e848SRick Macklem 			ncl_iodwant[i] = NFSIOD_AVAILABLE;
191464a0e848SRick Macklem 			ncl_iodmount[i] = NULL;
191564a0e848SRick Macklem 		}
1916b662b41eSRick Macklem 	NFSUNLOCKIOD();
191747cbff34SRick Macklem 
191847cbff34SRick Macklem 	/*
191947cbff34SRick Macklem 	 * We can now set mnt_data to NULL and wait for
192047cbff34SRick Macklem 	 * nfssvc(NFSSVC_FORCEDISM) to complete.
192147cbff34SRick Macklem 	 */
192247cbff34SRick Macklem 	mtx_lock(&mountlist_mtx);
192347cbff34SRick Macklem 	mtx_lock(&nmp->nm_mtx);
192447cbff34SRick Macklem 	mp->mnt_data = NULL;
192547cbff34SRick Macklem 	mtx_unlock(&mountlist_mtx);
192647cbff34SRick Macklem 	while ((nmp->nm_privflag & NFSMNTP_CANCELRPCS) != 0)
192747cbff34SRick Macklem 		msleep(nmp, &nmp->nm_mtx, PVFS, "nfsfdism", 0);
192847cbff34SRick Macklem 	mtx_unlock(&nmp->nm_mtx);
192947cbff34SRick Macklem 
19301e0a518dSRick Macklem 	newnfs_disconnect(nmp, &nmp->nm_sockreq);
19319ec7b004SRick Macklem 	crfree(nmp->nm_sockreq.nr_cred);
1932222daa42SConrad Meyer 	free(nmp->nm_nam, M_SONAME);
193388a2437aSRick Macklem 	if (nmp->nm_sockreq.nr_auth != NULL)
193488a2437aSRick Macklem 		AUTH_DESTROY(nmp->nm_sockreq.nr_auth);
19359ec7b004SRick Macklem 	mtx_destroy(&nmp->nm_sockreq.nr_mtx);
19369ec7b004SRick Macklem 	mtx_destroy(&nmp->nm_mtx);
1937c20a7210SRick Macklem 	TAILQ_FOREACH_SAFE(dsp, &nmp->nm_sess, nfsclds_list, tdsp) {
1938c20a7210SRick Macklem 		if (dsp != TAILQ_FIRST(&nmp->nm_sess) &&
1939c20a7210SRick Macklem 		    dsp->nfsclds_sockp != NULL)
19401e0a518dSRick Macklem 			newnfs_disconnect(NULL, dsp->nfsclds_sockp);
19411f60bfd8SRick Macklem 		nfscl_freenfsclds(dsp);
1942c20a7210SRick Macklem 	}
1943665b1365SRick Macklem 	free(nmp->nm_tlscertname, M_NEWNFSMNT);
1944222daa42SConrad Meyer 	free(nmp, M_NEWNFSMNT);
194544122258SRick Macklem 
194644122258SRick Macklem 	/* Free up the delegation structures for forced dismounts. */
194744122258SRick Macklem 	TAILQ_FOREACH_SAFE(dp, &dh, nfsdl_list, ndp) {
194844122258SRick Macklem 		TAILQ_REMOVE(&dh, dp, nfsdl_list);
194944122258SRick Macklem 		free(dp, M_NFSCLDELEG);
195044122258SRick Macklem 	}
19519ec7b004SRick Macklem out:
19529ec7b004SRick Macklem 	return (error);
19539ec7b004SRick Macklem }
19549ec7b004SRick Macklem 
19559ec7b004SRick Macklem /*
19569ec7b004SRick Macklem  * Return root of a filesystem
19579ec7b004SRick Macklem  */
19589ec7b004SRick Macklem static int
1959dfd233edSAttilio Rao nfs_root(struct mount *mp, int flags, struct vnode **vpp)
19609ec7b004SRick Macklem {
19619ec7b004SRick Macklem 	struct vnode *vp;
19629ec7b004SRick Macklem 	struct nfsmount *nmp;
19639ec7b004SRick Macklem 	struct nfsnode *np;
19649ec7b004SRick Macklem 	int error;
1965896516e5SRick Macklem 	char *fakefh;
19669ec7b004SRick Macklem 
19679ec7b004SRick Macklem 	nmp = VFSTONFS(mp);
1968896516e5SRick Macklem 	if ((nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0) {
1969896516e5SRick Macklem 		/* Attempt to get the actual root file handle. */
1970896516e5SRick Macklem 		if (nmp->nm_fhsize == 0)
1971896516e5SRick Macklem 			error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp),
1972896516e5SRick Macklem 			    curthread->td_ucred, curthread);
1973896516e5SRick Macklem 		fakefh = malloc(NFSX_FHMAX + 1, M_TEMP, M_WAITOK | M_ZERO);
1974896516e5SRick Macklem 		error = ncl_nget(mp, fakefh, NFSX_FHMAX + 1, &np, flags);
1975896516e5SRick Macklem 		free(fakefh, M_TEMP);
1976896516e5SRick Macklem 	} else {
19774b3a38ecSRick Macklem 		error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, flags);
1978896516e5SRick Macklem 	}
19799ec7b004SRick Macklem 	if (error)
19809ec7b004SRick Macklem 		return error;
19819ec7b004SRick Macklem 	vp = NFSTOV(np);
19829ec7b004SRick Macklem 	/*
19839ec7b004SRick Macklem 	 * Get transfer parameters and attributes for root vnode once.
19849ec7b004SRick Macklem 	 */
19859ec7b004SRick Macklem 	mtx_lock(&nmp->nm_mtx);
19869ec7b004SRick Macklem 	if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) {
19879ec7b004SRick Macklem 		mtx_unlock(&nmp->nm_mtx);
19889ec7b004SRick Macklem 		ncl_fsinfo(nmp, vp, curthread->td_ucred, curthread);
19899ec7b004SRick Macklem 	} else
19909ec7b004SRick Macklem 		mtx_unlock(&nmp->nm_mtx);
19919ec7b004SRick Macklem 	if (vp->v_type == VNON)
19929ec7b004SRick Macklem 	    vp->v_type = VDIR;
19939ec7b004SRick Macklem 	vp->v_vflag |= VV_ROOT;
19949ec7b004SRick Macklem 	*vpp = vp;
19959ec7b004SRick Macklem 	return (0);
19969ec7b004SRick Macklem }
19979ec7b004SRick Macklem 
19989ec7b004SRick Macklem /*
19999ec7b004SRick Macklem  * Flush out the buffer cache
20009ec7b004SRick Macklem  */
20019ec7b004SRick Macklem /* ARGSUSED */
20029ec7b004SRick Macklem static int
2003dfd233edSAttilio Rao nfs_sync(struct mount *mp, int waitfor)
20049ec7b004SRick Macklem {
20059ec7b004SRick Macklem 	struct vnode *vp, *mvp;
2006dfd233edSAttilio Rao 	struct thread *td;
20079ec7b004SRick Macklem 	int error, allerror = 0;
20089ec7b004SRick Macklem 
2009dfd233edSAttilio Rao 	td = curthread;
2010dfd233edSAttilio Rao 
20118b5e8315SRick Macklem 	MNT_ILOCK(mp);
20128b5e8315SRick Macklem 	/*
20138b5e8315SRick Macklem 	 * If a forced dismount is in progress, return from here so that
20148b5e8315SRick Macklem 	 * the umount(2) syscall doesn't get stuck in VFS_SYNC() before
20158b5e8315SRick Macklem 	 * calling VFS_UNMOUNT().
20168b5e8315SRick Macklem 	 */
201716f300faSRick Macklem 	if (NFSCL_FORCEDISM(mp)) {
20188b5e8315SRick Macklem 		MNT_IUNLOCK(mp);
20198b5e8315SRick Macklem 		return (EBADF);
20208b5e8315SRick Macklem 	}
202171469bb3SKirk McKusick 	MNT_IUNLOCK(mp);
20228b5e8315SRick Macklem 
20235ff7fb76SMateusz Guzik 	if (waitfor == MNT_LAZY)
20245ff7fb76SMateusz Guzik 		return (0);
20255ff7fb76SMateusz Guzik 
20269ec7b004SRick Macklem 	/*
20279ec7b004SRick Macklem 	 * Force stale buffer cache information to be flushed.
20289ec7b004SRick Macklem 	 */
20299ec7b004SRick Macklem loop:
203071469bb3SKirk McKusick 	MNT_VNODE_FOREACH_ALL(vp, mp, mvp) {
20319ec7b004SRick Macklem 		/* XXX Racy bv_cnt check. */
20325ff7fb76SMateusz Guzik 		if (NFSVOPISLOCKED(vp) || vp->v_bufobj.bo_dirty.bv_cnt == 0) {
20339ec7b004SRick Macklem 			VI_UNLOCK(vp);
20349ec7b004SRick Macklem 			continue;
20359ec7b004SRick Macklem 		}
2036a92a971bSMateusz Guzik 		if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK)) {
203771469bb3SKirk McKusick 			MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp);
20389ec7b004SRick Macklem 			goto loop;
20399ec7b004SRick Macklem 		}
20409ec7b004SRick Macklem 		error = VOP_FSYNC(vp, waitfor, td);
20419ec7b004SRick Macklem 		if (error)
20429ec7b004SRick Macklem 			allerror = error;
2043b249ce48SMateusz Guzik 		NFSVOPUNLOCK(vp);
20449ec7b004SRick Macklem 		vrele(vp);
20459ec7b004SRick Macklem 	}
20469ec7b004SRick Macklem 	return (allerror);
20479ec7b004SRick Macklem }
20489ec7b004SRick Macklem 
20499ec7b004SRick Macklem static int
20509ec7b004SRick Macklem nfs_sysctl(struct mount *mp, fsctlop_t op, struct sysctl_req *req)
20519ec7b004SRick Macklem {
20529ec7b004SRick Macklem 	struct nfsmount *nmp = VFSTONFS(mp);
20539ec7b004SRick Macklem 	struct vfsquery vq;
20549ec7b004SRick Macklem 	int error;
20559ec7b004SRick Macklem 
20569ec7b004SRick Macklem 	bzero(&vq, sizeof(vq));
20579ec7b004SRick Macklem 	switch (op) {
20589ec7b004SRick Macklem #if 0
20599ec7b004SRick Macklem 	case VFS_CTL_NOLOCKS:
20609ec7b004SRick Macklem 		val = (nmp->nm_flag & NFSMNT_NOLOCKS) ? 1 : 0;
20619ec7b004SRick Macklem  		if (req->oldptr != NULL) {
20629ec7b004SRick Macklem  			error = SYSCTL_OUT(req, &val, sizeof(val));
20639ec7b004SRick Macklem  			if (error)
20649ec7b004SRick Macklem  				return (error);
20659ec7b004SRick Macklem  		}
20669ec7b004SRick Macklem  		if (req->newptr != NULL) {
20679ec7b004SRick Macklem  			error = SYSCTL_IN(req, &val, sizeof(val));
20689ec7b004SRick Macklem  			if (error)
20699ec7b004SRick Macklem  				return (error);
20709ec7b004SRick Macklem 			if (val)
20719ec7b004SRick Macklem 				nmp->nm_flag |= NFSMNT_NOLOCKS;
20729ec7b004SRick Macklem 			else
20739ec7b004SRick Macklem 				nmp->nm_flag &= ~NFSMNT_NOLOCKS;
20749ec7b004SRick Macklem  		}
20759ec7b004SRick Macklem 		break;
20769ec7b004SRick Macklem #endif
20779ec7b004SRick Macklem 	case VFS_CTL_QUERY:
20789ec7b004SRick Macklem 		mtx_lock(&nmp->nm_mtx);
20799ec7b004SRick Macklem 		if (nmp->nm_state & NFSSTA_TIMEO)
20809ec7b004SRick Macklem 			vq.vq_flags |= VQ_NOTRESP;
20819ec7b004SRick Macklem 		mtx_unlock(&nmp->nm_mtx);
20829ec7b004SRick Macklem #if 0
20839ec7b004SRick Macklem 		if (!(nmp->nm_flag & NFSMNT_NOLOCKS) &&
20849ec7b004SRick Macklem 		    (nmp->nm_state & NFSSTA_LOCKTIMEO))
20859ec7b004SRick Macklem 			vq.vq_flags |= VQ_NOTRESPLOCK;
20869ec7b004SRick Macklem #endif
20879ec7b004SRick Macklem 		error = SYSCTL_OUT(req, &vq, sizeof(vq));
20889ec7b004SRick Macklem 		break;
20899ec7b004SRick Macklem  	case VFS_CTL_TIMEO:
20909ec7b004SRick Macklem  		if (req->oldptr != NULL) {
20919ec7b004SRick Macklem  			error = SYSCTL_OUT(req, &nmp->nm_tprintf_initial_delay,
20929ec7b004SRick Macklem  			    sizeof(nmp->nm_tprintf_initial_delay));
20939ec7b004SRick Macklem  			if (error)
20949ec7b004SRick Macklem  				return (error);
20959ec7b004SRick Macklem  		}
20969ec7b004SRick Macklem  		if (req->newptr != NULL) {
20979ec7b004SRick Macklem 			error = vfs_suser(mp, req->td);
20989ec7b004SRick Macklem 			if (error)
20999ec7b004SRick Macklem 				return (error);
21009ec7b004SRick Macklem  			error = SYSCTL_IN(req, &nmp->nm_tprintf_initial_delay,
21019ec7b004SRick Macklem  			    sizeof(nmp->nm_tprintf_initial_delay));
21029ec7b004SRick Macklem  			if (error)
21039ec7b004SRick Macklem  				return (error);
21049ec7b004SRick Macklem  			if (nmp->nm_tprintf_initial_delay < 0)
21059ec7b004SRick Macklem  				nmp->nm_tprintf_initial_delay = 0;
21069ec7b004SRick Macklem  		}
21079ec7b004SRick Macklem 		break;
21089ec7b004SRick Macklem 	default:
21099ec7b004SRick Macklem 		return (ENOTSUP);
21109ec7b004SRick Macklem 	}
21119ec7b004SRick Macklem 	return (0);
21129ec7b004SRick Macklem }
21139ec7b004SRick Macklem 
2114ca27c028SRick Macklem /*
21158fe6bddfSRick Macklem  * Purge any RPCs in progress, so that they will all return errors.
21168fe6bddfSRick Macklem  * This allows dounmount() to continue as far as VFS_UNMOUNT() for a
21178fe6bddfSRick Macklem  * forced dismount.
21188fe6bddfSRick Macklem  */
21198fe6bddfSRick Macklem static void
21208fe6bddfSRick Macklem nfs_purge(struct mount *mp)
21218fe6bddfSRick Macklem {
21228fe6bddfSRick Macklem 	struct nfsmount *nmp = VFSTONFS(mp);
21238fe6bddfSRick Macklem 
21248fe6bddfSRick Macklem 	newnfs_nmcancelreqs(nmp);
21258fe6bddfSRick Macklem }
21268fe6bddfSRick Macklem 
21278fe6bddfSRick Macklem /*
2128ca27c028SRick Macklem  * Extract the information needed by the nlm from the nfs vnode.
2129ca27c028SRick Macklem  */
2130ca27c028SRick Macklem static void
21314d4f9a37SRick Macklem nfs_getnlminfo(struct vnode *vp, uint8_t *fhp, size_t *fhlenp,
213290305aa3SRick Macklem     struct sockaddr_storage *sp, int *is_v3p, off_t *sizep,
213390305aa3SRick Macklem     struct timeval *timeop)
2134ca27c028SRick Macklem {
2135ca27c028SRick Macklem 	struct nfsmount *nmp;
2136ca27c028SRick Macklem 	struct nfsnode *np = VTONFS(vp);
2137ca27c028SRick Macklem 
2138ca27c028SRick Macklem 	nmp = VFSTONFS(vp->v_mount);
2139ca27c028SRick Macklem 	if (fhlenp != NULL)
21404d4f9a37SRick Macklem 		*fhlenp = (size_t)np->n_fhp->nfh_len;
2141ca27c028SRick Macklem 	if (fhp != NULL)
2142ca27c028SRick Macklem 		bcopy(np->n_fhp->nfh_fh, fhp, np->n_fhp->nfh_len);
2143ca27c028SRick Macklem 	if (sp != NULL)
2144ca27c028SRick Macklem 		bcopy(nmp->nm_nam, sp, min(nmp->nm_nam->sa_len, sizeof(*sp)));
2145ca27c028SRick Macklem 	if (is_v3p != NULL)
2146ca27c028SRick Macklem 		*is_v3p = NFS_ISV3(vp);
2147ca27c028SRick Macklem 	if (sizep != NULL)
2148ca27c028SRick Macklem 		*sizep = np->n_size;
214990305aa3SRick Macklem 	if (timeop != NULL) {
215090305aa3SRick Macklem 		timeop->tv_sec = nmp->nm_timeo / NFS_HZ;
215190305aa3SRick Macklem 		timeop->tv_usec = (nmp->nm_timeo % NFS_HZ) * (1000000 / NFS_HZ);
215290305aa3SRick Macklem 	}
2153ca27c028SRick Macklem }
2154ca27c028SRick Macklem 
215599d2727dSRick Macklem /*
215699d2727dSRick Macklem  * This function prints out an option name, based on the conditional
215799d2727dSRick Macklem  * argument.
215899d2727dSRick Macklem  */
215999d2727dSRick Macklem static __inline void nfscl_printopt(struct nfsmount *nmp, int testval,
216099d2727dSRick Macklem     char *opt, char **buf, size_t *blen)
216199d2727dSRick Macklem {
216299d2727dSRick Macklem 	int len;
216399d2727dSRick Macklem 
216499d2727dSRick Macklem 	if (testval != 0 && *blen > strlen(opt)) {
216599d2727dSRick Macklem 		len = snprintf(*buf, *blen, "%s", opt);
216699d2727dSRick Macklem 		if (len != strlen(opt))
216799d2727dSRick Macklem 			printf("EEK!!\n");
216899d2727dSRick Macklem 		*buf += len;
216999d2727dSRick Macklem 		*blen -= len;
217099d2727dSRick Macklem 	}
217199d2727dSRick Macklem }
217299d2727dSRick Macklem 
217399d2727dSRick Macklem /*
217499d2727dSRick Macklem  * This function printf out an options integer value.
217599d2727dSRick Macklem  */
217699d2727dSRick Macklem static __inline void nfscl_printoptval(struct nfsmount *nmp, int optval,
217799d2727dSRick Macklem     char *opt, char **buf, size_t *blen)
217899d2727dSRick Macklem {
217999d2727dSRick Macklem 	int len;
218099d2727dSRick Macklem 
218199d2727dSRick Macklem 	if (*blen > strlen(opt) + 1) {
218299d2727dSRick Macklem 		/* Could result in truncated output string. */
218399d2727dSRick Macklem 		len = snprintf(*buf, *blen, "%s=%d", opt, optval);
218499d2727dSRick Macklem 		if (len < *blen) {
218599d2727dSRick Macklem 			*buf += len;
218699d2727dSRick Macklem 			*blen -= len;
218799d2727dSRick Macklem 		}
218899d2727dSRick Macklem 	}
218999d2727dSRick Macklem }
219099d2727dSRick Macklem 
219199d2727dSRick Macklem /*
219299d2727dSRick Macklem  * Load the option flags and values into the buffer.
219399d2727dSRick Macklem  */
219499d2727dSRick Macklem void nfscl_retopts(struct nfsmount *nmp, char *buffer, size_t buflen)
219599d2727dSRick Macklem {
219699d2727dSRick Macklem 	char *buf;
219799d2727dSRick Macklem 	size_t blen;
219899d2727dSRick Macklem 
219999d2727dSRick Macklem 	buf = buffer;
220099d2727dSRick Macklem 	blen = buflen;
220199d2727dSRick Macklem 	nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NFSV4) != 0, "nfsv4", &buf,
220299d2727dSRick Macklem 	    &blen);
2203ef8f1261SRick Macklem 	if ((nmp->nm_flag & NFSMNT_NFSV4) != 0) {
2204ef8f1261SRick Macklem 		nfscl_printoptval(nmp, nmp->nm_minorvers, ",minorversion", &buf,
2205ef8f1261SRick Macklem 		    &blen);
2206ef8f1261SRick Macklem 		nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_PNFS) != 0, ",pnfs",
2207ef8f1261SRick Macklem 		    &buf, &blen);
2208037a2012SRick Macklem 		nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_ONEOPENOWN) != 0 &&
2209037a2012SRick Macklem 		    nmp->nm_minorvers > 0, ",oneopenown", &buf, &blen);
2210ef8f1261SRick Macklem 	}
221199d2727dSRick Macklem 	nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NFSV3) != 0, "nfsv3", &buf,
221299d2727dSRick Macklem 	    &blen);
221399d2727dSRick Macklem 	nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0,
221499d2727dSRick Macklem 	    "nfsv2", &buf, &blen);
221599d2727dSRick Macklem 	nfscl_printopt(nmp, nmp->nm_sotype == SOCK_STREAM, ",tcp", &buf, &blen);
221699d2727dSRick Macklem 	nfscl_printopt(nmp, nmp->nm_sotype != SOCK_STREAM, ",udp", &buf, &blen);
221799d2727dSRick Macklem 	nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_RESVPORT) != 0, ",resvport",
221899d2727dSRick Macklem 	    &buf, &blen);
22196e4b6ff8SRick Macklem 	nfscl_printopt(nmp, (nmp->nm_newflag & NFSMNT_TLS) != 0, ",tls", &buf,
22206e4b6ff8SRick Macklem 	    &blen);
2221896516e5SRick Macklem 	nfscl_printopt(nmp, (nmp->nm_newflag & NFSMNT_SYSKRB5) != 0,
2222896516e5SRick Macklem 	    ",syskrb5", &buf, &blen);
222399d2727dSRick Macklem 	nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCONN) != 0, ",noconn",
222499d2727dSRick Macklem 	    &buf, &blen);
22251e0a518dSRick Macklem 	nfscl_printoptval(nmp, nmp->nm_aconnect + 1, ",nconnect", &buf, &blen);
222699d2727dSRick Macklem 	nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_SOFT) == 0, ",hard", &buf,
222799d2727dSRick Macklem 	    &blen);
222899d2727dSRick Macklem 	nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_SOFT) != 0, ",soft", &buf,
222999d2727dSRick Macklem 	    &blen);
223099d2727dSRick Macklem 	nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_INT) != 0, ",intr", &buf,
223199d2727dSRick Macklem 	    &blen);
223299d2727dSRick Macklem 	nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCTO) == 0, ",cto", &buf,
223399d2727dSRick Macklem 	    &blen);
223499d2727dSRick Macklem 	nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCTO) != 0, ",nocto", &buf,
223599d2727dSRick Macklem 	    &blen);
2236cf766161SRick Macklem 	nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NONCONTIGWR) != 0,
2237cf766161SRick Macklem 	    ",noncontigwr", &buf, &blen);
223899d2727dSRick Macklem 	nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_NOLOCKD | NFSMNT_NFSV4)) ==
223999d2727dSRick Macklem 	    0, ",lockd", &buf, &blen);
224033721eb9SRick Macklem 	nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOLOCKD) != 0, ",nolockd",
224133721eb9SRick Macklem 	    &buf, &blen);
224299d2727dSRick Macklem 	nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_RDIRPLUS) != 0, ",rdirplus",
224399d2727dSRick Macklem 	    &buf, &blen);
224499d2727dSRick Macklem 	nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_KERB) == 0, ",sec=sys",
224599d2727dSRick Macklem 	    &buf, &blen);
224699d2727dSRick Macklem 	nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY |
224799d2727dSRick Macklem 	    NFSMNT_PRIVACY)) == NFSMNT_KERB, ",sec=krb5", &buf, &blen);
224899d2727dSRick Macklem 	nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY |
224999d2727dSRick Macklem 	    NFSMNT_PRIVACY)) == (NFSMNT_KERB | NFSMNT_INTEGRITY), ",sec=krb5i",
225099d2727dSRick Macklem 	    &buf, &blen);
225199d2727dSRick Macklem 	nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY |
225299d2727dSRick Macklem 	    NFSMNT_PRIVACY)) == (NFSMNT_KERB | NFSMNT_PRIVACY), ",sec=krb5p",
225399d2727dSRick Macklem 	    &buf, &blen);
225499d2727dSRick Macklem 	nfscl_printoptval(nmp, nmp->nm_acdirmin, ",acdirmin", &buf, &blen);
225599d2727dSRick Macklem 	nfscl_printoptval(nmp, nmp->nm_acdirmax, ",acdirmax", &buf, &blen);
225699d2727dSRick Macklem 	nfscl_printoptval(nmp, nmp->nm_acregmin, ",acregmin", &buf, &blen);
225799d2727dSRick Macklem 	nfscl_printoptval(nmp, nmp->nm_acregmax, ",acregmax", &buf, &blen);
225899d2727dSRick Macklem 	nfscl_printoptval(nmp, nmp->nm_nametimeo, ",nametimeo", &buf, &blen);
225999d2727dSRick Macklem 	nfscl_printoptval(nmp, nmp->nm_negnametimeo, ",negnametimeo", &buf,
226099d2727dSRick Macklem 	    &blen);
226199d2727dSRick Macklem 	nfscl_printoptval(nmp, nmp->nm_rsize, ",rsize", &buf, &blen);
226299d2727dSRick Macklem 	nfscl_printoptval(nmp, nmp->nm_wsize, ",wsize", &buf, &blen);
226399d2727dSRick Macklem 	nfscl_printoptval(nmp, nmp->nm_readdirsize, ",readdirsize", &buf,
226499d2727dSRick Macklem 	    &blen);
226599d2727dSRick Macklem 	nfscl_printoptval(nmp, nmp->nm_readahead, ",readahead", &buf, &blen);
226699d2727dSRick Macklem 	nfscl_printoptval(nmp, nmp->nm_wcommitsize, ",wcommitsize", &buf,
226799d2727dSRick Macklem 	    &blen);
226899d2727dSRick Macklem 	nfscl_printoptval(nmp, nmp->nm_timeo, ",timeout", &buf, &blen);
226999d2727dSRick Macklem 	nfscl_printoptval(nmp, nmp->nm_retry, ",retrans", &buf, &blen);
227099d2727dSRick Macklem }
2271