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/fs/nullfs/null_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) 1992, 1993, 1995
    3  *      The Regents of the University of California.  All rights reserved.
    4  *
    5  * This code is derived from software donated to Berkeley by
    6  * Jan-Simon Pendry.
    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  * 4. Neither the name of the University nor the names of its contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  *
   32  *      @(#)null_vfsops.c       8.2 (Berkeley) 1/21/94
   33  *
   34  * @(#)lofs_vfsops.c    1.2 (Berkeley) 6/18/92
   35  * $FreeBSD: releng/6.4/sys/fs/nullfs/null_vfsops.c 176599 2008-02-26 18:19:49Z obrien $
   36  */
   37 
   38 /*
   39  * Null Layer
   40  * (See null_vnops.c for a description of what this does.)
   41  */
   42 
   43 #include <sys/param.h>
   44 #include <sys/systm.h>
   45 #include <sys/kdb.h>
   46 #include <sys/kernel.h>
   47 #include <sys/lock.h>
   48 #include <sys/malloc.h>
   49 #include <sys/mount.h>
   50 #include <sys/namei.h>
   51 #include <sys/proc.h>
   52 #include <sys/vnode.h>
   53 
   54 #include <fs/nullfs/null.h>
   55 
   56 static MALLOC_DEFINE(M_NULLFSMNT, "NULLFS mount", "NULLFS mount structure");
   57 
   58 static vfs_fhtovp_t     nullfs_fhtovp;
   59 static vfs_mount_t      nullfs_mount;
   60 static vfs_quotactl_t   nullfs_quotactl;
   61 static vfs_root_t       nullfs_root;
   62 static vfs_sync_t       nullfs_sync;
   63 static vfs_statfs_t     nullfs_statfs;
   64 static vfs_unmount_t    nullfs_unmount;
   65 static vfs_vget_t       nullfs_vget;
   66 static vfs_vptofh_t     nullfs_vptofh;
   67 static vfs_extattrctl_t nullfs_extattrctl;
   68 
   69 /*
   70  * Mount null layer
   71  */
   72 static int
   73 nullfs_mount(struct mount *mp, struct thread *td)
   74 {
   75         int error = 0;
   76         struct vnode *lowerrootvp, *vp;
   77         struct vnode *nullm_rootvp;
   78         struct null_mount *xmp;
   79         char *target;
   80         int isvnunlocked = 0, len;
   81         struct nameidata nd, *ndp = &nd;
   82 
   83         NULLFSDEBUG("nullfs_mount(mp = %p)\n", (void *)mp);
   84 
   85         if (mp->mnt_flag & MNT_ROOTFS)
   86                 return (EOPNOTSUPP);
   87         /*
   88          * Update is a no-op
   89          */
   90         if (mp->mnt_flag & MNT_UPDATE) {
   91                 /*
   92                  * Only support update mounts for NFS export.
   93                  */
   94                 if (vfs_flagopt(mp->mnt_optnew, "export", NULL, 0))
   95                         return (0);
   96                 else
   97                         return (EOPNOTSUPP);
   98         }
   99 
  100         /*
  101          * Get argument
  102          */
  103         error = vfs_getopt(mp->mnt_optnew, "target", (void **)&target, &len);
  104         if (error || target[len - 1] != '\0')
  105                 return (EINVAL);
  106 
  107         /*
  108          * Unlock lower node to avoid deadlock.
  109          * (XXX) VOP_ISLOCKED is needed?
  110          */
  111         if ((mp->mnt_vnodecovered->v_op == &null_vnodeops) &&
  112                 VOP_ISLOCKED(mp->mnt_vnodecovered, NULL)) {
  113                 VOP_UNLOCK(mp->mnt_vnodecovered, 0, td);
  114                 isvnunlocked = 1;
  115         }
  116         /*
  117          * Find lower node
  118          */
  119         NDINIT(ndp, LOOKUP, FOLLOW|LOCKLEAF,
  120                 UIO_SYSSPACE, target, td);
  121         error = namei(ndp);
  122         /*
  123          * Re-lock vnode.
  124          */
  125         if (isvnunlocked && !VOP_ISLOCKED(mp->mnt_vnodecovered, NULL))
  126                 vn_lock(mp->mnt_vnodecovered, LK_EXCLUSIVE | LK_RETRY, td);
  127 
  128         if (error)
  129                 return (error);
  130         NDFREE(ndp, NDF_ONLY_PNBUF);
  131 
  132         /*
  133          * Sanity check on lower vnode
  134          */
  135         lowerrootvp = ndp->ni_vp;
  136 
  137         /*
  138          * Check multi null mount to avoid `lock against myself' panic.
  139          */
  140         if (lowerrootvp == VTONULL(mp->mnt_vnodecovered)->null_lowervp) {
  141                 NULLFSDEBUG("nullfs_mount: multi null mount?\n");
  142                 vput(lowerrootvp);
  143                 return (EDEADLK);
  144         }
  145 
  146         xmp = (struct null_mount *) malloc(sizeof(struct null_mount),
  147                                 M_NULLFSMNT, M_WAITOK); /* XXX */
  148 
  149         /*
  150          * Save reference to underlying FS
  151          */
  152         xmp->nullm_vfs = lowerrootvp->v_mount;
  153 
  154         /*
  155          * Save reference.  Each mount also holds
  156          * a reference on the root vnode.
  157          */
  158         error = null_nodeget(mp, lowerrootvp, &vp);
  159         /*
  160          * Make sure the node alias worked
  161          */
  162         if (error) {
  163                 VOP_UNLOCK(vp, 0, td);
  164                 vrele(lowerrootvp);
  165                 free(xmp, M_NULLFSMNT); /* XXX */
  166                 return (error);
  167         }
  168 
  169         /*
  170          * Keep a held reference to the root vnode.
  171          * It is vrele'd in nullfs_unmount.
  172          */
  173         nullm_rootvp = vp;
  174         nullm_rootvp->v_vflag |= VV_ROOT;
  175         xmp->nullm_rootvp = nullm_rootvp;
  176 
  177         /*
  178          * Unlock the node (either the lower or the alias)
  179          */
  180         VOP_UNLOCK(vp, 0, td);
  181 
  182         if (NULLVPTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL) {
  183                 MNT_ILOCK(mp);
  184                 mp->mnt_flag |= MNT_LOCAL;
  185                 MNT_IUNLOCK(mp);
  186         }
  187         MNT_ILOCK(mp);
  188         mp->mnt_kern_flag |= lowerrootvp->v_mount->mnt_kern_flag & MNTK_MPSAFE;
  189         MNT_IUNLOCK(mp);
  190         mp->mnt_data = (qaddr_t) xmp;
  191         vfs_getnewfsid(mp);
  192 
  193         vfs_mountedfrom(mp, target);
  194 
  195         NULLFSDEBUG("nullfs_mount: lower %s, alias at %s\n",
  196                 mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname);
  197         return (0);
  198 }
  199 
  200 /*
  201  * Free reference to null layer
  202  */
  203 static int
  204 nullfs_unmount(mp, mntflags, td)
  205         struct mount *mp;
  206         int mntflags;
  207         struct thread *td;
  208 {
  209         void *mntdata;
  210         int error;
  211         int flags = 0;
  212 
  213         NULLFSDEBUG("nullfs_unmount: mp = %p\n", (void *)mp);
  214 
  215         if (mntflags & MNT_FORCE)
  216                 flags |= FORCECLOSE;
  217 
  218         /* There is 1 extra root vnode reference (nullm_rootvp). */
  219         error = vflush(mp, 1, flags, td);
  220         if (error)
  221                 return (error);
  222 
  223         /*
  224          * Finally, throw away the null_mount structure
  225          */
  226         mntdata = mp->mnt_data;
  227         mp->mnt_data = 0;
  228         free(mntdata, M_NULLFSMNT);
  229         return 0;
  230 }
  231 
  232 static int
  233 nullfs_root(mp, flags, vpp, td)
  234         struct mount *mp;
  235         int flags;
  236         struct vnode **vpp;
  237         struct thread *td;
  238 {
  239         struct vnode *vp;
  240 
  241         NULLFSDEBUG("nullfs_root(mp = %p, vp = %p->%p)\n", (void *)mp,
  242             (void *)MOUNTTONULLMOUNT(mp)->nullm_rootvp,
  243             (void *)NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp));
  244 
  245         /*
  246          * Return locked reference to root.
  247          */
  248         vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp;
  249         VREF(vp);
  250 
  251 #ifdef NULLFS_DEBUG
  252         if (VOP_ISLOCKED(vp, NULL)) {
  253                 kdb_enter("root vnode is locked.\n");
  254                 vrele(vp);
  255                 return (EDEADLK);
  256         }
  257 #endif
  258         vn_lock(vp, flags | LK_RETRY, td);
  259         *vpp = vp;
  260         return 0;
  261 }
  262 
  263 static int
  264 nullfs_quotactl(mp, cmd, uid, arg, td)
  265         struct mount *mp;
  266         int cmd;
  267         uid_t uid;
  268         caddr_t arg;
  269         struct thread *td;
  270 {
  271         return VFS_QUOTACTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, uid, arg, td);
  272 }
  273 
  274 static int
  275 nullfs_statfs(mp, sbp, td)
  276         struct mount *mp;
  277         struct statfs *sbp;
  278         struct thread *td;
  279 {
  280         int error;
  281         struct statfs mstat;
  282 
  283         NULLFSDEBUG("nullfs_statfs(mp = %p, vp = %p->%p)\n", (void *)mp,
  284             (void *)MOUNTTONULLMOUNT(mp)->nullm_rootvp,
  285             (void *)NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp));
  286 
  287         bzero(&mstat, sizeof(mstat));
  288 
  289         error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, &mstat, td);
  290         if (error)
  291                 return (error);
  292 
  293         /* now copy across the "interesting" information and fake the rest */
  294         sbp->f_type = mstat.f_type;
  295         sbp->f_flags = mstat.f_flags;
  296         sbp->f_bsize = mstat.f_bsize;
  297         sbp->f_iosize = mstat.f_iosize;
  298         sbp->f_blocks = mstat.f_blocks;
  299         sbp->f_bfree = mstat.f_bfree;
  300         sbp->f_bavail = mstat.f_bavail;
  301         sbp->f_files = mstat.f_files;
  302         sbp->f_ffree = mstat.f_ffree;
  303         return (0);
  304 }
  305 
  306 static int
  307 nullfs_sync(mp, waitfor, td)
  308         struct mount *mp;
  309         int waitfor;
  310         struct thread *td;
  311 {
  312         /*
  313          * XXX - Assumes no data cached at null layer.
  314          */
  315         return (0);
  316 }
  317 
  318 static int
  319 nullfs_vget(mp, ino, flags, vpp)
  320         struct mount *mp;
  321         ino_t ino;
  322         int flags;
  323         struct vnode **vpp;
  324 {
  325         int error;
  326         error = VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, flags, vpp);
  327         if (error)
  328                 return (error);
  329 
  330         return (null_nodeget(mp, *vpp, vpp));
  331 }
  332 
  333 static int
  334 nullfs_fhtovp(mp, fidp, vpp)
  335         struct mount *mp;
  336         struct fid *fidp;
  337         struct vnode **vpp;
  338 {
  339         int error;
  340         error = VFS_FHTOVP(MOUNTTONULLMOUNT(mp)->nullm_vfs, fidp, vpp);
  341         if (error)
  342                 return (error);
  343 
  344         return (null_nodeget(mp, *vpp, vpp));
  345 }
  346 
  347 static int
  348 nullfs_vptofh(vp, fhp)
  349         struct vnode *vp;
  350         struct fid *fhp;
  351 {
  352         struct vnode *lvp;
  353 
  354         lvp = NULLVPTOLOWERVP(vp);
  355         return VFS_VPTOFH(lvp, fhp);
  356 }
  357 
  358 static int                        
  359 nullfs_extattrctl(mp, cmd, filename_vp, namespace, attrname, td)
  360         struct mount *mp;
  361         int cmd;
  362         struct vnode *filename_vp;
  363         int namespace;
  364         const char *attrname;
  365         struct thread *td;            
  366 {
  367         return VFS_EXTATTRCTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, filename_vp,
  368             namespace, attrname, td);
  369 }
  370 
  371 
  372 static struct vfsops null_vfsops = {
  373         .vfs_extattrctl =       nullfs_extattrctl,
  374         .vfs_fhtovp =           nullfs_fhtovp,
  375         .vfs_init =             nullfs_init,
  376         .vfs_mount =            nullfs_mount,
  377         .vfs_quotactl =         nullfs_quotactl,
  378         .vfs_root =             nullfs_root,
  379         .vfs_statfs =           nullfs_statfs,
  380         .vfs_sync =             nullfs_sync,
  381         .vfs_uninit =           nullfs_uninit,
  382         .vfs_unmount =          nullfs_unmount,
  383         .vfs_vget =             nullfs_vget,
  384         .vfs_vptofh =           nullfs_vptofh,
  385 };
  386 
  387 VFS_SET(null_vfsops, nullfs, VFCF_LOOPBACK);

Cache object: 967dca88af5c5b515edb3156ef818340


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