nfs_clvfsops.c revision 251147
1/*-
2 * Copyright (c) 1989, 1993, 1995
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 *	from nfs_vfsops.c	8.12 (Berkeley) 5/20/95
33 */
34
35#include <sys/cdefs.h>
36__FBSDID("$FreeBSD: stable/9/sys/fs/nfsclient/nfs_clvfsops.c 251147 2013-05-30 19:14:34Z jhb $");
37
38
39#include "opt_bootp.h"
40#include "opt_nfsroot.h"
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/kernel.h>
45#include <sys/bio.h>
46#include <sys/buf.h>
47#include <sys/clock.h>
48#include <sys/jail.h>
49#include <sys/limits.h>
50#include <sys/lock.h>
51#include <sys/malloc.h>
52#include <sys/mbuf.h>
53#include <sys/module.h>
54#include <sys/mount.h>
55#include <sys/proc.h>
56#include <sys/socket.h>
57#include <sys/socketvar.h>
58#include <sys/sockio.h>
59#include <sys/sysctl.h>
60#include <sys/vnode.h>
61#include <sys/signalvar.h>
62
63#include <vm/vm.h>
64#include <vm/vm_extern.h>
65#include <vm/uma.h>
66
67#include <net/if.h>
68#include <net/route.h>
69#include <netinet/in.h>
70
71#include <fs/nfs/nfsport.h>
72#include <fs/nfsclient/nfsnode.h>
73#include <fs/nfsclient/nfsmount.h>
74#include <fs/nfsclient/nfs.h>
75#include <nfs/nfsdiskless.h>
76
77FEATURE(nfscl, "NFSv4 client");
78
79extern int nfscl_ticks;
80extern struct timeval nfsboottime;
81extern struct nfsstats	newnfsstats;
82extern int nfsrv_useacl;
83extern enum nfsiod_state ncl_iodwant[NFS_MAXASYNCDAEMON];
84extern struct nfsmount *ncl_iodmount[NFS_MAXASYNCDAEMON];
85extern struct mtx ncl_iod_mutex;
86
87MALLOC_DEFINE(M_NEWNFSREQ, "newnfsclient_req", "New NFS request header");
88MALLOC_DEFINE(M_NEWNFSMNT, "newnfsmnt", "New NFS mount struct");
89
90SYSCTL_DECL(_vfs_nfs);
91static int nfs_ip_paranoia = 1;
92SYSCTL_INT(_vfs_nfs, OID_AUTO, nfs_ip_paranoia, CTLFLAG_RW,
93    &nfs_ip_paranoia, 0, "");
94static int nfs_tprintf_initial_delay = NFS_TPRINTF_INITIAL_DELAY;
95SYSCTL_INT(_vfs_nfs, NFS_TPRINTF_INITIAL_DELAY,
96        downdelayinitial, CTLFLAG_RW, &nfs_tprintf_initial_delay, 0, "");
97/* how long between console messages "nfs server foo not responding" */
98static int nfs_tprintf_delay = NFS_TPRINTF_DELAY;
99SYSCTL_INT(_vfs_nfs, NFS_TPRINTF_DELAY,
100        downdelayinterval, CTLFLAG_RW, &nfs_tprintf_delay, 0, "");
101
102static int	nfs_mountroot(struct mount *);
103static void	nfs_sec_name(char *, int *);
104static void	nfs_decode_args(struct mount *mp, struct nfsmount *nmp,
105		    struct nfs_args *argp, const char *, struct ucred *,
106		    struct thread *);
107static int	mountnfs(struct nfs_args *, struct mount *,
108		    struct sockaddr *, char *, u_char *, int, u_char *, int,
109		    u_char *, int, struct vnode **, struct ucred *,
110		    struct thread *, int, int);
111static void	nfs_getnlminfo(struct vnode *, uint8_t *, size_t *,
112		    struct sockaddr_storage *, int *, off_t *,
113		    struct timeval *);
114static vfs_mount_t nfs_mount;
115static vfs_cmount_t nfs_cmount;
116static vfs_unmount_t nfs_unmount;
117static vfs_root_t nfs_root;
118static vfs_statfs_t nfs_statfs;
119static vfs_sync_t nfs_sync;
120static vfs_sysctl_t nfs_sysctl;
121
122/*
123 * nfs vfs operations.
124 */
125static struct vfsops nfs_vfsops = {
126	.vfs_init =		ncl_init,
127	.vfs_mount =		nfs_mount,
128	.vfs_cmount =		nfs_cmount,
129	.vfs_root =		nfs_root,
130	.vfs_statfs =		nfs_statfs,
131	.vfs_sync =		nfs_sync,
132	.vfs_uninit =		ncl_uninit,
133	.vfs_unmount =		nfs_unmount,
134	.vfs_sysctl =		nfs_sysctl,
135};
136VFS_SET(nfs_vfsops, nfs, VFCF_NETWORK | VFCF_SBDRY);
137
138/* So that loader and kldload(2) can find us, wherever we are.. */
139MODULE_VERSION(nfs, 1);
140MODULE_DEPEND(nfs, nfscommon, 1, 1, 1);
141MODULE_DEPEND(nfs, krpc, 1, 1, 1);
142MODULE_DEPEND(nfs, nfssvc, 1, 1, 1);
143MODULE_DEPEND(nfs, nfslock, 1, 1, 1);
144
145/*
146 * This structure is now defined in sys/nfs/nfs_diskless.c so that it
147 * can be shared by both NFS clients. It is declared here so that it
148 * will be defined for kernels built without NFS_ROOT, although it
149 * isn't used in that case.
150 */
151#if !defined(NFS_ROOT) && !defined(NFSCLIENT)
152struct nfs_diskless	nfs_diskless = { { { 0 } } };
153struct nfsv3_diskless	nfsv3_diskless = { { { 0 } } };
154int			nfs_diskless_valid = 0;
155#endif
156
157SYSCTL_INT(_vfs_nfs, OID_AUTO, diskless_valid, CTLFLAG_RD,
158    &nfs_diskless_valid, 0,
159    "Has the diskless struct been filled correctly");
160
161SYSCTL_STRING(_vfs_nfs, OID_AUTO, diskless_rootpath, CTLFLAG_RD,
162    nfsv3_diskless.root_hostnam, 0, "Path to nfs root");
163
164SYSCTL_OPAQUE(_vfs_nfs, OID_AUTO, diskless_rootaddr, CTLFLAG_RD,
165    &nfsv3_diskless.root_saddr, sizeof(nfsv3_diskless.root_saddr),
166    "%Ssockaddr_in", "Diskless root nfs address");
167
168
169void		newnfsargs_ntoh(struct nfs_args *);
170static int	nfs_mountdiskless(char *,
171		    struct sockaddr_in *, struct nfs_args *,
172		    struct thread *, struct vnode **, struct mount *);
173static void	nfs_convert_diskless(void);
174static void	nfs_convert_oargs(struct nfs_args *args,
175		    struct onfs_args *oargs);
176
177int
178newnfs_iosize(struct nfsmount *nmp)
179{
180	int iosize, maxio;
181
182	/* First, set the upper limit for iosize */
183	if (nmp->nm_flag & NFSMNT_NFSV4) {
184		maxio = NFS_MAXBSIZE;
185	} else if (nmp->nm_flag & NFSMNT_NFSV3) {
186		if (nmp->nm_sotype == SOCK_DGRAM)
187			maxio = NFS_MAXDGRAMDATA;
188		else
189			maxio = NFS_MAXBSIZE;
190	} else {
191		maxio = NFS_V2MAXDATA;
192	}
193	if (nmp->nm_rsize > maxio || nmp->nm_rsize == 0)
194		nmp->nm_rsize = maxio;
195	if (nmp->nm_rsize > MAXBSIZE)
196		nmp->nm_rsize = MAXBSIZE;
197	if (nmp->nm_readdirsize > maxio || nmp->nm_readdirsize == 0)
198		nmp->nm_readdirsize = maxio;
199	if (nmp->nm_readdirsize > nmp->nm_rsize)
200		nmp->nm_readdirsize = nmp->nm_rsize;
201	if (nmp->nm_wsize > maxio || nmp->nm_wsize == 0)
202		nmp->nm_wsize = maxio;
203	if (nmp->nm_wsize > MAXBSIZE)
204		nmp->nm_wsize = MAXBSIZE;
205
206	/*
207	 * Calculate the size used for io buffers.  Use the larger
208	 * of the two sizes to minimise nfs requests but make sure
209	 * that it is at least one VM page to avoid wasting buffer
210	 * space.
211	 */
212	iosize = imax(nmp->nm_rsize, nmp->nm_wsize);
213	iosize = imax(iosize, PAGE_SIZE);
214	nmp->nm_mountp->mnt_stat.f_iosize = iosize;
215	return (iosize);
216}
217
218static void
219nfs_convert_oargs(struct nfs_args *args, struct onfs_args *oargs)
220{
221
222	args->version = NFS_ARGSVERSION;
223	args->addr = oargs->addr;
224	args->addrlen = oargs->addrlen;
225	args->sotype = oargs->sotype;
226	args->proto = oargs->proto;
227	args->fh = oargs->fh;
228	args->fhsize = oargs->fhsize;
229	args->flags = oargs->flags;
230	args->wsize = oargs->wsize;
231	args->rsize = oargs->rsize;
232	args->readdirsize = oargs->readdirsize;
233	args->timeo = oargs->timeo;
234	args->retrans = oargs->retrans;
235	args->readahead = oargs->readahead;
236	args->hostname = oargs->hostname;
237}
238
239static void
240nfs_convert_diskless(void)
241{
242
243	bcopy(&nfs_diskless.myif, &nfsv3_diskless.myif,
244		sizeof(struct ifaliasreq));
245	bcopy(&nfs_diskless.mygateway, &nfsv3_diskless.mygateway,
246		sizeof(struct sockaddr_in));
247	nfs_convert_oargs(&nfsv3_diskless.root_args,&nfs_diskless.root_args);
248	if (nfsv3_diskless.root_args.flags & NFSMNT_NFSV3) {
249		nfsv3_diskless.root_fhsize = NFSX_MYFH;
250		bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_MYFH);
251	} else {
252		nfsv3_diskless.root_fhsize = NFSX_V2FH;
253		bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_V2FH);
254	}
255	bcopy(&nfs_diskless.root_saddr,&nfsv3_diskless.root_saddr,
256		sizeof(struct sockaddr_in));
257	bcopy(nfs_diskless.root_hostnam, nfsv3_diskless.root_hostnam, MNAMELEN);
258	nfsv3_diskless.root_time = nfs_diskless.root_time;
259	bcopy(nfs_diskless.my_hostnam, nfsv3_diskless.my_hostnam,
260		MAXHOSTNAMELEN);
261	nfs_diskless_valid = 3;
262}
263
264/*
265 * nfs statfs call
266 */
267static int
268nfs_statfs(struct mount *mp, struct statfs *sbp)
269{
270	struct vnode *vp;
271	struct thread *td;
272	struct nfsmount *nmp = VFSTONFS(mp);
273	struct nfsvattr nfsva;
274	struct nfsfsinfo fs;
275	struct nfsstatfs sb;
276	int error = 0, attrflag, gotfsinfo = 0, ret;
277	struct nfsnode *np;
278
279	td = curthread;
280
281	error = vfs_busy(mp, MBF_NOWAIT);
282	if (error)
283		return (error);
284	error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, LK_EXCLUSIVE);
285	if (error) {
286		vfs_unbusy(mp);
287		return (error);
288	}
289	vp = NFSTOV(np);
290	mtx_lock(&nmp->nm_mtx);
291	if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) {
292		mtx_unlock(&nmp->nm_mtx);
293		error = nfsrpc_fsinfo(vp, &fs, td->td_ucred, td, &nfsva,
294		    &attrflag, NULL);
295		if (!error)
296			gotfsinfo = 1;
297	} else
298		mtx_unlock(&nmp->nm_mtx);
299	if (!error)
300		error = nfsrpc_statfs(vp, &sb, &fs, td->td_ucred, td, &nfsva,
301		    &attrflag, NULL);
302	if (attrflag == 0) {
303		ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1,
304		    td->td_ucred, td, &nfsva, NULL);
305		if (ret) {
306			/*
307			 * Just set default values to get things going.
308			 */
309			NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr));
310			nfsva.na_vattr.va_type = VDIR;
311			nfsva.na_vattr.va_mode = 0777;
312			nfsva.na_vattr.va_nlink = 100;
313			nfsva.na_vattr.va_uid = (uid_t)0;
314			nfsva.na_vattr.va_gid = (gid_t)0;
315			nfsva.na_vattr.va_fileid = 2;
316			nfsva.na_vattr.va_gen = 1;
317			nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE;
318			nfsva.na_vattr.va_size = 512 * 1024;
319		}
320	}
321	(void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1);
322	if (!error) {
323	    mtx_lock(&nmp->nm_mtx);
324	    if (gotfsinfo || (nmp->nm_flag & NFSMNT_NFSV4))
325		nfscl_loadfsinfo(nmp, &fs);
326	    nfscl_loadsbinfo(nmp, &sb, sbp);
327	    sbp->f_iosize = newnfs_iosize(nmp);
328	    mtx_unlock(&nmp->nm_mtx);
329	    if (sbp != &mp->mnt_stat) {
330		bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
331		bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
332	    }
333	    strncpy(&sbp->f_fstypename[0], mp->mnt_vfc->vfc_name, MFSNAMELEN);
334	} else if (NFS_ISV4(vp)) {
335		error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0);
336	}
337	vput(vp);
338	vfs_unbusy(mp);
339	return (error);
340}
341
342/*
343 * nfs version 3 fsinfo rpc call
344 */
345int
346ncl_fsinfo(struct nfsmount *nmp, struct vnode *vp, struct ucred *cred,
347    struct thread *td)
348{
349	struct nfsfsinfo fs;
350	struct nfsvattr nfsva;
351	int error, attrflag;
352
353	error = nfsrpc_fsinfo(vp, &fs, cred, td, &nfsva, &attrflag, NULL);
354	if (!error) {
355		if (attrflag)
356			(void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0,
357			    1);
358		mtx_lock(&nmp->nm_mtx);
359		nfscl_loadfsinfo(nmp, &fs);
360		mtx_unlock(&nmp->nm_mtx);
361	}
362	return (error);
363}
364
365/*
366 * Mount a remote root fs via. nfs. This depends on the info in the
367 * nfs_diskless structure that has been filled in properly by some primary
368 * bootstrap.
369 * It goes something like this:
370 * - do enough of "ifconfig" by calling ifioctl() so that the system
371 *   can talk to the server
372 * - If nfs_diskless.mygateway is filled in, use that address as
373 *   a default gateway.
374 * - build the rootfs mount point and call mountnfs() to do the rest.
375 *
376 * It is assumed to be safe to read, modify, and write the nfsv3_diskless
377 * structure, as well as other global NFS client variables here, as
378 * nfs_mountroot() will be called once in the boot before any other NFS
379 * client activity occurs.
380 */
381static int
382nfs_mountroot(struct mount *mp)
383{
384	struct thread *td = curthread;
385	struct nfsv3_diskless *nd = &nfsv3_diskless;
386	struct socket *so;
387	struct vnode *vp;
388	struct ifreq ir;
389	int error;
390	u_long l;
391	char buf[128];
392	char *cp;
393
394#if defined(BOOTP_NFSROOT) && defined(BOOTP)
395	bootpc_init();		/* use bootp to get nfs_diskless filled in */
396#elif defined(NFS_ROOT)
397	nfs_setup_diskless();
398#endif
399
400	if (nfs_diskless_valid == 0)
401		return (-1);
402	if (nfs_diskless_valid == 1)
403		nfs_convert_diskless();
404
405	/*
406	 * XXX splnet, so networks will receive...
407	 */
408	splnet();
409
410	/*
411	 * Do enough of ifconfig(8) so that the critical net interface can
412	 * talk to the server.
413	 */
414	error = socreate(nd->myif.ifra_addr.sa_family, &so, nd->root_args.sotype, 0,
415	    td->td_ucred, td);
416	if (error)
417		panic("nfs_mountroot: socreate(%04x): %d",
418			nd->myif.ifra_addr.sa_family, error);
419
420#if 0 /* XXX Bad idea */
421	/*
422	 * We might not have been told the right interface, so we pass
423	 * over the first ten interfaces of the same kind, until we get
424	 * one of them configured.
425	 */
426
427	for (i = strlen(nd->myif.ifra_name) - 1;
428		nd->myif.ifra_name[i] >= '0' &&
429		nd->myif.ifra_name[i] <= '9';
430		nd->myif.ifra_name[i] ++) {
431		error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td);
432		if(!error)
433			break;
434	}
435#endif
436	error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td);
437	if (error)
438		panic("nfs_mountroot: SIOCAIFADDR: %d", error);
439	if ((cp = getenv("boot.netif.mtu")) != NULL) {
440		ir.ifr_mtu = strtol(cp, NULL, 10);
441		bcopy(nd->myif.ifra_name, ir.ifr_name, IFNAMSIZ);
442		freeenv(cp);
443		error = ifioctl(so, SIOCSIFMTU, (caddr_t)&ir, td);
444		if (error)
445			printf("nfs_mountroot: SIOCSIFMTU: %d", error);
446	}
447	soclose(so);
448
449	/*
450	 * If the gateway field is filled in, set it as the default route.
451	 * Note that pxeboot will set a default route of 0 if the route
452	 * is not set by the DHCP server.  Check also for a value of 0
453	 * to avoid panicking inappropriately in that situation.
454	 */
455	if (nd->mygateway.sin_len != 0 &&
456	    nd->mygateway.sin_addr.s_addr != 0) {
457		struct sockaddr_in mask, sin;
458
459		bzero((caddr_t)&mask, sizeof(mask));
460		sin = mask;
461		sin.sin_family = AF_INET;
462		sin.sin_len = sizeof(sin);
463                /* XXX MRT use table 0 for this sort of thing */
464		CURVNET_SET(TD_TO_VNET(td));
465		error = rtrequest_fib(RTM_ADD, (struct sockaddr *)&sin,
466		    (struct sockaddr *)&nd->mygateway,
467		    (struct sockaddr *)&mask,
468		    RTF_UP | RTF_GATEWAY, NULL, RT_DEFAULT_FIB);
469		CURVNET_RESTORE();
470		if (error)
471			panic("nfs_mountroot: RTM_ADD: %d", error);
472	}
473
474	/*
475	 * Create the rootfs mount point.
476	 */
477	nd->root_args.fh = nd->root_fh;
478	nd->root_args.fhsize = nd->root_fhsize;
479	l = ntohl(nd->root_saddr.sin_addr.s_addr);
480	snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s",
481		(l >> 24) & 0xff, (l >> 16) & 0xff,
482		(l >>  8) & 0xff, (l >>  0) & 0xff, nd->root_hostnam);
483	printf("NFS ROOT: %s\n", buf);
484	nd->root_args.hostname = buf;
485	if ((error = nfs_mountdiskless(buf,
486	    &nd->root_saddr, &nd->root_args, td, &vp, mp)) != 0) {
487		return (error);
488	}
489
490	/*
491	 * This is not really an nfs issue, but it is much easier to
492	 * set hostname here and then let the "/etc/rc.xxx" files
493	 * mount the right /var based upon its preset value.
494	 */
495	mtx_lock(&prison0.pr_mtx);
496	strlcpy(prison0.pr_hostname, nd->my_hostnam,
497	    sizeof(prison0.pr_hostname));
498	mtx_unlock(&prison0.pr_mtx);
499	inittodr(ntohl(nd->root_time));
500	return (0);
501}
502
503/*
504 * Internal version of mount system call for diskless setup.
505 */
506static int
507nfs_mountdiskless(char *path,
508    struct sockaddr_in *sin, struct nfs_args *args, struct thread *td,
509    struct vnode **vpp, struct mount *mp)
510{
511	struct sockaddr *nam;
512	int dirlen, error;
513	char *dirpath;
514
515	/*
516	 * Find the directory path in "path", which also has the server's
517	 * name/ip address in it.
518	 */
519	dirpath = strchr(path, ':');
520	if (dirpath != NULL)
521		dirlen = strlen(++dirpath);
522	else
523		dirlen = 0;
524	nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK);
525	if ((error = mountnfs(args, mp, nam, path, NULL, 0, dirpath, dirlen,
526	    NULL, 0, vpp, td->td_ucred, td, NFS_DEFAULT_NAMETIMEO,
527	    NFS_DEFAULT_NEGNAMETIMEO)) != 0) {
528		printf("nfs_mountroot: mount %s on /: %d\n", path, error);
529		return (error);
530	}
531	return (0);
532}
533
534static void
535nfs_sec_name(char *sec, int *flagsp)
536{
537	if (!strcmp(sec, "krb5"))
538		*flagsp |= NFSMNT_KERB;
539	else if (!strcmp(sec, "krb5i"))
540		*flagsp |= (NFSMNT_KERB | NFSMNT_INTEGRITY);
541	else if (!strcmp(sec, "krb5p"))
542		*flagsp |= (NFSMNT_KERB | NFSMNT_PRIVACY);
543}
544
545static void
546nfs_decode_args(struct mount *mp, struct nfsmount *nmp, struct nfs_args *argp,
547    const char *hostname, struct ucred *cred, struct thread *td)
548{
549	int s;
550	int adjsock;
551	char *p;
552
553	s = splnet();
554
555	/*
556	 * Set read-only flag if requested; otherwise, clear it if this is
557	 * an update.  If this is not an update, then either the read-only
558	 * flag is already clear, or this is a root mount and it was set
559	 * intentionally at some previous point.
560	 */
561	if (vfs_getopt(mp->mnt_optnew, "ro", NULL, NULL) == 0) {
562		MNT_ILOCK(mp);
563		mp->mnt_flag |= MNT_RDONLY;
564		MNT_IUNLOCK(mp);
565	} else if (mp->mnt_flag & MNT_UPDATE) {
566		MNT_ILOCK(mp);
567		mp->mnt_flag &= ~MNT_RDONLY;
568		MNT_IUNLOCK(mp);
569	}
570
571	/*
572	 * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes
573	 * no sense in that context.  Also, set up appropriate retransmit
574	 * and soft timeout behavior.
575	 */
576	if (argp->sotype == SOCK_STREAM) {
577		nmp->nm_flag &= ~NFSMNT_NOCONN;
578		nmp->nm_timeo = NFS_MAXTIMEO;
579		if ((argp->flags & NFSMNT_NFSV4) != 0)
580			nmp->nm_retry = INT_MAX;
581		else
582			nmp->nm_retry = NFS_RETRANS_TCP;
583	}
584
585	/* Also clear RDIRPLUS if NFSv2, it crashes some servers */
586	if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) {
587		argp->flags &= ~NFSMNT_RDIRPLUS;
588		nmp->nm_flag &= ~NFSMNT_RDIRPLUS;
589	}
590
591	/* Clear NFSMNT_RESVPORT for NFSv4, since it is not required. */
592	if ((argp->flags & NFSMNT_NFSV4) != 0) {
593		argp->flags &= ~NFSMNT_RESVPORT;
594		nmp->nm_flag &= ~NFSMNT_RESVPORT;
595	}
596
597	/* Re-bind if rsrvd port requested and wasn't on one */
598	adjsock = !(nmp->nm_flag & NFSMNT_RESVPORT)
599		  && (argp->flags & NFSMNT_RESVPORT);
600	/* Also re-bind if we're switching to/from a connected UDP socket */
601	adjsock |= ((nmp->nm_flag & NFSMNT_NOCONN) !=
602		    (argp->flags & NFSMNT_NOCONN));
603
604	/* Update flags atomically.  Don't change the lock bits. */
605	nmp->nm_flag = argp->flags | nmp->nm_flag;
606	splx(s);
607
608	if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
609		nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
610		if (nmp->nm_timeo < NFS_MINTIMEO)
611			nmp->nm_timeo = NFS_MINTIMEO;
612		else if (nmp->nm_timeo > NFS_MAXTIMEO)
613			nmp->nm_timeo = NFS_MAXTIMEO;
614	}
615
616	if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
617		nmp->nm_retry = argp->retrans;
618		if (nmp->nm_retry > NFS_MAXREXMIT)
619			nmp->nm_retry = NFS_MAXREXMIT;
620	}
621
622	if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
623		nmp->nm_wsize = argp->wsize;
624		/* Round down to multiple of blocksize */
625		nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1);
626		if (nmp->nm_wsize <= 0)
627			nmp->nm_wsize = NFS_FABLKSIZE;
628	}
629
630	if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
631		nmp->nm_rsize = argp->rsize;
632		/* Round down to multiple of blocksize */
633		nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1);
634		if (nmp->nm_rsize <= 0)
635			nmp->nm_rsize = NFS_FABLKSIZE;
636	}
637
638	if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) {
639		nmp->nm_readdirsize = argp->readdirsize;
640	}
641
642	if ((argp->flags & NFSMNT_ACREGMIN) && argp->acregmin >= 0)
643		nmp->nm_acregmin = argp->acregmin;
644	else
645		nmp->nm_acregmin = NFS_MINATTRTIMO;
646	if ((argp->flags & NFSMNT_ACREGMAX) && argp->acregmax >= 0)
647		nmp->nm_acregmax = argp->acregmax;
648	else
649		nmp->nm_acregmax = NFS_MAXATTRTIMO;
650	if ((argp->flags & NFSMNT_ACDIRMIN) && argp->acdirmin >= 0)
651		nmp->nm_acdirmin = argp->acdirmin;
652	else
653		nmp->nm_acdirmin = NFS_MINDIRATTRTIMO;
654	if ((argp->flags & NFSMNT_ACDIRMAX) && argp->acdirmax >= 0)
655		nmp->nm_acdirmax = argp->acdirmax;
656	else
657		nmp->nm_acdirmax = NFS_MAXDIRATTRTIMO;
658	if (nmp->nm_acdirmin > nmp->nm_acdirmax)
659		nmp->nm_acdirmin = nmp->nm_acdirmax;
660	if (nmp->nm_acregmin > nmp->nm_acregmax)
661		nmp->nm_acregmin = nmp->nm_acregmax;
662
663	if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0) {
664		if (argp->readahead <= NFS_MAXRAHEAD)
665			nmp->nm_readahead = argp->readahead;
666		else
667			nmp->nm_readahead = NFS_MAXRAHEAD;
668	}
669	if ((argp->flags & NFSMNT_WCOMMITSIZE) && argp->wcommitsize >= 0) {
670		if (argp->wcommitsize < nmp->nm_wsize)
671			nmp->nm_wcommitsize = nmp->nm_wsize;
672		else
673			nmp->nm_wcommitsize = argp->wcommitsize;
674	}
675
676	adjsock |= ((nmp->nm_sotype != argp->sotype) ||
677		    (nmp->nm_soproto != argp->proto));
678
679	if (nmp->nm_client != NULL && adjsock) {
680		int haslock = 0, error = 0;
681
682		if (nmp->nm_sotype == SOCK_STREAM) {
683			error = newnfs_sndlock(&nmp->nm_sockreq.nr_lock);
684			if (!error)
685				haslock = 1;
686		}
687		if (!error) {
688		    newnfs_disconnect(&nmp->nm_sockreq);
689		    if (haslock)
690			newnfs_sndunlock(&nmp->nm_sockreq.nr_lock);
691		    nmp->nm_sotype = argp->sotype;
692		    nmp->nm_soproto = argp->proto;
693		    if (nmp->nm_sotype == SOCK_DGRAM)
694			while (newnfs_connect(nmp, &nmp->nm_sockreq,
695			    cred, td, 0)) {
696				printf("newnfs_args: retrying connect\n");
697				(void) nfs_catnap(PSOCK, 0, "newnfscon");
698			}
699		}
700	} else {
701		nmp->nm_sotype = argp->sotype;
702		nmp->nm_soproto = argp->proto;
703	}
704
705	if (hostname != NULL) {
706		strlcpy(nmp->nm_hostname, hostname,
707		    sizeof(nmp->nm_hostname));
708		p = strchr(nmp->nm_hostname, ':');
709		if (p != NULL)
710			*p = '\0';
711	}
712}
713
714static const char *nfs_opts[] = { "from", "nfs_args",
715    "noatime", "noexec", "suiddir", "nosuid", "nosymfollow", "union",
716    "noclusterr", "noclusterw", "multilabel", "acls", "force", "update",
717    "async", "noconn", "nolockd", "conn", "lockd", "intr", "rdirplus",
718    "readdirsize", "soft", "hard", "mntudp", "tcp", "udp", "wsize", "rsize",
719    "retrans", "acregmin", "acregmax", "acdirmin", "acdirmax", "resvport",
720    "readahead", "hostname", "timeout", "addr", "fh", "nfsv3", "sec",
721    "principal", "nfsv4", "gssname", "allgssname", "dirpath",
722    "nametimeo", "negnametimeo", "nocto", "wcommitsize",
723    NULL };
724
725/*
726 * VFS Operations.
727 *
728 * mount system call
729 * It seems a bit dumb to copyinstr() the host and path here and then
730 * bcopy() them in mountnfs(), but I wanted to detect errors before
731 * doing the sockargs() call because sockargs() allocates an mbuf and
732 * an error after that means that I have to release the mbuf.
733 */
734/* ARGSUSED */
735static int
736nfs_mount(struct mount *mp)
737{
738	struct nfs_args args = {
739	    .version = NFS_ARGSVERSION,
740	    .addr = NULL,
741	    .addrlen = sizeof (struct sockaddr_in),
742	    .sotype = SOCK_STREAM,
743	    .proto = 0,
744	    .fh = NULL,
745	    .fhsize = 0,
746	    .flags = NFSMNT_RESVPORT,
747	    .wsize = NFS_WSIZE,
748	    .rsize = NFS_RSIZE,
749	    .readdirsize = NFS_READDIRSIZE,
750	    .timeo = 10,
751	    .retrans = NFS_RETRANS,
752	    .readahead = NFS_DEFRAHEAD,
753	    .wcommitsize = 0,			/* was: NQ_DEFLEASE */
754	    .hostname = NULL,
755	    .acregmin = NFS_MINATTRTIMO,
756	    .acregmax = NFS_MAXATTRTIMO,
757	    .acdirmin = NFS_MINDIRATTRTIMO,
758	    .acdirmax = NFS_MAXDIRATTRTIMO,
759	};
760	int error = 0, ret, len;
761	struct sockaddr *nam = NULL;
762	struct vnode *vp;
763	struct thread *td;
764	char hst[MNAMELEN];
765	u_char nfh[NFSX_FHMAX], krbname[100], dirpath[100], srvkrbname[100];
766	char *opt, *name, *secname;
767	int nametimeo = NFS_DEFAULT_NAMETIMEO;
768	int negnametimeo = NFS_DEFAULT_NEGNAMETIMEO;
769	int dirlen, has_nfs_args_opt, krbnamelen, srvkrbnamelen;
770	size_t hstlen;
771
772	has_nfs_args_opt = 0;
773	if (vfs_filteropt(mp->mnt_optnew, nfs_opts)) {
774		error = EINVAL;
775		goto out;
776	}
777
778	td = curthread;
779	if ((mp->mnt_flag & (MNT_ROOTFS | MNT_UPDATE)) == MNT_ROOTFS) {
780		error = nfs_mountroot(mp);
781		goto out;
782	}
783
784	nfscl_init();
785
786	/*
787	 * The old mount_nfs program passed the struct nfs_args
788	 * from userspace to kernel.  The new mount_nfs program
789	 * passes string options via nmount() from userspace to kernel
790	 * and we populate the struct nfs_args in the kernel.
791	 */
792	if (vfs_getopt(mp->mnt_optnew, "nfs_args", NULL, NULL) == 0) {
793		error = vfs_copyopt(mp->mnt_optnew, "nfs_args", &args,
794		    sizeof(args));
795		if (error != 0)
796			goto out;
797
798		if (args.version != NFS_ARGSVERSION) {
799			error = EPROGMISMATCH;
800			goto out;
801		}
802		has_nfs_args_opt = 1;
803	}
804
805	/* Handle the new style options. */
806	if (vfs_getopt(mp->mnt_optnew, "noconn", NULL, NULL) == 0)
807		args.flags |= NFSMNT_NOCONN;
808	if (vfs_getopt(mp->mnt_optnew, "conn", NULL, NULL) == 0)
809		args.flags |= NFSMNT_NOCONN;
810	if (vfs_getopt(mp->mnt_optnew, "nolockd", NULL, NULL) == 0)
811		args.flags |= NFSMNT_NOLOCKD;
812	if (vfs_getopt(mp->mnt_optnew, "lockd", NULL, NULL) == 0)
813		args.flags &= ~NFSMNT_NOLOCKD;
814	if (vfs_getopt(mp->mnt_optnew, "intr", NULL, NULL) == 0)
815		args.flags |= NFSMNT_INT;
816	if (vfs_getopt(mp->mnt_optnew, "rdirplus", NULL, NULL) == 0)
817		args.flags |= NFSMNT_RDIRPLUS;
818	if (vfs_getopt(mp->mnt_optnew, "resvport", NULL, NULL) == 0)
819		args.flags |= NFSMNT_RESVPORT;
820	if (vfs_getopt(mp->mnt_optnew, "noresvport", NULL, NULL) == 0)
821		args.flags &= ~NFSMNT_RESVPORT;
822	if (vfs_getopt(mp->mnt_optnew, "soft", NULL, NULL) == 0)
823		args.flags |= NFSMNT_SOFT;
824	if (vfs_getopt(mp->mnt_optnew, "hard", NULL, NULL) == 0)
825		args.flags &= ~NFSMNT_SOFT;
826	if (vfs_getopt(mp->mnt_optnew, "mntudp", NULL, NULL) == 0)
827		args.sotype = SOCK_DGRAM;
828	if (vfs_getopt(mp->mnt_optnew, "udp", NULL, NULL) == 0)
829		args.sotype = SOCK_DGRAM;
830	if (vfs_getopt(mp->mnt_optnew, "tcp", NULL, NULL) == 0)
831		args.sotype = SOCK_STREAM;
832	if (vfs_getopt(mp->mnt_optnew, "nfsv3", NULL, NULL) == 0)
833		args.flags |= NFSMNT_NFSV3;
834	if (vfs_getopt(mp->mnt_optnew, "nfsv4", NULL, NULL) == 0) {
835		args.flags |= NFSMNT_NFSV4;
836		args.sotype = SOCK_STREAM;
837	}
838	if (vfs_getopt(mp->mnt_optnew, "allgssname", NULL, NULL) == 0)
839		args.flags |= NFSMNT_ALLGSSNAME;
840	if (vfs_getopt(mp->mnt_optnew, "nocto", NULL, NULL) == 0)
841		args.flags |= NFSMNT_NOCTO;
842	if (vfs_getopt(mp->mnt_optnew, "readdirsize", (void **)&opt, NULL) == 0) {
843		if (opt == NULL) {
844			vfs_mount_error(mp, "illegal readdirsize");
845			error = EINVAL;
846			goto out;
847		}
848		ret = sscanf(opt, "%d", &args.readdirsize);
849		if (ret != 1 || args.readdirsize <= 0) {
850			vfs_mount_error(mp, "illegal readdirsize: %s",
851			    opt);
852			error = EINVAL;
853			goto out;
854		}
855		args.flags |= NFSMNT_READDIRSIZE;
856	}
857	if (vfs_getopt(mp->mnt_optnew, "readahead", (void **)&opt, NULL) == 0) {
858		if (opt == NULL) {
859			vfs_mount_error(mp, "illegal readahead");
860			error = EINVAL;
861			goto out;
862		}
863		ret = sscanf(opt, "%d", &args.readahead);
864		if (ret != 1 || args.readahead <= 0) {
865			vfs_mount_error(mp, "illegal readahead: %s",
866			    opt);
867			error = EINVAL;
868			goto out;
869		}
870		args.flags |= NFSMNT_READAHEAD;
871	}
872	if (vfs_getopt(mp->mnt_optnew, "wsize", (void **)&opt, NULL) == 0) {
873		if (opt == NULL) {
874			vfs_mount_error(mp, "illegal wsize");
875			error = EINVAL;
876			goto out;
877		}
878		ret = sscanf(opt, "%d", &args.wsize);
879		if (ret != 1 || args.wsize <= 0) {
880			vfs_mount_error(mp, "illegal wsize: %s",
881			    opt);
882			error = EINVAL;
883			goto out;
884		}
885		args.flags |= NFSMNT_WSIZE;
886	}
887	if (vfs_getopt(mp->mnt_optnew, "rsize", (void **)&opt, NULL) == 0) {
888		if (opt == NULL) {
889			vfs_mount_error(mp, "illegal rsize");
890			error = EINVAL;
891			goto out;
892		}
893		ret = sscanf(opt, "%d", &args.rsize);
894		if (ret != 1 || args.rsize <= 0) {
895			vfs_mount_error(mp, "illegal wsize: %s",
896			    opt);
897			error = EINVAL;
898			goto out;
899		}
900		args.flags |= NFSMNT_RSIZE;
901	}
902	if (vfs_getopt(mp->mnt_optnew, "retrans", (void **)&opt, NULL) == 0) {
903		if (opt == NULL) {
904			vfs_mount_error(mp, "illegal retrans");
905			error = EINVAL;
906			goto out;
907		}
908		ret = sscanf(opt, "%d", &args.retrans);
909		if (ret != 1 || args.retrans <= 0) {
910			vfs_mount_error(mp, "illegal retrans: %s",
911			    opt);
912			error = EINVAL;
913			goto out;
914		}
915		args.flags |= NFSMNT_RETRANS;
916	}
917	if (vfs_getopt(mp->mnt_optnew, "acregmin", (void **)&opt, NULL) == 0) {
918		ret = sscanf(opt, "%d", &args.acregmin);
919		if (ret != 1 || args.acregmin < 0) {
920			vfs_mount_error(mp, "illegal acregmin: %s",
921			    opt);
922			error = EINVAL;
923			goto out;
924		}
925		args.flags |= NFSMNT_ACREGMIN;
926	}
927	if (vfs_getopt(mp->mnt_optnew, "acregmax", (void **)&opt, NULL) == 0) {
928		ret = sscanf(opt, "%d", &args.acregmax);
929		if (ret != 1 || args.acregmax < 0) {
930			vfs_mount_error(mp, "illegal acregmax: %s",
931			    opt);
932			error = EINVAL;
933			goto out;
934		}
935		args.flags |= NFSMNT_ACREGMAX;
936	}
937	if (vfs_getopt(mp->mnt_optnew, "acdirmin", (void **)&opt, NULL) == 0) {
938		ret = sscanf(opt, "%d", &args.acdirmin);
939		if (ret != 1 || args.acdirmin < 0) {
940			vfs_mount_error(mp, "illegal acdirmin: %s",
941			    opt);
942			error = EINVAL;
943			goto out;
944		}
945		args.flags |= NFSMNT_ACDIRMIN;
946	}
947	if (vfs_getopt(mp->mnt_optnew, "acdirmax", (void **)&opt, NULL) == 0) {
948		ret = sscanf(opt, "%d", &args.acdirmax);
949		if (ret != 1 || args.acdirmax < 0) {
950			vfs_mount_error(mp, "illegal acdirmax: %s",
951			    opt);
952			error = EINVAL;
953			goto out;
954		}
955		args.flags |= NFSMNT_ACDIRMAX;
956	}
957	if (vfs_getopt(mp->mnt_optnew, "wcommitsize", (void **)&opt, NULL) == 0) {
958		ret = sscanf(opt, "%d", &args.wcommitsize);
959		if (ret != 1 || args.wcommitsize < 0) {
960			vfs_mount_error(mp, "illegal wcommitsize: %s", opt);
961			error = EINVAL;
962			goto out;
963		}
964		args.flags |= NFSMNT_WCOMMITSIZE;
965	}
966	if (vfs_getopt(mp->mnt_optnew, "timeout", (void **)&opt, NULL) == 0) {
967		ret = sscanf(opt, "%d", &args.timeo);
968		if (ret != 1 || args.timeo <= 0) {
969			vfs_mount_error(mp, "illegal timeout: %s",
970			    opt);
971			error = EINVAL;
972			goto out;
973		}
974		args.flags |= NFSMNT_TIMEO;
975	}
976	if (vfs_getopt(mp->mnt_optnew, "nametimeo", (void **)&opt, NULL) == 0) {
977		ret = sscanf(opt, "%d", &nametimeo);
978		if (ret != 1 || nametimeo < 0) {
979			vfs_mount_error(mp, "illegal nametimeo: %s", opt);
980			error = EINVAL;
981			goto out;
982		}
983	}
984	if (vfs_getopt(mp->mnt_optnew, "negnametimeo", (void **)&opt, NULL)
985	    == 0) {
986		ret = sscanf(opt, "%d", &negnametimeo);
987		if (ret != 1 || negnametimeo < 0) {
988			vfs_mount_error(mp, "illegal negnametimeo: %s",
989			    opt);
990			error = EINVAL;
991			goto out;
992		}
993	}
994	if (vfs_getopt(mp->mnt_optnew, "sec",
995		(void **) &secname, NULL) == 0)
996		nfs_sec_name(secname, &args.flags);
997
998	if (mp->mnt_flag & MNT_UPDATE) {
999		struct nfsmount *nmp = VFSTONFS(mp);
1000
1001		if (nmp == NULL) {
1002			error = EIO;
1003			goto out;
1004		}
1005
1006		/*
1007		 * If a change from TCP->UDP is done and there are thread(s)
1008		 * that have I/O RPC(s) in progress with a tranfer size
1009		 * greater than NFS_MAXDGRAMDATA, those thread(s) will be
1010		 * hung, retrying the RPC(s) forever. Usually these threads
1011		 * will be seen doing an uninterruptible sleep on wait channel
1012		 * "newnfsreq" (truncated to "newnfsre" by procstat).
1013		 */
1014		if (args.sotype == SOCK_DGRAM && nmp->nm_sotype == SOCK_STREAM)
1015			tprintf(td->td_proc, LOG_WARNING,
1016	"Warning: mount -u that changes TCP->UDP can result in hung threads\n");
1017
1018		/*
1019		 * When doing an update, we can't change version,
1020		 * security, switch lockd strategies or change cookie
1021		 * translation
1022		 */
1023		args.flags = (args.flags &
1024		    ~(NFSMNT_NFSV3 |
1025		      NFSMNT_NFSV4 |
1026		      NFSMNT_KERB |
1027		      NFSMNT_INTEGRITY |
1028		      NFSMNT_PRIVACY |
1029		      NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)) |
1030		    (nmp->nm_flag &
1031			(NFSMNT_NFSV3 |
1032			 NFSMNT_NFSV4 |
1033			 NFSMNT_KERB |
1034			 NFSMNT_INTEGRITY |
1035			 NFSMNT_PRIVACY |
1036			 NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/));
1037		nfs_decode_args(mp, nmp, &args, NULL, td->td_ucred, td);
1038		goto out;
1039	}
1040
1041	/*
1042	 * Make the nfs_ip_paranoia sysctl serve as the default connection
1043	 * or no-connection mode for those protocols that support
1044	 * no-connection mode (the flag will be cleared later for protocols
1045	 * that do not support no-connection mode).  This will allow a client
1046	 * to receive replies from a different IP then the request was
1047	 * sent to.  Note: default value for nfs_ip_paranoia is 1 (paranoid),
1048	 * not 0.
1049	 */
1050	if (nfs_ip_paranoia == 0)
1051		args.flags |= NFSMNT_NOCONN;
1052
1053	if (has_nfs_args_opt != 0) {
1054		/*
1055		 * In the 'nfs_args' case, the pointers in the args
1056		 * structure are in userland - we copy them in here.
1057		 */
1058		if (args.fhsize < 0 || args.fhsize > NFSX_V3FHMAX) {
1059			vfs_mount_error(mp, "Bad file handle");
1060			error = EINVAL;
1061			goto out;
1062		}
1063		error = copyin((caddr_t)args.fh, (caddr_t)nfh,
1064		    args.fhsize);
1065		if (error != 0)
1066			goto out;
1067		error = copyinstr(args.hostname, hst, MNAMELEN - 1, &hstlen);
1068		if (error != 0)
1069			goto out;
1070		bzero(&hst[hstlen], MNAMELEN - hstlen);
1071		args.hostname = hst;
1072		/* sockargs() call must be after above copyin() calls */
1073		error = getsockaddr(&nam, (caddr_t)args.addr,
1074		    args.addrlen);
1075		if (error != 0)
1076			goto out;
1077	} else {
1078		if (vfs_getopt(mp->mnt_optnew, "fh", (void **)&args.fh,
1079		    &args.fhsize) == 0) {
1080			if (args.fhsize < 0 || args.fhsize > NFSX_FHMAX) {
1081				vfs_mount_error(mp, "Bad file handle");
1082				error = EINVAL;
1083				goto out;
1084			}
1085			bcopy(args.fh, nfh, args.fhsize);
1086		} else {
1087			args.fhsize = 0;
1088		}
1089		(void) vfs_getopt(mp->mnt_optnew, "hostname",
1090		    (void **)&args.hostname, &len);
1091		if (args.hostname == NULL) {
1092			vfs_mount_error(mp, "Invalid hostname");
1093			error = EINVAL;
1094			goto out;
1095		}
1096		bcopy(args.hostname, hst, MNAMELEN);
1097		hst[MNAMELEN - 1] = '\0';
1098	}
1099
1100	if (vfs_getopt(mp->mnt_optnew, "principal", (void **)&name, NULL) == 0)
1101		strlcpy(srvkrbname, name, sizeof (srvkrbname));
1102	else
1103		snprintf(srvkrbname, sizeof (srvkrbname), "nfs@%s", hst);
1104	srvkrbnamelen = strlen(srvkrbname);
1105
1106	if (vfs_getopt(mp->mnt_optnew, "gssname", (void **)&name, NULL) == 0)
1107		strlcpy(krbname, name, sizeof (krbname));
1108	else
1109		krbname[0] = '\0';
1110	krbnamelen = strlen(krbname);
1111
1112	if (vfs_getopt(mp->mnt_optnew, "dirpath", (void **)&name, NULL) == 0)
1113		strlcpy(dirpath, name, sizeof (dirpath));
1114	else
1115		dirpath[0] = '\0';
1116	dirlen = strlen(dirpath);
1117
1118	if (has_nfs_args_opt == 0) {
1119		if (vfs_getopt(mp->mnt_optnew, "addr",
1120		    (void **)&args.addr, &args.addrlen) == 0) {
1121			if (args.addrlen > SOCK_MAXADDRLEN) {
1122				error = ENAMETOOLONG;
1123				goto out;
1124			}
1125			nam = malloc(args.addrlen, M_SONAME, M_WAITOK);
1126			bcopy(args.addr, nam, args.addrlen);
1127			nam->sa_len = args.addrlen;
1128		} else {
1129			vfs_mount_error(mp, "No server address");
1130			error = EINVAL;
1131			goto out;
1132		}
1133	}
1134
1135	args.fh = nfh;
1136	error = mountnfs(&args, mp, nam, hst, krbname, krbnamelen, dirpath,
1137	    dirlen, srvkrbname, srvkrbnamelen, &vp, td->td_ucred, td,
1138	    nametimeo, negnametimeo);
1139out:
1140	if (!error) {
1141		MNT_ILOCK(mp);
1142		mp->mnt_kern_flag |= MNTK_MPSAFE | MNTK_LOOKUP_SHARED |
1143		    MNTK_NO_IOPF;
1144		MNT_IUNLOCK(mp);
1145	}
1146	return (error);
1147}
1148
1149
1150/*
1151 * VFS Operations.
1152 *
1153 * mount system call
1154 * It seems a bit dumb to copyinstr() the host and path here and then
1155 * bcopy() them in mountnfs(), but I wanted to detect errors before
1156 * doing the sockargs() call because sockargs() allocates an mbuf and
1157 * an error after that means that I have to release the mbuf.
1158 */
1159/* ARGSUSED */
1160static int
1161nfs_cmount(struct mntarg *ma, void *data, uint64_t flags)
1162{
1163	int error;
1164	struct nfs_args args;
1165
1166	error = copyin(data, &args, sizeof (struct nfs_args));
1167	if (error)
1168		return error;
1169
1170	ma = mount_arg(ma, "nfs_args", &args, sizeof args);
1171
1172	error = kernel_mount(ma, flags);
1173	return (error);
1174}
1175
1176/*
1177 * Common code for mount and mountroot
1178 */
1179static int
1180mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
1181    char *hst, u_char *krbname, int krbnamelen, u_char *dirpath, int dirlen,
1182    u_char *srvkrbname, int srvkrbnamelen, struct vnode **vpp,
1183    struct ucred *cred, struct thread *td, int nametimeo, int negnametimeo)
1184{
1185	struct nfsmount *nmp;
1186	struct nfsnode *np;
1187	int error, trycnt, ret;
1188	struct nfsvattr nfsva;
1189	static u_int64_t clval = 0;
1190
1191	if (mp->mnt_flag & MNT_UPDATE) {
1192		nmp = VFSTONFS(mp);
1193		printf("%s: MNT_UPDATE is no longer handled here\n", __func__);
1194		FREE(nam, M_SONAME);
1195		return (0);
1196	} else {
1197		MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount) +
1198		    krbnamelen + dirlen + srvkrbnamelen + 2,
1199		    M_NEWNFSMNT, M_WAITOK | M_ZERO);
1200		TAILQ_INIT(&nmp->nm_bufq);
1201		if (clval == 0)
1202			clval = (u_int64_t)nfsboottime.tv_sec;
1203		nmp->nm_clval = clval++;
1204		nmp->nm_krbnamelen = krbnamelen;
1205		nmp->nm_dirpathlen = dirlen;
1206		nmp->nm_srvkrbnamelen = srvkrbnamelen;
1207		if (td->td_ucred->cr_uid != (uid_t)0) {
1208			/*
1209			 * nm_uid is used to get KerberosV credentials for
1210			 * the nfsv4 state handling operations if there is
1211			 * no host based principal set. Use the uid of
1212			 * this user if not root, since they are doing the
1213			 * mount. I don't think setting this for root will
1214			 * work, since root normally does not have user
1215			 * credentials in a credentials cache.
1216			 */
1217			nmp->nm_uid = td->td_ucred->cr_uid;
1218		} else {
1219			/*
1220			 * Just set to -1, so it won't be used.
1221			 */
1222			nmp->nm_uid = (uid_t)-1;
1223		}
1224
1225		/* Copy and null terminate all the names */
1226		if (nmp->nm_krbnamelen > 0) {
1227			bcopy(krbname, nmp->nm_krbname, nmp->nm_krbnamelen);
1228			nmp->nm_name[nmp->nm_krbnamelen] = '\0';
1229		}
1230		if (nmp->nm_dirpathlen > 0) {
1231			bcopy(dirpath, NFSMNT_DIRPATH(nmp),
1232			    nmp->nm_dirpathlen);
1233			nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen
1234			    + 1] = '\0';
1235		}
1236		if (nmp->nm_srvkrbnamelen > 0) {
1237			bcopy(srvkrbname, NFSMNT_SRVKRBNAME(nmp),
1238			    nmp->nm_srvkrbnamelen);
1239			nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen
1240			    + nmp->nm_srvkrbnamelen + 2] = '\0';
1241		}
1242		nmp->nm_sockreq.nr_cred = crhold(cred);
1243		mtx_init(&nmp->nm_sockreq.nr_mtx, "nfssock", NULL, MTX_DEF);
1244		mp->mnt_data = nmp;
1245		nmp->nm_getinfo = nfs_getnlminfo;
1246		nmp->nm_vinvalbuf = ncl_vinvalbuf;
1247	}
1248	vfs_getnewfsid(mp);
1249	nmp->nm_mountp = mp;
1250	mtx_init(&nmp->nm_mtx, "NFSmount lock", NULL, MTX_DEF | MTX_DUPOK);
1251
1252	/*
1253	 * Since nfs_decode_args() might optionally set them, these
1254	 * need to be set to defaults before the call, so that the
1255	 * optional settings aren't overwritten.
1256	 */
1257	nmp->nm_nametimeo = nametimeo;
1258	nmp->nm_negnametimeo = negnametimeo;
1259	nmp->nm_timeo = NFS_TIMEO;
1260	nmp->nm_retry = NFS_RETRANS;
1261	nmp->nm_readahead = NFS_DEFRAHEAD;
1262	if (desiredvnodes >= 11000)
1263		nmp->nm_wcommitsize = hibufspace / (desiredvnodes / 1000);
1264	else
1265		nmp->nm_wcommitsize = hibufspace / 10;
1266
1267	nfs_decode_args(mp, nmp, argp, hst, cred, td);
1268
1269	/*
1270	 * V2 can only handle 32 bit filesizes.  A 4GB-1 limit may be too
1271	 * high, depending on whether we end up with negative offsets in
1272	 * the client or server somewhere.  2GB-1 may be safer.
1273	 *
1274	 * For V3, ncl_fsinfo will adjust this as necessary.  Assume maximum
1275	 * that we can handle until we find out otherwise.
1276	 * XXX Our "safe" limit on the client is what we can store in our
1277	 * buffer cache using signed(!) block numbers.
1278	 */
1279	if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0)
1280		nmp->nm_maxfilesize = 0xffffffffLL;
1281	else
1282		nmp->nm_maxfilesize = OFF_MAX;
1283
1284	if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) {
1285		nmp->nm_wsize = NFS_WSIZE;
1286		nmp->nm_rsize = NFS_RSIZE;
1287		nmp->nm_readdirsize = NFS_READDIRSIZE;
1288	}
1289	nmp->nm_numgrps = NFS_MAXGRPS;
1290	nmp->nm_tprintf_delay = nfs_tprintf_delay;
1291	if (nmp->nm_tprintf_delay < 0)
1292		nmp->nm_tprintf_delay = 0;
1293	nmp->nm_tprintf_initial_delay = nfs_tprintf_initial_delay;
1294	if (nmp->nm_tprintf_initial_delay < 0)
1295		nmp->nm_tprintf_initial_delay = 0;
1296	nmp->nm_fhsize = argp->fhsize;
1297	if (nmp->nm_fhsize > 0)
1298		bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize);
1299	bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
1300	nmp->nm_nam = nam;
1301	/* Set up the sockets and per-host congestion */
1302	nmp->nm_sotype = argp->sotype;
1303	nmp->nm_soproto = argp->proto;
1304	nmp->nm_sockreq.nr_prog = NFS_PROG;
1305	if ((argp->flags & NFSMNT_NFSV4))
1306		nmp->nm_sockreq.nr_vers = NFS_VER4;
1307	else if ((argp->flags & NFSMNT_NFSV3))
1308		nmp->nm_sockreq.nr_vers = NFS_VER3;
1309	else
1310		nmp->nm_sockreq.nr_vers = NFS_VER2;
1311
1312
1313	if ((error = newnfs_connect(nmp, &nmp->nm_sockreq, cred, td, 0)))
1314		goto bad;
1315
1316	/*
1317	 * A reference count is needed on the nfsnode representing the
1318	 * remote root.  If this object is not persistent, then backward
1319	 * traversals of the mount point (i.e. "..") will not work if
1320	 * the nfsnode gets flushed out of the cache. Ufs does not have
1321	 * this problem, because one can identify root inodes by their
1322	 * number == ROOTINO (2).
1323	 */
1324	if (nmp->nm_fhsize == 0 && (nmp->nm_flag & NFSMNT_NFSV4) &&
1325	    nmp->nm_dirpathlen > 0) {
1326		/*
1327		 * If the fhsize on the mount point == 0 for V4, the mount
1328		 * path needs to be looked up.
1329		 */
1330		trycnt = 3;
1331		do {
1332			error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp),
1333			    cred, td);
1334			if (error)
1335				(void) nfs_catnap(PZERO, error, "nfsgetdirp");
1336		} while (error && --trycnt > 0);
1337		if (error) {
1338			error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0);
1339			goto bad;
1340		}
1341	}
1342	if (nmp->nm_fhsize > 0) {
1343		/*
1344		 * Set f_iosize to NFS_DIRBLKSIZ so that bo_bsize gets set
1345		 * non-zero for the root vnode. f_iosize will be set correctly
1346		 * by nfs_statfs() before any I/O occurs.
1347		 */
1348		mp->mnt_stat.f_iosize = NFS_DIRBLKSIZ;
1349		error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np,
1350		    LK_EXCLUSIVE);
1351		if (error)
1352			goto bad;
1353		*vpp = NFSTOV(np);
1354
1355		/*
1356		 * Get file attributes and transfer parameters for the
1357		 * mountpoint.  This has the side effect of filling in
1358		 * (*vpp)->v_type with the correct value.
1359		 */
1360		ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1,
1361		    cred, td, &nfsva, NULL);
1362		if (ret) {
1363			/*
1364			 * Just set default values to get things going.
1365			 */
1366			NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr));
1367			nfsva.na_vattr.va_type = VDIR;
1368			nfsva.na_vattr.va_mode = 0777;
1369			nfsva.na_vattr.va_nlink = 100;
1370			nfsva.na_vattr.va_uid = (uid_t)0;
1371			nfsva.na_vattr.va_gid = (gid_t)0;
1372			nfsva.na_vattr.va_fileid = 2;
1373			nfsva.na_vattr.va_gen = 1;
1374			nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE;
1375			nfsva.na_vattr.va_size = 512 * 1024;
1376		}
1377		(void) nfscl_loadattrcache(vpp, &nfsva, NULL, NULL, 0, 1);
1378		if (argp->flags & NFSMNT_NFSV3)
1379			ncl_fsinfo(nmp, *vpp, cred, td);
1380
1381		/* Mark if the mount point supports NFSv4 ACLs. */
1382		if ((argp->flags & NFSMNT_NFSV4) != 0 && nfsrv_useacl != 0 &&
1383		    ret == 0 &&
1384		    NFSISSET_ATTRBIT(&nfsva.na_suppattr, NFSATTRBIT_ACL)) {
1385			MNT_ILOCK(mp);
1386			mp->mnt_flag |= MNT_NFS4ACLS;
1387			MNT_IUNLOCK(mp);
1388		}
1389
1390		/*
1391		 * Lose the lock but keep the ref.
1392		 */
1393		NFSVOPUNLOCK(*vpp, 0);
1394		return (0);
1395	}
1396	error = EIO;
1397
1398bad:
1399	newnfs_disconnect(&nmp->nm_sockreq);
1400	crfree(nmp->nm_sockreq.nr_cred);
1401	mtx_destroy(&nmp->nm_sockreq.nr_mtx);
1402	mtx_destroy(&nmp->nm_mtx);
1403	FREE(nmp, M_NEWNFSMNT);
1404	FREE(nam, M_SONAME);
1405	return (error);
1406}
1407
1408/*
1409 * unmount system call
1410 */
1411static int
1412nfs_unmount(struct mount *mp, int mntflags)
1413{
1414	struct thread *td;
1415	struct nfsmount *nmp;
1416	int error, flags = 0, i, trycnt = 0;
1417
1418	td = curthread;
1419
1420	if (mntflags & MNT_FORCE)
1421		flags |= FORCECLOSE;
1422	nmp = VFSTONFS(mp);
1423	/*
1424	 * Goes something like this..
1425	 * - Call vflush() to clear out vnodes for this filesystem
1426	 * - Close the socket
1427	 * - Free up the data structures
1428	 */
1429	/* In the forced case, cancel any outstanding requests. */
1430	if (mntflags & MNT_FORCE) {
1431		error = newnfs_nmcancelreqs(nmp);
1432		if (error)
1433			goto out;
1434		/* For a forced close, get rid of the renew thread now */
1435		nfscl_umount(nmp, td);
1436	}
1437	/* We hold 1 extra ref on the root vnode; see comment in mountnfs(). */
1438	do {
1439		error = vflush(mp, 1, flags, td);
1440		if ((mntflags & MNT_FORCE) && error != 0 && ++trycnt < 30)
1441			(void) nfs_catnap(PSOCK, error, "newndm");
1442	} while ((mntflags & MNT_FORCE) && error != 0 && trycnt < 30);
1443	if (error)
1444		goto out;
1445
1446	/*
1447	 * We are now committed to the unmount.
1448	 */
1449	if ((mntflags & MNT_FORCE) == 0)
1450		nfscl_umount(nmp, td);
1451	/* Make sure no nfsiods are assigned to this mount. */
1452	mtx_lock(&ncl_iod_mutex);
1453	for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
1454		if (ncl_iodmount[i] == nmp) {
1455			ncl_iodwant[i] = NFSIOD_AVAILABLE;
1456			ncl_iodmount[i] = NULL;
1457		}
1458	mtx_unlock(&ncl_iod_mutex);
1459	newnfs_disconnect(&nmp->nm_sockreq);
1460	crfree(nmp->nm_sockreq.nr_cred);
1461	FREE(nmp->nm_nam, M_SONAME);
1462
1463	mtx_destroy(&nmp->nm_sockreq.nr_mtx);
1464	mtx_destroy(&nmp->nm_mtx);
1465	FREE(nmp, M_NEWNFSMNT);
1466out:
1467	return (error);
1468}
1469
1470/*
1471 * Return root of a filesystem
1472 */
1473static int
1474nfs_root(struct mount *mp, int flags, struct vnode **vpp)
1475{
1476	struct vnode *vp;
1477	struct nfsmount *nmp;
1478	struct nfsnode *np;
1479	int error;
1480
1481	nmp = VFSTONFS(mp);
1482	error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, flags);
1483	if (error)
1484		return error;
1485	vp = NFSTOV(np);
1486	/*
1487	 * Get transfer parameters and attributes for root vnode once.
1488	 */
1489	mtx_lock(&nmp->nm_mtx);
1490	if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) {
1491		mtx_unlock(&nmp->nm_mtx);
1492		ncl_fsinfo(nmp, vp, curthread->td_ucred, curthread);
1493	} else
1494		mtx_unlock(&nmp->nm_mtx);
1495	if (vp->v_type == VNON)
1496	    vp->v_type = VDIR;
1497	vp->v_vflag |= VV_ROOT;
1498	*vpp = vp;
1499	return (0);
1500}
1501
1502/*
1503 * Flush out the buffer cache
1504 */
1505/* ARGSUSED */
1506static int
1507nfs_sync(struct mount *mp, int waitfor)
1508{
1509	struct vnode *vp, *mvp;
1510	struct thread *td;
1511	int error, allerror = 0;
1512
1513	td = curthread;
1514
1515	MNT_ILOCK(mp);
1516	/*
1517	 * If a forced dismount is in progress, return from here so that
1518	 * the umount(2) syscall doesn't get stuck in VFS_SYNC() before
1519	 * calling VFS_UNMOUNT().
1520	 */
1521	if ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
1522		MNT_IUNLOCK(mp);
1523		return (EBADF);
1524	}
1525	MNT_IUNLOCK(mp);
1526
1527	/*
1528	 * Force stale buffer cache information to be flushed.
1529	 */
1530loop:
1531	MNT_VNODE_FOREACH_ALL(vp, mp, mvp) {
1532		/* XXX Racy bv_cnt check. */
1533		if (NFSVOPISLOCKED(vp) || vp->v_bufobj.bo_dirty.bv_cnt == 0 ||
1534		    waitfor == MNT_LAZY) {
1535			VI_UNLOCK(vp);
1536			continue;
1537		}
1538		if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) {
1539			MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp);
1540			goto loop;
1541		}
1542		error = VOP_FSYNC(vp, waitfor, td);
1543		if (error)
1544			allerror = error;
1545		NFSVOPUNLOCK(vp, 0);
1546		vrele(vp);
1547	}
1548	return (allerror);
1549}
1550
1551static int
1552nfs_sysctl(struct mount *mp, fsctlop_t op, struct sysctl_req *req)
1553{
1554	struct nfsmount *nmp = VFSTONFS(mp);
1555	struct vfsquery vq;
1556	int error;
1557
1558	bzero(&vq, sizeof(vq));
1559	switch (op) {
1560#if 0
1561	case VFS_CTL_NOLOCKS:
1562		val = (nmp->nm_flag & NFSMNT_NOLOCKS) ? 1 : 0;
1563 		if (req->oldptr != NULL) {
1564 			error = SYSCTL_OUT(req, &val, sizeof(val));
1565 			if (error)
1566 				return (error);
1567 		}
1568 		if (req->newptr != NULL) {
1569 			error = SYSCTL_IN(req, &val, sizeof(val));
1570 			if (error)
1571 				return (error);
1572			if (val)
1573				nmp->nm_flag |= NFSMNT_NOLOCKS;
1574			else
1575				nmp->nm_flag &= ~NFSMNT_NOLOCKS;
1576 		}
1577		break;
1578#endif
1579	case VFS_CTL_QUERY:
1580		mtx_lock(&nmp->nm_mtx);
1581		if (nmp->nm_state & NFSSTA_TIMEO)
1582			vq.vq_flags |= VQ_NOTRESP;
1583		mtx_unlock(&nmp->nm_mtx);
1584#if 0
1585		if (!(nmp->nm_flag & NFSMNT_NOLOCKS) &&
1586		    (nmp->nm_state & NFSSTA_LOCKTIMEO))
1587			vq.vq_flags |= VQ_NOTRESPLOCK;
1588#endif
1589		error = SYSCTL_OUT(req, &vq, sizeof(vq));
1590		break;
1591 	case VFS_CTL_TIMEO:
1592 		if (req->oldptr != NULL) {
1593 			error = SYSCTL_OUT(req, &nmp->nm_tprintf_initial_delay,
1594 			    sizeof(nmp->nm_tprintf_initial_delay));
1595 			if (error)
1596 				return (error);
1597 		}
1598 		if (req->newptr != NULL) {
1599			error = vfs_suser(mp, req->td);
1600			if (error)
1601				return (error);
1602 			error = SYSCTL_IN(req, &nmp->nm_tprintf_initial_delay,
1603 			    sizeof(nmp->nm_tprintf_initial_delay));
1604 			if (error)
1605 				return (error);
1606 			if (nmp->nm_tprintf_initial_delay < 0)
1607 				nmp->nm_tprintf_initial_delay = 0;
1608 		}
1609		break;
1610	default:
1611		return (ENOTSUP);
1612	}
1613	return (0);
1614}
1615
1616/*
1617 * Extract the information needed by the nlm from the nfs vnode.
1618 */
1619static void
1620nfs_getnlminfo(struct vnode *vp, uint8_t *fhp, size_t *fhlenp,
1621    struct sockaddr_storage *sp, int *is_v3p, off_t *sizep,
1622    struct timeval *timeop)
1623{
1624	struct nfsmount *nmp;
1625	struct nfsnode *np = VTONFS(vp);
1626
1627	nmp = VFSTONFS(vp->v_mount);
1628	if (fhlenp != NULL)
1629		*fhlenp = (size_t)np->n_fhp->nfh_len;
1630	if (fhp != NULL)
1631		bcopy(np->n_fhp->nfh_fh, fhp, np->n_fhp->nfh_len);
1632	if (sp != NULL)
1633		bcopy(nmp->nm_nam, sp, min(nmp->nm_nam->sa_len, sizeof(*sp)));
1634	if (is_v3p != NULL)
1635		*is_v3p = NFS_ISV3(vp);
1636	if (sizep != NULL)
1637		*sizep = np->n_size;
1638	if (timeop != NULL) {
1639		timeop->tv_sec = nmp->nm_timeo / NFS_HZ;
1640		timeop->tv_usec = (nmp->nm_timeo % NFS_HZ) * (1000000 / NFS_HZ);
1641	}
1642}
1643
1644/*
1645 * This function prints out an option name, based on the conditional
1646 * argument.
1647 */
1648static __inline void nfscl_printopt(struct nfsmount *nmp, int testval,
1649    char *opt, char **buf, size_t *blen)
1650{
1651	int len;
1652
1653	if (testval != 0 && *blen > strlen(opt)) {
1654		len = snprintf(*buf, *blen, "%s", opt);
1655		if (len != strlen(opt))
1656			printf("EEK!!\n");
1657		*buf += len;
1658		*blen -= len;
1659	}
1660}
1661
1662/*
1663 * This function printf out an options integer value.
1664 */
1665static __inline void nfscl_printoptval(struct nfsmount *nmp, int optval,
1666    char *opt, char **buf, size_t *blen)
1667{
1668	int len;
1669
1670	if (*blen > strlen(opt) + 1) {
1671		/* Could result in truncated output string. */
1672		len = snprintf(*buf, *blen, "%s=%d", opt, optval);
1673		if (len < *blen) {
1674			*buf += len;
1675			*blen -= len;
1676		}
1677	}
1678}
1679
1680/*
1681 * Load the option flags and values into the buffer.
1682 */
1683void nfscl_retopts(struct nfsmount *nmp, char *buffer, size_t buflen)
1684{
1685	char *buf;
1686	size_t blen;
1687
1688	buf = buffer;
1689	blen = buflen;
1690	nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NFSV4) != 0, "nfsv4", &buf,
1691	    &blen);
1692	nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NFSV3) != 0, "nfsv3", &buf,
1693	    &blen);
1694	nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0,
1695	    "nfsv2", &buf, &blen);
1696	nfscl_printopt(nmp, nmp->nm_sotype == SOCK_STREAM, ",tcp", &buf, &blen);
1697	nfscl_printopt(nmp, nmp->nm_sotype != SOCK_STREAM, ",udp", &buf, &blen);
1698	nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_RESVPORT) != 0, ",resvport",
1699	    &buf, &blen);
1700	nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCONN) != 0, ",noconn",
1701	    &buf, &blen);
1702	nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_SOFT) == 0, ",hard", &buf,
1703	    &blen);
1704	nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_SOFT) != 0, ",soft", &buf,
1705	    &blen);
1706	nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_INT) != 0, ",intr", &buf,
1707	    &blen);
1708	nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCTO) == 0, ",cto", &buf,
1709	    &blen);
1710	nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCTO) != 0, ",nocto", &buf,
1711	    &blen);
1712	nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_NOLOCKD | NFSMNT_NFSV4)) ==
1713	    0, ",lockd", &buf, &blen);
1714	nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_NOLOCKD | NFSMNT_NFSV4)) ==
1715	    NFSMNT_NOLOCKD, ",nolockd", &buf, &blen);
1716	nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_RDIRPLUS) != 0, ",rdirplus",
1717	    &buf, &blen);
1718	nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_KERB) == 0, ",sec=sys",
1719	    &buf, &blen);
1720	nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY |
1721	    NFSMNT_PRIVACY)) == NFSMNT_KERB, ",sec=krb5", &buf, &blen);
1722	nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY |
1723	    NFSMNT_PRIVACY)) == (NFSMNT_KERB | NFSMNT_INTEGRITY), ",sec=krb5i",
1724	    &buf, &blen);
1725	nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY |
1726	    NFSMNT_PRIVACY)) == (NFSMNT_KERB | NFSMNT_PRIVACY), ",sec=krb5p",
1727	    &buf, &blen);
1728	nfscl_printoptval(nmp, nmp->nm_acdirmin, ",acdirmin", &buf, &blen);
1729	nfscl_printoptval(nmp, nmp->nm_acdirmax, ",acdirmax", &buf, &blen);
1730	nfscl_printoptval(nmp, nmp->nm_acregmin, ",acregmin", &buf, &blen);
1731	nfscl_printoptval(nmp, nmp->nm_acregmax, ",acregmax", &buf, &blen);
1732	nfscl_printoptval(nmp, nmp->nm_nametimeo, ",nametimeo", &buf, &blen);
1733	nfscl_printoptval(nmp, nmp->nm_negnametimeo, ",negnametimeo", &buf,
1734	    &blen);
1735	nfscl_printoptval(nmp, nmp->nm_rsize, ",rsize", &buf, &blen);
1736	nfscl_printoptval(nmp, nmp->nm_wsize, ",wsize", &buf, &blen);
1737	nfscl_printoptval(nmp, nmp->nm_readdirsize, ",readdirsize", &buf,
1738	    &blen);
1739	nfscl_printoptval(nmp, nmp->nm_readahead, ",readahead", &buf, &blen);
1740	nfscl_printoptval(nmp, nmp->nm_wcommitsize, ",wcommitsize", &buf,
1741	    &blen);
1742	nfscl_printoptval(nmp, nmp->nm_timeo, ",timeout", &buf, &blen);
1743	nfscl_printoptval(nmp, nmp->nm_retry, ",retrans", &buf, &blen);
1744}
1745
1746