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

Cache object: e6eaffe861de663595c19ba405fd2dcd


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