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

Cache object: c3788f9b5744ee4a356570b7ed70defe


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