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

Cache object: c0ff1118c9cbcc0bd111512a09b1930e


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