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

Cache object: 1eef5c5d494780ab7f130a5a004035b0


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