2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright (c) 1989, 1993, 1995
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * Rick Macklem at The University of Guelph.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * from nfs_vfsops.c 8.12 (Berkeley) 5/20/95
37 #include <sys/cdefs.h>
38 __FBSDID("$FreeBSD$");
40 #include "opt_bootp.h"
41 #include "opt_nfsroot.h"
42 #include "opt_kern_tls.h"
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
49 #include <sys/clock.h>
51 #include <sys/limits.h>
53 #include <sys/malloc.h>
55 #include <sys/mount.h>
57 #include <sys/socket.h>
58 #include <sys/socketvar.h>
59 #include <sys/sockio.h>
60 #include <sys/sysctl.h>
61 #include <sys/vnode.h>
62 #include <sys/signalvar.h>
65 #include <vm/vm_extern.h>
69 #include <net/route.h>
70 #include <net/route/route_ctl.h>
71 #include <netinet/in.h>
73 #include <fs/nfs/nfsport.h>
74 #include <fs/nfsclient/nfsnode.h>
75 #include <fs/nfsclient/nfsmount.h>
76 #include <fs/nfsclient/nfs.h>
77 #include <nfs/nfsdiskless.h>
79 #include <rpc/rpcsec_tls.h>
81 FEATURE(nfscl, "NFSv4 client");
83 extern int nfscl_ticks;
84 extern struct timeval nfsboottime;
85 extern int nfsrv_useacl;
86 extern int nfscl_debuglevel;
87 extern enum nfsiod_state ncl_iodwant[NFS_MAXASYNCDAEMON];
88 extern struct nfsmount *ncl_iodmount[NFS_MAXASYNCDAEMON];
89 extern struct mtx ncl_iod_mutex;
91 extern struct mtx nfsrv_dslock_mtx;
93 MALLOC_DEFINE(M_NEWNFSREQ, "newnfsclient_req", "NFS request header");
94 MALLOC_DEFINE(M_NEWNFSMNT, "newnfsmnt", "NFS mount struct");
96 SYSCTL_DECL(_vfs_nfs);
97 static int nfs_ip_paranoia = 1;
98 SYSCTL_INT(_vfs_nfs, OID_AUTO, nfs_ip_paranoia, CTLFLAG_RW,
99 &nfs_ip_paranoia, 0, "");
100 static int nfs_tprintf_initial_delay = NFS_TPRINTF_INITIAL_DELAY;
101 SYSCTL_INT(_vfs_nfs, NFS_TPRINTF_INITIAL_DELAY,
102 downdelayinitial, CTLFLAG_RW, &nfs_tprintf_initial_delay, 0, "");
103 /* how long between console messages "nfs server foo not responding" */
104 static int nfs_tprintf_delay = NFS_TPRINTF_DELAY;
105 SYSCTL_INT(_vfs_nfs, NFS_TPRINTF_DELAY,
106 downdelayinterval, CTLFLAG_RW, &nfs_tprintf_delay, 0, "");
109 SYSCTL_INT(_vfs_nfs, OID_AUTO, debug, CTLFLAG_RW, &nfs_debug, 0,
110 "Toggle debug flag");
113 static int nfs_mountroot(struct mount *);
114 static void nfs_sec_name(char *, int *);
115 static void nfs_decode_args(struct mount *mp, struct nfsmount *nmp,
116 struct nfs_args *argp, const char *, struct ucred *,
118 static int mountnfs(struct nfs_args *, struct mount *,
119 struct sockaddr *, char *, u_char *, int, u_char *, int,
120 u_char *, int, struct vnode **, struct ucred *,
121 struct thread *, int, int, int, uint32_t, char *);
122 static void nfs_getnlminfo(struct vnode *, uint8_t *, size_t *,
123 struct sockaddr_storage *, int *, off_t *,
125 static vfs_mount_t nfs_mount;
126 static vfs_cmount_t nfs_cmount;
127 static vfs_unmount_t nfs_unmount;
128 static vfs_root_t nfs_root;
129 static vfs_statfs_t nfs_statfs;
130 static vfs_sync_t nfs_sync;
131 static vfs_sysctl_t nfs_sysctl;
132 static vfs_purge_t nfs_purge;
135 * nfs vfs operations.
137 static struct vfsops nfs_vfsops = {
138 .vfs_init = ncl_init,
139 .vfs_mount = nfs_mount,
140 .vfs_cmount = nfs_cmount,
141 .vfs_root = vfs_cache_root,
142 .vfs_cachedroot = nfs_root,
143 .vfs_statfs = nfs_statfs,
144 .vfs_sync = nfs_sync,
145 .vfs_uninit = ncl_uninit,
146 .vfs_unmount = nfs_unmount,
147 .vfs_sysctl = nfs_sysctl,
148 .vfs_purge = nfs_purge,
151 * This macro declares that the file system type is named "nfs".
152 * It also declares a module name of "nfs" and uses vfs_modevent()
153 * as the event handling function.
154 * The main module declaration is found in sys/fs/nfsclient/nfs_clport.c
155 * for "nfscl" and is needed so that a custom event handling
156 * function gets called. MODULE_DEPEND() macros are found there.
158 VFS_SET(nfs_vfsops, nfs, VFCF_NETWORK | VFCF_SBDRY);
160 MODULE_VERSION(nfs, 1);
163 * This structure is now defined in sys/nfs/nfs_diskless.c so that it
164 * can be shared by both NFS clients. It is declared here so that it
165 * will be defined for kernels built without NFS_ROOT, although it
166 * isn't used in that case.
168 #if !defined(NFS_ROOT)
169 struct nfs_diskless nfs_diskless = { { { 0 } } };
170 struct nfsv3_diskless nfsv3_diskless = { { { 0 } } };
171 int nfs_diskless_valid = 0;
174 SYSCTL_INT(_vfs_nfs, OID_AUTO, diskless_valid, CTLFLAG_RD,
175 &nfs_diskless_valid, 0,
176 "Has the diskless struct been filled correctly");
178 SYSCTL_STRING(_vfs_nfs, OID_AUTO, diskless_rootpath, CTLFLAG_RD,
179 nfsv3_diskless.root_hostnam, 0, "Path to nfs root");
181 SYSCTL_OPAQUE(_vfs_nfs, OID_AUTO, diskless_rootaddr, CTLFLAG_RD,
182 &nfsv3_diskless.root_saddr, sizeof(nfsv3_diskless.root_saddr),
183 "%Ssockaddr_in", "Diskless root nfs address");
185 void newnfsargs_ntoh(struct nfs_args *);
186 static int nfs_mountdiskless(char *,
187 struct sockaddr_in *, struct nfs_args *,
188 struct thread *, struct vnode **, struct mount *);
189 static void nfs_convert_diskless(void);
190 static void nfs_convert_oargs(struct nfs_args *args,
191 struct onfs_args *oargs);
194 newnfs_iosize(struct nfsmount *nmp)
198 /* First, set the upper limit for iosize */
199 if (nmp->nm_flag & NFSMNT_NFSV4) {
200 maxio = NFS_MAXBSIZE;
201 } else if (nmp->nm_flag & NFSMNT_NFSV3) {
202 if (nmp->nm_sotype == SOCK_DGRAM)
203 maxio = NFS_MAXDGRAMDATA;
205 maxio = NFS_MAXBSIZE;
207 maxio = NFS_V2MAXDATA;
209 if (nmp->nm_rsize > maxio || nmp->nm_rsize == 0)
210 nmp->nm_rsize = maxio;
211 if (nmp->nm_rsize > NFS_MAXBSIZE)
212 nmp->nm_rsize = NFS_MAXBSIZE;
213 if (nmp->nm_readdirsize > maxio || nmp->nm_readdirsize == 0)
214 nmp->nm_readdirsize = maxio;
215 if (nmp->nm_readdirsize > nmp->nm_rsize)
216 nmp->nm_readdirsize = nmp->nm_rsize;
217 if (nmp->nm_wsize > maxio || nmp->nm_wsize == 0)
218 nmp->nm_wsize = maxio;
219 if (nmp->nm_wsize > NFS_MAXBSIZE)
220 nmp->nm_wsize = NFS_MAXBSIZE;
223 * Calculate the size used for io buffers. Use the larger
224 * of the two sizes to minimise nfs requests but make sure
225 * that it is at least one VM page to avoid wasting buffer
226 * space. It must also be at least NFS_DIRBLKSIZ, since
227 * that is the buffer size used for directories.
229 iosize = imax(nmp->nm_rsize, nmp->nm_wsize);
230 iosize = imax(iosize, PAGE_SIZE);
231 iosize = imax(iosize, NFS_DIRBLKSIZ);
232 nmp->nm_mountp->mnt_stat.f_iosize = iosize;
237 nfs_convert_oargs(struct nfs_args *args, struct onfs_args *oargs)
240 args->version = NFS_ARGSVERSION;
241 args->addr = oargs->addr;
242 args->addrlen = oargs->addrlen;
243 args->sotype = oargs->sotype;
244 args->proto = oargs->proto;
245 args->fh = oargs->fh;
246 args->fhsize = oargs->fhsize;
247 args->flags = oargs->flags;
248 args->wsize = oargs->wsize;
249 args->rsize = oargs->rsize;
250 args->readdirsize = oargs->readdirsize;
251 args->timeo = oargs->timeo;
252 args->retrans = oargs->retrans;
253 args->readahead = oargs->readahead;
254 args->hostname = oargs->hostname;
258 nfs_convert_diskless(void)
261 bcopy(&nfs_diskless.myif, &nfsv3_diskless.myif,
262 sizeof(struct ifaliasreq));
263 bcopy(&nfs_diskless.mygateway, &nfsv3_diskless.mygateway,
264 sizeof(struct sockaddr_in));
265 nfs_convert_oargs(&nfsv3_diskless.root_args,&nfs_diskless.root_args);
266 if (nfsv3_diskless.root_args.flags & NFSMNT_NFSV3) {
267 nfsv3_diskless.root_fhsize = NFSX_MYFH;
268 bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_MYFH);
270 nfsv3_diskless.root_fhsize = NFSX_V2FH;
271 bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_V2FH);
273 bcopy(&nfs_diskless.root_saddr,&nfsv3_diskless.root_saddr,
274 sizeof(struct sockaddr_in));
275 bcopy(nfs_diskless.root_hostnam, nfsv3_diskless.root_hostnam, MNAMELEN);
276 nfsv3_diskless.root_time = nfs_diskless.root_time;
277 bcopy(nfs_diskless.my_hostnam, nfsv3_diskless.my_hostnam,
279 nfs_diskless_valid = 3;
286 nfs_statfs(struct mount *mp, struct statfs *sbp)
290 struct nfsmount *nmp = VFSTONFS(mp);
291 struct nfsvattr nfsva;
294 int error = 0, attrflag, gotfsinfo = 0, ret;
299 error = vfs_busy(mp, MBF_NOWAIT);
302 error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, LK_EXCLUSIVE);
308 mtx_lock(&nmp->nm_mtx);
309 if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) {
310 mtx_unlock(&nmp->nm_mtx);
311 error = nfsrpc_fsinfo(vp, &fs, td->td_ucred, td, &nfsva,
316 mtx_unlock(&nmp->nm_mtx);
318 error = nfsrpc_statfs(vp, &sb, &fs, td->td_ucred, td, &nfsva,
321 NFSCL_DEBUG(2, "statfs=%d\n", error);
323 ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1,
324 td->td_ucred, td, &nfsva, NULL, NULL);
327 * Just set default values to get things going.
329 NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr));
330 nfsva.na_vattr.va_type = VDIR;
331 nfsva.na_vattr.va_mode = 0777;
332 nfsva.na_vattr.va_nlink = 100;
333 nfsva.na_vattr.va_uid = (uid_t)0;
334 nfsva.na_vattr.va_gid = (gid_t)0;
335 nfsva.na_vattr.va_fileid = 2;
336 nfsva.na_vattr.va_gen = 1;
337 nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE;
338 nfsva.na_vattr.va_size = 512 * 1024;
341 (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1);
343 mtx_lock(&nmp->nm_mtx);
344 if (gotfsinfo || (nmp->nm_flag & NFSMNT_NFSV4))
345 nfscl_loadfsinfo(nmp, &fs);
346 nfscl_loadsbinfo(nmp, &sb, sbp);
347 sbp->f_iosize = newnfs_iosize(nmp);
348 mtx_unlock(&nmp->nm_mtx);
349 if (sbp != &mp->mnt_stat) {
350 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
351 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
353 strncpy(&sbp->f_fstypename[0], mp->mnt_vfc->vfc_name, MFSNAMELEN);
354 } else if (NFS_ISV4(vp)) {
355 error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0);
363 * nfs version 3 fsinfo rpc call
366 ncl_fsinfo(struct nfsmount *nmp, struct vnode *vp, struct ucred *cred,
370 struct nfsvattr nfsva;
373 error = nfsrpc_fsinfo(vp, &fs, cred, td, &nfsva, &attrflag, NULL);
376 (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0,
378 mtx_lock(&nmp->nm_mtx);
379 nfscl_loadfsinfo(nmp, &fs);
380 mtx_unlock(&nmp->nm_mtx);
386 * Mount a remote root fs via. nfs. This depends on the info in the
387 * nfs_diskless structure that has been filled in properly by some primary
389 * It goes something like this:
390 * - do enough of "ifconfig" by calling ifioctl() so that the system
391 * can talk to the server
392 * - If nfs_diskless.mygateway is filled in, use that address as
394 * - build the rootfs mount point and call mountnfs() to do the rest.
396 * It is assumed to be safe to read, modify, and write the nfsv3_diskless
397 * structure, as well as other global NFS client variables here, as
398 * nfs_mountroot() will be called once in the boot before any other NFS
399 * client activity occurs.
402 nfs_mountroot(struct mount *mp)
404 struct thread *td = curthread;
405 struct nfsv3_diskless *nd = &nfsv3_diskless;
414 #if defined(BOOTP_NFSROOT) && defined(BOOTP)
415 bootpc_init(); /* use bootp to get nfs_diskless filled in */
416 #elif defined(NFS_ROOT)
417 nfs_setup_diskless();
420 if (nfs_diskless_valid == 0)
422 if (nfs_diskless_valid == 1)
423 nfs_convert_diskless();
426 * Do enough of ifconfig(8) so that the critical net interface can
427 * talk to the server.
429 error = socreate(nd->myif.ifra_addr.sa_family, &so, nd->root_args.sotype, 0,
432 panic("nfs_mountroot: socreate(%04x): %d",
433 nd->myif.ifra_addr.sa_family, error);
435 #if 0 /* XXX Bad idea */
437 * We might not have been told the right interface, so we pass
438 * over the first ten interfaces of the same kind, until we get
439 * one of them configured.
442 for (i = strlen(nd->myif.ifra_name) - 1;
443 nd->myif.ifra_name[i] >= '0' &&
444 nd->myif.ifra_name[i] <= '9';
445 nd->myif.ifra_name[i] ++) {
446 error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td);
451 error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td);
453 panic("nfs_mountroot: SIOCAIFADDR: %d", error);
454 if ((cp = kern_getenv("boot.netif.mtu")) != NULL) {
455 ir.ifr_mtu = strtol(cp, NULL, 10);
456 bcopy(nd->myif.ifra_name, ir.ifr_name, IFNAMSIZ);
458 error = ifioctl(so, SIOCSIFMTU, (caddr_t)&ir, td);
460 printf("nfs_mountroot: SIOCSIFMTU: %d", error);
465 * If the gateway field is filled in, set it as the default route.
466 * Note that pxeboot will set a default route of 0 if the route
467 * is not set by the DHCP server. Check also for a value of 0
468 * to avoid panicking inappropriately in that situation.
470 if (nd->mygateway.sin_len != 0 &&
471 nd->mygateway.sin_addr.s_addr != 0) {
472 struct sockaddr_in mask, sin;
473 struct epoch_tracker et;
474 struct rt_addrinfo info;
475 struct rib_cmd_info rc;
477 bzero((caddr_t)&mask, sizeof(mask));
479 sin.sin_family = AF_INET;
480 sin.sin_len = sizeof(sin);
481 /* XXX MRT use table 0 for this sort of thing */
483 CURVNET_SET(TD_TO_VNET(td));
485 bzero((caddr_t)&info, sizeof(info));
486 info.rti_flags = RTF_UP | RTF_GATEWAY;
487 info.rti_info[RTAX_DST] = (struct sockaddr *)&sin;
488 info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&nd->mygateway;
489 info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&mask;
491 error = rib_action(RT_DEFAULT_FIB, RTM_ADD, &info, &rc);
495 panic("nfs_mountroot: RTM_ADD: %d", error);
499 * Create the rootfs mount point.
501 nd->root_args.fh = nd->root_fh;
502 nd->root_args.fhsize = nd->root_fhsize;
503 l = ntohl(nd->root_saddr.sin_addr.s_addr);
504 snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s",
505 (l >> 24) & 0xff, (l >> 16) & 0xff,
506 (l >> 8) & 0xff, (l >> 0) & 0xff, nd->root_hostnam);
507 printf("NFS ROOT: %s\n", buf);
508 nd->root_args.hostname = buf;
509 if ((error = nfs_mountdiskless(buf,
510 &nd->root_saddr, &nd->root_args, td, &vp, mp)) != 0) {
515 * This is not really an nfs issue, but it is much easier to
516 * set hostname here and then let the "/etc/rc.xxx" files
517 * mount the right /var based upon its preset value.
519 mtx_lock(&prison0.pr_mtx);
520 strlcpy(prison0.pr_hostname, nd->my_hostnam,
521 sizeof(prison0.pr_hostname));
522 mtx_unlock(&prison0.pr_mtx);
523 inittodr(ntohl(nd->root_time));
528 * Internal version of mount system call for diskless setup.
531 nfs_mountdiskless(char *path,
532 struct sockaddr_in *sin, struct nfs_args *args, struct thread *td,
533 struct vnode **vpp, struct mount *mp)
535 struct sockaddr *nam;
540 * Find the directory path in "path", which also has the server's
541 * name/ip address in it.
543 dirpath = strchr(path, ':');
545 dirlen = strlen(++dirpath);
548 nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK);
549 if ((error = mountnfs(args, mp, nam, path, NULL, 0, dirpath, dirlen,
550 NULL, 0, vpp, td->td_ucred, td, NFS_DEFAULT_NAMETIMEO,
551 NFS_DEFAULT_NEGNAMETIMEO, 0, 0, NULL)) != 0) {
552 printf("nfs_mountroot: mount %s on /: %d\n", path, error);
559 nfs_sec_name(char *sec, int *flagsp)
561 if (!strcmp(sec, "krb5"))
562 *flagsp |= NFSMNT_KERB;
563 else if (!strcmp(sec, "krb5i"))
564 *flagsp |= (NFSMNT_KERB | NFSMNT_INTEGRITY);
565 else if (!strcmp(sec, "krb5p"))
566 *flagsp |= (NFSMNT_KERB | NFSMNT_PRIVACY);
570 nfs_decode_args(struct mount *mp, struct nfsmount *nmp, struct nfs_args *argp,
571 const char *hostname, struct ucred *cred, struct thread *td)
577 * Set read-only flag if requested; otherwise, clear it if this is
578 * an update. If this is not an update, then either the read-only
579 * flag is already clear, or this is a root mount and it was set
580 * intentionally at some previous point.
582 if (vfs_getopt(mp->mnt_optnew, "ro", NULL, NULL) == 0) {
584 mp->mnt_flag |= MNT_RDONLY;
586 } else if (mp->mnt_flag & MNT_UPDATE) {
588 mp->mnt_flag &= ~MNT_RDONLY;
593 * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes
594 * no sense in that context. Also, set up appropriate retransmit
595 * and soft timeout behavior.
597 if (argp->sotype == SOCK_STREAM) {
598 nmp->nm_flag &= ~NFSMNT_NOCONN;
599 nmp->nm_timeo = NFS_MAXTIMEO;
600 if ((argp->flags & NFSMNT_NFSV4) != 0)
601 nmp->nm_retry = INT_MAX;
603 nmp->nm_retry = NFS_RETRANS_TCP;
606 /* Also clear RDIRPLUS if NFSv2, it crashes some servers */
607 if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) {
608 argp->flags &= ~NFSMNT_RDIRPLUS;
609 nmp->nm_flag &= ~NFSMNT_RDIRPLUS;
612 /* Clear ONEOPENOWN for NFSv2, 3 and 4.0. */
613 if (nmp->nm_minorvers == 0) {
614 argp->flags &= ~NFSMNT_ONEOPENOWN;
615 nmp->nm_flag &= ~NFSMNT_ONEOPENOWN;
618 /* Re-bind if rsrvd port requested and wasn't on one */
619 adjsock = !(nmp->nm_flag & NFSMNT_RESVPORT)
620 && (argp->flags & NFSMNT_RESVPORT);
621 /* Also re-bind if we're switching to/from a connected UDP socket */
622 adjsock |= ((nmp->nm_flag & NFSMNT_NOCONN) !=
623 (argp->flags & NFSMNT_NOCONN));
625 /* Update flags atomically. Don't change the lock bits. */
626 nmp->nm_flag = argp->flags | nmp->nm_flag;
628 if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
629 nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
630 if (nmp->nm_timeo < NFS_MINTIMEO)
631 nmp->nm_timeo = NFS_MINTIMEO;
632 else if (nmp->nm_timeo > NFS_MAXTIMEO)
633 nmp->nm_timeo = NFS_MAXTIMEO;
636 if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
637 nmp->nm_retry = argp->retrans;
638 if (nmp->nm_retry > NFS_MAXREXMIT)
639 nmp->nm_retry = NFS_MAXREXMIT;
642 if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
643 nmp->nm_wsize = argp->wsize;
645 * Clip at the power of 2 below the size. There is an
646 * issue (not isolated) that causes intermittent page
647 * faults if this is not done.
649 if (nmp->nm_wsize > NFS_FABLKSIZE)
650 nmp->nm_wsize = 1 << (fls(nmp->nm_wsize) - 1);
652 nmp->nm_wsize = NFS_FABLKSIZE;
655 if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
656 nmp->nm_rsize = argp->rsize;
658 * Clip at the power of 2 below the size. There is an
659 * issue (not isolated) that causes intermittent page
660 * faults if this is not done.
662 if (nmp->nm_rsize > NFS_FABLKSIZE)
663 nmp->nm_rsize = 1 << (fls(nmp->nm_rsize) - 1);
665 nmp->nm_rsize = NFS_FABLKSIZE;
668 if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) {
669 nmp->nm_readdirsize = argp->readdirsize;
672 if ((argp->flags & NFSMNT_ACREGMIN) && argp->acregmin >= 0)
673 nmp->nm_acregmin = argp->acregmin;
675 nmp->nm_acregmin = NFS_MINATTRTIMO;
676 if ((argp->flags & NFSMNT_ACREGMAX) && argp->acregmax >= 0)
677 nmp->nm_acregmax = argp->acregmax;
679 nmp->nm_acregmax = NFS_MAXATTRTIMO;
680 if ((argp->flags & NFSMNT_ACDIRMIN) && argp->acdirmin >= 0)
681 nmp->nm_acdirmin = argp->acdirmin;
683 nmp->nm_acdirmin = NFS_MINDIRATTRTIMO;
684 if ((argp->flags & NFSMNT_ACDIRMAX) && argp->acdirmax >= 0)
685 nmp->nm_acdirmax = argp->acdirmax;
687 nmp->nm_acdirmax = NFS_MAXDIRATTRTIMO;
688 if (nmp->nm_acdirmin > nmp->nm_acdirmax)
689 nmp->nm_acdirmin = nmp->nm_acdirmax;
690 if (nmp->nm_acregmin > nmp->nm_acregmax)
691 nmp->nm_acregmin = nmp->nm_acregmax;
693 if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0) {
694 if (argp->readahead <= NFS_MAXRAHEAD)
695 nmp->nm_readahead = argp->readahead;
697 nmp->nm_readahead = NFS_MAXRAHEAD;
699 if ((argp->flags & NFSMNT_WCOMMITSIZE) && argp->wcommitsize >= 0) {
700 if (argp->wcommitsize < nmp->nm_wsize)
701 nmp->nm_wcommitsize = nmp->nm_wsize;
703 nmp->nm_wcommitsize = argp->wcommitsize;
706 adjsock |= ((nmp->nm_sotype != argp->sotype) ||
707 (nmp->nm_soproto != argp->proto));
709 if (nmp->nm_client != NULL && adjsock) {
710 int haslock = 0, error = 0;
712 if (nmp->nm_sotype == SOCK_STREAM) {
713 error = newnfs_sndlock(&nmp->nm_sockreq.nr_lock);
718 newnfs_disconnect(&nmp->nm_sockreq);
720 newnfs_sndunlock(&nmp->nm_sockreq.nr_lock);
721 nmp->nm_sotype = argp->sotype;
722 nmp->nm_soproto = argp->proto;
723 if (nmp->nm_sotype == SOCK_DGRAM)
724 while (newnfs_connect(nmp, &nmp->nm_sockreq,
725 cred, td, 0, false)) {
726 printf("newnfs_args: retrying connect\n");
727 (void) nfs_catnap(PSOCK, 0, "nfscon");
731 nmp->nm_sotype = argp->sotype;
732 nmp->nm_soproto = argp->proto;
735 if (hostname != NULL) {
736 strlcpy(nmp->nm_hostname, hostname,
737 sizeof(nmp->nm_hostname));
738 p = strchr(nmp->nm_hostname, ':');
744 static const char *nfs_opts[] = { "from", "nfs_args",
745 "noac", "noatime", "noexec", "suiddir", "nosuid", "nosymfollow", "union",
746 "noclusterr", "noclusterw", "multilabel", "acls", "force", "update",
747 "async", "noconn", "nolockd", "conn", "lockd", "intr", "rdirplus",
748 "readdirsize", "soft", "hard", "mntudp", "tcp", "udp", "wsize", "rsize",
749 "retrans", "actimeo", "acregmin", "acregmax", "acdirmin", "acdirmax",
750 "resvport", "readahead", "hostname", "timeo", "timeout", "addr", "fh",
751 "nfsv3", "sec", "principal", "nfsv4", "gssname", "allgssname", "dirpath",
752 "minorversion", "nametimeo", "negnametimeo", "nocto", "noncontigwr",
753 "pnfs", "wcommitsize", "oneopenown", "tls", "tlscertname",
757 * Parse the "from" mountarg, passed by the generic mount(8) program
758 * or the mountroot code. This is used when rerooting into NFS.
760 * Note that the "hostname" is actually a "hostname:/share/path" string.
763 nfs_mount_parse_from(struct vfsoptlist *opts, char **hostnamep,
764 struct sockaddr_in **sinp, char *dirpath, size_t dirpathsize, int *dirlenp)
766 char *nam, *delimp, *hostp, *spec;
767 int error, have_bracket = 0, offset, rv, speclen;
768 struct sockaddr_in *sin;
771 error = vfs_getopt(opts, "from", (void **)&spec, &speclen);
774 nam = malloc(MNAMELEN + 1, M_TEMP, M_WAITOK);
777 * This part comes from sbin/mount_nfs/mount_nfs.c:getnfsargs().
779 if (*spec == '[' && (delimp = strchr(spec + 1, ']')) != NULL &&
780 *(delimp + 1) == ':') {
784 } else if ((delimp = strrchr(spec, ':')) != NULL) {
787 } else if ((delimp = strrchr(spec, '@')) != NULL) {
788 printf("%s: path@server syntax is deprecated, "
789 "use server:path\n", __func__);
792 printf("%s: no <host>:<dirpath> nfs-name\n", __func__);
799 * If there has been a trailing slash at mounttime it seems
800 * that some mountd implementations fail to remove the mount
801 * entries from their mountlist while unmounting.
803 for (speclen = strlen(spec);
804 speclen > 1 && spec[speclen - 1] == '/';
806 spec[speclen - 1] = '\0';
807 if (strlen(hostp) + strlen(spec) + 1 > MNAMELEN) {
808 printf("%s: %s:%s: name too long", __func__, hostp, spec);
812 /* Make both '@' and ':' notations equal */
813 if (*hostp != '\0') {
818 memmove(nam + offset, hostp, len);
820 nam[len + offset++] = ']';
821 nam[len + offset++] = ':';
822 memmove(nam + len + offset, spec, speclen);
823 nam[len + speclen + offset] = '\0';
830 sin = malloc(sizeof(*sin), M_SONAME, M_WAITOK);
831 rv = inet_pton(AF_INET, hostp, &sin->sin_addr);
833 printf("%s: cannot parse '%s', inet_pton() returned %d\n",
834 __func__, hostp, rv);
840 sin->sin_len = sizeof(*sin);
841 sin->sin_family = AF_INET;
843 * XXX: hardcoded port number.
845 sin->sin_port = htons(2049);
847 *hostnamep = strdup(nam, M_NEWNFSMNT);
849 strlcpy(dirpath, spec, dirpathsize);
850 *dirlenp = strlen(dirpath);
860 * It seems a bit dumb to copyinstr() the host and path here and then
861 * bcopy() them in mountnfs(), but I wanted to detect errors before
862 * doing the getsockaddr() call because getsockaddr() allocates an mbuf and
863 * an error after that means that I have to release the mbuf.
867 nfs_mount(struct mount *mp)
869 struct nfs_args args = {
870 .version = NFS_ARGSVERSION,
872 .addrlen = sizeof (struct sockaddr_in),
873 .sotype = SOCK_STREAM,
877 .flags = NFSMNT_RESVPORT,
880 .readdirsize = NFS_READDIRSIZE,
882 .retrans = NFS_RETRANS,
883 .readahead = NFS_DEFRAHEAD,
884 .wcommitsize = 0, /* was: NQ_DEFLEASE */
886 .acregmin = NFS_MINATTRTIMO,
887 .acregmax = NFS_MAXATTRTIMO,
888 .acdirmin = NFS_MINDIRATTRTIMO,
889 .acdirmax = NFS_MAXDIRATTRTIMO,
891 int error = 0, ret, len;
892 struct sockaddr *nam = NULL;
896 u_char nfh[NFSX_FHMAX], krbname[100], dirpath[100], srvkrbname[100];
897 char *cp, *opt, *name, *secname, *tlscertname;
898 int nametimeo = NFS_DEFAULT_NAMETIMEO;
899 int negnametimeo = NFS_DEFAULT_NEGNAMETIMEO;
901 int dirlen, has_nfs_args_opt, has_nfs_from_opt,
902 krbnamelen, srvkrbnamelen;
906 has_nfs_args_opt = 0;
907 has_nfs_from_opt = 0;
910 hst = malloc(MNAMELEN, M_TEMP, M_WAITOK);
911 if (vfs_filteropt(mp->mnt_optnew, nfs_opts)) {
917 if ((mp->mnt_flag & (MNT_ROOTFS | MNT_UPDATE)) == MNT_ROOTFS &&
918 nfs_diskless_valid != 0) {
919 error = nfs_mountroot(mp);
926 * The old mount_nfs program passed the struct nfs_args
927 * from userspace to kernel. The new mount_nfs program
928 * passes string options via nmount() from userspace to kernel
929 * and we populate the struct nfs_args in the kernel.
931 if (vfs_getopt(mp->mnt_optnew, "nfs_args", NULL, NULL) == 0) {
932 error = vfs_copyopt(mp->mnt_optnew, "nfs_args", &args,
937 if (args.version != NFS_ARGSVERSION) {
938 error = EPROGMISMATCH;
941 has_nfs_args_opt = 1;
944 /* Handle the new style options. */
945 if (vfs_getopt(mp->mnt_optnew, "noac", NULL, NULL) == 0) {
946 args.acdirmin = args.acdirmax =
947 args.acregmin = args.acregmax = 0;
948 args.flags |= NFSMNT_ACDIRMIN | NFSMNT_ACDIRMAX |
949 NFSMNT_ACREGMIN | NFSMNT_ACREGMAX;
951 if (vfs_getopt(mp->mnt_optnew, "noconn", NULL, NULL) == 0)
952 args.flags |= NFSMNT_NOCONN;
953 if (vfs_getopt(mp->mnt_optnew, "conn", NULL, NULL) == 0)
954 args.flags &= ~NFSMNT_NOCONN;
955 if (vfs_getopt(mp->mnt_optnew, "nolockd", NULL, NULL) == 0)
956 args.flags |= NFSMNT_NOLOCKD;
957 if (vfs_getopt(mp->mnt_optnew, "lockd", NULL, NULL) == 0)
958 args.flags &= ~NFSMNT_NOLOCKD;
959 if (vfs_getopt(mp->mnt_optnew, "intr", NULL, NULL) == 0)
960 args.flags |= NFSMNT_INT;
961 if (vfs_getopt(mp->mnt_optnew, "rdirplus", NULL, NULL) == 0)
962 args.flags |= NFSMNT_RDIRPLUS;
963 if (vfs_getopt(mp->mnt_optnew, "resvport", NULL, NULL) == 0)
964 args.flags |= NFSMNT_RESVPORT;
965 if (vfs_getopt(mp->mnt_optnew, "noresvport", NULL, NULL) == 0)
966 args.flags &= ~NFSMNT_RESVPORT;
967 if (vfs_getopt(mp->mnt_optnew, "soft", NULL, NULL) == 0)
968 args.flags |= NFSMNT_SOFT;
969 if (vfs_getopt(mp->mnt_optnew, "hard", NULL, NULL) == 0)
970 args.flags &= ~NFSMNT_SOFT;
971 if (vfs_getopt(mp->mnt_optnew, "mntudp", NULL, NULL) == 0)
972 args.sotype = SOCK_DGRAM;
973 if (vfs_getopt(mp->mnt_optnew, "udp", NULL, NULL) == 0)
974 args.sotype = SOCK_DGRAM;
975 if (vfs_getopt(mp->mnt_optnew, "tcp", NULL, NULL) == 0)
976 args.sotype = SOCK_STREAM;
977 if (vfs_getopt(mp->mnt_optnew, "nfsv3", NULL, NULL) == 0)
978 args.flags |= NFSMNT_NFSV3;
979 if (vfs_getopt(mp->mnt_optnew, "nfsv4", NULL, NULL) == 0) {
980 args.flags |= NFSMNT_NFSV4;
981 args.sotype = SOCK_STREAM;
983 if (vfs_getopt(mp->mnt_optnew, "allgssname", NULL, NULL) == 0)
984 args.flags |= NFSMNT_ALLGSSNAME;
985 if (vfs_getopt(mp->mnt_optnew, "nocto", NULL, NULL) == 0)
986 args.flags |= NFSMNT_NOCTO;
987 if (vfs_getopt(mp->mnt_optnew, "noncontigwr", NULL, NULL) == 0)
988 args.flags |= NFSMNT_NONCONTIGWR;
989 if (vfs_getopt(mp->mnt_optnew, "pnfs", NULL, NULL) == 0)
990 args.flags |= NFSMNT_PNFS;
991 if (vfs_getopt(mp->mnt_optnew, "oneopenown", NULL, NULL) == 0)
992 args.flags |= NFSMNT_ONEOPENOWN;
993 if (vfs_getopt(mp->mnt_optnew, "tls", NULL, NULL) == 0)
994 newflag |= NFSMNT_TLS;
995 if (vfs_getopt(mp->mnt_optnew, "tlscertname", (void **)&opt, &len) ==
998 * tlscertname with "key.pem" appended to it forms a file
999 * name. As such, the maximum allowable strlen(tlscertname) is
1000 * NAME_MAX - 7. However, "len" includes the nul termination
1001 * byte so it can be up to NAME_MAX - 6.
1003 if (opt == NULL || len <= 1 || len > NAME_MAX - 6) {
1004 vfs_mount_error(mp, "invalid tlscertname");
1008 tlscertname = malloc(len, M_NEWNFSMNT, M_WAITOK);
1009 strlcpy(tlscertname, opt, len);
1011 if (vfs_getopt(mp->mnt_optnew, "readdirsize", (void **)&opt, NULL) == 0) {
1013 vfs_mount_error(mp, "illegal readdirsize");
1017 ret = sscanf(opt, "%d", &args.readdirsize);
1018 if (ret != 1 || args.readdirsize <= 0) {
1019 vfs_mount_error(mp, "illegal readdirsize: %s",
1024 args.flags |= NFSMNT_READDIRSIZE;
1026 if (vfs_getopt(mp->mnt_optnew, "readahead", (void **)&opt, NULL) == 0) {
1028 vfs_mount_error(mp, "illegal readahead");
1032 ret = sscanf(opt, "%d", &args.readahead);
1033 if (ret != 1 || args.readahead <= 0) {
1034 vfs_mount_error(mp, "illegal readahead: %s",
1039 args.flags |= NFSMNT_READAHEAD;
1041 if (vfs_getopt(mp->mnt_optnew, "wsize", (void **)&opt, NULL) == 0) {
1043 vfs_mount_error(mp, "illegal wsize");
1047 ret = sscanf(opt, "%d", &args.wsize);
1048 if (ret != 1 || args.wsize <= 0) {
1049 vfs_mount_error(mp, "illegal wsize: %s",
1054 args.flags |= NFSMNT_WSIZE;
1056 if (vfs_getopt(mp->mnt_optnew, "rsize", (void **)&opt, NULL) == 0) {
1058 vfs_mount_error(mp, "illegal rsize");
1062 ret = sscanf(opt, "%d", &args.rsize);
1063 if (ret != 1 || args.rsize <= 0) {
1064 vfs_mount_error(mp, "illegal wsize: %s",
1069 args.flags |= NFSMNT_RSIZE;
1071 if (vfs_getopt(mp->mnt_optnew, "retrans", (void **)&opt, NULL) == 0) {
1073 vfs_mount_error(mp, "illegal retrans");
1077 ret = sscanf(opt, "%d", &args.retrans);
1078 if (ret != 1 || args.retrans <= 0) {
1079 vfs_mount_error(mp, "illegal retrans: %s",
1084 args.flags |= NFSMNT_RETRANS;
1086 if (vfs_getopt(mp->mnt_optnew, "actimeo", (void **)&opt, NULL) == 0) {
1087 ret = sscanf(opt, "%d", &args.acregmin);
1088 if (ret != 1 || args.acregmin < 0) {
1089 vfs_mount_error(mp, "illegal actimeo: %s",
1094 args.acdirmin = args.acdirmax = args.acregmax = args.acregmin;
1095 args.flags |= NFSMNT_ACDIRMIN | NFSMNT_ACDIRMAX |
1096 NFSMNT_ACREGMIN | NFSMNT_ACREGMAX;
1098 if (vfs_getopt(mp->mnt_optnew, "acregmin", (void **)&opt, NULL) == 0) {
1099 ret = sscanf(opt, "%d", &args.acregmin);
1100 if (ret != 1 || args.acregmin < 0) {
1101 vfs_mount_error(mp, "illegal acregmin: %s",
1106 args.flags |= NFSMNT_ACREGMIN;
1108 if (vfs_getopt(mp->mnt_optnew, "acregmax", (void **)&opt, NULL) == 0) {
1109 ret = sscanf(opt, "%d", &args.acregmax);
1110 if (ret != 1 || args.acregmax < 0) {
1111 vfs_mount_error(mp, "illegal acregmax: %s",
1116 args.flags |= NFSMNT_ACREGMAX;
1118 if (vfs_getopt(mp->mnt_optnew, "acdirmin", (void **)&opt, NULL) == 0) {
1119 ret = sscanf(opt, "%d", &args.acdirmin);
1120 if (ret != 1 || args.acdirmin < 0) {
1121 vfs_mount_error(mp, "illegal acdirmin: %s",
1126 args.flags |= NFSMNT_ACDIRMIN;
1128 if (vfs_getopt(mp->mnt_optnew, "acdirmax", (void **)&opt, NULL) == 0) {
1129 ret = sscanf(opt, "%d", &args.acdirmax);
1130 if (ret != 1 || args.acdirmax < 0) {
1131 vfs_mount_error(mp, "illegal acdirmax: %s",
1136 args.flags |= NFSMNT_ACDIRMAX;
1138 if (vfs_getopt(mp->mnt_optnew, "wcommitsize", (void **)&opt, NULL) == 0) {
1139 ret = sscanf(opt, "%d", &args.wcommitsize);
1140 if (ret != 1 || args.wcommitsize < 0) {
1141 vfs_mount_error(mp, "illegal wcommitsize: %s", opt);
1145 args.flags |= NFSMNT_WCOMMITSIZE;
1147 if (vfs_getopt(mp->mnt_optnew, "timeo", (void **)&opt, NULL) == 0) {
1148 ret = sscanf(opt, "%d", &args.timeo);
1149 if (ret != 1 || args.timeo <= 0) {
1150 vfs_mount_error(mp, "illegal timeo: %s",
1155 args.flags |= NFSMNT_TIMEO;
1157 if (vfs_getopt(mp->mnt_optnew, "timeout", (void **)&opt, NULL) == 0) {
1158 ret = sscanf(opt, "%d", &args.timeo);
1159 if (ret != 1 || args.timeo <= 0) {
1160 vfs_mount_error(mp, "illegal timeout: %s",
1165 args.flags |= NFSMNT_TIMEO;
1167 if (vfs_getopt(mp->mnt_optnew, "nametimeo", (void **)&opt, NULL) == 0) {
1168 ret = sscanf(opt, "%d", &nametimeo);
1169 if (ret != 1 || nametimeo < 0) {
1170 vfs_mount_error(mp, "illegal nametimeo: %s", opt);
1175 if (vfs_getopt(mp->mnt_optnew, "negnametimeo", (void **)&opt, NULL)
1177 ret = sscanf(opt, "%d", &negnametimeo);
1178 if (ret != 1 || negnametimeo < 0) {
1179 vfs_mount_error(mp, "illegal negnametimeo: %s",
1185 if (vfs_getopt(mp->mnt_optnew, "minorversion", (void **)&opt, NULL) ==
1187 ret = sscanf(opt, "%d", &minvers);
1188 if (ret != 1 || minvers < 0 || minvers > 2 ||
1189 (args.flags & NFSMNT_NFSV4) == 0) {
1190 vfs_mount_error(mp, "illegal minorversion: %s", opt);
1195 if (vfs_getopt(mp->mnt_optnew, "sec",
1196 (void **) &secname, NULL) == 0)
1197 nfs_sec_name(secname, &args.flags);
1199 if (mp->mnt_flag & MNT_UPDATE) {
1200 struct nfsmount *nmp = VFSTONFS(mp);
1208 * If a change from TCP->UDP is done and there are thread(s)
1209 * that have I/O RPC(s) in progress with a transfer size
1210 * greater than NFS_MAXDGRAMDATA, those thread(s) will be
1211 * hung, retrying the RPC(s) forever. Usually these threads
1212 * will be seen doing an uninterruptible sleep on wait channel
1215 if (args.sotype == SOCK_DGRAM && nmp->nm_sotype == SOCK_STREAM)
1216 tprintf(td->td_proc, LOG_WARNING,
1217 "Warning: mount -u that changes TCP->UDP can result in hung threads\n");
1220 * When doing an update, we can't change version,
1221 * security, switch lockd strategies, change cookie
1222 * translation or switch oneopenown.
1224 args.flags = (args.flags &
1231 NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)) |
1239 NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/));
1240 nfs_decode_args(mp, nmp, &args, NULL, td->td_ucred, td);
1245 * Make the nfs_ip_paranoia sysctl serve as the default connection
1246 * or no-connection mode for those protocols that support
1247 * no-connection mode (the flag will be cleared later for protocols
1248 * that do not support no-connection mode). This will allow a client
1249 * to receive replies from a different IP then the request was
1250 * sent to. Note: default value for nfs_ip_paranoia is 1 (paranoid),
1253 if (nfs_ip_paranoia == 0)
1254 args.flags |= NFSMNT_NOCONN;
1256 if (has_nfs_args_opt != 0) {
1258 * In the 'nfs_args' case, the pointers in the args
1259 * structure are in userland - we copy them in here.
1261 if (args.fhsize < 0 || args.fhsize > NFSX_V3FHMAX) {
1262 vfs_mount_error(mp, "Bad file handle");
1266 error = copyin((caddr_t)args.fh, (caddr_t)nfh,
1270 error = copyinstr(args.hostname, hst, MNAMELEN - 1, &hstlen);
1273 bzero(&hst[hstlen], MNAMELEN - hstlen);
1274 args.hostname = hst;
1275 /* getsockaddr() call must be after above copyin() calls */
1276 error = getsockaddr(&nam, args.addr, args.addrlen);
1279 } else if (nfs_mount_parse_from(mp->mnt_optnew,
1280 &args.hostname, (struct sockaddr_in **)&nam, dirpath,
1281 sizeof(dirpath), &dirlen) == 0) {
1282 has_nfs_from_opt = 1;
1283 bcopy(args.hostname, hst, MNAMELEN);
1284 hst[MNAMELEN - 1] = '\0';
1287 * This only works with NFSv4 for now.
1290 args.flags |= NFSMNT_NFSV4;
1291 args.sotype = SOCK_STREAM;
1293 if (vfs_getopt(mp->mnt_optnew, "fh", (void **)&args.fh,
1294 &args.fhsize) == 0) {
1295 if (args.fhsize < 0 || args.fhsize > NFSX_FHMAX) {
1296 vfs_mount_error(mp, "Bad file handle");
1300 bcopy(args.fh, nfh, args.fhsize);
1304 (void) vfs_getopt(mp->mnt_optnew, "hostname",
1305 (void **)&args.hostname, &len);
1306 if (args.hostname == NULL) {
1307 vfs_mount_error(mp, "Invalid hostname");
1311 if (len >= MNAMELEN) {
1312 vfs_mount_error(mp, "Hostname too long");
1316 bcopy(args.hostname, hst, len);
1320 if (vfs_getopt(mp->mnt_optnew, "principal", (void **)&name, NULL) == 0)
1321 strlcpy(srvkrbname, name, sizeof (srvkrbname));
1323 snprintf(srvkrbname, sizeof (srvkrbname), "nfs@%s", hst);
1324 cp = strchr(srvkrbname, ':');
1328 srvkrbnamelen = strlen(srvkrbname);
1330 if (vfs_getopt(mp->mnt_optnew, "gssname", (void **)&name, NULL) == 0)
1331 strlcpy(krbname, name, sizeof (krbname));
1334 krbnamelen = strlen(krbname);
1336 if (has_nfs_from_opt == 0) {
1337 if (vfs_getopt(mp->mnt_optnew,
1338 "dirpath", (void **)&name, NULL) == 0)
1339 strlcpy(dirpath, name, sizeof (dirpath));
1342 dirlen = strlen(dirpath);
1345 if (has_nfs_args_opt == 0 && has_nfs_from_opt == 0) {
1346 if (vfs_getopt(mp->mnt_optnew, "addr",
1347 (void **)&args.addr, &args.addrlen) == 0) {
1348 if (args.addrlen > SOCK_MAXADDRLEN) {
1349 error = ENAMETOOLONG;
1352 nam = malloc(args.addrlen, M_SONAME, M_WAITOK);
1353 bcopy(args.addr, nam, args.addrlen);
1354 nam->sa_len = args.addrlen;
1356 vfs_mount_error(mp, "No server address");
1363 error = mountnfs(&args, mp, nam, hst, krbname, krbnamelen, dirpath,
1364 dirlen, srvkrbname, srvkrbnamelen, &vp, td->td_ucred, td,
1365 nametimeo, negnametimeo, minvers, newflag, tlscertname);
1369 mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_NO_IOPF |
1371 if ((VFSTONFS(mp)->nm_flag & NFSMNT_NFSV4) != 0)
1372 mp->mnt_kern_flag |= MNTK_NULL_NOCACHE;
1383 * It seems a bit dumb to copyinstr() the host and path here and then
1384 * bcopy() them in mountnfs(), but I wanted to detect errors before
1385 * doing the getsockaddr() call because getsockaddr() allocates an mbuf and
1386 * an error after that means that I have to release the mbuf.
1390 nfs_cmount(struct mntarg *ma, void *data, uint64_t flags)
1393 struct nfs_args args;
1395 error = copyin(data, &args, sizeof (struct nfs_args));
1399 ma = mount_arg(ma, "nfs_args", &args, sizeof args);
1401 error = kernel_mount(ma, flags);
1406 * Common code for mount and mountroot
1409 mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
1410 char *hst, u_char *krbname, int krbnamelen, u_char *dirpath, int dirlen,
1411 u_char *srvkrbname, int srvkrbnamelen, struct vnode **vpp,
1412 struct ucred *cred, struct thread *td, int nametimeo, int negnametimeo,
1413 int minvers, uint32_t newflag, char *tlscertname)
1415 struct nfsmount *nmp;
1417 int error, trycnt, ret;
1418 struct nfsvattr nfsva;
1419 struct nfsclclient *clp;
1420 struct nfsclds *dsp, *tdsp;
1422 static u_int64_t clval = 0;
1427 NFSCL_DEBUG(3, "in mnt\n");
1429 if (mp->mnt_flag & MNT_UPDATE) {
1431 printf("%s: MNT_UPDATE is no longer handled here\n", __func__);
1432 free(nam, M_SONAME);
1433 free(tlscertname, M_NEWNFSMNT);
1436 /* NFS-over-TLS requires that rpctls be functioning. */
1437 if ((newflag & NFSMNT_TLS) != 0) {
1440 /* KERN_TLS is only supported for TCP. */
1441 if (argp->sotype == SOCK_STREAM &&
1442 rpctls_getinfo(&maxlen, true, false))
1446 free(nam, M_SONAME);
1447 free(tlscertname, M_NEWNFSMNT);
1451 nmp = malloc(sizeof (struct nfsmount) +
1452 krbnamelen + dirlen + srvkrbnamelen + 2,
1453 M_NEWNFSMNT, M_WAITOK | M_ZERO);
1454 nmp->nm_tlscertname = tlscertname;
1455 nmp->nm_newflag = newflag;
1456 TAILQ_INIT(&nmp->nm_bufq);
1457 TAILQ_INIT(&nmp->nm_sess);
1459 clval = (u_int64_t)nfsboottime.tv_sec;
1460 nmp->nm_clval = clval++;
1461 nmp->nm_krbnamelen = krbnamelen;
1462 nmp->nm_dirpathlen = dirlen;
1463 nmp->nm_srvkrbnamelen = srvkrbnamelen;
1464 if (td->td_ucred->cr_uid != (uid_t)0) {
1466 * nm_uid is used to get KerberosV credentials for
1467 * the nfsv4 state handling operations if there is
1468 * no host based principal set. Use the uid of
1469 * this user if not root, since they are doing the
1470 * mount. I don't think setting this for root will
1471 * work, since root normally does not have user
1472 * credentials in a credentials cache.
1474 nmp->nm_uid = td->td_ucred->cr_uid;
1477 * Just set to -1, so it won't be used.
1479 nmp->nm_uid = (uid_t)-1;
1482 /* Copy and null terminate all the names */
1483 if (nmp->nm_krbnamelen > 0) {
1484 bcopy(krbname, nmp->nm_krbname, nmp->nm_krbnamelen);
1485 nmp->nm_name[nmp->nm_krbnamelen] = '\0';
1487 if (nmp->nm_dirpathlen > 0) {
1488 bcopy(dirpath, NFSMNT_DIRPATH(nmp),
1489 nmp->nm_dirpathlen);
1490 nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen
1493 if (nmp->nm_srvkrbnamelen > 0) {
1494 bcopy(srvkrbname, NFSMNT_SRVKRBNAME(nmp),
1495 nmp->nm_srvkrbnamelen);
1496 nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen
1497 + nmp->nm_srvkrbnamelen + 2] = '\0';
1499 nmp->nm_sockreq.nr_cred = crhold(cred);
1500 mtx_init(&nmp->nm_sockreq.nr_mtx, "nfssock", NULL, MTX_DEF);
1502 nmp->nm_getinfo = nfs_getnlminfo;
1503 nmp->nm_vinvalbuf = ncl_vinvalbuf;
1506 nmp->nm_mountp = mp;
1507 mtx_init(&nmp->nm_mtx, "NFSmount lock", NULL, MTX_DEF | MTX_DUPOK);
1510 * Since nfs_decode_args() might optionally set them, these
1511 * need to be set to defaults before the call, so that the
1512 * optional settings aren't overwritten.
1514 nmp->nm_nametimeo = nametimeo;
1515 nmp->nm_negnametimeo = negnametimeo;
1516 nmp->nm_timeo = NFS_TIMEO;
1517 nmp->nm_retry = NFS_RETRANS;
1518 nmp->nm_readahead = NFS_DEFRAHEAD;
1520 /* This is empirical approximation of sqrt(hibufspace) * 256. */
1521 nmp->nm_wcommitsize = NFS_MAXBSIZE / 256;
1522 while ((long)nmp->nm_wcommitsize * nmp->nm_wcommitsize < hibufspace)
1523 nmp->nm_wcommitsize *= 2;
1524 nmp->nm_wcommitsize *= 256;
1526 if ((argp->flags & NFSMNT_NFSV4) != 0)
1527 nmp->nm_minorvers = minvers;
1529 nmp->nm_minorvers = 0;
1531 nfs_decode_args(mp, nmp, argp, hst, cred, td);
1534 * V2 can only handle 32 bit filesizes. A 4GB-1 limit may be too
1535 * high, depending on whether we end up with negative offsets in
1536 * the client or server somewhere. 2GB-1 may be safer.
1538 * For V3, ncl_fsinfo will adjust this as necessary. Assume maximum
1539 * that we can handle until we find out otherwise.
1541 if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0)
1542 nmp->nm_maxfilesize = 0xffffffffLL;
1544 nmp->nm_maxfilesize = OFF_MAX;
1546 if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) {
1547 nmp->nm_wsize = NFS_WSIZE;
1548 nmp->nm_rsize = NFS_RSIZE;
1549 nmp->nm_readdirsize = NFS_READDIRSIZE;
1551 nmp->nm_numgrps = NFS_MAXGRPS;
1552 nmp->nm_tprintf_delay = nfs_tprintf_delay;
1553 if (nmp->nm_tprintf_delay < 0)
1554 nmp->nm_tprintf_delay = 0;
1555 nmp->nm_tprintf_initial_delay = nfs_tprintf_initial_delay;
1556 if (nmp->nm_tprintf_initial_delay < 0)
1557 nmp->nm_tprintf_initial_delay = 0;
1558 nmp->nm_fhsize = argp->fhsize;
1559 if (nmp->nm_fhsize > 0)
1560 bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize);
1561 bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
1563 /* Set up the sockets and per-host congestion */
1564 nmp->nm_sotype = argp->sotype;
1565 nmp->nm_soproto = argp->proto;
1566 nmp->nm_sockreq.nr_prog = NFS_PROG;
1567 if ((argp->flags & NFSMNT_NFSV4))
1568 nmp->nm_sockreq.nr_vers = NFS_VER4;
1569 else if ((argp->flags & NFSMNT_NFSV3))
1570 nmp->nm_sockreq.nr_vers = NFS_VER3;
1572 nmp->nm_sockreq.nr_vers = NFS_VER2;
1574 if ((error = newnfs_connect(nmp, &nmp->nm_sockreq, cred, td, 0, false)))
1576 /* For NFSv4.1, get the clientid now. */
1577 if (nmp->nm_minorvers > 0) {
1578 NFSCL_DEBUG(3, "at getcl\n");
1579 error = nfscl_getcl(mp, cred, td, 0, &clp);
1580 NFSCL_DEBUG(3, "aft getcl=%d\n", error);
1585 if (nmp->nm_fhsize == 0 && (nmp->nm_flag & NFSMNT_NFSV4) &&
1586 nmp->nm_dirpathlen > 0) {
1587 NFSCL_DEBUG(3, "in dirp\n");
1589 * If the fhsize on the mount point == 0 for V4, the mount
1590 * path needs to be looked up.
1594 error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp),
1596 NFSCL_DEBUG(3, "aft dirp=%d\n", error);
1598 (void) nfs_catnap(PZERO, error, "nfsgetdirp");
1599 } while (error && --trycnt > 0);
1605 * A reference count is needed on the nfsnode representing the
1606 * remote root. If this object is not persistent, then backward
1607 * traversals of the mount point (i.e. "..") will not work if
1608 * the nfsnode gets flushed out of the cache. Ufs does not have
1609 * this problem, because one can identify root inodes by their
1610 * number == UFS_ROOTINO (2).
1612 if (nmp->nm_fhsize > 0) {
1614 * Set f_iosize to NFS_DIRBLKSIZ so that bo_bsize gets set
1615 * non-zero for the root vnode. f_iosize will be set correctly
1616 * by nfs_statfs() before any I/O occurs.
1618 mp->mnt_stat.f_iosize = NFS_DIRBLKSIZ;
1619 error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np,
1626 * Get file attributes and transfer parameters for the
1627 * mountpoint. This has the side effect of filling in
1628 * (*vpp)->v_type with the correct value.
1630 ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1,
1631 cred, td, &nfsva, NULL, &lease);
1634 * Just set default values to get things going.
1636 NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr));
1637 nfsva.na_vattr.va_type = VDIR;
1638 nfsva.na_vattr.va_mode = 0777;
1639 nfsva.na_vattr.va_nlink = 100;
1640 nfsva.na_vattr.va_uid = (uid_t)0;
1641 nfsva.na_vattr.va_gid = (gid_t)0;
1642 nfsva.na_vattr.va_fileid = 2;
1643 nfsva.na_vattr.va_gen = 1;
1644 nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE;
1645 nfsva.na_vattr.va_size = 512 * 1024;
1648 (void) nfscl_loadattrcache(vpp, &nfsva, NULL, NULL, 0, 1);
1649 if (nmp->nm_minorvers > 0) {
1650 NFSCL_DEBUG(3, "lease=%d\n", (int)lease);
1652 clp->nfsc_renew = NFSCL_RENEW(lease);
1653 clp->nfsc_expire = NFSD_MONOSEC + clp->nfsc_renew;
1654 clp->nfsc_clientidrev++;
1655 if (clp->nfsc_clientidrev == 0)
1656 clp->nfsc_clientidrev++;
1659 * Mount will succeed, so the renew thread can be
1662 nfscl_start_renewthread(clp);
1663 nfscl_clientrelease(clp);
1665 if (argp->flags & NFSMNT_NFSV3)
1666 ncl_fsinfo(nmp, *vpp, cred, td);
1668 /* Mark if the mount point supports NFSv4 ACLs. */
1669 if ((argp->flags & NFSMNT_NFSV4) != 0 && nfsrv_useacl != 0 &&
1671 NFSISSET_ATTRBIT(&nfsva.na_suppattr, NFSATTRBIT_ACL)) {
1673 mp->mnt_flag |= MNT_NFS4ACLS;
1678 * Lose the lock but keep the ref.
1681 vfs_cache_root_set(mp, *vpp);
1688 nfscl_clientrelease(clp);
1689 newnfs_disconnect(&nmp->nm_sockreq);
1690 crfree(nmp->nm_sockreq.nr_cred);
1691 if (nmp->nm_sockreq.nr_auth != NULL)
1692 AUTH_DESTROY(nmp->nm_sockreq.nr_auth);
1693 mtx_destroy(&nmp->nm_sockreq.nr_mtx);
1694 mtx_destroy(&nmp->nm_mtx);
1695 if (nmp->nm_clp != NULL) {
1697 LIST_REMOVE(nmp->nm_clp, nfsc_list);
1699 free(nmp->nm_clp, M_NFSCLCLIENT);
1701 TAILQ_FOREACH_SAFE(dsp, &nmp->nm_sess, nfsclds_list, tdsp) {
1702 if (dsp != TAILQ_FIRST(&nmp->nm_sess) &&
1703 dsp->nfsclds_sockp != NULL)
1704 newnfs_disconnect(dsp->nfsclds_sockp);
1705 nfscl_freenfsclds(dsp);
1707 free(nmp->nm_tlscertname, M_NEWNFSMNT);
1708 free(nmp, M_NEWNFSMNT);
1709 free(nam, M_SONAME);
1714 * unmount system call
1717 nfs_unmount(struct mount *mp, int mntflags)
1720 struct nfsmount *nmp;
1721 int error, flags = 0, i, trycnt = 0;
1722 struct nfsclds *dsp, *tdsp;
1726 if (mntflags & MNT_FORCE)
1727 flags |= FORCECLOSE;
1731 * Goes something like this..
1732 * - Call vflush() to clear out vnodes for this filesystem
1733 * - Close the socket
1734 * - Free up the data structures
1736 /* In the forced case, cancel any outstanding requests. */
1737 if (mntflags & MNT_FORCE) {
1739 if (nfsv4_findmirror(nmp) != NULL)
1744 error = newnfs_nmcancelreqs(nmp);
1747 /* For a forced close, get rid of the renew thread now */
1748 nfscl_umount(nmp, td);
1750 /* We hold 1 extra ref on the root vnode; see comment in mountnfs(). */
1752 error = vflush(mp, 1, flags, td);
1753 if ((mntflags & MNT_FORCE) && error != 0 && ++trycnt < 30)
1754 (void) nfs_catnap(PSOCK, error, "newndm");
1755 } while ((mntflags & MNT_FORCE) && error != 0 && trycnt < 30);
1760 * We are now committed to the unmount.
1762 if ((mntflags & MNT_FORCE) == 0)
1763 nfscl_umount(nmp, td);
1765 mtx_lock(&nmp->nm_mtx);
1766 nmp->nm_privflag |= NFSMNTP_FORCEDISM;
1767 mtx_unlock(&nmp->nm_mtx);
1769 /* Make sure no nfsiods are assigned to this mount. */
1771 for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
1772 if (ncl_iodmount[i] == nmp) {
1773 ncl_iodwant[i] = NFSIOD_AVAILABLE;
1774 ncl_iodmount[i] = NULL;
1779 * We can now set mnt_data to NULL and wait for
1780 * nfssvc(NFSSVC_FORCEDISM) to complete.
1782 mtx_lock(&mountlist_mtx);
1783 mtx_lock(&nmp->nm_mtx);
1784 mp->mnt_data = NULL;
1785 mtx_unlock(&mountlist_mtx);
1786 while ((nmp->nm_privflag & NFSMNTP_CANCELRPCS) != 0)
1787 msleep(nmp, &nmp->nm_mtx, PVFS, "nfsfdism", 0);
1788 mtx_unlock(&nmp->nm_mtx);
1790 newnfs_disconnect(&nmp->nm_sockreq);
1791 crfree(nmp->nm_sockreq.nr_cred);
1792 free(nmp->nm_nam, M_SONAME);
1793 if (nmp->nm_sockreq.nr_auth != NULL)
1794 AUTH_DESTROY(nmp->nm_sockreq.nr_auth);
1795 mtx_destroy(&nmp->nm_sockreq.nr_mtx);
1796 mtx_destroy(&nmp->nm_mtx);
1797 TAILQ_FOREACH_SAFE(dsp, &nmp->nm_sess, nfsclds_list, tdsp) {
1798 if (dsp != TAILQ_FIRST(&nmp->nm_sess) &&
1799 dsp->nfsclds_sockp != NULL)
1800 newnfs_disconnect(dsp->nfsclds_sockp);
1801 nfscl_freenfsclds(dsp);
1803 free(nmp->nm_tlscertname, M_NEWNFSMNT);
1804 free(nmp, M_NEWNFSMNT);
1810 * Return root of a filesystem
1813 nfs_root(struct mount *mp, int flags, struct vnode **vpp)
1816 struct nfsmount *nmp;
1821 error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, flags);
1826 * Get transfer parameters and attributes for root vnode once.
1828 mtx_lock(&nmp->nm_mtx);
1829 if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) {
1830 mtx_unlock(&nmp->nm_mtx);
1831 ncl_fsinfo(nmp, vp, curthread->td_ucred, curthread);
1833 mtx_unlock(&nmp->nm_mtx);
1834 if (vp->v_type == VNON)
1836 vp->v_vflag |= VV_ROOT;
1842 * Flush out the buffer cache
1846 nfs_sync(struct mount *mp, int waitfor)
1848 struct vnode *vp, *mvp;
1850 int error, allerror = 0;
1856 * If a forced dismount is in progress, return from here so that
1857 * the umount(2) syscall doesn't get stuck in VFS_SYNC() before
1858 * calling VFS_UNMOUNT().
1860 if (NFSCL_FORCEDISM(mp)) {
1867 * Force stale buffer cache information to be flushed.
1870 MNT_VNODE_FOREACH_ALL(vp, mp, mvp) {
1871 /* XXX Racy bv_cnt check. */
1872 if (NFSVOPISLOCKED(vp) || vp->v_bufobj.bo_dirty.bv_cnt == 0 ||
1873 waitfor == MNT_LAZY) {
1877 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK)) {
1878 MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp);
1881 error = VOP_FSYNC(vp, waitfor, td);
1891 nfs_sysctl(struct mount *mp, fsctlop_t op, struct sysctl_req *req)
1893 struct nfsmount *nmp = VFSTONFS(mp);
1897 bzero(&vq, sizeof(vq));
1900 case VFS_CTL_NOLOCKS:
1901 val = (nmp->nm_flag & NFSMNT_NOLOCKS) ? 1 : 0;
1902 if (req->oldptr != NULL) {
1903 error = SYSCTL_OUT(req, &val, sizeof(val));
1907 if (req->newptr != NULL) {
1908 error = SYSCTL_IN(req, &val, sizeof(val));
1912 nmp->nm_flag |= NFSMNT_NOLOCKS;
1914 nmp->nm_flag &= ~NFSMNT_NOLOCKS;
1919 mtx_lock(&nmp->nm_mtx);
1920 if (nmp->nm_state & NFSSTA_TIMEO)
1921 vq.vq_flags |= VQ_NOTRESP;
1922 mtx_unlock(&nmp->nm_mtx);
1924 if (!(nmp->nm_flag & NFSMNT_NOLOCKS) &&
1925 (nmp->nm_state & NFSSTA_LOCKTIMEO))
1926 vq.vq_flags |= VQ_NOTRESPLOCK;
1928 error = SYSCTL_OUT(req, &vq, sizeof(vq));
1931 if (req->oldptr != NULL) {
1932 error = SYSCTL_OUT(req, &nmp->nm_tprintf_initial_delay,
1933 sizeof(nmp->nm_tprintf_initial_delay));
1937 if (req->newptr != NULL) {
1938 error = vfs_suser(mp, req->td);
1941 error = SYSCTL_IN(req, &nmp->nm_tprintf_initial_delay,
1942 sizeof(nmp->nm_tprintf_initial_delay));
1945 if (nmp->nm_tprintf_initial_delay < 0)
1946 nmp->nm_tprintf_initial_delay = 0;
1956 * Purge any RPCs in progress, so that they will all return errors.
1957 * This allows dounmount() to continue as far as VFS_UNMOUNT() for a
1961 nfs_purge(struct mount *mp)
1963 struct nfsmount *nmp = VFSTONFS(mp);
1965 newnfs_nmcancelreqs(nmp);
1969 * Extract the information needed by the nlm from the nfs vnode.
1972 nfs_getnlminfo(struct vnode *vp, uint8_t *fhp, size_t *fhlenp,
1973 struct sockaddr_storage *sp, int *is_v3p, off_t *sizep,
1974 struct timeval *timeop)
1976 struct nfsmount *nmp;
1977 struct nfsnode *np = VTONFS(vp);
1979 nmp = VFSTONFS(vp->v_mount);
1981 *fhlenp = (size_t)np->n_fhp->nfh_len;
1983 bcopy(np->n_fhp->nfh_fh, fhp, np->n_fhp->nfh_len);
1985 bcopy(nmp->nm_nam, sp, min(nmp->nm_nam->sa_len, sizeof(*sp)));
1987 *is_v3p = NFS_ISV3(vp);
1989 *sizep = np->n_size;
1990 if (timeop != NULL) {
1991 timeop->tv_sec = nmp->nm_timeo / NFS_HZ;
1992 timeop->tv_usec = (nmp->nm_timeo % NFS_HZ) * (1000000 / NFS_HZ);
1997 * This function prints out an option name, based on the conditional
2000 static __inline void nfscl_printopt(struct nfsmount *nmp, int testval,
2001 char *opt, char **buf, size_t *blen)
2005 if (testval != 0 && *blen > strlen(opt)) {
2006 len = snprintf(*buf, *blen, "%s", opt);
2007 if (len != strlen(opt))
2015 * This function printf out an options integer value.
2017 static __inline void nfscl_printoptval(struct nfsmount *nmp, int optval,
2018 char *opt, char **buf, size_t *blen)
2022 if (*blen > strlen(opt) + 1) {
2023 /* Could result in truncated output string. */
2024 len = snprintf(*buf, *blen, "%s=%d", opt, optval);
2033 * Load the option flags and values into the buffer.
2035 void nfscl_retopts(struct nfsmount *nmp, char *buffer, size_t buflen)
2042 nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NFSV4) != 0, "nfsv4", &buf,
2044 if ((nmp->nm_flag & NFSMNT_NFSV4) != 0) {
2045 nfscl_printoptval(nmp, nmp->nm_minorvers, ",minorversion", &buf,
2047 nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_PNFS) != 0, ",pnfs",
2049 nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_ONEOPENOWN) != 0 &&
2050 nmp->nm_minorvers > 0, ",oneopenown", &buf, &blen);
2052 nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NFSV3) != 0, "nfsv3", &buf,
2054 nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0,
2055 "nfsv2", &buf, &blen);
2056 nfscl_printopt(nmp, nmp->nm_sotype == SOCK_STREAM, ",tcp", &buf, &blen);
2057 nfscl_printopt(nmp, nmp->nm_sotype != SOCK_STREAM, ",udp", &buf, &blen);
2058 nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_RESVPORT) != 0, ",resvport",
2060 nfscl_printopt(nmp, (nmp->nm_newflag & NFSMNT_TLS) != 0, ",tls", &buf,
2062 nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCONN) != 0, ",noconn",
2064 nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_SOFT) == 0, ",hard", &buf,
2066 nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_SOFT) != 0, ",soft", &buf,
2068 nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_INT) != 0, ",intr", &buf,
2070 nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCTO) == 0, ",cto", &buf,
2072 nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCTO) != 0, ",nocto", &buf,
2074 nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NONCONTIGWR) != 0,
2075 ",noncontigwr", &buf, &blen);
2076 nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_NOLOCKD | NFSMNT_NFSV4)) ==
2077 0, ",lockd", &buf, &blen);
2078 nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_NOLOCKD | NFSMNT_NFSV4)) ==
2079 NFSMNT_NOLOCKD, ",nolockd", &buf, &blen);
2080 nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_RDIRPLUS) != 0, ",rdirplus",
2082 nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_KERB) == 0, ",sec=sys",
2084 nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY |
2085 NFSMNT_PRIVACY)) == NFSMNT_KERB, ",sec=krb5", &buf, &blen);
2086 nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY |
2087 NFSMNT_PRIVACY)) == (NFSMNT_KERB | NFSMNT_INTEGRITY), ",sec=krb5i",
2089 nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY |
2090 NFSMNT_PRIVACY)) == (NFSMNT_KERB | NFSMNT_PRIVACY), ",sec=krb5p",
2092 nfscl_printoptval(nmp, nmp->nm_acdirmin, ",acdirmin", &buf, &blen);
2093 nfscl_printoptval(nmp, nmp->nm_acdirmax, ",acdirmax", &buf, &blen);
2094 nfscl_printoptval(nmp, nmp->nm_acregmin, ",acregmin", &buf, &blen);
2095 nfscl_printoptval(nmp, nmp->nm_acregmax, ",acregmax", &buf, &blen);
2096 nfscl_printoptval(nmp, nmp->nm_nametimeo, ",nametimeo", &buf, &blen);
2097 nfscl_printoptval(nmp, nmp->nm_negnametimeo, ",negnametimeo", &buf,
2099 nfscl_printoptval(nmp, nmp->nm_rsize, ",rsize", &buf, &blen);
2100 nfscl_printoptval(nmp, nmp->nm_wsize, ",wsize", &buf, &blen);
2101 nfscl_printoptval(nmp, nmp->nm_readdirsize, ",readdirsize", &buf,
2103 nfscl_printoptval(nmp, nmp->nm_readahead, ",readahead", &buf, &blen);
2104 nfscl_printoptval(nmp, nmp->nm_wcommitsize, ",wcommitsize", &buf,
2106 nfscl_printoptval(nmp, nmp->nm_timeo, ",timeout", &buf, &blen);
2107 nfscl_printoptval(nmp, nmp->nm_retry, ",retrans", &buf, &blen);