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.
    5  * Copyright (c) 2005, 2006 Masanori Ozawa <ozawa@ongs.co.jp>, ONGS Inc.
    6  * Copyright (c) 2006 Daichi Goto <daichi@freebsd.org>
    7  * All rights reserved.
    8  *
    9  * This code is derived from software contributed to Berkeley by
   10  * Jan-Simon Pendry.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 4. Neither the name of the University nor the names of its contributors
   21  *    may be used to endorse or promote products derived from this software
   22  *    without specific prior written permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   34  * SUCH DAMAGE.
   35  *
   36  *      @(#)union_vnops.c       8.32 (Berkeley) 6/23/95
   37  * $FreeBSD$
   38  *
   39  */
   40 
   41 #include <sys/param.h>
   42 #include <sys/systm.h>
   43 #include <sys/conf.h>
   44 #include <sys/kernel.h>
   45 #include <sys/lock.h>
   46 #include <sys/malloc.h>
   47 #include <sys/mount.h>
   48 #include <sys/mutex.h>
   49 #include <sys/namei.h>
   50 #include <sys/sysctl.h>
   51 #include <sys/vnode.h>
   52 #include <sys/kdb.h>
   53 #include <sys/fcntl.h>
   54 #include <sys/stat.h>
   55 #include <sys/dirent.h>
   56 #include <sys/proc.h>
   57 #include <sys/bio.h>
   58 #include <sys/buf.h>
   59 
   60 #include <fs/unionfs/union.h>
   61 
   62 #include <vm/vm.h>
   63 #include <vm/vm_extern.h>
   64 #include <vm/vm_object.h>
   65 #include <vm/vnode_pager.h>
   66 
   67 #if 0
   68 #define UNIONFS_INTERNAL_DEBUG(msg, args...)    printf(msg, ## args)
   69 #define UNIONFS_IDBG_RENAME
   70 #else
   71 #define UNIONFS_INTERNAL_DEBUG(msg, args...)
   72 #endif
   73 
   74 #define KASSERT_UNIONFS_VNODE(vp) \
   75         KASSERT(((vp)->v_op == &unionfs_vnodeops), \
   76             ("unionfs: it is not unionfs-vnode"))
   77 
   78 /* lockmgr lock <-> reverse table */
   79 struct lk_lr_table {
   80         int     lock;
   81         int     revlock;
   82 };
   83 
   84 static struct lk_lr_table un_llt[] = {
   85         {LK_SHARED, LK_RELEASE},
   86         {LK_EXCLUSIVE, LK_RELEASE},
   87         {LK_UPGRADE, LK_DOWNGRADE},
   88         {LK_EXCLUPGRADE, LK_DOWNGRADE},
   89         {LK_DOWNGRADE, LK_UPGRADE},
   90         {0, 0}
   91 };
   92 
   93 
   94 static int
   95 unionfs_lookup(struct vop_cachedlookup_args *ap)
   96 {
   97         int             iswhiteout;
   98         int             lockflag;
   99         int             error , uerror, lerror;
  100         u_long          nameiop;
  101         u_long          cnflags, cnflagsbk;
  102         struct unionfs_node *dunp;
  103         struct vnode   *dvp, *udvp, *ldvp, *vp, *uvp, *lvp, *dtmpvp;
  104         struct vattr    va;
  105         struct componentname *cnp;
  106         struct thread  *td;
  107 
  108         iswhiteout = 0;
  109         lockflag = 0;
  110         error = uerror = lerror = ENOENT;
  111         cnp = ap->a_cnp;
  112         nameiop = cnp->cn_nameiop;
  113         cnflags = cnp->cn_flags;
  114         dvp = ap->a_dvp;
  115         dunp = VTOUNIONFS(dvp);
  116         udvp = dunp->un_uppervp;
  117         ldvp = dunp->un_lowervp;
  118         vp = uvp = lvp = NULLVP;
  119         td = curthread;
  120         *(ap->a_vpp) = NULLVP;
  121 
  122         UNIONFS_INTERNAL_DEBUG("unionfs_lookup: enter: nameiop=%ld, flags=%lx, path=%s\n", nameiop, cnflags, cnp->cn_nameptr);
  123 
  124         if (dvp->v_type != VDIR)
  125                 return (ENOTDIR);
  126 
  127         /*
  128          * If read-only and op is not LOOKUP, will return EROFS.
  129          */
  130         if ((cnflags & ISLASTCN) &&
  131             (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
  132             LOOKUP != nameiop)
  133                 return (EROFS);
  134 
  135         /*
  136          * lookup dotdot
  137          */
  138         if (cnflags & ISDOTDOT) {
  139                 if (LOOKUP != nameiop && udvp == NULLVP)
  140                         return (EROFS);
  141 
  142                 if (udvp != NULLVP) {
  143                         dtmpvp = udvp;
  144                         if (ldvp != NULLVP)
  145                                 VOP_UNLOCK(ldvp, 0, td);
  146                 }
  147                 else
  148                         dtmpvp = ldvp;
  149 
  150                 error = VOP_LOOKUP(dtmpvp, &vp, cnp);
  151 
  152                 if (dtmpvp == udvp && ldvp != NULLVP) {
  153                         VOP_UNLOCK(udvp, 0, td);
  154                         vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td);
  155                 }
  156 
  157                 if (error == 0) {
  158                         /*
  159                          * Exchange lock and reference from vp to
  160                          * dunp->un_dvp. vp is upper/lower vnode, but it
  161                          * will need to return the unionfs vnode.
  162                          */
  163                         if (nameiop == DELETE  || nameiop == RENAME ||
  164                             (cnp->cn_lkflags & LK_TYPE_MASK))
  165                                 VOP_UNLOCK(vp, 0, td);
  166                         vrele(vp);
  167 
  168                         VOP_UNLOCK(dvp, 0, td);
  169                         *(ap->a_vpp) = dunp->un_dvp;
  170                         vref(dunp->un_dvp);
  171 
  172                         if (nameiop == DELETE || nameiop == RENAME)
  173                                 vn_lock(dunp->un_dvp, LK_EXCLUSIVE | LK_RETRY, td);
  174                         else if (cnp->cn_lkflags & LK_TYPE_MASK)
  175                                 vn_lock(dunp->un_dvp, cnp->cn_lkflags | LK_RETRY, td);
  176 
  177                         vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td);
  178                 } else if (error == ENOENT && (cnflags & MAKEENTRY) &&
  179                     nameiop != CREATE)
  180                         cache_enter(dvp, NULLVP, cnp);
  181 
  182                 UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", error);
  183 
  184                 return (error);
  185         }
  186 
  187         /*
  188          * lookup upper layer
  189          */
  190         if (udvp != NULLVP) {
  191                 uerror = VOP_LOOKUP(udvp, &uvp, cnp);
  192 
  193                 if (uerror == 0) {
  194                         if (udvp == uvp) {      /* is dot */
  195                                 vrele(uvp);
  196                                 *(ap->a_vpp) = dvp;
  197                                 vref(dvp);
  198 
  199                                 UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", uerror);
  200 
  201                                 return (uerror);
  202                         }
  203                         if (nameiop == DELETE || nameiop == RENAME ||
  204                             (cnp->cn_lkflags & LK_TYPE_MASK))
  205                                 VOP_UNLOCK(uvp, 0, td);
  206                 }
  207 
  208                 /* check whiteout */
  209                 if (uerror == ENOENT || uerror == EJUSTRETURN)
  210                         if (cnp->cn_flags & ISWHITEOUT)
  211                                 iswhiteout = 1; /* don't lookup lower */
  212                 if (iswhiteout == 0 && ldvp != NULLVP)
  213                         if (VOP_GETATTR(udvp, &va, cnp->cn_cred, td) == 0 &&
  214                             (va.va_flags & OPAQUE))
  215                                 iswhiteout = 1; /* don't lookup lower */
  216 #if 0
  217                 UNIONFS_INTERNAL_DEBUG("unionfs_lookup: debug: whiteout=%d, path=%s\n", iswhiteout, cnp->cn_nameptr);
  218 #endif
  219         }
  220 
  221         /*
  222          * lookup lower layer
  223          */
  224         if (ldvp != NULLVP && !(cnflags & DOWHITEOUT) && iswhiteout == 0) {
  225                 /* always op is LOOKUP */
  226                 cnp->cn_nameiop = LOOKUP;
  227                 cnflagsbk = cnp->cn_flags;
  228                 cnp->cn_flags = cnflags;
  229 
  230                 lerror = VOP_LOOKUP(ldvp, &lvp, cnp);
  231 
  232                 cnp->cn_nameiop = nameiop;
  233                 if (udvp != NULLVP && (uerror == 0 || uerror == EJUSTRETURN))
  234                         cnp->cn_flags = cnflagsbk;
  235 
  236                 if (lerror == 0) {
  237                         if (ldvp == lvp) {      /* is dot */
  238                                 if (uvp != NULLVP)
  239                                         vrele(uvp);     /* no need? */
  240                                 vrele(lvp);
  241                                 *(ap->a_vpp) = dvp;
  242                                 vref(dvp);
  243 
  244                                 UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", lerror);
  245 
  246                                 return (lerror);
  247                         }
  248                         if (cnp->cn_lkflags & LK_TYPE_MASK)
  249                                 VOP_UNLOCK(lvp, 0, td);
  250                 }
  251         }
  252 
  253         /*
  254          * check lookup result
  255          */
  256         if (uvp == NULLVP && lvp == NULLVP) {
  257                 UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n",
  258                     (udvp != NULLVP ? uerror : lerror));
  259                 return (udvp != NULLVP ? uerror : lerror);
  260         }
  261 
  262         /*
  263          * check vnode type
  264          */
  265         if (uvp != NULLVP && lvp != NULLVP && uvp->v_type != lvp->v_type) {
  266                 vrele(lvp);
  267                 lvp = NULLVP;
  268         }
  269 
  270         /*
  271          * check shadow dir
  272          */
  273         if (uerror != 0 && uerror != EJUSTRETURN && udvp != NULLVP &&
  274             lerror == 0 && lvp != NULLVP && lvp->v_type == VDIR &&
  275             !(dvp->v_mount->mnt_flag & MNT_RDONLY) &&
  276             (1 < cnp->cn_namelen || '.' != *(cnp->cn_nameptr))) {
  277                 /* get unionfs vnode in order to create a new shadow dir. */
  278                 error = unionfs_nodeget(dvp->v_mount, NULLVP, lvp, dvp, &vp,
  279                     cnp, td);
  280                 if (error != 0)
  281                         goto unionfs_lookup_out;
  282 
  283                 if (LK_SHARED == (cnp->cn_lkflags & LK_TYPE_MASK))
  284                         VOP_UNLOCK(vp, 0, td);
  285                 if (LK_EXCLUSIVE != VOP_ISLOCKED(vp, td)) {
  286                         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
  287                         lockflag = 1;
  288                 }
  289                 error = unionfs_mkshadowdir(MOUNTTOUNIONFSMOUNT(dvp->v_mount),
  290                     udvp, VTOUNIONFS(vp), cnp, td);
  291                 if (lockflag != 0)
  292                         VOP_UNLOCK(vp, 0, td);
  293                 if (error != 0) {
  294                         UNIONFSDEBUG("unionfs_lookup: Unable to create shadow dir.");
  295                         if ((cnp->cn_lkflags & LK_TYPE_MASK) == LK_EXCLUSIVE)
  296                                 vput(vp);
  297                         else
  298                                 vrele(vp);
  299                         goto unionfs_lookup_out;
  300                 }
  301                 if ((cnp->cn_lkflags & LK_TYPE_MASK) == LK_SHARED)
  302                         vn_lock(vp, LK_SHARED | LK_RETRY, td);
  303         }
  304         /*
  305          * get unionfs vnode.
  306          */
  307         else {
  308                 if (uvp != NULLVP)
  309                         error = uerror;
  310                 else
  311                         error = lerror;
  312                 if (error != 0)
  313                         goto unionfs_lookup_out;
  314                 /*
  315                  * get socket vnode.
  316                  */
  317                 if (uvp != NULLVP && uvp->v_type == VSOCK) {
  318                         vp = uvp;
  319                         vref(vp);
  320                         if (cnp->cn_lkflags & LK_TYPE_MASK)
  321                                 vn_lock(vp, cnp->cn_lkflags | LK_RETRY, td);
  322                 }
  323                 else if (lvp != NULLVP && lvp->v_type == VSOCK) {
  324                         vp = lvp;
  325                         vref(vp);
  326                         if (cnp->cn_lkflags & LK_TYPE_MASK)
  327                                 vn_lock(vp, cnp->cn_lkflags | LK_RETRY, td);
  328                 }
  329                 /*
  330                  * get unionfs vnode.
  331                  */
  332                 else
  333                         error = unionfs_nodeget(dvp->v_mount, uvp, lvp,
  334                             dvp, &vp, cnp, td);
  335                 if (error != 0) {
  336                         UNIONFSDEBUG("unionfs_lookup: Unable to create unionfs vnode.");
  337                         goto unionfs_lookup_out;
  338                 }
  339                 if ((nameiop == DELETE || nameiop == RENAME) &&
  340                     (cnp->cn_lkflags & LK_TYPE_MASK) == 0)
  341                         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
  342         }
  343 
  344         *(ap->a_vpp) = vp;
  345 
  346         if ((cnflags & MAKEENTRY) && vp->v_type != VSOCK)
  347                 cache_enter(dvp, vp, cnp);
  348 
  349 unionfs_lookup_out:
  350         if (uvp != NULLVP)
  351                 vrele(uvp);
  352         if (lvp != NULLVP)
  353                 vrele(lvp);
  354 
  355         if (error == ENOENT && (cnflags & MAKEENTRY) && nameiop != CREATE)
  356                 cache_enter(dvp, NULLVP, cnp);
  357 
  358         UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", error);
  359 
  360         return (error);
  361 }
  362 
  363 static int
  364 unionfs_create(struct vop_create_args *ap)
  365 {
  366         struct unionfs_node *dunp;
  367         struct componentname *cnp;
  368         struct thread  *td;
  369         struct vnode   *udvp;
  370         struct vnode   *vp;
  371         int             error;
  372 
  373         UNIONFS_INTERNAL_DEBUG("unionfs_create: enter\n");
  374 
  375         KASSERT_UNIONFS_VNODE(ap->a_dvp);
  376 
  377         dunp = VTOUNIONFS(ap->a_dvp);
  378         cnp = ap->a_cnp;
  379         td = curthread;
  380         udvp = dunp->un_uppervp;
  381         error = EROFS;
  382 
  383         if (udvp != NULLVP) {
  384                 error = VOP_CREATE(udvp, &vp, cnp, ap->a_vap);
  385                 if (error != 0)
  386                         goto unionfs_create_abort;
  387 
  388                 if (vp->v_type == VSOCK)
  389                         *(ap->a_vpp) = vp;
  390                 else {
  391                         VOP_UNLOCK(vp, 0, td);
  392                         error = unionfs_nodeget(ap->a_dvp->v_mount, vp, NULLVP,
  393                             ap->a_dvp, ap->a_vpp, cnp, td);
  394                         vrele(vp);
  395                 }
  396         }
  397 
  398 unionfs_create_abort:
  399         UNIONFS_INTERNAL_DEBUG("unionfs_create: leave (%d)\n", error);
  400 
  401         return (error);
  402 }
  403 
  404 static int
  405 unionfs_whiteout(struct vop_whiteout_args *ap)
  406 {
  407         struct unionfs_node *dunp;
  408         struct componentname *cnp;
  409         struct vnode   *udvp;
  410         int             error;
  411 
  412         UNIONFS_INTERNAL_DEBUG("unionfs_whiteout: enter\n");
  413 
  414         KASSERT_UNIONFS_VNODE(ap->a_dvp);
  415 
  416         dunp = VTOUNIONFS(ap->a_dvp);
  417         cnp = ap->a_cnp;
  418         udvp = dunp->un_uppervp;
  419         error = EOPNOTSUPP;
  420 
  421         if (udvp != NULLVP) {
  422                 switch (ap->a_flags) {
  423                 case CREATE:
  424                 case DELETE:
  425                 case LOOKUP:
  426                         error = VOP_WHITEOUT(udvp, cnp, ap->a_flags);
  427                         break;
  428                 default:
  429                         error = EINVAL;
  430                         break;
  431                 }
  432         }
  433 
  434         UNIONFS_INTERNAL_DEBUG("unionfs_whiteout: leave (%d)\n", error);
  435 
  436         return (error);
  437 }
  438 
  439 static int
  440 unionfs_mknod(struct vop_mknod_args *ap)
  441 {
  442         struct unionfs_node *dunp;
  443         struct componentname *cnp;
  444         struct thread  *td;
  445         struct vnode   *udvp;
  446         struct vnode   *vp;
  447         int             error;
  448 
  449         UNIONFS_INTERNAL_DEBUG("unionfs_mknod: enter\n");
  450 
  451         KASSERT_UNIONFS_VNODE(ap->a_dvp);
  452 
  453         dunp = VTOUNIONFS(ap->a_dvp);
  454         cnp = ap->a_cnp;
  455         td = curthread;
  456         udvp = dunp->un_uppervp;
  457         error = EROFS;
  458 
  459         if (udvp != NULLVP) {
  460                 error = VOP_MKNOD(udvp, &vp, cnp, ap->a_vap);
  461                 if (error != 0)
  462                         goto unionfs_mknod_abort;
  463 
  464                 if (vp->v_type == VSOCK)
  465                         *(ap->a_vpp) = vp;
  466                 else {
  467                         VOP_UNLOCK(vp, 0, td);
  468                         error = unionfs_nodeget(ap->a_dvp->v_mount, vp, NULLVP,
  469                             ap->a_dvp, ap->a_vpp, cnp, td);
  470                         vrele(vp);
  471                 }
  472         }
  473 
  474 unionfs_mknod_abort:
  475         UNIONFS_INTERNAL_DEBUG("unionfs_mknod: leave (%d)\n", error);
  476 
  477         return (error);
  478 }
  479 
  480 static int
  481 unionfs_open(struct vop_open_args *ap)
  482 {
  483         int             error;
  484         struct unionfs_node *unp;
  485         struct unionfs_node_status *unsp;
  486         struct vnode   *uvp;
  487         struct vnode   *lvp;
  488         struct vnode   *targetvp;
  489         struct ucred   *cred;
  490         struct thread  *td;
  491 
  492         UNIONFS_INTERNAL_DEBUG("unionfs_open: enter\n");
  493 
  494         KASSERT_UNIONFS_VNODE(ap->a_vp);
  495 
  496         error = 0;
  497         unp = VTOUNIONFS(ap->a_vp);
  498         uvp = unp->un_uppervp;
  499         lvp = unp->un_lowervp;
  500         targetvp = NULLVP;
  501         cred = ap->a_cred;
  502         td = ap->a_td;
  503 
  504         unionfs_get_node_status(unp, td, &unsp);
  505 
  506         if (unsp->uns_lower_opencnt > 0 || unsp->uns_upper_opencnt > 0) {
  507                 /* vnode is already opend. */
  508                 if (unsp->uns_upper_opencnt > 0)
  509                         targetvp = uvp;
  510                 else
  511                         targetvp = lvp;
  512 
  513                 if (targetvp == lvp &&
  514                     (ap->a_mode & FWRITE) && lvp->v_type == VREG)
  515                         targetvp = NULLVP;
  516         }
  517         if (targetvp == NULLVP) {
  518                 if (uvp == NULLVP) {
  519                         if ((ap->a_mode & FWRITE) && lvp->v_type == VREG) {
  520                                 error = unionfs_copyfile(unp,
  521                                     !(ap->a_mode & O_TRUNC), cred, td);
  522                                 if (error != 0)
  523                                         goto unionfs_open_abort;
  524                                 targetvp = uvp = unp->un_uppervp;
  525                         } else
  526                                 targetvp = lvp;
  527                 } else
  528                         targetvp = uvp;
  529         }
  530 
  531         error = VOP_OPEN(targetvp, ap->a_mode, cred, td, ap->a_fp);
  532         if (error == 0) {
  533                 if (targetvp == uvp) {
  534                         if (uvp->v_type == VDIR && lvp != NULLVP &&
  535                             unsp->uns_lower_opencnt <= 0) {
  536                                 /* open lower for readdir */
  537                                 error = VOP_OPEN(lvp, FREAD, cred, td, NULL);
  538                                 if (error != 0) {
  539                                         VOP_CLOSE(uvp, ap->a_mode, cred, td);
  540                                         goto unionfs_open_abort;
  541                                 }
  542                                 unsp->uns_node_flag |= UNS_OPENL_4_READDIR;
  543                                 unsp->uns_lower_opencnt++;
  544                         }
  545                         unsp->uns_upper_opencnt++;
  546                 } else {
  547                         unsp->uns_lower_opencnt++;
  548                         unsp->uns_lower_openmode = ap->a_mode;
  549                 }
  550                 ap->a_vp->v_object = targetvp->v_object;
  551         }
  552 
  553 unionfs_open_abort:
  554         if (error != 0)
  555                 unionfs_tryrem_node_status(unp, unsp);
  556 
  557         UNIONFS_INTERNAL_DEBUG("unionfs_open: leave (%d)\n", error);
  558 
  559         return (error);
  560 }
  561 
  562 static int
  563 unionfs_close(struct vop_close_args *ap)
  564 {
  565         int             error;
  566         int             locked;
  567         struct unionfs_node *unp;
  568         struct unionfs_node_status *unsp;
  569         struct ucred   *cred;
  570         struct thread  *td;
  571         struct vnode   *ovp;
  572 
  573         UNIONFS_INTERNAL_DEBUG("unionfs_close: enter\n");
  574 
  575         KASSERT_UNIONFS_VNODE(ap->a_vp);
  576 
  577         locked = 0;
  578         unp = VTOUNIONFS(ap->a_vp);
  579         cred = ap->a_cred;
  580         td = ap->a_td;
  581 
  582         if (VOP_ISLOCKED(ap->a_vp, td) != LK_EXCLUSIVE) {
  583                 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, td);
  584                 locked = 1;
  585         }
  586         unionfs_get_node_status(unp, td, &unsp);
  587 
  588         if (unsp->uns_lower_opencnt <= 0 && unsp->uns_upper_opencnt <= 0) {
  589 #ifdef DIAGNOSTIC
  590                 printf("unionfs_close: warning: open count is 0\n");
  591 #endif
  592                 if (unp->un_uppervp != NULLVP)
  593                         ovp = unp->un_uppervp;
  594                 else
  595                         ovp = unp->un_lowervp;
  596         } else if (unsp->uns_upper_opencnt > 0)
  597                 ovp = unp->un_uppervp;
  598         else
  599                 ovp = unp->un_lowervp;
  600 
  601         error = VOP_CLOSE(ovp, ap->a_fflag, cred, td);
  602 
  603         if (error != 0)
  604                 goto unionfs_close_abort;
  605 
  606         ap->a_vp->v_object = ovp->v_object;
  607 
  608         if (ovp == unp->un_uppervp) {
  609                 unsp->uns_upper_opencnt--;
  610                 if (unsp->uns_upper_opencnt == 0) {
  611                         if (unsp->uns_node_flag & UNS_OPENL_4_READDIR) {
  612                                 VOP_CLOSE(unp->un_lowervp, FREAD, cred, td);
  613                                 unsp->uns_node_flag &= ~UNS_OPENL_4_READDIR;
  614                                 unsp->uns_lower_opencnt--;
  615                         }
  616                         if (unsp->uns_lower_opencnt > 0)
  617                                 ap->a_vp->v_object = unp->un_lowervp->v_object;
  618                 }
  619         } else
  620                 unsp->uns_lower_opencnt--;
  621 
  622 unionfs_close_abort:
  623         unionfs_tryrem_node_status(unp, unsp);
  624 
  625         if (locked != 0)
  626                 VOP_UNLOCK(ap->a_vp, 0, td);
  627 
  628         UNIONFS_INTERNAL_DEBUG("unionfs_close: leave (%d)\n", error);
  629 
  630         return (error);
  631 }
  632 
  633 /*
  634  * Check the access mode toward shadow file/dir.
  635  */
  636 static int
  637 unionfs_check_corrected_access(u_short mode,
  638                              struct vattr *va,
  639                              struct ucred *cred)
  640 {
  641         int             count;
  642         uid_t           uid;    /* upper side vnode's uid */
  643         gid_t           gid;    /* upper side vnode's gid */
  644         u_short         vmode;  /* upper side vnode's mode */
  645         gid_t          *gp;
  646         u_short         mask;
  647 
  648         mask = 0;
  649         uid = va->va_uid;
  650         gid = va->va_gid;
  651         vmode = va->va_mode;
  652 
  653         /* check owner */
  654         if (cred->cr_uid == uid) {
  655                 if (mode & VEXEC)
  656                         mask |= S_IXUSR;
  657                 if (mode & VREAD)
  658                         mask |= S_IRUSR;
  659                 if (mode & VWRITE)
  660                         mask |= S_IWUSR;
  661                 return ((vmode & mask) == mask ? 0 : EACCES);
  662         }
  663 
  664         /* check group */
  665         count = 0;
  666         gp = cred->cr_groups;
  667         for (; count < cred->cr_ngroups; count++, gp++) {
  668                 if (gid == *gp) {
  669                         if (mode & VEXEC)
  670                                 mask |= S_IXGRP;
  671                         if (mode & VREAD)
  672                                 mask |= S_IRGRP;
  673                         if (mode & VWRITE)
  674                                 mask |= S_IWGRP;
  675                         return ((vmode & mask) == mask ? 0 : EACCES);
  676                 }
  677         }
  678 
  679         /* check other */
  680         if (mode & VEXEC)
  681                 mask |= S_IXOTH;
  682         if (mode & VREAD)
  683                 mask |= S_IROTH;
  684         if (mode & VWRITE)
  685                 mask |= S_IWOTH;
  686 
  687         return ((vmode & mask) == mask ? 0 : EACCES);
  688 }
  689 
  690 static int
  691 unionfs_access(struct vop_access_args *ap)
  692 {
  693         struct unionfs_mount *ump;
  694         struct unionfs_node *unp;
  695         struct vnode   *uvp;
  696         struct vnode   *lvp;
  697         struct thread  *td;
  698         struct vattr    va;
  699         int             mode;
  700         int             error;
  701 
  702         UNIONFS_INTERNAL_DEBUG("unionfs_access: enter\n");
  703 
  704         KASSERT_UNIONFS_VNODE(ap->a_vp);
  705 
  706         ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount);
  707         unp = VTOUNIONFS(ap->a_vp);
  708         uvp = unp->un_uppervp;
  709         lvp = unp->un_lowervp;
  710         td = ap->a_td;
  711         mode = ap->a_mode;
  712         error = EACCES;
  713 
  714         if ((mode & VWRITE) &&
  715             (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)) {
  716                 switch (ap->a_vp->v_type) {
  717                 case VREG:
  718                 case VDIR:
  719                 case VLNK:
  720                         return (EROFS);
  721                 default:
  722                         break;
  723                 }
  724         }
  725 
  726         if (uvp != NULLVP) {
  727                 error = VOP_ACCESS(uvp, mode, ap->a_cred, td);
  728 
  729                 UNIONFS_INTERNAL_DEBUG("unionfs_access: leave (%d)\n", error);
  730 
  731                 return (error);
  732         }
  733 
  734         if (lvp != NULLVP) {
  735                 if (mode & VWRITE) {
  736                         if (ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY) {
  737                                 switch (ap->a_vp->v_type) {
  738                                 case VREG:
  739                                 case VDIR:
  740                                 case VLNK:
  741                                         return (EROFS);
  742                                 default:
  743                                         break;
  744                                 }
  745                         } else if (ap->a_vp->v_type == VREG || ap->a_vp->v_type == VDIR) {
  746                                 /* check shadow file/dir */
  747                                 if (ump->um_copymode != UNIONFS_TRANSPARENT) {
  748                                         error = unionfs_create_uppervattr(ump,
  749                                             lvp, &va, ap->a_cred, td);
  750                                         if (error != 0)
  751                                                 return (error);
  752 
  753                                         error = unionfs_check_corrected_access(
  754                                             mode, &va, ap->a_cred);
  755                                         if (error != 0)
  756                                                 return (error);
  757                                 }
  758                         }
  759                         mode &= ~VWRITE;
  760                         mode |= VREAD; /* will copy to upper */
  761                 }
  762                 error = VOP_ACCESS(lvp, mode, ap->a_cred, td);
  763         }
  764 
  765         UNIONFS_INTERNAL_DEBUG("unionfs_access: leave (%d)\n", error);
  766 
  767         return (error);
  768 }
  769 
  770 static int
  771 unionfs_getattr(struct vop_getattr_args *ap)
  772 {
  773         int             error;
  774         struct unionfs_node *unp;
  775         struct unionfs_mount *ump;
  776         struct vnode   *uvp;
  777         struct vnode   *lvp;
  778         struct thread  *td;
  779         struct vattr    va;
  780 
  781         UNIONFS_INTERNAL_DEBUG("unionfs_getattr: enter\n");
  782 
  783         KASSERT_UNIONFS_VNODE(ap->a_vp);
  784 
  785         unp = VTOUNIONFS(ap->a_vp);
  786         ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount);
  787         uvp = unp->un_uppervp;
  788         lvp = unp->un_lowervp;
  789         td = ap->a_td;
  790 
  791         if (uvp != NULLVP) {
  792                 if ((error = VOP_GETATTR(uvp, ap->a_vap, ap->a_cred, td)) == 0)
  793                         ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
  794 
  795                 UNIONFS_INTERNAL_DEBUG("unionfs_getattr: leave mode=%o, uid=%d, gid=%d (%d)\n",
  796                     ap->a_vap->va_mode, ap->a_vap->va_uid,
  797                     ap->a_vap->va_gid, error);
  798 
  799                 return (error);
  800         }
  801 
  802         error = VOP_GETATTR(lvp, ap->a_vap, ap->a_cred, td);
  803 
  804         if (error == 0 && !(ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY)) {
  805                 /* correct the attr toward shadow file/dir. */
  806                 if (ap->a_vp->v_type == VREG || ap->a_vp->v_type == VDIR) {
  807                         unionfs_create_uppervattr_core(ump, ap->a_vap, &va, td);
  808                         ap->a_vap->va_mode = va.va_mode;
  809                         ap->a_vap->va_uid = va.va_uid;
  810                         ap->a_vap->va_gid = va.va_gid;
  811                 }
  812         }
  813 
  814         if (error == 0)
  815                 ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
  816 
  817         UNIONFS_INTERNAL_DEBUG("unionfs_getattr: leave mode=%o, uid=%d, gid=%d (%d)\n",
  818             ap->a_vap->va_mode, ap->a_vap->va_uid, ap->a_vap->va_gid, error);
  819 
  820         return (error);
  821 }
  822 
  823 static int
  824 unionfs_setattr(struct vop_setattr_args *ap)
  825 {
  826         int             error;
  827         struct unionfs_node *unp;
  828         struct vnode   *uvp;
  829         struct vnode   *lvp;
  830         struct thread  *td;
  831         struct vattr   *vap;
  832 
  833         UNIONFS_INTERNAL_DEBUG("unionfs_setattr: enter\n");
  834 
  835         KASSERT_UNIONFS_VNODE(ap->a_vp);
  836 
  837         error = EROFS;
  838         unp = VTOUNIONFS(ap->a_vp);
  839         uvp = unp->un_uppervp;
  840         lvp = unp->un_lowervp;
  841         td = ap->a_td;
  842         vap = ap->a_vap;
  843 
  844         if ((ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) &&
  845             (vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
  846              vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
  847              vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL))
  848                 return (EROFS);
  849 
  850         if (uvp == NULLVP && lvp->v_type == VREG) {
  851                 error = unionfs_copyfile(unp, (vap->va_size != 0),
  852                     ap->a_cred, td);
  853                 if (error != 0)
  854                         return (error);
  855                 uvp = unp->un_uppervp;
  856         }
  857 
  858         if (uvp != NULLVP)
  859                 error = VOP_SETATTR(uvp, vap, ap->a_cred, td);
  860 
  861         UNIONFS_INTERNAL_DEBUG("unionfs_setattr: leave (%d)\n", error);
  862 
  863         return (error);
  864 }
  865 
  866 static int
  867 unionfs_read(struct vop_read_args *ap)
  868 {
  869         int             error;
  870         struct unionfs_node *unp;
  871         struct vnode   *tvp;
  872 
  873         /* UNIONFS_INTERNAL_DEBUG("unionfs_read: enter\n"); */
  874 
  875         KASSERT_UNIONFS_VNODE(ap->a_vp);
  876 
  877         unp = VTOUNIONFS(ap->a_vp);
  878         tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
  879 
  880         error = VOP_READ(tvp, ap->a_uio, ap->a_ioflag, ap->a_cred);
  881 
  882         /* UNIONFS_INTERNAL_DEBUG("unionfs_read: leave (%d)\n", error); */
  883 
  884         return (error);
  885 }
  886 
  887 static int
  888 unionfs_write(struct vop_write_args *ap)
  889 {
  890         int             error;
  891         struct unionfs_node *unp;
  892         struct vnode   *tvp;
  893 
  894         /* UNIONFS_INTERNAL_DEBUG("unionfs_write: enter\n"); */
  895 
  896         KASSERT_UNIONFS_VNODE(ap->a_vp);
  897 
  898         unp = VTOUNIONFS(ap->a_vp);
  899         tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
  900 
  901         error = VOP_WRITE(tvp, ap->a_uio, ap->a_ioflag, ap->a_cred);
  902 
  903         /* UNIONFS_INTERNAL_DEBUG("unionfs_write: leave (%d)\n", error); */
  904 
  905         return (error);
  906 }
  907 
  908 static int
  909 unionfs_lease(struct vop_lease_args *ap)
  910 {
  911         int error;
  912         struct unionfs_node *unp;
  913         struct vnode   *vp;
  914 
  915         UNIONFS_INTERNAL_DEBUG("unionfs_lease: enter\n");
  916 
  917         KASSERT_UNIONFS_VNODE(ap->a_vp);
  918 
  919         unp = VTOUNIONFS(ap->a_vp);
  920         vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
  921 
  922         error = VOP_LEASE(vp, ap->a_td, ap->a_cred, ap->a_flag);
  923 
  924         UNIONFS_INTERNAL_DEBUG("unionfs_lease: lease (%d)\n", error);
  925 
  926         return (error);
  927 }
  928 
  929 static int
  930 unionfs_ioctl(struct vop_ioctl_args *ap)
  931 {
  932         int error;
  933         struct unionfs_node *unp;
  934         struct unionfs_node_status *unsp;
  935         struct vnode   *ovp;
  936 
  937         UNIONFS_INTERNAL_DEBUG("unionfs_ioctl: enter\n");
  938 
  939         KASSERT_UNIONFS_VNODE(ap->a_vp);
  940 
  941         vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, ap->a_td);
  942         unp = VTOUNIONFS(ap->a_vp);
  943         unionfs_get_node_status(unp, ap->a_td, &unsp);
  944         ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp);
  945         unionfs_tryrem_node_status(unp, unsp);
  946         VOP_UNLOCK(ap->a_vp, 0, ap->a_td);
  947 
  948         if (ovp == NULLVP)
  949                 return (EBADF);
  950 
  951         error = VOP_IOCTL(ovp, ap->a_command, ap->a_data, ap->a_fflag,
  952             ap->a_cred, ap->a_td);
  953 
  954         UNIONFS_INTERNAL_DEBUG("unionfs_ioctl: lease (%d)\n", error);
  955 
  956         return (error);
  957 }
  958 
  959 static int
  960 unionfs_poll(struct vop_poll_args *ap)
  961 {
  962         struct unionfs_node *unp;
  963         struct unionfs_node_status *unsp;
  964         struct vnode   *ovp;
  965 
  966         KASSERT_UNIONFS_VNODE(ap->a_vp);
  967 
  968         vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, ap->a_td);
  969         unp = VTOUNIONFS(ap->a_vp);
  970         unionfs_get_node_status(unp, ap->a_td, &unsp);
  971         ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp);
  972         unionfs_tryrem_node_status(unp, unsp);
  973         VOP_UNLOCK(ap->a_vp, 0, ap->a_td);
  974 
  975         if (ovp == NULLVP)
  976                 return (EBADF);
  977 
  978         return (VOP_POLL(ovp, ap->a_events, ap->a_cred, ap->a_td));
  979 }
  980 
  981 static int
  982 unionfs_fsync(struct vop_fsync_args *ap)
  983 {
  984         struct unionfs_node *unp;
  985         struct unionfs_node_status *unsp;
  986         struct vnode   *ovp;
  987 
  988         KASSERT_UNIONFS_VNODE(ap->a_vp);
  989 
  990         unp = VTOUNIONFS(ap->a_vp);
  991         unionfs_get_node_status(unp, ap->a_td, &unsp);
  992         ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp);
  993         unionfs_tryrem_node_status(unp, unsp);
  994 
  995         if (ovp == NULLVP)
  996                 return (EBADF);
  997 
  998         return (VOP_FSYNC(ovp, ap->a_waitfor, ap->a_td));
  999 }
 1000 
 1001 static int
 1002 unionfs_remove(struct vop_remove_args *ap)
 1003 {
 1004         int             error;
 1005         char           *path;
 1006         struct unionfs_node *dunp;
 1007         struct unionfs_node *unp;
 1008         struct unionfs_mount *ump;
 1009         struct vnode   *udvp;
 1010         struct vnode   *uvp;
 1011         struct vnode   *lvp;
 1012         struct vnode   *vp;
 1013         struct componentname *cnp;
 1014         struct componentname cn;
 1015         struct thread  *td;
 1016 
 1017         UNIONFS_INTERNAL_DEBUG("unionfs_remove: enter\n");
 1018 
 1019         KASSERT_UNIONFS_VNODE(ap->a_dvp);
 1020 
 1021         error = 0;
 1022         dunp = VTOUNIONFS(ap->a_dvp);
 1023         udvp = dunp->un_uppervp;
 1024         cnp = ap->a_cnp;
 1025         td = curthread;
 1026 
 1027         if (ap->a_vp->v_op != &unionfs_vnodeops) {
 1028                 if (ap->a_vp->v_type != VSOCK)
 1029                         return (EINVAL);
 1030                 ump = NULL;
 1031                 vp = uvp = lvp = NULLVP;
 1032                 /* search vnode */
 1033                 VOP_UNLOCK(ap->a_vp, 0, td);
 1034                 error = unionfs_relookup(udvp, &vp, cnp, &cn, td,
 1035                     cnp->cn_nameptr, strlen(cnp->cn_nameptr), DELETE);
 1036                 if (error != 0 && error != ENOENT) {
 1037                         vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, td);
 1038                         return (error);
 1039                 }
 1040 
 1041                 if (error == 0 && vp == ap->a_vp) {
 1042                         /* target vnode in upper */
 1043                         uvp = vp;
 1044                         vrele(vp);
 1045                         path = NULL;
 1046                 } else {
 1047                         /* target vnode in lower */
 1048                         if (vp != NULLVP) {
 1049                                 if (udvp == vp)
 1050                                         vrele(vp);
 1051                                 else
 1052                                         vput(vp);
 1053                         }
 1054                         vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, td);
 1055                         lvp = ap->a_vp;
 1056                         path = ap->a_cnp->cn_nameptr;
 1057                 }
 1058         } else {
 1059                 ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount);
 1060                 unp = VTOUNIONFS(ap->a_vp);
 1061                 uvp = unp->un_uppervp;
 1062                 lvp = unp->un_lowervp;
 1063                 path = unp->un_path;
 1064         }
 1065 
 1066         if (udvp == NULLVP)
 1067                 return (EROFS);
 1068 
 1069         if (uvp != NULLVP) {
 1070                 /*
 1071                  * XXX: if the vnode type is VSOCK, it will create whiteout
 1072                  *      after remove.
 1073                  */
 1074                 if (ump == NULL || ump->um_whitemode == UNIONFS_WHITE_ALWAYS ||
 1075                     lvp != NULLVP)
 1076                         cnp->cn_flags |= DOWHITEOUT;
 1077                 error = VOP_REMOVE(udvp, uvp, cnp);
 1078         } else if (lvp != NULLVP)
 1079                 error = unionfs_mkwhiteout(udvp, cnp, td, path);
 1080 
 1081         UNIONFS_INTERNAL_DEBUG("unionfs_remove: leave (%d)\n", error);
 1082 
 1083         return (error);
 1084 }
 1085 
 1086 static int
 1087 unionfs_link(struct vop_link_args *ap)
 1088 {
 1089         int             error;
 1090         int             needrelookup;
 1091         struct unionfs_node *dunp;
 1092         struct unionfs_node *unp;
 1093         struct vnode   *udvp;
 1094         struct vnode   *uvp;
 1095         struct componentname *cnp;
 1096         struct thread  *td;
 1097 
 1098         UNIONFS_INTERNAL_DEBUG("unionfs_link: enter\n");
 1099 
 1100         KASSERT_UNIONFS_VNODE(ap->a_tdvp);
 1101         KASSERT_UNIONFS_VNODE(ap->a_vp);
 1102 
 1103         error = 0;
 1104         needrelookup = 0;
 1105         dunp = VTOUNIONFS(ap->a_tdvp);
 1106         unp = NULL;
 1107         udvp = dunp->un_uppervp;
 1108         uvp = NULLVP;
 1109         cnp = ap->a_cnp;
 1110         td = curthread;
 1111 
 1112         if (udvp == NULLVP)
 1113                 return (EROFS);
 1114 
 1115         if (ap->a_vp->v_op != &unionfs_vnodeops)
 1116                 uvp = ap->a_vp;
 1117         else {
 1118                 unp = VTOUNIONFS(ap->a_vp);
 1119 
 1120                 if (unp->un_uppervp == NULLVP) {
 1121                         if (ap->a_vp->v_type != VREG)
 1122                                 return (EOPNOTSUPP);
 1123 
 1124                         error = unionfs_copyfile(unp, 1, cnp->cn_cred, td);
 1125                         if (error != 0)
 1126                                 return (error);
 1127                         needrelookup = 1;
 1128                 }
 1129                 uvp = unp->un_uppervp;
 1130         }
 1131 
 1132         if (needrelookup != 0)
 1133                 error = unionfs_relookup_for_create(ap->a_tdvp, cnp, td);
 1134 
 1135         if (error == 0)
 1136                 error = VOP_LINK(udvp, uvp, cnp);
 1137 
 1138         UNIONFS_INTERNAL_DEBUG("unionfs_link: leave (%d)\n", error);
 1139 
 1140         return (error);
 1141 }
 1142 
 1143 static int
 1144 unionfs_rename(struct vop_rename_args *ap)
 1145 {
 1146         int             error;
 1147         struct vnode   *fdvp;
 1148         struct vnode   *fvp;
 1149         struct componentname *fcnp;
 1150         struct vnode   *tdvp;
 1151         struct vnode   *tvp;
 1152         struct componentname *tcnp;
 1153         struct vnode   *ltdvp;
 1154         struct vnode   *ltvp;
 1155         struct thread  *td;
 1156 
 1157         /* rename target vnodes */
 1158         struct vnode   *rfdvp;
 1159         struct vnode   *rfvp;
 1160         struct vnode   *rtdvp;
 1161         struct vnode   *rtvp;
 1162 
 1163         int             needrelookup;
 1164         struct unionfs_mount *ump;
 1165         struct unionfs_node *unp;
 1166 
 1167         UNIONFS_INTERNAL_DEBUG("unionfs_rename: enter\n");
 1168 
 1169         error = 0;
 1170         fdvp = ap->a_fdvp;
 1171         fvp = ap->a_fvp;
 1172         fcnp = ap->a_fcnp;
 1173         tdvp = ap->a_tdvp;
 1174         tvp = ap->a_tvp;
 1175         tcnp = ap->a_tcnp;
 1176         ltdvp = NULLVP;
 1177         ltvp = NULLVP;
 1178         td = curthread;
 1179         rfdvp = fdvp;
 1180         rfvp = fvp;
 1181         rtdvp = tdvp;
 1182         rtvp = tvp;
 1183         needrelookup = 0;
 1184 
 1185 #ifdef DIAGNOSTIC
 1186         if (!(fcnp->cn_flags & HASBUF) || !(tcnp->cn_flags & HASBUF))
 1187                 panic("unionfs_rename: no name");
 1188 #endif
 1189 
 1190         /* check for cross device rename */
 1191         if (fvp->v_mount != tdvp->v_mount ||
 1192             (tvp != NULLVP && fvp->v_mount != tvp->v_mount)) {
 1193                 if (fvp->v_op != &unionfs_vnodeops)
 1194                         error = ENODEV;
 1195                 else
 1196                         error = EXDEV;
 1197                 goto unionfs_rename_abort;
 1198         }
 1199 
 1200         /* Renaming a file to itself has no effect. */
 1201         if (fvp == tvp)
 1202                 goto unionfs_rename_abort;
 1203 
 1204         /*
 1205          * from/to vnode is unionfs node.
 1206          */
 1207 
 1208         KASSERT_UNIONFS_VNODE(fdvp);
 1209         KASSERT_UNIONFS_VNODE(fvp);
 1210         KASSERT_UNIONFS_VNODE(tdvp);
 1211         if (tvp != NULLVP)
 1212                 KASSERT_UNIONFS_VNODE(tvp);
 1213 
 1214         unp = VTOUNIONFS(fdvp);
 1215 #ifdef UNIONFS_IDBG_RENAME
 1216         UNIONFS_INTERNAL_DEBUG("fdvp=%p, ufdvp=%p, lfdvp=%p\n", fdvp, unp->un_uppervp, unp->un_lowervp);
 1217 #endif
 1218         if (unp->un_uppervp == NULLVP) {
 1219                 error = ENODEV;
 1220                 goto unionfs_rename_abort;
 1221         }
 1222         rfdvp = unp->un_uppervp;
 1223         vref(rfdvp);
 1224 
 1225         unp = VTOUNIONFS(fvp);
 1226 #ifdef UNIONFS_IDBG_RENAME
 1227         UNIONFS_INTERNAL_DEBUG("fvp=%p, ufvp=%p, lfvp=%p\n", fvp, unp->un_uppervp, unp->un_lowervp);
 1228 #endif
 1229         ump = MOUNTTOUNIONFSMOUNT(fvp->v_mount);
 1230         if (unp->un_uppervp == NULLVP) {
 1231                 switch (fvp->v_type) {
 1232                 case VREG:
 1233                         if ((error = vn_lock(fvp, LK_EXCLUSIVE, td)) != 0)
 1234                                 goto unionfs_rename_abort;
 1235                         error = unionfs_copyfile(unp, 1, fcnp->cn_cred, td);
 1236                         VOP_UNLOCK(fvp, 0, td);
 1237                         if (error != 0)
 1238                                 goto unionfs_rename_abort;
 1239                         break;
 1240                 case VDIR:
 1241                         if ((error = vn_lock(fvp, LK_EXCLUSIVE, td)) != 0)
 1242                                 goto unionfs_rename_abort;
 1243                         error = unionfs_mkshadowdir(ump, rfdvp, unp, fcnp, td);
 1244                         VOP_UNLOCK(fvp, 0, td);
 1245                         if (error != 0)
 1246                                 goto unionfs_rename_abort;
 1247                         break;
 1248                 default:
 1249                         error = ENODEV;
 1250                         goto unionfs_rename_abort;
 1251                 }
 1252 
 1253                 needrelookup = 1;
 1254         }
 1255 
 1256         if (unp->un_lowervp != NULLVP)
 1257                 fcnp->cn_flags |= DOWHITEOUT;
 1258         rfvp = unp->un_uppervp;
 1259         vref(rfvp);
 1260 
 1261         unp = VTOUNIONFS(tdvp);
 1262 #ifdef UNIONFS_IDBG_RENAME
 1263         UNIONFS_INTERNAL_DEBUG("tdvp=%p, utdvp=%p, ltdvp=%p\n", tdvp, unp->un_uppervp, unp->un_lowervp);
 1264 #endif
 1265         if (unp->un_uppervp == NULLVP) {
 1266                 error = ENODEV;
 1267                 goto unionfs_rename_abort;
 1268         }
 1269         rtdvp = unp->un_uppervp;
 1270         ltdvp = unp->un_lowervp;
 1271         vref(rtdvp);
 1272 
 1273         if (tdvp == tvp) {
 1274                 rtvp = rtdvp;
 1275                 vref(rtvp);
 1276         } else if (tvp != NULLVP) {
 1277                 unp = VTOUNIONFS(tvp);
 1278 #ifdef UNIONFS_IDBG_RENAME
 1279                 UNIONFS_INTERNAL_DEBUG("tvp=%p, utvp=%p, ltvp=%p\n", tvp, unp->un_uppervp, unp->un_lowervp);
 1280 #endif
 1281                 if (unp->un_uppervp == NULLVP)
 1282                         rtvp = NULLVP;
 1283                 else {
 1284                         if (tvp->v_type == VDIR) {
 1285                                 error = EINVAL;
 1286                                 goto unionfs_rename_abort;
 1287                         }
 1288                         rtvp = unp->un_uppervp;
 1289                         ltvp = unp->un_lowervp;
 1290                         vref(rtvp);
 1291                 }
 1292         }
 1293 
 1294         if (rfvp == rtvp)
 1295                 goto unionfs_rename_abort;
 1296 
 1297         if (needrelookup != 0) {
 1298                 if ((error = vn_lock(fdvp, LK_EXCLUSIVE, td)) != 0)
 1299                         goto unionfs_rename_abort;
 1300                 error = unionfs_relookup_for_delete(fdvp, fcnp, td);
 1301                 VOP_UNLOCK(fdvp, 0, td);
 1302                 if (error != 0)
 1303                         goto unionfs_rename_abort;
 1304 
 1305                 /* Locke of tvp is canceled in order to avoid recursive lock. */
 1306                 if (tvp != NULLVP && tvp != tdvp)
 1307                         VOP_UNLOCK(tvp, 0, td);
 1308                 error = unionfs_relookup_for_rename(tdvp, tcnp, td);
 1309                 if (tvp != NULLVP && tvp != tdvp)
 1310                         vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY, td);
 1311                 if (error != 0)
 1312                         goto unionfs_rename_abort;
 1313         }
 1314 
 1315         error = VOP_RENAME(rfdvp, rfvp, fcnp, rtdvp, rtvp, tcnp);
 1316 
 1317         if (error == 0) {
 1318                 if (rtvp != NULLVP && rtvp->v_type == VDIR)
 1319                         cache_purge(tdvp);
 1320                 if (fvp->v_type == VDIR && fdvp != tdvp)
 1321                         cache_purge(fdvp);
 1322         }
 1323 
 1324         if (ltdvp != NULLVP)
 1325                 VOP_UNLOCK(ltdvp, 0, td);
 1326         if (tdvp != rtdvp)
 1327                 vrele(tdvp);
 1328         if (ltvp != NULLVP)
 1329                 VOP_UNLOCK(ltvp, 0, td);
 1330         if (tvp != rtvp && tvp != NULLVP) {
 1331                 if (rtvp == NULLVP)
 1332                         vput(tvp);
 1333                 else
 1334                         vrele(tvp);
 1335         }
 1336         if (fdvp != rfdvp)
 1337                 vrele(fdvp);
 1338         if (fvp != rfvp)
 1339                 vrele(fvp);
 1340 
 1341         UNIONFS_INTERNAL_DEBUG("unionfs_rename: leave (%d)\n", error);
 1342 
 1343         return (error);
 1344 
 1345 unionfs_rename_abort:
 1346         vput(tdvp);
 1347         if (tdvp != rtdvp)
 1348                 vrele(rtdvp);
 1349         if (tvp != NULLVP) {
 1350                 if (tdvp != tvp)
 1351                         vput(tvp);
 1352                 else
 1353                         vrele(tvp);
 1354         }
 1355         if (tvp != rtvp && rtvp != NULLVP)
 1356                 vrele(rtvp);
 1357         if (fdvp != rfdvp)
 1358                 vrele(rfdvp);
 1359         if (fvp != rfvp)
 1360                 vrele(rfvp);
 1361         vrele(fdvp);
 1362         vrele(fvp);
 1363 
 1364         UNIONFS_INTERNAL_DEBUG("unionfs_rename: leave (%d)\n", error);
 1365 
 1366         return (error);
 1367 }
 1368 
 1369 static int
 1370 unionfs_mkdir(struct vop_mkdir_args *ap)
 1371 {
 1372         int             error;
 1373         int             lkflags;
 1374         struct unionfs_node *dunp;
 1375         struct componentname *cnp;
 1376         struct thread  *td;
 1377         struct vnode   *udvp;
 1378         struct vnode   *uvp;
 1379         struct vattr    va;
 1380 
 1381         UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: enter\n");
 1382 
 1383         KASSERT_UNIONFS_VNODE(ap->a_dvp);
 1384 
 1385         error = EROFS;
 1386         dunp = VTOUNIONFS(ap->a_dvp);
 1387         cnp = ap->a_cnp;
 1388         lkflags = cnp->cn_lkflags;
 1389         td = curthread;
 1390         udvp = dunp->un_uppervp;
 1391 
 1392         if (udvp != NULLVP) {
 1393                 /* check opaque */
 1394                 if (!(cnp->cn_flags & ISWHITEOUT)) {
 1395                         error = VOP_GETATTR(udvp, &va, cnp->cn_cred, td);
 1396                         if (error != 0)
 1397                                 return (error);
 1398                         if (va.va_flags & OPAQUE) 
 1399                                 cnp->cn_flags |= ISWHITEOUT;
 1400                 }
 1401 
 1402                 if ((error = VOP_MKDIR(udvp, &uvp, cnp, ap->a_vap)) == 0) {
 1403                         VOP_UNLOCK(uvp, 0, td);
 1404                         cnp->cn_lkflags = LK_EXCLUSIVE;
 1405                         error = unionfs_nodeget(ap->a_dvp->v_mount, uvp, NULLVP,
 1406                             ap->a_dvp, ap->a_vpp, cnp, td);
 1407                         cnp->cn_lkflags = lkflags;
 1408                         vrele(uvp);
 1409                 }
 1410         }
 1411 
 1412         UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: leave (%d)\n", error);
 1413 
 1414         return (error);
 1415 }
 1416 
 1417 static int
 1418 unionfs_rmdir(struct vop_rmdir_args *ap)
 1419 {
 1420         int             error;
 1421         struct unionfs_node *dunp;
 1422         struct unionfs_node *unp;
 1423         struct unionfs_mount *ump;
 1424         struct componentname *cnp;
 1425         struct thread  *td;
 1426         struct vnode   *udvp;
 1427         struct vnode   *uvp;
 1428         struct vnode   *lvp;
 1429 
 1430         UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: enter\n");
 1431 
 1432         KASSERT_UNIONFS_VNODE(ap->a_dvp);
 1433         KASSERT_UNIONFS_VNODE(ap->a_vp);
 1434 
 1435         error = 0;
 1436         dunp = VTOUNIONFS(ap->a_dvp);
 1437         unp = VTOUNIONFS(ap->a_vp);
 1438         cnp = ap->a_cnp;
 1439         td = curthread;
 1440         udvp = dunp->un_uppervp;
 1441         uvp = unp->un_uppervp;
 1442         lvp = unp->un_lowervp;
 1443 
 1444         if (udvp == NULLVP)
 1445                 return (EROFS);
 1446 
 1447         if (udvp == uvp)
 1448                 return (EOPNOTSUPP);
 1449 
 1450         if (uvp != NULLVP) {
 1451                 if (lvp != NULLVP) {
 1452                         error = unionfs_check_rmdir(ap->a_vp, cnp->cn_cred, td);
 1453                         if (error != 0)
 1454                                 return (error);
 1455                 }
 1456                 ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount);
 1457                 if (ump->um_whitemode == UNIONFS_WHITE_ALWAYS || lvp != NULLVP)
 1458                         cnp->cn_flags |= DOWHITEOUT;
 1459                 error = VOP_RMDIR(udvp, uvp, cnp);
 1460         }
 1461         else if (lvp != NULLVP)
 1462                 error = unionfs_mkwhiteout(udvp, cnp, td, unp->un_path);
 1463 
 1464         if (error == 0) {
 1465                 cache_purge(ap->a_dvp);
 1466                 cache_purge(ap->a_vp);
 1467         }
 1468 
 1469         UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: leave (%d)\n", error);
 1470 
 1471         return (error);
 1472 }
 1473 
 1474 static int
 1475 unionfs_symlink(struct vop_symlink_args *ap)
 1476 {
 1477         int             error;
 1478         int             lkflags;
 1479         struct unionfs_node *dunp;
 1480         struct componentname *cnp;
 1481         struct thread  *td;
 1482         struct vnode   *udvp;
 1483         struct vnode   *uvp;
 1484 
 1485         UNIONFS_INTERNAL_DEBUG("unionfs_symlink: enter\n");
 1486 
 1487         KASSERT_UNIONFS_VNODE(ap->a_dvp);
 1488 
 1489         error = EROFS;
 1490         dunp = VTOUNIONFS(ap->a_dvp);
 1491         cnp = ap->a_cnp;
 1492         lkflags = cnp->cn_lkflags;
 1493         td = curthread;
 1494         udvp = dunp->un_uppervp;
 1495 
 1496         if (udvp != NULLVP) {
 1497                 error = VOP_SYMLINK(udvp, &uvp, cnp, ap->a_vap, ap->a_target);
 1498                 if (error == 0) {
 1499                         VOP_UNLOCK(uvp, 0, td);
 1500                         cnp->cn_lkflags = LK_EXCLUSIVE;
 1501                         error = unionfs_nodeget(ap->a_dvp->v_mount, uvp, NULLVP,
 1502                             ap->a_dvp, ap->a_vpp, cnp, td);
 1503                         cnp->cn_lkflags = lkflags;
 1504                         vrele(uvp);
 1505                 }
 1506         }
 1507 
 1508         UNIONFS_INTERNAL_DEBUG("unionfs_symlink: leave (%d)\n", error);
 1509 
 1510         return (error);
 1511 }
 1512 
 1513 static int
 1514 unionfs_readdir(struct vop_readdir_args *ap)
 1515 {
 1516         int             error;
 1517         int             eofflag;
 1518         int             locked;
 1519         struct unionfs_node *unp;
 1520         struct unionfs_node_status *unsp;
 1521         struct uio     *uio;
 1522         struct vnode   *uvp;
 1523         struct vnode   *lvp;
 1524         struct thread  *td;
 1525         struct vattr    va;
 1526 
 1527         int             ncookies_bk;
 1528         u_long         *cookies_bk;
 1529 
 1530         UNIONFS_INTERNAL_DEBUG("unionfs_readdir: enter\n");
 1531 
 1532         KASSERT_UNIONFS_VNODE(ap->a_vp);
 1533 
 1534         error = 0;
 1535         eofflag = 0;
 1536         locked = 0;
 1537         unp = VTOUNIONFS(ap->a_vp);
 1538         uio = ap->a_uio;
 1539         uvp = unp->un_uppervp;
 1540         lvp = unp->un_lowervp;
 1541         td = uio->uio_td;
 1542         ncookies_bk = 0;
 1543         cookies_bk = NULL;
 1544 
 1545         if (ap->a_vp->v_type != VDIR)
 1546                 return (ENOTDIR);
 1547 
 1548         /* check opaque */
 1549         if (uvp != NULLVP && lvp != NULLVP) {
 1550                 if ((error = VOP_GETATTR(uvp, &va, ap->a_cred, td)) != 0)
 1551                         goto unionfs_readdir_exit;
 1552                 if (va.va_flags & OPAQUE)
 1553                         lvp = NULLVP;
 1554         }
 1555 
 1556         /* check the open count. unionfs needs to open before readdir. */
 1557         if (VOP_ISLOCKED(ap->a_vp, td) != LK_EXCLUSIVE) {
 1558                 vn_lock(ap->a_vp, LK_UPGRADE | LK_RETRY, td);
 1559                 locked = 1;
 1560         }
 1561         unionfs_get_node_status(unp, td, &unsp);
 1562         if ((uvp != NULLVP && unsp->uns_upper_opencnt <= 0) ||
 1563             (lvp != NULLVP && unsp->uns_lower_opencnt <= 0)) {
 1564                 unionfs_tryrem_node_status(unp, unsp);
 1565                 error = EBADF;
 1566         }
 1567         if (locked == 1)
 1568                 vn_lock(ap->a_vp, LK_DOWNGRADE | LK_RETRY, td);
 1569         if (error != 0)
 1570                 goto unionfs_readdir_exit;
 1571 
 1572         /* upper only */
 1573         if (uvp != NULLVP && lvp == NULLVP) {
 1574                 error = VOP_READDIR(uvp, uio, ap->a_cred, ap->a_eofflag,
 1575                     ap->a_ncookies, ap->a_cookies);
 1576                 unsp->uns_readdir_status = 0;
 1577 
 1578                 goto unionfs_readdir_exit;
 1579         }
 1580 
 1581         /* lower only */
 1582         if (uvp == NULLVP && lvp != NULLVP) {
 1583                 error = VOP_READDIR(lvp, uio, ap->a_cred, ap->a_eofflag,
 1584                     ap->a_ncookies, ap->a_cookies);
 1585                 unsp->uns_readdir_status = 2;
 1586 
 1587                 goto unionfs_readdir_exit;
 1588         }
 1589 
 1590         /*
 1591          * readdir upper and lower
 1592          */
 1593         KASSERT(uvp != NULLVP, ("unionfs_readdir: null upper vp"));
 1594         KASSERT(lvp != NULLVP, ("unionfs_readdir: null lower vp"));
 1595         if (uio->uio_offset == 0)
 1596                 unsp->uns_readdir_status = 0;
 1597 
 1598         if (unsp->uns_readdir_status == 0) {
 1599                 /* read upper */
 1600                 error = VOP_READDIR(uvp, uio, ap->a_cred, &eofflag,
 1601                                     ap->a_ncookies, ap->a_cookies);
 1602 
 1603                 if (error != 0 || eofflag == 0)
 1604                         goto unionfs_readdir_exit;
 1605                 unsp->uns_readdir_status = 1;
 1606 
 1607                 /*
 1608                  * ufs(and other fs) needs size of uio_resid larger than
 1609                  * DIRBLKSIZ.
 1610                  * size of DIRBLKSIZ equals DEV_BSIZE.
 1611                  * (see: ufs/ufs/ufs_vnops.c ufs_readdir func , ufs/ufs/dir.h)
 1612                  */
 1613                 if (uio->uio_resid <= (uio->uio_resid & (DEV_BSIZE -1)))
 1614                         goto unionfs_readdir_exit;
 1615 
 1616                 /*
 1617                  * backup cookies
 1618                  * It prepares to readdir in lower.
 1619                  */
 1620                 if (ap->a_ncookies != NULL) {
 1621                         ncookies_bk = *(ap->a_ncookies);
 1622                         *(ap->a_ncookies) = 0;
 1623                 }
 1624                 if (ap->a_cookies != NULL) {
 1625                         cookies_bk = *(ap->a_cookies);
 1626                         *(ap->a_cookies) = NULL;
 1627                 }
 1628         }
 1629 
 1630         /* initialize for readdir in lower */
 1631         if (unsp->uns_readdir_status == 1) {
 1632                 unsp->uns_readdir_status = 2;
 1633                 uio->uio_offset = 0;
 1634         }
 1635 
 1636         if (lvp == NULLVP) {
 1637                 error = EBADF;
 1638                 goto unionfs_readdir_exit;
 1639         }
 1640         /* read lower */
 1641         error = VOP_READDIR(lvp, uio, ap->a_cred, ap->a_eofflag,
 1642                             ap->a_ncookies, ap->a_cookies);
 1643 
 1644         if (cookies_bk != NULL) {
 1645                 /* merge cookies */
 1646                 int             size;
 1647                 u_long         *newcookies, *pos;
 1648 
 1649                 size = *(ap->a_ncookies) + ncookies_bk;
 1650                 newcookies = (u_long *) malloc(size * sizeof(u_long),
 1651                     M_TEMP, M_WAITOK);
 1652                 pos = newcookies;
 1653 
 1654                 memcpy(pos, cookies_bk, ncookies_bk * sizeof(u_long));
 1655                 pos += ncookies_bk * sizeof(u_long);
 1656                 memcpy(pos, *(ap->a_cookies), *(ap->a_ncookies) * sizeof(u_long));
 1657                 free(cookies_bk, M_TEMP);
 1658                 free(*(ap->a_cookies), M_TEMP);
 1659                 *(ap->a_ncookies) = size;
 1660                 *(ap->a_cookies) = newcookies;
 1661         }
 1662 
 1663 unionfs_readdir_exit:
 1664         if (error != 0 && ap->a_eofflag != NULL)
 1665                 *(ap->a_eofflag) = 1;
 1666 
 1667         UNIONFS_INTERNAL_DEBUG("unionfs_readdir: leave (%d)\n", error);
 1668 
 1669         return (error);
 1670 }
 1671 
 1672 static int
 1673 unionfs_readlink(struct vop_readlink_args *ap)
 1674 {
 1675         int error;
 1676         struct unionfs_node *unp;
 1677         struct vnode   *vp;
 1678 
 1679         UNIONFS_INTERNAL_DEBUG("unionfs_readlink: enter\n");
 1680 
 1681         KASSERT_UNIONFS_VNODE(ap->a_vp);
 1682 
 1683         unp = VTOUNIONFS(ap->a_vp);
 1684         vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
 1685 
 1686         error = VOP_READLINK(vp, ap->a_uio, ap->a_cred);
 1687 
 1688         UNIONFS_INTERNAL_DEBUG("unionfs_readlink: leave (%d)\n", error);
 1689 
 1690         return (error);
 1691 }
 1692 
 1693 static int
 1694 unionfs_getwritemount(struct vop_getwritemount_args *ap)
 1695 {
 1696         int             error;
 1697         struct vnode   *uvp;
 1698         struct vnode   *vp;
 1699 
 1700         UNIONFS_INTERNAL_DEBUG("unionfs_getwritemount: enter\n");
 1701 
 1702         error = 0;
 1703         vp = ap->a_vp;
 1704 
 1705         if (vp == NULLVP || (vp->v_mount->mnt_flag & MNT_RDONLY))
 1706                 return (EACCES);
 1707 
 1708         KASSERT_UNIONFS_VNODE(vp);
 1709 
 1710         uvp = UNIONFSVPTOUPPERVP(vp);
 1711         if (uvp == NULLVP && VREG == vp->v_type)
 1712                 uvp = UNIONFSVPTOUPPERVP(VTOUNIONFS(vp)->un_dvp);
 1713 
 1714         if (uvp != NULLVP)
 1715                 error = VOP_GETWRITEMOUNT(uvp, ap->a_mpp);
 1716         else {
 1717                 VI_LOCK(vp);
 1718                 if (vp->v_iflag & VI_FREE)
 1719                         error = EOPNOTSUPP;
 1720                 else
 1721                         error = EACCES;
 1722                 VI_UNLOCK(vp);
 1723         }
 1724 
 1725         UNIONFS_INTERNAL_DEBUG("unionfs_getwritemount: leave (%d)\n", error);
 1726 
 1727         return (error);
 1728 }
 1729 
 1730 static int
 1731 unionfs_inactive(struct vop_inactive_args *ap)
 1732 {
 1733         ap->a_vp->v_object = NULL;
 1734         vrecycle(ap->a_vp, ap->a_td);
 1735         return (0);
 1736 }
 1737 
 1738 static int
 1739 unionfs_reclaim(struct vop_reclaim_args *ap)
 1740 {
 1741         /* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: enter\n"); */
 1742 
 1743         unionfs_noderem(ap->a_vp, ap->a_td);
 1744 
 1745         /* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: leave\n"); */
 1746 
 1747         return (0);
 1748 }
 1749 
 1750 static int
 1751 unionfs_print(struct vop_print_args *ap)
 1752 {
 1753         struct unionfs_node *unp;
 1754         /* struct unionfs_node_status *unsp; */
 1755 
 1756         unp = VTOUNIONFS(ap->a_vp);
 1757         /* unionfs_get_node_status(unp, curthread, &unsp); */
 1758 
 1759         printf("unionfs_vp=%p, uppervp=%p, lowervp=%p\n",
 1760             ap->a_vp, unp->un_uppervp, unp->un_lowervp);
 1761         /*
 1762         printf("unionfs opencnt: uppervp=%d, lowervp=%d\n",
 1763             unsp->uns_upper_opencnt, unsp->uns_lower_opencnt);
 1764         */
 1765 
 1766         if (unp->un_uppervp != NULLVP)
 1767                 vprint("unionfs: upper", unp->un_uppervp);
 1768         if (unp->un_lowervp != NULLVP)
 1769                 vprint("unionfs: lower", unp->un_lowervp);
 1770 
 1771         return (0);
 1772 }
 1773 
 1774 static int
 1775 unionfs_get_llt_revlock(int flags)
 1776 {
 1777         int count;
 1778 
 1779         flags &= LK_TYPE_MASK;
 1780         for (count = 0; un_llt[count].lock != 0; count++) {
 1781                 if (flags == un_llt[count].lock) {
 1782                         return un_llt[count].revlock;
 1783                 }
 1784         }
 1785 
 1786         return 0;
 1787 }
 1788 
 1789 static int
 1790 unionfs_lock(struct vop_lock1_args *ap)
 1791 {
 1792         int             error;
 1793         int             flags;
 1794         int             revlock;
 1795         int             uhold;
 1796         struct mount   *mp;
 1797         struct unionfs_mount *ump;
 1798         struct unionfs_node *unp;
 1799         struct vnode   *vp;
 1800         struct vnode   *uvp;
 1801         struct vnode   *lvp;
 1802         struct thread  *td;
 1803 
 1804         KASSERT_UNIONFS_VNODE(ap->a_vp);
 1805 
 1806         error = 0;
 1807         uhold = 0;
 1808         flags = ap->a_flags;
 1809         vp = ap->a_vp;
 1810         td = ap->a_td;
 1811 
 1812         if (LK_RELEASE == (flags & LK_TYPE_MASK) || !(flags & LK_TYPE_MASK))
 1813                 return (VOP_UNLOCK(vp, flags, td));
 1814 
 1815         if ((revlock = unionfs_get_llt_revlock(flags)) == 0)
 1816                 panic("unknown lock type: 0x%x", flags & LK_TYPE_MASK);
 1817 
 1818         if ((flags & LK_INTERLOCK) == 0)
 1819                 VI_LOCK(vp);
 1820 
 1821         mp = vp->v_mount;
 1822         if (mp == NULL)
 1823                 goto unionfs_lock_null_vnode;
 1824 
 1825         ump = MOUNTTOUNIONFSMOUNT(mp);
 1826         unp = VTOUNIONFS(vp);
 1827         if (ump == NULL || unp == NULL)
 1828                 goto unionfs_lock_null_vnode;
 1829         lvp = unp->un_lowervp;
 1830         uvp = unp->un_uppervp;
 1831 
 1832         if ((mp->mnt_kern_flag & MNTK_MPSAFE) != 0 &&
 1833             (vp->v_iflag & VI_OWEINACT) != 0)
 1834                 flags |= LK_NOWAIT;
 1835 
 1836         /*
 1837          * Sometimes, lower or upper is already exclusive locked.
 1838          * (ex. vfs_domount: mounted vnode is already locked.)
 1839          */
 1840         if ((flags & LK_TYPE_MASK) == LK_EXCLUSIVE &&
 1841             vp == ump->um_rootvp)
 1842                 flags |= LK_CANRECURSE;
 1843 
 1844         if (lvp != NULLVP) {
 1845                 VI_LOCK_FLAGS(lvp, MTX_DUPOK);
 1846                 flags |= LK_INTERLOCK;
 1847                 vholdl(lvp);
 1848 
 1849                 VI_UNLOCK(vp);
 1850                 ap->a_flags &= ~LK_INTERLOCK;
 1851 
 1852                 error = VOP_LOCK(lvp, flags, td);
 1853 
 1854                 VI_LOCK(vp);
 1855                 unp = VTOUNIONFS(vp);
 1856                 if (unp == NULL) {
 1857                         VI_UNLOCK(vp);
 1858                         if (error == 0)
 1859                                 VOP_UNLOCK(lvp, 0, td);
 1860                         vdrop(lvp);
 1861                         return (vop_stdlock(ap));
 1862                 }
 1863         }
 1864 
 1865         if (error == 0 && uvp != NULLVP) {
 1866                 VI_LOCK_FLAGS(uvp, MTX_DUPOK);
 1867                 flags |= LK_INTERLOCK;
 1868                 vholdl(uvp);
 1869                 uhold = 1;
 1870 
 1871                 VI_UNLOCK(vp);
 1872                 ap->a_flags &= ~LK_INTERLOCK;
 1873 
 1874                 error = VOP_LOCK(uvp, flags, td);
 1875 
 1876                 VI_LOCK(vp);
 1877                 unp = VTOUNIONFS(vp);
 1878                 if (unp == NULL) {
 1879                         VI_UNLOCK(vp);
 1880                         if (error == 0) {
 1881                                 VOP_UNLOCK(uvp, 0, td);
 1882                                 if (lvp != NULLVP)
 1883                                         VOP_UNLOCK(lvp, 0, td);
 1884                         }
 1885                         if (lvp != NULLVP)
 1886                                 vdrop(lvp);
 1887                         vdrop(uvp);
 1888                         return (vop_stdlock(ap));
 1889                 }
 1890 
 1891                 if (error != 0 && lvp != NULLVP) {
 1892                         VI_UNLOCK(vp);
 1893                         if ((revlock & LK_TYPE_MASK) == LK_RELEASE)
 1894                                 VOP_UNLOCK(lvp, revlock, td);
 1895                         else
 1896                                 vn_lock(lvp, revlock | LK_RETRY, td);
 1897                         goto unionfs_lock_abort;
 1898                 }
 1899         }
 1900 
 1901         VI_UNLOCK(vp);
 1902 unionfs_lock_abort:
 1903         if (lvp != NULLVP)
 1904                 vdrop(lvp);
 1905         if (uhold != 0)
 1906                 vdrop(uvp);
 1907 
 1908         return (error);
 1909 
 1910 unionfs_lock_null_vnode:
 1911         ap->a_flags |= LK_INTERLOCK;
 1912         return (vop_stdlock(ap));
 1913 }
 1914 
 1915 static int
 1916 unionfs_unlock(struct vop_unlock_args *ap)
 1917 {
 1918         int             error;
 1919         int             flags;
 1920         int             mtxlkflag;
 1921         int             uhold;
 1922         struct vnode   *vp;
 1923         struct vnode   *lvp;
 1924         struct vnode   *uvp;
 1925         struct unionfs_node *unp;
 1926 
 1927         KASSERT_UNIONFS_VNODE(ap->a_vp);
 1928 
 1929         error = 0;
 1930         mtxlkflag = 0;
 1931         uhold = 0;
 1932         flags = ap->a_flags | LK_RELEASE;
 1933         vp = ap->a_vp;
 1934 
 1935         if ((flags & LK_INTERLOCK) != 0)
 1936                 mtxlkflag = 1;
 1937         else if (mtx_owned(VI_MTX(vp)) == 0) {
 1938                 VI_LOCK(vp);
 1939                 mtxlkflag = 2;
 1940         }
 1941 
 1942         unp = VTOUNIONFS(vp);
 1943         if (unp == NULL)
 1944                 goto unionfs_unlock_null_vnode;
 1945         lvp = unp->un_lowervp;
 1946         uvp = unp->un_uppervp;
 1947 
 1948         if (lvp != NULLVP) {
 1949                 VI_LOCK_FLAGS(lvp, MTX_DUPOK);
 1950                 flags |= LK_INTERLOCK;
 1951                 vholdl(lvp);
 1952 
 1953                 VI_UNLOCK(vp);
 1954                 ap->a_flags &= ~LK_INTERLOCK;
 1955 
 1956                 error = VOP_UNLOCK(lvp, flags, ap->a_td);
 1957 
 1958                 VI_LOCK(vp);
 1959         }
 1960 
 1961         if (error == 0 && uvp != NULLVP) {
 1962                 VI_LOCK_FLAGS(uvp, MTX_DUPOK);
 1963                 flags |= LK_INTERLOCK;
 1964                 vholdl(uvp);
 1965                 uhold = 1;
 1966 
 1967                 VI_UNLOCK(vp);
 1968                 ap->a_flags &= ~LK_INTERLOCK;
 1969 
 1970                 error = VOP_UNLOCK(uvp, flags, ap->a_td);
 1971 
 1972                 VI_LOCK(vp);
 1973         }
 1974 
 1975         VI_UNLOCK(vp);
 1976         if (lvp != NULLVP)
 1977                 vdrop(lvp);
 1978         if (uhold != 0)
 1979                 vdrop(uvp);
 1980         if (mtxlkflag == 0)
 1981                 VI_LOCK(vp);
 1982 
 1983         return error;
 1984 
 1985 unionfs_unlock_null_vnode:
 1986         if (mtxlkflag == 2)
 1987                 VI_UNLOCK(vp);
 1988         return (vop_stdunlock(ap));
 1989 }
 1990 
 1991 static int
 1992 unionfs_pathconf(struct vop_pathconf_args *ap)
 1993 {
 1994         struct unionfs_node *unp;
 1995         struct vnode   *vp;
 1996 
 1997         KASSERT_UNIONFS_VNODE(ap->a_vp);
 1998 
 1999         unp = VTOUNIONFS(ap->a_vp);
 2000         vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
 2001 
 2002         return (VOP_PATHCONF(vp, ap->a_name, ap->a_retval));
 2003 }
 2004 
 2005 static int
 2006 unionfs_advlock(struct vop_advlock_args *ap)
 2007 {
 2008         int error;
 2009         struct unionfs_node *unp;
 2010         struct unionfs_node_status *unsp;
 2011         struct vnode   *vp;
 2012         struct vnode   *uvp;
 2013         struct thread  *td;
 2014 
 2015         UNIONFS_INTERNAL_DEBUG("unionfs_advlock: enter\n");
 2016 
 2017         KASSERT_UNIONFS_VNODE(ap->a_vp);
 2018 
 2019         vp = ap->a_vp;
 2020         td = curthread;
 2021 
 2022         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
 2023 
 2024         unp = VTOUNIONFS(ap->a_vp);
 2025         uvp = unp->un_uppervp;
 2026 
 2027         if (uvp == NULLVP) {
 2028                 error = unionfs_copyfile(unp, 1, td->td_ucred, td);
 2029                 if (error != 0)
 2030                         goto unionfs_advlock_abort;
 2031                 uvp = unp->un_uppervp;
 2032 
 2033                 unionfs_get_node_status(unp, td, &unsp);
 2034                 if (unsp->uns_lower_opencnt > 0) {
 2035                         /* try reopen the vnode */
 2036                         error = VOP_OPEN(uvp, unsp->uns_lower_openmode,
 2037                                 td->td_ucred, td, NULL);
 2038                         if (error)
 2039                                 goto unionfs_advlock_abort;
 2040                         unsp->uns_upper_opencnt++;
 2041                         VOP_CLOSE(unp->un_lowervp, unsp->uns_lower_openmode, td->td_ucred, td);
 2042                         unsp->uns_lower_opencnt--;
 2043                 } else
 2044                         unionfs_tryrem_node_status(unp, unsp);
 2045         }
 2046 
 2047         VOP_UNLOCK(vp, 0, td);
 2048 
 2049         error = VOP_ADVLOCK(uvp, ap->a_id, ap->a_op, ap->a_fl, ap->a_flags);
 2050 
 2051         UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error);
 2052 
 2053         return error;
 2054 
 2055 unionfs_advlock_abort:
 2056         VOP_UNLOCK(vp, 0, td);
 2057 
 2058         UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error);
 2059 
 2060         return error;
 2061 }
 2062 
 2063 static int
 2064 unionfs_strategy(struct vop_strategy_args *ap)
 2065 {
 2066         struct unionfs_node *unp;
 2067         struct vnode   *vp;
 2068 
 2069         KASSERT_UNIONFS_VNODE(ap->a_vp);
 2070 
 2071         unp = VTOUNIONFS(ap->a_vp);
 2072         vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
 2073 
 2074 #ifdef DIAGNOSTIC
 2075         if (vp == NULLVP)
 2076                 panic("unionfs_strategy: nullvp");
 2077 
 2078         if (ap->a_bp->b_iocmd == BIO_WRITE && vp == unp->un_lowervp)
 2079                 panic("unionfs_strategy: writing to lowervp");
 2080 #endif
 2081 
 2082         return (VOP_STRATEGY(vp, ap->a_bp));
 2083 }
 2084 
 2085 static int
 2086 unionfs_getacl(struct vop_getacl_args *ap)
 2087 {
 2088         int             error;
 2089         struct unionfs_node *unp;
 2090         struct vnode   *vp;
 2091 
 2092         KASSERT_UNIONFS_VNODE(ap->a_vp);
 2093 
 2094         unp = VTOUNIONFS(ap->a_vp);
 2095         vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
 2096 
 2097         UNIONFS_INTERNAL_DEBUG("unionfs_getacl: enter\n");
 2098 
 2099         error = VOP_GETACL(vp, ap->a_type, ap->a_aclp, ap->a_cred, ap->a_td);
 2100 
 2101         UNIONFS_INTERNAL_DEBUG("unionfs_getacl: leave (%d)\n", error);
 2102 
 2103         return (error);
 2104 }
 2105 
 2106 static int
 2107 unionfs_setacl(struct vop_setacl_args *ap)
 2108 {
 2109         int             error;
 2110         struct unionfs_node *unp;
 2111         struct vnode   *uvp;
 2112         struct vnode   *lvp;
 2113         struct thread  *td;
 2114 
 2115         UNIONFS_INTERNAL_DEBUG("unionfs_setacl: enter\n");
 2116 
 2117         KASSERT_UNIONFS_VNODE(ap->a_vp);
 2118 
 2119         error = EROFS;
 2120         unp = VTOUNIONFS(ap->a_vp);
 2121         uvp = unp->un_uppervp;
 2122         lvp = unp->un_lowervp;
 2123         td = ap->a_td;
 2124 
 2125         if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
 2126                 return (EROFS);
 2127 
 2128         if (uvp == NULLVP && lvp->v_type == VREG) {
 2129                 if ((error = unionfs_copyfile(unp, 1, ap->a_cred, td)) != 0)
 2130                         return (error);
 2131                 uvp = unp->un_uppervp;
 2132         }
 2133 
 2134         if (uvp != NULLVP)
 2135                 error = VOP_SETACL(uvp, ap->a_type, ap->a_aclp, ap->a_cred, td);
 2136 
 2137         UNIONFS_INTERNAL_DEBUG("unionfs_setacl: leave (%d)\n", error);
 2138 
 2139         return (error);
 2140 }
 2141 
 2142 static int
 2143 unionfs_aclcheck(struct vop_aclcheck_args *ap)
 2144 {
 2145         int             error;
 2146         struct unionfs_node *unp;
 2147         struct vnode   *vp;
 2148 
 2149         UNIONFS_INTERNAL_DEBUG("unionfs_aclcheck: enter\n");
 2150 
 2151         KASSERT_UNIONFS_VNODE(ap->a_vp);
 2152 
 2153         unp = VTOUNIONFS(ap->a_vp);
 2154         vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
 2155 
 2156         error = VOP_ACLCHECK(vp, ap->a_type, ap->a_aclp, ap->a_cred, ap->a_td);
 2157 
 2158         UNIONFS_INTERNAL_DEBUG("unionfs_aclcheck: leave (%d)\n", error);
 2159 
 2160         return (error);
 2161 }
 2162 
 2163 static int
 2164 unionfs_openextattr(struct vop_openextattr_args *ap)
 2165 {
 2166         int             error;
 2167         struct unionfs_node *unp;
 2168         struct vnode   *vp;
 2169         struct vnode   *tvp;
 2170 
 2171         KASSERT_UNIONFS_VNODE(ap->a_vp);
 2172 
 2173         vp = ap->a_vp;
 2174         unp = VTOUNIONFS(vp);
 2175         tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
 2176 
 2177         if ((tvp == unp->un_uppervp && (unp->un_flag & UNIONFS_OPENEXTU)) ||
 2178             (tvp == unp->un_lowervp && (unp->un_flag & UNIONFS_OPENEXTL)))
 2179                 return (EBUSY);
 2180 
 2181         error = VOP_OPENEXTATTR(tvp, ap->a_cred, ap->a_td);
 2182 
 2183         if (error == 0) {
 2184                 vn_lock(vp, LK_UPGRADE | LK_RETRY, ap->a_td);
 2185                 if (tvp == unp->un_uppervp)
 2186                         unp->un_flag |= UNIONFS_OPENEXTU;
 2187                 else
 2188                         unp->un_flag |= UNIONFS_OPENEXTL;
 2189                 vn_lock(vp, LK_DOWNGRADE | LK_RETRY, ap->a_td);
 2190         }
 2191 
 2192         return (error);
 2193 }
 2194 
 2195 static int
 2196 unionfs_closeextattr(struct vop_closeextattr_args *ap)
 2197 {
 2198         int             error;
 2199         struct unionfs_node *unp;
 2200         struct vnode   *vp;
 2201         struct vnode   *tvp;
 2202 
 2203         KASSERT_UNIONFS_VNODE(ap->a_vp);
 2204 
 2205         vp = ap->a_vp;
 2206         unp = VTOUNIONFS(vp);
 2207         tvp = NULLVP;
 2208 
 2209         if (unp->un_flag & UNIONFS_OPENEXTU)
 2210                 tvp = unp->un_uppervp;
 2211         else if (unp->un_flag & UNIONFS_OPENEXTL)
 2212                 tvp = unp->un_lowervp;
 2213 
 2214         if (tvp == NULLVP)
 2215                 return (EOPNOTSUPP);
 2216 
 2217         error = VOP_CLOSEEXTATTR(tvp, ap->a_commit, ap->a_cred, ap->a_td);
 2218 
 2219         if (error == 0) {
 2220                 vn_lock(vp, LK_UPGRADE | LK_RETRY, ap->a_td);
 2221                 if (tvp == unp->un_uppervp)
 2222                         unp->un_flag &= ~UNIONFS_OPENEXTU;
 2223                 else
 2224                         unp->un_flag &= ~UNIONFS_OPENEXTL;
 2225                 vn_lock(vp, LK_DOWNGRADE | LK_RETRY, ap->a_td);
 2226         }
 2227 
 2228         return (error);
 2229 }
 2230 
 2231 static int
 2232 unionfs_getextattr(struct vop_getextattr_args *ap)
 2233 {
 2234         struct unionfs_node *unp;
 2235         struct vnode   *vp;
 2236 
 2237         KASSERT_UNIONFS_VNODE(ap->a_vp);
 2238 
 2239         unp = VTOUNIONFS(ap->a_vp);
 2240         vp = NULLVP;
 2241 
 2242         if (unp->un_flag & UNIONFS_OPENEXTU)
 2243                 vp = unp->un_uppervp;
 2244         else if (unp->un_flag & UNIONFS_OPENEXTL)
 2245                 vp = unp->un_lowervp;
 2246 
 2247         if (vp == NULLVP)
 2248                 return (EOPNOTSUPP);
 2249 
 2250         return (VOP_GETEXTATTR(vp, ap->a_attrnamespace, ap->a_name,
 2251             ap->a_uio, ap->a_size, ap->a_cred, ap->a_td));
 2252 }
 2253 
 2254 static int
 2255 unionfs_setextattr(struct vop_setextattr_args *ap)
 2256 {
 2257         int             error;
 2258         struct unionfs_node *unp;
 2259         struct vnode   *uvp;
 2260         struct vnode   *lvp;
 2261         struct vnode   *ovp;
 2262         struct ucred   *cred;
 2263         struct thread  *td;
 2264 
 2265         KASSERT_UNIONFS_VNODE(ap->a_vp);
 2266 
 2267         error = EROFS;
 2268         unp = VTOUNIONFS(ap->a_vp);
 2269         uvp = unp->un_uppervp;
 2270         lvp = unp->un_lowervp;
 2271         ovp = NULLVP;
 2272         cred = ap->a_cred;
 2273         td = ap->a_td;
 2274 
 2275         UNIONFS_INTERNAL_DEBUG("unionfs_setextattr: enter (un_flag=%x)\n", unp->un_flag);
 2276 
 2277         if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
 2278                 return (EROFS);
 2279 
 2280         if (unp->un_flag & UNIONFS_OPENEXTU)
 2281                 ovp = unp->un_uppervp;
 2282         else if (unp->un_flag & UNIONFS_OPENEXTL)
 2283                 ovp = unp->un_lowervp;
 2284 
 2285         if (ovp == NULLVP)
 2286                 return (EOPNOTSUPP);
 2287 
 2288         if (ovp == lvp && lvp->v_type == VREG) {
 2289                 VOP_CLOSEEXTATTR(lvp, 0, cred, td);
 2290                 if (uvp == NULLVP &&
 2291                     (error = unionfs_copyfile(unp, 1, cred, td)) != 0) {
 2292 unionfs_setextattr_reopen:
 2293                         if ((unp->un_flag & UNIONFS_OPENEXTL) &&
 2294                             VOP_OPENEXTATTR(lvp, cred, td)) {
 2295 #ifdef DIAGNOSTIC
 2296                                 panic("unionfs: VOP_OPENEXTATTR failed");
 2297 #endif
 2298                                 unp->un_flag &= ~UNIONFS_OPENEXTL;
 2299                         }
 2300                         goto unionfs_setextattr_abort;
 2301                 }
 2302                 uvp = unp->un_uppervp;
 2303                 if ((error = VOP_OPENEXTATTR(uvp, cred, td)) != 0)
 2304                         goto unionfs_setextattr_reopen;
 2305                 unp->un_flag &= ~UNIONFS_OPENEXTL;
 2306                 unp->un_flag |= UNIONFS_OPENEXTU;
 2307                 ovp = uvp;
 2308         }
 2309 
 2310         if (ovp == uvp)
 2311                 error = VOP_SETEXTATTR(ovp, ap->a_attrnamespace, ap->a_name,
 2312                     ap->a_uio, cred, td);
 2313 
 2314 unionfs_setextattr_abort:
 2315         UNIONFS_INTERNAL_DEBUG("unionfs_setextattr: leave (%d)\n", error);
 2316 
 2317         return (error);
 2318 }
 2319 
 2320 static int
 2321 unionfs_listextattr(struct vop_listextattr_args *ap)
 2322 {
 2323         struct unionfs_node *unp;
 2324         struct vnode   *vp;
 2325 
 2326         KASSERT_UNIONFS_VNODE(ap->a_vp);
 2327 
 2328         unp = VTOUNIONFS(ap->a_vp);
 2329         vp = NULLVP;
 2330 
 2331         if (unp->un_flag & UNIONFS_OPENEXTU)
 2332                 vp = unp->un_uppervp;
 2333         else if (unp->un_flag & UNIONFS_OPENEXTL)
 2334                 vp = unp->un_lowervp;
 2335 
 2336         if (vp == NULLVP)
 2337                 return (EOPNOTSUPP);
 2338 
 2339         return (VOP_LISTEXTATTR(vp, ap->a_attrnamespace, ap->a_uio,
 2340             ap->a_size, ap->a_cred, ap->a_td));
 2341 }
 2342 
 2343 static int
 2344 unionfs_deleteextattr(struct vop_deleteextattr_args *ap)
 2345 {
 2346         int             error;
 2347         struct unionfs_node *unp;
 2348         struct vnode   *uvp;
 2349         struct vnode   *lvp;
 2350         struct vnode   *ovp;
 2351         struct ucred   *cred;
 2352         struct thread  *td;
 2353 
 2354         KASSERT_UNIONFS_VNODE(ap->a_vp);
 2355 
 2356         error = EROFS;
 2357         unp = VTOUNIONFS(ap->a_vp);
 2358         uvp = unp->un_uppervp;
 2359         lvp = unp->un_lowervp;
 2360         ovp = NULLVP;
 2361         cred = ap->a_cred;
 2362         td = ap->a_td;
 2363 
 2364         UNIONFS_INTERNAL_DEBUG("unionfs_deleteextattr: enter (un_flag=%x)\n", unp->un_flag);
 2365 
 2366         if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
 2367                 return (EROFS);
 2368 
 2369         if (unp->un_flag & UNIONFS_OPENEXTU)
 2370                 ovp = unp->un_uppervp;
 2371         else if (unp->un_flag & UNIONFS_OPENEXTL)
 2372                 ovp = unp->un_lowervp;
 2373 
 2374         if (ovp == NULLVP)
 2375                 return (EOPNOTSUPP);
 2376 
 2377         if (ovp == lvp && lvp->v_type == VREG) {
 2378                 VOP_CLOSEEXTATTR(lvp, 0, cred, td);
 2379                 if (uvp == NULLVP &&
 2380                     (error = unionfs_copyfile(unp, 1, cred, td)) != 0) {
 2381 unionfs_deleteextattr_reopen:
 2382                         if ((unp->un_flag & UNIONFS_OPENEXTL) &&
 2383                             VOP_OPENEXTATTR(lvp, cred, td)) {
 2384 #ifdef DIAGNOSTIC
 2385                                 panic("unionfs: VOP_OPENEXTATTR failed");
 2386 #endif
 2387                                 unp->un_flag &= ~UNIONFS_OPENEXTL;
 2388                         }
 2389                         goto unionfs_deleteextattr_abort;
 2390                 }
 2391                 uvp = unp->un_uppervp;
 2392                 if ((error = VOP_OPENEXTATTR(uvp, cred, td)) != 0)
 2393                         goto unionfs_deleteextattr_reopen;
 2394                 unp->un_flag &= ~UNIONFS_OPENEXTL;
 2395                 unp->un_flag |= UNIONFS_OPENEXTU;
 2396                 ovp = uvp;
 2397         }
 2398 
 2399         if (ovp == uvp)
 2400                 error = VOP_DELETEEXTATTR(ovp, ap->a_attrnamespace, ap->a_name,
 2401                     ap->a_cred, ap->a_td);
 2402 
 2403 unionfs_deleteextattr_abort:
 2404         UNIONFS_INTERNAL_DEBUG("unionfs_deleteextattr: leave (%d)\n", error);
 2405 
 2406         return (error);
 2407 }
 2408 
 2409 static int
 2410 unionfs_setlabel(struct vop_setlabel_args *ap)
 2411 {
 2412         int             error;
 2413         struct unionfs_node *unp;
 2414         struct vnode   *uvp;
 2415         struct vnode   *lvp;
 2416         struct thread  *td;
 2417 
 2418         UNIONFS_INTERNAL_DEBUG("unionfs_setlabel: enter\n");
 2419 
 2420         KASSERT_UNIONFS_VNODE(ap->a_vp);
 2421 
 2422         error = EROFS;
 2423         unp = VTOUNIONFS(ap->a_vp);
 2424         uvp = unp->un_uppervp;
 2425         lvp = unp->un_lowervp;
 2426         td = ap->a_td;
 2427 
 2428         if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
 2429                 return (EROFS);
 2430 
 2431         if (uvp == NULLVP && lvp->v_type == VREG) {
 2432                 if ((error = unionfs_copyfile(unp, 1, ap->a_cred, td)) != 0)
 2433                         return (error);
 2434                 uvp = unp->un_uppervp;
 2435         }
 2436 
 2437         if (uvp != NULLVP)
 2438                 error = VOP_SETLABEL(uvp, ap->a_label, ap->a_cred, td);
 2439 
 2440         UNIONFS_INTERNAL_DEBUG("unionfs_setlabel: leave (%d)\n", error);
 2441 
 2442         return (error);
 2443 }
 2444 
 2445 static int
 2446 unionfs_vptofh(struct vop_vptofh_args *ap)
 2447 {
 2448         return (EOPNOTSUPP);
 2449 }
 2450 
 2451 struct vop_vector unionfs_vnodeops = {
 2452         .vop_default =          &default_vnodeops,
 2453 
 2454         .vop_access =           unionfs_access,
 2455         .vop_aclcheck =         unionfs_aclcheck,
 2456         .vop_advlock =          unionfs_advlock,
 2457         .vop_bmap =             VOP_EOPNOTSUPP,
 2458         .vop_cachedlookup =     unionfs_lookup,
 2459         .vop_close =            unionfs_close,
 2460         .vop_closeextattr =     unionfs_closeextattr,
 2461         .vop_create =           unionfs_create,
 2462         .vop_deleteextattr =    unionfs_deleteextattr,
 2463         .vop_fsync =            unionfs_fsync,
 2464         .vop_getacl =           unionfs_getacl,
 2465         .vop_getattr =          unionfs_getattr,
 2466         .vop_getextattr =       unionfs_getextattr,
 2467         .vop_getwritemount =    unionfs_getwritemount,
 2468         .vop_inactive =         unionfs_inactive,
 2469         .vop_ioctl =            unionfs_ioctl,
 2470         .vop_lease =            unionfs_lease,
 2471         .vop_link =             unionfs_link,
 2472         .vop_listextattr =      unionfs_listextattr,
 2473         .vop_lock1 =            unionfs_lock,
 2474         .vop_lookup =           vfs_cache_lookup,
 2475         .vop_mkdir =            unionfs_mkdir,
 2476         .vop_mknod =            unionfs_mknod,
 2477         .vop_open =             unionfs_open,
 2478         .vop_openextattr =      unionfs_openextattr,
 2479         .vop_pathconf =         unionfs_pathconf,
 2480         .vop_poll =             unionfs_poll,
 2481         .vop_print =            unionfs_print,
 2482         .vop_read =             unionfs_read,
 2483         .vop_readdir =          unionfs_readdir,
 2484         .vop_readlink =         unionfs_readlink,
 2485         .vop_reclaim =          unionfs_reclaim,
 2486         .vop_remove =           unionfs_remove,
 2487         .vop_rename =           unionfs_rename,
 2488         .vop_rmdir =            unionfs_rmdir,
 2489         .vop_setacl =           unionfs_setacl,
 2490         .vop_setattr =          unionfs_setattr,
 2491         .vop_setextattr =       unionfs_setextattr,
 2492         .vop_setlabel =         unionfs_setlabel,
 2493         .vop_strategy =         unionfs_strategy,
 2494         .vop_symlink =          unionfs_symlink,
 2495         .vop_unlock =           unionfs_unlock,
 2496         .vop_whiteout =         unionfs_whiteout,
 2497         .vop_write =            unionfs_write,
 2498         .vop_vptofh =           unionfs_vptofh,
 2499 };

Cache object: 0b99dd8290a8285ac84a02c6ef01ad95


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