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 *, int);
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)) != 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, &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, &nmp->nm_sockreq.nr_client)) {
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", "nconnect",
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;
907 has_nfs_args_opt = 0;
908 has_nfs_from_opt = 0;
911 hst = malloc(MNAMELEN, M_TEMP, M_WAITOK);
912 if (vfs_filteropt(mp->mnt_optnew, nfs_opts)) {
918 if ((mp->mnt_flag & (MNT_ROOTFS | MNT_UPDATE)) == MNT_ROOTFS &&
919 nfs_diskless_valid != 0) {
920 error = nfs_mountroot(mp);
927 * The old mount_nfs program passed the struct nfs_args
928 * from userspace to kernel. The new mount_nfs program
929 * passes string options via nmount() from userspace to kernel
930 * and we populate the struct nfs_args in the kernel.
932 if (vfs_getopt(mp->mnt_optnew, "nfs_args", NULL, NULL) == 0) {
933 error = vfs_copyopt(mp->mnt_optnew, "nfs_args", &args,
938 if (args.version != NFS_ARGSVERSION) {
939 error = EPROGMISMATCH;
942 has_nfs_args_opt = 1;
945 /* Handle the new style options. */
946 if (vfs_getopt(mp->mnt_optnew, "noac", NULL, NULL) == 0) {
947 args.acdirmin = args.acdirmax =
948 args.acregmin = args.acregmax = 0;
949 args.flags |= NFSMNT_ACDIRMIN | NFSMNT_ACDIRMAX |
950 NFSMNT_ACREGMIN | NFSMNT_ACREGMAX;
952 if (vfs_getopt(mp->mnt_optnew, "noconn", NULL, NULL) == 0)
953 args.flags |= NFSMNT_NOCONN;
954 if (vfs_getopt(mp->mnt_optnew, "conn", NULL, NULL) == 0)
955 args.flags &= ~NFSMNT_NOCONN;
956 if (vfs_getopt(mp->mnt_optnew, "nolockd", NULL, NULL) == 0)
957 args.flags |= NFSMNT_NOLOCKD;
958 if (vfs_getopt(mp->mnt_optnew, "lockd", NULL, NULL) == 0)
959 args.flags &= ~NFSMNT_NOLOCKD;
960 if (vfs_getopt(mp->mnt_optnew, "intr", NULL, NULL) == 0)
961 args.flags |= NFSMNT_INT;
962 if (vfs_getopt(mp->mnt_optnew, "rdirplus", NULL, NULL) == 0)
963 args.flags |= NFSMNT_RDIRPLUS;
964 if (vfs_getopt(mp->mnt_optnew, "resvport", NULL, NULL) == 0)
965 args.flags |= NFSMNT_RESVPORT;
966 if (vfs_getopt(mp->mnt_optnew, "noresvport", NULL, NULL) == 0)
967 args.flags &= ~NFSMNT_RESVPORT;
968 if (vfs_getopt(mp->mnt_optnew, "soft", NULL, NULL) == 0)
969 args.flags |= NFSMNT_SOFT;
970 if (vfs_getopt(mp->mnt_optnew, "hard", NULL, NULL) == 0)
971 args.flags &= ~NFSMNT_SOFT;
972 if (vfs_getopt(mp->mnt_optnew, "mntudp", NULL, NULL) == 0)
973 args.sotype = SOCK_DGRAM;
974 if (vfs_getopt(mp->mnt_optnew, "udp", NULL, NULL) == 0)
975 args.sotype = SOCK_DGRAM;
976 if (vfs_getopt(mp->mnt_optnew, "tcp", NULL, NULL) == 0)
977 args.sotype = SOCK_STREAM;
978 if (vfs_getopt(mp->mnt_optnew, "nfsv3", NULL, NULL) == 0)
979 args.flags |= NFSMNT_NFSV3;
980 if (vfs_getopt(mp->mnt_optnew, "nfsv4", NULL, NULL) == 0) {
981 args.flags |= NFSMNT_NFSV4;
982 args.sotype = SOCK_STREAM;
984 if (vfs_getopt(mp->mnt_optnew, "allgssname", NULL, NULL) == 0)
985 args.flags |= NFSMNT_ALLGSSNAME;
986 if (vfs_getopt(mp->mnt_optnew, "nocto", NULL, NULL) == 0)
987 args.flags |= NFSMNT_NOCTO;
988 if (vfs_getopt(mp->mnt_optnew, "noncontigwr", NULL, NULL) == 0)
989 args.flags |= NFSMNT_NONCONTIGWR;
990 if (vfs_getopt(mp->mnt_optnew, "pnfs", NULL, NULL) == 0)
991 args.flags |= NFSMNT_PNFS;
992 if (vfs_getopt(mp->mnt_optnew, "oneopenown", NULL, NULL) == 0)
993 args.flags |= NFSMNT_ONEOPENOWN;
994 if (vfs_getopt(mp->mnt_optnew, "tls", NULL, NULL) == 0)
995 newflag |= NFSMNT_TLS;
996 if (vfs_getopt(mp->mnt_optnew, "tlscertname", (void **)&opt, &len) ==
999 * tlscertname with "key.pem" appended to it forms a file
1000 * name. As such, the maximum allowable strlen(tlscertname) is
1001 * NAME_MAX - 7. However, "len" includes the nul termination
1002 * byte so it can be up to NAME_MAX - 6.
1004 if (opt == NULL || len <= 1 || len > NAME_MAX - 6) {
1005 vfs_mount_error(mp, "invalid tlscertname");
1009 tlscertname = malloc(len, M_NEWNFSMNT, M_WAITOK);
1010 strlcpy(tlscertname, opt, len);
1012 if (vfs_getopt(mp->mnt_optnew, "readdirsize", (void **)&opt, NULL) == 0) {
1014 vfs_mount_error(mp, "illegal readdirsize");
1018 ret = sscanf(opt, "%d", &args.readdirsize);
1019 if (ret != 1 || args.readdirsize <= 0) {
1020 vfs_mount_error(mp, "illegal readdirsize: %s",
1025 args.flags |= NFSMNT_READDIRSIZE;
1027 if (vfs_getopt(mp->mnt_optnew, "readahead", (void **)&opt, NULL) == 0) {
1029 vfs_mount_error(mp, "illegal readahead");
1033 ret = sscanf(opt, "%d", &args.readahead);
1034 if (ret != 1 || args.readahead <= 0) {
1035 vfs_mount_error(mp, "illegal readahead: %s",
1040 args.flags |= NFSMNT_READAHEAD;
1042 if (vfs_getopt(mp->mnt_optnew, "wsize", (void **)&opt, NULL) == 0) {
1044 vfs_mount_error(mp, "illegal wsize");
1048 ret = sscanf(opt, "%d", &args.wsize);
1049 if (ret != 1 || args.wsize <= 0) {
1050 vfs_mount_error(mp, "illegal wsize: %s",
1055 args.flags |= NFSMNT_WSIZE;
1057 if (vfs_getopt(mp->mnt_optnew, "rsize", (void **)&opt, NULL) == 0) {
1059 vfs_mount_error(mp, "illegal rsize");
1063 ret = sscanf(opt, "%d", &args.rsize);
1064 if (ret != 1 || args.rsize <= 0) {
1065 vfs_mount_error(mp, "illegal wsize: %s",
1070 args.flags |= NFSMNT_RSIZE;
1072 if (vfs_getopt(mp->mnt_optnew, "retrans", (void **)&opt, NULL) == 0) {
1074 vfs_mount_error(mp, "illegal retrans");
1078 ret = sscanf(opt, "%d", &args.retrans);
1079 if (ret != 1 || args.retrans <= 0) {
1080 vfs_mount_error(mp, "illegal retrans: %s",
1085 args.flags |= NFSMNT_RETRANS;
1087 if (vfs_getopt(mp->mnt_optnew, "actimeo", (void **)&opt, NULL) == 0) {
1088 ret = sscanf(opt, "%d", &args.acregmin);
1089 if (ret != 1 || args.acregmin < 0) {
1090 vfs_mount_error(mp, "illegal actimeo: %s",
1095 args.acdirmin = args.acdirmax = args.acregmax = args.acregmin;
1096 args.flags |= NFSMNT_ACDIRMIN | NFSMNT_ACDIRMAX |
1097 NFSMNT_ACREGMIN | NFSMNT_ACREGMAX;
1099 if (vfs_getopt(mp->mnt_optnew, "acregmin", (void **)&opt, NULL) == 0) {
1100 ret = sscanf(opt, "%d", &args.acregmin);
1101 if (ret != 1 || args.acregmin < 0) {
1102 vfs_mount_error(mp, "illegal acregmin: %s",
1107 args.flags |= NFSMNT_ACREGMIN;
1109 if (vfs_getopt(mp->mnt_optnew, "acregmax", (void **)&opt, NULL) == 0) {
1110 ret = sscanf(opt, "%d", &args.acregmax);
1111 if (ret != 1 || args.acregmax < 0) {
1112 vfs_mount_error(mp, "illegal acregmax: %s",
1117 args.flags |= NFSMNT_ACREGMAX;
1119 if (vfs_getopt(mp->mnt_optnew, "acdirmin", (void **)&opt, NULL) == 0) {
1120 ret = sscanf(opt, "%d", &args.acdirmin);
1121 if (ret != 1 || args.acdirmin < 0) {
1122 vfs_mount_error(mp, "illegal acdirmin: %s",
1127 args.flags |= NFSMNT_ACDIRMIN;
1129 if (vfs_getopt(mp->mnt_optnew, "acdirmax", (void **)&opt, NULL) == 0) {
1130 ret = sscanf(opt, "%d", &args.acdirmax);
1131 if (ret != 1 || args.acdirmax < 0) {
1132 vfs_mount_error(mp, "illegal acdirmax: %s",
1137 args.flags |= NFSMNT_ACDIRMAX;
1139 if (vfs_getopt(mp->mnt_optnew, "wcommitsize", (void **)&opt, NULL) == 0) {
1140 ret = sscanf(opt, "%d", &args.wcommitsize);
1141 if (ret != 1 || args.wcommitsize < 0) {
1142 vfs_mount_error(mp, "illegal wcommitsize: %s", opt);
1146 args.flags |= NFSMNT_WCOMMITSIZE;
1148 if (vfs_getopt(mp->mnt_optnew, "timeo", (void **)&opt, NULL) == 0) {
1149 ret = sscanf(opt, "%d", &args.timeo);
1150 if (ret != 1 || args.timeo <= 0) {
1151 vfs_mount_error(mp, "illegal timeo: %s",
1156 args.flags |= NFSMNT_TIMEO;
1158 if (vfs_getopt(mp->mnt_optnew, "timeout", (void **)&opt, NULL) == 0) {
1159 ret = sscanf(opt, "%d", &args.timeo);
1160 if (ret != 1 || args.timeo <= 0) {
1161 vfs_mount_error(mp, "illegal timeout: %s",
1166 args.flags |= NFSMNT_TIMEO;
1168 if (vfs_getopt(mp->mnt_optnew, "nametimeo", (void **)&opt, NULL) == 0) {
1169 ret = sscanf(opt, "%d", &nametimeo);
1170 if (ret != 1 || nametimeo < 0) {
1171 vfs_mount_error(mp, "illegal nametimeo: %s", opt);
1176 if (vfs_getopt(mp->mnt_optnew, "negnametimeo", (void **)&opt, NULL)
1178 ret = sscanf(opt, "%d", &negnametimeo);
1179 if (ret != 1 || negnametimeo < 0) {
1180 vfs_mount_error(mp, "illegal negnametimeo: %s",
1186 if (vfs_getopt(mp->mnt_optnew, "minorversion", (void **)&opt, NULL) ==
1188 ret = sscanf(opt, "%d", &minvers);
1189 if (ret != 1 || minvers < 0 || minvers > 2 ||
1190 (args.flags & NFSMNT_NFSV4) == 0) {
1191 vfs_mount_error(mp, "illegal minorversion: %s", opt);
1196 if (vfs_getopt(mp->mnt_optnew, "nconnect", (void **)&opt, NULL) ==
1198 ret = sscanf(opt, "%d", &aconn);
1199 if (ret != 1 || aconn < 1 || aconn > NFS_MAXNCONN) {
1200 vfs_mount_error(mp, "illegal nconnect: %s", opt);
1205 * Setting nconnect=1 is a no-op, allowed so that
1206 * the option can be used in a Linux compatible way.
1210 if (vfs_getopt(mp->mnt_optnew, "sec",
1211 (void **) &secname, NULL) == 0)
1212 nfs_sec_name(secname, &args.flags);
1214 if (mp->mnt_flag & MNT_UPDATE) {
1215 struct nfsmount *nmp = VFSTONFS(mp);
1223 * If a change from TCP->UDP is done and there are thread(s)
1224 * that have I/O RPC(s) in progress with a transfer size
1225 * greater than NFS_MAXDGRAMDATA, those thread(s) will be
1226 * hung, retrying the RPC(s) forever. Usually these threads
1227 * will be seen doing an uninterruptible sleep on wait channel
1230 if (args.sotype == SOCK_DGRAM && nmp->nm_sotype == SOCK_STREAM)
1231 tprintf(td->td_proc, LOG_WARNING,
1232 "Warning: mount -u that changes TCP->UDP can result in hung threads\n");
1235 * When doing an update, we can't change version,
1236 * security, switch lockd strategies, change cookie
1237 * translation or switch oneopenown.
1239 args.flags = (args.flags &
1246 NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)) |
1254 NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/));
1255 nfs_decode_args(mp, nmp, &args, NULL, td->td_ucred, td);
1260 * Make the nfs_ip_paranoia sysctl serve as the default connection
1261 * or no-connection mode for those protocols that support
1262 * no-connection mode (the flag will be cleared later for protocols
1263 * that do not support no-connection mode). This will allow a client
1264 * to receive replies from a different IP then the request was
1265 * sent to. Note: default value for nfs_ip_paranoia is 1 (paranoid),
1268 if (nfs_ip_paranoia == 0)
1269 args.flags |= NFSMNT_NOCONN;
1271 if (has_nfs_args_opt != 0) {
1273 * In the 'nfs_args' case, the pointers in the args
1274 * structure are in userland - we copy them in here.
1276 if (args.fhsize < 0 || args.fhsize > NFSX_V3FHMAX) {
1277 vfs_mount_error(mp, "Bad file handle");
1281 error = copyin((caddr_t)args.fh, (caddr_t)nfh,
1285 error = copyinstr(args.hostname, hst, MNAMELEN - 1, &hstlen);
1288 bzero(&hst[hstlen], MNAMELEN - hstlen);
1289 args.hostname = hst;
1290 /* getsockaddr() call must be after above copyin() calls */
1291 error = getsockaddr(&nam, args.addr, args.addrlen);
1294 } else if (nfs_mount_parse_from(mp->mnt_optnew,
1295 &args.hostname, (struct sockaddr_in **)&nam, dirpath,
1296 sizeof(dirpath), &dirlen) == 0) {
1297 has_nfs_from_opt = 1;
1298 bcopy(args.hostname, hst, MNAMELEN);
1299 hst[MNAMELEN - 1] = '\0';
1302 * This only works with NFSv4 for now.
1305 args.flags |= NFSMNT_NFSV4;
1306 args.sotype = SOCK_STREAM;
1308 if (vfs_getopt(mp->mnt_optnew, "fh", (void **)&args.fh,
1309 &args.fhsize) == 0) {
1310 if (args.fhsize < 0 || args.fhsize > NFSX_FHMAX) {
1311 vfs_mount_error(mp, "Bad file handle");
1315 bcopy(args.fh, nfh, args.fhsize);
1319 (void) vfs_getopt(mp->mnt_optnew, "hostname",
1320 (void **)&args.hostname, &len);
1321 if (args.hostname == NULL) {
1322 vfs_mount_error(mp, "Invalid hostname");
1326 if (len >= MNAMELEN) {
1327 vfs_mount_error(mp, "Hostname too long");
1331 bcopy(args.hostname, hst, len);
1335 if (vfs_getopt(mp->mnt_optnew, "principal", (void **)&name, NULL) == 0)
1336 strlcpy(srvkrbname, name, sizeof (srvkrbname));
1338 snprintf(srvkrbname, sizeof (srvkrbname), "nfs@%s", hst);
1339 cp = strchr(srvkrbname, ':');
1343 srvkrbnamelen = strlen(srvkrbname);
1345 if (vfs_getopt(mp->mnt_optnew, "gssname", (void **)&name, NULL) == 0)
1346 strlcpy(krbname, name, sizeof (krbname));
1349 krbnamelen = strlen(krbname);
1351 if (has_nfs_from_opt == 0) {
1352 if (vfs_getopt(mp->mnt_optnew,
1353 "dirpath", (void **)&name, NULL) == 0)
1354 strlcpy(dirpath, name, sizeof (dirpath));
1357 dirlen = strlen(dirpath);
1360 if (has_nfs_args_opt == 0 && has_nfs_from_opt == 0) {
1361 if (vfs_getopt(mp->mnt_optnew, "addr",
1362 (void **)&args.addr, &args.addrlen) == 0) {
1363 if (args.addrlen > SOCK_MAXADDRLEN) {
1364 error = ENAMETOOLONG;
1367 nam = malloc(args.addrlen, M_SONAME, M_WAITOK);
1368 bcopy(args.addr, nam, args.addrlen);
1369 nam->sa_len = args.addrlen;
1371 vfs_mount_error(mp, "No server address");
1377 if (aconn > 0 && (args.sotype != SOCK_STREAM ||
1378 (args.flags & NFSMNT_NFSV4) == 0 || minvers == 0)) {
1380 * RFC 5661 requires that an NFSv4.1/4.2 server
1381 * send an RPC reply on the same TCP connection
1382 * as the one it received the request on.
1383 * This property in required for "nconnect" and
1384 * might not be the case for NFSv3 or NFSv4.0 servers.
1386 vfs_mount_error(mp, "nconnect should only be used "
1387 "for NFSv4.1/4.2 mounts");
1393 error = mountnfs(&args, mp, nam, hst, krbname, krbnamelen, dirpath,
1394 dirlen, srvkrbname, srvkrbnamelen, &vp, td->td_ucred, td,
1395 nametimeo, negnametimeo, minvers, newflag, tlscertname, aconn);
1399 mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_NO_IOPF |
1401 if ((VFSTONFS(mp)->nm_flag & NFSMNT_NFSV4) != 0)
1402 mp->mnt_kern_flag |= MNTK_NULL_NOCACHE;
1413 * It seems a bit dumb to copyinstr() the host and path here and then
1414 * bcopy() them in mountnfs(), but I wanted to detect errors before
1415 * doing the getsockaddr() call because getsockaddr() allocates an mbuf and
1416 * an error after that means that I have to release the mbuf.
1420 nfs_cmount(struct mntarg *ma, void *data, uint64_t flags)
1423 struct nfs_args args;
1425 error = copyin(data, &args, sizeof (struct nfs_args));
1429 ma = mount_arg(ma, "nfs_args", &args, sizeof args);
1431 error = kernel_mount(ma, flags);
1436 * Common code for mount and mountroot
1439 mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
1440 char *hst, u_char *krbname, int krbnamelen, u_char *dirpath, int dirlen,
1441 u_char *srvkrbname, int srvkrbnamelen, struct vnode **vpp,
1442 struct ucred *cred, struct thread *td, int nametimeo, int negnametimeo,
1443 int minvers, uint32_t newflag, char *tlscertname, int aconn)
1445 struct nfsmount *nmp;
1447 int error, trycnt, ret;
1448 struct nfsvattr nfsva;
1449 struct nfsclclient *clp;
1450 struct nfsclds *dsp, *tdsp;
1453 static u_int64_t clval = 0;
1458 NFSCL_DEBUG(3, "in mnt\n");
1460 if (mp->mnt_flag & MNT_UPDATE) {
1462 printf("%s: MNT_UPDATE is no longer handled here\n", __func__);
1463 free(nam, M_SONAME);
1464 free(tlscertname, M_NEWNFSMNT);
1467 /* NFS-over-TLS requires that rpctls be functioning. */
1468 if ((newflag & NFSMNT_TLS) != 0) {
1471 /* KERN_TLS is only supported for TCP. */
1472 if (argp->sotype == SOCK_STREAM &&
1473 rpctls_getinfo(&maxlen, true, false))
1477 free(nam, M_SONAME);
1478 free(tlscertname, M_NEWNFSMNT);
1482 nmp = malloc(sizeof (struct nfsmount) +
1483 krbnamelen + dirlen + srvkrbnamelen + 2,
1484 M_NEWNFSMNT, M_WAITOK | M_ZERO);
1485 nmp->nm_tlscertname = tlscertname;
1486 nmp->nm_newflag = newflag;
1487 TAILQ_INIT(&nmp->nm_bufq);
1488 TAILQ_INIT(&nmp->nm_sess);
1490 clval = (u_int64_t)nfsboottime.tv_sec;
1491 nmp->nm_clval = clval++;
1492 nmp->nm_krbnamelen = krbnamelen;
1493 nmp->nm_dirpathlen = dirlen;
1494 nmp->nm_srvkrbnamelen = srvkrbnamelen;
1495 if (td->td_ucred->cr_uid != (uid_t)0) {
1497 * nm_uid is used to get KerberosV credentials for
1498 * the nfsv4 state handling operations if there is
1499 * no host based principal set. Use the uid of
1500 * this user if not root, since they are doing the
1501 * mount. I don't think setting this for root will
1502 * work, since root normally does not have user
1503 * credentials in a credentials cache.
1505 nmp->nm_uid = td->td_ucred->cr_uid;
1508 * Just set to -1, so it won't be used.
1510 nmp->nm_uid = (uid_t)-1;
1513 /* Copy and null terminate all the names */
1514 if (nmp->nm_krbnamelen > 0) {
1515 bcopy(krbname, nmp->nm_krbname, nmp->nm_krbnamelen);
1516 nmp->nm_name[nmp->nm_krbnamelen] = '\0';
1518 if (nmp->nm_dirpathlen > 0) {
1519 bcopy(dirpath, NFSMNT_DIRPATH(nmp),
1520 nmp->nm_dirpathlen);
1521 nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen
1524 if (nmp->nm_srvkrbnamelen > 0) {
1525 bcopy(srvkrbname, NFSMNT_SRVKRBNAME(nmp),
1526 nmp->nm_srvkrbnamelen);
1527 nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen
1528 + nmp->nm_srvkrbnamelen + 2] = '\0';
1530 nmp->nm_sockreq.nr_cred = crhold(cred);
1531 mtx_init(&nmp->nm_sockreq.nr_mtx, "nfssock", NULL, MTX_DEF);
1533 nmp->nm_getinfo = nfs_getnlminfo;
1534 nmp->nm_vinvalbuf = ncl_vinvalbuf;
1537 nmp->nm_mountp = mp;
1538 mtx_init(&nmp->nm_mtx, "NFSmount lock", NULL, MTX_DEF | MTX_DUPOK);
1541 * Since nfs_decode_args() might optionally set them, these
1542 * need to be set to defaults before the call, so that the
1543 * optional settings aren't overwritten.
1545 nmp->nm_nametimeo = nametimeo;
1546 nmp->nm_negnametimeo = negnametimeo;
1547 nmp->nm_timeo = NFS_TIMEO;
1548 nmp->nm_retry = NFS_RETRANS;
1549 nmp->nm_readahead = NFS_DEFRAHEAD;
1551 /* This is empirical approximation of sqrt(hibufspace) * 256. */
1552 nmp->nm_wcommitsize = NFS_MAXBSIZE / 256;
1553 while ((long)nmp->nm_wcommitsize * nmp->nm_wcommitsize < hibufspace)
1554 nmp->nm_wcommitsize *= 2;
1555 nmp->nm_wcommitsize *= 256;
1558 if ((argp->flags & NFSMNT_NFSV4) != 0) {
1561 minvers = NFSV42_MINORVERSION;
1563 nmp->nm_minorvers = minvers;
1565 nmp->nm_minorvers = 0;
1567 nfs_decode_args(mp, nmp, argp, hst, cred, td);
1570 * V2 can only handle 32 bit filesizes. A 4GB-1 limit may be too
1571 * high, depending on whether we end up with negative offsets in
1572 * the client or server somewhere. 2GB-1 may be safer.
1574 * For V3, ncl_fsinfo will adjust this as necessary. Assume maximum
1575 * that we can handle until we find out otherwise.
1577 if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0)
1578 nmp->nm_maxfilesize = 0xffffffffLL;
1580 nmp->nm_maxfilesize = OFF_MAX;
1582 if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) {
1583 nmp->nm_wsize = NFS_WSIZE;
1584 nmp->nm_rsize = NFS_RSIZE;
1585 nmp->nm_readdirsize = NFS_READDIRSIZE;
1587 nmp->nm_numgrps = NFS_MAXGRPS;
1588 nmp->nm_tprintf_delay = nfs_tprintf_delay;
1589 if (nmp->nm_tprintf_delay < 0)
1590 nmp->nm_tprintf_delay = 0;
1591 nmp->nm_tprintf_initial_delay = nfs_tprintf_initial_delay;
1592 if (nmp->nm_tprintf_initial_delay < 0)
1593 nmp->nm_tprintf_initial_delay = 0;
1594 nmp->nm_fhsize = argp->fhsize;
1595 if (nmp->nm_fhsize > 0)
1596 bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize);
1597 strlcpy(mp->mnt_stat.f_mntfromname, hst, MNAMELEN);
1599 /* Set up the sockets and per-host congestion */
1600 nmp->nm_sotype = argp->sotype;
1601 nmp->nm_soproto = argp->proto;
1602 nmp->nm_sockreq.nr_prog = NFS_PROG;
1603 if ((argp->flags & NFSMNT_NFSV4))
1604 nmp->nm_sockreq.nr_vers = NFS_VER4;
1605 else if ((argp->flags & NFSMNT_NFSV3))
1606 nmp->nm_sockreq.nr_vers = NFS_VER3;
1608 nmp->nm_sockreq.nr_vers = NFS_VER2;
1610 if ((error = newnfs_connect(nmp, &nmp->nm_sockreq, cred, td, 0, false,
1611 &nmp->nm_sockreq.nr_client)))
1613 /* For NFSv4, get the clientid now. */
1614 if ((argp->flags & NFSMNT_NFSV4) != 0) {
1615 NFSCL_DEBUG(3, "at getcl\n");
1616 error = nfscl_getcl(mp, cred, td, tryminvers, &clp);
1617 NFSCL_DEBUG(3, "aft getcl=%d\n", error);
1620 if (aconn > 0 && nmp->nm_minorvers == 0) {
1621 vfs_mount_error(mp, "nconnect should only be used "
1622 "for NFSv4.1/4.2 mounts");
1628 if (nmp->nm_fhsize == 0 && (nmp->nm_flag & NFSMNT_NFSV4) &&
1629 nmp->nm_dirpathlen > 0) {
1630 NFSCL_DEBUG(3, "in dirp\n");
1632 * If the fhsize on the mount point == 0 for V4, the mount
1633 * path needs to be looked up.
1637 error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp),
1639 NFSCL_DEBUG(3, "aft dirp=%d\n", error);
1641 (void) nfs_catnap(PZERO, error, "nfsgetdirp");
1642 } while (error && --trycnt > 0);
1648 * A reference count is needed on the nfsnode representing the
1649 * remote root. If this object is not persistent, then backward
1650 * traversals of the mount point (i.e. "..") will not work if
1651 * the nfsnode gets flushed out of the cache. Ufs does not have
1652 * this problem, because one can identify root inodes by their
1653 * number == UFS_ROOTINO (2).
1655 if (nmp->nm_fhsize > 0) {
1657 * Set f_iosize to NFS_DIRBLKSIZ so that bo_bsize gets set
1658 * non-zero for the root vnode. f_iosize will be set correctly
1659 * by nfs_statfs() before any I/O occurs.
1661 mp->mnt_stat.f_iosize = NFS_DIRBLKSIZ;
1662 error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np,
1669 * Get file attributes and transfer parameters for the
1670 * mountpoint. This has the side effect of filling in
1671 * (*vpp)->v_type with the correct value.
1673 ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1,
1674 cred, td, &nfsva, NULL, &lease);
1677 * Just set default values to get things going.
1679 NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr));
1680 nfsva.na_vattr.va_type = VDIR;
1681 nfsva.na_vattr.va_mode = 0777;
1682 nfsva.na_vattr.va_nlink = 100;
1683 nfsva.na_vattr.va_uid = (uid_t)0;
1684 nfsva.na_vattr.va_gid = (gid_t)0;
1685 nfsva.na_vattr.va_fileid = 2;
1686 nfsva.na_vattr.va_gen = 1;
1687 nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE;
1688 nfsva.na_vattr.va_size = 512 * 1024;
1691 (void) nfscl_loadattrcache(vpp, &nfsva, NULL, NULL, 0, 1);
1692 if ((argp->flags & NFSMNT_NFSV4) != 0) {
1693 NFSCL_DEBUG(3, "lease=%d\n", (int)lease);
1695 clp->nfsc_renew = NFSCL_RENEW(lease);
1696 clp->nfsc_expire = NFSD_MONOSEC + clp->nfsc_renew;
1697 clp->nfsc_clientidrev++;
1698 if (clp->nfsc_clientidrev == 0)
1699 clp->nfsc_clientidrev++;
1702 * Mount will succeed, so the renew thread can be
1705 nfscl_start_renewthread(clp);
1706 nfscl_clientrelease(clp);
1708 if (argp->flags & NFSMNT_NFSV3)
1709 ncl_fsinfo(nmp, *vpp, cred, td);
1711 /* Mark if the mount point supports NFSv4 ACLs. */
1712 if ((argp->flags & NFSMNT_NFSV4) != 0 && nfsrv_useacl != 0 &&
1714 NFSISSET_ATTRBIT(&nfsva.na_suppattr, NFSATTRBIT_ACL)) {
1716 mp->mnt_flag |= MNT_NFS4ACLS;
1720 /* Can now allow additional connections. */
1722 nmp->nm_aconnect = aconn;
1725 * Lose the lock but keep the ref.
1728 vfs_cache_root_set(mp, *vpp);
1735 nfscl_clientrelease(clp);
1736 newnfs_disconnect(NULL, &nmp->nm_sockreq);
1737 crfree(nmp->nm_sockreq.nr_cred);
1738 if (nmp->nm_sockreq.nr_auth != NULL)
1739 AUTH_DESTROY(nmp->nm_sockreq.nr_auth);
1740 mtx_destroy(&nmp->nm_sockreq.nr_mtx);
1741 mtx_destroy(&nmp->nm_mtx);
1742 if (nmp->nm_clp != NULL) {
1744 LIST_REMOVE(nmp->nm_clp, nfsc_list);
1746 free(nmp->nm_clp, M_NFSCLCLIENT);
1748 TAILQ_FOREACH_SAFE(dsp, &nmp->nm_sess, nfsclds_list, tdsp) {
1749 if (dsp != TAILQ_FIRST(&nmp->nm_sess) &&
1750 dsp->nfsclds_sockp != NULL)
1751 newnfs_disconnect(NULL, dsp->nfsclds_sockp);
1752 nfscl_freenfsclds(dsp);
1754 free(nmp->nm_tlscertname, M_NEWNFSMNT);
1755 free(nmp, M_NEWNFSMNT);
1756 free(nam, M_SONAME);
1761 * unmount system call
1764 nfs_unmount(struct mount *mp, int mntflags)
1767 struct nfsmount *nmp;
1768 int error, flags = 0, i, trycnt = 0;
1769 struct nfsclds *dsp, *tdsp;
1773 if (mntflags & MNT_FORCE)
1774 flags |= FORCECLOSE;
1778 * Goes something like this..
1779 * - Call vflush() to clear out vnodes for this filesystem
1780 * - Close the socket
1781 * - Free up the data structures
1783 /* In the forced case, cancel any outstanding requests. */
1784 if (mntflags & MNT_FORCE) {
1786 if (nfsv4_findmirror(nmp) != NULL)
1791 error = newnfs_nmcancelreqs(nmp);
1794 /* For a forced close, get rid of the renew thread now */
1795 nfscl_umount(nmp, td);
1797 /* We hold 1 extra ref on the root vnode; see comment in mountnfs(). */
1799 error = vflush(mp, 1, flags, td);
1800 if ((mntflags & MNT_FORCE) && error != 0 && ++trycnt < 30)
1801 (void) nfs_catnap(PSOCK, error, "newndm");
1802 } while ((mntflags & MNT_FORCE) && error != 0 && trycnt < 30);
1807 * We are now committed to the unmount.
1809 if ((mntflags & MNT_FORCE) == 0)
1810 nfscl_umount(nmp, td);
1812 mtx_lock(&nmp->nm_mtx);
1813 nmp->nm_privflag |= NFSMNTP_FORCEDISM;
1814 mtx_unlock(&nmp->nm_mtx);
1816 /* Make sure no nfsiods are assigned to this mount. */
1818 for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
1819 if (ncl_iodmount[i] == nmp) {
1820 ncl_iodwant[i] = NFSIOD_AVAILABLE;
1821 ncl_iodmount[i] = NULL;
1826 * We can now set mnt_data to NULL and wait for
1827 * nfssvc(NFSSVC_FORCEDISM) to complete.
1829 mtx_lock(&mountlist_mtx);
1830 mtx_lock(&nmp->nm_mtx);
1831 mp->mnt_data = NULL;
1832 mtx_unlock(&mountlist_mtx);
1833 while ((nmp->nm_privflag & NFSMNTP_CANCELRPCS) != 0)
1834 msleep(nmp, &nmp->nm_mtx, PVFS, "nfsfdism", 0);
1835 mtx_unlock(&nmp->nm_mtx);
1837 newnfs_disconnect(nmp, &nmp->nm_sockreq);
1838 crfree(nmp->nm_sockreq.nr_cred);
1839 free(nmp->nm_nam, M_SONAME);
1840 if (nmp->nm_sockreq.nr_auth != NULL)
1841 AUTH_DESTROY(nmp->nm_sockreq.nr_auth);
1842 mtx_destroy(&nmp->nm_sockreq.nr_mtx);
1843 mtx_destroy(&nmp->nm_mtx);
1844 TAILQ_FOREACH_SAFE(dsp, &nmp->nm_sess, nfsclds_list, tdsp) {
1845 if (dsp != TAILQ_FIRST(&nmp->nm_sess) &&
1846 dsp->nfsclds_sockp != NULL)
1847 newnfs_disconnect(NULL, dsp->nfsclds_sockp);
1848 nfscl_freenfsclds(dsp);
1850 free(nmp->nm_tlscertname, M_NEWNFSMNT);
1851 free(nmp, M_NEWNFSMNT);
1857 * Return root of a filesystem
1860 nfs_root(struct mount *mp, int flags, struct vnode **vpp)
1863 struct nfsmount *nmp;
1868 error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, flags);
1873 * Get transfer parameters and attributes for root vnode once.
1875 mtx_lock(&nmp->nm_mtx);
1876 if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) {
1877 mtx_unlock(&nmp->nm_mtx);
1878 ncl_fsinfo(nmp, vp, curthread->td_ucred, curthread);
1880 mtx_unlock(&nmp->nm_mtx);
1881 if (vp->v_type == VNON)
1883 vp->v_vflag |= VV_ROOT;
1889 * Flush out the buffer cache
1893 nfs_sync(struct mount *mp, int waitfor)
1895 struct vnode *vp, *mvp;
1897 int error, allerror = 0;
1903 * If a forced dismount is in progress, return from here so that
1904 * the umount(2) syscall doesn't get stuck in VFS_SYNC() before
1905 * calling VFS_UNMOUNT().
1907 if (NFSCL_FORCEDISM(mp)) {
1914 * Force stale buffer cache information to be flushed.
1917 MNT_VNODE_FOREACH_ALL(vp, mp, mvp) {
1918 /* XXX Racy bv_cnt check. */
1919 if (NFSVOPISLOCKED(vp) || vp->v_bufobj.bo_dirty.bv_cnt == 0 ||
1920 waitfor == MNT_LAZY) {
1924 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK)) {
1925 MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp);
1928 error = VOP_FSYNC(vp, waitfor, td);
1938 nfs_sysctl(struct mount *mp, fsctlop_t op, struct sysctl_req *req)
1940 struct nfsmount *nmp = VFSTONFS(mp);
1944 bzero(&vq, sizeof(vq));
1947 case VFS_CTL_NOLOCKS:
1948 val = (nmp->nm_flag & NFSMNT_NOLOCKS) ? 1 : 0;
1949 if (req->oldptr != NULL) {
1950 error = SYSCTL_OUT(req, &val, sizeof(val));
1954 if (req->newptr != NULL) {
1955 error = SYSCTL_IN(req, &val, sizeof(val));
1959 nmp->nm_flag |= NFSMNT_NOLOCKS;
1961 nmp->nm_flag &= ~NFSMNT_NOLOCKS;
1966 mtx_lock(&nmp->nm_mtx);
1967 if (nmp->nm_state & NFSSTA_TIMEO)
1968 vq.vq_flags |= VQ_NOTRESP;
1969 mtx_unlock(&nmp->nm_mtx);
1971 if (!(nmp->nm_flag & NFSMNT_NOLOCKS) &&
1972 (nmp->nm_state & NFSSTA_LOCKTIMEO))
1973 vq.vq_flags |= VQ_NOTRESPLOCK;
1975 error = SYSCTL_OUT(req, &vq, sizeof(vq));
1978 if (req->oldptr != NULL) {
1979 error = SYSCTL_OUT(req, &nmp->nm_tprintf_initial_delay,
1980 sizeof(nmp->nm_tprintf_initial_delay));
1984 if (req->newptr != NULL) {
1985 error = vfs_suser(mp, req->td);
1988 error = SYSCTL_IN(req, &nmp->nm_tprintf_initial_delay,
1989 sizeof(nmp->nm_tprintf_initial_delay));
1992 if (nmp->nm_tprintf_initial_delay < 0)
1993 nmp->nm_tprintf_initial_delay = 0;
2003 * Purge any RPCs in progress, so that they will all return errors.
2004 * This allows dounmount() to continue as far as VFS_UNMOUNT() for a
2008 nfs_purge(struct mount *mp)
2010 struct nfsmount *nmp = VFSTONFS(mp);
2012 newnfs_nmcancelreqs(nmp);
2016 * Extract the information needed by the nlm from the nfs vnode.
2019 nfs_getnlminfo(struct vnode *vp, uint8_t *fhp, size_t *fhlenp,
2020 struct sockaddr_storage *sp, int *is_v3p, off_t *sizep,
2021 struct timeval *timeop)
2023 struct nfsmount *nmp;
2024 struct nfsnode *np = VTONFS(vp);
2026 nmp = VFSTONFS(vp->v_mount);
2028 *fhlenp = (size_t)np->n_fhp->nfh_len;
2030 bcopy(np->n_fhp->nfh_fh, fhp, np->n_fhp->nfh_len);
2032 bcopy(nmp->nm_nam, sp, min(nmp->nm_nam->sa_len, sizeof(*sp)));
2034 *is_v3p = NFS_ISV3(vp);
2036 *sizep = np->n_size;
2037 if (timeop != NULL) {
2038 timeop->tv_sec = nmp->nm_timeo / NFS_HZ;
2039 timeop->tv_usec = (nmp->nm_timeo % NFS_HZ) * (1000000 / NFS_HZ);
2044 * This function prints out an option name, based on the conditional
2047 static __inline void nfscl_printopt(struct nfsmount *nmp, int testval,
2048 char *opt, char **buf, size_t *blen)
2052 if (testval != 0 && *blen > strlen(opt)) {
2053 len = snprintf(*buf, *blen, "%s", opt);
2054 if (len != strlen(opt))
2062 * This function printf out an options integer value.
2064 static __inline void nfscl_printoptval(struct nfsmount *nmp, int optval,
2065 char *opt, char **buf, size_t *blen)
2069 if (*blen > strlen(opt) + 1) {
2070 /* Could result in truncated output string. */
2071 len = snprintf(*buf, *blen, "%s=%d", opt, optval);
2080 * Load the option flags and values into the buffer.
2082 void nfscl_retopts(struct nfsmount *nmp, char *buffer, size_t buflen)
2089 nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NFSV4) != 0, "nfsv4", &buf,
2091 if ((nmp->nm_flag & NFSMNT_NFSV4) != 0) {
2092 nfscl_printoptval(nmp, nmp->nm_minorvers, ",minorversion", &buf,
2094 nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_PNFS) != 0, ",pnfs",
2096 nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_ONEOPENOWN) != 0 &&
2097 nmp->nm_minorvers > 0, ",oneopenown", &buf, &blen);
2099 nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NFSV3) != 0, "nfsv3", &buf,
2101 nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0,
2102 "nfsv2", &buf, &blen);
2103 nfscl_printopt(nmp, nmp->nm_sotype == SOCK_STREAM, ",tcp", &buf, &blen);
2104 nfscl_printopt(nmp, nmp->nm_sotype != SOCK_STREAM, ",udp", &buf, &blen);
2105 nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_RESVPORT) != 0, ",resvport",
2107 nfscl_printopt(nmp, (nmp->nm_newflag & NFSMNT_TLS) != 0, ",tls", &buf,
2109 nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCONN) != 0, ",noconn",
2111 nfscl_printoptval(nmp, nmp->nm_aconnect + 1, ",nconnect", &buf, &blen);
2112 nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_SOFT) == 0, ",hard", &buf,
2114 nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_SOFT) != 0, ",soft", &buf,
2116 nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_INT) != 0, ",intr", &buf,
2118 nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCTO) == 0, ",cto", &buf,
2120 nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCTO) != 0, ",nocto", &buf,
2122 nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NONCONTIGWR) != 0,
2123 ",noncontigwr", &buf, &blen);
2124 nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_NOLOCKD | NFSMNT_NFSV4)) ==
2125 0, ",lockd", &buf, &blen);
2126 nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_NOLOCKD | NFSMNT_NFSV4)) ==
2127 NFSMNT_NOLOCKD, ",nolockd", &buf, &blen);
2128 nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_RDIRPLUS) != 0, ",rdirplus",
2130 nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_KERB) == 0, ",sec=sys",
2132 nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY |
2133 NFSMNT_PRIVACY)) == NFSMNT_KERB, ",sec=krb5", &buf, &blen);
2134 nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY |
2135 NFSMNT_PRIVACY)) == (NFSMNT_KERB | NFSMNT_INTEGRITY), ",sec=krb5i",
2137 nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY |
2138 NFSMNT_PRIVACY)) == (NFSMNT_KERB | NFSMNT_PRIVACY), ",sec=krb5p",
2140 nfscl_printoptval(nmp, nmp->nm_acdirmin, ",acdirmin", &buf, &blen);
2141 nfscl_printoptval(nmp, nmp->nm_acdirmax, ",acdirmax", &buf, &blen);
2142 nfscl_printoptval(nmp, nmp->nm_acregmin, ",acregmin", &buf, &blen);
2143 nfscl_printoptval(nmp, nmp->nm_acregmax, ",acregmax", &buf, &blen);
2144 nfscl_printoptval(nmp, nmp->nm_nametimeo, ",nametimeo", &buf, &blen);
2145 nfscl_printoptval(nmp, nmp->nm_negnametimeo, ",negnametimeo", &buf,
2147 nfscl_printoptval(nmp, nmp->nm_rsize, ",rsize", &buf, &blen);
2148 nfscl_printoptval(nmp, nmp->nm_wsize, ",wsize", &buf, &blen);
2149 nfscl_printoptval(nmp, nmp->nm_readdirsize, ",readdirsize", &buf,
2151 nfscl_printoptval(nmp, nmp->nm_readahead, ",readahead", &buf, &blen);
2152 nfscl_printoptval(nmp, nmp->nm_wcommitsize, ",wcommitsize", &buf,
2154 nfscl_printoptval(nmp, nmp->nm_timeo, ",timeout", &buf, &blen);
2155 nfscl_printoptval(nmp, nmp->nm_retry, ",retrans", &buf, &blen);