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  * 3. All advertising materials mentioning features or use of this software
   17  *    must display the following acknowledgement:
   18  *      This product includes software developed by the University of
   19  *      California, Berkeley and its contributors.
   20  * 4. Neither the name of the University nor the names of its contributors
   21  *    may be used to endorse or promote products derived from this software
   22  *    without specific prior written permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   34  * SUCH DAMAGE.
   35  *
   36  *      @(#)nfs_vfsops.c        8.12 (Berkeley) 5/20/95
   37  */
   38 
   39 #include <sys/cdefs.h>
   40 __FBSDID("$FreeBSD: releng/5.1/sys/nfsclient/nfs_vfsops.c 115172 2003-05-19 22:35:00Z peter $");
   41 
   42 #include "opt_bootp.h"
   43 #include "opt_nfsroot.h"
   44 
   45 #include <sys/param.h>
   46 #include <sys/systm.h>
   47 #include <sys/kernel.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 
   61 #include <vm/vm.h>
   62 #include <vm/vm_extern.h>
   63 #include <vm/uma.h>
   64 
   65 #include <net/if.h>
   66 #include <net/route.h>
   67 #include <netinet/in.h>
   68 
   69 #include <nfs/rpcv2.h>
   70 #include <nfs/nfsproto.h>
   71 #include <nfsclient/nfs.h>
   72 #include <nfsclient/nfsnode.h>
   73 #include <nfsclient/nfsmount.h>
   74 #include <nfs/xdr_subs.h>
   75 #include <nfsclient/nfsm_subs.h>
   76 #include <nfsclient/nfsdiskless.h>
   77 
   78 MALLOC_DEFINE(M_NFSREQ, "NFS req", "NFS request header");
   79 MALLOC_DEFINE(M_NFSBIGFH, "NFSV3 bigfh", "NFS version 3 file handle");
   80 MALLOC_DEFINE(M_NFSDIROFF, "NFSV3 diroff", "NFS directory offset data");
   81 MALLOC_DEFINE(M_NFSHASH, "NFS hash", "NFS hash tables");
   82 
   83 uma_zone_t nfsmount_zone;
   84 
   85 struct nfsstats nfsstats;
   86 SYSCTL_NODE(_vfs, OID_AUTO, nfs, CTLFLAG_RW, 0, "NFS filesystem");
   87 SYSCTL_STRUCT(_vfs_nfs, NFS_NFSSTATS, nfsstats, CTLFLAG_RD,
   88         &nfsstats, nfsstats, "S,nfsstats");
   89 static int nfs_ip_paranoia = 1;
   90 SYSCTL_INT(_vfs_nfs, OID_AUTO, nfs_ip_paranoia, CTLFLAG_RW,
   91     &nfs_ip_paranoia, 0, "");
   92 #ifdef NFS_DEBUG
   93 int nfs_debug;
   94 SYSCTL_INT(_vfs_nfs, OID_AUTO, debug, CTLFLAG_RW, &nfs_debug, 0, "");
   95 #endif
   96 
   97 static int      nfs_iosize(struct nfsmount *nmp);
   98 static void     nfs_decode_args(struct nfsmount *nmp, struct nfs_args *argp);
   99 static int      mountnfs(struct nfs_args *, struct mount *,
  100                     struct sockaddr *, char *, char *, struct vnode **,
  101                     struct ucred *cred);
  102 static vfs_mount_t nfs_mount;
  103 static vfs_unmount_t nfs_unmount;
  104 static vfs_root_t nfs_root;
  105 static vfs_statfs_t nfs_statfs;
  106 static vfs_sync_t nfs_sync;
  107 
  108 /*
  109  * nfs vfs operations.
  110  */
  111 static struct vfsops nfs_vfsops = {
  112         nfs_mount,
  113         vfs_stdstart,
  114         nfs_unmount,
  115         nfs_root,
  116         vfs_stdquotactl,
  117         nfs_statfs,
  118         nfs_sync,
  119         vfs_stdvget,
  120         vfs_stdfhtovp,          /* shouldn't happen */
  121         vfs_stdcheckexp,
  122         vfs_stdvptofh,          /* shouldn't happen */
  123         nfs_init,
  124         nfs_uninit,
  125         vfs_stdextattrctl,
  126 };
  127 VFS_SET(nfs_vfsops, nfs, VFCF_NETWORK);
  128 
  129 /* So that loader and kldload(2) can find us, wherever we are.. */
  130 MODULE_VERSION(nfs, 1);
  131 
  132 /*
  133  * This structure must be filled in by a primary bootstrap or bootstrap
  134  * server for a diskless/dataless machine. It is initialized below just
  135  * to ensure that it is allocated to initialized data (.data not .bss).
  136  */
  137 struct nfs_diskless nfs_diskless = { { { 0 } } };
  138 struct nfsv3_diskless nfsv3_diskless = { { { 0 } } };
  139 int nfs_diskless_valid = 0;
  140 
  141 SYSCTL_INT(_vfs_nfs, OID_AUTO, diskless_valid, CTLFLAG_RD,
  142         &nfs_diskless_valid, 0, "");
  143 
  144 SYSCTL_STRING(_vfs_nfs, OID_AUTO, diskless_rootpath, CTLFLAG_RD,
  145         nfsv3_diskless.root_hostnam, 0, "");
  146 
  147 SYSCTL_OPAQUE(_vfs_nfs, OID_AUTO, diskless_rootaddr, CTLFLAG_RD,
  148         &nfsv3_diskless.root_saddr, sizeof nfsv3_diskless.root_saddr,
  149         "%Ssockaddr_in", "");
  150 
  151 SYSCTL_STRING(_vfs_nfs, OID_AUTO, diskless_swappath, CTLFLAG_RD,
  152         nfsv3_diskless.swap_hostnam, 0, "");
  153 
  154 SYSCTL_OPAQUE(_vfs_nfs, OID_AUTO, diskless_swapaddr, CTLFLAG_RD,
  155         &nfsv3_diskless.swap_saddr, sizeof nfsv3_diskless.swap_saddr,
  156         "%Ssockaddr_in","");
  157 
  158 
  159 void            nfsargs_ntoh(struct nfs_args *);
  160 static int      nfs_mountdiskless(char *, char *, int,
  161                     struct sockaddr_in *, struct nfs_args *,
  162                     struct thread *, struct vnode **, struct mount **);
  163 static void     nfs_convert_diskless(void);
  164 static void     nfs_convert_oargs(struct nfs_args *args,
  165                     struct onfs_args *oargs);
  166 
  167 static int
  168 nfs_iosize(struct nfsmount *nmp)
  169 {
  170         int iosize;
  171 
  172         /*
  173          * Calculate the size used for io buffers.  Use the larger
  174          * of the two sizes to minimise nfs requests but make sure
  175          * that it is at least one VM page to avoid wasting buffer
  176          * space.
  177          */
  178         iosize = max(nmp->nm_rsize, nmp->nm_wsize);
  179         if (iosize < PAGE_SIZE) iosize = PAGE_SIZE;
  180         return iosize;
  181 }
  182 
  183 static void
  184 nfs_convert_oargs(struct nfs_args *args, struct onfs_args *oargs)
  185 {
  186 
  187         args->version = NFS_ARGSVERSION;
  188         args->addr = oargs->addr;
  189         args->addrlen = oargs->addrlen;
  190         args->sotype = oargs->sotype;
  191         args->proto = oargs->proto;
  192         args->fh = oargs->fh;
  193         args->fhsize = oargs->fhsize;
  194         args->flags = oargs->flags;
  195         args->wsize = oargs->wsize;
  196         args->rsize = oargs->rsize;
  197         args->readdirsize = oargs->readdirsize;
  198         args->timeo = oargs->timeo;
  199         args->retrans = oargs->retrans;
  200         args->maxgrouplist = oargs->maxgrouplist;
  201         args->readahead = oargs->readahead;
  202         args->deadthresh = oargs->deadthresh;
  203         args->hostname = oargs->hostname;
  204 }
  205 
  206 static void
  207 nfs_convert_diskless(void)
  208 {
  209 
  210         bcopy(&nfs_diskless.myif, &nfsv3_diskless.myif,
  211                 sizeof(struct ifaliasreq));
  212         bcopy(&nfs_diskless.mygateway, &nfsv3_diskless.mygateway,
  213                 sizeof(struct sockaddr_in));
  214         nfs_convert_oargs(&nfsv3_diskless.swap_args,&nfs_diskless.swap_args);
  215         nfsv3_diskless.swap_fhsize = NFSX_V2FH;
  216         bcopy(nfs_diskless.swap_fh, nfsv3_diskless.swap_fh, NFSX_V2FH);
  217         bcopy(&nfs_diskless.swap_saddr,&nfsv3_diskless.swap_saddr,
  218                 sizeof(struct sockaddr_in));
  219         bcopy(nfs_diskless.swap_hostnam, nfsv3_diskless.swap_hostnam, MNAMELEN);
  220         nfsv3_diskless.swap_nblks = nfs_diskless.swap_nblks;
  221         bcopy(&nfs_diskless.swap_ucred, &nfsv3_diskless.swap_ucred,
  222                 sizeof(struct ucred));
  223         nfs_convert_oargs(&nfsv3_diskless.root_args,&nfs_diskless.root_args);
  224         nfsv3_diskless.root_fhsize = NFSX_V2FH;
  225         bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_V2FH);
  226         bcopy(&nfs_diskless.root_saddr,&nfsv3_diskless.root_saddr,
  227                 sizeof(struct sockaddr_in));
  228         bcopy(nfs_diskless.root_hostnam, nfsv3_diskless.root_hostnam, MNAMELEN);
  229         nfsv3_diskless.root_time = nfs_diskless.root_time;
  230         bcopy(nfs_diskless.my_hostnam, nfsv3_diskless.my_hostnam,
  231                 MAXHOSTNAMELEN);
  232         nfs_diskless_valid = 3;
  233 }
  234 
  235 /*
  236  * nfs statfs call
  237  */
  238 static int
  239 nfs_statfs(struct mount *mp, struct statfs *sbp, struct thread *td)
  240 {
  241         struct vnode *vp;
  242         struct nfs_statfs *sfp;
  243         caddr_t bpos, dpos;
  244         struct nfsmount *nmp = VFSTONFS(mp);
  245         int error = 0, v3 = (nmp->nm_flag & NFSMNT_NFSV3), retattr;
  246         struct mbuf *mreq, *mrep, *md, *mb;
  247         struct nfsnode *np;
  248         u_quad_t tquad;
  249         int bsize;
  250 
  251 #ifndef nolint
  252         sfp = NULL;
  253 #endif
  254         error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
  255         if (error)
  256                 return (error);
  257         vp = NFSTOV(np);
  258         if (v3 && (nmp->nm_state & NFSSTA_GOTFSINFO) == 0)
  259                 (void)nfs_fsinfo(nmp, vp, td->td_ucred, td);
  260         nfsstats.rpccnt[NFSPROC_FSSTAT]++;
  261         mreq = nfsm_reqhead(vp, NFSPROC_FSSTAT, NFSX_FH(v3));
  262         mb = mreq;
  263         bpos = mtod(mb, caddr_t);
  264         nfsm_fhtom(vp, v3);
  265         nfsm_request(vp, NFSPROC_FSSTAT, td, td->td_ucred);
  266         if (v3)
  267                 nfsm_postop_attr(vp, retattr);
  268         if (error) {
  269                 if (mrep != NULL)
  270                         m_freem(mrep);
  271                 goto nfsmout;
  272         }
  273         sfp = nfsm_dissect(struct nfs_statfs *, NFSX_STATFS(v3));
  274         sbp->f_flags = nmp->nm_flag;
  275         sbp->f_iosize = nfs_iosize(nmp);
  276         if (v3) {
  277                 for (bsize = NFS_FABLKSIZE; ; bsize *= 2) {
  278                         sbp->f_bsize = bsize;
  279                         tquad = fxdr_hyper(&sfp->sf_tbytes);
  280                         if (((long)(tquad / bsize) > LONG_MAX) ||
  281                             ((long)(tquad / bsize) < LONG_MIN))
  282                                 continue;
  283                         sbp->f_blocks = tquad / bsize;
  284                         tquad = fxdr_hyper(&sfp->sf_fbytes);
  285                         if (((long)(tquad / bsize) > LONG_MAX) ||
  286                             ((long)(tquad / bsize) < LONG_MIN))
  287                                 continue;
  288                         sbp->f_bfree = tquad / bsize;
  289                         tquad = fxdr_hyper(&sfp->sf_abytes);
  290                         if (((long)(tquad / bsize) > LONG_MAX) ||
  291                             ((long)(tquad / bsize) < LONG_MIN))
  292                                 continue;
  293                         sbp->f_bavail = tquad / bsize;
  294                         sbp->f_files = (fxdr_unsigned(int32_t,
  295                             sfp->sf_tfiles.nfsuquad[1]) & 0x7fffffff);
  296                         sbp->f_ffree = (fxdr_unsigned(int32_t,
  297                             sfp->sf_ffiles.nfsuquad[1]) & 0x7fffffff);
  298                         break;
  299                 }
  300         } else {
  301                 sbp->f_bsize = fxdr_unsigned(int32_t, sfp->sf_bsize);
  302                 sbp->f_blocks = fxdr_unsigned(int32_t, sfp->sf_blocks);
  303                 sbp->f_bfree = fxdr_unsigned(int32_t, sfp->sf_bfree);
  304                 sbp->f_bavail = fxdr_unsigned(int32_t, sfp->sf_bavail);
  305                 sbp->f_files = 0;
  306                 sbp->f_ffree = 0;
  307         }
  308         if (sbp != &mp->mnt_stat) {
  309                 sbp->f_type = mp->mnt_vfc->vfc_typenum;
  310                 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
  311                 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
  312         }
  313         m_freem(mrep);
  314 nfsmout:
  315         vput(vp);
  316         return (error);
  317 }
  318 
  319 /*
  320  * nfs version 3 fsinfo rpc call
  321  */
  322 int
  323 nfs_fsinfo(struct nfsmount *nmp, struct vnode *vp, struct ucred *cred,
  324     struct thread *td)
  325 {
  326         struct nfsv3_fsinfo *fsp;
  327         u_int32_t pref, max;
  328         caddr_t bpos, dpos;
  329         int error = 0, retattr;
  330         struct mbuf *mreq, *mrep, *md, *mb;
  331         u_int64_t maxfsize;
  332 
  333         nfsstats.rpccnt[NFSPROC_FSINFO]++;
  334         mreq = nfsm_reqhead(vp, NFSPROC_FSINFO, NFSX_FH(1));
  335         mb = mreq;
  336         bpos = mtod(mb, caddr_t);
  337         nfsm_fhtom(vp, 1);
  338         nfsm_request(vp, NFSPROC_FSINFO, td, cred);
  339         nfsm_postop_attr(vp, retattr);
  340         if (!error) {
  341                 fsp = nfsm_dissect(struct nfsv3_fsinfo *, NFSX_V3FSINFO);
  342                 pref = fxdr_unsigned(u_int32_t, fsp->fs_wtpref);
  343                 if (pref < nmp->nm_wsize && pref >= NFS_FABLKSIZE)
  344                         nmp->nm_wsize = (pref + NFS_FABLKSIZE - 1) &
  345                                 ~(NFS_FABLKSIZE - 1);
  346                 max = fxdr_unsigned(u_int32_t, fsp->fs_wtmax);
  347                 if (max < nmp->nm_wsize && max > 0) {
  348                         nmp->nm_wsize = max & ~(NFS_FABLKSIZE - 1);
  349                         if (nmp->nm_wsize == 0)
  350                                 nmp->nm_wsize = max;
  351                 }
  352                 pref = fxdr_unsigned(u_int32_t, fsp->fs_rtpref);
  353                 if (pref < nmp->nm_rsize && pref >= NFS_FABLKSIZE)
  354                         nmp->nm_rsize = (pref + NFS_FABLKSIZE - 1) &
  355                                 ~(NFS_FABLKSIZE - 1);
  356                 max = fxdr_unsigned(u_int32_t, fsp->fs_rtmax);
  357                 if (max < nmp->nm_rsize && max > 0) {
  358                         nmp->nm_rsize = max & ~(NFS_FABLKSIZE - 1);
  359                         if (nmp->nm_rsize == 0)
  360                                 nmp->nm_rsize = max;
  361                 }
  362                 pref = fxdr_unsigned(u_int32_t, fsp->fs_dtpref);
  363                 if (pref < nmp->nm_readdirsize && pref >= NFS_DIRBLKSIZ)
  364                         nmp->nm_readdirsize = (pref + NFS_DIRBLKSIZ - 1) &
  365                                 ~(NFS_DIRBLKSIZ - 1);
  366                 if (max < nmp->nm_readdirsize && max > 0) {
  367                         nmp->nm_readdirsize = max & ~(NFS_DIRBLKSIZ - 1);
  368                         if (nmp->nm_readdirsize == 0)
  369                                 nmp->nm_readdirsize = max;
  370                 }
  371                 maxfsize = fxdr_hyper(&fsp->fs_maxfilesize);
  372                 if (maxfsize > 0 && maxfsize < nmp->nm_maxfilesize)
  373                         nmp->nm_maxfilesize = maxfsize;
  374                 nmp->nm_state |= NFSSTA_GOTFSINFO;
  375         }
  376         m_freem(mrep);
  377 nfsmout:
  378         return (error);
  379 }
  380 
  381 /*
  382  * Mount a remote root fs via. nfs. This depends on the info in the
  383  * nfs_diskless structure that has been filled in properly by some primary
  384  * bootstrap.
  385  * It goes something like this:
  386  * - do enough of "ifconfig" by calling ifioctl() so that the system
  387  *   can talk to the server
  388  * - If nfs_diskless.mygateway is filled in, use that address as
  389  *   a default gateway.
  390  * - build the rootfs mount point and call mountnfs() to do the rest.
  391  */
  392 int
  393 nfs_mountroot(struct mount *mp, struct thread *td)
  394 {
  395         struct mount  *swap_mp;
  396         struct nfsv3_diskless *nd = &nfsv3_diskless;
  397         struct socket *so;
  398         struct vnode *vp;
  399         int error, i;
  400         u_long l;
  401         char buf[128];
  402 
  403 #if defined(BOOTP_NFSROOT) && defined(BOOTP)
  404         bootpc_init();          /* use bootp to get nfs_diskless filled in */
  405 #elif defined(NFS_ROOT)
  406         nfs_setup_diskless();
  407 #endif
  408 
  409         if (nfs_diskless_valid == 0)
  410                 return (-1);
  411         if (nfs_diskless_valid == 1)
  412                 nfs_convert_diskless();
  413 
  414         /*
  415          * XXX splnet, so networks will receive...
  416          */
  417         splnet();
  418 
  419 #ifdef notyet
  420         /* Set up swap credentials. */
  421         proc0.p_ucred->cr_uid = ntohl(nd->swap_ucred.cr_uid);
  422         proc0.p_ucred->cr_gid = ntohl(nd->swap_ucred.cr_gid);
  423         if ((proc0.p_ucred->cr_ngroups = ntohs(nd->swap_ucred.cr_ngroups)) >
  424                 NGROUPS)
  425                 proc0.p_ucred->cr_ngroups = NGROUPS;
  426         for (i = 0; i < proc0.p_ucred->cr_ngroups; i++)
  427             proc0.p_ucred->cr_groups[i] = ntohl(nd->swap_ucred.cr_groups[i]);
  428 #endif
  429 
  430         /*
  431          * Do enough of ifconfig(8) so that the critical net interface can
  432          * talk to the server.
  433          */
  434         error = socreate(nd->myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0,
  435             td->td_ucred, td);
  436         if (error)
  437                 panic("nfs_mountroot: socreate(%04x): %d",
  438                         nd->myif.ifra_addr.sa_family, error);
  439 
  440 #if 0 /* XXX Bad idea */
  441         /*
  442          * We might not have been told the right interface, so we pass
  443          * over the first ten interfaces of the same kind, until we get
  444          * one of them configured.
  445          */
  446 
  447         for (i = strlen(nd->myif.ifra_name) - 1;
  448                 nd->myif.ifra_name[i] >= '' &&
  449                 nd->myif.ifra_name[i] <= '9';
  450                 nd->myif.ifra_name[i] ++) {
  451                 error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td);
  452                 if(!error)
  453                         break;
  454         }
  455 #endif
  456         error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td);
  457         if (error)
  458                 panic("nfs_mountroot: SIOCAIFADDR: %d", error);
  459         soclose(so);
  460 
  461         /*
  462          * If the gateway field is filled in, set it as the default route.
  463          * Note that pxeboot will set a default route of 0 if the route
  464          * is not set by the DHCP server.  Check also for a value of 0
  465          * to avoid panicking inappropriately in that situation.
  466          */
  467         if (nd->mygateway.sin_len != 0 &&
  468             nd->mygateway.sin_addr.s_addr != 0) {
  469                 struct sockaddr_in mask, sin;
  470 
  471                 bzero((caddr_t)&mask, sizeof(mask));
  472                 sin = mask;
  473                 sin.sin_family = AF_INET;
  474                 sin.sin_len = sizeof(sin);
  475                 error = rtrequest(RTM_ADD, (struct sockaddr *)&sin,
  476                     (struct sockaddr *)&nd->mygateway,
  477                     (struct sockaddr *)&mask,
  478                     RTF_UP | RTF_GATEWAY, NULL);
  479                 if (error)
  480                         panic("nfs_mountroot: RTM_ADD: %d", error);
  481         }
  482 
  483         /*
  484          * Create the rootfs mount point.
  485          */
  486         nd->root_args.fh = nd->root_fh;
  487         nd->root_args.fhsize = nd->root_fhsize;
  488         l = ntohl(nd->root_saddr.sin_addr.s_addr);
  489         snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s",
  490                 (l >> 24) & 0xff, (l >> 16) & 0xff,
  491                 (l >>  8) & 0xff, (l >>  0) & 0xff, nd->root_hostnam);
  492         printf("NFS ROOT: %s\n", buf);
  493         if ((error = nfs_mountdiskless(buf, "/", MNT_RDONLY,
  494             &nd->root_saddr, &nd->root_args, td, &vp, &mp)) != 0) {
  495                 return (error);
  496         }
  497 
  498         swap_mp = NULL;
  499         if (nd->swap_nblks) {
  500 
  501                 /* Convert to DEV_BSIZE instead of Kilobyte */
  502                 nd->swap_nblks *= 2;
  503 
  504                 /*
  505                  * Create a fake mount point just for the swap vnode so that the
  506                  * swap file can be on a different server from the rootfs.
  507                  */
  508                 nd->swap_args.fh = nd->swap_fh;
  509                 nd->swap_args.fhsize = nd->swap_fhsize;
  510                 l = ntohl(nd->swap_saddr.sin_addr.s_addr);
  511                 snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s",
  512                         (l >> 24) & 0xff, (l >> 16) & 0xff,
  513                         (l >>  8) & 0xff, (l >>  0) & 0xff, nd->swap_hostnam);
  514                 printf("NFS SWAP: %s\n", buf);
  515                 if ((error = nfs_mountdiskless(buf, "/swap", 0,
  516                     &nd->swap_saddr, &nd->swap_args, td, &vp, &swap_mp)) != 0)
  517                         return (error);
  518                 vfs_unbusy(swap_mp, td);
  519 
  520                 VTONFS(vp)->n_size = VTONFS(vp)->n_vattr.va_size =
  521                                 nd->swap_nblks * DEV_BSIZE ;
  522                 /*
  523                  * Since the swap file is not the root dir of a filesystem,
  524                  * hack it to a regular file.
  525                  */
  526                 vp->v_type = VREG;
  527                 vp->v_vflag = 0;
  528                 vp->v_iflag = 0;
  529                 VREF(vp);
  530                 swaponvp(td, vp, NODEV, nd->swap_nblks);
  531         }
  532 
  533         mp->mnt_flag |= MNT_ROOTFS;
  534         mp->mnt_vnodecovered = NULLVP;
  535         rootvp = vp;
  536         vfs_unbusy(mp, td);
  537 
  538         /*
  539          * This is not really an nfs issue, but it is much easier to
  540          * set hostname here and then let the "/etc/rc.xxx" files
  541          * mount the right /var based upon its preset value.
  542          */
  543         bcopy(nd->my_hostnam, hostname, MAXHOSTNAMELEN);
  544         hostname[MAXHOSTNAMELEN - 1] = '\0';
  545         for (i = 0; i < MAXHOSTNAMELEN; i++)
  546                 if (hostname[i] == '\0')
  547                         break;
  548         inittodr(ntohl(nd->root_time));
  549         return (0);
  550 }
  551 
  552 /*
  553  * Internal version of mount system call for diskless setup.
  554  */
  555 static int
  556 nfs_mountdiskless(char *path, char *which, int mountflag,
  557     struct sockaddr_in *sin, struct nfs_args *args, struct thread *td,
  558     struct vnode **vpp, struct mount **mpp)
  559 {
  560         struct mount *mp;
  561         struct sockaddr *nam;
  562         int error;
  563         int didalloc = 0;
  564 
  565         mp = *mpp;
  566 
  567         if (mp == NULL) {
  568                 if ((error = vfs_rootmountalloc("nfs", path, &mp)) != 0) {
  569                         printf("nfs_mountroot: NFS not configured");
  570                         return (error);
  571                 }
  572                 didalloc = 1;
  573         }
  574 
  575         mp->mnt_kern_flag = 0;
  576         mp->mnt_flag = mountflag;
  577         nam = dup_sockaddr((struct sockaddr *)sin, 1);
  578         if ((error = mountnfs(args, mp, nam, which, path, vpp,
  579             td->td_ucred)) != 0) {
  580                 printf("nfs_mountroot: mount %s on %s: %d", path, which, error);
  581                 mp->mnt_vfc->vfc_refcount--;
  582                 vfs_unbusy(mp, td);
  583                 if (didalloc)
  584                         free(mp, M_MOUNT);
  585                 FREE(nam, M_SONAME);
  586                 return (error);
  587         }
  588         (void) copystr(which, mp->mnt_stat.f_mntonname, MNAMELEN - 1, 0);
  589         *mpp = mp;
  590         return (0);
  591 }
  592 
  593 static void
  594 nfs_decode_args(struct nfsmount *nmp, struct nfs_args *argp)
  595 {
  596         int s;
  597         int adjsock;
  598         int maxio;
  599 
  600         s = splnet();
  601         /*
  602          * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes
  603          * no sense in that context.
  604          */
  605         if (argp->sotype == SOCK_STREAM)
  606                 nmp->nm_flag &= ~NFSMNT_NOCONN;
  607 
  608         /* Also clear RDIRPLUS if not NFSv3, it crashes some servers */
  609         if ((argp->flags & NFSMNT_NFSV3) == 0)
  610                 nmp->nm_flag &= ~NFSMNT_RDIRPLUS;
  611 
  612         /* Re-bind if rsrvd port requested and wasn't on one */
  613         adjsock = !(nmp->nm_flag & NFSMNT_RESVPORT)
  614                   && (argp->flags & NFSMNT_RESVPORT);
  615         /* Also re-bind if we're switching to/from a connected UDP socket */
  616         adjsock |= ((nmp->nm_flag & NFSMNT_NOCONN) !=
  617                     (argp->flags & NFSMNT_NOCONN));
  618 
  619         /* Update flags atomically.  Don't change the lock bits. */
  620         nmp->nm_flag = argp->flags | nmp->nm_flag;
  621         splx(s);
  622 
  623         if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
  624                 nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
  625                 if (nmp->nm_timeo < NFS_MINTIMEO)
  626                         nmp->nm_timeo = NFS_MINTIMEO;
  627                 else if (nmp->nm_timeo > NFS_MAXTIMEO)
  628                         nmp->nm_timeo = NFS_MAXTIMEO;
  629         }
  630 
  631         if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
  632                 nmp->nm_retry = argp->retrans;
  633                 if (nmp->nm_retry > NFS_MAXREXMIT)
  634                         nmp->nm_retry = NFS_MAXREXMIT;
  635         }
  636 
  637         if (argp->flags & NFSMNT_NFSV3) {
  638                 if (argp->sotype == SOCK_DGRAM)
  639                         maxio = NFS_MAXDGRAMDATA;
  640                 else
  641                         maxio = NFS_MAXDATA;
  642         } else
  643                 maxio = NFS_V2MAXDATA;
  644 
  645         if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
  646                 nmp->nm_wsize = argp->wsize;
  647                 /* Round down to multiple of blocksize */
  648                 nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1);
  649                 if (nmp->nm_wsize <= 0)
  650                         nmp->nm_wsize = NFS_FABLKSIZE;
  651         }
  652         if (nmp->nm_wsize > maxio)
  653                 nmp->nm_wsize = maxio;
  654         if (nmp->nm_wsize > MAXBSIZE)
  655                 nmp->nm_wsize = MAXBSIZE;
  656 
  657         if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
  658                 nmp->nm_rsize = argp->rsize;
  659                 /* Round down to multiple of blocksize */
  660                 nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1);
  661                 if (nmp->nm_rsize <= 0)
  662                         nmp->nm_rsize = NFS_FABLKSIZE;
  663         }
  664         if (nmp->nm_rsize > maxio)
  665                 nmp->nm_rsize = maxio;
  666         if (nmp->nm_rsize > MAXBSIZE)
  667                 nmp->nm_rsize = MAXBSIZE;
  668 
  669         if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) {
  670                 nmp->nm_readdirsize = argp->readdirsize;
  671         }
  672         if (nmp->nm_readdirsize > maxio)
  673                 nmp->nm_readdirsize = maxio;
  674         if (nmp->nm_readdirsize > nmp->nm_rsize)
  675                 nmp->nm_readdirsize = nmp->nm_rsize;
  676 
  677         if ((argp->flags & NFSMNT_ACREGMIN) && argp->acregmin >= 0)
  678                 nmp->nm_acregmin = argp->acregmin;
  679         else
  680                 nmp->nm_acregmin = NFS_MINATTRTIMO;
  681         if ((argp->flags & NFSMNT_ACREGMAX) && argp->acregmax >= 0)
  682                 nmp->nm_acregmax = argp->acregmax;
  683         else
  684                 nmp->nm_acregmax = NFS_MAXATTRTIMO;
  685         if ((argp->flags & NFSMNT_ACDIRMIN) && argp->acdirmin >= 0)
  686                 nmp->nm_acdirmin = argp->acdirmin;
  687         else
  688                 nmp->nm_acdirmin = NFS_MINDIRATTRTIMO;
  689         if ((argp->flags & NFSMNT_ACDIRMAX) && argp->acdirmax >= 0)
  690                 nmp->nm_acdirmax = argp->acdirmax;
  691         else
  692                 nmp->nm_acdirmax = NFS_MAXDIRATTRTIMO;
  693         if (nmp->nm_acdirmin > nmp->nm_acdirmax)
  694                 nmp->nm_acdirmin = nmp->nm_acdirmax;
  695         if (nmp->nm_acregmin > nmp->nm_acregmax)
  696                 nmp->nm_acregmin = nmp->nm_acregmax;
  697 
  698         if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0) {
  699                 if (argp->maxgrouplist <= NFS_MAXGRPS)
  700                         nmp->nm_numgrps = argp->maxgrouplist;
  701                 else
  702                         nmp->nm_numgrps = NFS_MAXGRPS;
  703         }
  704         if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0) {
  705                 if (argp->readahead <= NFS_MAXRAHEAD)
  706                         nmp->nm_readahead = argp->readahead;
  707                 else
  708                         nmp->nm_readahead = NFS_MAXRAHEAD;
  709         }
  710         if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 0) {
  711                 if (argp->deadthresh <= NFS_MAXDEADTHRESH)
  712                         nmp->nm_deadthresh = argp->deadthresh;
  713                 else
  714                         nmp->nm_deadthresh = NFS_MAXDEADTHRESH;
  715         }
  716 
  717         adjsock |= ((nmp->nm_sotype != argp->sotype) ||
  718                     (nmp->nm_soproto != argp->proto));
  719         nmp->nm_sotype = argp->sotype;
  720         nmp->nm_soproto = argp->proto;
  721 
  722         if (nmp->nm_so && adjsock) {
  723                 nfs_safedisconnect(nmp);
  724                 if (nmp->nm_sotype == SOCK_DGRAM)
  725                         while (nfs_connect(nmp, NULL)) {
  726                                 printf("nfs_args: retrying connect\n");
  727                                 (void) tsleep((caddr_t)&lbolt,
  728                                               PSOCK, "nfscon", 0);
  729                         }
  730         }
  731 }
  732 
  733 /*
  734  * VFS Operations.
  735  *
  736  * mount system call
  737  * It seems a bit dumb to copyinstr() the host and path here and then
  738  * bcopy() them in mountnfs(), but I wanted to detect errors before
  739  * doing the sockargs() call because sockargs() allocates an mbuf and
  740  * an error after that means that I have to release the mbuf.
  741  */
  742 /* ARGSUSED */
  743 static int
  744 nfs_mount(struct mount *mp, char *path, caddr_t data, struct nameidata *ndp,
  745     struct thread *td)
  746 {
  747         int error;
  748         struct nfs_args args;
  749         struct sockaddr *nam;
  750         struct vnode *vp;
  751         char hst[MNAMELEN];
  752         size_t len;
  753         u_char nfh[NFSX_V3FHMAX];
  754 
  755         if (path == NULL)
  756                 return (nfs_mountroot(mp, td));
  757         error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args));
  758         if (error)
  759                 return (error);
  760         if (args.version != NFS_ARGSVERSION) {
  761 #ifdef COMPAT_PRELITE2
  762                 /*
  763                  * If the argument version is unknown, then assume the
  764                  * caller is a pre-lite2 4.4BSD client and convert its
  765                  * arguments.
  766                  */
  767                 struct onfs_args oargs;
  768                 error = copyin(data, (caddr_t)&oargs, sizeof (struct onfs_args));
  769                 if (error)
  770                         return (error);
  771                 nfs_convert_oargs(&args,&oargs);
  772 #else /* !COMPAT_PRELITE2 */
  773                 return (EPROGMISMATCH);
  774 #endif /* COMPAT_PRELITE2 */
  775         }
  776         if (mp->mnt_flag & MNT_UPDATE) {
  777                 struct nfsmount *nmp = VFSTONFS(mp);
  778 
  779                 if (nmp == NULL)
  780                         return (EIO);
  781                 /*
  782                  * When doing an update, we can't change from or to
  783                  * v3, switch lockd strategies or change cookie translation
  784                  */
  785                 args.flags = (args.flags &
  786                     ~(NFSMNT_NFSV3 | NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)) |
  787                     (nmp->nm_flag &
  788                         (NFSMNT_NFSV3 | NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/));
  789                 nfs_decode_args(nmp, &args);
  790                 return (0);
  791         }
  792 
  793         /*
  794          * Make the nfs_ip_paranoia sysctl serve as the default connection
  795          * or no-connection mode for those protocols that support 
  796          * no-connection mode (the flag will be cleared later for protocols
  797          * that do not support no-connection mode).  This will allow a client
  798          * to receive replies from a different IP then the request was
  799          * sent to.  Note: default value for nfs_ip_paranoia is 1 (paranoid),
  800          * not 0.
  801          */
  802         if (nfs_ip_paranoia == 0)
  803                 args.flags |= NFSMNT_NOCONN;
  804         if (args.fhsize < 0 || args.fhsize > NFSX_V3FHMAX)
  805                 return (EINVAL);
  806         error = copyin((caddr_t)args.fh, (caddr_t)nfh, args.fhsize);
  807         if (error)
  808                 return (error);
  809         error = copyinstr(args.hostname, hst, MNAMELEN-1, &len);
  810         if (error)
  811                 return (error);
  812         bzero(&hst[len], MNAMELEN - len);
  813         /* sockargs() call must be after above copyin() calls */
  814         error = getsockaddr(&nam, (caddr_t)args.addr, args.addrlen);
  815         if (error)
  816                 return (error);
  817         args.fh = nfh;
  818         error = mountnfs(&args, mp, nam, path, hst, &vp, td->td_ucred);
  819         return (error);
  820 }
  821 
  822 /*
  823  * Common code for mount and mountroot
  824  */
  825 static int
  826 mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
  827     char *pth, char *hst, struct vnode **vpp, struct ucred *cred)
  828 {
  829         struct nfsmount *nmp;
  830         struct nfsnode *np;
  831         int error;
  832         struct vattr attrs;
  833 
  834         if (mp->mnt_flag & MNT_UPDATE) {
  835                 nmp = VFSTONFS(mp);
  836                 /* update paths, file handles, etc, here        XXX */
  837                 FREE(nam, M_SONAME);
  838                 return (0);
  839         } else {
  840                 nmp = uma_zalloc(nfsmount_zone, M_WAITOK);
  841                 bzero((caddr_t)nmp, sizeof (struct nfsmount));
  842                 TAILQ_INIT(&nmp->nm_bufq);
  843                 mp->mnt_data = (qaddr_t)nmp;
  844         }
  845         vfs_getnewfsid(mp);
  846         nmp->nm_mountp = mp;
  847 
  848         /*
  849          * V2 can only handle 32 bit filesizes.  A 4GB-1 limit may be too
  850          * high, depending on whether we end up with negative offsets in
  851          * the client or server somewhere.  2GB-1 may be safer.
  852          *
  853          * For V3, nfs_fsinfo will adjust this as necessary.  Assume maximum
  854          * that we can handle until we find out otherwise.
  855          * XXX Our "safe" limit on the client is what we can store in our
  856          * buffer cache using signed(!) block numbers.
  857          */
  858         if ((argp->flags & NFSMNT_NFSV3) == 0)
  859                 nmp->nm_maxfilesize = 0xffffffffLL;
  860         else
  861                 nmp->nm_maxfilesize = (u_int64_t)0x80000000 * DEV_BSIZE - 1;
  862 
  863         nmp->nm_timeo = NFS_TIMEO;
  864         nmp->nm_retry = NFS_RETRANS;
  865         nmp->nm_wsize = NFS_WSIZE;
  866         nmp->nm_rsize = NFS_RSIZE;
  867         nmp->nm_readdirsize = NFS_READDIRSIZE;
  868         nmp->nm_numgrps = NFS_MAXGRPS;
  869         nmp->nm_readahead = NFS_DEFRAHEAD;
  870         nmp->nm_deadthresh = NFS_MAXDEADTHRESH;
  871         nmp->nm_fhsize = argp->fhsize;
  872         bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize);
  873         bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
  874         bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN);
  875         nmp->nm_nam = nam;
  876         /* Set up the sockets and per-host congestion */
  877         nmp->nm_sotype = argp->sotype;
  878         nmp->nm_soproto = argp->proto;
  879 
  880         nfs_decode_args(nmp, argp);
  881 
  882         /*
  883          * For Connection based sockets (TCP,...) defer the connect until
  884          * the first request, in case the server is not responding.
  885          */
  886         if (nmp->nm_sotype == SOCK_DGRAM &&
  887                 (error = nfs_connect(nmp, NULL)))
  888                 goto bad;
  889 
  890         /*
  891          * This is silly, but it has to be set so that vinifod() works.
  892          * We do not want to do an nfs_statfs() here since we can get
  893          * stuck on a dead server and we are holding a lock on the mount
  894          * point.
  895          */
  896         mp->mnt_stat.f_iosize = nfs_iosize(nmp);
  897         /*
  898          * A reference count is needed on the nfsnode representing the
  899          * remote root.  If this object is not persistent, then backward
  900          * traversals of the mount point (i.e. "..") will not work if
  901          * the nfsnode gets flushed out of the cache. Ufs does not have
  902          * this problem, because one can identify root inodes by their
  903          * number == ROOTINO (2).
  904          */
  905         error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
  906         if (error)
  907                 goto bad;
  908         *vpp = NFSTOV(np);
  909 
  910         /*
  911          * Get file attributes for the mountpoint.  This has the side
  912          * effect of filling in (*vpp)->v_type with the correct value.
  913          */
  914         VOP_GETATTR(*vpp, &attrs, curthread->td_ucred, curthread);
  915 
  916         /*
  917          * Lose the lock but keep the ref.
  918          */
  919         VOP_UNLOCK(*vpp, 0, curthread);
  920 
  921         return (0);
  922 bad:
  923         nfs_disconnect(nmp);
  924         uma_zfree(nfsmount_zone, nmp);
  925         FREE(nam, M_SONAME);
  926         return (error);
  927 }
  928 
  929 /*
  930  * unmount system call
  931  */
  932 static int
  933 nfs_unmount(struct mount *mp, int mntflags, struct thread *td)
  934 {
  935         struct nfsmount *nmp;
  936         int error, flags = 0;
  937 
  938         if (mntflags & MNT_FORCE)
  939                 flags |= FORCECLOSE;
  940         nmp = VFSTONFS(mp);
  941         /*
  942          * Goes something like this..
  943          * - Call vflush() to clear out vnodes for this filesystem
  944          * - Close the socket
  945          * - Free up the data structures
  946          */
  947         /* In the forced case, cancel any outstanding requests. */
  948         if (flags & FORCECLOSE) {
  949                 error = nfs_nmcancelreqs(nmp);
  950                 if (error)
  951                         return (error);
  952         }
  953         /* We hold 1 extra ref on the root vnode; see comment in mountnfs(). */
  954         error = vflush(mp, 1, flags);
  955         if (error)
  956                 return (error);
  957 
  958         /*
  959          * We are now committed to the unmount.
  960          */
  961         nfs_disconnect(nmp);
  962         FREE(nmp->nm_nam, M_SONAME);
  963 
  964         uma_zfree(nfsmount_zone, nmp);
  965         return (0);
  966 }
  967 
  968 /*
  969  * Return root of a filesystem
  970  */
  971 static int
  972 nfs_root(struct mount *mp, struct vnode **vpp)
  973 {
  974         struct vnode *vp;
  975         struct nfsmount *nmp;
  976         struct nfsnode *np;
  977         int error;
  978 
  979         nmp = VFSTONFS(mp);
  980         error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
  981         if (error)
  982                 return (error);
  983         vp = NFSTOV(np);
  984         if (vp->v_type == VNON)
  985             vp->v_type = VDIR;
  986         vp->v_vflag |= VV_ROOT;
  987         *vpp = vp;
  988         return (0);
  989 }
  990 
  991 /*
  992  * Flush out the buffer cache
  993  */
  994 /* ARGSUSED */
  995 static int
  996 nfs_sync(struct mount *mp, int waitfor, struct ucred *cred, struct thread *td)
  997 {
  998         struct vnode *vp, *vnp;
  999         int error, allerror = 0;
 1000 
 1001         /*
 1002          * Force stale buffer cache information to be flushed.
 1003          */
 1004         mtx_lock(&mntvnode_mtx);
 1005 loop:
 1006         for (vp = TAILQ_FIRST(&mp->mnt_nvnodelist);
 1007              vp != NULL;
 1008              vp = vnp) {
 1009                 /*
 1010                  * If the vnode that we are about to sync is no longer
 1011                  * associated with this mount point, start over.
 1012                  */
 1013                 if (vp->v_mount != mp)
 1014                         goto loop;
 1015                 vnp = TAILQ_NEXT(vp, v_nmntvnodes);
 1016                 mtx_unlock(&mntvnode_mtx);
 1017                 VI_LOCK(vp);
 1018                 if (VOP_ISLOCKED(vp, NULL) || TAILQ_EMPTY(&vp->v_dirtyblkhd) ||
 1019                     waitfor == MNT_LAZY) {
 1020                         VI_UNLOCK(vp);
 1021                         mtx_lock(&mntvnode_mtx);
 1022                         continue;
 1023                 }
 1024                 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) {
 1025                         mtx_lock(&mntvnode_mtx);
 1026                         goto loop;
 1027                 }
 1028                 error = VOP_FSYNC(vp, cred, waitfor, td);
 1029                 if (error)
 1030                         allerror = error;
 1031                 vput(vp);
 1032                 mtx_lock(&mntvnode_mtx);
 1033         }
 1034         mtx_unlock(&mntvnode_mtx);
 1035         return (allerror);
 1036 }

Cache object: a4bdde59c34c6ba63357073258ab0080


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