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

Cache object: 0a3705390fb933d6438501c70cc341ac


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