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

Cache object: c71984f7699be009941b396425bd1e59


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