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


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

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

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

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

Cache object: b0d17bad4b9f06b7277fb52602d86dae


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