]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/fs/nfsclient/nfs_clvfsops.c
Import atf 0.22 snapshot 55c21b2c5fb189bbdfccb2b297bfa89236502542
[FreeBSD/FreeBSD.git] / sys / fs / nfsclient / nfs_clvfsops.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1989, 1993, 1995
5  *      The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Rick Macklem at The University of Guelph.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
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.
21  *
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
32  * SUCH DAMAGE.
33  *
34  *      from nfs_vfsops.c       8.12 (Berkeley) 5/20/95
35  */
36
37 #include <sys/cdefs.h>
38 __FBSDID("$FreeBSD$");
39
40 #include "opt_bootp.h"
41 #include "opt_nfsroot.h"
42 #include "opt_kern_tls.h"
43
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
47 #include <sys/bio.h>
48 #include <sys/buf.h>
49 #include <sys/clock.h>
50 #include <sys/jail.h>
51 #include <sys/limits.h>
52 #include <sys/lock.h>
53 #include <sys/malloc.h>
54 #include <sys/mbuf.h>
55 #include <sys/mount.h>
56 #include <sys/proc.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>
63
64 #include <vm/vm.h>
65 #include <vm/vm_extern.h>
66 #include <vm/uma.h>
67
68 #include <net/if.h>
69 #include <net/route.h>
70 #include <net/route/route_ctl.h>
71 #include <netinet/in.h>
72
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>
78
79 #include <rpc/rpcsec_tls.h>
80
81 FEATURE(nfscl, "NFSv4 client");
82
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;
90 NFSCLSTATEMUTEX;
91 extern struct mtx nfsrv_dslock_mtx;
92
93 MALLOC_DEFINE(M_NEWNFSREQ, "newnfsclient_req", "NFS request header");
94 MALLOC_DEFINE(M_NEWNFSMNT, "newnfsmnt", "NFS mount struct");
95
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, "");
107 #ifdef NFS_DEBUG
108 int nfs_debug;
109 SYSCTL_INT(_vfs_nfs, OID_AUTO, debug, CTLFLAG_RW, &nfs_debug, 0,
110     "Toggle debug flag");
111 #endif
112
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 *,
117                     struct thread *);
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 *,
124                     struct timeval *);
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;
133
134 /*
135  * nfs vfs operations.
136  */
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,
149 };
150 /*
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.
157  */
158 VFS_SET(nfs_vfsops, nfs, VFCF_NETWORK | VFCF_SBDRY);
159
160 MODULE_VERSION(nfs, 1);
161
162 /*
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.
167  */
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;
172 #endif
173
174 SYSCTL_INT(_vfs_nfs, OID_AUTO, diskless_valid, CTLFLAG_RD,
175     &nfs_diskless_valid, 0,
176     "Has the diskless struct been filled correctly");
177
178 SYSCTL_STRING(_vfs_nfs, OID_AUTO, diskless_rootpath, CTLFLAG_RD,
179     nfsv3_diskless.root_hostnam, 0, "Path to nfs root");
180
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");
184
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);
192
193 int
194 newnfs_iosize(struct nfsmount *nmp)
195 {
196         int iosize, maxio;
197
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;
204                 else
205                         maxio = NFS_MAXBSIZE;
206         } else {
207                 maxio = NFS_V2MAXDATA;
208         }
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;
221
222         /*
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.
228          */
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;
233         return (iosize);
234 }
235
236 static void
237 nfs_convert_oargs(struct nfs_args *args, struct onfs_args *oargs)
238 {
239
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;
255 }
256
257 static void
258 nfs_convert_diskless(void)
259 {
260
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);
269         } else {
270                 nfsv3_diskless.root_fhsize = NFSX_V2FH;
271                 bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_V2FH);
272         }
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,
278                 MAXHOSTNAMELEN);
279         nfs_diskless_valid = 3;
280 }
281
282 /*
283  * nfs statfs call
284  */
285 static int
286 nfs_statfs(struct mount *mp, struct statfs *sbp)
287 {
288         struct vnode *vp;
289         struct thread *td;
290         struct nfsmount *nmp = VFSTONFS(mp);
291         struct nfsvattr nfsva;
292         struct nfsfsinfo fs;
293         struct nfsstatfs sb;
294         int error = 0, attrflag, gotfsinfo = 0, ret;
295         struct nfsnode *np;
296
297         td = curthread;
298
299         error = vfs_busy(mp, MBF_NOWAIT);
300         if (error)
301                 return (error);
302         error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, LK_EXCLUSIVE);
303         if (error) {
304                 vfs_unbusy(mp);
305                 return (error);
306         }
307         vp = NFSTOV(np);
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,
312                     &attrflag, NULL);
313                 if (!error)
314                         gotfsinfo = 1;
315         } else
316                 mtx_unlock(&nmp->nm_mtx);
317         if (!error)
318                 error = nfsrpc_statfs(vp, &sb, &fs, td->td_ucred, td, &nfsva,
319                     &attrflag, NULL);
320         if (error != 0)
321                 NFSCL_DEBUG(2, "statfs=%d\n", error);
322         if (attrflag == 0) {
323                 ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1,
324                     td->td_ucred, td, &nfsva, NULL, NULL);
325                 if (ret) {
326                         /*
327                          * Just set default values to get things going.
328                          */
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;
339                 }
340         }
341         (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1);
342         if (!error) {
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);
352             }
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);
356         }
357         vput(vp);
358         vfs_unbusy(mp);
359         return (error);
360 }
361
362 /*
363  * nfs version 3 fsinfo rpc call
364  */
365 int
366 ncl_fsinfo(struct nfsmount *nmp, struct vnode *vp, struct ucred *cred,
367     struct thread *td)
368 {
369         struct nfsfsinfo fs;
370         struct nfsvattr nfsva;
371         int error, attrflag;
372
373         error = nfsrpc_fsinfo(vp, &fs, cred, td, &nfsva, &attrflag, NULL);
374         if (!error) {
375                 if (attrflag)
376                         (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0,
377                             1);
378                 mtx_lock(&nmp->nm_mtx);
379                 nfscl_loadfsinfo(nmp, &fs);
380                 mtx_unlock(&nmp->nm_mtx);
381         }
382         return (error);
383 }
384
385 /*
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
388  * bootstrap.
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
393  *   a default gateway.
394  * - build the rootfs mount point and call mountnfs() to do the rest.
395  *
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.
400  */
401 static int
402 nfs_mountroot(struct mount *mp)
403 {
404         struct thread *td = curthread;
405         struct nfsv3_diskless *nd = &nfsv3_diskless;
406         struct socket *so;
407         struct vnode *vp;
408         struct ifreq ir;
409         int error;
410         u_long l;
411         char buf[128];
412         char *cp;
413
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();
418 #endif
419
420         if (nfs_diskless_valid == 0)
421                 return (-1);
422         if (nfs_diskless_valid == 1)
423                 nfs_convert_diskless();
424
425         /*
426          * Do enough of ifconfig(8) so that the critical net interface can
427          * talk to the server.
428          */
429         error = socreate(nd->myif.ifra_addr.sa_family, &so, nd->root_args.sotype, 0,
430             td->td_ucred, td);
431         if (error)
432                 panic("nfs_mountroot: socreate(%04x): %d",
433                         nd->myif.ifra_addr.sa_family, error);
434
435 #if 0 /* XXX Bad idea */
436         /*
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.
440          */
441
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);
447                 if(!error)
448                         break;
449         }
450 #endif
451         error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td);
452         if (error)
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);
457                 freeenv(cp);
458                 error = ifioctl(so, SIOCSIFMTU, (caddr_t)&ir, td);
459                 if (error)
460                         printf("nfs_mountroot: SIOCSIFMTU: %d", error);
461         }
462         soclose(so);
463
464         /*
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.
469          */
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;
476
477                 bzero((caddr_t)&mask, sizeof(mask));
478                 sin = mask;
479                 sin.sin_family = AF_INET;
480                 sin.sin_len = sizeof(sin);
481                 /* XXX MRT use table 0 for this sort of thing */
482                 NET_EPOCH_ENTER(et);
483                 CURVNET_SET(TD_TO_VNET(td));
484
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;
490
491                 error = rib_action(RT_DEFAULT_FIB, RTM_ADD, &info, &rc);
492                 CURVNET_RESTORE();
493                 NET_EPOCH_EXIT(et);
494                 if (error)
495                         panic("nfs_mountroot: RTM_ADD: %d", error);
496         }
497
498         /*
499          * Create the rootfs mount point.
500          */
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) {
511                 return (error);
512         }
513
514         /*
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.
518          */
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));
524         return (0);
525 }
526
527 /*
528  * Internal version of mount system call for diskless setup.
529  */
530 static int
531 nfs_mountdiskless(char *path,
532     struct sockaddr_in *sin, struct nfs_args *args, struct thread *td,
533     struct vnode **vpp, struct mount *mp)
534 {
535         struct sockaddr *nam;
536         int dirlen, error;
537         char *dirpath;
538
539         /*
540          * Find the directory path in "path", which also has the server's
541          * name/ip address in it.
542          */
543         dirpath = strchr(path, ':');
544         if (dirpath != NULL)
545                 dirlen = strlen(++dirpath);
546         else
547                 dirlen = 0;
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);
553                 return (error);
554         }
555         return (0);
556 }
557
558 static void
559 nfs_sec_name(char *sec, int *flagsp)
560 {
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);
567 }
568
569 static void
570 nfs_decode_args(struct mount *mp, struct nfsmount *nmp, struct nfs_args *argp,
571     const char *hostname, struct ucred *cred, struct thread *td)
572 {
573         int adjsock;
574         char *p;
575
576         /*
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.
581          */
582         if (vfs_getopt(mp->mnt_optnew, "ro", NULL, NULL) == 0) {
583                 MNT_ILOCK(mp);
584                 mp->mnt_flag |= MNT_RDONLY;
585                 MNT_IUNLOCK(mp);
586         } else if (mp->mnt_flag & MNT_UPDATE) {
587                 MNT_ILOCK(mp);
588                 mp->mnt_flag &= ~MNT_RDONLY;
589                 MNT_IUNLOCK(mp);
590         }
591
592         /*
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.
596          */
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;
602                 else
603                         nmp->nm_retry = NFS_RETRANS_TCP;
604         }
605
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;
610         }
611
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;
616         }
617
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));
624
625         /* Update flags atomically.  Don't change the lock bits. */
626         nmp->nm_flag = argp->flags | nmp->nm_flag;
627
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;
634         }
635
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;
640         }
641
642         if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
643                 nmp->nm_wsize = argp->wsize;
644                 /*
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.
648                  */
649                 if (nmp->nm_wsize > NFS_FABLKSIZE)
650                         nmp->nm_wsize = 1 << (fls(nmp->nm_wsize) - 1);
651                 else
652                         nmp->nm_wsize = NFS_FABLKSIZE;
653         }
654
655         if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
656                 nmp->nm_rsize = argp->rsize;
657                 /*
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.
661                  */
662                 if (nmp->nm_rsize > NFS_FABLKSIZE)
663                         nmp->nm_rsize = 1 << (fls(nmp->nm_rsize) - 1);
664                 else
665                         nmp->nm_rsize = NFS_FABLKSIZE;
666         }
667
668         if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) {
669                 nmp->nm_readdirsize = argp->readdirsize;
670         }
671
672         if ((argp->flags & NFSMNT_ACREGMIN) && argp->acregmin >= 0)
673                 nmp->nm_acregmin = argp->acregmin;
674         else
675                 nmp->nm_acregmin = NFS_MINATTRTIMO;
676         if ((argp->flags & NFSMNT_ACREGMAX) && argp->acregmax >= 0)
677                 nmp->nm_acregmax = argp->acregmax;
678         else
679                 nmp->nm_acregmax = NFS_MAXATTRTIMO;
680         if ((argp->flags & NFSMNT_ACDIRMIN) && argp->acdirmin >= 0)
681                 nmp->nm_acdirmin = argp->acdirmin;
682         else
683                 nmp->nm_acdirmin = NFS_MINDIRATTRTIMO;
684         if ((argp->flags & NFSMNT_ACDIRMAX) && argp->acdirmax >= 0)
685                 nmp->nm_acdirmax = argp->acdirmax;
686         else
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;
692
693         if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0) {
694                 if (argp->readahead <= NFS_MAXRAHEAD)
695                         nmp->nm_readahead = argp->readahead;
696                 else
697                         nmp->nm_readahead = NFS_MAXRAHEAD;
698         }
699         if ((argp->flags & NFSMNT_WCOMMITSIZE) && argp->wcommitsize >= 0) {
700                 if (argp->wcommitsize < nmp->nm_wsize)
701                         nmp->nm_wcommitsize = nmp->nm_wsize;
702                 else
703                         nmp->nm_wcommitsize = argp->wcommitsize;
704         }
705
706         adjsock |= ((nmp->nm_sotype != argp->sotype) ||
707                     (nmp->nm_soproto != argp->proto));
708
709         if (nmp->nm_client != NULL && adjsock) {
710                 int haslock = 0, error = 0;
711
712                 if (nmp->nm_sotype == SOCK_STREAM) {
713                         error = newnfs_sndlock(&nmp->nm_sockreq.nr_lock);
714                         if (!error)
715                                 haslock = 1;
716                 }
717                 if (!error) {
718                     newnfs_disconnect(nmp, &nmp->nm_sockreq);
719                     if (haslock)
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");
728                         }
729                 }
730         } else {
731                 nmp->nm_sotype = argp->sotype;
732                 nmp->nm_soproto = argp->proto;
733         }
734
735         if (hostname != NULL) {
736                 strlcpy(nmp->nm_hostname, hostname,
737                     sizeof(nmp->nm_hostname));
738                 p = strchr(nmp->nm_hostname, ':');
739                 if (p != NULL)
740                         *p = '\0';
741         }
742 }
743
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",
754     NULL };
755
756 /*
757  * Parse the "from" mountarg, passed by the generic mount(8) program
758  * or the mountroot code.  This is used when rerooting into NFS.
759  *
760  * Note that the "hostname" is actually a "hostname:/share/path" string.
761  */
762 static int
763 nfs_mount_parse_from(struct vfsoptlist *opts, char **hostnamep,
764     struct sockaddr_in **sinp, char *dirpath, size_t dirpathsize, int *dirlenp)
765 {
766         char *nam, *delimp, *hostp, *spec;
767         int error, have_bracket = 0, offset, rv, speclen;
768         struct sockaddr_in *sin;
769         size_t len;
770
771         error = vfs_getopt(opts, "from", (void **)&spec, &speclen);
772         if (error != 0)
773                 return (error);
774         nam = malloc(MNAMELEN + 1, M_TEMP, M_WAITOK);
775
776         /*
777          * This part comes from sbin/mount_nfs/mount_nfs.c:getnfsargs().
778          */
779         if (*spec == '[' && (delimp = strchr(spec + 1, ']')) != NULL &&
780             *(delimp + 1) == ':') {
781                 hostp = spec + 1;
782                 spec = delimp + 2;
783                 have_bracket = 1;
784         } else if ((delimp = strrchr(spec, ':')) != NULL) {
785                 hostp = spec;
786                 spec = delimp + 1;
787         } else if ((delimp = strrchr(spec, '@')) != NULL) {
788                 printf("%s: path@server syntax is deprecated, "
789                     "use server:path\n", __func__);
790                 hostp = delimp + 1;
791         } else {
792                 printf("%s: no <host>:<dirpath> nfs-name\n", __func__);
793                 free(nam, M_TEMP);
794                 return (EINVAL);
795         }
796         *delimp = '\0';
797
798         /*
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.
802          */
803         for (speclen = strlen(spec);
804             speclen > 1 && spec[speclen - 1] == '/';
805             speclen--)
806                 spec[speclen - 1] = '\0';
807         if (strlen(hostp) + strlen(spec) + 1 > MNAMELEN) {
808                 printf("%s: %s:%s: name too long", __func__, hostp, spec);
809                 free(nam, M_TEMP);
810                 return (EINVAL);
811         }
812         /* Make both '@' and ':' notations equal */
813         if (*hostp != '\0') {
814                 len = strlen(hostp);
815                 offset = 0;
816                 if (have_bracket)
817                         nam[offset++] = '[';
818                 memmove(nam + offset, hostp, len);
819                 if (have_bracket)
820                         nam[len + offset++] = ']';
821                 nam[len + offset++] = ':';
822                 memmove(nam + len + offset, spec, speclen);
823                 nam[len + speclen + offset] = '\0';
824         } else
825                 nam[0] = '\0';
826
827         /*
828          * XXX: IPv6
829          */
830         sin = malloc(sizeof(*sin), M_SONAME, M_WAITOK);
831         rv = inet_pton(AF_INET, hostp, &sin->sin_addr);
832         if (rv != 1) {
833                 printf("%s: cannot parse '%s', inet_pton() returned %d\n",
834                     __func__, hostp, rv);
835                 free(nam, M_TEMP);
836                 free(sin, M_SONAME);
837                 return (EINVAL);
838         }
839
840         sin->sin_len = sizeof(*sin);
841         sin->sin_family = AF_INET;
842         /*
843          * XXX: hardcoded port number.
844          */
845         sin->sin_port = htons(2049);
846
847         *hostnamep = strdup(nam, M_NEWNFSMNT);
848         *sinp = sin;
849         strlcpy(dirpath, spec, dirpathsize);
850         *dirlenp = strlen(dirpath);
851
852         free(nam, M_TEMP);
853         return (0);
854 }
855
856 /*
857  * VFS Operations.
858  *
859  * mount system call
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.
864  */
865 /* ARGSUSED */
866 static int
867 nfs_mount(struct mount *mp)
868 {
869         struct nfs_args args = {
870             .version = NFS_ARGSVERSION,
871             .addr = NULL,
872             .addrlen = sizeof (struct sockaddr_in),
873             .sotype = SOCK_STREAM,
874             .proto = 0,
875             .fh = NULL,
876             .fhsize = 0,
877             .flags = NFSMNT_RESVPORT,
878             .wsize = NFS_WSIZE,
879             .rsize = NFS_RSIZE,
880             .readdirsize = NFS_READDIRSIZE,
881             .timeo = 10,
882             .retrans = NFS_RETRANS,
883             .readahead = NFS_DEFRAHEAD,
884             .wcommitsize = 0,                   /* was: NQ_DEFLEASE */
885             .hostname = NULL,
886             .acregmin = NFS_MINATTRTIMO,
887             .acregmax = NFS_MAXATTRTIMO,
888             .acdirmin = NFS_MINDIRATTRTIMO,
889             .acdirmax = NFS_MAXDIRATTRTIMO,
890         };
891         int error = 0, ret, len;
892         struct sockaddr *nam = NULL;
893         struct vnode *vp;
894         struct thread *td;
895         char *hst;
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;
900         int minvers = -1;
901         int dirlen, has_nfs_args_opt, has_nfs_from_opt,
902             krbnamelen, srvkrbnamelen;
903         size_t hstlen;
904         uint32_t newflag;
905         int aconn = 0;
906
907         has_nfs_args_opt = 0;
908         has_nfs_from_opt = 0;
909         newflag = 0;
910         tlscertname = NULL;
911         hst = malloc(MNAMELEN, M_TEMP, M_WAITOK);
912         if (vfs_filteropt(mp->mnt_optnew, nfs_opts)) {
913                 error = EINVAL;
914                 goto out;
915         }
916
917         td = curthread;
918         if ((mp->mnt_flag & (MNT_ROOTFS | MNT_UPDATE)) == MNT_ROOTFS &&
919             nfs_diskless_valid != 0) {
920                 error = nfs_mountroot(mp);
921                 goto out;
922         }
923
924         nfscl_init();
925
926         /*
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.
931          */
932         if (vfs_getopt(mp->mnt_optnew, "nfs_args", NULL, NULL) == 0) {
933                 error = vfs_copyopt(mp->mnt_optnew, "nfs_args", &args,
934                     sizeof(args));
935                 if (error != 0)
936                         goto out;
937
938                 if (args.version != NFS_ARGSVERSION) {
939                         error = EPROGMISMATCH;
940                         goto out;
941                 }
942                 has_nfs_args_opt = 1;
943         }
944
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;
951         }
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;
983         }
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) ==
997             0) {
998                 /*
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.
1003                  */
1004                 if (opt == NULL || len <= 1 || len > NAME_MAX - 6) {
1005                         vfs_mount_error(mp, "invalid tlscertname");
1006                         error = EINVAL;
1007                         goto out;
1008                 }
1009                 tlscertname = malloc(len, M_NEWNFSMNT, M_WAITOK);
1010                 strlcpy(tlscertname, opt, len);
1011         }
1012         if (vfs_getopt(mp->mnt_optnew, "readdirsize", (void **)&opt, NULL) == 0) {
1013                 if (opt == NULL) { 
1014                         vfs_mount_error(mp, "illegal readdirsize");
1015                         error = EINVAL;
1016                         goto out;
1017                 }
1018                 ret = sscanf(opt, "%d", &args.readdirsize);
1019                 if (ret != 1 || args.readdirsize <= 0) {
1020                         vfs_mount_error(mp, "illegal readdirsize: %s",
1021                             opt);
1022                         error = EINVAL;
1023                         goto out;
1024                 }
1025                 args.flags |= NFSMNT_READDIRSIZE;
1026         }
1027         if (vfs_getopt(mp->mnt_optnew, "readahead", (void **)&opt, NULL) == 0) {
1028                 if (opt == NULL) { 
1029                         vfs_mount_error(mp, "illegal readahead");
1030                         error = EINVAL;
1031                         goto out;
1032                 }
1033                 ret = sscanf(opt, "%d", &args.readahead);
1034                 if (ret != 1 || args.readahead <= 0) {
1035                         vfs_mount_error(mp, "illegal readahead: %s",
1036                             opt);
1037                         error = EINVAL;
1038                         goto out;
1039                 }
1040                 args.flags |= NFSMNT_READAHEAD;
1041         }
1042         if (vfs_getopt(mp->mnt_optnew, "wsize", (void **)&opt, NULL) == 0) {
1043                 if (opt == NULL) { 
1044                         vfs_mount_error(mp, "illegal wsize");
1045                         error = EINVAL;
1046                         goto out;
1047                 }
1048                 ret = sscanf(opt, "%d", &args.wsize);
1049                 if (ret != 1 || args.wsize <= 0) {
1050                         vfs_mount_error(mp, "illegal wsize: %s",
1051                             opt);
1052                         error = EINVAL;
1053                         goto out;
1054                 }
1055                 args.flags |= NFSMNT_WSIZE;
1056         }
1057         if (vfs_getopt(mp->mnt_optnew, "rsize", (void **)&opt, NULL) == 0) {
1058                 if (opt == NULL) { 
1059                         vfs_mount_error(mp, "illegal rsize");
1060                         error = EINVAL;
1061                         goto out;
1062                 }
1063                 ret = sscanf(opt, "%d", &args.rsize);
1064                 if (ret != 1 || args.rsize <= 0) {
1065                         vfs_mount_error(mp, "illegal wsize: %s",
1066                             opt);
1067                         error = EINVAL;
1068                         goto out;
1069                 }
1070                 args.flags |= NFSMNT_RSIZE;
1071         }
1072         if (vfs_getopt(mp->mnt_optnew, "retrans", (void **)&opt, NULL) == 0) {
1073                 if (opt == NULL) { 
1074                         vfs_mount_error(mp, "illegal retrans");
1075                         error = EINVAL;
1076                         goto out;
1077                 }
1078                 ret = sscanf(opt, "%d", &args.retrans);
1079                 if (ret != 1 || args.retrans <= 0) {
1080                         vfs_mount_error(mp, "illegal retrans: %s",
1081                             opt);
1082                         error = EINVAL;
1083                         goto out;
1084                 }
1085                 args.flags |= NFSMNT_RETRANS;
1086         }
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",
1091                             opt);
1092                         error = EINVAL;
1093                         goto out;
1094                 }
1095                 args.acdirmin = args.acdirmax = args.acregmax = args.acregmin;
1096                 args.flags |= NFSMNT_ACDIRMIN | NFSMNT_ACDIRMAX |
1097                     NFSMNT_ACREGMIN | NFSMNT_ACREGMAX;
1098         }
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",
1103                             opt);
1104                         error = EINVAL;
1105                         goto out;
1106                 }
1107                 args.flags |= NFSMNT_ACREGMIN;
1108         }
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",
1113                             opt);
1114                         error = EINVAL;
1115                         goto out;
1116                 }
1117                 args.flags |= NFSMNT_ACREGMAX;
1118         }
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",
1123                             opt);
1124                         error = EINVAL;
1125                         goto out;
1126                 }
1127                 args.flags |= NFSMNT_ACDIRMIN;
1128         }
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",
1133                             opt);
1134                         error = EINVAL;
1135                         goto out;
1136                 }
1137                 args.flags |= NFSMNT_ACDIRMAX;
1138         }
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);
1143                         error = EINVAL;
1144                         goto out;
1145                 }
1146                 args.flags |= NFSMNT_WCOMMITSIZE;
1147         }
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",
1152                             opt);
1153                         error = EINVAL;
1154                         goto out;
1155                 }
1156                 args.flags |= NFSMNT_TIMEO;
1157         }
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",
1162                             opt);
1163                         error = EINVAL;
1164                         goto out;
1165                 }
1166                 args.flags |= NFSMNT_TIMEO;
1167         }
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);
1172                         error = EINVAL;
1173                         goto out;
1174                 }
1175         }
1176         if (vfs_getopt(mp->mnt_optnew, "negnametimeo", (void **)&opt, NULL)
1177             == 0) {
1178                 ret = sscanf(opt, "%d", &negnametimeo);
1179                 if (ret != 1 || negnametimeo < 0) {
1180                         vfs_mount_error(mp, "illegal negnametimeo: %s",
1181                             opt);
1182                         error = EINVAL;
1183                         goto out;
1184                 }
1185         }
1186         if (vfs_getopt(mp->mnt_optnew, "minorversion", (void **)&opt, NULL) ==
1187             0) {
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);
1192                         error = EINVAL;
1193                         goto out;
1194                 }
1195         }
1196         if (vfs_getopt(mp->mnt_optnew, "nconnect", (void **)&opt, NULL) ==
1197             0) {
1198                 ret = sscanf(opt, "%d", &aconn);
1199                 if (ret != 1 || aconn < 1 || aconn > NFS_MAXNCONN) {
1200                         vfs_mount_error(mp, "illegal nconnect: %s", opt);
1201                         error = EINVAL;
1202                         goto out;
1203                 }
1204                 /*
1205                  * Setting nconnect=1 is a no-op, allowed so that
1206                  * the option can be used in a Linux compatible way.
1207                  */
1208                 aconn--;
1209         }
1210         if (vfs_getopt(mp->mnt_optnew, "sec",
1211                 (void **) &secname, NULL) == 0)
1212                 nfs_sec_name(secname, &args.flags);
1213
1214         if (mp->mnt_flag & MNT_UPDATE) {
1215                 struct nfsmount *nmp = VFSTONFS(mp);
1216
1217                 if (nmp == NULL) {
1218                         error = EIO;
1219                         goto out;
1220                 }
1221
1222                 /*
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
1228                  * "nfsreq".
1229                  */
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");
1233
1234                 /*
1235                  * When doing an update, we can't change version,
1236                  * security, switch lockd strategies, change cookie
1237                  * translation or switch oneopenown.
1238                  */
1239                 args.flags = (args.flags &
1240                     ~(NFSMNT_NFSV3 |
1241                       NFSMNT_NFSV4 |
1242                       NFSMNT_KERB |
1243                       NFSMNT_INTEGRITY |
1244                       NFSMNT_PRIVACY |
1245                       NFSMNT_ONEOPENOWN |
1246                       NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)) |
1247                     (nmp->nm_flag &
1248                         (NFSMNT_NFSV3 |
1249                          NFSMNT_NFSV4 |
1250                          NFSMNT_KERB |
1251                          NFSMNT_INTEGRITY |
1252                          NFSMNT_PRIVACY |
1253                          NFSMNT_ONEOPENOWN |
1254                          NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/));
1255                 nfs_decode_args(mp, nmp, &args, NULL, td->td_ucred, td);
1256                 goto out;
1257         }
1258
1259         /*
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),
1266          * not 0.
1267          */
1268         if (nfs_ip_paranoia == 0)
1269                 args.flags |= NFSMNT_NOCONN;
1270
1271         if (has_nfs_args_opt != 0) {
1272                 /*
1273                  * In the 'nfs_args' case, the pointers in the args
1274                  * structure are in userland - we copy them in here.
1275                  */
1276                 if (args.fhsize < 0 || args.fhsize > NFSX_V3FHMAX) {
1277                         vfs_mount_error(mp, "Bad file handle");
1278                         error = EINVAL;
1279                         goto out;
1280                 }
1281                 error = copyin((caddr_t)args.fh, (caddr_t)nfh,
1282                     args.fhsize);
1283                 if (error != 0)
1284                         goto out;
1285                 error = copyinstr(args.hostname, hst, MNAMELEN - 1, &hstlen);
1286                 if (error != 0)
1287                         goto out;
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);
1292                 if (error != 0)
1293                         goto out;
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';
1300
1301                 /*
1302                  * This only works with NFSv4 for now.
1303                  */
1304                 args.fhsize = 0;
1305                 args.flags |= NFSMNT_NFSV4;
1306                 args.sotype = SOCK_STREAM;
1307         } else {
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");
1312                                 error = EINVAL;
1313                                 goto out;
1314                         }
1315                         bcopy(args.fh, nfh, args.fhsize);
1316                 } else {
1317                         args.fhsize = 0;
1318                 }
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");
1323                         error = EINVAL;
1324                         goto out;
1325                 }
1326                 if (len >= MNAMELEN) {
1327                         vfs_mount_error(mp, "Hostname too long");
1328                         error = EINVAL;
1329                         goto out;
1330                 }
1331                 bcopy(args.hostname, hst, len);
1332                 hst[len] = '\0';
1333         }
1334
1335         if (vfs_getopt(mp->mnt_optnew, "principal", (void **)&name, NULL) == 0)
1336                 strlcpy(srvkrbname, name, sizeof (srvkrbname));
1337         else {
1338                 snprintf(srvkrbname, sizeof (srvkrbname), "nfs@%s", hst);
1339                 cp = strchr(srvkrbname, ':');
1340                 if (cp != NULL)
1341                         *cp = '\0';
1342         }
1343         srvkrbnamelen = strlen(srvkrbname);
1344
1345         if (vfs_getopt(mp->mnt_optnew, "gssname", (void **)&name, NULL) == 0)
1346                 strlcpy(krbname, name, sizeof (krbname));
1347         else
1348                 krbname[0] = '\0';
1349         krbnamelen = strlen(krbname);
1350
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));
1355                 else
1356                         dirpath[0] = '\0';
1357                 dirlen = strlen(dirpath);
1358         }
1359
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;
1365                                 goto out;
1366                         }
1367                         nam = malloc(args.addrlen, M_SONAME, M_WAITOK);
1368                         bcopy(args.addr, nam, args.addrlen);
1369                         nam->sa_len = args.addrlen;
1370                 } else {
1371                         vfs_mount_error(mp, "No server address");
1372                         error = EINVAL;
1373                         goto out;
1374                 }
1375         }
1376
1377         if (aconn > 0 && (args.sotype != SOCK_STREAM ||
1378             (args.flags & NFSMNT_NFSV4) == 0 || minvers == 0)) {
1379                 /*
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.
1385                  */
1386                 vfs_mount_error(mp, "nconnect should only be used "
1387                     "for NFSv4.1/4.2 mounts");
1388                 error = EINVAL;
1389                 goto out;
1390         }
1391
1392         args.fh = nfh;
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);
1396 out:
1397         if (!error) {
1398                 MNT_ILOCK(mp);
1399                 mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_NO_IOPF |
1400                     MNTK_USES_BCACHE;
1401                 if ((VFSTONFS(mp)->nm_flag & NFSMNT_NFSV4) != 0)
1402                         mp->mnt_kern_flag |= MNTK_NULL_NOCACHE;
1403                 MNT_IUNLOCK(mp);
1404         }
1405         free(hst, M_TEMP);
1406         return (error);
1407 }
1408
1409 /*
1410  * VFS Operations.
1411  *
1412  * mount system call
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.
1417  */
1418 /* ARGSUSED */
1419 static int
1420 nfs_cmount(struct mntarg *ma, void *data, uint64_t flags)
1421 {
1422         int error;
1423         struct nfs_args args;
1424
1425         error = copyin(data, &args, sizeof (struct nfs_args));
1426         if (error)
1427                 return error;
1428
1429         ma = mount_arg(ma, "nfs_args", &args, sizeof args);
1430
1431         error = kernel_mount(ma, flags);
1432         return (error);
1433 }
1434
1435 /*
1436  * Common code for mount and mountroot
1437  */
1438 static int
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)
1444 {
1445         struct nfsmount *nmp;
1446         struct nfsnode *np;
1447         int error, trycnt, ret;
1448         struct nfsvattr nfsva;
1449         struct nfsclclient *clp;
1450         struct nfsclds *dsp, *tdsp;
1451         uint32_t lease;
1452         bool tryminvers;
1453         static u_int64_t clval = 0;
1454 #ifdef KERN_TLS
1455         u_int maxlen;
1456 #endif
1457
1458         NFSCL_DEBUG(3, "in mnt\n");
1459         clp = NULL;
1460         if (mp->mnt_flag & MNT_UPDATE) {
1461                 nmp = VFSTONFS(mp);
1462                 printf("%s: MNT_UPDATE is no longer handled here\n", __func__);
1463                 free(nam, M_SONAME);
1464                 free(tlscertname, M_NEWNFSMNT);
1465                 return (0);
1466         } else {
1467                 /* NFS-over-TLS requires that rpctls be functioning. */
1468                 if ((newflag & NFSMNT_TLS) != 0) {
1469                         error = EINVAL;
1470 #ifdef KERN_TLS
1471                         /* KERN_TLS is only supported for TCP. */
1472                         if (argp->sotype == SOCK_STREAM &&
1473                             rpctls_getinfo(&maxlen, true, false))
1474                                 error = 0;
1475 #endif
1476                         if (error != 0) {
1477                                 free(nam, M_SONAME);
1478                                 free(tlscertname, M_NEWNFSMNT);
1479                                 return (error);
1480                         }
1481                 }
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);
1489                 if (clval == 0)
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) {
1496                         /*
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.
1504                          */
1505                         nmp->nm_uid = td->td_ucred->cr_uid;
1506                 } else {
1507                         /*
1508                          * Just set to -1, so it won't be used.
1509                          */
1510                         nmp->nm_uid = (uid_t)-1;
1511                 }
1512
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';
1517                 }
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
1522                             + 1] = '\0';
1523                 }
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';
1529                 }
1530                 nmp->nm_sockreq.nr_cred = crhold(cred);
1531                 mtx_init(&nmp->nm_sockreq.nr_mtx, "nfssock", NULL, MTX_DEF);
1532                 mp->mnt_data = nmp;
1533                 nmp->nm_getinfo = nfs_getnlminfo;
1534                 nmp->nm_vinvalbuf = ncl_vinvalbuf;
1535         }
1536         vfs_getnewfsid(mp);
1537         nmp->nm_mountp = mp;
1538         mtx_init(&nmp->nm_mtx, "NFSmount lock", NULL, MTX_DEF | MTX_DUPOK);
1539
1540         /*
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.
1544          */
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;
1550
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;
1556
1557         tryminvers = false;
1558         if ((argp->flags & NFSMNT_NFSV4) != 0) {
1559                 if (minvers < 0) {
1560                         tryminvers = true;
1561                         minvers = NFSV42_MINORVERSION;
1562                 }
1563                 nmp->nm_minorvers = minvers;
1564         } else
1565                 nmp->nm_minorvers = 0;
1566
1567         nfs_decode_args(mp, nmp, argp, hst, cred, td);
1568
1569         /*
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.
1573          *
1574          * For V3, ncl_fsinfo will adjust this as necessary.  Assume maximum
1575          * that we can handle until we find out otherwise.
1576          */
1577         if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0)
1578                 nmp->nm_maxfilesize = 0xffffffffLL;
1579         else
1580                 nmp->nm_maxfilesize = OFF_MAX;
1581
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;
1586         }
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);
1598         nmp->nm_nam = nam;
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;
1607         else
1608                 nmp->nm_sockreq.nr_vers = NFS_VER2;
1609
1610         if ((error = newnfs_connect(nmp, &nmp->nm_sockreq, cred, td, 0, false,
1611             &nmp->nm_sockreq.nr_client)))
1612                 goto bad;
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);
1618                 if (error != 0)
1619                         goto bad;
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");
1623                         error = EINVAL;
1624                         goto bad;
1625                 }
1626         }
1627
1628         if (nmp->nm_fhsize == 0 && (nmp->nm_flag & NFSMNT_NFSV4) &&
1629             nmp->nm_dirpathlen > 0) {
1630                 NFSCL_DEBUG(3, "in dirp\n");
1631                 /*
1632                  * If the fhsize on the mount point == 0 for V4, the mount
1633                  * path needs to be looked up.
1634                  */
1635                 trycnt = 3;
1636                 do {
1637                         error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp),
1638                             cred, td);
1639                         NFSCL_DEBUG(3, "aft dirp=%d\n", error);
1640                         if (error)
1641                                 (void) nfs_catnap(PZERO, error, "nfsgetdirp");
1642                 } while (error && --trycnt > 0);
1643                 if (error)
1644                         goto bad;
1645         }
1646
1647         /*
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).
1654          */
1655         if (nmp->nm_fhsize > 0) {
1656                 /*
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.
1660                  */
1661                 mp->mnt_stat.f_iosize = NFS_DIRBLKSIZ;
1662                 error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np,
1663                     LK_EXCLUSIVE);
1664                 if (error)
1665                         goto bad;
1666                 *vpp = NFSTOV(np);
1667
1668                 /*
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.
1672                  */
1673                 ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1,
1674                     cred, td, &nfsva, NULL, &lease);
1675                 if (ret) {
1676                         /*
1677                          * Just set default values to get things going.
1678                          */
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;
1689                         lease = 60;
1690                 }
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);
1694                         NFSLOCKCLSTATE();
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++;
1700                         NFSUNLOCKCLSTATE();
1701                         /*
1702                          * Mount will succeed, so the renew thread can be
1703                          * started now.
1704                          */
1705                         nfscl_start_renewthread(clp);
1706                         nfscl_clientrelease(clp);
1707                 }
1708                 if (argp->flags & NFSMNT_NFSV3)
1709                         ncl_fsinfo(nmp, *vpp, cred, td);
1710
1711                 /* Mark if the mount point supports NFSv4 ACLs. */
1712                 if ((argp->flags & NFSMNT_NFSV4) != 0 && nfsrv_useacl != 0 &&
1713                     ret == 0 &&
1714                     NFSISSET_ATTRBIT(&nfsva.na_suppattr, NFSATTRBIT_ACL)) {
1715                         MNT_ILOCK(mp);
1716                         mp->mnt_flag |= MNT_NFS4ACLS;
1717                         MNT_IUNLOCK(mp);
1718                 }
1719
1720                 /* Can now allow additional connections. */
1721                 if (aconn > 0)
1722                         nmp->nm_aconnect = aconn;
1723
1724                 /*
1725                  * Lose the lock but keep the ref.
1726                  */
1727                 NFSVOPUNLOCK(*vpp);
1728                 vfs_cache_root_set(mp, *vpp);
1729                 return (0);
1730         }
1731         error = EIO;
1732
1733 bad:
1734         if (clp != NULL)
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) {
1743                 NFSLOCKCLSTATE();
1744                 LIST_REMOVE(nmp->nm_clp, nfsc_list);
1745                 NFSUNLOCKCLSTATE();
1746                 free(nmp->nm_clp, M_NFSCLCLIENT);
1747         }
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);
1753         }
1754         free(nmp->nm_tlscertname, M_NEWNFSMNT);
1755         free(nmp, M_NEWNFSMNT);
1756         free(nam, M_SONAME);
1757         return (error);
1758 }
1759
1760 /*
1761  * unmount system call
1762  */
1763 static int
1764 nfs_unmount(struct mount *mp, int mntflags)
1765 {
1766         struct thread *td;
1767         struct nfsmount *nmp;
1768         int error, flags = 0, i, trycnt = 0;
1769         struct nfsclds *dsp, *tdsp;
1770
1771         td = curthread;
1772
1773         if (mntflags & MNT_FORCE)
1774                 flags |= FORCECLOSE;
1775         nmp = VFSTONFS(mp);
1776         error = 0;
1777         /*
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
1782          */
1783         /* In the forced case, cancel any outstanding requests. */
1784         if (mntflags & MNT_FORCE) {
1785                 NFSDDSLOCK();
1786                 if (nfsv4_findmirror(nmp) != NULL)
1787                         error = ENXIO;
1788                 NFSDDSUNLOCK();
1789                 if (error)
1790                         goto out;
1791                 error = newnfs_nmcancelreqs(nmp);
1792                 if (error)
1793                         goto out;
1794                 /* For a forced close, get rid of the renew thread now */
1795                 nfscl_umount(nmp, td);
1796         }
1797         /* We hold 1 extra ref on the root vnode; see comment in mountnfs(). */
1798         do {
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);
1803         if (error)
1804                 goto out;
1805
1806         /*
1807          * We are now committed to the unmount.
1808          */
1809         if ((mntflags & MNT_FORCE) == 0)
1810                 nfscl_umount(nmp, td);
1811         else {
1812                 mtx_lock(&nmp->nm_mtx);
1813                 nmp->nm_privflag |= NFSMNTP_FORCEDISM;
1814                 mtx_unlock(&nmp->nm_mtx);
1815         }
1816         /* Make sure no nfsiods are assigned to this mount. */
1817         NFSLOCKIOD();
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;
1822                 }
1823         NFSUNLOCKIOD();
1824
1825         /*
1826          * We can now set mnt_data to NULL and wait for
1827          * nfssvc(NFSSVC_FORCEDISM) to complete.
1828          */
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);
1836
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);
1849         }
1850         free(nmp->nm_tlscertname, M_NEWNFSMNT);
1851         free(nmp, M_NEWNFSMNT);
1852 out:
1853         return (error);
1854 }
1855
1856 /*
1857  * Return root of a filesystem
1858  */
1859 static int
1860 nfs_root(struct mount *mp, int flags, struct vnode **vpp)
1861 {
1862         struct vnode *vp;
1863         struct nfsmount *nmp;
1864         struct nfsnode *np;
1865         int error;
1866
1867         nmp = VFSTONFS(mp);
1868         error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, flags);
1869         if (error)
1870                 return error;
1871         vp = NFSTOV(np);
1872         /*
1873          * Get transfer parameters and attributes for root vnode once.
1874          */
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);
1879         } else 
1880                 mtx_unlock(&nmp->nm_mtx);
1881         if (vp->v_type == VNON)
1882             vp->v_type = VDIR;
1883         vp->v_vflag |= VV_ROOT;
1884         *vpp = vp;
1885         return (0);
1886 }
1887
1888 /*
1889  * Flush out the buffer cache
1890  */
1891 /* ARGSUSED */
1892 static int
1893 nfs_sync(struct mount *mp, int waitfor)
1894 {
1895         struct vnode *vp, *mvp;
1896         struct thread *td;
1897         int error, allerror = 0;
1898
1899         td = curthread;
1900
1901         MNT_ILOCK(mp);
1902         /*
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().
1906          */
1907         if (NFSCL_FORCEDISM(mp)) {
1908                 MNT_IUNLOCK(mp);
1909                 return (EBADF);
1910         }
1911         MNT_IUNLOCK(mp);
1912
1913         /*
1914          * Force stale buffer cache information to be flushed.
1915          */
1916 loop:
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) {
1921                         VI_UNLOCK(vp);
1922                         continue;
1923                 }
1924                 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK)) {
1925                         MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp);
1926                         goto loop;
1927                 }
1928                 error = VOP_FSYNC(vp, waitfor, td);
1929                 if (error)
1930                         allerror = error;
1931                 NFSVOPUNLOCK(vp);
1932                 vrele(vp);
1933         }
1934         return (allerror);
1935 }
1936
1937 static int
1938 nfs_sysctl(struct mount *mp, fsctlop_t op, struct sysctl_req *req)
1939 {
1940         struct nfsmount *nmp = VFSTONFS(mp);
1941         struct vfsquery vq;
1942         int error;
1943
1944         bzero(&vq, sizeof(vq));
1945         switch (op) {
1946 #if 0
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));
1951                         if (error)
1952                                 return (error);
1953                 }
1954                 if (req->newptr != NULL) {
1955                         error = SYSCTL_IN(req, &val, sizeof(val));
1956                         if (error)
1957                                 return (error);
1958                         if (val)
1959                                 nmp->nm_flag |= NFSMNT_NOLOCKS;
1960                         else
1961                                 nmp->nm_flag &= ~NFSMNT_NOLOCKS;
1962                 }
1963                 break;
1964 #endif
1965         case VFS_CTL_QUERY:
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);
1970 #if 0
1971                 if (!(nmp->nm_flag & NFSMNT_NOLOCKS) &&
1972                     (nmp->nm_state & NFSSTA_LOCKTIMEO))
1973                         vq.vq_flags |= VQ_NOTRESPLOCK;
1974 #endif
1975                 error = SYSCTL_OUT(req, &vq, sizeof(vq));
1976                 break;
1977         case VFS_CTL_TIMEO:
1978                 if (req->oldptr != NULL) {
1979                         error = SYSCTL_OUT(req, &nmp->nm_tprintf_initial_delay,
1980                             sizeof(nmp->nm_tprintf_initial_delay));
1981                         if (error)
1982                                 return (error);
1983                 }
1984                 if (req->newptr != NULL) {
1985                         error = vfs_suser(mp, req->td);
1986                         if (error)
1987                                 return (error);
1988                         error = SYSCTL_IN(req, &nmp->nm_tprintf_initial_delay,
1989                             sizeof(nmp->nm_tprintf_initial_delay));
1990                         if (error)
1991                                 return (error);
1992                         if (nmp->nm_tprintf_initial_delay < 0)
1993                                 nmp->nm_tprintf_initial_delay = 0;
1994                 }
1995                 break;
1996         default:
1997                 return (ENOTSUP);
1998         }
1999         return (0);
2000 }
2001
2002 /*
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
2005  * forced dismount.
2006  */
2007 static void
2008 nfs_purge(struct mount *mp)
2009 {
2010         struct nfsmount *nmp = VFSTONFS(mp);
2011
2012         newnfs_nmcancelreqs(nmp);
2013 }
2014
2015 /*
2016  * Extract the information needed by the nlm from the nfs vnode.
2017  */
2018 static void
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)
2022 {
2023         struct nfsmount *nmp;
2024         struct nfsnode *np = VTONFS(vp);
2025
2026         nmp = VFSTONFS(vp->v_mount);
2027         if (fhlenp != NULL)
2028                 *fhlenp = (size_t)np->n_fhp->nfh_len;
2029         if (fhp != NULL)
2030                 bcopy(np->n_fhp->nfh_fh, fhp, np->n_fhp->nfh_len);
2031         if (sp != NULL)
2032                 bcopy(nmp->nm_nam, sp, min(nmp->nm_nam->sa_len, sizeof(*sp)));
2033         if (is_v3p != NULL)
2034                 *is_v3p = NFS_ISV3(vp);
2035         if (sizep != NULL)
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);
2040         }
2041 }
2042
2043 /*
2044  * This function prints out an option name, based on the conditional
2045  * argument.
2046  */
2047 static __inline void nfscl_printopt(struct nfsmount *nmp, int testval,
2048     char *opt, char **buf, size_t *blen)
2049 {
2050         int len;
2051
2052         if (testval != 0 && *blen > strlen(opt)) {
2053                 len = snprintf(*buf, *blen, "%s", opt);
2054                 if (len != strlen(opt))
2055                         printf("EEK!!\n");
2056                 *buf += len;
2057                 *blen -= len;
2058         }
2059 }
2060
2061 /*
2062  * This function printf out an options integer value.
2063  */
2064 static __inline void nfscl_printoptval(struct nfsmount *nmp, int optval,
2065     char *opt, char **buf, size_t *blen)
2066 {
2067         int len;
2068
2069         if (*blen > strlen(opt) + 1) {
2070                 /* Could result in truncated output string. */
2071                 len = snprintf(*buf, *blen, "%s=%d", opt, optval);
2072                 if (len < *blen) {
2073                         *buf += len;
2074                         *blen -= len;
2075                 }
2076         }
2077 }
2078
2079 /*
2080  * Load the option flags and values into the buffer.
2081  */
2082 void nfscl_retopts(struct nfsmount *nmp, char *buffer, size_t buflen)
2083 {
2084         char *buf;
2085         size_t blen;
2086
2087         buf = buffer;
2088         blen = buflen;
2089         nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NFSV4) != 0, "nfsv4", &buf,
2090             &blen);
2091         if ((nmp->nm_flag & NFSMNT_NFSV4) != 0) {
2092                 nfscl_printoptval(nmp, nmp->nm_minorvers, ",minorversion", &buf,
2093                     &blen);
2094                 nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_PNFS) != 0, ",pnfs",
2095                     &buf, &blen);
2096                 nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_ONEOPENOWN) != 0 &&
2097                     nmp->nm_minorvers > 0, ",oneopenown", &buf, &blen);
2098         }
2099         nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NFSV3) != 0, "nfsv3", &buf,
2100             &blen);
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",
2106             &buf, &blen);
2107         nfscl_printopt(nmp, (nmp->nm_newflag & NFSMNT_TLS) != 0, ",tls", &buf,
2108             &blen);
2109         nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCONN) != 0, ",noconn",
2110             &buf, &blen);
2111         nfscl_printoptval(nmp, nmp->nm_aconnect + 1, ",nconnect", &buf, &blen);
2112         nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_SOFT) == 0, ",hard", &buf,
2113             &blen);
2114         nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_SOFT) != 0, ",soft", &buf,
2115             &blen);
2116         nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_INT) != 0, ",intr", &buf,
2117             &blen);
2118         nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCTO) == 0, ",cto", &buf,
2119             &blen);
2120         nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCTO) != 0, ",nocto", &buf,
2121             &blen);
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",
2129             &buf, &blen);
2130         nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_KERB) == 0, ",sec=sys",
2131             &buf, &blen);
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",
2136             &buf, &blen);
2137         nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY |
2138             NFSMNT_PRIVACY)) == (NFSMNT_KERB | NFSMNT_PRIVACY), ",sec=krb5p",
2139             &buf, &blen);
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,
2146             &blen);
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,
2150             &blen);
2151         nfscl_printoptval(nmp, nmp->nm_readahead, ",readahead", &buf, &blen);
2152         nfscl_printoptval(nmp, nmp->nm_wcommitsize, ",wcommitsize", &buf,
2153             &blen);
2154         nfscl_printoptval(nmp, nmp->nm_timeo, ",timeout", &buf, &blen);
2155         nfscl_printoptval(nmp, nmp->nm_retry, ",retrans", &buf, &blen);
2156 }