The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/nfsclient/nfs_clvfsops.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 0b2820bb2166a95c52c929795a149f48


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.