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

Cache object: 32df85f0187e8b0c897893c18813d9ef


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