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


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

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

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

    1 /*-
    2  * Copyright (c) 1989, 1993, 1995
    3  *      The Regents of the University of California.  All rights reserved.
    4  *
    5  * This code is derived from software contributed to Berkeley by
    6  * Rick Macklem at The University of Guelph.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 4. Neither the name of the University nor the names of its contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  *
   32  *      from nfs_vfsops.c       8.12 (Berkeley) 5/20/95
   33  */
   34 
   35 #include <sys/cdefs.h>
   36 __FBSDID("$FreeBSD: releng/8.2/sys/fs/nfsclient/nfs_clvfsops.c 214612 2010-11-01 01:03:05Z 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/lock.h>
   50 #include <sys/malloc.h>
   51 #include <sys/mbuf.h>
   52 #include <sys/module.h>
   53 #include <sys/mount.h>
   54 #include <sys/proc.h>
   55 #include <sys/socket.h>
   56 #include <sys/socketvar.h>
   57 #include <sys/sockio.h>
   58 #include <sys/sysctl.h>
   59 #include <sys/vnode.h>
   60 #include <sys/signalvar.h>
   61 
   62 #include <vm/vm.h>
   63 #include <vm/vm_extern.h>
   64 #include <vm/uma.h>
   65 
   66 #include <net/if.h>
   67 #include <net/route.h>
   68 #include <netinet/in.h>
   69 
   70 #include <fs/nfs/nfsport.h>
   71 #include <fs/nfsclient/nfsnode.h>
   72 #include <fs/nfsclient/nfsmount.h>
   73 #include <fs/nfsclient/nfs.h>
   74 #include <fs/nfsclient/nfsdiskless.h>
   75 
   76 extern int nfscl_ticks;
   77 extern struct timeval nfsboottime;
   78 extern struct nfsstats  newnfsstats;
   79 
   80 MALLOC_DEFINE(M_NEWNFSREQ, "newnfsclient_req", "New NFS request header");
   81 MALLOC_DEFINE(M_NEWNFSMNT, "newnfsmnt", "New NFS mount struct");
   82 
   83 SYSCTL_DECL(_vfs_newnfs);
   84 SYSCTL_STRUCT(_vfs_newnfs, NFS_NFSSTATS, nfsstats, CTLFLAG_RW,
   85         &newnfsstats, nfsstats, "S,nfsstats");
   86 static int nfs_ip_paranoia = 1;
   87 SYSCTL_INT(_vfs_newnfs, OID_AUTO, nfs_ip_paranoia, CTLFLAG_RW,
   88     &nfs_ip_paranoia, 0, "");
   89 static int nfs_tprintf_initial_delay = NFS_TPRINTF_INITIAL_DELAY;
   90 SYSCTL_INT(_vfs_newnfs, NFS_TPRINTF_INITIAL_DELAY,
   91         downdelayinitial, CTLFLAG_RW, &nfs_tprintf_initial_delay, 0, "");
   92 /* how long between console messages "nfs server foo not responding" */
   93 static int nfs_tprintf_delay = NFS_TPRINTF_DELAY;
   94 SYSCTL_INT(_vfs_newnfs, NFS_TPRINTF_DELAY,
   95         downdelayinterval, CTLFLAG_RW, &nfs_tprintf_delay, 0, "");
   96 
   97 static void     nfs_sec_name(char *, int *);
   98 static void     nfs_decode_args(struct mount *mp, struct nfsmount *nmp,
   99                     struct nfs_args *argp, const char *, struct ucred *,
  100                     struct thread *);
  101 static int      mountnfs(struct nfs_args *, struct mount *,
  102                     struct sockaddr *, char *, u_char *, u_char *, u_char *,
  103                     struct vnode **, struct ucred *, struct thread *, int);
  104 static void     nfs_getnlminfo(struct vnode *, uint8_t *, size_t *,
  105                     struct sockaddr_storage *, int *, off_t *);
  106 static vfs_mount_t nfs_mount;
  107 static vfs_cmount_t nfs_cmount;
  108 static vfs_unmount_t nfs_unmount;
  109 static vfs_root_t nfs_root;
  110 static vfs_statfs_t nfs_statfs;
  111 static vfs_sync_t nfs_sync;
  112 static vfs_sysctl_t nfs_sysctl;
  113 
  114 /*
  115  * nfs vfs operations.
  116  */
  117 static struct vfsops nfs_vfsops = {
  118         .vfs_init =             ncl_init,
  119         .vfs_mount =            nfs_mount,
  120         .vfs_cmount =           nfs_cmount,
  121         .vfs_root =             nfs_root,
  122         .vfs_statfs =           nfs_statfs,
  123         .vfs_sync =             nfs_sync,
  124         .vfs_uninit =           ncl_uninit,
  125         .vfs_unmount =          nfs_unmount,
  126         .vfs_sysctl =           nfs_sysctl,
  127 };
  128 VFS_SET(nfs_vfsops, newnfs, VFCF_NETWORK);
  129 
  130 /* So that loader and kldload(2) can find us, wherever we are.. */
  131 MODULE_VERSION(newnfs, 1);
  132 
  133 /*
  134  * This structure must be filled in by a primary bootstrap or bootstrap
  135  * server for a diskless/dataless machine. It is initialized below just
  136  * to ensure that it is allocated to initialized data (.data not .bss).
  137  */
  138 struct nfs_diskless newnfs_diskless = { { { 0 } } };
  139 struct nfsv3_diskless newnfsv3_diskless = { { { 0 } } };
  140 int newnfs_diskless_valid = 0;
  141 
  142 SYSCTL_INT(_vfs_newnfs, OID_AUTO, diskless_valid, CTLFLAG_RD,
  143     &newnfs_diskless_valid, 0,
  144     "Has the diskless struct been filled correctly");
  145 
  146 SYSCTL_STRING(_vfs_newnfs, OID_AUTO, diskless_rootpath, CTLFLAG_RD,
  147     newnfsv3_diskless.root_hostnam, 0, "Path to nfs root");
  148 
  149 SYSCTL_OPAQUE(_vfs_newnfs, OID_AUTO, diskless_rootaddr, CTLFLAG_RD,
  150     &newnfsv3_diskless.root_saddr, sizeof newnfsv3_diskless.root_saddr,
  151     "%Ssockaddr_in", "Diskless root nfs address");
  152 
  153 
  154 void            newnfsargs_ntoh(struct nfs_args *);
  155 static int      nfs_mountdiskless(char *,
  156                     struct sockaddr_in *, struct nfs_args *,
  157                     struct thread *, struct vnode **, struct mount *);
  158 static void     nfs_convert_diskless(void);
  159 static void     nfs_convert_oargs(struct nfs_args *args,
  160                     struct onfs_args *oargs);
  161 
  162 int
  163 newnfs_iosize(struct nfsmount *nmp)
  164 {
  165         int iosize, maxio;
  166 
  167         /* First, set the upper limit for iosize */
  168         if (nmp->nm_flag & NFSMNT_NFSV4) {
  169                 maxio = NFS_MAXBSIZE;
  170         } else if (nmp->nm_flag & NFSMNT_NFSV3) {
  171                 if (nmp->nm_sotype == SOCK_DGRAM)
  172                         maxio = NFS_MAXDGRAMDATA;
  173                 else
  174                         maxio = NFS_MAXBSIZE;
  175         } else {
  176                 maxio = NFS_V2MAXDATA;
  177         }
  178         if (nmp->nm_rsize > maxio || nmp->nm_rsize == 0)
  179                 nmp->nm_rsize = maxio;
  180         if (nmp->nm_rsize > MAXBSIZE)
  181                 nmp->nm_rsize = MAXBSIZE;
  182         if (nmp->nm_readdirsize > maxio || nmp->nm_readdirsize == 0)
  183                 nmp->nm_readdirsize = maxio;
  184         if (nmp->nm_readdirsize > nmp->nm_rsize)
  185                 nmp->nm_readdirsize = nmp->nm_rsize;
  186         if (nmp->nm_wsize > maxio || nmp->nm_wsize == 0)
  187                 nmp->nm_wsize = maxio;
  188         if (nmp->nm_wsize > MAXBSIZE)
  189                 nmp->nm_wsize = MAXBSIZE;
  190 
  191         /*
  192          * Calculate the size used for io buffers.  Use the larger
  193          * of the two sizes to minimise nfs requests but make sure
  194          * that it is at least one VM page to avoid wasting buffer
  195          * space.
  196          */
  197         iosize = imax(nmp->nm_rsize, nmp->nm_wsize);
  198         iosize = imax(iosize, PAGE_SIZE);
  199         nmp->nm_mountp->mnt_stat.f_iosize = iosize;
  200         return (iosize);
  201 }
  202 
  203 static void
  204 nfs_convert_oargs(struct nfs_args *args, struct onfs_args *oargs)
  205 {
  206 
  207         args->version = NFS_ARGSVERSION;
  208         args->addr = oargs->addr;
  209         args->addrlen = oargs->addrlen;
  210         args->sotype = oargs->sotype;
  211         args->proto = oargs->proto;
  212         args->fh = oargs->fh;
  213         args->fhsize = oargs->fhsize;
  214         args->flags = oargs->flags;
  215         args->wsize = oargs->wsize;
  216         args->rsize = oargs->rsize;
  217         args->readdirsize = oargs->readdirsize;
  218         args->timeo = oargs->timeo;
  219         args->retrans = oargs->retrans;
  220         args->readahead = oargs->readahead;
  221         args->hostname = oargs->hostname;
  222 }
  223 
  224 static void
  225 nfs_convert_diskless(void)
  226 {
  227 
  228         bcopy(&newnfs_diskless.myif, &newnfsv3_diskless.myif,
  229             sizeof (struct ifaliasreq));
  230         bcopy(&newnfs_diskless.mygateway, &newnfsv3_diskless.mygateway,
  231             sizeof (struct sockaddr_in));
  232         nfs_convert_oargs(&newnfsv3_diskless.root_args,
  233             &newnfs_diskless.root_args);
  234         if (newnfsv3_diskless.root_args.flags & NFSMNT_NFSV3) {
  235                 newnfsv3_diskless.root_fhsize = NFSX_MYFH;
  236                 bcopy(newnfs_diskless.root_fh, newnfsv3_diskless.root_fh,
  237                     NFSX_MYFH);
  238         } else {
  239                 newnfsv3_diskless.root_fhsize = NFSX_V2FH;
  240                 bcopy(newnfs_diskless.root_fh, newnfsv3_diskless.root_fh,
  241                     NFSX_V2FH);
  242         }
  243         bcopy(&newnfs_diskless.root_saddr,&newnfsv3_diskless.root_saddr,
  244             sizeof(struct sockaddr_in));
  245         bcopy(newnfs_diskless.root_hostnam, newnfsv3_diskless.root_hostnam,
  246             MNAMELEN);
  247         newnfsv3_diskless.root_time = newnfs_diskless.root_time;
  248         bcopy(newnfs_diskless.my_hostnam, newnfsv3_diskless.my_hostnam,
  249             MAXHOSTNAMELEN);
  250         newnfs_diskless_valid = 3;
  251 }
  252 
  253 /*
  254  * nfs statfs call
  255  */
  256 static int
  257 nfs_statfs(struct mount *mp, struct statfs *sbp)
  258 {
  259         struct vnode *vp;
  260         struct thread *td;
  261         struct nfsmount *nmp = VFSTONFS(mp);
  262         struct nfsvattr nfsva;
  263         struct nfsfsinfo fs;
  264         struct nfsstatfs sb;
  265         int error = 0, attrflag, gotfsinfo = 0, ret;
  266         struct nfsnode *np;
  267 
  268         td = curthread;
  269 
  270         error = vfs_busy(mp, MBF_NOWAIT);
  271         if (error)
  272                 return (error);
  273         error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np);
  274         if (error) {
  275                 vfs_unbusy(mp);
  276                 return (error);
  277         }
  278         vp = NFSTOV(np);
  279         mtx_lock(&nmp->nm_mtx);
  280         if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) {
  281                 mtx_unlock(&nmp->nm_mtx);
  282                 error = nfsrpc_fsinfo(vp, &fs, td->td_ucred, td, &nfsva,
  283                     &attrflag, NULL);
  284                 if (!error)
  285                         gotfsinfo = 1;
  286         } else
  287                 mtx_unlock(&nmp->nm_mtx);
  288         if (!error)
  289                 error = nfsrpc_statfs(vp, &sb, &fs, td->td_ucred, td, &nfsva,
  290                     &attrflag, NULL);
  291         if (attrflag == 0) {
  292                 ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1,
  293                     td->td_ucred, td, &nfsva, NULL);
  294                 if (ret) {
  295                         /*
  296                          * Just set default values to get things going.
  297                          */
  298                         NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr));
  299                         nfsva.na_vattr.va_type = VDIR;
  300                         nfsva.na_vattr.va_mode = 0777;
  301                         nfsva.na_vattr.va_nlink = 100;
  302                         nfsva.na_vattr.va_uid = (uid_t)0;
  303                         nfsva.na_vattr.va_gid = (gid_t)0;
  304                         nfsva.na_vattr.va_fileid = 2;
  305                         nfsva.na_vattr.va_gen = 1;
  306                         nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE;
  307                         nfsva.na_vattr.va_size = 512 * 1024;
  308                 }
  309         }
  310         (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1);
  311         if (!error) {
  312             mtx_lock(&nmp->nm_mtx);
  313             if (gotfsinfo || (nmp->nm_flag & NFSMNT_NFSV4))
  314                 nfscl_loadfsinfo(nmp, &fs);
  315             nfscl_loadsbinfo(nmp, &sb, sbp);
  316             sbp->f_flags = nmp->nm_flag;
  317             sbp->f_iosize = newnfs_iosize(nmp);
  318             mtx_unlock(&nmp->nm_mtx);
  319             if (sbp != &mp->mnt_stat) {
  320                 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
  321                 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
  322             }
  323             strncpy(&sbp->f_fstypename[0], mp->mnt_vfc->vfc_name, MFSNAMELEN);
  324         } else if (NFS_ISV4(vp)) {
  325                 error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0);
  326         }
  327         vput(vp);
  328         vfs_unbusy(mp);
  329         return (error);
  330 }
  331 
  332 /*
  333  * nfs version 3 fsinfo rpc call
  334  */
  335 int
  336 ncl_fsinfo(struct nfsmount *nmp, struct vnode *vp, struct ucred *cred,
  337     struct thread *td)
  338 {
  339         struct nfsfsinfo fs;
  340         struct nfsvattr nfsva;
  341         int error, attrflag;
  342         
  343         error = nfsrpc_fsinfo(vp, &fs, cred, td, &nfsva, &attrflag, NULL);
  344         if (!error) {
  345                 if (attrflag)
  346                         (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0,
  347                             1);
  348                 mtx_lock(&nmp->nm_mtx);
  349                 nfscl_loadfsinfo(nmp, &fs);
  350                 mtx_unlock(&nmp->nm_mtx);
  351         }
  352         return (error);
  353 }
  354 
  355 /*
  356  * Mount a remote root fs via. nfs. This depends on the info in the
  357  * newnfs_diskless structure that has been filled in properly by some primary
  358  * bootstrap.
  359  * It goes something like this:
  360  * - do enough of "ifconfig" by calling ifioctl() so that the system
  361  *   can talk to the server
  362  * - If newnfs_diskless.mygateway is filled in, use that address as
  363  *   a default gateway.
  364  * - build the rootfs mount point and call mountnfs() to do the rest.
  365  *
  366  * It is assumed to be safe to read, modify, and write the nfsv3_diskless
  367  * structure, as well as other global NFS client variables here, as
  368  * nfs_mountroot() will be called once in the boot before any other NFS
  369  * client activity occurs.
  370  */
  371 int
  372 ncl_mountroot(struct mount *mp)
  373 {
  374         struct thread *td = curthread;
  375         struct nfsv3_diskless *nd = &newnfsv3_diskless;
  376         struct socket *so;
  377         struct vnode *vp;
  378         struct ifreq ir;
  379         int error;
  380         u_long l;
  381         char buf[128];
  382         char *cp;
  383 
  384 #if defined(BOOTP_NFSROOT) && defined(BOOTP)
  385         bootpc_init();          /* use bootp to get nfs_diskless filled in */
  386 #elif defined(NFS_ROOT)
  387         nfs_setup_diskless();
  388 #endif
  389 
  390         if (newnfs_diskless_valid == 0)
  391                 return (-1);
  392         if (newnfs_diskless_valid == 1)
  393                 nfs_convert_diskless();
  394 
  395         /*
  396          * XXX splnet, so networks will receive...
  397          */
  398         splnet();
  399 
  400         /*
  401          * Do enough of ifconfig(8) so that the critical net interface can
  402          * talk to the server.
  403          */
  404         error = socreate(nd->myif.ifra_addr.sa_family, &so, nd->root_args.sotype, 0,
  405             td->td_ucred, td);
  406         if (error)
  407                 panic("nfs_mountroot: socreate(%04x): %d",
  408                         nd->myif.ifra_addr.sa_family, error);
  409 
  410 #if 0 /* XXX Bad idea */
  411         /*
  412          * We might not have been told the right interface, so we pass
  413          * over the first ten interfaces of the same kind, until we get
  414          * one of them configured.
  415          */
  416 
  417         for (i = strlen(nd->myif.ifra_name) - 1;
  418                 nd->myif.ifra_name[i] >= '' &&
  419                 nd->myif.ifra_name[i] <= '9';
  420                 nd->myif.ifra_name[i] ++) {
  421                 error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td);
  422                 if(!error)
  423                         break;
  424         }
  425 #endif
  426         error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td);
  427         if (error)
  428                 panic("nfs_mountroot: SIOCAIFADDR: %d", error);
  429         if ((cp = getenv("boot.netif.mtu")) != NULL) {
  430                 ir.ifr_mtu = strtol(cp, NULL, 10);
  431                 bcopy(nd->myif.ifra_name, ir.ifr_name, IFNAMSIZ);
  432                 freeenv(cp);
  433                 error = ifioctl(so, SIOCSIFMTU, (caddr_t)&ir, td);
  434                 if (error)
  435                         printf("nfs_mountroot: SIOCSIFMTU: %d", error);
  436         }
  437         soclose(so);
  438 
  439         /*
  440          * If the gateway field is filled in, set it as the default route.
  441          * Note that pxeboot will set a default route of 0 if the route
  442          * is not set by the DHCP server.  Check also for a value of 0
  443          * to avoid panicking inappropriately in that situation.
  444          */
  445         if (nd->mygateway.sin_len != 0 &&
  446             nd->mygateway.sin_addr.s_addr != 0) {
  447                 struct sockaddr_in mask, sin;
  448 
  449                 bzero((caddr_t)&mask, sizeof(mask));
  450                 sin = mask;
  451                 sin.sin_family = AF_INET;
  452                 sin.sin_len = sizeof(sin);
  453                 /* XXX MRT use table 0 for this sort of thing */
  454                 error = rtrequest(RTM_ADD, (struct sockaddr *)&sin,
  455                     (struct sockaddr *)&nd->mygateway,
  456                     (struct sockaddr *)&mask,
  457                     RTF_UP | RTF_GATEWAY, NULL);
  458                 if (error)
  459                         panic("nfs_mountroot: RTM_ADD: %d", error);
  460         }
  461 
  462         /*
  463          * Create the rootfs mount point.
  464          */
  465         nd->root_args.fh = nd->root_fh;
  466         nd->root_args.fhsize = nd->root_fhsize;
  467         l = ntohl(nd->root_saddr.sin_addr.s_addr);
  468         snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s",
  469                 (l >> 24) & 0xff, (l >> 16) & 0xff,
  470                 (l >>  8) & 0xff, (l >>  0) & 0xff, nd->root_hostnam);
  471         printf("NFS ROOT: %s\n", buf);
  472         nd->root_args.hostname = buf;
  473         if ((error = nfs_mountdiskless(buf,
  474             &nd->root_saddr, &nd->root_args, td, &vp, mp)) != 0) {
  475                 return (error);
  476         }
  477 
  478         /*
  479          * This is not really an nfs issue, but it is much easier to
  480          * set hostname here and then let the "/etc/rc.xxx" files
  481          * mount the right /var based upon its preset value.
  482          */
  483         mtx_lock(&prison0.pr_mtx);
  484         strlcpy(prison0.pr_hostname, nd->my_hostnam,
  485             sizeof(prison0.pr_hostname));
  486         mtx_unlock(&prison0.pr_mtx);
  487         inittodr(ntohl(nd->root_time));
  488         return (0);
  489 }
  490 
  491 /*
  492  * Internal version of mount system call for diskless setup.
  493  */
  494 static int
  495 nfs_mountdiskless(char *path,
  496     struct sockaddr_in *sin, struct nfs_args *args, struct thread *td,
  497     struct vnode **vpp, struct mount *mp)
  498 {
  499         struct sockaddr *nam;
  500         int error;
  501 
  502         nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK);
  503         if ((error = mountnfs(args, mp, nam, path, NULL, NULL, NULL, vpp,
  504             td->td_ucred, td, NFS_DEFAULT_NEGNAMETIMEO)) != 0) {
  505                 printf("nfs_mountroot: mount %s on /: %d\n", path, error);
  506                 return (error);
  507         }
  508         return (0);
  509 }
  510 
  511 static void
  512 nfs_sec_name(char *sec, int *flagsp)
  513 {
  514         if (!strcmp(sec, "krb5"))
  515                 *flagsp |= NFSMNT_KERB;
  516         else if (!strcmp(sec, "krb5i"))
  517                 *flagsp |= (NFSMNT_KERB | NFSMNT_INTEGRITY);
  518         else if (!strcmp(sec, "krb5p"))
  519                 *flagsp |= (NFSMNT_KERB | NFSMNT_PRIVACY);
  520 }
  521 
  522 static void
  523 nfs_decode_args(struct mount *mp, struct nfsmount *nmp, struct nfs_args *argp,
  524     const char *hostname, struct ucred *cred, struct thread *td)
  525 {
  526         int s;
  527         int adjsock;
  528         char *p;
  529 
  530         s = splnet();
  531 
  532         /*
  533          * Set read-only flag if requested; otherwise, clear it if this is
  534          * an update.  If this is not an update, then either the read-only
  535          * flag is already clear, or this is a root mount and it was set
  536          * intentionally at some previous point.
  537          */
  538         if (vfs_getopt(mp->mnt_optnew, "ro", NULL, NULL) == 0) {
  539                 MNT_ILOCK(mp);
  540                 mp->mnt_flag |= MNT_RDONLY;
  541                 MNT_IUNLOCK(mp);
  542         } else if (mp->mnt_flag & MNT_UPDATE) {
  543                 MNT_ILOCK(mp);
  544                 mp->mnt_flag &= ~MNT_RDONLY;
  545                 MNT_IUNLOCK(mp);
  546         }
  547 
  548         /*
  549          * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes
  550          * no sense in that context.  Also, set up appropriate retransmit
  551          * and soft timeout behavior.
  552          */
  553         if (argp->sotype == SOCK_STREAM) {
  554                 nmp->nm_flag &= ~NFSMNT_NOCONN;
  555                 nmp->nm_timeo = NFS_MAXTIMEO;
  556         }
  557 
  558         /* Also clear RDIRPLUS if not NFSv3, it crashes some servers */
  559         if ((argp->flags & NFSMNT_NFSV3) == 0)
  560                 nmp->nm_flag &= ~NFSMNT_RDIRPLUS;
  561 
  562         /* Also re-bind if we're switching to/from a connected UDP socket */
  563         adjsock = ((nmp->nm_flag & NFSMNT_NOCONN) !=
  564                     (argp->flags & NFSMNT_NOCONN));
  565 
  566         /* Update flags atomically.  Don't change the lock bits. */
  567         nmp->nm_flag = argp->flags | nmp->nm_flag;
  568         splx(s);
  569 
  570         if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
  571                 nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
  572                 if (nmp->nm_timeo < NFS_MINTIMEO)
  573                         nmp->nm_timeo = NFS_MINTIMEO;
  574                 else if (nmp->nm_timeo > NFS_MAXTIMEO)
  575                         nmp->nm_timeo = NFS_MAXTIMEO;
  576         }
  577 
  578         if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
  579                 nmp->nm_retry = argp->retrans;
  580                 if (nmp->nm_retry > NFS_MAXREXMIT)
  581                         nmp->nm_retry = NFS_MAXREXMIT;
  582         }
  583 
  584         if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
  585                 nmp->nm_wsize = argp->wsize;
  586                 /* Round down to multiple of blocksize */
  587                 nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1);
  588                 if (nmp->nm_wsize <= 0)
  589                         nmp->nm_wsize = NFS_FABLKSIZE;
  590         }
  591 
  592         if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
  593                 nmp->nm_rsize = argp->rsize;
  594                 /* Round down to multiple of blocksize */
  595                 nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1);
  596                 if (nmp->nm_rsize <= 0)
  597                         nmp->nm_rsize = NFS_FABLKSIZE;
  598         }
  599 
  600         if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) {
  601                 nmp->nm_readdirsize = argp->readdirsize;
  602         }
  603 
  604         if ((argp->flags & NFSMNT_ACREGMIN) && argp->acregmin >= 0)
  605                 nmp->nm_acregmin = argp->acregmin;
  606         else
  607                 nmp->nm_acregmin = NFS_MINATTRTIMO;
  608         if ((argp->flags & NFSMNT_ACREGMAX) && argp->acregmax >= 0)
  609                 nmp->nm_acregmax = argp->acregmax;
  610         else
  611                 nmp->nm_acregmax = NFS_MAXATTRTIMO;
  612         if ((argp->flags & NFSMNT_ACDIRMIN) && argp->acdirmin >= 0)
  613                 nmp->nm_acdirmin = argp->acdirmin;
  614         else
  615                 nmp->nm_acdirmin = NFS_MINDIRATTRTIMO;
  616         if ((argp->flags & NFSMNT_ACDIRMAX) && argp->acdirmax >= 0)
  617                 nmp->nm_acdirmax = argp->acdirmax;
  618         else
  619                 nmp->nm_acdirmax = NFS_MAXDIRATTRTIMO;
  620         if (nmp->nm_acdirmin > nmp->nm_acdirmax)
  621                 nmp->nm_acdirmin = nmp->nm_acdirmax;
  622         if (nmp->nm_acregmin > nmp->nm_acregmax)
  623                 nmp->nm_acregmin = nmp->nm_acregmax;
  624 
  625         if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0) {
  626                 if (argp->readahead <= NFS_MAXRAHEAD)
  627                         nmp->nm_readahead = argp->readahead;
  628                 else
  629                         nmp->nm_readahead = NFS_MAXRAHEAD;
  630         }
  631         if ((argp->flags & NFSMNT_WCOMMITSIZE) && argp->wcommitsize >= 0) {
  632                 if (argp->wcommitsize < nmp->nm_wsize)
  633                         nmp->nm_wcommitsize = nmp->nm_wsize;
  634                 else
  635                         nmp->nm_wcommitsize = argp->wcommitsize;
  636         }
  637 
  638         adjsock |= ((nmp->nm_sotype != argp->sotype) ||
  639                     (nmp->nm_soproto != argp->proto));
  640 
  641         if (nmp->nm_client != NULL && adjsock) {
  642                 int haslock = 0, error = 0;
  643 
  644                 if (nmp->nm_sotype == SOCK_STREAM) {
  645                         error = newnfs_sndlock(&nmp->nm_sockreq.nr_lock);
  646                         if (!error)
  647                                 haslock = 1;
  648                 }
  649                 if (!error) {
  650                     newnfs_disconnect(&nmp->nm_sockreq);
  651                     if (haslock)
  652                         newnfs_sndunlock(&nmp->nm_sockreq.nr_lock);
  653                     nmp->nm_sotype = argp->sotype;
  654                     nmp->nm_soproto = argp->proto;
  655                     if (nmp->nm_sotype == SOCK_DGRAM)
  656                         while (newnfs_connect(nmp, &nmp->nm_sockreq,
  657                             cred, td, 0)) {
  658                                 printf("newnfs_args: retrying connect\n");
  659                                 (void) nfs_catnap(PSOCK, 0, "newnfscon");
  660                         }
  661                 }
  662         } else {
  663                 nmp->nm_sotype = argp->sotype;
  664                 nmp->nm_soproto = argp->proto;
  665         }
  666 
  667         if (hostname != NULL) {
  668                 strlcpy(nmp->nm_hostname, hostname,
  669                     sizeof(nmp->nm_hostname));
  670                 p = strchr(nmp->nm_hostname, ':');
  671                 if (p != NULL)
  672                         *p = '\0';
  673         }
  674 }
  675 
  676 static const char *nfs_opts[] = { "from",
  677     "noatime", "noexec", "suiddir", "nosuid", "nosymfollow", "union",
  678     "noclusterr", "noclusterw", "multilabel", "acls", "force", "update",
  679     "async", "noconn", "nolockd", "conn", "lockd", "intr", "rdirplus",
  680     "readdirsize", "soft", "hard", "mntudp", "tcp", "udp", "wsize", "rsize",
  681     "retrans", "acregmin", "acregmax", "acdirmin", "acdirmax", "resvport",
  682     "readahead", "hostname", "timeout", "addr", "fh", "nfsv3", "sec",
  683     "principal", "nfsv4", "gssname", "allgssname", "dirpath",
  684     "negnametimeo",
  685     NULL };
  686 
  687 /*
  688  * VFS Operations.
  689  *
  690  * mount system call
  691  * It seems a bit dumb to copyinstr() the host and path here and then
  692  * bcopy() them in mountnfs(), but I wanted to detect errors before
  693  * doing the sockargs() call because sockargs() allocates an mbuf and
  694  * an error after that means that I have to release the mbuf.
  695  */
  696 /* ARGSUSED */
  697 static int
  698 nfs_mount(struct mount *mp)
  699 {
  700         struct nfs_args args = {
  701             .version = NFS_ARGSVERSION,
  702             .addr = NULL,
  703             .addrlen = sizeof (struct sockaddr_in),
  704             .sotype = SOCK_STREAM,
  705             .proto = 0,
  706             .fh = NULL,
  707             .fhsize = 0,
  708             .flags = 0,
  709             .wsize = NFS_WSIZE,
  710             .rsize = NFS_RSIZE,
  711             .readdirsize = NFS_READDIRSIZE,
  712             .timeo = 10,
  713             .retrans = NFS_RETRANS,
  714             .readahead = NFS_DEFRAHEAD,
  715             .wcommitsize = 0,                   /* was: NQ_DEFLEASE */
  716             .hostname = NULL,
  717             /* args version 4 */
  718             .acregmin = NFS_MINATTRTIMO,
  719             .acregmax = NFS_MAXATTRTIMO,
  720             .acdirmin = NFS_MINDIRATTRTIMO,
  721             .acdirmax = NFS_MAXDIRATTRTIMO,
  722             .dirlen = 0,
  723             .krbnamelen = 0,
  724             .srvkrbnamelen = 0,
  725         };
  726         int error = 0, ret, len;
  727         struct sockaddr *nam = NULL;
  728         struct vnode *vp;
  729         struct thread *td;
  730         char hst[MNAMELEN];
  731         u_char nfh[NFSX_FHMAX], krbname[100], dirpath[100], srvkrbname[100];
  732         char *opt, *name, *secname;
  733         int negnametimeo = NFS_DEFAULT_NEGNAMETIMEO;
  734 
  735         if (vfs_filteropt(mp->mnt_optnew, nfs_opts)) {
  736                 error = EINVAL;
  737                 goto out;
  738         }
  739 
  740         td = curthread;
  741         if ((mp->mnt_flag & (MNT_ROOTFS | MNT_UPDATE)) == MNT_ROOTFS) {
  742                 error = ncl_mountroot(mp);
  743                 goto out;
  744         }
  745 
  746         nfscl_init();
  747 
  748         /* Handle the new style options. */
  749         if (vfs_getopt(mp->mnt_optnew, "noconn", NULL, NULL) == 0)
  750                 args.flags |= NFSMNT_NOCONN;
  751         if (vfs_getopt(mp->mnt_optnew, "conn", NULL, NULL) == 0)
  752                 args.flags |= NFSMNT_NOCONN;
  753         if (vfs_getopt(mp->mnt_optnew, "nolockd", NULL, NULL) == 0)
  754                 args.flags |= NFSMNT_NOLOCKD;
  755         if (vfs_getopt(mp->mnt_optnew, "lockd", NULL, NULL) == 0)
  756                 args.flags &= ~NFSMNT_NOLOCKD;
  757         if (vfs_getopt(mp->mnt_optnew, "intr", NULL, NULL) == 0)
  758                 args.flags |= NFSMNT_INT;
  759         if (vfs_getopt(mp->mnt_optnew, "rdirplus", NULL, NULL) == 0)
  760                 args.flags |= NFSMNT_RDIRPLUS;
  761         if (vfs_getopt(mp->mnt_optnew, "resvport", NULL, NULL) == 0)
  762                 args.flags |= NFSMNT_RESVPORT;
  763         if (vfs_getopt(mp->mnt_optnew, "noresvport", NULL, NULL) == 0)
  764                 args.flags &= ~NFSMNT_RESVPORT;
  765         if (vfs_getopt(mp->mnt_optnew, "soft", NULL, NULL) == 0)
  766                 args.flags |= NFSMNT_SOFT;
  767         if (vfs_getopt(mp->mnt_optnew, "hard", NULL, NULL) == 0)
  768                 args.flags &= ~NFSMNT_SOFT;
  769         if (vfs_getopt(mp->mnt_optnew, "mntudp", NULL, NULL) == 0)
  770                 args.sotype = SOCK_DGRAM;
  771         if (vfs_getopt(mp->mnt_optnew, "udp", NULL, NULL) == 0)
  772                 args.sotype = SOCK_DGRAM;
  773         if (vfs_getopt(mp->mnt_optnew, "tcp", NULL, NULL) == 0)
  774                 args.sotype = SOCK_STREAM;
  775         if (vfs_getopt(mp->mnt_optnew, "nfsv3", NULL, NULL) == 0)
  776                 args.flags |= NFSMNT_NFSV3;
  777         if (vfs_getopt(mp->mnt_optnew, "nfsv4", NULL, NULL) == 0) {
  778                 args.flags |= NFSMNT_NFSV4;
  779                 args.sotype = SOCK_STREAM;
  780         }
  781         if (vfs_getopt(mp->mnt_optnew, "allgssname", NULL, NULL) == 0)
  782                 args.flags |= NFSMNT_ALLGSSNAME;
  783         if (vfs_getopt(mp->mnt_optnew, "readdirsize", (void **)&opt, NULL) == 0) {
  784                 if (opt == NULL) { 
  785                         vfs_mount_error(mp, "illegal readdirsize");
  786                         error = EINVAL;
  787                         goto out;
  788                 }
  789                 ret = sscanf(opt, "%d", &args.readdirsize);
  790                 if (ret != 1 || args.readdirsize <= 0) {
  791                         vfs_mount_error(mp, "illegal readdirsize: %s",
  792                             opt);
  793                         error = EINVAL;
  794                         goto out;
  795                 }
  796                 args.flags |= NFSMNT_READDIRSIZE;
  797         }
  798         if (vfs_getopt(mp->mnt_optnew, "readahead", (void **)&opt, NULL) == 0) {
  799                 if (opt == NULL) { 
  800                         vfs_mount_error(mp, "illegal readahead");
  801                         error = EINVAL;
  802                         goto out;
  803                 }
  804                 ret = sscanf(opt, "%d", &args.readahead);
  805                 if (ret != 1 || args.readahead <= 0) {
  806                         vfs_mount_error(mp, "illegal readahead: %s",
  807                             opt);
  808                         error = EINVAL;
  809                         goto out;
  810                 }
  811                 args.flags |= NFSMNT_READAHEAD;
  812         }
  813         if (vfs_getopt(mp->mnt_optnew, "wsize", (void **)&opt, NULL) == 0) {
  814                 if (opt == NULL) { 
  815                         vfs_mount_error(mp, "illegal wsize");
  816                         error = EINVAL;
  817                         goto out;
  818                 }
  819                 ret = sscanf(opt, "%d", &args.wsize);
  820                 if (ret != 1 || args.wsize <= 0) {
  821                         vfs_mount_error(mp, "illegal wsize: %s",
  822                             opt);
  823                         error = EINVAL;
  824                         goto out;
  825                 }
  826                 args.flags |= NFSMNT_WSIZE;
  827         }
  828         if (vfs_getopt(mp->mnt_optnew, "rsize", (void **)&opt, NULL) == 0) {
  829                 if (opt == NULL) { 
  830                         vfs_mount_error(mp, "illegal rsize");
  831                         error = EINVAL;
  832                         goto out;
  833                 }
  834                 ret = sscanf(opt, "%d", &args.rsize);
  835                 if (ret != 1 || args.rsize <= 0) {
  836                         vfs_mount_error(mp, "illegal wsize: %s",
  837                             opt);
  838                         error = EINVAL;
  839                         goto out;
  840                 }
  841                 args.flags |= NFSMNT_RSIZE;
  842         }
  843         if (vfs_getopt(mp->mnt_optnew, "retrans", (void **)&opt, NULL) == 0) {
  844                 if (opt == NULL) { 
  845                         vfs_mount_error(mp, "illegal retrans");
  846                         error = EINVAL;
  847                         goto out;
  848                 }
  849                 ret = sscanf(opt, "%d", &args.retrans);
  850                 if (ret != 1 || args.retrans <= 0) {
  851                         vfs_mount_error(mp, "illegal retrans: %s",
  852                             opt);
  853                         error = EINVAL;
  854                         goto out;
  855                 }
  856                 args.flags |= NFSMNT_RETRANS;
  857         }
  858         if (vfs_getopt(mp->mnt_optnew, "acregmin", (void **)&opt, NULL) == 0) {
  859                 ret = sscanf(opt, "%d", &args.acregmin);
  860                 if (ret != 1 || args.acregmin < 0) {
  861                         vfs_mount_error(mp, "illegal acregmin: %s",
  862                             opt);
  863                         error = EINVAL;
  864                         goto out;
  865                 }
  866                 args.flags |= NFSMNT_ACREGMIN;
  867         }
  868         if (vfs_getopt(mp->mnt_optnew, "acregmax", (void **)&opt, NULL) == 0) {
  869                 ret = sscanf(opt, "%d", &args.acregmax);
  870                 if (ret != 1 || args.acregmax < 0) {
  871                         vfs_mount_error(mp, "illegal acregmax: %s",
  872                             opt);
  873                         error = EINVAL;
  874                         goto out;
  875                 }
  876                 args.flags |= NFSMNT_ACREGMAX;
  877         }
  878         if (vfs_getopt(mp->mnt_optnew, "acdirmin", (void **)&opt, NULL) == 0) {
  879                 ret = sscanf(opt, "%d", &args.acdirmin);
  880                 if (ret != 1 || args.acdirmin < 0) {
  881                         vfs_mount_error(mp, "illegal acdirmin: %s",
  882                             opt);
  883                         error = EINVAL;
  884                         goto out;
  885                 }
  886                 args.flags |= NFSMNT_ACDIRMIN;
  887         }
  888         if (vfs_getopt(mp->mnt_optnew, "acdirmax", (void **)&opt, NULL) == 0) {
  889                 ret = sscanf(opt, "%d", &args.acdirmax);
  890                 if (ret != 1 || args.acdirmax < 0) {
  891                         vfs_mount_error(mp, "illegal acdirmax: %s",
  892                             opt);
  893                         error = EINVAL;
  894                         goto out;
  895                 }
  896                 args.flags |= NFSMNT_ACDIRMAX;
  897         }
  898         if (vfs_getopt(mp->mnt_optnew, "timeout", (void **)&opt, NULL) == 0) {
  899                 ret = sscanf(opt, "%d", &args.timeo);
  900                 if (ret != 1 || args.timeo <= 0) {
  901                         vfs_mount_error(mp, "illegal timeout: %s",
  902                             opt);
  903                         error = EINVAL;
  904                         goto out;
  905                 }
  906                 args.flags |= NFSMNT_TIMEO;
  907         }
  908         if (vfs_getopt(mp->mnt_optnew, "negnametimeo", (void **)&opt, NULL)
  909             == 0) {
  910                 ret = sscanf(opt, "%d", &negnametimeo);
  911                 if (ret != 1 || negnametimeo < 0) {
  912                         vfs_mount_error(mp, "illegal negnametimeo: %s",
  913                             opt);
  914                         error = EINVAL;
  915                         goto out;
  916                 }
  917         }
  918         if (vfs_getopt(mp->mnt_optnew, "sec",
  919                 (void **) &secname, NULL) == 0)
  920                 nfs_sec_name(secname, &args.flags);
  921 
  922         if (mp->mnt_flag & MNT_UPDATE) {
  923                 struct nfsmount *nmp = VFSTONFS(mp);
  924 
  925                 if (nmp == NULL) {
  926                         error = EIO;
  927                         goto out;
  928                 }
  929                 /*
  930                  * When doing an update, we can't change version,
  931                  * security, switch lockd strategies or change cookie
  932                  * translation
  933                  */
  934                 args.flags = (args.flags &
  935                     ~(NFSMNT_NFSV3 |
  936                       NFSMNT_NFSV4 |
  937                       NFSMNT_KERB |
  938                       NFSMNT_INTEGRITY |
  939                       NFSMNT_PRIVACY |
  940                       NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)) |
  941                     (nmp->nm_flag &
  942                         (NFSMNT_NFSV3 |
  943                          NFSMNT_NFSV4 |
  944                          NFSMNT_KERB |
  945                          NFSMNT_INTEGRITY |
  946                          NFSMNT_PRIVACY |
  947                          NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/));
  948                 nfs_decode_args(mp, nmp, &args, NULL, td->td_ucred, td);
  949                 goto out;
  950         }
  951 
  952         /*
  953          * Make the nfs_ip_paranoia sysctl serve as the default connection
  954          * or no-connection mode for those protocols that support 
  955          * no-connection mode (the flag will be cleared later for protocols
  956          * that do not support no-connection mode).  This will allow a client
  957          * to receive replies from a different IP then the request was
  958          * sent to.  Note: default value for nfs_ip_paranoia is 1 (paranoid),
  959          * not 0.
  960          */
  961         if (nfs_ip_paranoia == 0)
  962                 args.flags |= NFSMNT_NOCONN;
  963 
  964         if (vfs_getopt(mp->mnt_optnew, "fh", (void **)&args.fh,
  965             &args.fhsize) == 0) {
  966                 if (args.fhsize < 0 || args.fhsize > NFSX_FHMAX) {
  967                         vfs_mount_error(mp, "Bad file handle");
  968                         error = EINVAL;
  969                         goto out;
  970                 }
  971                 bcopy(args.fh, nfh, args.fhsize);
  972         } else {
  973                 args.fhsize = 0;
  974         }
  975 
  976         (void) vfs_getopt(mp->mnt_optnew, "hostname", (void **)&args.hostname,
  977             &len);
  978         if (args.hostname == NULL) {
  979                 vfs_mount_error(mp, "Invalid hostname");
  980                 error = EINVAL;
  981                 goto out;
  982         }
  983         bcopy(args.hostname, hst, MNAMELEN);
  984         hst[MNAMELEN - 1] = '\0';
  985 
  986         if (vfs_getopt(mp->mnt_optnew, "principal", (void **)&name, NULL) == 0)
  987                 strlcpy(srvkrbname, name, sizeof (srvkrbname));
  988         else
  989                 snprintf(srvkrbname, sizeof (srvkrbname), "nfs@%s", hst);
  990         args.srvkrbnamelen = strlen(srvkrbname);
  991 
  992         if (vfs_getopt(mp->mnt_optnew, "gssname", (void **)&name, NULL) == 0)
  993                 strlcpy(krbname, name, sizeof (krbname));
  994         else
  995                 krbname[0] = '\0';
  996         args.krbnamelen = strlen(krbname);
  997 
  998         if (vfs_getopt(mp->mnt_optnew, "dirpath", (void **)&name, NULL) == 0)
  999                 strlcpy(dirpath, name, sizeof (dirpath));
 1000         else
 1001                 dirpath[0] = '\0';
 1002         args.dirlen = strlen(dirpath);
 1003 
 1004         if (vfs_getopt(mp->mnt_optnew, "addr", (void **)&args.addr,
 1005             &args.addrlen) == 0) {
 1006                 if (args.addrlen > SOCK_MAXADDRLEN) {
 1007                         error = ENAMETOOLONG;
 1008                         goto out;
 1009                 }
 1010                 nam = malloc(args.addrlen, M_SONAME, M_WAITOK);
 1011                 bcopy(args.addr, nam, args.addrlen);
 1012                 nam->sa_len = args.addrlen;
 1013         }
 1014 
 1015         args.fh = nfh;
 1016         error = mountnfs(&args, mp, nam, hst, krbname, dirpath, srvkrbname,
 1017             &vp, td->td_ucred, td, negnametimeo);
 1018 out:
 1019         if (!error) {
 1020                 MNT_ILOCK(mp);
 1021                 mp->mnt_kern_flag |= (MNTK_MPSAFE|MNTK_LOOKUP_SHARED);
 1022                 MNT_IUNLOCK(mp);
 1023         }
 1024         return (error);
 1025 }
 1026 
 1027 
 1028 /*
 1029  * VFS Operations.
 1030  *
 1031  * mount system call
 1032  * It seems a bit dumb to copyinstr() the host and path here and then
 1033  * bcopy() them in mountnfs(), but I wanted to detect errors before
 1034  * doing the sockargs() call because sockargs() allocates an mbuf and
 1035  * an error after that means that I have to release the mbuf.
 1036  */
 1037 /* ARGSUSED */
 1038 static int
 1039 nfs_cmount(struct mntarg *ma, void *data, int flags)
 1040 {
 1041         int error;
 1042         struct nfs_args args;
 1043 
 1044         error = copyin(data, &args, sizeof (struct nfs_args));
 1045         if (error)
 1046                 return error;
 1047 
 1048         ma = mount_arg(ma, "nfs_args", &args, sizeof args);
 1049 
 1050         error = kernel_mount(ma, flags);
 1051         return (error);
 1052 }
 1053 
 1054 /*
 1055  * Common code for mount and mountroot
 1056  */
 1057 static int
 1058 mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
 1059     char *hst, u_char *krbname, u_char *dirpath, u_char *srvkrbname,
 1060     struct vnode **vpp, struct ucred *cred, struct thread *td,
 1061     int negnametimeo)
 1062 {
 1063         struct nfsmount *nmp;
 1064         struct nfsnode *np;
 1065         int error, trycnt, ret;
 1066         struct nfsvattr nfsva;
 1067         static u_int64_t clval = 0;
 1068 
 1069         if (mp->mnt_flag & MNT_UPDATE) {
 1070                 nmp = VFSTONFS(mp);
 1071                 printf("%s: MNT_UPDATE is no longer handled here\n", __func__);
 1072                 FREE(nam, M_SONAME);
 1073                 return (0);
 1074         } else {
 1075                 MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount) +
 1076                     argp->krbnamelen + argp->dirlen + argp->srvkrbnamelen + 2,
 1077                     M_NEWNFSMNT, M_WAITOK);
 1078                 bzero((caddr_t)nmp, sizeof (struct nfsmount) +
 1079                     argp->krbnamelen + argp->dirlen + argp->srvkrbnamelen + 2);
 1080                 TAILQ_INIT(&nmp->nm_bufq);
 1081                 if (clval == 0)
 1082                         clval = (u_int64_t)nfsboottime.tv_sec;
 1083                 nmp->nm_clval = clval++;
 1084                 nmp->nm_krbnamelen = argp->krbnamelen;
 1085                 nmp->nm_dirpathlen = argp->dirlen;
 1086                 nmp->nm_srvkrbnamelen = argp->srvkrbnamelen;
 1087                 if (td->td_ucred->cr_uid != (uid_t)0) {
 1088                         /*
 1089                          * nm_uid is used to get KerberosV credentials for
 1090                          * the nfsv4 state handling operations if there is
 1091                          * no host based principal set. Use the uid of
 1092                          * this user if not root, since they are doing the
 1093                          * mount. I don't think setting this for root will
 1094                          * work, since root normally does not have user
 1095                          * credentials in a credentials cache.
 1096                          */
 1097                         nmp->nm_uid = td->td_ucred->cr_uid;
 1098                 } else {
 1099                         /*
 1100                          * Just set to -1, so it won't be used.
 1101                          */
 1102                         nmp->nm_uid = (uid_t)-1;
 1103                 }
 1104 
 1105                 /* Copy and null terminate all the names */
 1106                 if (nmp->nm_krbnamelen > 0) {
 1107                         bcopy(krbname, nmp->nm_krbname, nmp->nm_krbnamelen);
 1108                         nmp->nm_name[nmp->nm_krbnamelen] = '\0';
 1109                 }
 1110                 if (nmp->nm_dirpathlen > 0) {
 1111                         bcopy(dirpath, NFSMNT_DIRPATH(nmp),
 1112                             nmp->nm_dirpathlen);
 1113                         nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen
 1114                             + 1] = '\0';
 1115                 }
 1116                 if (nmp->nm_srvkrbnamelen > 0) {
 1117                         bcopy(srvkrbname, NFSMNT_SRVKRBNAME(nmp),
 1118                             nmp->nm_srvkrbnamelen);
 1119                         nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen
 1120                             + nmp->nm_srvkrbnamelen + 2] = '\0';
 1121                 }
 1122                 nmp->nm_sockreq.nr_cred = crhold(cred);
 1123                 mtx_init(&nmp->nm_sockreq.nr_mtx, "nfssock", NULL, MTX_DEF);
 1124                 mp->mnt_data = nmp;
 1125                 nmp->nm_getinfo = nfs_getnlminfo;
 1126         }
 1127         vfs_getnewfsid(mp);
 1128         nmp->nm_mountp = mp;
 1129         mtx_init(&nmp->nm_mtx, "NFSmount lock", NULL, MTX_DEF | MTX_DUPOK);                     
 1130         nmp->nm_negnametimeo = negnametimeo;
 1131 
 1132         nfs_decode_args(mp, nmp, argp, hst, cred, td);
 1133 
 1134         /*
 1135          * V2 can only handle 32 bit filesizes.  A 4GB-1 limit may be too
 1136          * high, depending on whether we end up with negative offsets in
 1137          * the client or server somewhere.  2GB-1 may be safer.
 1138          *
 1139          * For V3, ncl_fsinfo will adjust this as necessary.  Assume maximum
 1140          * that we can handle until we find out otherwise.
 1141          * XXX Our "safe" limit on the client is what we can store in our
 1142          * buffer cache using signed(!) block numbers.
 1143          */
 1144         if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0)
 1145                 nmp->nm_maxfilesize = 0xffffffffLL;
 1146         else
 1147                 nmp->nm_maxfilesize = (u_int64_t)0x80000000 * DEV_BSIZE - 1;
 1148 
 1149         nmp->nm_timeo = NFS_TIMEO;
 1150         nmp->nm_retry = NFS_RETRANS;
 1151         if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) {
 1152                 nmp->nm_wsize = NFS_WSIZE;
 1153                 nmp->nm_rsize = NFS_RSIZE;
 1154                 nmp->nm_readdirsize = NFS_READDIRSIZE;
 1155         }
 1156         nmp->nm_wcommitsize = hibufspace / (desiredvnodes / 1000);
 1157         nmp->nm_numgrps = NFS_MAXGRPS;
 1158         nmp->nm_readahead = NFS_DEFRAHEAD;
 1159         nmp->nm_tprintf_delay = nfs_tprintf_delay;
 1160         if (nmp->nm_tprintf_delay < 0)
 1161                 nmp->nm_tprintf_delay = 0;
 1162         nmp->nm_tprintf_initial_delay = nfs_tprintf_initial_delay;
 1163         if (nmp->nm_tprintf_initial_delay < 0)
 1164                 nmp->nm_tprintf_initial_delay = 0;
 1165         nmp->nm_fhsize = argp->fhsize;
 1166         if (nmp->nm_fhsize > 0)
 1167                 bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize);
 1168         bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
 1169         nmp->nm_nam = nam;
 1170         /* Set up the sockets and per-host congestion */
 1171         nmp->nm_sotype = argp->sotype;
 1172         nmp->nm_soproto = argp->proto;
 1173         nmp->nm_sockreq.nr_prog = NFS_PROG;
 1174         if ((argp->flags & NFSMNT_NFSV4))
 1175                 nmp->nm_sockreq.nr_vers = NFS_VER4;
 1176         else if ((argp->flags & NFSMNT_NFSV3))
 1177                 nmp->nm_sockreq.nr_vers = NFS_VER3;
 1178         else
 1179                 nmp->nm_sockreq.nr_vers = NFS_VER2;
 1180 
 1181 
 1182         if ((error = newnfs_connect(nmp, &nmp->nm_sockreq, cred, td, 0)))
 1183                 goto bad;
 1184 
 1185         /*
 1186          * A reference count is needed on the nfsnode representing the
 1187          * remote root.  If this object is not persistent, then backward
 1188          * traversals of the mount point (i.e. "..") will not work if
 1189          * the nfsnode gets flushed out of the cache. Ufs does not have
 1190          * this problem, because one can identify root inodes by their
 1191          * number == ROOTINO (2).
 1192          */
 1193         if (nmp->nm_fhsize == 0 && (nmp->nm_flag & NFSMNT_NFSV4) &&
 1194             nmp->nm_dirpathlen > 0) {
 1195                 /*
 1196                  * If the fhsize on the mount point == 0 for V4, the mount
 1197                  * path needs to be looked up.
 1198                  */
 1199                 trycnt = 3;
 1200                 do {
 1201                         error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp),
 1202                             cred, td);
 1203                         if (error)
 1204                                 (void) nfs_catnap(PZERO, error, "nfsgetdirp");
 1205                 } while (error && --trycnt > 0);
 1206                 if (error) {
 1207                         error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0);
 1208                         goto bad;
 1209                 }
 1210         }
 1211         if (nmp->nm_fhsize > 0) {
 1212                 /*
 1213                  * Set f_iosize to NFS_DIRBLKSIZ so that bo_bsize gets set
 1214                  * non-zero for the root vnode. f_iosize will be set correctly
 1215                  * by nfs_statfs() before any I/O occurs.
 1216                  */
 1217                 mp->mnt_stat.f_iosize = NFS_DIRBLKSIZ;
 1218                 error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np);
 1219                 if (error)
 1220                         goto bad;
 1221                 *vpp = NFSTOV(np);
 1222         
 1223                 /*
 1224                  * Get file attributes and transfer parameters for the
 1225                  * mountpoint.  This has the side effect of filling in
 1226                  * (*vpp)->v_type with the correct value.
 1227                  */
 1228                 ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1,
 1229                     cred, td, &nfsva, NULL);
 1230                 if (ret) {
 1231                         /*
 1232                          * Just set default values to get things going.
 1233                          */
 1234                         NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr));
 1235                         nfsva.na_vattr.va_type = VDIR;
 1236                         nfsva.na_vattr.va_mode = 0777;
 1237                         nfsva.na_vattr.va_nlink = 100;
 1238                         nfsva.na_vattr.va_uid = (uid_t)0;
 1239                         nfsva.na_vattr.va_gid = (gid_t)0;
 1240                         nfsva.na_vattr.va_fileid = 2;
 1241                         nfsva.na_vattr.va_gen = 1;
 1242                         nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE;
 1243                         nfsva.na_vattr.va_size = 512 * 1024;
 1244                 }
 1245                 (void) nfscl_loadattrcache(vpp, &nfsva, NULL, NULL, 0, 1);
 1246                 if (argp->flags & NFSMNT_NFSV3)
 1247                         ncl_fsinfo(nmp, *vpp, cred, td);
 1248         
 1249                 /*
 1250                  * Lose the lock but keep the ref.
 1251                  */
 1252                 VOP_UNLOCK(*vpp, 0);
 1253                 return (0);
 1254         }
 1255         error = EIO;
 1256 
 1257 bad:
 1258         newnfs_disconnect(&nmp->nm_sockreq);
 1259         crfree(nmp->nm_sockreq.nr_cred);
 1260         mtx_destroy(&nmp->nm_sockreq.nr_mtx);
 1261         mtx_destroy(&nmp->nm_mtx);
 1262         FREE(nmp, M_NEWNFSMNT);
 1263         FREE(nam, M_SONAME);
 1264         return (error);
 1265 }
 1266 
 1267 /*
 1268  * unmount system call
 1269  */
 1270 static int
 1271 nfs_unmount(struct mount *mp, int mntflags)
 1272 {
 1273         struct thread *td;
 1274         struct nfsmount *nmp;
 1275         int error, flags = 0, trycnt = 0;
 1276 
 1277         td = curthread;
 1278 
 1279         if (mntflags & MNT_FORCE)
 1280                 flags |= FORCECLOSE;
 1281         nmp = VFSTONFS(mp);
 1282         /*
 1283          * Goes something like this..
 1284          * - Call vflush() to clear out vnodes for this filesystem
 1285          * - Close the socket
 1286          * - Free up the data structures
 1287          */
 1288         /* In the forced case, cancel any outstanding requests. */
 1289         if (mntflags & MNT_FORCE) {
 1290                 error = newnfs_nmcancelreqs(nmp);
 1291                 if (error)
 1292                         goto out;
 1293                 /* For a forced close, get rid of the renew thread now */
 1294                 nfscl_umount(nmp, td);
 1295         }
 1296         /* We hold 1 extra ref on the root vnode; see comment in mountnfs(). */
 1297         do {
 1298                 error = vflush(mp, 1, flags, td);
 1299                 if ((mntflags & MNT_FORCE) && error != 0 && ++trycnt < 30)
 1300                         (void) nfs_catnap(PSOCK, error, "newndm");
 1301         } while ((mntflags & MNT_FORCE) && error != 0 && trycnt < 30);
 1302         if (error)
 1303                 goto out;
 1304 
 1305         /*
 1306          * We are now committed to the unmount.
 1307          */
 1308         if ((mntflags & MNT_FORCE) == 0)
 1309                 nfscl_umount(nmp, td);
 1310         newnfs_disconnect(&nmp->nm_sockreq);
 1311         crfree(nmp->nm_sockreq.nr_cred);
 1312         FREE(nmp->nm_nam, M_SONAME);
 1313 
 1314         mtx_destroy(&nmp->nm_sockreq.nr_mtx);
 1315         mtx_destroy(&nmp->nm_mtx);
 1316         FREE(nmp, M_NEWNFSMNT);
 1317 out:
 1318         return (error);
 1319 }
 1320 
 1321 /*
 1322  * Return root of a filesystem
 1323  */
 1324 static int
 1325 nfs_root(struct mount *mp, int flags, struct vnode **vpp)
 1326 {
 1327         struct vnode *vp;
 1328         struct nfsmount *nmp;
 1329         struct nfsnode *np;
 1330         int error;
 1331 
 1332         nmp = VFSTONFS(mp);
 1333         error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np);
 1334         if (error)
 1335                 return error;
 1336         vp = NFSTOV(np);
 1337         /*
 1338          * Get transfer parameters and attributes for root vnode once.
 1339          */
 1340         mtx_lock(&nmp->nm_mtx);
 1341         if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) {
 1342                 mtx_unlock(&nmp->nm_mtx);
 1343                 ncl_fsinfo(nmp, vp, curthread->td_ucred, curthread);
 1344         } else 
 1345                 mtx_unlock(&nmp->nm_mtx);
 1346         if (vp->v_type == VNON)
 1347             vp->v_type = VDIR;
 1348         vp->v_vflag |= VV_ROOT;
 1349         *vpp = vp;
 1350         return (0);
 1351 }
 1352 
 1353 /*
 1354  * Flush out the buffer cache
 1355  */
 1356 /* ARGSUSED */
 1357 static int
 1358 nfs_sync(struct mount *mp, int waitfor)
 1359 {
 1360         struct vnode *vp, *mvp;
 1361         struct thread *td;
 1362         int error, allerror = 0;
 1363 
 1364         td = curthread;
 1365 
 1366         /*
 1367          * Force stale buffer cache information to be flushed.
 1368          */
 1369         MNT_ILOCK(mp);
 1370 loop:
 1371         MNT_VNODE_FOREACH(vp, mp, mvp) {
 1372                 VI_LOCK(vp);
 1373                 MNT_IUNLOCK(mp);
 1374                 /* XXX Racy bv_cnt check. */
 1375                 if (VOP_ISLOCKED(vp) || vp->v_bufobj.bo_dirty.bv_cnt == 0 ||
 1376                     waitfor == MNT_LAZY) {
 1377                         VI_UNLOCK(vp);
 1378                         MNT_ILOCK(mp);
 1379                         continue;
 1380                 }
 1381                 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) {
 1382                         MNT_ILOCK(mp);
 1383                         MNT_VNODE_FOREACH_ABORT_ILOCKED(mp, mvp);
 1384                         goto loop;
 1385                 }
 1386                 error = VOP_FSYNC(vp, waitfor, td);
 1387                 if (error)
 1388                         allerror = error;
 1389                 VOP_UNLOCK(vp, 0);
 1390                 vrele(vp);
 1391 
 1392                 MNT_ILOCK(mp);
 1393         }
 1394         MNT_IUNLOCK(mp);
 1395         return (allerror);
 1396 }
 1397 
 1398 static int
 1399 nfs_sysctl(struct mount *mp, fsctlop_t op, struct sysctl_req *req)
 1400 {
 1401         struct nfsmount *nmp = VFSTONFS(mp);
 1402         struct vfsquery vq;
 1403         int error;
 1404 
 1405         bzero(&vq, sizeof(vq));
 1406         switch (op) {
 1407 #if 0
 1408         case VFS_CTL_NOLOCKS:
 1409                 val = (nmp->nm_flag & NFSMNT_NOLOCKS) ? 1 : 0;
 1410                 if (req->oldptr != NULL) {
 1411                         error = SYSCTL_OUT(req, &val, sizeof(val));
 1412                         if (error)
 1413                                 return (error);
 1414                 }
 1415                 if (req->newptr != NULL) {
 1416                         error = SYSCTL_IN(req, &val, sizeof(val));
 1417                         if (error)
 1418                                 return (error);
 1419                         if (val)
 1420                                 nmp->nm_flag |= NFSMNT_NOLOCKS;
 1421                         else
 1422                                 nmp->nm_flag &= ~NFSMNT_NOLOCKS;
 1423                 }
 1424                 break;
 1425 #endif
 1426         case VFS_CTL_QUERY:
 1427                 mtx_lock(&nmp->nm_mtx);
 1428                 if (nmp->nm_state & NFSSTA_TIMEO)
 1429                         vq.vq_flags |= VQ_NOTRESP;
 1430                 mtx_unlock(&nmp->nm_mtx);
 1431 #if 0
 1432                 if (!(nmp->nm_flag & NFSMNT_NOLOCKS) &&
 1433                     (nmp->nm_state & NFSSTA_LOCKTIMEO))
 1434                         vq.vq_flags |= VQ_NOTRESPLOCK;
 1435 #endif
 1436                 error = SYSCTL_OUT(req, &vq, sizeof(vq));
 1437                 break;
 1438         case VFS_CTL_TIMEO:
 1439                 if (req->oldptr != NULL) {
 1440                         error = SYSCTL_OUT(req, &nmp->nm_tprintf_initial_delay,
 1441                             sizeof(nmp->nm_tprintf_initial_delay));
 1442                         if (error)
 1443                                 return (error);
 1444                 }
 1445                 if (req->newptr != NULL) {
 1446                         error = vfs_suser(mp, req->td);
 1447                         if (error)
 1448                                 return (error);
 1449                         error = SYSCTL_IN(req, &nmp->nm_tprintf_initial_delay,
 1450                             sizeof(nmp->nm_tprintf_initial_delay));
 1451                         if (error)
 1452                                 return (error);
 1453                         if (nmp->nm_tprintf_initial_delay < 0)
 1454                                 nmp->nm_tprintf_initial_delay = 0;
 1455                 }
 1456                 break;
 1457         default:
 1458                 return (ENOTSUP);
 1459         }
 1460         return (0);
 1461 }
 1462 
 1463 /*
 1464  * Extract the information needed by the nlm from the nfs vnode.
 1465  */
 1466 static void
 1467 nfs_getnlminfo(struct vnode *vp, uint8_t *fhp, size_t *fhlenp,
 1468     struct sockaddr_storage *sp, int *is_v3p, off_t *sizep)
 1469 {
 1470         struct nfsmount *nmp;
 1471         struct nfsnode *np = VTONFS(vp);
 1472 
 1473         nmp = VFSTONFS(vp->v_mount);
 1474         if (fhlenp != NULL)
 1475                 *fhlenp = (size_t)np->n_fhp->nfh_len;
 1476         if (fhp != NULL)
 1477                 bcopy(np->n_fhp->nfh_fh, fhp, np->n_fhp->nfh_len);
 1478         if (sp != NULL)
 1479                 bcopy(nmp->nm_nam, sp, min(nmp->nm_nam->sa_len, sizeof(*sp)));
 1480         if (is_v3p != NULL)
 1481                 *is_v3p = NFS_ISV3(vp);
 1482         if (sizep != NULL)
 1483                 *sizep = np->n_size;
 1484 }
 1485 

Cache object: 17c327c23a9fd290e08a37077dfb3d60


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