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