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/union/union_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 /*      $NetBSD: union_vfsops.c,v 1.40.2.1 2007/02/17 23:27:46 tron Exp $       */
    2 
    3 /*
    4  * Copyright (c) 1994 The Regents of the University of California.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software donated to Berkeley by
    8  * Jan-Simon Pendry.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. Neither the name of the University nor the names of its contributors
   19  *    may be used to endorse or promote products derived from this software
   20  *    without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   32  * SUCH DAMAGE.
   33  *
   34  *      @(#)union_vfsops.c      8.20 (Berkeley) 5/20/95
   35  */
   36 
   37 /*
   38  * Copyright (c) 1994 Jan-Simon Pendry.
   39  * All rights reserved.
   40  *
   41  * This code is derived from software donated to Berkeley by
   42  * Jan-Simon Pendry.
   43  *
   44  * Redistribution and use in source and binary forms, with or without
   45  * modification, are permitted provided that the following conditions
   46  * are met:
   47  * 1. Redistributions of source code must retain the above copyright
   48  *    notice, this list of conditions and the following disclaimer.
   49  * 2. Redistributions in binary form must reproduce the above copyright
   50  *    notice, this list of conditions and the following disclaimer in the
   51  *    documentation and/or other materials provided with the distribution.
   52  * 3. All advertising materials mentioning features or use of this software
   53  *    must display the following acknowledgement:
   54  *      This product includes software developed by the University of
   55  *      California, Berkeley and its contributors.
   56  * 4. Neither the name of the University nor the names of its contributors
   57  *    may be used to endorse or promote products derived from this software
   58  *    without specific prior written permission.
   59  *
   60  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   61  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   62  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   63  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   64  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   65  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   66  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   67  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   68  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   69  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   70  * SUCH DAMAGE.
   71  *
   72  *      @(#)union_vfsops.c      8.20 (Berkeley) 5/20/95
   73  */
   74 
   75 /*
   76  * Union Layer
   77  */
   78 
   79 #include <sys/cdefs.h>
   80 __KERNEL_RCSID(0, "$NetBSD: union_vfsops.c,v 1.40.2.1 2007/02/17 23:27:46 tron Exp $");
   81 
   82 #include <sys/param.h>
   83 #include <sys/systm.h>
   84 #include <sys/sysctl.h>
   85 #include <sys/time.h>
   86 #include <sys/proc.h>
   87 #include <sys/vnode.h>
   88 #include <sys/mount.h>
   89 #include <sys/namei.h>
   90 #include <sys/malloc.h>
   91 #include <sys/filedesc.h>
   92 #include <sys/queue.h>
   93 #include <sys/stat.h>
   94 #include <sys/kauth.h>
   95 
   96 #include <fs/union/union.h>
   97 
   98 int union_mount(struct mount *, const char *, void *, struct nameidata *,
   99                      struct lwp *);
  100 int union_start(struct mount *, int, struct lwp *);
  101 int union_unmount(struct mount *, int, struct lwp *);
  102 int union_root(struct mount *, struct vnode **);
  103 int union_quotactl(struct mount *, int, uid_t, void *, struct lwp *);
  104 int union_statvfs(struct mount *, struct statvfs *, struct lwp *);
  105 int union_sync(struct mount *, int, kauth_cred_t, struct lwp *);
  106 int union_vget(struct mount *, ino_t, struct vnode **);
  107 
  108 /*
  109  * Mount union filesystem
  110  */
  111 int
  112 union_mount(mp, path, data, ndp, l)
  113         struct mount *mp;
  114         const char *path;
  115         void *data;
  116         struct nameidata *ndp;
  117         struct lwp *l;
  118 {
  119         int error = 0;
  120         struct union_args args;
  121         struct vnode *lowerrootvp = NULLVP;
  122         struct vnode *upperrootvp = NULLVP;
  123         struct union_mount *um = 0;
  124         const char *cp;
  125         char *xp;
  126         int len;
  127         size_t size;
  128 
  129 #ifdef UNION_DIAGNOSTIC
  130         printf("union_mount(mp = %p)\n", mp);
  131 #endif
  132 
  133         if (mp->mnt_flag & MNT_GETARGS) {
  134                 um = MOUNTTOUNIONMOUNT(mp);
  135                 if (um == NULL)
  136                         return EIO;
  137                 args.target = NULL;
  138                 args.mntflags = um->um_op;
  139                 return copyout(&args, data, sizeof(args));
  140         }
  141         /*
  142          * Update is a no-op
  143          */
  144         if (mp->mnt_flag & MNT_UPDATE) {
  145                 /*
  146                  * Need to provide.
  147                  * 1. a way to convert between rdonly and rdwr mounts.
  148                  * 2. support for nfs exports.
  149                  */
  150                 error = EOPNOTSUPP;
  151                 goto bad;
  152         }
  153 
  154         /*
  155          * Get argument
  156          */
  157         error = copyin(data, &args, sizeof(struct union_args));
  158         if (error)
  159                 goto bad;
  160 
  161         lowerrootvp = mp->mnt_vnodecovered;
  162         VREF(lowerrootvp);
  163 
  164         /*
  165          * Find upper node.
  166          */
  167         NDINIT(ndp, LOOKUP, FOLLOW,
  168                UIO_USERSPACE, args.target, l);
  169 
  170         if ((error = namei(ndp)) != 0)
  171                 goto bad;
  172 
  173         upperrootvp = ndp->ni_vp;
  174 
  175         if (upperrootvp->v_type != VDIR) {
  176                 error = EINVAL;
  177                 goto bad;
  178         }
  179 
  180         um = (struct union_mount *) malloc(sizeof(struct union_mount),
  181                                 M_UFSMNT, M_WAITOK);    /* XXX */
  182 
  183         /*
  184          * Keep a held reference to the target vnodes.
  185          * They are vrele'd in union_unmount.
  186          *
  187          * Depending on the _BELOW flag, the filesystems are
  188          * viewed in a different order.  In effect, this is the
  189          * same as providing a mount under option to the mount syscall.
  190          */
  191 
  192         um->um_op = args.mntflags & UNMNT_OPMASK;
  193         switch (um->um_op) {
  194         case UNMNT_ABOVE:
  195                 um->um_lowervp = lowerrootvp;
  196                 um->um_uppervp = upperrootvp;
  197                 break;
  198 
  199         case UNMNT_BELOW:
  200                 um->um_lowervp = upperrootvp;
  201                 um->um_uppervp = lowerrootvp;
  202                 break;
  203 
  204         case UNMNT_REPLACE:
  205                 vrele(lowerrootvp);
  206                 lowerrootvp = NULLVP;
  207                 um->um_uppervp = upperrootvp;
  208                 um->um_lowervp = lowerrootvp;
  209                 break;
  210 
  211         default:
  212                 error = EINVAL;
  213                 goto bad;
  214         }
  215 
  216         /*
  217          * Unless the mount is readonly, ensure that the top layer
  218          * supports whiteout operations
  219          */
  220         if ((mp->mnt_flag & MNT_RDONLY) == 0) {
  221                 error = VOP_WHITEOUT(um->um_uppervp, (struct componentname *) 0, LOOKUP);
  222                 if (error)
  223                         goto bad;
  224         }
  225 
  226         um->um_cred = l->l_cred;
  227         kauth_cred_hold(um->um_cred);
  228         um->um_cmode = UN_DIRMODE &~ l->l_proc->p_cwdi->cwdi_cmask;
  229 
  230         /*
  231          * Depending on what you think the MNT_LOCAL flag might mean,
  232          * you may want the && to be || on the conditional below.
  233          * At the moment it has been defined that the filesystem is
  234          * only local if it is all local, ie the MNT_LOCAL flag implies
  235          * that the entire namespace is local.  If you think the MNT_LOCAL
  236          * flag implies that some of the files might be stored locally
  237          * then you will want to change the conditional.
  238          */
  239         if (um->um_op == UNMNT_ABOVE) {
  240                 if (((um->um_lowervp == NULLVP) ||
  241                      (um->um_lowervp->v_mount->mnt_flag & MNT_LOCAL)) &&
  242                     (um->um_uppervp->v_mount->mnt_flag & MNT_LOCAL))
  243                         mp->mnt_flag |= MNT_LOCAL;
  244         }
  245 
  246         /*
  247          * Copy in the upper layer's RDONLY flag.  This is for the benefit
  248          * of lookup() which explicitly checks the flag, rather than asking
  249          * the filesystem for it's own opinion.  This means, that an update
  250          * mount of the underlying filesystem to go from rdonly to rdwr
  251          * will leave the unioned view as read-only.
  252          */
  253         mp->mnt_flag |= (um->um_uppervp->v_mount->mnt_flag & MNT_RDONLY);
  254 
  255         mp->mnt_data = um;
  256         mp->mnt_leaf = um->um_uppervp->v_mount->mnt_leaf;
  257         vfs_getnewfsid(mp);
  258 
  259         error = set_statvfs_info( path, UIO_USERSPACE, NULL, UIO_USERSPACE,
  260             mp, l);
  261         if (error)
  262                 goto bad;
  263 
  264         switch (um->um_op) {
  265         case UNMNT_ABOVE:
  266                 cp = "<above>:";
  267                 break;
  268         case UNMNT_BELOW:
  269                 cp = "<below>:";
  270                 break;
  271         case UNMNT_REPLACE:
  272                 cp = "";
  273                 break;
  274         default:
  275                 cp = "<invalid>:";
  276 #ifdef DIAGNOSTIC
  277                 panic("union_mount: bad um_op");
  278 #endif
  279                 break;
  280         }
  281         len = strlen(cp);
  282         memcpy(mp->mnt_stat.f_mntfromname, cp, len);
  283 
  284         xp = mp->mnt_stat.f_mntfromname + len;
  285         len = MNAMELEN - len;
  286 
  287         (void) copyinstr(args.target, xp, len - 1, &size);
  288         memset(xp + size, 0, len - size);
  289 
  290 #ifdef UNION_DIAGNOSTIC
  291         printf("union_mount: from %s, on %s\n",
  292             mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname);
  293 #endif
  294 
  295         /* Setup the readdir hook if it's not set already */
  296         if (!vn_union_readdir_hook)
  297                 vn_union_readdir_hook = union_readdirhook;
  298 
  299         return (0);
  300 
  301 bad:
  302         if (um)
  303                 free(um, M_UFSMNT);
  304         if (upperrootvp)
  305                 vrele(upperrootvp);
  306         if (lowerrootvp)
  307                 vrele(lowerrootvp);
  308         return (error);
  309 }
  310 
  311 /*
  312  * VFS start.  Nothing needed here - the start routine
  313  * on the underlying filesystem(s) will have been called
  314  * when that filesystem was mounted.
  315  */
  316  /*ARGSUSED*/
  317 int
  318 union_start(struct mount *mp, int flags,
  319     struct lwp *l)
  320 {
  321 
  322         return (0);
  323 }
  324 
  325 /*
  326  * Free reference to union layer
  327  */
  328 int
  329 union_unmount(struct mount *mp, int mntflags, struct lwp *l)
  330 {
  331         struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
  332         int freeing;
  333         int error;
  334 
  335 #ifdef UNION_DIAGNOSTIC
  336         printf("union_unmount(mp = %p)\n", mp);
  337 #endif
  338 
  339         /*
  340          * Keep flushing vnodes from the mount list.
  341          * This is needed because of the un_pvp held
  342          * reference to the parent vnode.
  343          * If more vnodes have been freed on a given pass,
  344          * the try again.  The loop will iterate at most
  345          * (d) times, where (d) is the maximum tree depth
  346          * in the filesystem.
  347          */
  348         for (freeing = 0; (error = vflush(mp, NULL, 0)) != 0;) {
  349                 struct vnode *vp;
  350                 int n;
  351 
  352                 /* count #vnodes held on mount list */
  353                 n = 0;
  354                 TAILQ_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes)
  355                         n++;
  356 
  357                 /* if this is unchanged then stop */
  358                 if (n == freeing)
  359                         break;
  360 
  361                 /* otherwise try once more time */
  362                 freeing = n;
  363         }
  364 
  365         /*
  366          * Ok, now that we've tried doing it gently, get out the hammer.
  367          */
  368 
  369         if (mntflags & MNT_FORCE)
  370                 error = vflush(mp, NULL, FORCECLOSE);
  371 
  372         if (error)
  373                 return error;
  374 
  375         /*
  376          * Discard references to upper and lower target vnodes.
  377          */
  378         if (um->um_lowervp)
  379                 vrele(um->um_lowervp);
  380         vrele(um->um_uppervp);
  381         kauth_cred_free(um->um_cred);
  382         /*
  383          * Finally, throw away the union_mount structure
  384          */
  385         free(mp->mnt_data, M_UFSMNT);   /* XXX */
  386         mp->mnt_data = 0;
  387         return (0);
  388 }
  389 
  390 int
  391 union_root(mp, vpp)
  392         struct mount *mp;
  393         struct vnode **vpp;
  394 {
  395         struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
  396         int error;
  397 
  398         /*
  399          * Return locked reference to root.
  400          */
  401         VREF(um->um_uppervp);
  402         vn_lock(um->um_uppervp, LK_EXCLUSIVE | LK_RETRY);
  403         if (um->um_lowervp)
  404                 VREF(um->um_lowervp);
  405         error = union_allocvp(vpp, mp, NULL, NULL, NULL,
  406                               um->um_uppervp, um->um_lowervp, 1);
  407 
  408         if (error) {
  409                 vput(um->um_uppervp);
  410                 if (um->um_lowervp)
  411                         vrele(um->um_lowervp);
  412         }
  413 
  414         return (error);
  415 }
  416 
  417 /*ARGSUSED*/
  418 int
  419 union_quotactl(struct mount *mp, int cmd, uid_t uid,
  420     void *arg, struct lwp *l)
  421 {
  422 
  423         return (EOPNOTSUPP);
  424 }
  425 
  426 int
  427 union_statvfs(mp, sbp, l)
  428         struct mount *mp;
  429         struct statvfs *sbp;
  430         struct lwp *l;
  431 {
  432         int error;
  433         struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
  434         struct statvfs *sbuf = malloc(sizeof(*sbuf), M_TEMP, M_WAITOK | M_ZERO);
  435         unsigned long lbsize;
  436 
  437 #ifdef UNION_DIAGNOSTIC
  438         printf("union_statvfs(mp = %p, lvp = %p, uvp = %p)\n", mp,
  439             um->um_lowervp, um->um_uppervp);
  440 #endif
  441 
  442         if (um->um_lowervp) {
  443                 error = VFS_STATVFS(um->um_lowervp->v_mount, sbuf, l);
  444                 if (error)
  445                         goto done;
  446         }
  447 
  448         /* now copy across the "interesting" information and fake the rest */
  449         lbsize = sbuf->f_bsize;
  450         sbp->f_blocks = sbuf->f_blocks - sbuf->f_bfree;
  451         sbp->f_files = sbuf->f_files - sbuf->f_ffree;
  452 
  453         error = VFS_STATVFS(um->um_uppervp->v_mount, sbuf, l);
  454         if (error)
  455                 goto done;
  456 
  457         sbp->f_flag = sbuf->f_flag;
  458         sbp->f_bsize = sbuf->f_bsize;
  459         sbp->f_frsize = sbuf->f_frsize;
  460         sbp->f_iosize = sbuf->f_iosize;
  461 
  462         /*
  463          * The "total" fields count total resources in all layers,
  464          * the "free" fields count only those resources which are
  465          * free in the upper layer (since only the upper layer
  466          * is writable).
  467          */
  468 
  469         if (sbuf->f_bsize != lbsize)
  470                 sbp->f_blocks = sbp->f_blocks * lbsize / sbuf->f_bsize;
  471         sbp->f_blocks += sbuf->f_blocks;
  472         sbp->f_bfree = sbuf->f_bfree;
  473         sbp->f_bavail = sbuf->f_bavail;
  474         sbp->f_bresvd = sbuf->f_bresvd;
  475         sbp->f_files += sbuf->f_files;
  476         sbp->f_ffree = sbuf->f_ffree;
  477         sbp->f_favail = sbuf->f_favail;
  478         sbp->f_fresvd = sbuf->f_fresvd;
  479 
  480         copy_statvfs_info(sbp, mp);
  481 done:
  482         free(sbuf, M_TEMP);
  483         return error;
  484 }
  485 
  486 /*ARGSUSED*/
  487 int
  488 union_sync(struct mount *mp, int waitfor,
  489     kauth_cred_t cred, struct lwp *l)
  490 {
  491 
  492         /*
  493          * XXX - Assumes no data cached at union layer.
  494          */
  495         return (0);
  496 }
  497 
  498 /*ARGSUSED*/
  499 int
  500 union_vget(struct mount *mp, ino_t ino,
  501     struct vnode **vpp)
  502 {
  503 
  504         return (EOPNOTSUPP);
  505 }
  506 
  507 SYSCTL_SETUP(sysctl_vfs_union_setup, "sysctl vfs.union subtree setup")
  508 {
  509 
  510         sysctl_createv(clog, 0, NULL, NULL,
  511                        CTLFLAG_PERMANENT,
  512                        CTLTYPE_NODE, "vfs", NULL,
  513                        NULL, 0, NULL, 0,
  514                        CTL_VFS, CTL_EOL);
  515         sysctl_createv(clog, 0, NULL, NULL,
  516                        CTLFLAG_PERMANENT,
  517                        CTLTYPE_NODE, "union",
  518                        SYSCTL_DESCR("Union file system"),
  519                        NULL, 0, NULL, 0,
  520                        CTL_VFS, 15, CTL_EOL);
  521         /*
  522          * XXX the "15" above could be dynamic, thereby eliminating
  523          * one more instance of the "number to vfs" mapping problem,
  524          * but "15" is the order as taken from sys/mount.h
  525          */
  526 }
  527 
  528 extern const struct vnodeopv_desc union_vnodeop_opv_desc;
  529 
  530 const struct vnodeopv_desc * const union_vnodeopv_descs[] = {
  531         &union_vnodeop_opv_desc,
  532         NULL,
  533 };
  534 
  535 struct vfsops union_vfsops = {
  536         MOUNT_UNION,
  537         union_mount,
  538         union_start,
  539         union_unmount,
  540         union_root,
  541         union_quotactl,
  542         union_statvfs,
  543         union_sync,
  544         union_vget,
  545         (void *)eopnotsupp,             /* vfs_fhtovp */
  546         (void *)eopnotsupp,             /* vfs_vptofh */
  547         union_init,
  548         NULL,                           /* vfs_reinit */
  549         union_done,
  550         NULL,                           /* vfs_mountroot */
  551         (int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
  552         vfs_stdextattrctl,
  553         union_vnodeopv_descs,
  554         0,                              /* vfs_refcount */
  555         { NULL, NULL },
  556 };
  557 VFS_ATTACH(union_vfsops);

Cache object: 1f17f55f14a738f797f8692192bf49e2


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