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/unionfs/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: releng/5.0/sys/fs/unionfs/union_vnops.c 105212 2002-10-16 08:04:11Z phk $
   39  */
   40 
   41 #include <sys/param.h>
   42 #include <sys/systm.h>
   43 #include <sys/fcntl.h>
   44 #include <sys/stat.h>
   45 #include <sys/kernel.h>
   46 #include <sys/vnode.h>
   47 #include <sys/mount.h>
   48 #include <sys/namei.h>
   49 #include <sys/malloc.h>
   50 #include <sys/bio.h>
   51 #include <sys/buf.h>
   52 #include <sys/lock.h>
   53 #include <sys/sysctl.h>
   54 #include <fs/unionfs/union.h>
   55 
   56 #include <vm/vm.h>
   57 #include <vm/vnode_pager.h>
   58 
   59 #include <vm/vm_page.h>
   60 #include <vm/vm_object.h>
   61 
   62 int uniondebug = 0;
   63 
   64 #if UDEBUG_ENABLED
   65 SYSCTL_INT(_vfs, OID_AUTO, uniondebug, CTLFLAG_RW, &uniondebug, 0, "");
   66 #else
   67 SYSCTL_INT(_vfs, OID_AUTO, uniondebug, CTLFLAG_RD, &uniondebug, 0, "");
   68 #endif
   69 
   70 static int      union_access(struct vop_access_args *ap);
   71 static int      union_advlock(struct vop_advlock_args *ap);
   72 static int      union_close(struct vop_close_args *ap);
   73 static int      union_create(struct vop_create_args *ap);
   74 static int      union_createvobject(struct vop_createvobject_args *ap);
   75 static int      union_destroyvobject(struct vop_destroyvobject_args *ap);
   76 static int      union_fsync(struct vop_fsync_args *ap);
   77 static int      union_getattr(struct vop_getattr_args *ap);
   78 static int      union_getvobject(struct vop_getvobject_args *ap);
   79 static int      union_inactive(struct vop_inactive_args *ap);
   80 static int      union_ioctl(struct vop_ioctl_args *ap);
   81 static int      union_lease(struct vop_lease_args *ap);
   82 static int      union_link(struct vop_link_args *ap);
   83 static int      union_lookup(struct vop_lookup_args *ap);
   84 static int      union_lookup1(struct vnode *udvp, struct vnode **dvp,
   85                                    struct vnode **vpp,
   86                                    struct componentname *cnp);
   87 static int      union_mkdir(struct vop_mkdir_args *ap);
   88 static int      union_mknod(struct vop_mknod_args *ap);
   89 static int      union_open(struct vop_open_args *ap);
   90 static int      union_pathconf(struct vop_pathconf_args *ap);
   91 static int      union_print(struct vop_print_args *ap);
   92 static int      union_read(struct vop_read_args *ap);
   93 static int      union_readdir(struct vop_readdir_args *ap);
   94 static int      union_readlink(struct vop_readlink_args *ap);
   95 static int      union_getwritemount(struct vop_getwritemount_args *ap);
   96 static int      union_reclaim(struct vop_reclaim_args *ap);
   97 static int      union_remove(struct vop_remove_args *ap);
   98 static int      union_rename(struct vop_rename_args *ap);
   99 static int      union_revoke(struct vop_revoke_args *ap);
  100 static int      union_rmdir(struct vop_rmdir_args *ap);
  101 static int      union_poll(struct vop_poll_args *ap);
  102 static int      union_setattr(struct vop_setattr_args *ap);
  103 static int      union_strategy(struct vop_strategy_args *ap);
  104 static int      union_symlink(struct vop_symlink_args *ap);
  105 static int      union_whiteout(struct vop_whiteout_args *ap);
  106 static int      union_write(struct vop_read_args *ap);
  107 
  108 static __inline
  109 struct vnode *
  110 union_lock_upper(struct union_node *un, struct thread *td)
  111 {
  112         struct vnode *uppervp;
  113 
  114         if ((uppervp = un->un_uppervp) != NULL) {
  115                 VREF(uppervp);
  116                 vn_lock(uppervp, LK_EXCLUSIVE | LK_CANRECURSE | LK_RETRY, td);
  117         }
  118         KASSERT((uppervp == NULL || vrefcnt(uppervp) > 0), ("uppervp usecount is 0"));
  119         return(uppervp);
  120 }
  121 
  122 static __inline
  123 void
  124 union_unlock_upper(struct vnode *uppervp, struct thread *td)
  125 {
  126         vput(uppervp);
  127 }
  128 
  129 static __inline
  130 struct vnode *
  131 union_lock_other(struct union_node *un, struct thread *td)
  132 {
  133         struct vnode *vp;
  134 
  135         if (un->un_uppervp != NULL) {
  136                 vp = union_lock_upper(un, td);
  137         } else if ((vp = un->un_lowervp) != NULL) {
  138                 VREF(vp);
  139                 vn_lock(vp, LK_EXCLUSIVE | LK_CANRECURSE | LK_RETRY, td);
  140         }
  141         return(vp);
  142 }
  143 
  144 static __inline
  145 void
  146 union_unlock_other(struct vnode *vp, struct thread *td)
  147 {
  148         vput(vp);
  149 }
  150 
  151 /*
  152  *      union_lookup:
  153  *
  154  *      udvp    must be exclusively locked on call and will remain 
  155  *              exclusively locked on return.  This is the mount point 
  156  *              for our filesystem.
  157  *
  158  *      dvp     Our base directory, locked and referenced.
  159  *              The passed dvp will be dereferenced and unlocked on return
  160  *              and a new dvp will be returned which is locked and 
  161  *              referenced in the same variable.
  162  *
  163  *      vpp     is filled in with the result if no error occured,
  164  *              locked and ref'd.
  165  *
  166  *              If an error is returned, *vpp is set to NULLVP.  If no
  167  *              error occurs, *vpp is returned with a reference and an
  168  *              exclusive lock.
  169  */
  170 
  171 static int
  172 union_lookup1(udvp, pdvp, vpp, cnp)
  173         struct vnode *udvp;
  174         struct vnode **pdvp;
  175         struct vnode **vpp;
  176         struct componentname *cnp;
  177 {
  178         int error;
  179         struct thread *td = cnp->cn_thread;
  180         struct vnode *dvp = *pdvp;
  181         struct vnode *tdvp;
  182         struct mount *mp;
  183 
  184         /*
  185          * If stepping up the directory tree, check for going
  186          * back across the mount point, in which case do what
  187          * lookup would do by stepping back down the mount
  188          * hierarchy.
  189          */
  190         if (cnp->cn_flags & ISDOTDOT) {
  191                 while ((dvp != udvp) && (dvp->v_vflag & VV_ROOT)) {
  192                         /*
  193                          * Don't do the NOCROSSMOUNT check
  194                          * at this level.  By definition,
  195                          * union fs deals with namespaces, not
  196                          * filesystems.
  197                          */
  198                         tdvp = dvp;
  199                         dvp = dvp->v_mount->mnt_vnodecovered;
  200                         VREF(dvp);
  201                         vput(tdvp);
  202                         vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td);
  203                 }
  204         }
  205 
  206         /*
  207          * Set return dvp to be the upperdvp 'parent directory.
  208          */
  209         *pdvp = dvp;
  210 
  211         /*
  212          * If the VOP_LOOKUP() call generates an error, tdvp is invalid and
  213          * no changes will have been made to dvp, so we are set to return.
  214          */
  215 
  216         error = VOP_LOOKUP(dvp, &tdvp, cnp);
  217         if (error) {
  218                 UDEBUG(("dvp %p error %d flags %lx\n", dvp, error, cnp->cn_flags));
  219                 *vpp = NULL;
  220                 return (error);
  221         }
  222 
  223         /*
  224          * The parent directory will have been unlocked, unless lookup
  225          * found the last component or if dvp == tdvp (tdvp must be locked).
  226          *
  227          * We want our dvp to remain locked and ref'd.  We also want tdvp
  228          * to remain locked and ref'd.
  229          */
  230         UDEBUG(("parentdir %p result %p flag %lx\n", dvp, tdvp, cnp->cn_flags));
  231 
  232         if (dvp != tdvp && (cnp->cn_flags & ISLASTCN) == 0)
  233                 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td);
  234 
  235         /*
  236          * Lastly check if the current node is a mount point in
  237          * which case walk up the mount hierarchy making sure not to
  238          * bump into the root of the mount tree (ie. dvp != udvp).
  239          *
  240          * We use dvp as a temporary variable here, it is no longer related
  241          * to the dvp above.  However, we have to ensure that both *pdvp and
  242          * tdvp are locked on return.
  243          */
  244 
  245         dvp = tdvp;
  246         while (
  247             dvp != udvp && 
  248             (dvp->v_type == VDIR) &&
  249             (mp = dvp->v_mountedhere)
  250         ) {
  251                 int relock_pdvp = 0;
  252 
  253                 if (vfs_busy(mp, 0, 0, td))
  254                         continue;
  255 
  256                 if (dvp == *pdvp)
  257                         relock_pdvp = 1;
  258                 vput(dvp);
  259                 dvp = NULL;
  260                 error = VFS_ROOT(mp, &dvp);
  261 
  262                 vfs_unbusy(mp, td);
  263 
  264                 if (relock_pdvp)
  265                         vn_lock(*pdvp, LK_EXCLUSIVE | LK_RETRY, td);
  266 
  267                 if (error) {
  268                         *vpp = NULL;
  269                         return (error);
  270                 }
  271         }
  272         *vpp = dvp;
  273         return (0);
  274 }
  275 
  276 static int
  277 union_lookup(ap)
  278         struct vop_lookup_args /* {
  279                 struct vnodeop_desc *a_desc;
  280                 struct vnode *a_dvp;
  281                 struct vnode **a_vpp;
  282                 struct componentname *a_cnp;
  283         } */ *ap;
  284 {
  285         int error;
  286         int uerror, lerror;
  287         struct vnode *uppervp, *lowervp;
  288         struct vnode *upperdvp, *lowerdvp;
  289         struct vnode *dvp = ap->a_dvp;          /* starting dir */
  290         struct union_node *dun = VTOUNION(dvp); /* associated union node */
  291         struct componentname *cnp = ap->a_cnp;
  292         struct thread *td = cnp->cn_thread;
  293         int lockparent = cnp->cn_flags & LOCKPARENT;
  294         struct union_mount *um = MOUNTTOUNIONMOUNT(dvp->v_mount);
  295         struct ucred *saved_cred = NULL;
  296         int iswhiteout;
  297         struct vattr va;
  298 
  299         *ap->a_vpp = NULLVP;
  300 
  301         /*
  302          * Disallow write attempts to the filesystem mounted read-only.
  303          */
  304         if ((cnp->cn_flags & ISLASTCN) && 
  305             (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
  306             (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
  307                 return (EROFS);
  308         }
  309 
  310         /*
  311          * For any lookups we do, always return with the parent locked.
  312          */
  313         cnp->cn_flags |= LOCKPARENT;
  314 
  315         lowerdvp = dun->un_lowervp;
  316         uppervp = NULLVP;
  317         lowervp = NULLVP;
  318         iswhiteout = 0;
  319 
  320         uerror = ENOENT;
  321         lerror = ENOENT;
  322 
  323         /*
  324          * Get a private lock on uppervp and a reference, effectively 
  325          * taking it out of the union_node's control.
  326          *
  327          * We must lock upperdvp while holding our lock on dvp
  328          * to avoid a deadlock.
  329          */
  330         upperdvp = union_lock_upper(dun, td);
  331 
  332         /*
  333          * Do the lookup in the upper level.
  334          * If that level consumes additional pathnames,
  335          * then assume that something special is going
  336          * on and just return that vnode.
  337          */
  338         if (upperdvp != NULLVP) {
  339                 /*
  340                  * We do not have to worry about the DOTDOT case, we've
  341                  * already unlocked dvp.
  342                  */
  343                 UDEBUG(("A %p\n", upperdvp));
  344 
  345                 /*
  346                  * Do the lookup.   We must supply a locked and referenced
  347                  * upperdvp to the function and will get a new locked and
  348                  * referenced upperdvp back, with the old having been 
  349                  * dereferenced.
  350                  *
  351                  * If an error is returned, uppervp will be NULLVP.  If no
  352                  * error occurs, uppervp will be the locked and referenced.
  353                  * Return vnode, or possibly NULL, depending on what is being
  354                  * requested.  It is possible that the returned uppervp
  355                  * will be the same as upperdvp.
  356                  */
  357                 uerror = union_lookup1(um->um_uppervp, &upperdvp, &uppervp, cnp);
  358                 UDEBUG((
  359                     "uerror %d upperdvp %p %d/%d, uppervp %p ref=%d/lck=%d\n",
  360                     uerror,
  361                     upperdvp,
  362                     vrefcnt(upperdvp),
  363                     VOP_ISLOCKED(upperdvp, NULL),
  364                     uppervp,
  365                     (uppervp ? vrefcnt(uppervp) : -99),
  366                     (uppervp ? VOP_ISLOCKED(uppervp, NULL) : -99)
  367                 ));
  368 
  369                 /*
  370                  * Disallow write attempts to the filesystem mounted read-only.
  371                  */
  372                 if (uerror == EJUSTRETURN && (cnp->cn_flags & ISLASTCN) &&
  373                     (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
  374                     (cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME)) {
  375                         error = EROFS;
  376                         goto out;
  377                 }
  378 
  379                 /*
  380                  * Special case: If cn_consume != 0 then skip out.  The result
  381                  * of the lookup is transfered to our return variable.  If
  382                  * an error occured we have to throw away the results.
  383                  */
  384 
  385                 if (cnp->cn_consume != 0) {
  386                         if ((error = uerror) == 0) {
  387                                 *ap->a_vpp = uppervp;
  388                                 uppervp = NULL;
  389                         }
  390                         goto out;
  391                 }
  392 
  393                 /*
  394                  * Calculate whiteout, fall through.
  395                  */
  396 
  397                 if (uerror == ENOENT || uerror == EJUSTRETURN) {
  398                         if (cnp->cn_flags & ISWHITEOUT) {
  399                                 iswhiteout = 1;
  400                         } else if (lowerdvp != NULLVP) {
  401                                 int terror;
  402 
  403                                 terror = VOP_GETATTR(upperdvp, &va,
  404                                         cnp->cn_cred, cnp->cn_thread);
  405                                 if (terror == 0 && (va.va_flags & OPAQUE))
  406                                         iswhiteout = 1;
  407                         }
  408                 }
  409         }
  410 
  411         /*
  412          * In a similar way to the upper layer, do the lookup
  413          * in the lower layer.   This time, if there is some
  414          * component magic going on, then vput whatever we got
  415          * back from the upper layer and return the lower vnode
  416          * instead.
  417          */
  418 
  419         if (lowerdvp != NULLVP && !iswhiteout) {
  420                 int nameiop;
  421 
  422                 UDEBUG(("B %p\n", lowerdvp));
  423 
  424                 /*
  425                  * Force only LOOKUPs on the lower node, since
  426                  * we won't be making changes to it anyway.
  427                  */
  428                 nameiop = cnp->cn_nameiop;
  429                 cnp->cn_nameiop = LOOKUP;
  430                 if (um->um_op == UNMNT_BELOW) {
  431                         saved_cred = cnp->cn_cred;
  432                         cnp->cn_cred = um->um_cred;
  433                 }
  434 
  435                 /*
  436                  * We shouldn't have to worry about locking interactions
  437                  * between the lower layer and our union layer (w.r.t.
  438                  * `..' processing) because we don't futz with lowervp
  439                  * locks in the union-node instantiation code path.
  440                  *
  441                  * union_lookup1() requires lowervp to be locked on entry,
  442                  * and it will be unlocked on return.  The ref count will
  443                  * not change.  On return lowervp doesn't represent anything
  444                  * to us so we NULL it out.
  445                  */
  446                 VREF(lowerdvp);
  447                 vn_lock(lowerdvp, LK_EXCLUSIVE | LK_RETRY, td);
  448                 lerror = union_lookup1(um->um_lowervp, &lowerdvp, &lowervp, cnp);
  449                 if (lowerdvp == lowervp)
  450                         vrele(lowerdvp);
  451                 else
  452                         vput(lowerdvp);
  453                 lowerdvp = NULL;        /* lowerdvp invalid after vput */
  454 
  455                 if (um->um_op == UNMNT_BELOW)
  456                         cnp->cn_cred = saved_cred;
  457                 cnp->cn_nameiop = nameiop;
  458 
  459                 if (cnp->cn_consume != 0 || lerror == EACCES) {
  460                         if ((error = lerror) == 0) {
  461                                 *ap->a_vpp = lowervp;
  462                                 lowervp = NULL;
  463                         }
  464                         goto out;
  465                 }
  466         } else {
  467                 UDEBUG(("C %p\n", lowerdvp));
  468                 if ((cnp->cn_flags & ISDOTDOT) && dun->un_pvp != NULLVP) {
  469                         if ((lowervp = LOWERVP(dun->un_pvp)) != NULL) {
  470                                 VREF(lowervp);
  471                                 vn_lock(lowervp, LK_EXCLUSIVE | LK_RETRY, td);
  472                                 lerror = 0;
  473                         }
  474                 }
  475         }
  476 
  477         /*
  478          * Ok.  Now we have uerror, uppervp, upperdvp, lerror, and lowervp.
  479          *
  480          * 1. If both layers returned an error, select the upper layer.
  481          *
  482          * 2. If the upper layer failed and the bottom layer succeeded,
  483          *    two subcases occur:
  484          *
  485          *      a.  The bottom vnode is not a directory, in which case
  486          *          just return a new union vnode referencing an
  487          *          empty top layer and the existing bottom layer.
  488          *
  489          *      b.  The bottom vnode is a directory, in which case
  490          *          create a new directory in the top layer and
  491          *          and fall through to case 3.
  492          *
  493          * 3. If the top layer succeeded, then return a new union
  494          *    vnode referencing whatever the new top layer and
  495          *    whatever the bottom layer returned.
  496          */
  497 
  498         /* case 1. */
  499         if ((uerror != 0) && (lerror != 0)) {
  500                 error = uerror;
  501                 goto out;
  502         }
  503 
  504         /* case 2. */
  505         if (uerror != 0 /* && (lerror == 0) */ ) {
  506                 if (lowervp->v_type == VDIR) { /* case 2b. */
  507                         KASSERT(uppervp == NULL, ("uppervp unexpectedly non-NULL"));
  508                         /*
  509                          * Oops, uppervp has a problem, we may have to shadow.
  510                          */
  511                         uerror = union_mkshadow(um, upperdvp, cnp, &uppervp);
  512                         if (uerror) {
  513                                 error = uerror;
  514                                 goto out;
  515                         }
  516                 }
  517         }
  518 
  519         /*
  520          * Must call union_allocvp() with both the upper and lower vnodes
  521          * referenced and the upper vnode locked.   ap->a_vpp is returned 
  522          * referenced and locked.  lowervp, uppervp, and upperdvp are 
  523          * absorbed by union_allocvp() whether it succeeds or fails.
  524          *
  525          * upperdvp is the parent directory of uppervp which may be
  526          * different, depending on the path, from dvp->un_uppervp.  That's
  527          * why it is a separate argument.  Note that it must be unlocked.
  528          *
  529          * dvp must be locked on entry to the call and will be locked on
  530          * return.
  531          */
  532 
  533         if (uppervp && uppervp != upperdvp)
  534                 VOP_UNLOCK(uppervp, 0, td);
  535         if (lowervp)
  536                 VOP_UNLOCK(lowervp, 0, td);
  537         if (upperdvp)
  538                 VOP_UNLOCK(upperdvp, 0, td);
  539 
  540         error = union_allocvp(ap->a_vpp, dvp->v_mount, dvp, upperdvp, cnp,
  541                               uppervp, lowervp, 1);
  542 
  543         UDEBUG(("Create %p = %p %p refs=%d\n", *ap->a_vpp, uppervp, lowervp, (*ap->a_vpp) ? vrefcnt(*ap->a_vpp) : -99));
  544 
  545         uppervp = NULL;
  546         upperdvp = NULL;
  547         lowervp = NULL;
  548 
  549         /* 
  550          *      Termination Code
  551          *
  552          *      - put away any extra junk laying around.  Note that lowervp
  553          *        (if not NULL) will never be the same as *ap->a_vp and 
  554          *        neither will uppervp, because when we set that state we 
  555          *        NULL-out lowervp or uppervp.  On the otherhand, upperdvp
  556          *        may match uppervp or *ap->a_vpp.
  557          *
  558          *      - relock/unlock dvp if appropriate.
  559          */
  560 
  561 out:
  562         if (upperdvp) {
  563                 if (upperdvp == uppervp || upperdvp == *ap->a_vpp)
  564                         vrele(upperdvp);
  565                 else
  566                         vput(upperdvp);
  567         }
  568 
  569         if (uppervp)
  570                 vput(uppervp);
  571 
  572         if (lowervp)
  573                 vput(lowervp);
  574 
  575         /*
  576          * Restore LOCKPARENT state
  577          */
  578 
  579         if (!lockparent)
  580                 cnp->cn_flags &= ~LOCKPARENT;
  581 
  582         UDEBUG(("Out %d vpp %p/%d lower %p upper %p\n", error, *ap->a_vpp,
  583                 ((*ap->a_vpp) ? vrefcnt(*ap->a_vpp) : -99),
  584                 lowervp, uppervp));
  585 
  586         /*
  587          * dvp lock state, determine whether to relock dvp.  dvp is expected
  588          * to be locked on return if:
  589          *
  590          *      - there was an error (except not EJUSTRETURN), or
  591          *      - we hit the last component and lockparent is true
  592          *
  593          * dvp_is_locked is the current state of the dvp lock, not counting
  594          * the possibility that *ap->a_vpp == dvp (in which case it is locked
  595          * anyway).  Note that *ap->a_vpp == dvp only if no error occured.
  596          */
  597 
  598         if (*ap->a_vpp != dvp) {
  599                 if ((error == 0 || error == EJUSTRETURN) &&
  600                     (!lockparent || (cnp->cn_flags & ISLASTCN) == 0)) {
  601                         VOP_UNLOCK(dvp, 0, td);
  602                 }
  603         }
  604 
  605         /*
  606          * Diagnostics
  607          */
  608 
  609 #ifdef DIAGNOSTIC
  610         if (cnp->cn_namelen == 1 &&
  611             cnp->cn_nameptr[0] == '.' &&
  612             *ap->a_vpp != dvp) {
  613                 panic("union_lookup returning . (%p) not same as startdir (%p)", ap->a_vpp, dvp);
  614         }
  615 #endif
  616 
  617         return (error);
  618 }
  619 
  620 /*
  621  *      union_create:
  622  *
  623  * a_dvp is locked on entry and remains locked on return.  a_vpp is returned
  624  * locked if no error occurs, otherwise it is garbage.
  625  */
  626 
  627 static int
  628 union_create(ap)
  629         struct vop_create_args /* {
  630                 struct vnode *a_dvp;
  631                 struct vnode **a_vpp;
  632                 struct componentname *a_cnp;
  633                 struct vattr *a_vap;
  634         } */ *ap;
  635 {
  636         struct union_node *dun = VTOUNION(ap->a_dvp);
  637         struct componentname *cnp = ap->a_cnp;
  638         struct thread *td = cnp->cn_thread;
  639         struct vnode *dvp;
  640         int error = EROFS;
  641 
  642         if ((dvp = union_lock_upper(dun, td)) != NULL) {
  643                 struct vnode *vp;
  644                 struct mount *mp;
  645 
  646                 error = VOP_CREATE(dvp, &vp, cnp, ap->a_vap);
  647                 if (error == 0) {
  648                         mp = ap->a_dvp->v_mount;
  649                         VOP_UNLOCK(vp, 0, td);
  650                         UDEBUG(("ALLOCVP-1 FROM %p REFS %d\n", vp, vrefcnt(vp)));
  651                         error = union_allocvp(ap->a_vpp, mp, NULLVP, NULLVP,
  652                                 cnp, vp, NULLVP, 1);
  653                         UDEBUG(("ALLOCVP-2B FROM %p REFS %d\n", *ap->a_vpp, vrefcnt(vp)));
  654                 }
  655                 union_unlock_upper(dvp, td);
  656         }
  657         return (error);
  658 }
  659 
  660 static int
  661 union_whiteout(ap)
  662         struct vop_whiteout_args /* {
  663                 struct vnode *a_dvp;
  664                 struct componentname *a_cnp;
  665                 int a_flags;
  666         } */ *ap;
  667 {
  668         struct union_node *un = VTOUNION(ap->a_dvp);
  669         struct componentname *cnp = ap->a_cnp;
  670         struct vnode *uppervp;
  671         int error = EOPNOTSUPP;
  672 
  673         if ((uppervp = union_lock_upper(un, cnp->cn_thread)) != NULLVP) {
  674                 error = VOP_WHITEOUT(un->un_uppervp, cnp, ap->a_flags);
  675                 union_unlock_upper(uppervp, cnp->cn_thread);
  676         }
  677         return(error);
  678 }
  679 
  680 /*
  681  *      union_mknod:
  682  *
  683  *      a_dvp is locked on entry and should remain locked on return.
  684  *      a_vpp is garbagre whether an error occurs or not.
  685  */
  686 
  687 static int
  688 union_mknod(ap)
  689         struct vop_mknod_args /* {
  690                 struct vnode *a_dvp;
  691                 struct vnode **a_vpp;
  692                 struct componentname *a_cnp;
  693                 struct vattr *a_vap;
  694         } */ *ap;
  695 {
  696         struct union_node *dun = VTOUNION(ap->a_dvp);
  697         struct componentname *cnp = ap->a_cnp;
  698         struct vnode *dvp;
  699         int error = EROFS;
  700 
  701         if ((dvp = union_lock_upper(dun, cnp->cn_thread)) != NULL) {
  702                 error = VOP_MKNOD(dvp, ap->a_vpp, cnp, ap->a_vap);
  703                 union_unlock_upper(dvp, cnp->cn_thread);
  704         }
  705         return (error);
  706 }
  707 
  708 /*
  709  *      union_open:
  710  *
  711  *      run open VOP.  When opening the underlying vnode we have to mimic
  712  *      vn_open().  What we *really* need to do to avoid screwups if the
  713  *      open semantics change is to call vn_open().  For example, ufs blows
  714  *      up if you open a file but do not vmio it prior to writing.
  715  */
  716 
  717 static int
  718 union_open(ap)
  719         struct vop_open_args /* {
  720                 struct vnodeop_desc *a_desc;
  721                 struct vnode *a_vp;
  722                 int a_mode;
  723                 struct ucred *a_cred;
  724                 struct thread *a_td;
  725         } */ *ap;
  726 {
  727         struct union_node *un = VTOUNION(ap->a_vp);
  728         struct vnode *tvp;
  729         int mode = ap->a_mode;
  730         struct ucred *cred = ap->a_cred;
  731         struct thread *td = ap->a_td;
  732         int error = 0;
  733         int tvpisupper = 1;
  734 
  735         /*
  736          * If there is an existing upper vp then simply open that.
  737          * The upper vp takes precedence over the lower vp.  When opening
  738          * a lower vp for writing copy it to the uppervp and then open the
  739          * uppervp.
  740          *
  741          * At the end of this section tvp will be left locked.
  742          */
  743         if ((tvp = union_lock_upper(un, td)) == NULLVP) {
  744                 /*
  745                  * If the lower vnode is being opened for writing, then
  746                  * copy the file contents to the upper vnode and open that,
  747                  * otherwise can simply open the lower vnode.
  748                  */
  749                 tvp = un->un_lowervp;
  750                 if ((ap->a_mode & FWRITE) && (tvp->v_type == VREG)) {
  751                         int docopy = !(mode & O_TRUNC);
  752                         error = union_copyup(un, docopy, cred, td);
  753                         tvp = union_lock_upper(un, td);
  754                 } else {
  755                         un->un_openl++;
  756                         VREF(tvp);
  757                         vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY, td);
  758                         tvpisupper = 0;
  759                 }
  760         }
  761 
  762         /*
  763          * We are holding the correct vnode, open it.
  764          */
  765 
  766         if (error == 0)
  767                 error = VOP_OPEN(tvp, mode, cred, td);
  768 
  769         /*
  770          * This is absolutely necessary or UFS will blow up.
  771          */
  772         if (error == 0 && vn_canvmio(tvp) == TRUE) {
  773                 error = vfs_object_create(tvp, td, cred);
  774         }
  775 
  776         /*
  777          * Release any locks held.
  778          */
  779         if (tvpisupper) {
  780                 if (tvp)
  781                         union_unlock_upper(tvp, td);
  782         } else {
  783                 vput(tvp);
  784         }
  785         return (error);
  786 }
  787 
  788 /*
  789  *      union_close:
  790  *
  791  *      It is unclear whether a_vp is passed locked or unlocked.  Whatever
  792  *      the case we do not change it.
  793  */
  794 
  795 static int
  796 union_close(ap)
  797         struct vop_close_args /* {
  798                 struct vnode *a_vp;
  799                 int  a_fflag;
  800                 struct ucred *a_cred;
  801                 struct thread *a_td;
  802         } */ *ap;
  803 {
  804         struct union_node *un = VTOUNION(ap->a_vp);
  805         struct vnode *vp;
  806 
  807         if ((vp = un->un_uppervp) == NULLVP) {
  808 #ifdef UNION_DIAGNOSTIC
  809                 if (un->un_openl <= 0)
  810                         panic("union: un_openl cnt");
  811 #endif
  812                 --un->un_openl;
  813                 vp = un->un_lowervp;
  814         }
  815         ap->a_vp = vp;
  816         return (VCALL(vp, VOFFSET(vop_close), ap));
  817 }
  818 
  819 /*
  820  * Check access permission on the union vnode.
  821  * The access check being enforced is to check
  822  * against both the underlying vnode, and any
  823  * copied vnode.  This ensures that no additional
  824  * file permissions are given away simply because
  825  * the user caused an implicit file copy.
  826  */
  827 static int
  828 union_access(ap)
  829         struct vop_access_args /* {
  830                 struct vnodeop_desc *a_desc;
  831                 struct vnode *a_vp;
  832                 int a_mode;
  833                 struct ucred *a_cred;
  834                 struct thread *a_td;
  835         } */ *ap;
  836 {
  837         struct union_node *un = VTOUNION(ap->a_vp);
  838         struct thread *td = ap->a_td;
  839         int error = EACCES;
  840         struct vnode *vp;
  841 
  842         /*
  843          * Disallow write attempts on filesystems mounted read-only.
  844          */
  845         if ((ap->a_mode & VWRITE) && 
  846             (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)) {
  847                 switch (ap->a_vp->v_type) {
  848                 case VREG: 
  849                 case VDIR:
  850                 case VLNK:
  851                         return (EROFS);
  852                 default:
  853                         break;
  854                 }
  855         }
  856 
  857         if ((vp = union_lock_upper(un, td)) != NULLVP) {
  858                 ap->a_vp = vp;
  859                 error = VCALL(vp, VOFFSET(vop_access), ap);
  860                 union_unlock_upper(vp, td);
  861                 return(error);
  862         }
  863 
  864         if ((vp = un->un_lowervp) != NULLVP) {
  865                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
  866                 ap->a_vp = vp;
  867 
  868                 /*
  869                  * Remove VWRITE from a_mode if our mount point is RW, because
  870                  * we want to allow writes and lowervp may be read-only.
  871                  */
  872                 if ((un->un_vnode->v_mount->mnt_flag & MNT_RDONLY) == 0)
  873                         ap->a_mode &= ~VWRITE;
  874 
  875                 error = VCALL(vp, VOFFSET(vop_access), ap);
  876                 if (error == 0) {
  877                         struct union_mount *um;
  878 
  879                         um = MOUNTTOUNIONMOUNT(un->un_vnode->v_mount);
  880 
  881                         if (um->um_op == UNMNT_BELOW) {
  882                                 ap->a_cred = um->um_cred;
  883                                 error = VCALL(vp, VOFFSET(vop_access), ap);
  884                         }
  885                 }
  886                 VOP_UNLOCK(vp, 0, td);
  887         }
  888         return(error);
  889 }
  890 
  891 /*
  892  * We handle getattr only to change the fsid and
  893  * track object sizes
  894  *
  895  * It's not clear whether VOP_GETATTR is to be
  896  * called with the vnode locked or not.  stat() calls
  897  * it with (vp) locked, and fstat() calls it with
  898  * (vp) unlocked. 
  899  *
  900  * Because of this we cannot use our normal locking functions
  901  * if we do not intend to lock the main a_vp node.  At the moment
  902  * we are running without any specific locking at all, but beware
  903  * to any programmer that care must be taken if locking is added
  904  * to this function.
  905  */
  906 
  907 static int
  908 union_getattr(ap)
  909         struct vop_getattr_args /* {
  910                 struct vnode *a_vp;
  911                 struct vattr *a_vap;
  912                 struct ucred *a_cred;
  913                 struct thread *a_td;
  914         } */ *ap;
  915 {
  916         int error;
  917         struct union_node *un = VTOUNION(ap->a_vp);
  918         struct vnode *vp;
  919         struct vattr *vap;
  920         struct vattr va;
  921 
  922         /*
  923          * Some programs walk the filesystem hierarchy by counting
  924          * links to directories to avoid stat'ing all the time.
  925          * This means the link count on directories needs to be "correct".
  926          * The only way to do that is to call getattr on both layers
  927          * and fix up the link count.  The link count will not necessarily
  928          * be accurate but will be large enough to defeat the tree walkers.
  929          */
  930 
  931         vap = ap->a_vap;
  932 
  933         if ((vp = un->un_uppervp) != NULLVP) {
  934                 error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_td);
  935                 if (error)
  936                         return (error);
  937                 /* XXX isn't this dangerous without a lock? */
  938                 union_newsize(ap->a_vp, vap->va_size, VNOVAL);
  939         }
  940 
  941         if (vp == NULLVP) {
  942                 vp = un->un_lowervp;
  943         } else if (vp->v_type == VDIR && un->un_lowervp != NULLVP) {
  944                 vp = un->un_lowervp;
  945                 vap = &va;
  946         } else {
  947                 vp = NULLVP;
  948         }
  949 
  950         if (vp != NULLVP) {
  951                 error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_td);
  952                 if (error)
  953                         return (error);
  954                 /* XXX isn't this dangerous without a lock? */
  955                 union_newsize(ap->a_vp, VNOVAL, vap->va_size);
  956         }
  957 
  958         if ((vap != ap->a_vap) && (vap->va_type == VDIR))
  959                 ap->a_vap->va_nlink += vap->va_nlink;
  960         return (0);
  961 }
  962 
  963 static int
  964 union_setattr(ap)
  965         struct vop_setattr_args /* {
  966                 struct vnode *a_vp;
  967                 struct vattr *a_vap;
  968                 struct ucred *a_cred;
  969                 struct thread *a_td;
  970         } */ *ap;
  971 {
  972         struct union_node *un = VTOUNION(ap->a_vp);
  973         struct thread *td = ap->a_td;
  974         struct vattr *vap = ap->a_vap;
  975         struct vnode *uppervp;
  976         int error;
  977 
  978         /*
  979          * Disallow write attempts on filesystems mounted read-only.
  980          */
  981         if ((ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) &&
  982             (vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
  983              vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
  984              vap->va_mtime.tv_sec != VNOVAL || 
  985              vap->va_mode != (mode_t)VNOVAL)) {
  986                 return (EROFS);
  987         }
  988 
  989         /*
  990          * Handle case of truncating lower object to zero size
  991          * by creating a zero length upper object.  This is to
  992          * handle the case of open with O_TRUNC and O_CREAT.
  993          */
  994         if (un->un_uppervp == NULLVP && (un->un_lowervp->v_type == VREG)) {
  995                 error = union_copyup(un, (ap->a_vap->va_size != 0),
  996                             ap->a_cred, ap->a_td);
  997                 if (error)
  998                         return (error);
  999         }
 1000 
 1001         /*
 1002          * Try to set attributes in upper layer,
 1003          * otherwise return read-only filesystem error.
 1004          */
 1005         error = EROFS;
 1006         if ((uppervp = union_lock_upper(un, td)) != NULLVP) {
 1007                 error = VOP_SETATTR(un->un_uppervp, ap->a_vap,
 1008                                         ap->a_cred, ap->a_td);
 1009                 if ((error == 0) && (ap->a_vap->va_size != VNOVAL))
 1010                         union_newsize(ap->a_vp, ap->a_vap->va_size, VNOVAL);
 1011                 union_unlock_upper(uppervp, td);
 1012         }
 1013         return (error);
 1014 }
 1015 
 1016 static int
 1017 union_read(ap)
 1018         struct vop_read_args /* {
 1019                 struct vnode *a_vp;
 1020                 struct uio *a_uio;
 1021                 int  a_ioflag;
 1022                 struct ucred *a_cred;
 1023         } */ *ap;
 1024 {
 1025         struct union_node *un = VTOUNION(ap->a_vp);
 1026         struct thread *td = ap->a_uio->uio_td;
 1027         struct vnode *uvp;
 1028         int error;
 1029 
 1030         uvp = union_lock_other(un, td);
 1031         KASSERT(uvp != NULL, ("union_read: backing vnode missing!"));
 1032 
 1033         error = VOP_READ(uvp, ap->a_uio, ap->a_ioflag, ap->a_cred);
 1034         union_unlock_other(uvp, td);
 1035 
 1036         /*
 1037          * XXX
 1038          * Perhaps the size of the underlying object has changed under
 1039          * our feet.  Take advantage of the offset information present
 1040          * in the uio structure.
 1041          */
 1042         if (error == 0) {
 1043                 struct union_node *un = VTOUNION(ap->a_vp);
 1044                 off_t cur = ap->a_uio->uio_offset;
 1045 
 1046                 if (uvp == un->un_uppervp) {
 1047                         if (cur > un->un_uppersz)
 1048                                 union_newsize(ap->a_vp, cur, VNOVAL);
 1049                 } else {
 1050                         if (cur > un->un_lowersz)
 1051                                 union_newsize(ap->a_vp, VNOVAL, cur);
 1052                 }
 1053         }
 1054         return (error);
 1055 }
 1056 
 1057 static int
 1058 union_write(ap)
 1059         struct vop_read_args /* {
 1060                 struct vnode *a_vp;
 1061                 struct uio *a_uio;
 1062                 int  a_ioflag;
 1063                 struct ucred *a_cred;
 1064         } */ *ap;
 1065 {
 1066         struct union_node *un = VTOUNION(ap->a_vp);
 1067         struct thread *td = ap->a_uio->uio_td;
 1068         struct vnode *uppervp;
 1069         int error;
 1070 
 1071         if ((uppervp = union_lock_upper(un, td)) == NULLVP)
 1072                 panic("union: missing upper layer in write");
 1073 
 1074         error = VOP_WRITE(uppervp, ap->a_uio, ap->a_ioflag, ap->a_cred);
 1075 
 1076         /*
 1077          * The size of the underlying object may be changed by the
 1078          * write.
 1079          */
 1080         if (error == 0) {
 1081                 off_t cur = ap->a_uio->uio_offset;
 1082 
 1083                 if (cur > un->un_uppersz)
 1084                         union_newsize(ap->a_vp, cur, VNOVAL);
 1085         }
 1086         union_unlock_upper(uppervp, td);
 1087         return (error);
 1088 }
 1089 
 1090 static int
 1091 union_lease(ap)
 1092         struct vop_lease_args /* {
 1093                 struct vnode *a_vp;
 1094                 struct thread *a_td;
 1095                 struct ucred *a_cred;
 1096                 int a_flag;
 1097         } */ *ap;
 1098 {
 1099         struct vnode *ovp = OTHERVP(ap->a_vp);
 1100 
 1101         ap->a_vp = ovp;
 1102         return (VCALL(ovp, VOFFSET(vop_lease), ap));
 1103 }
 1104 
 1105 static int
 1106 union_ioctl(ap)
 1107         struct vop_ioctl_args /* {
 1108                 struct vnode *a_vp;
 1109                 u_long  a_command;
 1110                 caddr_t  a_data;
 1111                 int  a_fflag;
 1112                 struct ucred *a_cred;
 1113                 struct thread *a_td;
 1114         } */ *ap;
 1115 {
 1116         struct vnode *ovp = OTHERVP(ap->a_vp);
 1117 
 1118         ap->a_vp = ovp;
 1119         return (VCALL(ovp, VOFFSET(vop_ioctl), ap));
 1120 }
 1121 
 1122 static int
 1123 union_poll(ap)
 1124         struct vop_poll_args /* {
 1125                 struct vnode *a_vp;
 1126                 int  a_events;
 1127                 struct ucred *a_cred;
 1128                 struct thread *a_td;
 1129         } */ *ap;
 1130 {
 1131         struct vnode *ovp = OTHERVP(ap->a_vp);
 1132 
 1133         ap->a_vp = ovp;
 1134         return (VCALL(ovp, VOFFSET(vop_poll), ap));
 1135 }
 1136 
 1137 static int
 1138 union_revoke(ap)
 1139         struct vop_revoke_args /* {
 1140                 struct vnode *a_vp;
 1141                 int a_flags;
 1142                 struct thread *a_td;
 1143         } */ *ap;
 1144 {
 1145         struct vnode *vp = ap->a_vp;
 1146 
 1147         if (UPPERVP(vp))
 1148                 VOP_REVOKE(UPPERVP(vp), ap->a_flags);
 1149         if (LOWERVP(vp))
 1150                 VOP_REVOKE(LOWERVP(vp), ap->a_flags);
 1151         vgone(vp);
 1152         return (0);
 1153 }
 1154 
 1155 static int
 1156 union_fsync(ap)
 1157         struct vop_fsync_args /* {
 1158                 struct vnode *a_vp;
 1159                 struct ucred *a_cred;
 1160                 int  a_waitfor;
 1161                 struct thread *a_td;
 1162         } */ *ap;
 1163 {
 1164         int error = 0;
 1165         struct thread *td = ap->a_td;
 1166         struct vnode *targetvp;
 1167         struct union_node *un = VTOUNION(ap->a_vp);
 1168 
 1169         if ((targetvp = union_lock_other(un, td)) != NULLVP) {
 1170                 error = VOP_FSYNC(targetvp, ap->a_cred, ap->a_waitfor, td);
 1171                 union_unlock_other(targetvp, td);
 1172         }
 1173 
 1174         return (error);
 1175 }
 1176 
 1177 /*
 1178  *      union_remove:
 1179  *
 1180  *      Remove the specified cnp.  The dvp and vp are passed to us locked
 1181  *      and must remain locked on return.
 1182  */
 1183 
 1184 static int
 1185 union_remove(ap)
 1186         struct vop_remove_args /* {
 1187                 struct vnode *a_dvp;
 1188                 struct vnode *a_vp;
 1189                 struct componentname *a_cnp;
 1190         } */ *ap;
 1191 {
 1192         struct union_node *dun = VTOUNION(ap->a_dvp);
 1193         struct union_node *un = VTOUNION(ap->a_vp);
 1194         struct componentname *cnp = ap->a_cnp;
 1195         struct thread *td = cnp->cn_thread;
 1196         struct vnode *uppervp;
 1197         struct vnode *upperdvp;
 1198         int error;
 1199 
 1200         if ((upperdvp = union_lock_upper(dun, td)) == NULLVP)
 1201                 panic("union remove: null upper vnode");
 1202 
 1203         if ((uppervp = union_lock_upper(un, td)) != NULLVP) {
 1204                 if (union_dowhiteout(un, cnp->cn_cred, td))
 1205                         cnp->cn_flags |= DOWHITEOUT;
 1206                 error = VOP_REMOVE(upperdvp, uppervp, cnp);
 1207 #if 0
 1208                 /* XXX */
 1209                 if (!error)
 1210                         union_removed_upper(un);
 1211 #endif
 1212                 union_unlock_upper(uppervp, td);
 1213         } else {
 1214                 error = union_mkwhiteout(
 1215                             MOUNTTOUNIONMOUNT(ap->a_dvp->v_mount),
 1216                             upperdvp, ap->a_cnp, un->un_path);
 1217         }
 1218         union_unlock_upper(upperdvp, td);
 1219         return (error);
 1220 }
 1221 
 1222 /*
 1223  *      union_link:
 1224  *
 1225  *      tdvp and vp will be locked on entry.
 1226  *      tdvp and vp should remain locked on return.
 1227  */
 1228 
 1229 static int
 1230 union_link(ap)
 1231         struct vop_link_args /* {
 1232                 struct vnode *a_tdvp;
 1233                 struct vnode *a_vp;
 1234                 struct componentname *a_cnp;
 1235         } */ *ap;
 1236 {
 1237         struct componentname *cnp = ap->a_cnp;
 1238         struct thread *td = cnp->cn_thread;
 1239         struct union_node *dun = VTOUNION(ap->a_tdvp);
 1240         struct vnode *vp;
 1241         struct vnode *tdvp;
 1242         int error = 0;
 1243 
 1244         if (ap->a_tdvp->v_op != ap->a_vp->v_op) {
 1245                 vp = ap->a_vp;
 1246         } else {
 1247                 struct union_node *tun = VTOUNION(ap->a_vp);
 1248 
 1249                 if (tun->un_uppervp == NULLVP) {
 1250 #if 0
 1251                         if (dun->un_uppervp == tun->un_dirvp) {
 1252                                 if (dun->un_flags & UN_ULOCK) {
 1253                                         dun->un_flags &= ~UN_ULOCK;
 1254                                         VOP_UNLOCK(dun->un_uppervp, 0, td);
 1255                                 }
 1256                         }
 1257 #endif
 1258                         error = union_copyup(tun, 1, cnp->cn_cred, td);
 1259 #if 0
 1260                         if (dun->un_uppervp == tun->un_dirvp) {
 1261                                 vn_lock(dun->un_uppervp,
 1262                                             LK_EXCLUSIVE | LK_RETRY, td);
 1263                                 dun->un_flags |= UN_ULOCK;
 1264                         }
 1265 #endif
 1266                         if (error)
 1267                                 return (error);
 1268                 }
 1269                 vp = tun->un_uppervp;
 1270                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
 1271         }
 1272 
 1273         /*
 1274          * Make sure upper is locked, then unlock the union directory we were 
 1275          * called with to avoid a deadlock while we are calling VOP_LINK() on 
 1276          * the upper (with tdvp locked and vp not locked).  Our ap->a_tdvp
 1277          * is expected to be locked on return.
 1278          */
 1279 
 1280         if ((tdvp = union_lock_upper(dun, td)) == NULLVP)
 1281                 return (EROFS);
 1282 
 1283         VOP_UNLOCK(ap->a_tdvp, 0, td);          /* unlock calling node */
 1284         error = VOP_LINK(tdvp, vp, cnp);        /* call link on upper */
 1285 
 1286         /*
 1287          * Unlock tun->un_uppervp if we locked it above.
 1288          */
 1289         if (ap->a_tdvp->v_op == ap->a_vp->v_op)
 1290                 VOP_UNLOCK(vp, 0, td);
 1291         /*
 1292          * We have to unlock tdvp prior to relocking our calling node in
 1293          * order to avoid a deadlock.  We also have to unlock ap->a_vp
 1294          * before relocking the directory, but then we have to relock
 1295          * ap->a_vp as our caller expects.
 1296          */
 1297         VOP_UNLOCK(ap->a_vp, 0, td);
 1298         union_unlock_upper(tdvp, td);
 1299         vn_lock(ap->a_tdvp, LK_EXCLUSIVE | LK_RETRY, td);
 1300         vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, td);
 1301         return (error);
 1302 }
 1303 
 1304 static int
 1305 union_rename(ap)
 1306         struct vop_rename_args  /* {
 1307                 struct vnode *a_fdvp;
 1308                 struct vnode *a_fvp;
 1309                 struct componentname *a_fcnp;
 1310                 struct vnode *a_tdvp;
 1311                 struct vnode *a_tvp;
 1312                 struct componentname *a_tcnp;
 1313         } */ *ap;
 1314 {
 1315         int error;
 1316         struct vnode *fdvp = ap->a_fdvp;
 1317         struct vnode *fvp = ap->a_fvp;
 1318         struct vnode *tdvp = ap->a_tdvp;
 1319         struct vnode *tvp = ap->a_tvp;
 1320 
 1321         /*
 1322          * Figure out what fdvp to pass to our upper or lower vnode.  If we
 1323          * replace the fdvp, release the original one and ref the new one.
 1324          */
 1325 
 1326         if (fdvp->v_op == union_vnodeop_p) {    /* always true */
 1327                 struct union_node *un = VTOUNION(fdvp);
 1328                 if (un->un_uppervp == NULLVP) {
 1329                         /*
 1330                          * this should never happen in normal
 1331                          * operation but might if there was
 1332                          * a problem creating the top-level shadow
 1333                          * directory.
 1334                          */
 1335                         error = EXDEV;
 1336                         goto bad;
 1337                 }
 1338                 fdvp = un->un_uppervp;
 1339                 VREF(fdvp);
 1340                 vrele(ap->a_fdvp);
 1341         }
 1342 
 1343         /*
 1344          * Figure out what fvp to pass to our upper or lower vnode.  If we
 1345          * replace the fvp, release the original one and ref the new one.
 1346          */
 1347 
 1348         if (fvp->v_op == union_vnodeop_p) {     /* always true */
 1349                 struct union_node *un = VTOUNION(fvp);
 1350 #if 0
 1351                 struct union_mount *um = MOUNTTOUNIONMOUNT(fvp->v_mount);
 1352 #endif
 1353 
 1354                 if (un->un_uppervp == NULLVP) {
 1355                         switch(fvp->v_type) {
 1356                         case VREG:
 1357                                 vn_lock(un->un_vnode, LK_EXCLUSIVE | LK_RETRY, ap->a_fcnp->cn_thread);
 1358                                 error = union_copyup(un, 1, ap->a_fcnp->cn_cred, ap->a_fcnp->cn_thread);
 1359                                 VOP_UNLOCK(un->un_vnode, 0, ap->a_fcnp->cn_thread);
 1360                                 if (error)
 1361                                         goto bad;
 1362                                 break;
 1363                         case VDIR:
 1364                                 /*
 1365                                  * XXX not yet.
 1366                                  *
 1367                                  * There is only one way to rename a directory
 1368                                  * based in the lowervp, and that is to copy
 1369                                  * the entire directory hierarchy.  Otherwise
 1370                                  * it would not last across a reboot.
 1371                                  */
 1372 #if 0
 1373                                 vrele(fvp);
 1374                                 fvp = NULL;
 1375                                 vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY, ap->a_fcnp->cn_thread);
 1376                                 error = union_mkshadow(um, fdvp, 
 1377                                             ap->a_fcnp, &un->un_uppervp);
 1378                                 VOP_UNLOCK(fdvp, 0, ap->a_fcnp->cn_thread);
 1379                                 if (un->un_uppervp)
 1380                                         VOP_UNLOCK(un->un_uppervp, 0, ap->a_fcnp->cn_thread);
 1381                                 if (error)
 1382                                         goto bad;
 1383                                 break;
 1384 #endif
 1385                         default:
 1386                                 error = EXDEV;
 1387                                 goto bad;
 1388                         }
 1389                 }
 1390 
 1391                 if (un->un_lowervp != NULLVP)
 1392                         ap->a_fcnp->cn_flags |= DOWHITEOUT;
 1393                 fvp = un->un_uppervp;
 1394                 VREF(fvp);
 1395                 vrele(ap->a_fvp);
 1396         }
 1397 
 1398         /*
 1399          * Figure out what tdvp (destination directory) to pass to the
 1400          * lower level.  If we replace it with uppervp, we need to vput the 
 1401          * old one.  The exclusive lock is transfered to what we will pass
 1402          * down in the VOP_RENAME() and we replace uppervp with a simple
 1403          * reference.
 1404          */
 1405 
 1406         if (tdvp->v_op == union_vnodeop_p) {
 1407                 struct union_node *un = VTOUNION(tdvp);
 1408 
 1409                 if (un->un_uppervp == NULLVP) {
 1410                         /*
 1411                          * This should never happen in normal
 1412                          * operation but might if there was
 1413                          * a problem creating the top-level shadow
 1414                          * directory.
 1415                          */
 1416                         error = EXDEV;
 1417                         goto bad;
 1418                 }
 1419 
 1420                 /*
 1421                  * New tdvp is a lock and reference on uppervp.
 1422                  * Put away the old tdvp.
 1423                  */
 1424                 tdvp = union_lock_upper(un, ap->a_tcnp->cn_thread);
 1425                 vput(ap->a_tdvp);
 1426         }
 1427 
 1428         /*
 1429          * Figure out what tvp (destination file) to pass to the
 1430          * lower level.
 1431          *
 1432          * If the uppervp file does not exist, put away the (wrong)
 1433          * file and change tvp to NULL.
 1434          */
 1435 
 1436         if (tvp != NULLVP && tvp->v_op == union_vnodeop_p) {
 1437                 struct union_node *un = VTOUNION(tvp);
 1438 
 1439                 tvp = union_lock_upper(un, ap->a_tcnp->cn_thread);
 1440                 vput(ap->a_tvp);
 1441                 /* note: tvp may be NULL */
 1442         }
 1443 
 1444         /*
 1445          * VOP_RENAME() releases/vputs prior to returning, so we have no
 1446          * cleanup to do.
 1447          */
 1448 
 1449         return (VOP_RENAME(fdvp, fvp, ap->a_fcnp, tdvp, tvp, ap->a_tcnp));
 1450 
 1451         /*
 1452          * Error.  We still have to release / vput the various elements.
 1453          */
 1454 
 1455 bad:
 1456         vrele(fdvp);
 1457         if (fvp)
 1458                 vrele(fvp);
 1459         vput(tdvp);
 1460         if (tvp != NULLVP) {
 1461                 if (tvp != tdvp)
 1462                         vput(tvp);
 1463                 else
 1464                         vrele(tvp);
 1465         }
 1466         return (error);
 1467 }
 1468 
 1469 static int
 1470 union_mkdir(ap)
 1471         struct vop_mkdir_args /* {
 1472                 struct vnode *a_dvp;
 1473                 struct vnode **a_vpp;
 1474                 struct componentname *a_cnp;
 1475                 struct vattr *a_vap;
 1476         } */ *ap;
 1477 {
 1478         struct union_node *dun = VTOUNION(ap->a_dvp);
 1479         struct componentname *cnp = ap->a_cnp;
 1480         struct thread *td = cnp->cn_thread;
 1481         struct vnode *upperdvp;
 1482         int error = EROFS;
 1483 
 1484         if ((upperdvp = union_lock_upper(dun, td)) != NULLVP) {
 1485                 struct vnode *vp;
 1486 
 1487                 error = VOP_MKDIR(upperdvp, &vp, cnp, ap->a_vap);
 1488                 union_unlock_upper(upperdvp, td);
 1489 
 1490                 if (error == 0) {
 1491                         VOP_UNLOCK(vp, 0, td);
 1492                         UDEBUG(("ALLOCVP-2 FROM %p REFS %d\n", vp, vrefcnt(vp)));
 1493                         error = union_allocvp(ap->a_vpp, ap->a_dvp->v_mount,
 1494                                 ap->a_dvp, NULLVP, cnp, vp, NULLVP, 1);
 1495                         UDEBUG(("ALLOCVP-2B FROM %p REFS %d\n", *ap->a_vpp, vrefcnt(vp)));
 1496                 }
 1497         }
 1498         return (error);
 1499 }
 1500 
 1501 static int
 1502 union_rmdir(ap)
 1503         struct vop_rmdir_args /* {
 1504                 struct vnode *a_dvp;
 1505                 struct vnode *a_vp;
 1506                 struct componentname *a_cnp;
 1507         } */ *ap;
 1508 {
 1509         struct union_node *dun = VTOUNION(ap->a_dvp);
 1510         struct union_node *un = VTOUNION(ap->a_vp);
 1511         struct componentname *cnp = ap->a_cnp;
 1512         struct thread *td = cnp->cn_thread;
 1513         struct vnode *upperdvp;
 1514         struct vnode *uppervp;
 1515         int error;
 1516 
 1517         if ((upperdvp = union_lock_upper(dun, td)) == NULLVP)
 1518                 panic("union rmdir: null upper vnode");
 1519 
 1520         if ((uppervp = union_lock_upper(un, td)) != NULLVP) {
 1521                 if (union_dowhiteout(un, cnp->cn_cred, td))
 1522                         cnp->cn_flags |= DOWHITEOUT;
 1523                 error = VOP_RMDIR(upperdvp, uppervp, ap->a_cnp);
 1524                 union_unlock_upper(uppervp, td);
 1525         } else {
 1526                 error = union_mkwhiteout(
 1527                             MOUNTTOUNIONMOUNT(ap->a_dvp->v_mount),
 1528                             dun->un_uppervp, ap->a_cnp, un->un_path);
 1529         }
 1530         union_unlock_upper(upperdvp, td);
 1531         return (error);
 1532 }
 1533 
 1534 /*
 1535  *      union_symlink:
 1536  *
 1537  *      dvp is locked on entry and remains locked on return.  a_vpp is garbage
 1538  *      (unused).
 1539  */
 1540 
 1541 static int
 1542 union_symlink(ap)
 1543         struct vop_symlink_args /* {
 1544                 struct vnode *a_dvp;
 1545                 struct vnode **a_vpp;
 1546                 struct componentname *a_cnp;
 1547                 struct vattr *a_vap;
 1548                 char *a_target;
 1549         } */ *ap;
 1550 {
 1551         struct union_node *dun = VTOUNION(ap->a_dvp);
 1552         struct componentname *cnp = ap->a_cnp;
 1553         struct thread *td = cnp->cn_thread;
 1554         struct vnode *dvp;
 1555         int error = EROFS;
 1556 
 1557         if ((dvp = union_lock_upper(dun, td)) != NULLVP) {
 1558                 error = VOP_SYMLINK(dvp, ap->a_vpp, cnp, ap->a_vap,
 1559                             ap->a_target);
 1560                 union_unlock_upper(dvp, td);
 1561         }
 1562         return (error);
 1563 }
 1564 
 1565 /*
 1566  * union_readdir ()works in concert with getdirentries() and
 1567  * readdir(3) to provide a list of entries in the unioned
 1568  * directories.  getdirentries()  is responsible for walking
 1569  * down the union stack.  readdir(3) is responsible for
 1570  * eliminating duplicate names from the returned data stream.
 1571  */
 1572 static int
 1573 union_readdir(ap)
 1574         struct vop_readdir_args /* {
 1575                 struct vnode *a_vp;
 1576                 struct uio *a_uio;
 1577                 struct ucred *a_cred;
 1578                 int *a_eofflag;
 1579                 u_long *a_cookies;
 1580                 int a_ncookies;
 1581         } */ *ap;
 1582 {
 1583         struct union_node *un = VTOUNION(ap->a_vp);
 1584         struct thread *td = ap->a_uio->uio_td;
 1585         struct vnode *uvp;
 1586         int error = 0;
 1587 
 1588         if ((uvp = union_lock_upper(un, td)) != NULLVP) {
 1589                 ap->a_vp = uvp;
 1590                 error = VCALL(uvp, VOFFSET(vop_readdir), ap);
 1591                 union_unlock_upper(uvp, td);
 1592         }
 1593         return(error);
 1594 }
 1595 
 1596 static int
 1597 union_readlink(ap)
 1598         struct vop_readlink_args /* {
 1599                 struct vnode *a_vp;
 1600                 struct uio *a_uio;
 1601                 struct ucred *a_cred;
 1602         } */ *ap;
 1603 {
 1604         int error;
 1605         struct union_node *un = VTOUNION(ap->a_vp);
 1606         struct uio *uio = ap->a_uio;
 1607         struct thread *td = uio->uio_td;
 1608         struct vnode *vp;
 1609 
 1610         vp = union_lock_other(un, td);
 1611         KASSERT(vp != NULL, ("union_readlink: backing vnode missing!"));
 1612 
 1613         ap->a_vp = vp;
 1614         error = VCALL(vp, VOFFSET(vop_readlink), ap);
 1615         union_unlock_other(vp, td);
 1616 
 1617         return (error);
 1618 }
 1619 
 1620 static int
 1621 union_getwritemount(ap)
 1622         struct vop_getwritemount_args /* {
 1623                 struct vnode *a_vp;
 1624                 struct mount **a_mpp;
 1625         } */ *ap;
 1626 {
 1627         struct vnode *vp = ap->a_vp;
 1628         struct vnode *uvp = UPPERVP(vp);
 1629 
 1630         if (uvp == NULL) {
 1631                 VI_LOCK(vp);
 1632                 if (vp->v_iflag & VI_FREE) {
 1633                         VI_UNLOCK(vp);
 1634                         return (EOPNOTSUPP);
 1635                 }
 1636                 VI_UNLOCK(vp);
 1637                 return (EACCES);
 1638         }
 1639         return(VOP_GETWRITEMOUNT(uvp, ap->a_mpp));
 1640 }
 1641 
 1642 /*
 1643  *      union_inactive:
 1644  *
 1645  *      Called with the vnode locked.  We are expected to unlock the vnode.
 1646  */
 1647 
 1648 static int
 1649 union_inactive(ap)
 1650         struct vop_inactive_args /* {
 1651                 struct vnode *a_vp;
 1652                 struct thread *a_td;
 1653         } */ *ap;
 1654 {
 1655         struct vnode *vp = ap->a_vp;
 1656         struct thread *td = ap->a_td;
 1657         struct union_node *un = VTOUNION(vp);
 1658         struct vnode **vpp;
 1659 
 1660         /*
 1661          * Do nothing (and _don't_ bypass).
 1662          * Wait to vrele lowervp until reclaim,
 1663          * so that until then our union_node is in the
 1664          * cache and reusable.
 1665          *
 1666          */
 1667 
 1668         if (un->un_dircache != 0) {
 1669                 for (vpp = un->un_dircache; *vpp != NULLVP; vpp++)
 1670                         vrele(*vpp);
 1671                 free (un->un_dircache, M_TEMP);
 1672                 un->un_dircache = 0;
 1673         }
 1674 
 1675 #if 0
 1676         if ((un->un_flags & UN_ULOCK) && un->un_uppervp) {
 1677                 un->un_flags &= ~UN_ULOCK;
 1678                 VOP_UNLOCK(un->un_uppervp, 0, td);
 1679         }
 1680 #endif
 1681 
 1682         VOP_UNLOCK(vp, 0, td);
 1683 
 1684         if ((un->un_flags & UN_CACHED) == 0)
 1685                 vgone(vp);
 1686 
 1687         return (0);
 1688 }
 1689 
 1690 static int
 1691 union_reclaim(ap)
 1692         struct vop_reclaim_args /* {
 1693                 struct vnode *a_vp;
 1694         } */ *ap;
 1695 {
 1696         union_freevp(ap->a_vp);
 1697 
 1698         return (0);
 1699 }
 1700 
 1701 /*
 1702  * unionvp do not hold a VM object and there is no need to create one for
 1703  * upper or lower vp because it is done in the union_open()
 1704  */
 1705 static int
 1706 union_createvobject(ap)
 1707         struct vop_createvobject_args /* {
 1708                 struct vnode *vp;
 1709                 struct ucred *cred;
 1710                 struct thread *td;
 1711         } */ *ap;
 1712 {
 1713         struct vnode *vp = ap->a_vp;
 1714 
 1715         vp->v_vflag |= VV_OBJBUF;
 1716         return (0);
 1717 }
 1718 
 1719 /*
 1720  * We have nothing to destroy and this operation shouldn't be bypassed.
 1721  */
 1722 static int
 1723 union_destroyvobject(ap)
 1724         struct vop_destroyvobject_args /* {
 1725                 struct vnode *vp;
 1726         } */ *ap;
 1727 {
 1728         struct vnode *vp = ap->a_vp;
 1729 
 1730         vp->v_vflag &= ~VV_OBJBUF;
 1731         return (0);
 1732 }
 1733 
 1734 /*
 1735  * Get VM object from the upper or lower vp
 1736  */
 1737 static int
 1738 union_getvobject(ap)
 1739         struct vop_getvobject_args /* {
 1740                 struct vnode *vp;
 1741                 struct vm_object **objpp;
 1742         } */ *ap;
 1743 {
 1744         struct vnode *ovp = OTHERVP(ap->a_vp);
 1745 
 1746         if (ovp == NULL)
 1747                 return EINVAL;
 1748         return (VOP_GETVOBJECT(ovp, ap->a_objpp));
 1749 }
 1750 
 1751 static int
 1752 union_print(ap)
 1753         struct vop_print_args /* {
 1754                 struct vnode *a_vp;
 1755         } */ *ap;
 1756 {
 1757         struct vnode *vp = ap->a_vp;
 1758 
 1759         printf("\ttag %s, vp=%p, uppervp=%p, lowervp=%p\n", vp->v_tag,
 1760                vp, UPPERVP(vp), LOWERVP(vp));
 1761         if (UPPERVP(vp) != NULLVP)
 1762                 vprint("union: upper", UPPERVP(vp));
 1763         if (LOWERVP(vp) != NULLVP)
 1764                 vprint("union: lower", LOWERVP(vp));
 1765 
 1766         return (0);
 1767 }
 1768 
 1769 static int
 1770 union_pathconf(ap)
 1771         struct vop_pathconf_args /* {
 1772                 struct vnode *a_vp;
 1773                 int a_name;
 1774                 int *a_retval;
 1775         } */ *ap;
 1776 {
 1777         int error;
 1778         struct thread *td = curthread;          /* XXX */
 1779         struct union_node *un = VTOUNION(ap->a_vp);
 1780         struct vnode *vp;
 1781 
 1782         vp = union_lock_other(un, td);
 1783         KASSERT(vp != NULL, ("union_pathconf: backing vnode missing!"));
 1784 
 1785         ap->a_vp = vp;
 1786         error = VCALL(vp, VOFFSET(vop_pathconf), ap);
 1787         union_unlock_other(vp, td);
 1788 
 1789         return (error);
 1790 }
 1791 
 1792 static int
 1793 union_advlock(ap)
 1794         struct vop_advlock_args /* {
 1795                 struct vnode *a_vp;
 1796                 caddr_t  a_id;
 1797                 int  a_op;
 1798                 struct flock *a_fl;
 1799                 int  a_flags;
 1800         } */ *ap;
 1801 {
 1802         register struct vnode *ovp = OTHERVP(ap->a_vp);
 1803 
 1804         ap->a_vp = ovp;
 1805         return (VCALL(ovp, VOFFSET(vop_advlock), ap));
 1806 }
 1807 
 1808 
 1809 /*
 1810  * XXX - vop_strategy must be hand coded because it has no
 1811  * YYY - and it is not coherent with anything
 1812  *
 1813  * vnode in its arguments.
 1814  * This goes away with a merged VM/buffer cache.
 1815  */
 1816 static int
 1817 union_strategy(ap)
 1818         struct vop_strategy_args /* {
 1819                 struct vnode *a_vp;
 1820                 struct buf *a_bp;
 1821         } */ *ap;
 1822 {
 1823         struct buf *bp = ap->a_bp;
 1824         struct vnode *othervp = OTHERVP(bp->b_vp);
 1825 
 1826 #ifdef DIAGNOSTIC
 1827         if (othervp == NULLVP)
 1828                 panic("union_strategy: nil vp");
 1829         if ((bp->b_iocmd == BIO_WRITE) &&
 1830             (othervp == LOWERVP(bp->b_vp)))
 1831                 panic("union_strategy: writing to lowervp");
 1832 #endif
 1833         return (VOP_STRATEGY(othervp, bp));
 1834 }
 1835 
 1836 /*
 1837  * Global vfs data structures
 1838  */
 1839 vop_t **union_vnodeop_p;
 1840 static struct vnodeopv_entry_desc union_vnodeop_entries[] = {
 1841         { &vop_default_desc,            (vop_t *) vop_defaultop },
 1842         { &vop_access_desc,             (vop_t *) union_access },
 1843         { &vop_advlock_desc,            (vop_t *) union_advlock },
 1844         { &vop_bmap_desc,               (vop_t *) vop_eopnotsupp },
 1845         { &vop_close_desc,              (vop_t *) union_close },
 1846         { &vop_create_desc,             (vop_t *) union_create },
 1847         { &vop_createvobject_desc,      (vop_t *) union_createvobject },
 1848         { &vop_destroyvobject_desc,     (vop_t *) union_destroyvobject },
 1849         { &vop_fsync_desc,              (vop_t *) union_fsync },
 1850         { &vop_getattr_desc,            (vop_t *) union_getattr },
 1851         { &vop_getvobject_desc,         (vop_t *) union_getvobject },
 1852         { &vop_inactive_desc,           (vop_t *) union_inactive },
 1853         { &vop_ioctl_desc,              (vop_t *) union_ioctl },
 1854         { &vop_islocked_desc,           (vop_t *) vop_stdislocked },
 1855         { &vop_lease_desc,              (vop_t *) union_lease },
 1856         { &vop_link_desc,               (vop_t *) union_link },
 1857         { &vop_lookup_desc,             (vop_t *) union_lookup },
 1858         { &vop_mkdir_desc,              (vop_t *) union_mkdir },
 1859         { &vop_mknod_desc,              (vop_t *) union_mknod },
 1860         { &vop_open_desc,               (vop_t *) union_open },
 1861         { &vop_pathconf_desc,           (vop_t *) union_pathconf },
 1862         { &vop_poll_desc,               (vop_t *) union_poll },
 1863         { &vop_print_desc,              (vop_t *) union_print },
 1864         { &vop_read_desc,               (vop_t *) union_read },
 1865         { &vop_readdir_desc,            (vop_t *) union_readdir },
 1866         { &vop_readlink_desc,           (vop_t *) union_readlink },
 1867         { &vop_getwritemount_desc,      (vop_t *) union_getwritemount },
 1868         { &vop_reclaim_desc,            (vop_t *) union_reclaim },
 1869         { &vop_remove_desc,             (vop_t *) union_remove },
 1870         { &vop_rename_desc,             (vop_t *) union_rename },
 1871         { &vop_revoke_desc,             (vop_t *) union_revoke },
 1872         { &vop_rmdir_desc,              (vop_t *) union_rmdir },
 1873         { &vop_setattr_desc,            (vop_t *) union_setattr },
 1874         { &vop_strategy_desc,           (vop_t *) union_strategy },
 1875         { &vop_symlink_desc,            (vop_t *) union_symlink },
 1876         { &vop_whiteout_desc,           (vop_t *) union_whiteout },
 1877         { &vop_write_desc,              (vop_t *) union_write },
 1878         { NULL, NULL }
 1879 };
 1880 static struct vnodeopv_desc union_vnodeop_opv_desc =
 1881         { &union_vnodeop_p, union_vnodeop_entries };
 1882 
 1883 VNODEOP_SET(union_vnodeop_opv_desc);

Cache object: 25f97c3faa1d44f5bcfe32914765b51c


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