The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/unionfs/union_vnops.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 5cc1c01b614d3e7d7d0206b154c0578d


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