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

Cache object: 10742934fefa53c90ae7587840567f6b


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