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

Cache object: f61dd23843639cc9d4d8b69dde459986


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