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

Cache object: fad041341c59a9175a330a73a2f852fd


[ 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.