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

Cache object: 6ff6cdd84468c1ac30634ee6ed9347c9


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