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

Cache object: 550361b02f81f23a0a50db12d0b8a6b3


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