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/miscfs/union/union_vnops.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, 1994, 1995 Jan-Simon Pendry.
    3  * Copyright (c) 1992, 1993, 1994, 1995
    4  *      The Regents of the University of California.  All rights reserved.
    5  *
    6  * This code is derived from software contributed to Berkeley by
    7  * Jan-Simon Pendry.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  * 3. All advertising materials mentioning features or use of this software
   18  *    must display the following acknowledgement:
   19  *      This product includes software developed by the University of
   20  *      California, Berkeley and its contributors.
   21  * 4. Neither the name of the University nor the names of its contributors
   22  *    may be used to endorse or promote products derived from this software
   23  *    without specific prior written permission.
   24  *
   25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   35  * SUCH DAMAGE.
   36  *
   37  *      @(#)union_vnops.c       8.32 (Berkeley) 6/23/95
   38  * $FreeBSD$
   39  */
   40 
   41 #include <sys/param.h>
   42 #include <sys/systm.h>
   43 #include <sys/proc.h>
   44 #include <sys/fcntl.h>
   45 #include <sys/stat.h>
   46 #include <sys/kernel.h>
   47 #include <sys/vnode.h>
   48 #include <sys/mount.h>
   49 #include <sys/namei.h>
   50 #include <sys/malloc.h>
   51 #include <sys/buf.h>
   52 #include <sys/lock.h>
   53 #include <miscfs/union/union.h>
   54 
   55 #define FIXUP(un, p) { \
   56         if (((un)->un_flags & UN_ULOCK) == 0) { \
   57                 union_fixup(un, p); \
   58         } \
   59 }
   60 
   61 static int      union_abortop __P((struct vop_abortop_args *ap));
   62 static int      union_access __P((struct vop_access_args *ap));
   63 static int      union_advlock __P((struct vop_advlock_args *ap));
   64 static int      union_bmap __P((struct vop_bmap_args *ap));
   65 static int      union_close __P((struct vop_close_args *ap));
   66 static int      union_create __P((struct vop_create_args *ap));
   67 static void     union_fixup __P((struct union_node *un, struct proc *p));
   68 static int      union_fsync __P((struct vop_fsync_args *ap));
   69 static int      union_getattr __P((struct vop_getattr_args *ap));
   70 static int      union_inactive __P((struct vop_inactive_args *ap));
   71 static int      union_ioctl __P((struct vop_ioctl_args *ap));
   72 static int      union_islocked __P((struct vop_islocked_args *ap));
   73 static int      union_lease __P((struct vop_lease_args *ap));
   74 static int      union_link __P((struct vop_link_args *ap));
   75 static int      union_lock __P((struct vop_lock_args *ap));
   76 static int      union_lookup __P((struct vop_lookup_args *ap));
   77 static int      union_lookup1 __P((struct vnode *udvp, struct vnode **dvpp,
   78                                    struct vnode **vpp,
   79                                    struct componentname *cnp));
   80 static int      union_mkdir __P((struct vop_mkdir_args *ap));
   81 static int      union_mknod __P((struct vop_mknod_args *ap));
   82 static int      union_mmap __P((struct vop_mmap_args *ap));
   83 static int      union_open __P((struct vop_open_args *ap));
   84 static int      union_pathconf __P((struct vop_pathconf_args *ap));
   85 static int      union_print __P((struct vop_print_args *ap));
   86 static int      union_read __P((struct vop_read_args *ap));
   87 static int      union_readdir __P((struct vop_readdir_args *ap));
   88 static int      union_readlink __P((struct vop_readlink_args *ap));
   89 static int      union_reclaim __P((struct vop_reclaim_args *ap));
   90 static int      union_remove __P((struct vop_remove_args *ap));
   91 static int      union_rename __P((struct vop_rename_args *ap));
   92 static int      union_revoke __P((struct vop_revoke_args *ap));
   93 static int      union_rmdir __P((struct vop_rmdir_args *ap));
   94 static int      union_poll __P((struct vop_poll_args *ap));
   95 static int      union_setattr __P((struct vop_setattr_args *ap));
   96 static int      union_strategy __P((struct vop_strategy_args *ap));
   97 static int      union_symlink __P((struct vop_symlink_args *ap));
   98 static int      union_unlock __P((struct vop_unlock_args *ap));
   99 static int      union_whiteout __P((struct vop_whiteout_args *ap));
  100 static int      union_write __P((struct vop_read_args *ap));
  101 
  102 static void
  103 union_fixup(un, p)
  104         struct union_node *un;
  105         struct proc *p;
  106 {
  107 
  108         vn_lock(un->un_uppervp, LK_EXCLUSIVE | LK_RETRY, p);
  109         un->un_flags |= UN_ULOCK;
  110 }
  111 
  112 static int
  113 union_lookup1(udvp, dvpp, vpp, cnp)
  114         struct vnode *udvp;
  115         struct vnode **dvpp;
  116         struct vnode **vpp;
  117         struct componentname *cnp;
  118 {
  119         int error;
  120         struct proc *p = cnp->cn_proc;
  121         struct vnode *tdvp;
  122         struct vnode *dvp;
  123         struct mount *mp;
  124 
  125         dvp = *dvpp;
  126 
  127         /*
  128          * If stepping up the directory tree, check for going
  129          * back across the mount point, in which case do what
  130          * lookup would do by stepping back down the mount
  131          * hierarchy.
  132          */
  133         if (cnp->cn_flags & ISDOTDOT) {
  134                 while ((dvp != udvp) && (dvp->v_flag & VROOT)) {
  135                         /*
  136                          * Don't do the NOCROSSMOUNT check
  137                          * at this level.  By definition,
  138                          * union fs deals with namespaces, not
  139                          * filesystems.
  140                          */
  141                         tdvp = dvp;
  142                         *dvpp = dvp = dvp->v_mount->mnt_vnodecovered;
  143                         vput(tdvp);
  144                         VREF(dvp);
  145                         vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
  146                 }
  147         }
  148 
  149         error = VOP_LOOKUP(dvp, &tdvp, cnp);
  150         if (error)
  151                 return (error);
  152 
  153         /*
  154          * The parent directory will have been unlocked, unless lookup
  155          * found the last component.  In which case, re-lock the node
  156          * here to allow it to be unlocked again (phew) in union_lookup.
  157          */
  158         if (dvp != tdvp && !(cnp->cn_flags & ISLASTCN))
  159                 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
  160 
  161         dvp = tdvp;
  162 
  163         /*
  164          * Lastly check if the current node is a mount point in
  165          * which case walk up the mount hierarchy making sure not to
  166          * bump into the root of the mount tree (ie. dvp != udvp).
  167          */
  168         while (dvp != udvp && (dvp->v_type == VDIR) &&
  169                (mp = dvp->v_mountedhere)) {
  170 
  171                 if (vfs_busy(mp, 0, 0, p))
  172                         continue;
  173 
  174                 error = VFS_ROOT(mp, &tdvp);
  175                 vfs_unbusy(mp, p);
  176                 if (error) {
  177                         vput(dvp);
  178                         return (error);
  179                 }
  180 
  181                 vput(dvp);
  182                 dvp = tdvp;
  183         }
  184 
  185         *vpp = dvp;
  186         return (0);
  187 }
  188 
  189 static int
  190 union_lookup(ap)
  191         struct vop_lookup_args /* {
  192                 struct vnodeop_desc *a_desc;
  193                 struct vnode *a_dvp;
  194                 struct vnode **a_vpp;
  195                 struct componentname *a_cnp;
  196         } */ *ap;
  197 {
  198         int error;
  199         int uerror, lerror;
  200         struct vnode *uppervp, *lowervp;
  201         struct vnode *upperdvp, *lowerdvp;
  202         struct vnode *dvp = ap->a_dvp;
  203         struct union_node *dun = VTOUNION(dvp);
  204         struct componentname *cnp = ap->a_cnp;
  205         struct proc *p = cnp->cn_proc;
  206         int lockparent = cnp->cn_flags & LOCKPARENT;
  207         struct union_mount *um = MOUNTTOUNIONMOUNT(dvp->v_mount);
  208         struct ucred *saved_cred = NULL;
  209         int iswhiteout;
  210         struct vattr va;
  211 
  212 
  213         /*
  214          * Disallow write attemps to the filesystem mounted read-only.
  215          */
  216         if ((cnp->cn_flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
  217                 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
  218                 return (EROFS);
  219 
  220 #ifdef notyet
  221         if (cnp->cn_namelen == 3 &&
  222                         cnp->cn_nameptr[2] == '.' &&
  223                         cnp->cn_nameptr[1] == '.' &&
  224                         cnp->cn_nameptr[0] == '.') {
  225                 dvp = *ap->a_vpp = LOWERVP(ap->a_dvp);
  226                 if (dvp == NULLVP)
  227                         return (ENOENT);
  228                 VREF(dvp);
  229                 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
  230                 if (!lockparent || !(cnp->cn_flags & ISLASTCN))
  231                         VOP_UNLOCK(ap->a_dvp, 0, p);
  232                 return (0);
  233         }
  234 #endif
  235 
  236         cnp->cn_flags |= LOCKPARENT;
  237 
  238         upperdvp = dun->un_uppervp;
  239         lowerdvp = dun->un_lowervp;
  240         uppervp = NULLVP;
  241         lowervp = NULLVP;
  242         iswhiteout = 0;
  243 
  244         if (cnp->cn_flags & ISDOTDOT) {
  245                 if (upperdvp != NULL)
  246                         VREF(upperdvp);
  247                 if (lowerdvp != NULL)
  248                         VREF(lowerdvp);
  249         }
  250 
  251         /*
  252          * do the lookup in the upper level.
  253          * if that level comsumes additional pathnames,
  254          * then assume that something special is going
  255          * on and just return that vnode.
  256          */
  257         if (upperdvp != NULLVP) {
  258                 FIXUP(dun, p);
  259                 /*
  260                  * If we're doing `..' in the underlying filesystem,
  261                  * we must drop our lock on the union node before
  262                  * going up the tree in the lower file system--if we block
  263                  * on the lowervp lock, and that's held by someone else
  264                  * coming down the tree and who's waiting for our lock,
  265                  * we would be hosed.
  266                  */
  267                 if (cnp->cn_flags & ISDOTDOT) {
  268                         /* retain lock on underlying VP: */
  269                         dun->un_flags |= UN_KLOCK;
  270                         VOP_UNLOCK(dvp, 0, p);
  271                 }
  272                 uerror = union_lookup1(um->um_uppervp, &upperdvp,
  273                                         &uppervp, cnp);
  274                 /*
  275                  * Disallow write attemps to the filesystem mounted read-only.
  276                  */
  277                 if (uerror == EJUSTRETURN && (cnp->cn_flags & ISLASTCN) &&
  278                         (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
  279                         (cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME)) {
  280                         if (!lockparent)
  281                                 cnp->cn_flags &= ~LOCKPARENT;
  282                         return (EROFS);
  283                 }
  284                         
  285                 if (cnp->cn_flags & ISDOTDOT) {
  286                         if (dun->un_uppervp == upperdvp) {
  287                                 /*
  288                                  * We got the underlying bugger back locked...
  289                                  * now take back the union node lock.  Since we
  290                                  * hold the uppervp lock, we can diddle union
  291                                  * locking flags at will. :)
  292                                  */
  293                                 dun->un_flags |= UN_ULOCK;
  294                         }
  295                         /*
  296                          * If upperdvp got swapped out, it means we did
  297                          * some mount point magic, and we do not have
  298                          * dun->un_uppervp locked currently--so we get it
  299                          * locked here (don't set the UN_ULOCK flag).
  300                          */
  301                         vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
  302                 }
  303 
  304                 /*if (uppervp == upperdvp)
  305                         dun->un_flags |= UN_KLOCK;*/
  306 
  307                 if (cnp->cn_consume != 0) {
  308                         *ap->a_vpp = uppervp;
  309                         if (!lockparent)
  310                                 cnp->cn_flags &= ~LOCKPARENT;
  311                         error = uerror;
  312                         goto out;
  313                 }
  314                 if (uerror == ENOENT || uerror == EJUSTRETURN) {
  315                         if (cnp->cn_flags & ISWHITEOUT) {
  316                                 iswhiteout = 1;
  317                         } else if (lowerdvp != NULLVP) {
  318                                 lerror = VOP_GETATTR(upperdvp, &va,
  319                                         cnp->cn_cred, cnp->cn_proc);
  320                                 if (lerror == 0 && (va.va_flags & OPAQUE))
  321                                         iswhiteout = 1;
  322                         }
  323                 }
  324         } else {
  325                 uerror = ENOENT;
  326         }
  327 
  328         /*
  329          * in a similar way to the upper layer, do the lookup
  330          * in the lower layer.   this time, if there is some
  331          * component magic going on, then vput whatever we got
  332          * back from the upper layer and return the lower vnode
  333          * instead.
  334          */
  335         if (lowerdvp != NULLVP && !iswhiteout) {
  336                 int nameiop;
  337 
  338                 vn_lock(lowerdvp, LK_EXCLUSIVE | LK_RETRY, p);
  339 
  340                 /*
  341                  * Only do a LOOKUP on the bottom node, since
  342                  * we won't be making changes to it anyway.
  343                  */
  344                 nameiop = cnp->cn_nameiop;
  345                 cnp->cn_nameiop = LOOKUP;
  346                 if (um->um_op == UNMNT_BELOW) {
  347                         saved_cred = cnp->cn_cred;
  348                         cnp->cn_cred = um->um_cred;
  349                 }
  350                 /*
  351                  * We shouldn't have to worry about locking interactions
  352                  * between the lower layer and our union layer (w.r.t.
  353                  * `..' processing) because we don't futz with lowervp
  354                  * locks in the union-node instantiation code path.
  355                  */
  356                 lerror = union_lookup1(um->um_lowervp, &lowerdvp,
  357                                 &lowervp, cnp);
  358                 if (um->um_op == UNMNT_BELOW)
  359                         cnp->cn_cred = saved_cred;
  360                 cnp->cn_nameiop = nameiop;
  361 
  362                 if (lowervp != lowerdvp)
  363                         VOP_UNLOCK(lowerdvp, 0, p);
  364 
  365                 if (cnp->cn_consume != 0 || lerror == EACCES) {
  366                         if (lerror == EACCES)
  367                                 lowervp = NULLVP;
  368                         if (uppervp != NULLVP) {
  369                                 if (uppervp == upperdvp)
  370                                         vrele(uppervp);
  371                                 else
  372                                         vput(uppervp);
  373                                 uppervp = NULLVP;
  374                         }
  375                         *ap->a_vpp = lowervp;
  376                         if (!lockparent)
  377                                 cnp->cn_flags &= ~LOCKPARENT;
  378                         error = lerror;
  379                         goto out;
  380                 }
  381         } else {
  382                 lerror = ENOENT;
  383                 if ((cnp->cn_flags & ISDOTDOT) && dun->un_pvp != NULLVP) {
  384                         lowervp = LOWERVP(dun->un_pvp);
  385                         if (lowervp != NULLVP) {
  386                                 VREF(lowervp);
  387                                 vn_lock(lowervp, LK_EXCLUSIVE | LK_RETRY, p);
  388                                 lerror = 0;
  389                         }
  390                 }
  391         }
  392 
  393         if (!lockparent)
  394                 cnp->cn_flags &= ~LOCKPARENT;
  395 
  396         /*
  397          * at this point, we have uerror and lerror indicating
  398          * possible errors with the lookups in the upper and lower
  399          * layers.  additionally, uppervp and lowervp are (locked)
  400          * references to existing vnodes in the upper and lower layers.
  401          *
  402          * there are now three cases to consider.
  403          * 1. if both layers returned an error, then return whatever
  404          *    error the upper layer generated.
  405          *
  406          * 2. if the top layer failed and the bottom layer succeeded
  407          *    then two subcases occur.
  408          *    a.  the bottom vnode is not a directory, in which
  409          *        case just return a new union vnode referencing
  410          *        an empty top layer and the existing bottom layer.
  411          *    b.  the bottom vnode is a directory, in which case
  412          *        create a new directory in the top-level and
  413          *        continue as in case 3.
  414          *
  415          * 3. if the top layer succeeded then return a new union
  416          *    vnode referencing whatever the new top layer and
  417          *    whatever the bottom layer returned.
  418          */
  419 
  420         *ap->a_vpp = NULLVP;
  421 
  422         /* case 1. */
  423         if ((uerror != 0) && (lerror != 0)) {
  424                 error = uerror;
  425                 goto out;
  426         }
  427 
  428         /* case 2. */
  429         if (uerror != 0 /* && (lerror == 0) */ ) {
  430                 if (lowervp->v_type == VDIR) { /* case 2b. */
  431                         dun->un_flags &= ~UN_ULOCK;
  432                         VOP_UNLOCK(upperdvp, 0, p);
  433                         uerror = union_mkshadow(um, upperdvp, cnp, &uppervp);
  434                         vn_lock(upperdvp, LK_EXCLUSIVE | LK_RETRY, p);
  435                         dun->un_flags |= UN_ULOCK;
  436 
  437                         if (uerror) {
  438                                 if (lowervp != NULLVP) {
  439                                         vput(lowervp);
  440                                         lowervp = NULLVP;
  441                                 }
  442                                 error = uerror;
  443                                 goto out;
  444                         }
  445                 }
  446         }
  447 
  448         if (lowervp != NULLVP)
  449                 VOP_UNLOCK(lowervp, 0, p);
  450 
  451         error = union_allocvp(ap->a_vpp, dvp->v_mount, dvp, upperdvp, cnp,
  452                               uppervp, lowervp, 1);
  453 
  454         if (error) {
  455                 if (uppervp != NULLVP)
  456                         vput(uppervp);
  457                 if (lowervp != NULLVP)
  458                         vrele(lowervp);
  459         } else {
  460                 if (*ap->a_vpp != dvp)
  461                         if (!lockparent || !(cnp->cn_flags & ISLASTCN))
  462                                 VOP_UNLOCK(dvp, 0, p);
  463 #ifdef DIAGNOSTIC
  464         if (cnp->cn_namelen == 1 &&
  465             cnp->cn_nameptr[0] == '.' &&
  466             *ap->a_vpp != dvp) {
  467             panic("union_lookup returning . (%p) not same as startdir (%p)",
  468                                   ap->a_vpp, dvp);
  469                 }
  470 #endif
  471         }
  472 
  473 out:
  474     if (cnp->cn_flags & ISDOTDOT) {
  475         if (upperdvp != NULL)
  476             vrele(upperdvp);
  477         if (lowerdvp != NULL)
  478             vrele(lowerdvp);
  479     }
  480 
  481         return (error);
  482 }
  483 
  484 static int
  485 union_create(ap)
  486         struct vop_create_args /* {
  487                 struct vnode *a_dvp;
  488                 struct vnode **a_vpp;
  489                 struct componentname *a_cnp;
  490                 struct vattr *a_vap;
  491         } */ *ap;
  492 {
  493         struct union_node *dun = VTOUNION(ap->a_dvp);
  494         struct vnode *dvp = dun->un_uppervp;
  495         struct componentname *cnp = ap->a_cnp;
  496         struct proc *p = cnp->cn_proc;
  497 
  498         if (dvp != NULLVP) {
  499                 struct vnode *vp;
  500                 struct mount *mp;
  501                 int error;
  502 
  503                 FIXUP(dun, p);
  504 
  505                 dun->un_flags |= UN_KLOCK;
  506                 VOP_UNLOCK(ap->a_dvp, 0, p);
  507                 error = VOP_CREATE(dvp, &vp, cnp, ap->a_vap);
  508                 if (error) {
  509                         dun->un_flags |= UN_ULOCK;
  510                         return (error);
  511                 }
  512 
  513                 mp = ap->a_dvp->v_mount;
  514                 VOP_UNLOCK(dvp, 0, p);
  515                 error = union_allocvp(ap->a_vpp, mp, NULLVP, NULLVP, cnp, vp,
  516                                 NULLVP, 1);
  517                 if (error)
  518                         vput(vp);
  519                 vn_lock(ap->a_dvp, LK_EXCLUSIVE| LK_RETRY, p);
  520                 return (error);
  521         }
  522 
  523         return (EROFS);
  524 }
  525 
  526 static int
  527 union_whiteout(ap)
  528         struct vop_whiteout_args /* {
  529                 struct vnode *a_dvp;
  530                 struct componentname *a_cnp;
  531                 int a_flags;
  532         } */ *ap;
  533 {
  534         struct union_node *un = VTOUNION(ap->a_dvp);
  535         struct componentname *cnp = ap->a_cnp;
  536         struct proc *p = cnp->cn_proc;
  537 
  538         if (un->un_uppervp == NULLVP)
  539                 return (EOPNOTSUPP);
  540 
  541         FIXUP(un, p);
  542         return (VOP_WHITEOUT(un->un_uppervp, cnp, ap->a_flags));
  543 }
  544 
  545 static int
  546 union_mknod(ap)
  547         struct vop_mknod_args /* {
  548                 struct vnode *a_dvp;
  549                 struct vnode **a_vpp;
  550                 struct componentname *a_cnp;
  551                 struct vattr *a_vap;
  552         } */ *ap;
  553 {
  554         struct union_node *dun = VTOUNION(ap->a_dvp);
  555         struct vnode *dvp = dun->un_uppervp;
  556         struct componentname *cnp = ap->a_cnp;
  557         struct proc *p = cnp->cn_proc;
  558 
  559         if (dvp != NULLVP) {
  560                 struct vnode *vp;
  561                 struct mount *mp;
  562                 int error;
  563 
  564                 FIXUP(dun, p);
  565 
  566                 dun->un_flags |= UN_KLOCK;
  567                 VOP_UNLOCK(ap->a_dvp, 0, p);
  568                 error = VOP_MKNOD(dvp, &vp, cnp, ap->a_vap);
  569                 if (error) {
  570                         dun->un_flags |= UN_ULOCK;
  571                         return (error);
  572                 }
  573 
  574                 if (vp != NULLVP) {
  575                         mp = ap->a_dvp->v_mount;
  576                         VOP_UNLOCK(dvp, 0, p);
  577                         error = union_allocvp(ap->a_vpp, mp, NULLVP, NULLVP,
  578                                         cnp, vp, NULLVP, 1);
  579                         if (error)
  580                                 vput(vp);
  581                         vn_lock(ap->a_dvp, LK_EXCLUSIVE| LK_RETRY, p);
  582                 } else {
  583                         dun->un_flags |= UN_ULOCK;
  584                 }
  585                 return (error);
  586         }
  587 
  588         return (EROFS);
  589 }
  590 
  591 static int
  592 union_open(ap)
  593         struct vop_open_args /* {
  594                 struct vnodeop_desc *a_desc;
  595                 struct vnode *a_vp;
  596                 int a_mode;
  597                 struct ucred *a_cred;
  598                 struct proc *a_p;
  599         } */ *ap;
  600 {
  601         struct union_node *un = VTOUNION(ap->a_vp);
  602         struct vnode *tvp;
  603         int mode = ap->a_mode;
  604         struct ucred *cred = ap->a_cred;
  605         struct proc *p = ap->a_p;
  606         int error;
  607 
  608         /*
  609          * If there is an existing upper vp then simply open that.
  610          */
  611         tvp = un->un_uppervp;
  612         if (tvp == NULLVP) {
  613                 /*
  614                  * If the lower vnode is being opened for writing, then
  615                  * copy the file contents to the upper vnode and open that,
  616                  * otherwise can simply open the lower vnode.
  617                  */
  618                 tvp = un->un_lowervp;
  619                 if ((ap->a_mode & FWRITE) && (tvp->v_type == VREG)) {
  620                         error = union_copyup(un, (mode&O_TRUNC) == 0, cred, p);
  621                         if (error == 0)
  622                                 error = VOP_OPEN(un->un_uppervp, mode, cred, p);
  623                         return (error);
  624                 }
  625 
  626                 /*
  627                  * Just open the lower vnode
  628                  */
  629                 un->un_openl++;
  630                 vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY, p);
  631                 error = VOP_OPEN(tvp, mode, cred, p);
  632                 VOP_UNLOCK(tvp, 0, p);
  633 
  634                 return (error);
  635         }
  636 
  637         FIXUP(un, p);
  638 
  639         error = VOP_OPEN(tvp, mode, cred, p);
  640 
  641         return (error);
  642 }
  643 
  644 static int
  645 union_close(ap)
  646         struct vop_close_args /* {
  647                 struct vnode *a_vp;
  648                 int  a_fflag;
  649                 struct ucred *a_cred;
  650                 struct proc *a_p;
  651         } */ *ap;
  652 {
  653         struct union_node *un = VTOUNION(ap->a_vp);
  654         struct vnode *vp;
  655 
  656         if ((vp = un->un_uppervp) == NULLVP) {
  657 #ifdef UNION_DIAGNOSTIC
  658                 if (un->un_openl <= 0)
  659                         panic("union: un_openl cnt");
  660 #endif
  661                 --un->un_openl;
  662                 vp = un->un_lowervp;
  663         }
  664 
  665         ap->a_vp = vp;
  666         return (VCALL(vp, VOFFSET(vop_close), ap));
  667 }
  668 
  669 /*
  670  * Check access permission on the union vnode.
  671  * The access check being enforced is to check
  672  * against both the underlying vnode, and any
  673  * copied vnode.  This ensures that no additional
  674  * file permissions are given away simply because
  675  * the user caused an implicit file copy.
  676  */
  677 static int
  678 union_access(ap)
  679         struct vop_access_args /* {
  680                 struct vnodeop_desc *a_desc;
  681                 struct vnode *a_vp;
  682                 int a_mode;
  683                 struct ucred *a_cred;
  684                 struct proc *a_p;
  685         } */ *ap;
  686 {
  687         struct union_node *un = VTOUNION(ap->a_vp);
  688         struct proc *p = ap->a_p;
  689         int error = EACCES;
  690         struct vnode *vp;
  691         struct vnode *savedvp;
  692 
  693         /*
  694          * Disallow write attempts on filesystems mounted read-only.
  695          */
  696         if (ap->a_mode & VWRITE && (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)) {
  697                 switch (ap->a_vp->v_type) {
  698                 case VREG: case VDIR: case VLNK:
  699                         return (EROFS);
  700                 }
  701         }
  702         if ((vp = un->un_uppervp) != NULLVP) {
  703                 FIXUP(un, p);
  704                 ap->a_vp = vp;
  705                 return (VCALL(vp, VOFFSET(vop_access), ap));
  706         }
  707 
  708         if ((vp = un->un_lowervp) != NULLVP) {
  709                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
  710                 savedvp = ap->a_vp;
  711                 ap->a_vp = vp;
  712                 error = VCALL(vp, VOFFSET(vop_access), ap);
  713                 if (error == 0) {
  714                         struct union_mount *um = MOUNTTOUNIONMOUNT(savedvp->v_mount);
  715 
  716                         if (um->um_op == UNMNT_BELOW) {
  717                                 ap->a_cred = um->um_cred;
  718                                 error = VCALL(vp, VOFFSET(vop_access), ap);
  719                         }
  720                 }
  721                 VOP_UNLOCK(vp, 0, p);
  722                 if (error)
  723                         return (error);
  724         }
  725 
  726         return (error);
  727 }
  728 
  729 /*
  730  * We handle getattr only to change the fsid and
  731  * track object sizes
  732  */
  733 static int
  734 union_getattr(ap)
  735         struct vop_getattr_args /* {
  736                 struct vnode *a_vp;
  737                 struct vattr *a_vap;
  738                 struct ucred *a_cred;
  739                 struct proc *a_p;
  740         } */ *ap;
  741 {
  742         int error;
  743         struct union_node *un = VTOUNION(ap->a_vp);
  744         struct vnode *vp = un->un_uppervp;
  745         struct proc *p = ap->a_p;
  746         struct vattr *vap;
  747         struct vattr va;
  748 
  749 
  750         /*
  751          * Some programs walk the filesystem hierarchy by counting
  752          * links to directories to avoid stat'ing all the time.
  753          * This means the link count on directories needs to be "correct".
  754          * The only way to do that is to call getattr on both layers
  755          * and fix up the link count.  The link count will not necessarily
  756          * be accurate but will be large enough to defeat the tree walkers.
  757          */
  758 
  759         vap = ap->a_vap;
  760 
  761         vp = un->un_uppervp;
  762         if (vp != NULLVP) {
  763                 /*
  764                  * It's not clear whether VOP_GETATTR is to be
  765                  * called with the vnode locked or not.  stat() calls
  766                  * it with (vp) locked, and fstat calls it with
  767                  * (vp) unlocked.
  768                  * In the mean time, compensate here by checking
  769                  * the union_node's lock flag.
  770                  */
  771                 if (un->un_flags & UN_LOCKED)
  772                         FIXUP(un, p);
  773 
  774                 error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p);
  775                 if (error)
  776                         return (error);
  777                 union_newsize(ap->a_vp, vap->va_size, VNOVAL);
  778         }
  779 
  780         if (vp == NULLVP) {
  781                 vp = un->un_lowervp;
  782         } else if (vp->v_type == VDIR && un->un_lowervp != NULLVP) {
  783                 vp = un->un_lowervp;
  784                 vap = &va;
  785         } else {
  786                 vp = NULLVP;
  787         }
  788 
  789         if (vp != NULLVP) {
  790                 error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p);
  791                 if (error)
  792                         return (error);
  793                 union_newsize(ap->a_vp, VNOVAL, vap->va_size);
  794         }
  795 
  796         if ((vap != ap->a_vap) && (vap->va_type == VDIR))
  797                 ap->a_vap->va_nlink += vap->va_nlink;
  798 
  799         ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
  800         return (0);
  801 }
  802 
  803 static int
  804 union_setattr(ap)
  805         struct vop_setattr_args /* {
  806                 struct vnode *a_vp;
  807                 struct vattr *a_vap;
  808                 struct ucred *a_cred;
  809                 struct proc *a_p;
  810         } */ *ap;
  811 {
  812         struct union_node *un = VTOUNION(ap->a_vp);
  813         struct proc *p = ap->a_p;
  814         struct vattr *vap = ap->a_vap;
  815         int error;
  816 
  817         /*
  818          * Disallow write attempts on filesystems mounted read-only.
  819          */
  820         if ((ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) &&
  821                 (vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
  822                  vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
  823                  vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL))
  824                 return (EROFS);
  825 
  826         /*
  827          * Handle case of truncating lower object to zero size,
  828          * by creating a zero length upper object.  This is to
  829          * handle the case of open with O_TRUNC and O_CREAT.
  830          */
  831         if ((un->un_uppervp == NULLVP) &&
  832             /* assert(un->un_lowervp != NULLVP) */
  833             (un->un_lowervp->v_type == VREG)) {
  834                 error = union_copyup(un, (ap->a_vap->va_size != 0),
  835                                                 ap->a_cred, ap->a_p);
  836                 if (error)
  837                         return (error);
  838         }
  839 
  840         /*
  841          * Try to set attributes in upper layer,
  842          * otherwise return read-only filesystem error.
  843          */
  844         if (un->un_uppervp != NULLVP) {
  845                 FIXUP(un, p);
  846                 error = VOP_SETATTR(un->un_uppervp, ap->a_vap,
  847                                         ap->a_cred, ap->a_p);
  848                 if ((error == 0) && (ap->a_vap->va_size != VNOVAL))
  849                         union_newsize(ap->a_vp, ap->a_vap->va_size, VNOVAL);
  850         } else {
  851                 error = EROFS;
  852         }
  853 
  854         return (error);
  855 }
  856 
  857 static int
  858 union_read(ap)
  859         struct vop_read_args /* {
  860                 struct vnode *a_vp;
  861                 struct uio *a_uio;
  862                 int  a_ioflag;
  863                 struct ucred *a_cred;
  864         } */ *ap;
  865 {
  866         int error;
  867         struct proc *p = ap->a_uio->uio_procp;
  868         struct vnode *vp = OTHERVP(ap->a_vp);
  869         int dolock = (vp == LOWERVP(ap->a_vp));
  870 
  871         if (dolock)
  872                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
  873         else
  874                 FIXUP(VTOUNION(ap->a_vp), p);
  875         error = VOP_READ(vp, ap->a_uio, ap->a_ioflag, ap->a_cred);
  876         if (dolock)
  877                 VOP_UNLOCK(vp, 0, p);
  878 
  879         /*
  880          * XXX
  881          * perhaps the size of the underlying object has changed under
  882          * our feet.  take advantage of the offset information present
  883          * in the uio structure.
  884          */
  885         if (error == 0) {
  886                 struct union_node *un = VTOUNION(ap->a_vp);
  887                 off_t cur = ap->a_uio->uio_offset;
  888 
  889                 if (vp == un->un_uppervp) {
  890                         if (cur > un->un_uppersz)
  891                                 union_newsize(ap->a_vp, cur, VNOVAL);
  892                 } else {
  893                         if (cur > un->un_lowersz)
  894                                 union_newsize(ap->a_vp, VNOVAL, cur);
  895                 }
  896         }
  897 
  898         return (error);
  899 }
  900 
  901 static int
  902 union_write(ap)
  903         struct vop_read_args /* {
  904                 struct vnode *a_vp;
  905                 struct uio *a_uio;
  906                 int  a_ioflag;
  907                 struct ucred *a_cred;
  908         } */ *ap;
  909 {
  910         int error;
  911         struct vnode *vp;
  912         struct union_node *un = VTOUNION(ap->a_vp);
  913         struct proc *p = ap->a_uio->uio_procp;
  914 
  915         vp = UPPERVP(ap->a_vp);
  916         if (vp == NULLVP)
  917                 panic("union: missing upper layer in write");
  918 
  919         FIXUP(un, p);
  920         error = VOP_WRITE(vp, ap->a_uio, ap->a_ioflag, ap->a_cred);
  921 
  922         /*
  923          * the size of the underlying object may be changed by the
  924          * write.
  925          */
  926         if (error == 0) {
  927                 off_t cur = ap->a_uio->uio_offset;
  928 
  929                 if (cur > un->un_uppersz)
  930                         union_newsize(ap->a_vp, cur, VNOVAL);
  931         }
  932 
  933         return (error);
  934 }
  935 
  936 static int
  937 union_lease(ap)
  938         struct vop_lease_args /* {
  939                 struct vnode *a_vp;
  940                 struct proc *a_p;
  941                 struct ucred *a_cred;
  942                 int a_flag;
  943         } */ *ap;
  944 {
  945         register struct vnode *ovp = OTHERVP(ap->a_vp);
  946 
  947         ap->a_vp = ovp;
  948         return (VCALL(ovp, VOFFSET(vop_lease), ap));
  949 }
  950 
  951 static int
  952 union_ioctl(ap)
  953         struct vop_ioctl_args /* {
  954                 struct vnode *a_vp;
  955                 int  a_command;
  956                 caddr_t  a_data;
  957                 int  a_fflag;
  958                 struct ucred *a_cred;
  959                 struct proc *a_p;
  960         } */ *ap;
  961 {
  962         register struct vnode *ovp = OTHERVP(ap->a_vp);
  963 
  964         ap->a_vp = ovp;
  965         return (VCALL(ovp, VOFFSET(vop_ioctl), ap));
  966 }
  967 
  968 static int
  969 union_poll(ap)
  970         struct vop_poll_args /* {
  971                 struct vnode *a_vp;
  972                 int  a_events;
  973                 struct ucred *a_cred;
  974                 struct proc *a_p;
  975         } */ *ap;
  976 {
  977         register struct vnode *ovp = OTHERVP(ap->a_vp);
  978 
  979         ap->a_vp = ovp;
  980         return (VCALL(ovp, VOFFSET(vop_poll), ap));
  981 }
  982 
  983 static int
  984 union_revoke(ap)
  985         struct vop_revoke_args /* {
  986                 struct vnode *a_vp;
  987                 int a_flags;
  988                 struct proc *a_p;
  989         } */ *ap;
  990 {
  991         struct vnode *vp = ap->a_vp;
  992 
  993         if (UPPERVP(vp))
  994                 VOP_REVOKE(UPPERVP(vp), ap->a_flags);
  995         if (LOWERVP(vp))
  996                 VOP_REVOKE(LOWERVP(vp), ap->a_flags);
  997         vgone(vp);
  998         return (0);
  999 }
 1000 
 1001 static int
 1002 union_mmap(ap)
 1003         struct vop_mmap_args /* {
 1004                 struct vnode *a_vp;
 1005                 int  a_fflags;
 1006                 struct ucred *a_cred;
 1007                 struct proc *a_p;
 1008         } */ *ap;
 1009 {
 1010         register struct vnode *ovp = OTHERVP(ap->a_vp);
 1011 
 1012         ap->a_vp = ovp;
 1013         return (VCALL(ovp, VOFFSET(vop_mmap), ap));
 1014 }
 1015 
 1016 static int
 1017 union_fsync(ap)
 1018         struct vop_fsync_args /* {
 1019                 struct vnode *a_vp;
 1020                 struct ucred *a_cred;
 1021                 int  a_waitfor;
 1022                 struct proc *a_p;
 1023         } */ *ap;
 1024 {
 1025         int error = 0;
 1026         struct proc *p = ap->a_p;
 1027         struct vnode *targetvp = OTHERVP(ap->a_vp);
 1028         struct union_node *un;
 1029 
 1030         if (targetvp != NULLVP) {
 1031                 int dolock = (targetvp == LOWERVP(ap->a_vp));
 1032 
 1033                 un = VTOUNION(ap->a_vp);
 1034                 if (dolock)
 1035                         vn_lock(targetvp, LK_EXCLUSIVE | LK_RETRY, p);
 1036                 else  {
 1037                         un = VTOUNION(ap->a_vp);
 1038                         if ((un->un_flags & UN_ULOCK) == 0 &&
 1039                             targetvp->v_data != NULL &&
 1040                             ((struct lock *)targetvp->v_data)->lk_lockholder
 1041                                 == curproc->p_pid &&
 1042                             VOP_ISLOCKED(targetvp) != 0)
 1043                                 return 0;   /* XXX */
 1044 
 1045                         FIXUP(un, p);
 1046                 }
 1047 
 1048                 error = VOP_FSYNC(targetvp, ap->a_cred, ap->a_waitfor, p);
 1049                 if (dolock)
 1050                         VOP_UNLOCK(targetvp, 0, p);
 1051         }
 1052 
 1053         return (error);
 1054 }
 1055 
 1056 static int
 1057 union_remove(ap)
 1058         struct vop_remove_args /* {
 1059                 struct vnode *a_dvp;
 1060                 struct vnode *a_vp;
 1061                 struct componentname *a_cnp;
 1062         } */ *ap;
 1063 {
 1064         struct union_node *dun = VTOUNION(ap->a_dvp);
 1065         struct union_node *un = VTOUNION(ap->a_vp);
 1066         struct componentname *cnp = ap->a_cnp;
 1067         struct proc *p = cnp->cn_proc;
 1068         int error;
 1069 
 1070         if (dun->un_uppervp == NULLVP)
 1071                 panic("union remove: null upper vnode");
 1072 
 1073         if (un->un_uppervp != NULLVP) {
 1074                 struct vnode *dvp = dun->un_uppervp;
 1075                 struct vnode *vp = un->un_uppervp;
 1076 
 1077                 FIXUP(dun, p);
 1078                 dun->un_flags |= UN_KLOCK;
 1079                 VOP_UNLOCK(ap->a_dvp, 0, p);
 1080                 FIXUP(un, p);
 1081                 un->un_flags |= UN_KLOCK;
 1082                 VOP_UNLOCK(ap->a_vp, 0, p);
 1083 
 1084                 if (union_dowhiteout(un, cnp->cn_cred, p))
 1085                         cnp->cn_flags |= DOWHITEOUT;
 1086                 error = VOP_REMOVE(dvp, vp, cnp);
 1087 #if 0
 1088                 /* XXX */
 1089                 if (!error)
 1090                         union_removed_upper(un);
 1091 #endif
 1092                 dun->un_flags |= UN_ULOCK;
 1093                 un->un_flags |= UN_ULOCK;
 1094         } else {
 1095                 FIXUP(dun, p);
 1096                 error = union_mkwhiteout(
 1097                         MOUNTTOUNIONMOUNT(UNIONTOV(dun)->v_mount),
 1098                         dun->un_uppervp, ap->a_cnp, un->un_path);
 1099         }
 1100 
 1101         return (error);
 1102 }
 1103 
 1104 static int
 1105 union_link(ap)
 1106         struct vop_link_args /* {
 1107                 struct vnode *a_tdvp;
 1108                 struct vnode *a_vp;
 1109                 struct componentname *a_cnp;
 1110         } */ *ap;
 1111 {
 1112         struct componentname *cnp = ap->a_cnp;
 1113         struct proc *p = cnp->cn_proc;
 1114         struct union_node *dun = VTOUNION(ap->a_tdvp);
 1115         struct vnode *vp;
 1116         struct vnode *tdvp;
 1117         int error = 0;
 1118 
 1119 
 1120         if (ap->a_tdvp->v_op != ap->a_vp->v_op) {
 1121                 vp = ap->a_vp;
 1122         } else {
 1123                 struct union_node *tun = VTOUNION(ap->a_vp);
 1124                 if (tun->un_uppervp == NULLVP) {
 1125                         vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p);
 1126                         if (dun->un_uppervp == tun->un_dirvp) {
 1127                                 dun->un_flags &= ~UN_ULOCK;
 1128                                 VOP_UNLOCK(dun->un_uppervp, 0, p);
 1129                         }
 1130                         error = union_copyup(tun, 1, cnp->cn_cred, p);
 1131                         if (dun->un_uppervp == tun->un_dirvp) {
 1132                                 vn_lock(dun->un_uppervp,
 1133                                                 LK_EXCLUSIVE | LK_RETRY, p);
 1134                                 dun->un_flags |= UN_ULOCK;
 1135                         }
 1136                         VOP_UNLOCK(ap->a_vp, 0, p);
 1137                 }
 1138                 vp = tun->un_uppervp;
 1139         }
 1140 
 1141         tdvp = dun->un_uppervp;
 1142         if (tdvp == NULLVP)
 1143                 error = EROFS;
 1144 
 1145         if (error)
 1146                 return (error);
 1147 
 1148         FIXUP(dun, p);
 1149         dun->un_flags |= UN_KLOCK;
 1150         VOP_UNLOCK(ap->a_tdvp, 0, p);
 1151 
 1152         error = VOP_LINK(tdvp, vp, cnp);
 1153 
 1154         dun->un_flags |= UN_ULOCK;
 1155 
 1156         return (error);
 1157 }
 1158 
 1159 static int
 1160 union_rename(ap)
 1161         struct vop_rename_args  /* {
 1162                 struct vnode *a_fdvp;
 1163                 struct vnode *a_fvp;
 1164                 struct componentname *a_fcnp;
 1165                 struct vnode *a_tdvp;
 1166                 struct vnode *a_tvp;
 1167                 struct componentname *a_tcnp;
 1168         } */ *ap;
 1169 {
 1170         int error;
 1171 
 1172         struct vnode *fdvp = ap->a_fdvp;
 1173         struct vnode *fvp = ap->a_fvp;
 1174         struct vnode *tdvp = ap->a_tdvp;
 1175         struct vnode *tvp = ap->a_tvp;
 1176 
 1177         if (fdvp->v_op == union_vnodeop_p) {    /* always true */
 1178                 struct union_node *un = VTOUNION(fdvp);
 1179                 if (un->un_uppervp == NULLVP) {
 1180                         /*
 1181                          * this should never happen in normal
 1182                          * operation but might if there was
 1183                          * a problem creating the top-level shadow
 1184                          * directory.
 1185                          */
 1186                         error = EXDEV;
 1187                         goto bad;
 1188                 }
 1189 
 1190                 fdvp = un->un_uppervp;
 1191                 VREF(fdvp);
 1192                 vrele(ap->a_fdvp);
 1193         }
 1194 
 1195         if (fvp->v_op == union_vnodeop_p) {     /* always true */
 1196                 struct union_node *un = VTOUNION(fvp);
 1197                 if (un->un_uppervp == NULLVP) {
 1198                         /* XXX: should do a copyup */
 1199                         error = EXDEV;
 1200                         goto bad;
 1201                 }
 1202 
 1203                 if (un->un_lowervp != NULLVP)
 1204                         ap->a_fcnp->cn_flags |= DOWHITEOUT;
 1205 
 1206                 fvp = un->un_uppervp;
 1207                 VREF(fvp);
 1208                 vrele(ap->a_fvp);
 1209         }
 1210 
 1211         if (tdvp->v_op == union_vnodeop_p) {
 1212                 struct union_node *un = VTOUNION(tdvp);
 1213                 if (un->un_uppervp == NULLVP) {
 1214                         /*
 1215                          * this should never happen in normal
 1216                          * operation but might if there was
 1217                          * a problem creating the top-level shadow
 1218                          * directory.
 1219                          */
 1220                         error = EXDEV;
 1221                         goto bad;
 1222                 }
 1223 
 1224                 tdvp = un->un_uppervp;
 1225                 VREF(tdvp);
 1226                 un->un_flags |= UN_KLOCK;
 1227                 vput(ap->a_tdvp);
 1228         }
 1229 
 1230         if (tvp != NULLVP && tvp->v_op == union_vnodeop_p) {
 1231                 struct union_node *un = VTOUNION(tvp);
 1232 
 1233                 tvp = un->un_uppervp;
 1234                 if (tvp != NULLVP) {
 1235                         VREF(tvp);
 1236                         un->un_flags |= UN_KLOCK;
 1237                 }
 1238                 vput(ap->a_tvp);
 1239         }
 1240 
 1241         return (VOP_RENAME(fdvp, fvp, ap->a_fcnp, tdvp, tvp, ap->a_tcnp));
 1242 
 1243 bad:
 1244         vrele(fdvp);
 1245         vrele(fvp);
 1246         vput(tdvp);
 1247         if (tvp != NULLVP)
 1248                 vput(tvp);
 1249 
 1250         return (error);
 1251 }
 1252 
 1253 static int
 1254 union_mkdir(ap)
 1255         struct vop_mkdir_args /* {
 1256                 struct vnode *a_dvp;
 1257                 struct vnode **a_vpp;
 1258                 struct componentname *a_cnp;
 1259                 struct vattr *a_vap;
 1260         } */ *ap;
 1261 {
 1262         struct union_node *dun = VTOUNION(ap->a_dvp);
 1263         struct vnode *dvp = dun->un_uppervp;
 1264         struct componentname *cnp = ap->a_cnp;
 1265         struct proc *p = cnp->cn_proc;
 1266 
 1267         if (dvp != NULLVP) {
 1268                 struct vnode *vp;
 1269                 int error;
 1270 
 1271                 FIXUP(dun, p);
 1272                 dun->un_flags |= UN_KLOCK;
 1273                 VOP_UNLOCK(ap->a_dvp, 0, p);
 1274                 error = VOP_MKDIR(dvp, &vp, cnp, ap->a_vap);
 1275                 if (error) {
 1276                         dun->un_flags |= UN_ULOCK;
 1277                         return (error);
 1278                 }
 1279 
 1280                 VOP_UNLOCK(dvp, 0, p);
 1281                 error = union_allocvp(ap->a_vpp, ap->a_dvp->v_mount, ap->a_dvp,
 1282                                 NULLVP, cnp, vp, NULLVP, 1);
 1283                 if (error)
 1284                         vput(vp);
 1285                 vn_lock(ap->a_dvp, LK_EXCLUSIVE| LK_RETRY, p);
 1286 
 1287                 return (error);
 1288         }
 1289 
 1290         return (EROFS);
 1291 }
 1292 
 1293 static int
 1294 union_rmdir(ap)
 1295         struct vop_rmdir_args /* {
 1296                 struct vnode *a_dvp;
 1297                 struct vnode *a_vp;
 1298                 struct componentname *a_cnp;
 1299         } */ *ap;
 1300 {
 1301         struct union_node *dun = VTOUNION(ap->a_dvp);
 1302         struct union_node *un = VTOUNION(ap->a_vp);
 1303         struct componentname *cnp = ap->a_cnp;
 1304         struct proc *p = cnp->cn_proc;
 1305         int error;
 1306 
 1307         if (dun->un_uppervp == NULLVP)
 1308                 panic("union rmdir: null upper vnode");
 1309 
 1310         if (un->un_uppervp != NULLVP) {
 1311                 struct vnode *dvp = dun->un_uppervp;
 1312                 struct vnode *vp = un->un_uppervp;
 1313 
 1314                 FIXUP(dun, p);
 1315                 dun->un_flags |= UN_KLOCK;
 1316                 VOP_UNLOCK(ap->a_dvp, 0, p);
 1317                 FIXUP(un, p);
 1318                 un->un_flags |= UN_KLOCK;
 1319                 VOP_UNLOCK(ap->a_vp, 0, p);
 1320 
 1321                 if (union_dowhiteout(un, cnp->cn_cred, p))
 1322                         cnp->cn_flags |= DOWHITEOUT;
 1323                 error = VOP_RMDIR(dvp, vp, ap->a_cnp);
 1324 #if 0
 1325                 /* XXX */
 1326                 if (!error)
 1327                         union_removed_upper(un);
 1328 #endif
 1329                 dun->un_flags |= UN_ULOCK;
 1330                 un->un_flags |= UN_ULOCK;
 1331         } else {
 1332                 FIXUP(dun, p);
 1333                 error = union_mkwhiteout(
 1334                         MOUNTTOUNIONMOUNT(UNIONTOV(dun)->v_mount),
 1335                         dun->un_uppervp, ap->a_cnp, un->un_path);
 1336         }
 1337 
 1338         return (error);
 1339 }
 1340 
 1341 static int
 1342 union_symlink(ap)
 1343         struct vop_symlink_args /* {
 1344                 struct vnode *a_dvp;
 1345                 struct vnode **a_vpp;
 1346                 struct componentname *a_cnp;
 1347                 struct vattr *a_vap;
 1348                 char *a_target;
 1349         } */ *ap;
 1350 {
 1351         struct union_node *dun = VTOUNION(ap->a_dvp);
 1352         struct vnode *dvp = dun->un_uppervp;
 1353         struct componentname *cnp = ap->a_cnp;
 1354         struct proc *p = cnp->cn_proc;
 1355 
 1356         if (dvp != NULLVP) {
 1357                 struct vnode *vp;
 1358                 int error;
 1359 
 1360                 FIXUP(dun, p);
 1361                 dun->un_flags |= UN_KLOCK;
 1362                 VOP_UNLOCK(ap->a_dvp, 0, p);
 1363                 error = VOP_SYMLINK(dvp, &vp, cnp, ap->a_vap, ap->a_target);
 1364                 dun->un_flags |= UN_ULOCK;
 1365                 *ap->a_vpp = NULLVP;
 1366                 return (error);
 1367         }
 1368 
 1369         return (EROFS);
 1370 }
 1371 
 1372 /*
 1373  * union_readdir works in concert with getdirentries and
 1374  * readdir(3) to provide a list of entries in the unioned
 1375  * directories.  getdirentries is responsible for walking
 1376  * down the union stack.  readdir(3) is responsible for
 1377  * eliminating duplicate names from the returned data stream.
 1378  */
 1379 static int
 1380 union_readdir(ap)
 1381         struct vop_readdir_args /* {
 1382                 struct vnode *a_vp;
 1383                 struct uio *a_uio;
 1384                 struct ucred *a_cred;
 1385                 int *a_eofflag;
 1386                 u_long *a_cookies;
 1387                 int a_ncookies;
 1388         } */ *ap;
 1389 {
 1390         struct union_node *un = VTOUNION(ap->a_vp);
 1391         struct vnode *uvp = un->un_uppervp;
 1392         struct proc *p = ap->a_uio->uio_procp;
 1393 
 1394         if (uvp == NULLVP)
 1395                 return (0);
 1396 
 1397         FIXUP(un, p);
 1398         ap->a_vp = uvp;
 1399         return (VCALL(uvp, VOFFSET(vop_readdir), ap));
 1400 }
 1401 
 1402 static int
 1403 union_readlink(ap)
 1404         struct vop_readlink_args /* {
 1405                 struct vnode *a_vp;
 1406                 struct uio *a_uio;
 1407                 struct ucred *a_cred;
 1408         } */ *ap;
 1409 {
 1410         int error;
 1411         struct uio *uio = ap->a_uio;
 1412         struct proc *p = uio->uio_procp;
 1413         struct vnode *vp = OTHERVP(ap->a_vp);
 1414         int dolock = (vp == LOWERVP(ap->a_vp));
 1415 
 1416         if (dolock)
 1417                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
 1418         else
 1419                 FIXUP(VTOUNION(ap->a_vp), p);
 1420         ap->a_vp = vp;
 1421         error = VCALL(vp, VOFFSET(vop_readlink), ap);
 1422         if (dolock)
 1423                 VOP_UNLOCK(vp, 0, p);
 1424 
 1425         return (error);
 1426 }
 1427 
 1428 static int
 1429 union_abortop(ap)
 1430         struct vop_abortop_args /* {
 1431                 struct vnode *a_dvp;
 1432                 struct componentname *a_cnp;
 1433         } */ *ap;
 1434 {
 1435         int error;
 1436         struct componentname *cnp = ap->a_cnp;
 1437         struct proc *p = cnp->cn_proc;
 1438         struct vnode *vp = OTHERVP(ap->a_dvp);
 1439         struct union_node *un = VTOUNION(ap->a_dvp);
 1440         int islocked = un->un_flags & UN_LOCKED;
 1441         int dolock = (vp == LOWERVP(ap->a_dvp));
 1442 
 1443         if (islocked) {
 1444                 if (dolock)
 1445                         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
 1446                 else
 1447                         FIXUP(VTOUNION(ap->a_dvp), p);
 1448         }
 1449         ap->a_dvp = vp;
 1450         error = VCALL(vp, VOFFSET(vop_abortop), ap);
 1451         if (islocked && dolock)
 1452                 VOP_UNLOCK(vp, 0, p);
 1453 
 1454         return (error);
 1455 }
 1456 
 1457 static int
 1458 union_inactive(ap)
 1459         struct vop_inactive_args /* {
 1460                 struct vnode *a_vp;
 1461                 struct proc *a_p;
 1462         } */ *ap;
 1463 {
 1464         struct vnode *vp = ap->a_vp;
 1465         struct proc *p = ap->a_p;
 1466         struct union_node *un = VTOUNION(vp);
 1467         struct vnode **vpp;
 1468 
 1469         /*
 1470          * Do nothing (and _don't_ bypass).
 1471          * Wait to vrele lowervp until reclaim,
 1472          * so that until then our union_node is in the
 1473          * cache and reusable.
 1474          *
 1475          * NEEDSWORK: Someday, consider inactive'ing
 1476          * the lowervp and then trying to reactivate it
 1477          * with capabilities (v_id)
 1478          * like they do in the name lookup cache code.
 1479          * That's too much work for now.
 1480          */
 1481 
 1482         if (un->un_dircache != 0) {
 1483                 for (vpp = un->un_dircache; *vpp != NULLVP; vpp++)
 1484                         vrele(*vpp);
 1485                 free(un->un_dircache, M_TEMP);
 1486                 un->un_dircache = 0;
 1487         }
 1488 
 1489         VOP_UNLOCK(vp, 0, p);
 1490 
 1491         if ((un->un_flags & UN_CACHED) == 0)
 1492                 vgone(vp);
 1493 
 1494         return (0);
 1495 }
 1496 
 1497 static int
 1498 union_reclaim(ap)
 1499         struct vop_reclaim_args /* {
 1500                 struct vnode *a_vp;
 1501         } */ *ap;
 1502 {
 1503 
 1504         union_freevp(ap->a_vp);
 1505 
 1506         return (0);
 1507 }
 1508 
 1509 static int
 1510 union_lock(ap)
 1511         struct vop_lock_args *ap;
 1512 {
 1513         struct vnode *vp = ap->a_vp;
 1514         struct proc *p = ap->a_p;
 1515         int flags = ap->a_flags;
 1516         struct union_node *un;
 1517         int error;
 1518 
 1519         vop_nolock(ap);
 1520         /*
 1521          * Need to do real lockmgr-style locking here.
 1522          * in the mean time, draining won't work quite right,
 1523          * which could lead to a few race conditions.
 1524          * the following test was here, but is not quite right, we
 1525          * still need to take the lock:
 1526         if ((flags & LK_TYPE_MASK) == LK_DRAIN)
 1527                 return (0);
 1528          */
 1529         flags &= ~LK_INTERLOCK;
 1530 
 1531 start:
 1532         un = VTOUNION(vp);
 1533 
 1534         if (un->un_uppervp != NULLVP) {
 1535                 if (((un->un_flags & UN_ULOCK) == 0) &&
 1536                     (vp->v_usecount != 0)) {
 1537                         error = vn_lock(un->un_uppervp, flags, p);
 1538                         if (error)
 1539                                 return (error);
 1540                         un->un_flags |= UN_ULOCK;
 1541                 }
 1542 #ifdef DIAGNOSTIC
 1543                 if (un->un_flags & UN_KLOCK) {
 1544                         vprint("dangling upper lock", vp);
 1545                         panic("union: dangling upper lock");
 1546                 }
 1547 #endif
 1548         }
 1549 
 1550         if (un->un_flags & UN_LOCKED) {
 1551 #ifdef DIAGNOSTIC
 1552                 if (curproc && un->un_pid == curproc->p_pid &&
 1553                             un->un_pid > -1 && curproc->p_pid > -1)
 1554                         panic("union: locking against myself");
 1555 #endif
 1556                 un->un_flags |= UN_WANT;
 1557                 tsleep((caddr_t)&un->un_flags, PINOD, "unionlk2", 0);
 1558                 goto start;
 1559         }
 1560 
 1561 #ifdef DIAGNOSTIC
 1562         if (curproc)
 1563                 un->un_pid = curproc->p_pid;
 1564         else
 1565                 un->un_pid = -1;
 1566 #endif
 1567 
 1568         un->un_flags |= UN_LOCKED;
 1569         return (0);
 1570 }
 1571 
 1572 /*
 1573  * When operations want to vput() a union node yet retain a lock on
 1574  * the upper vnode (say, to do some further operations like link(),
 1575  * mkdir(), ...), they set UN_KLOCK on the union node, then call
 1576  * vput() which calls VOP_UNLOCK() and comes here.  union_unlock()
 1577  * unlocks the union node (leaving the upper vnode alone), clears the
 1578  * KLOCK flag, and then returns to vput().  The caller then does whatever
 1579  * is left to do with the upper vnode, and ensures that it gets unlocked.
 1580  *
 1581  * If UN_KLOCK isn't set, then the upper vnode is unlocked here.
 1582  */
 1583 static int
 1584 union_unlock(ap)
 1585         struct vop_unlock_args /* {
 1586                 struct vnode *a_vp;
 1587                 int a_flags;
 1588                 struct proc *a_p;
 1589         } */ *ap;
 1590 {
 1591         struct union_node *un = VTOUNION(ap->a_vp);
 1592         struct proc *p = ap->a_p;
 1593 
 1594 #ifdef DIAGNOSTIC
 1595         if ((un->un_flags & UN_LOCKED) == 0)
 1596                 panic("union: unlock unlocked node");
 1597         if (curproc && un->un_pid != curproc->p_pid &&
 1598                         curproc->p_pid > -1 && un->un_pid > -1)
 1599                 panic("union: unlocking other process's union node");
 1600 #endif
 1601 
 1602         un->un_flags &= ~UN_LOCKED;
 1603 
 1604         if ((un->un_flags & (UN_ULOCK|UN_KLOCK)) == UN_ULOCK)
 1605                 VOP_UNLOCK(un->un_uppervp, 0, p);
 1606 
 1607         un->un_flags &= ~(UN_ULOCK|UN_KLOCK);
 1608 
 1609         if (un->un_flags & UN_WANT) {
 1610                 un->un_flags &= ~UN_WANT;
 1611                 wakeup((caddr_t) &un->un_flags);
 1612         }
 1613 
 1614 #ifdef DIAGNOSTIC
 1615         un->un_pid = 0;
 1616 #endif
 1617         vop_nounlock(ap);
 1618 
 1619         return (0);
 1620 }
 1621 
 1622 static int
 1623 union_bmap(ap)
 1624         struct vop_bmap_args /* {
 1625                 struct vnode *a_vp;
 1626                 daddr_t  a_bn;
 1627                 struct vnode **a_vpp;
 1628                 daddr_t *a_bnp;
 1629                 int *a_runp;
 1630                 int *a_runb;
 1631         } */ *ap;
 1632 {
 1633         int error;
 1634         struct proc *p = curproc;               /* XXX */
 1635         struct vnode *vp = OTHERVP(ap->a_vp);
 1636         int dolock = (vp == LOWERVP(ap->a_vp));
 1637 
 1638         if (dolock)
 1639                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
 1640         else
 1641                 FIXUP(VTOUNION(ap->a_vp), p);
 1642         ap->a_vp = vp;
 1643         error = VCALL(vp, VOFFSET(vop_bmap), ap);
 1644         if (dolock)
 1645                 VOP_UNLOCK(vp, 0, p);
 1646 
 1647         return (error);
 1648 }
 1649 
 1650 static int
 1651 union_print(ap)
 1652         struct vop_print_args /* {
 1653                 struct vnode *a_vp;
 1654         } */ *ap;
 1655 {
 1656         struct vnode *vp = ap->a_vp;
 1657 
 1658         printf("\ttag VT_UNION, vp=%p, uppervp=%p, lowervp=%p\n",
 1659                         vp, UPPERVP(vp), LOWERVP(vp));
 1660         if (UPPERVP(vp) != NULLVP)
 1661                 vprint("union: upper", UPPERVP(vp));
 1662         if (LOWERVP(vp) != NULLVP)
 1663                 vprint("union: lower", LOWERVP(vp));
 1664 
 1665         return (0);
 1666 }
 1667 
 1668 static int
 1669 union_islocked(ap)
 1670         struct vop_islocked_args /* {
 1671                 struct vnode *a_vp;
 1672         } */ *ap;
 1673 {
 1674 
 1675         return ((VTOUNION(ap->a_vp)->un_flags & UN_LOCKED) ? 1 : 0);
 1676 }
 1677 
 1678 static int
 1679 union_pathconf(ap)
 1680         struct vop_pathconf_args /* {
 1681                 struct vnode *a_vp;
 1682                 int a_name;
 1683                 int *a_retval;
 1684         } */ *ap;
 1685 {
 1686         int error;
 1687         struct proc *p = curproc;               /* XXX */
 1688         struct vnode *vp = OTHERVP(ap->a_vp);
 1689         int dolock = (vp == LOWERVP(ap->a_vp));
 1690 
 1691         if (dolock)
 1692                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
 1693         else
 1694                 FIXUP(VTOUNION(ap->a_vp), p);
 1695         ap->a_vp = vp;
 1696         error = VCALL(vp, VOFFSET(vop_pathconf), ap);
 1697         if (dolock)
 1698                 VOP_UNLOCK(vp, 0, p);
 1699 
 1700         return (error);
 1701 }
 1702 
 1703 static int
 1704 union_advlock(ap)
 1705         struct vop_advlock_args /* {
 1706                 struct vnode *a_vp;
 1707                 caddr_t  a_id;
 1708                 int  a_op;
 1709                 struct flock *a_fl;
 1710                 int  a_flags;
 1711         } */ *ap;
 1712 {
 1713         register struct vnode *ovp = OTHERVP(ap->a_vp);
 1714 
 1715         ap->a_vp = ovp;
 1716         return (VCALL(ovp, VOFFSET(vop_advlock), ap));
 1717 }
 1718 
 1719 
 1720 /*
 1721  * XXX - vop_strategy must be hand coded because it has no
 1722  * vnode in its arguments.
 1723  * This goes away with a merged VM/buffer cache.
 1724  */
 1725 static int
 1726 union_strategy(ap)
 1727         struct vop_strategy_args /* {
 1728                 struct vnode *a_vp;
 1729                 struct buf *a_bp;
 1730         } */ *ap;
 1731 {
 1732         struct buf *bp = ap->a_bp;
 1733         int error;
 1734         struct vnode *savedvp;
 1735 
 1736         savedvp = bp->b_vp;
 1737         bp->b_vp = OTHERVP(bp->b_vp);
 1738 
 1739 #ifdef DIAGNOSTIC
 1740         if (bp->b_vp == NULLVP)
 1741                 panic("union_strategy: nil vp");
 1742         if (((bp->b_flags & B_READ) == 0) &&
 1743             (bp->b_vp == LOWERVP(savedvp)))
 1744                 panic("union_strategy: writing to lowervp");
 1745 #endif
 1746 
 1747         error = VOP_STRATEGY(bp->b_vp, bp);
 1748         bp->b_vp = savedvp;
 1749 
 1750         return (error);
 1751 }
 1752 
 1753 /*
 1754  * Global vfs data structures
 1755  */
 1756 vop_t **union_vnodeop_p;
 1757 static struct vnodeopv_entry_desc union_vnodeop_entries[] = {
 1758         { &vop_default_desc,            (vop_t *) vop_defaultop },
 1759         { &vop_abortop_desc,            (vop_t *) union_abortop },
 1760         { &vop_access_desc,             (vop_t *) union_access },
 1761         { &vop_advlock_desc,            (vop_t *) union_advlock },
 1762         { &vop_bmap_desc,               (vop_t *) union_bmap },
 1763         { &vop_close_desc,              (vop_t *) union_close },
 1764         { &vop_create_desc,             (vop_t *) union_create },
 1765         { &vop_fsync_desc,              (vop_t *) union_fsync },
 1766         { &vop_getattr_desc,            (vop_t *) union_getattr },
 1767         { &vop_inactive_desc,           (vop_t *) union_inactive },
 1768         { &vop_ioctl_desc,              (vop_t *) union_ioctl },
 1769         { &vop_islocked_desc,           (vop_t *) union_islocked },
 1770         { &vop_lease_desc,              (vop_t *) union_lease },
 1771         { &vop_link_desc,               (vop_t *) union_link },
 1772         { &vop_lock_desc,               (vop_t *) union_lock },
 1773         { &vop_lookup_desc,             (vop_t *) union_lookup },
 1774         { &vop_mkdir_desc,              (vop_t *) union_mkdir },
 1775         { &vop_mknod_desc,              (vop_t *) union_mknod },
 1776         { &vop_mmap_desc,               (vop_t *) union_mmap },
 1777         { &vop_open_desc,               (vop_t *) union_open },
 1778         { &vop_pathconf_desc,           (vop_t *) union_pathconf },
 1779         { &vop_poll_desc,               (vop_t *) union_poll },
 1780         { &vop_print_desc,              (vop_t *) union_print },
 1781         { &vop_read_desc,               (vop_t *) union_read },
 1782         { &vop_readdir_desc,            (vop_t *) union_readdir },
 1783         { &vop_readlink_desc,           (vop_t *) union_readlink },
 1784         { &vop_reclaim_desc,            (vop_t *) union_reclaim },
 1785         { &vop_remove_desc,             (vop_t *) union_remove },
 1786         { &vop_rename_desc,             (vop_t *) union_rename },
 1787         { &vop_revoke_desc,             (vop_t *) union_revoke },
 1788         { &vop_rmdir_desc,              (vop_t *) union_rmdir },
 1789         { &vop_setattr_desc,            (vop_t *) union_setattr },
 1790         { &vop_strategy_desc,           (vop_t *) union_strategy },
 1791         { &vop_symlink_desc,            (vop_t *) union_symlink },
 1792         { &vop_unlock_desc,             (vop_t *) union_unlock },
 1793         { &vop_whiteout_desc,           (vop_t *) union_whiteout },
 1794         { &vop_write_desc,              (vop_t *) union_write },
 1795         { NULL, NULL }
 1796 };
 1797 static struct vnodeopv_desc union_vnodeop_opv_desc =
 1798         { &union_vnodeop_p, union_vnodeop_entries };
 1799 
 1800 VNODEOP_SET(union_vnodeop_opv_desc);

Cache object: 2096663a57b85b01e931f7649da15b2e


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