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

Cache object: fe98ee3efe5bb57738384f7ec611f77e


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