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

Cache object: b731924cdcaeb0fe596becc4785274dc


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