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 /*      $OpenBSD: nfs_vfsops.c,v 1.127 2022/08/12 14:30:53 visa Exp $   */
    2 /*      $NetBSD: nfs_vfsops.c,v 1.46.4.1 1996/05/25 22:40:35 fvdl Exp $ */
    3 
    4 /*
    5  * Copyright (c) 1989, 1993, 1995
    6  *      The Regents of the University of California.  All rights reserved.
    7  *
    8  * This code is derived from software contributed to Berkeley by
    9  * Rick Macklem at The University of Guelph.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. Neither the name of the University nor the names of its contributors
   20  *    may be used to endorse or promote products derived from this software
   21  *    without specific prior written permission.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   33  * SUCH DAMAGE.
   34  *
   35  *      @(#)nfs_vfsops.c        8.12 (Berkeley) 5/20/95
   36  */
   37 
   38 #include <sys/param.h>
   39 #include <sys/conf.h>
   40 #include <sys/ioctl.h>
   41 #include <sys/signal.h>
   42 #include <sys/proc.h>
   43 #include <sys/namei.h>
   44 #include <sys/vnode.h>
   45 #include <sys/lock.h>
   46 #include <sys/kernel.h>
   47 #include <sys/mount.h>
   48 #include <sys/swap.h>
   49 #include <sys/buf.h>
   50 #include <sys/mbuf.h>
   51 #include <sys/dirent.h>
   52 #include <sys/socket.h>
   53 #include <sys/socketvar.h>
   54 #include <sys/systm.h>
   55 #include <sys/sysctl.h>
   56 #include <sys/queue.h>
   57 
   58 #include <netinet/in.h>
   59 
   60 #include <nfs/rpcv2.h>
   61 #include <nfs/nfsproto.h>
   62 #include <nfs/nfsnode.h>
   63 #include <nfs/nfs.h>
   64 #include <nfs/nfsmount.h>
   65 #include <nfs/xdr_subs.h>
   66 #include <nfs/nfsm_subs.h>
   67 #include <nfs/nfsdiskless.h>
   68 #include <nfs/nfs_var.h>
   69 
   70 extern struct nfsstats nfsstats;
   71 extern int nfs_ticks;
   72 extern u_int32_t nfs_procids[NFS_NPROCS];
   73 
   74 int     nfs_sysctl(int *, u_int, void *, size_t *, void *, size_t,
   75             struct proc *);
   76 int     nfs_checkexp(struct mount *, struct mbuf *, int *, struct ucred **);
   77 struct  mount *nfs_mount_diskless(struct nfs_dlmount *, char *, int,
   78             struct vnode **, struct proc *p);
   79 int     mountnfs(struct nfs_args *, struct mount *, struct mbuf *,
   80             const char *, char *, struct vnode **, struct proc *p);
   81 int     nfs_quotactl(struct mount *, int, uid_t, caddr_t, struct proc *);
   82 int     nfs_root(struct mount *, struct vnode **);
   83 int     nfs_start(struct mount *, int, struct proc *);
   84 int     nfs_statfs(struct mount *, struct statfs *, struct proc *);
   85 int     nfs_sync(struct mount *, int, int, struct ucred *, struct proc *);
   86 int     nfs_unmount(struct mount *, int, struct proc *);
   87 void    nfs_reaper(void *);
   88 int     nfs_vget(struct mount *, ino_t, struct vnode **);
   89 int     nfs_vptofh(struct vnode *, struct fid *);
   90 int     nfs_mountroot(void);
   91 void    nfs_decode_args(struct nfsmount *, struct nfs_args *,
   92             struct nfs_args *);
   93 int     nfs_fhtovp(struct mount *, struct fid *, struct vnode **);
   94 
   95 /*
   96  * nfs vfs operations.
   97  */
   98 const struct vfsops nfs_vfsops = {
   99         .vfs_mount      = nfs_mount,
  100         .vfs_start      = nfs_start,
  101         .vfs_unmount    = nfs_unmount,
  102         .vfs_root       = nfs_root,
  103         .vfs_quotactl   = nfs_quotactl,
  104         .vfs_statfs     = nfs_statfs,
  105         .vfs_sync       = nfs_sync,
  106         .vfs_vget       = nfs_vget,
  107         .vfs_fhtovp     = nfs_fhtovp,
  108         .vfs_vptofh     = nfs_vptofh,
  109         .vfs_init       = nfs_vfs_init,
  110         .vfs_sysctl     = nfs_sysctl,
  111         .vfs_checkexp   = nfs_checkexp,
  112 };
  113 
  114 /*
  115  * nfs statfs call
  116  */
  117 int
  118 nfs_statfs(struct mount *mp, struct statfs *sbp, struct proc *p)
  119 {
  120         struct vnode *vp;
  121         struct nfs_statfs *sfp = NULL;
  122         struct nfsm_info        info;
  123         u_int32_t *tl;
  124         int32_t t1;
  125         caddr_t cp2;
  126         struct nfsmount *nmp = VFSTONFS(mp);
  127         int error = 0, retattr;
  128         struct ucred *cred;
  129         u_quad_t tquad;
  130 
  131         info.nmi_v3 = (nmp->nm_flag & NFSMNT_NFSV3);
  132 
  133         error = nfs_root(mp, &vp);
  134         if (error)
  135                 return (error);
  136         cred = crget();
  137         cred->cr_ngroups = 0;
  138         if (info.nmi_v3 && (nmp->nm_flag & NFSMNT_GOTFSINFO) == 0)
  139                 (void)nfs_fsinfo(nmp, vp, cred, p);
  140         nfsstats.rpccnt[NFSPROC_FSSTAT]++;
  141         info.nmi_mb = info.nmi_mreq = nfsm_reqhead(NFSX_FH(info.nmi_v3));
  142         nfsm_fhtom(&info, vp, info.nmi_v3);
  143 
  144         info.nmi_procp = p;
  145         info.nmi_cred = cred;
  146         error = nfs_request(vp, NFSPROC_FSSTAT, &info);
  147         if (info.nmi_v3)
  148                 nfsm_postop_attr(vp, retattr);
  149         if (error) {
  150                 m_freem(info.nmi_mrep);
  151                 goto nfsmout;
  152         }
  153 
  154         nfsm_dissect(sfp, struct nfs_statfs *, NFSX_STATFS(info.nmi_v3));
  155         sbp->f_iosize = min(nmp->nm_rsize, nmp->nm_wsize);
  156         if (info.nmi_v3) {
  157                 sbp->f_bsize = NFS_FABLKSIZE;
  158                 tquad = fxdr_hyper(&sfp->sf_tbytes);
  159                 sbp->f_blocks = tquad / (u_quad_t)NFS_FABLKSIZE;
  160                 tquad = fxdr_hyper(&sfp->sf_fbytes);
  161                 sbp->f_bfree = tquad / (u_quad_t)NFS_FABLKSIZE;
  162                 tquad = fxdr_hyper(&sfp->sf_abytes);
  163                 sbp->f_bavail = (quad_t)tquad / (quad_t)NFS_FABLKSIZE;
  164 
  165                 tquad = fxdr_hyper(&sfp->sf_tfiles);
  166                 sbp->f_files = tquad;
  167                 tquad = fxdr_hyper(&sfp->sf_ffiles);
  168                 sbp->f_ffree = tquad;
  169                 sbp->f_favail = tquad;
  170         } else {
  171                 sbp->f_bsize = fxdr_unsigned(int32_t, sfp->sf_bsize);
  172                 sbp->f_blocks = fxdr_unsigned(int32_t, sfp->sf_blocks);
  173                 sbp->f_bfree = fxdr_unsigned(int32_t, sfp->sf_bfree);
  174                 sbp->f_bavail = fxdr_unsigned(int32_t, sfp->sf_bavail);
  175                 sbp->f_files = 0;
  176                 sbp->f_ffree = 0;
  177                 sbp->f_favail = 0;
  178         }
  179         copy_statfs_info(sbp, mp);
  180         m_freem(info.nmi_mrep);
  181 nfsmout: 
  182         vput(vp);
  183         crfree(cred);
  184         return (error);
  185 }
  186 
  187 /*
  188  * nfs version 3 fsinfo rpc call
  189  */
  190 int
  191 nfs_fsinfo(struct nfsmount *nmp, struct vnode *vp, struct ucred *cred,
  192     struct proc *p)
  193 {
  194         struct nfsv3_fsinfo *fsp;
  195         struct nfsm_info        info;
  196         int32_t t1;
  197         u_int32_t *tl, pref, max;
  198         caddr_t cp2;
  199         int error = 0, retattr;
  200 
  201         nfsstats.rpccnt[NFSPROC_FSINFO]++;
  202         info.nmi_mb = info.nmi_mreq = nfsm_reqhead(NFSX_FH(1));
  203         nfsm_fhtom(&info, vp, 1);
  204 
  205         info.nmi_procp = p;
  206         info.nmi_cred = cred;
  207         error = nfs_request(vp, NFSPROC_FSINFO, &info);
  208 
  209         nfsm_postop_attr(vp, retattr);
  210         if (error) {
  211                 m_freem(info.nmi_mrep);
  212                 goto nfsmout;
  213         }
  214 
  215         nfsm_dissect(fsp, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
  216         pref = fxdr_unsigned(u_int32_t, fsp->fs_wtpref);
  217         if (pref < nmp->nm_wsize)
  218                 nmp->nm_wsize = (pref + NFS_FABLKSIZE - 1) &
  219                         ~(NFS_FABLKSIZE - 1);
  220         max = fxdr_unsigned(u_int32_t, fsp->fs_wtmax);
  221         if (max < nmp->nm_wsize) {
  222                 nmp->nm_wsize = max & ~(NFS_FABLKSIZE - 1);
  223                 if (nmp->nm_wsize == 0)
  224                         nmp->nm_wsize = max;
  225         }
  226         pref = fxdr_unsigned(u_int32_t, fsp->fs_rtpref);
  227         if (pref < nmp->nm_rsize)
  228                 nmp->nm_rsize = (pref + NFS_FABLKSIZE - 1) &
  229                         ~(NFS_FABLKSIZE - 1);
  230         max = fxdr_unsigned(u_int32_t, fsp->fs_rtmax);
  231         if (max < nmp->nm_rsize) {
  232                 nmp->nm_rsize = max & ~(NFS_FABLKSIZE - 1);
  233                 if (nmp->nm_rsize == 0)
  234                         nmp->nm_rsize = max;
  235         }
  236         pref = fxdr_unsigned(u_int32_t, fsp->fs_dtpref);
  237         if (pref < nmp->nm_readdirsize)
  238                 nmp->nm_readdirsize = (pref + NFS_DIRBLKSIZ - 1) &
  239                         ~(NFS_DIRBLKSIZ - 1);
  240         if (max < nmp->nm_readdirsize) {
  241                 nmp->nm_readdirsize = max & ~(NFS_DIRBLKSIZ - 1);
  242                 if (nmp->nm_readdirsize == 0)
  243                         nmp->nm_readdirsize = max;
  244         }
  245         nmp->nm_flag |= NFSMNT_GOTFSINFO;
  246 
  247         m_freem(info.nmi_mrep);
  248 nfsmout: 
  249         return (error);
  250 }
  251 
  252 struct nfs_diskless nfs_diskless;
  253 
  254 /*
  255  * Mount a remote root fs via. NFS.  It goes like this:
  256  * - Call nfs_boot_init() to fill in the nfs_diskless struct
  257  *   (using RARP, bootparam RPC, mountd RPC)
  258  * - hand craft the swap nfs vnode hanging off a fake mount point
  259  *      if swdevt[0].sw_dev == NODEV
  260  * - build the rootfs mount point and call mountnfs() to do the rest.
  261  */
  262 int
  263 nfs_mountroot(void)
  264 {
  265         struct vattr attr;
  266         struct mount *mp;
  267         struct vnode *vp;
  268         struct proc *procp;
  269         long n;
  270         int error;
  271 
  272         procp = curproc; /* XXX */
  273 
  274         /*
  275          * Call nfs_boot_init() to fill in the nfs_diskless struct.
  276          * Side effect:  Finds and configures a network interface.
  277          */
  278         nfs_boot_init(&nfs_diskless, procp);
  279 
  280         /*
  281          * Create the root mount point.
  282          */
  283         if (nfs_boot_getfh(&nfs_diskless.nd_boot, "root", &nfs_diskless.nd_root, -1))
  284                 panic("nfs_mountroot: root");
  285         mp = nfs_mount_diskless(&nfs_diskless.nd_root, "/", 0, &vp, procp);
  286         printf("root on %s\n", nfs_diskless.nd_root.ndm_host);
  287 
  288         /*
  289          * Link it into the mount list.
  290          */
  291         TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
  292         rootvp = vp;
  293         vfs_unbusy(mp);
  294 
  295         /* Get root attributes (for the time). */
  296         error = VOP_GETATTR(rootvp, &attr, procp->p_ucred, procp);
  297         if (error) panic("nfs_mountroot: getattr for root");
  298         n = attr.va_atime.tv_sec;
  299 #ifdef  DEBUG
  300         printf("root time: 0x%lx\n", n);
  301 #endif
  302         inittodr(n);
  303 
  304 #ifdef notyet
  305         /* Set up swap credentials. */
  306         proc0.p_ucred->cr_uid = ntohl(nfs_diskless.swap_ucred.cr_uid);
  307         proc0.p_ucred->cr_gid = ntohl(nfs_diskless.swap_ucred.cr_gid);
  308         if ((proc0.p_ucred->cr_ngroups = ntohs(nfs_diskless.swap_ucred.cr_ngroups)) >
  309                 NGROUPS_MAX)
  310                 proc0.p_ucred->cr_ngroups = NGROUPS_MAX;
  311         for (i = 0; i < proc0.p_ucred->cr_ngroups; i++)
  312             proc0.p_ucred->cr_groups[i] = ntohl(nfs_diskless.swap_ucred.cr_groups[i]);
  313 #endif
  314 
  315         /*
  316          * "Mount" the swap device.
  317          *
  318          * On a "dataless" configuration (swap on disk) we will have:
  319          *      (swdevt[0].sw_dev != NODEV) identifying the swap device.
  320          */
  321         if (swdevt[0].sw_dev != NODEV) {
  322                 if (bdevvp(swapdev, &swapdev_vp))
  323                         panic("nfs_mountroot: can't setup swap vp");
  324                 printf("swap on device 0x%x\n", swdevt[0].sw_dev);
  325                 return (0);
  326         }
  327 
  328         /*
  329          * If swapping to an nfs node:  (swdevt[0].sw_dev == NODEV)
  330          * Create a fake mount point just for the swap vnode so that the
  331          * swap file can be on a different server from the rootfs.
  332          *
  333          * Wait 5 retries, finally no swap is cool. -mickey
  334          */
  335         error = nfs_boot_getfh(&nfs_diskless.nd_boot, "swap", &nfs_diskless.nd_swap, 5);
  336         if (!error) {
  337                 mp = nfs_mount_diskless(&nfs_diskless.nd_swap, "/swap", 0, &vp,
  338                     procp);
  339                 vfs_unbusy(mp);
  340 
  341                 /*
  342                  * Since the swap file is not the root dir of a file system,
  343                  * hack it to a regular file.
  344                  */
  345                 vp->v_type = VREG;
  346                 vp->v_flag = 0;
  347 
  348                 /*
  349                  * Next line is a hack to make swapmount() work on NFS
  350                  * swap files.
  351                  */
  352                 swdevt[0].sw_dev = NETDEV;
  353                 /* end hack */
  354                 nfs_diskless.sw_vp = vp;
  355 
  356                 /*
  357                  * Find out how large the swap file is.
  358                  */
  359                 error = VOP_GETATTR(vp, &attr, procp->p_ucred, procp);
  360                 if (error)
  361                         printf("nfs_mountroot: getattr for swap\n");
  362                 n = (long) (attr.va_size >> DEV_BSHIFT);
  363 
  364                 printf("swap on %s\n", nfs_diskless.nd_swap.ndm_host);
  365 #ifdef  DEBUG
  366                 printf("swap size: 0x%lx (blocks)\n", n);
  367 #endif
  368                 return (0);
  369         }
  370 
  371         printf("WARNING: no swap\n");
  372         swdevt[0].sw_dev = NODEV;
  373         return (0);
  374 }
  375 
  376 /*
  377  * Internal version of mount system call for diskless setup.
  378  */
  379 struct mount *
  380 nfs_mount_diskless(struct nfs_dlmount *ndmntp, char *mntname, int mntflag,
  381     struct vnode **vpp, struct proc *p)
  382 {
  383         struct mount *mp;
  384         struct mbuf *m;
  385         int error;
  386 
  387         if (vfs_rootmountalloc("nfs", mntname, &mp))
  388                 panic("nfs_mount_diskless: vfs_rootmountalloc failed");
  389         mp->mnt_flag |= mntflag;
  390 
  391         /* Get mbuf for server sockaddr. */
  392         m = m_get(M_WAIT, MT_SONAME);
  393         bcopy(ndmntp->ndm_args.addr, mtod(m, caddr_t),
  394             (m->m_len = ndmntp->ndm_args.addr->sa_len));
  395 
  396         error = mountnfs(&ndmntp->ndm_args, mp, m, mntname,
  397             ndmntp->ndm_args.hostname, vpp, p);
  398         if (error)
  399                 panic("nfs_mountroot: mount %s failed: %d", mntname, error);
  400 
  401         return (mp);
  402 }
  403 
  404 void
  405 nfs_decode_args(struct nfsmount *nmp, struct nfs_args *argp,
  406     struct nfs_args *nargp)
  407 {
  408         int adjsock = 0;
  409         int maxio;
  410 
  411 #if 0
  412         /* Re-bind if rsrvd port requested and wasn't on one */
  413         adjsock = !(nmp->nm_flag & NFSMNT_RESVPORT)
  414                   && (argp->flags & NFSMNT_RESVPORT);
  415 #endif
  416         /* Also re-bind if we're switching to/from a connected UDP socket */
  417         adjsock |= ((nmp->nm_flag & NFSMNT_NOCONN) !=
  418             (argp->flags & NFSMNT_NOCONN));
  419 
  420         nmp->nm_flag =
  421             (argp->flags & ~NFSMNT_INTERNAL) | (nmp->nm_flag & NFSMNT_INTERNAL);
  422 
  423         if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
  424                 nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
  425                 if (nmp->nm_timeo < NFS_MINTIMEO)
  426                         nmp->nm_timeo = NFS_MINTIMEO;
  427                 else if (nmp->nm_timeo > NFS_MAXTIMEO)
  428                         nmp->nm_timeo = NFS_MAXTIMEO;
  429         }
  430 
  431         if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1)
  432                 nmp->nm_retry = MIN(argp->retrans, NFS_MAXREXMIT);
  433         if (!(nmp->nm_flag & NFSMNT_SOFT))
  434                 nmp->nm_retry = NFS_MAXREXMIT + 1; /* past clip limit */
  435 
  436         if (argp->flags & NFSMNT_NFSV3) {
  437                 if (argp->sotype == SOCK_DGRAM)
  438                         maxio = NFS_MAXDGRAMDATA;
  439                 else
  440                         maxio = NFS_MAXDATA;
  441         } else
  442                 maxio = NFS_V2MAXDATA;
  443 
  444         if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
  445                 int osize = nmp->nm_wsize;
  446                 nmp->nm_wsize = argp->wsize;
  447                 /* Round down to multiple of blocksize */
  448                 nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1);
  449                 if (nmp->nm_wsize <= 0)
  450                         nmp->nm_wsize = NFS_FABLKSIZE;
  451                 adjsock |= (nmp->nm_wsize != osize);
  452         }
  453         if (nmp->nm_wsize > maxio)
  454                 nmp->nm_wsize = maxio;
  455         if (nmp->nm_wsize > MAXBSIZE)
  456                 nmp->nm_wsize = MAXBSIZE;
  457 
  458         if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
  459                 int osize = nmp->nm_rsize;
  460                 nmp->nm_rsize = argp->rsize;
  461                 /* Round down to multiple of blocksize */
  462                 nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1);
  463                 if (nmp->nm_rsize <= 0)
  464                         nmp->nm_rsize = NFS_FABLKSIZE;
  465                 adjsock |= (nmp->nm_rsize != osize);
  466         }
  467         if (nmp->nm_rsize > maxio)
  468                 nmp->nm_rsize = maxio;
  469         if (nmp->nm_rsize > MAXBSIZE)
  470                 nmp->nm_rsize = MAXBSIZE;
  471 
  472         if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) {
  473                 nmp->nm_readdirsize = argp->readdirsize;
  474                 /* Round down to multiple of blocksize */
  475                 nmp->nm_readdirsize &= ~(NFS_DIRBLKSIZ - 1);
  476                 if (nmp->nm_readdirsize < NFS_DIRBLKSIZ)
  477                         nmp->nm_readdirsize = NFS_DIRBLKSIZ;
  478         } else if (argp->flags & NFSMNT_RSIZE)
  479                 nmp->nm_readdirsize = nmp->nm_rsize;
  480 
  481         if (nmp->nm_readdirsize > maxio)
  482                 nmp->nm_readdirsize = maxio;
  483 
  484         if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0 &&
  485                 argp->maxgrouplist <= NFS_MAXGRPS)
  486                 nmp->nm_numgrps = argp->maxgrouplist;
  487         if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0 &&
  488                 argp->readahead <= NFS_MAXRAHEAD)
  489                 nmp->nm_readahead = argp->readahead;
  490         if (argp->flags & NFSMNT_ACREGMIN && argp->acregmin >= 0) {
  491                 if (argp->acregmin > 0xffff)
  492                         nmp->nm_acregmin = 0xffff;
  493                 else
  494                         nmp->nm_acregmin = argp->acregmin;
  495         }
  496         if (argp->flags & NFSMNT_ACREGMAX && argp->acregmax >= 0) {
  497                 if (argp->acregmax > 0xffff)
  498                         nmp->nm_acregmax = 0xffff;
  499                 else
  500                         nmp->nm_acregmax = argp->acregmax;
  501         }
  502         if (nmp->nm_acregmin > nmp->nm_acregmax)
  503           nmp->nm_acregmin = nmp->nm_acregmax;
  504 
  505         if (argp->flags & NFSMNT_ACDIRMIN && argp->acdirmin >= 0) {
  506                 if (argp->acdirmin > 0xffff)
  507                         nmp->nm_acdirmin = 0xffff;
  508                 else
  509                         nmp->nm_acdirmin = argp->acdirmin;
  510         }
  511         if (argp->flags & NFSMNT_ACDIRMAX && argp->acdirmax >= 0) {
  512                 if (argp->acdirmax > 0xffff)
  513                         nmp->nm_acdirmax = 0xffff;
  514                 else
  515                         nmp->nm_acdirmax = argp->acdirmax;
  516         }
  517         if (nmp->nm_acdirmin > nmp->nm_acdirmax)
  518           nmp->nm_acdirmin = nmp->nm_acdirmax;
  519 
  520         if (nmp->nm_so && adjsock) {
  521                 nfs_disconnect(nmp);
  522                 if (nmp->nm_sotype == SOCK_DGRAM)
  523                         while (nfs_connect(nmp, NULL)) {
  524                                 printf("nfs_args: retrying connect\n");
  525                                 tsleep_nsec(&nowake, PSOCK, "nfscon",
  526                                     SEC_TO_NSEC(1));
  527                         }
  528         }
  529 
  530         /* Update nargp based on nmp */
  531         nargp->wsize = nmp->nm_wsize;
  532         nargp->rsize = nmp->nm_rsize;
  533         nargp->readdirsize = nmp->nm_readdirsize;
  534         nargp->timeo = nmp->nm_timeo;
  535         nargp->retrans = nmp->nm_retry;
  536         nargp->maxgrouplist = nmp->nm_numgrps;
  537         nargp->readahead = nmp->nm_readahead;
  538         nargp->acregmin = nmp->nm_acregmin;
  539         nargp->acregmax = nmp->nm_acregmax;
  540         nargp->acdirmin = nmp->nm_acdirmin;
  541         nargp->acdirmax = nmp->nm_acdirmax;
  542 }
  543 
  544 /*
  545  * VFS Operations.
  546  *
  547  * mount system call
  548  * It seems a bit dumb to copyinstr() the host here and then
  549  * bcopy() it in mountnfs(), but I wanted to detect errors before
  550  * doing the sockargs() call because sockargs() allocates an mbuf and
  551  * an error after that means that I have to release the mbuf.
  552  */
  553 /* ARGSUSED */
  554 int
  555 nfs_mount(struct mount *mp, const char *path, void *data,
  556     struct nameidata *ndp, struct proc *p)
  557 {
  558         int error;
  559         struct nfs_args *args = data;
  560         struct mbuf *nam;
  561         struct vnode *vp;
  562         char hst[MNAMELEN];
  563         size_t len;
  564         u_char nfh[NFSX_V3FHMAX];
  565 
  566         if (args &&
  567             (args->flags & (NFSMNT_NFSV3|NFSMNT_RDIRPLUS)) == NFSMNT_RDIRPLUS)
  568                 return (EINVAL);
  569 
  570         if (nfs_niothreads < 0) {
  571                 nfs_niothreads = 4;
  572                 nfs_getset_niothreads(1);
  573         }
  574 
  575         if (mp->mnt_flag & MNT_UPDATE) {
  576                 struct nfsmount *nmp = VFSTONFS(mp);
  577 
  578                 if (nmp == NULL)
  579                         return (EIO);
  580                 /*
  581                  * When doing an update, we can't change from or to
  582                  * v3.
  583                  */
  584                 if (args) {
  585                         args->flags = (args->flags & ~(NFSMNT_NFSV3)) |
  586                             (nmp->nm_flag & (NFSMNT_NFSV3));
  587                         nfs_decode_args(nmp, args, &mp->mnt_stat.mount_info.nfs_args);
  588                 }
  589                 return (0);
  590         }
  591         if (args->fhsize < 0 || args->fhsize > NFSX_V3FHMAX)
  592                 return (EINVAL);
  593         error = copyin(args->fh, nfh, args->fhsize);
  594         if (error)
  595                 return (error);
  596         error = copyinstr(args->hostname, hst, MNAMELEN-1, &len);
  597         if (error)
  598                 return (error);
  599         memset(&hst[len], 0, MNAMELEN - len);
  600         /* sockargs() call must be after above copyin() calls */
  601         error = sockargs(&nam, args->addr, args->addrlen, MT_SONAME);
  602         if (error)
  603                 return (error);
  604         args->fh = nfh;
  605         error = mountnfs(args, mp, nam, path, hst, &vp, p);
  606         return (error);
  607 }
  608 
  609 /*
  610  * Common code for mount and mountroot
  611  */
  612 int
  613 mountnfs(struct nfs_args *argp, struct mount *mp, struct mbuf *nam,
  614     const char *pth, char *hst, struct vnode **vpp, struct proc *p)
  615 {
  616         struct nfsmount *nmp;
  617         struct nfsnode *np;
  618         struct vnode *vp;
  619         struct vattr attr;
  620         int error;
  621 
  622         if (mp->mnt_flag & MNT_UPDATE) {
  623                 nmp = VFSTONFS(mp);
  624                 /* update paths, file handles, etc, here        XXX */
  625                 m_freem(nam);
  626                 return (0);
  627         } else {
  628                 nmp = malloc(sizeof(*nmp), M_NFSMNT,
  629                     M_WAITOK|M_ZERO);
  630                 mp->mnt_data = nmp;
  631         }
  632 
  633         vfs_getnewfsid(mp);
  634         nmp->nm_mountp = mp;
  635         nmp->nm_timeo = NFS_TIMEO;
  636         nmp->nm_retry = NFS_RETRANS;
  637         nmp->nm_wsize = NFS_WSIZE;
  638         nmp->nm_rsize = NFS_RSIZE;
  639         nmp->nm_readdirsize = NFS_READDIRSIZE;
  640         nmp->nm_numgrps = NFS_MAXGRPS;
  641         nmp->nm_readahead = NFS_DEFRAHEAD;
  642         nmp->nm_acregmin = NFS_MINATTRTIMO;
  643         nmp->nm_acregmax = NFS_MAXATTRTIMO;
  644         nmp->nm_acdirmin = NFS_MINATTRTIMO;
  645         nmp->nm_acdirmax = NFS_MAXATTRTIMO;
  646         mp->mnt_stat.f_namemax = MAXNAMLEN;
  647         memset(mp->mnt_stat.f_mntonname, 0, MNAMELEN);
  648         strlcpy(mp->mnt_stat.f_mntonname, pth, MNAMELEN);
  649         memset(mp->mnt_stat.f_mntfromname, 0, MNAMELEN);
  650         strlcpy(mp->mnt_stat.f_mntfromname, hst, MNAMELEN);
  651         memset(mp->mnt_stat.f_mntfromspec, 0, MNAMELEN);
  652         strlcpy(mp->mnt_stat.f_mntfromspec, hst, MNAMELEN);
  653         bcopy(argp, &mp->mnt_stat.mount_info.nfs_args, sizeof(*argp));
  654         nmp->nm_nam = nam;
  655         nfs_decode_args(nmp, argp, &mp->mnt_stat.mount_info.nfs_args);
  656 
  657         nfs_ninit(nmp);
  658         TAILQ_INIT(&nmp->nm_reqsq);
  659         timeout_set_proc(&nmp->nm_rtimeout, nfs_timer, nmp);
  660 
  661         /* Set up the sockets and per-host congestion */
  662         nmp->nm_sotype = argp->sotype;
  663         nmp->nm_soproto = argp->proto;
  664 
  665         /*
  666          * For Connection based sockets (TCP,...) defer the connect until
  667          * the first request, in case the server is not responding.
  668          */
  669         if (nmp->nm_sotype == SOCK_DGRAM &&
  670             (error = nfs_connect(nmp, NULL)))
  671                 goto bad;
  672 
  673         /*
  674          * This is silly, but it has to be set so that vinifod() works.
  675          * We do not want to do an nfs_statfs() here since we can get
  676          * stuck on a dead server and we are holding a lock on the mount
  677          * point.
  678          */
  679         mp->mnt_stat.f_iosize = NFS_MAXDGRAMDATA;
  680         error = nfs_nget(mp, (nfsfh_t *)argp->fh, argp->fhsize, &np);
  681         if (error)
  682                 goto bad;
  683         vp = NFSTOV(np);
  684         error = VOP_GETATTR(vp, &attr, p->p_ucred, p);
  685         if (error) {
  686                 vput(vp);
  687                 goto bad;
  688         }
  689 
  690         /*
  691          * A reference count is needed on the nfsnode representing the
  692          * remote root.  If this object is not persistent, then backward
  693          * traversals of the mount point (i.e. "..") will not work if
  694          * the nfsnode gets flushed out of the cache. Ufs does not have
  695          * this problem, because one can identify root inodes by their
  696          * number == ROOTINO (2).  So, just unlock, but no rele.
  697          */
  698         nmp->nm_vnode = vp;
  699         if (vp->v_type == VNON)
  700                 vp->v_type = VDIR;
  701         vp->v_flag = VROOT;
  702         VOP_UNLOCK(vp);
  703         *vpp = vp;
  704 
  705         return (0);
  706 bad:
  707         nfs_disconnect(nmp);
  708         free(nmp, M_NFSMNT, sizeof(*nmp));
  709         m_freem(nam);
  710         return (error);
  711 }
  712 
  713 /* unmount system call */
  714 int
  715 nfs_unmount(struct mount *mp, int mntflags, struct proc *p)
  716 {
  717         struct nfsmount *nmp;
  718         struct vnode *vp;
  719         int error, flags = 0;
  720 
  721         nmp = VFSTONFS(mp);
  722         error = nfs_root(mp, &vp);
  723         if (error)
  724                 return (error);
  725 
  726         if ((mntflags & MNT_FORCE) == 0 && vp->v_usecount > 2) {
  727                 vput(vp);
  728                 return (EBUSY);
  729         }
  730 
  731         if (mntflags & MNT_FORCE)
  732                 flags |= FORCECLOSE;
  733 
  734         error = vflush(mp, vp, flags);
  735         if (error) {
  736                 vput(vp);
  737                 return (error);
  738         }
  739 
  740         /*
  741          * There are two references count to get rid of here: one
  742          * from mountnfs() and one from nfs_root() above.
  743          */
  744         vrele(vp);
  745         vput(vp);
  746         vgone(vp);
  747         nfs_disconnect(nmp);
  748         m_freem(nmp->nm_nam);
  749         timeout_del(&nmp->nm_rtimeout);
  750         timeout_set_proc(&nmp->nm_rtimeout, nfs_reaper, nmp);
  751         timeout_add(&nmp->nm_rtimeout, 0);
  752         mp->mnt_data = NULL;
  753         return (0);
  754 }
  755 
  756 /*
  757  * Delay nfs mount point free until pending or sleeping timeouts have finished.
  758  */
  759 void
  760 nfs_reaper(void *arg)
  761 {
  762         struct nfsmount *nmp = arg;
  763 
  764         free(nmp, M_NFSMNT, sizeof(*nmp));
  765 }
  766 
  767 /*
  768  * Return root of a filesystem
  769  */
  770 int
  771 nfs_root(struct mount *mp, struct vnode **vpp)
  772 {
  773         struct vnode *vp;
  774         struct nfsmount *nmp;
  775         int error;
  776 
  777         nmp = VFSTONFS(mp);
  778         vp = nmp->nm_vnode;
  779         vref(vp);
  780         error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
  781         if (error) {
  782                 vrele(vp);
  783                 return (error);
  784         }
  785         *vpp = vp;
  786         return (0);
  787 }
  788 
  789 /*
  790  * Flush out the buffer cache
  791  */
  792 int
  793 nfs_sync(struct mount *mp, int waitfor, int stall, struct ucred *cred, struct proc *p)
  794 {
  795         struct vnode *vp;
  796         int allerror = 0;
  797         int empty, error, s;
  798 
  799         /*
  800          * Don't traverse the vnode list if we want to skip all of them.
  801          */
  802         if (waitfor == MNT_LAZY)
  803                 return (allerror);
  804 
  805         /*
  806          * Force stale buffer cache information to be flushed.
  807          */
  808 loop:
  809         TAILQ_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) {
  810                 /*
  811                  * If the vnode that we are about to sync is no longer
  812                  * associated with this mount point, start over.
  813                  */
  814                 if (vp->v_mount != mp)
  815                         goto loop;
  816                 if (VOP_ISLOCKED(vp))
  817                         continue;
  818                 s = splbio();
  819                 empty = LIST_EMPTY(&vp->v_dirtyblkhd);
  820                 splx(s);
  821                 if (empty)
  822                         continue;
  823                 if (vget(vp, LK_EXCLUSIVE))
  824                         goto loop;
  825                 error = VOP_FSYNC(vp, cred, waitfor, p);
  826                 if (error)
  827                         allerror = error;
  828                 vput(vp);
  829         }
  830 
  831         return (allerror);
  832 }
  833 
  834 /*
  835  * NFS flat namespace lookup.
  836  * Currently unsupported.
  837  */
  838 /* ARGSUSED */
  839 int
  840 nfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
  841 {
  842 
  843         return (EOPNOTSUPP);
  844 }
  845 
  846 /*
  847  * Do that sysctl thang...
  848  */
  849 int
  850 nfs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
  851     size_t newlen, struct proc *p)
  852 {
  853         int rv;
  854 
  855         /*
  856          * All names at this level are terminal.
  857          */
  858         if(namelen > 1)
  859                 return ENOTDIR; /* overloaded */
  860 
  861         switch(name[0]) {
  862         case NFS_NFSSTATS:
  863                 if(!oldp) {
  864                         *oldlenp = sizeof nfsstats;
  865                         return 0;
  866                 }
  867 
  868                 if(*oldlenp < sizeof nfsstats) {
  869                         *oldlenp = sizeof nfsstats;
  870                         return ENOMEM;
  871                 }
  872 
  873                 rv = copyout(&nfsstats, oldp, sizeof nfsstats);
  874                 if(rv) return rv;
  875 
  876                 if(newp && newlen != sizeof nfsstats)
  877                         return EINVAL;
  878 
  879                 if(newp) {
  880                         return copyin(newp, &nfsstats, sizeof nfsstats);
  881                 }
  882                 return 0;
  883 
  884         case NFS_NIOTHREADS:
  885                 nfs_getset_niothreads(0);
  886 
  887                 rv = sysctl_int(oldp, oldlenp, newp, newlen, &nfs_niothreads);
  888                 if (newp)
  889                         nfs_getset_niothreads(1);
  890 
  891                 return rv;
  892 
  893         default:
  894                 return EOPNOTSUPP;
  895         }
  896 }
  897 
  898 
  899 /*
  900  * At this point, this should never happen
  901  */
  902 /* ARGSUSED */
  903 int
  904 nfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
  905 {
  906         return (EINVAL);
  907 }
  908 
  909 /*
  910  * Vnode pointer to File handle, should never happen either
  911  */
  912 /* ARGSUSED */
  913 int
  914 nfs_vptofh(struct vnode *vp, struct fid *fhp)
  915 {
  916         return (EINVAL);
  917 }
  918 
  919 /*
  920  * Vfs start routine, a no-op.
  921  */
  922 /* ARGSUSED */
  923 int
  924 nfs_start(struct mount *mp, int flags, struct proc *p)
  925 {
  926         return (0);
  927 }
  928 
  929 /*
  930  * Do operations associated with quotas, not supported
  931  */
  932 /* ARGSUSED */
  933 int
  934 nfs_quotactl(struct mount *mp, int cmd, uid_t uid, caddr_t arg, struct proc *p)
  935 {
  936         return (EOPNOTSUPP);
  937 }
  938 
  939 /*
  940  * check export permission, not supported
  941  */
  942 /* ARGUSED */
  943 int
  944 nfs_checkexp(struct mount *mp, struct mbuf *nam, int *exflagsp,
  945     struct ucred **credanonp)
  946 {
  947         return (EOPNOTSUPP);
  948 }
  949 

Cache object: f9d545adb9ef25a62ac37847562ae227


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