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_subr.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) 1994 Jan-Simon Pendry
    5  * Copyright (c) 1994
    6  *      The Regents of the University of California.  All rights reserved.
    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  *
   10  * This code is derived from software contributed to Berkeley by
   11  * Jan-Simon Pendry.
   12  *
   13  * Redistribution and use in source and binary forms, with or without
   14  * modification, are permitted provided that the following conditions
   15  * are met:
   16  * 1. Redistributions of source code must retain the above copyright
   17  *    notice, this list of conditions and the following disclaimer.
   18  * 2. Redistributions in binary form must reproduce the above copyright
   19  *    notice, this list of conditions and the following disclaimer in the
   20  *    documentation and/or other materials provided with the distribution.
   21  * 3. Neither the name of the University nor the names of its contributors
   22  *    may be used to endorse or promote products derived from this software
   23  *    without specific prior written permission.
   24  *
   25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   35  * SUCH DAMAGE.
   36  *
   37  *      @(#)union_subr.c        8.20 (Berkeley) 5/20/95
   38  * $FreeBSD$
   39  */
   40 
   41 #include <sys/param.h>
   42 #include <sys/systm.h>
   43 #include <sys/kernel.h>
   44 #include <sys/ktr.h>
   45 #include <sys/lock.h>
   46 #include <sys/mutex.h>
   47 #include <sys/malloc.h>
   48 #include <sys/mount.h>
   49 #include <sys/namei.h>
   50 #include <sys/proc.h>
   51 #include <sys/vnode.h>
   52 #include <sys/dirent.h>
   53 #include <sys/fcntl.h>
   54 #include <sys/filedesc.h>
   55 #include <sys/stat.h>
   56 #include <sys/resourcevar.h>
   57 
   58 #include <security/mac/mac_framework.h>
   59 
   60 #include <vm/uma.h>
   61 
   62 #include <fs/unionfs/union.h>
   63 
   64 #define NUNIONFSNODECACHE 16
   65 
   66 static MALLOC_DEFINE(M_UNIONFSHASH, "UNIONFS hash", "UNIONFS hash table");
   67 MALLOC_DEFINE(M_UNIONFSNODE, "UNIONFS node", "UNIONFS vnode private part");
   68 MALLOC_DEFINE(M_UNIONFSPATH, "UNIONFS path", "UNIONFS path private part");
   69 
   70 /*
   71  * Initialize
   72  */
   73 int 
   74 unionfs_init(struct vfsconf *vfsp)
   75 {
   76         UNIONFSDEBUG("unionfs_init\n"); /* printed during system boot */
   77         return (0);
   78 }
   79 
   80 /*
   81  * Uninitialize
   82  */
   83 int 
   84 unionfs_uninit(struct vfsconf *vfsp)
   85 {
   86         return (0);
   87 }
   88 
   89 static struct unionfs_node_hashhead *
   90 unionfs_get_hashhead(struct vnode *dvp, char *path)
   91 {
   92         int             count;
   93         char            hash;
   94         struct unionfs_node *unp;
   95 
   96         hash = 0;
   97         unp = VTOUNIONFS(dvp);
   98         if (path != NULL) {
   99                 for (count = 0; path[count]; count++)
  100                         hash += path[count];
  101         }
  102 
  103         return (&(unp->un_hashtbl[hash & (unp->un_hashmask)]));
  104 }
  105 
  106 /*
  107  * Get the cached vnode.
  108  */
  109 static struct vnode *
  110 unionfs_get_cached_vnode(struct vnode *uvp, struct vnode *lvp,
  111                         struct vnode *dvp, char *path)
  112 {
  113         struct unionfs_node_hashhead *hd;
  114         struct unionfs_node *unp;
  115         struct vnode   *vp;
  116 
  117         KASSERT((uvp == NULLVP || uvp->v_type == VDIR),
  118             ("unionfs_get_cached_vnode: v_type != VDIR"));
  119         KASSERT((lvp == NULLVP || lvp->v_type == VDIR),
  120             ("unionfs_get_cached_vnode: v_type != VDIR"));
  121 
  122         VI_LOCK(dvp);
  123         hd = unionfs_get_hashhead(dvp, path);
  124         LIST_FOREACH(unp, hd, un_hash) {
  125                 if (!strcmp(unp->un_path, path)) {
  126                         vp = UNIONFSTOV(unp);
  127                         VI_LOCK_FLAGS(vp, MTX_DUPOK);
  128                         VI_UNLOCK(dvp);
  129                         vp->v_iflag &= ~VI_OWEINACT;
  130                         if (VN_IS_DOOMED(vp) ||
  131                             ((vp->v_iflag & VI_DOINGINACT) != 0)) {
  132                                 VI_UNLOCK(vp);
  133                                 vp = NULLVP;
  134                         } else
  135                                 VI_UNLOCK(vp);
  136                         return (vp);
  137                 }
  138         }
  139         VI_UNLOCK(dvp);
  140 
  141         return (NULLVP);
  142 }
  143 
  144 /*
  145  * Add the new vnode into cache.
  146  */
  147 static struct vnode *
  148 unionfs_ins_cached_vnode(struct unionfs_node *uncp,
  149                         struct vnode *dvp, char *path)
  150 {
  151         struct unionfs_node_hashhead *hd;
  152         struct unionfs_node *unp;
  153         struct vnode   *vp;
  154 
  155         KASSERT((uncp->un_uppervp==NULLVP || uncp->un_uppervp->v_type==VDIR),
  156             ("unionfs_ins_cached_vnode: v_type != VDIR"));
  157         KASSERT((uncp->un_lowervp==NULLVP || uncp->un_lowervp->v_type==VDIR),
  158             ("unionfs_ins_cached_vnode: v_type != VDIR"));
  159 
  160         VI_LOCK(dvp);
  161         hd = unionfs_get_hashhead(dvp, path);
  162         LIST_FOREACH(unp, hd, un_hash) {
  163                 if (!strcmp(unp->un_path, path)) {
  164                         vp = UNIONFSTOV(unp);
  165                         VI_LOCK_FLAGS(vp, MTX_DUPOK);
  166                         vp->v_iflag &= ~VI_OWEINACT;
  167                         if (VN_IS_DOOMED(vp) ||
  168                             ((vp->v_iflag & VI_DOINGINACT) != 0)) {
  169                                 LIST_INSERT_HEAD(hd, uncp, un_hash);
  170                                 VI_UNLOCK(vp);
  171                                 vp = NULLVP;
  172                         } else
  173                                 VI_UNLOCK(vp);
  174                         VI_UNLOCK(dvp);
  175                         return (vp);
  176                 }
  177         }
  178 
  179         LIST_INSERT_HEAD(hd, uncp, un_hash);
  180         VI_UNLOCK(dvp);
  181 
  182         return (NULLVP);
  183 }
  184 
  185 /*
  186  * Remove the vnode.
  187  */
  188 static void
  189 unionfs_rem_cached_vnode(struct unionfs_node *unp, struct vnode *dvp)
  190 {
  191         KASSERT((unp != NULL), ("unionfs_rem_cached_vnode: null node"));
  192         KASSERT((dvp != NULLVP),
  193             ("unionfs_rem_cached_vnode: null parent vnode"));
  194         KASSERT((unp->un_hash.le_prev != NULL),
  195             ("unionfs_rem_cached_vnode: null hash"));
  196 
  197         VI_LOCK(dvp);
  198         LIST_REMOVE(unp, un_hash);
  199         unp->un_hash.le_next = NULL;
  200         unp->un_hash.le_prev = NULL;
  201         VI_UNLOCK(dvp);
  202 }
  203 
  204 /*
  205  * Make a new or get existing unionfs node.
  206  * 
  207  * uppervp and lowervp should be unlocked. Because if new unionfs vnode is
  208  * locked, uppervp or lowervp is locked too. In order to prevent dead lock,
  209  * you should not lock plurality simultaneously.
  210  */
  211 int
  212 unionfs_nodeget(struct mount *mp, struct vnode *uppervp,
  213                 struct vnode *lowervp, struct vnode *dvp,
  214                 struct vnode **vpp, struct componentname *cnp,
  215                 struct thread *td)
  216 {
  217         struct unionfs_mount *ump;
  218         struct unionfs_node *unp;
  219         struct vnode   *vp;
  220         int             error;
  221         int             lkflags;
  222         enum vtype      vt;
  223         char           *path;
  224 
  225         ump = MOUNTTOUNIONFSMOUNT(mp);
  226         lkflags = (cnp ? cnp->cn_lkflags : 0);
  227         path = (cnp ? cnp->cn_nameptr : NULL);
  228         *vpp = NULLVP;
  229 
  230         if (uppervp == NULLVP && lowervp == NULLVP)
  231                 panic("unionfs_nodeget: upper and lower is null");
  232 
  233         vt = (uppervp != NULLVP ? uppervp->v_type : lowervp->v_type);
  234 
  235         /* If it has no ISLASTCN flag, path check is skipped. */
  236         if (cnp && !(cnp->cn_flags & ISLASTCN))
  237                 path = NULL;
  238 
  239         /* check the cache */
  240         if (path != NULL && dvp != NULLVP && vt == VDIR) {
  241                 vp = unionfs_get_cached_vnode(uppervp, lowervp, dvp, path);
  242                 if (vp != NULLVP) {
  243                         vref(vp);
  244                         *vpp = vp;
  245                         goto unionfs_nodeget_out;
  246                 }
  247         }
  248 
  249         if ((uppervp == NULLVP || ump->um_uppervp != uppervp) ||
  250             (lowervp == NULLVP || ump->um_lowervp != lowervp)) {
  251                 /* dvp will be NULLVP only in case of root vnode. */
  252                 if (dvp == NULLVP)
  253                         return (EINVAL);
  254         }
  255         unp = malloc(sizeof(struct unionfs_node),
  256             M_UNIONFSNODE, M_WAITOK | M_ZERO);
  257 
  258         error = getnewvnode("unionfs", mp, &unionfs_vnodeops, &vp);
  259         if (error != 0) {
  260                 free(unp, M_UNIONFSNODE);
  261                 return (error);
  262         }
  263         error = insmntque(vp, mp);      /* XXX: Too early for mpsafe fs */
  264         if (error != 0) {
  265                 free(unp, M_UNIONFSNODE);
  266                 return (error);
  267         }
  268         if (dvp != NULLVP)
  269                 vref(dvp);
  270         if (uppervp != NULLVP)
  271                 vref(uppervp);
  272         if (lowervp != NULLVP)
  273                 vref(lowervp);
  274 
  275         if (vt == VDIR)
  276                 unp->un_hashtbl = hashinit(NUNIONFSNODECACHE, M_UNIONFSHASH,
  277                     &(unp->un_hashmask));
  278 
  279         unp->un_vnode = vp;
  280         unp->un_uppervp = uppervp;
  281         unp->un_lowervp = lowervp;
  282         unp->un_dvp = dvp;
  283         if (uppervp != NULLVP)
  284                 vp->v_vnlock = uppervp->v_vnlock;
  285         else
  286                 vp->v_vnlock = lowervp->v_vnlock;
  287 
  288         if (path != NULL) {
  289                 unp->un_path = (char *)
  290                     malloc(cnp->cn_namelen +1, M_UNIONFSPATH, M_WAITOK|M_ZERO);
  291                 bcopy(cnp->cn_nameptr, unp->un_path, cnp->cn_namelen);
  292                 unp->un_path[cnp->cn_namelen] = '\0';
  293         }
  294         vp->v_type = vt;
  295         vp->v_data = unp;
  296 
  297         if ((uppervp != NULLVP && ump->um_uppervp == uppervp) &&
  298             (lowervp != NULLVP && ump->um_lowervp == lowervp))
  299                 vp->v_vflag |= VV_ROOT;
  300 
  301         if (path != NULL && dvp != NULLVP && vt == VDIR)
  302                 *vpp = unionfs_ins_cached_vnode(unp, dvp, path);
  303         if ((*vpp) != NULLVP) {
  304                 if (dvp != NULLVP)
  305                         vrele(dvp);
  306                 if (uppervp != NULLVP)
  307                         vrele(uppervp);
  308                 if (lowervp != NULLVP)
  309                         vrele(lowervp);
  310 
  311                 unp->un_uppervp = NULLVP;
  312                 unp->un_lowervp = NULLVP;
  313                 unp->un_dvp = NULLVP;
  314                 vrele(vp);
  315                 vp = *vpp;
  316                 vref(vp);
  317         } else
  318                 *vpp = vp;
  319 
  320 unionfs_nodeget_out:
  321         if (lkflags & LK_TYPE_MASK)
  322                 vn_lock(vp, lkflags | LK_RETRY);
  323 
  324         return (0);
  325 }
  326 
  327 /*
  328  * Clean up the unionfs node.
  329  */
  330 void
  331 unionfs_noderem(struct vnode *vp, struct thread *td)
  332 {
  333         int             count;
  334         struct unionfs_node *unp, *unp_t1, *unp_t2;
  335         struct unionfs_node_hashhead *hd;
  336         struct unionfs_node_status *unsp, *unsp_tmp;
  337         struct vnode   *lvp;
  338         struct vnode   *uvp;
  339         struct vnode   *dvp;
  340 
  341         /*
  342          * Use the interlock to protect the clearing of v_data to
  343          * prevent faults in unionfs_lock().
  344          */
  345         VI_LOCK(vp);
  346         unp = VTOUNIONFS(vp);
  347         lvp = unp->un_lowervp;
  348         uvp = unp->un_uppervp;
  349         dvp = unp->un_dvp;
  350         unp->un_lowervp = unp->un_uppervp = NULLVP;
  351         vp->v_vnlock = &(vp->v_lock);
  352         vp->v_data = NULL;
  353         vp->v_object = NULL;
  354         if (vp->v_writecount > 0) {
  355                 if (uvp != NULL)
  356                         VOP_ADD_WRITECOUNT(uvp, -vp->v_writecount);
  357                 else if (lvp != NULL)
  358                         VOP_ADD_WRITECOUNT(lvp, -vp->v_writecount);
  359         } else if (vp->v_writecount < 0)
  360                 vp->v_writecount = 0;
  361         VI_UNLOCK(vp);
  362 
  363         if (lvp != NULLVP)
  364                 VOP_UNLOCK(lvp);
  365         if (uvp != NULLVP)
  366                 VOP_UNLOCK(uvp);
  367 
  368         if (dvp != NULLVP && unp->un_hash.le_prev != NULL)
  369                 unionfs_rem_cached_vnode(unp, dvp);
  370 
  371         if (lockmgr(vp->v_vnlock, LK_EXCLUSIVE, VI_MTX(vp)) != 0)
  372                 panic("the lock for deletion is unacquirable.");
  373 
  374         if (lvp != NULLVP)
  375                 vrele(lvp);
  376         if (uvp != NULLVP)
  377                 vrele(uvp);
  378         if (dvp != NULLVP) {
  379                 vrele(dvp);
  380                 unp->un_dvp = NULLVP;
  381         }
  382         if (unp->un_path != NULL) {
  383                 free(unp->un_path, M_UNIONFSPATH);
  384                 unp->un_path = NULL;
  385         }
  386 
  387         if (unp->un_hashtbl != NULL) {
  388                 for (count = 0; count <= unp->un_hashmask; count++) {
  389                         hd = unp->un_hashtbl + count;
  390                         LIST_FOREACH_SAFE(unp_t1, hd, un_hash, unp_t2) {
  391                                 LIST_REMOVE(unp_t1, un_hash);
  392                                 unp_t1->un_hash.le_next = NULL;
  393                                 unp_t1->un_hash.le_prev = NULL;
  394                         }
  395                 }
  396                 hashdestroy(unp->un_hashtbl, M_UNIONFSHASH, unp->un_hashmask);
  397         }
  398 
  399         LIST_FOREACH_SAFE(unsp, &(unp->un_unshead), uns_list, unsp_tmp) {
  400                 LIST_REMOVE(unsp, uns_list);
  401                 free(unsp, M_TEMP);
  402         }
  403         free(unp, M_UNIONFSNODE);
  404 }
  405 
  406 /*
  407  * Get the unionfs node status.
  408  * You need exclusive lock this vnode.
  409  */
  410 void
  411 unionfs_get_node_status(struct unionfs_node *unp, struct thread *td,
  412                         struct unionfs_node_status **unspp)
  413 {
  414         struct unionfs_node_status *unsp;
  415         pid_t pid = td->td_proc->p_pid;
  416 
  417         KASSERT(NULL != unspp, ("null pointer"));
  418         ASSERT_VOP_ELOCKED(UNIONFSTOV(unp), "unionfs_get_node_status");
  419 
  420         LIST_FOREACH(unsp, &(unp->un_unshead), uns_list) {
  421                 if (unsp->uns_pid == pid) {
  422                         *unspp = unsp;
  423                         return;
  424                 }
  425         }
  426 
  427         /* create a new unionfs node status */
  428         unsp = malloc(sizeof(struct unionfs_node_status),
  429             M_TEMP, M_WAITOK | M_ZERO);
  430 
  431         unsp->uns_pid = pid;
  432         LIST_INSERT_HEAD(&(unp->un_unshead), unsp, uns_list);
  433 
  434         *unspp = unsp;
  435 }
  436 
  437 /*
  438  * Remove the unionfs node status, if you can.
  439  * You need exclusive lock this vnode.
  440  */
  441 void
  442 unionfs_tryrem_node_status(struct unionfs_node *unp,
  443                            struct unionfs_node_status *unsp)
  444 {
  445         KASSERT(NULL != unsp, ("null pointer"));
  446         ASSERT_VOP_ELOCKED(UNIONFSTOV(unp), "unionfs_get_node_status");
  447 
  448         if (0 < unsp->uns_lower_opencnt || 0 < unsp->uns_upper_opencnt)
  449                 return;
  450 
  451         LIST_REMOVE(unsp, uns_list);
  452         free(unsp, M_TEMP);
  453 }
  454 
  455 /*
  456  * Create upper node attr.
  457  */
  458 void
  459 unionfs_create_uppervattr_core(struct unionfs_mount *ump,
  460                                struct vattr *lva,
  461                                struct vattr *uva,
  462                                struct thread *td)
  463 {
  464         VATTR_NULL(uva);
  465         uva->va_type = lva->va_type;
  466         uva->va_atime = lva->va_atime;
  467         uva->va_mtime = lva->va_mtime;
  468         uva->va_ctime = lva->va_ctime;
  469 
  470         switch (ump->um_copymode) {
  471         case UNIONFS_TRANSPARENT:
  472                 uva->va_mode = lva->va_mode;
  473                 uva->va_uid = lva->va_uid;
  474                 uva->va_gid = lva->va_gid;
  475                 break;
  476         case UNIONFS_MASQUERADE:
  477                 if (ump->um_uid == lva->va_uid) {
  478                         uva->va_mode = lva->va_mode & 077077;
  479                         uva->va_mode |= (lva->va_type == VDIR ? ump->um_udir : ump->um_ufile) & 0700;
  480                         uva->va_uid = lva->va_uid;
  481                         uva->va_gid = lva->va_gid;
  482                 } else {
  483                         uva->va_mode = (lva->va_type == VDIR ? ump->um_udir : ump->um_ufile);
  484                         uva->va_uid = ump->um_uid;
  485                         uva->va_gid = ump->um_gid;
  486                 }
  487                 break;
  488         default:                /* UNIONFS_TRADITIONAL */
  489                 uva->va_mode = 0777 & ~td->td_proc->p_pd->pd_cmask;
  490                 uva->va_uid = ump->um_uid;
  491                 uva->va_gid = ump->um_gid;
  492                 break;
  493         }
  494 }
  495 
  496 /*
  497  * Create upper node attr.
  498  */
  499 int
  500 unionfs_create_uppervattr(struct unionfs_mount *ump,
  501                           struct vnode *lvp,
  502                           struct vattr *uva,
  503                           struct ucred *cred,
  504                           struct thread *td)
  505 {
  506         int             error;
  507         struct vattr    lva;
  508 
  509         if ((error = VOP_GETATTR(lvp, &lva, cred)))
  510                 return (error);
  511 
  512         unionfs_create_uppervattr_core(ump, &lva, uva, td);
  513 
  514         return (error);
  515 }
  516 
  517 /*
  518  * relookup
  519  * 
  520  * dvp should be locked on entry and will be locked on return.
  521  * 
  522  * If an error is returned, *vpp will be invalid, otherwise it will hold a
  523  * locked, referenced vnode. If *vpp == dvp then remember that only one
  524  * LK_EXCLUSIVE lock is held.
  525  */
  526 int
  527 unionfs_relookup(struct vnode *dvp, struct vnode **vpp,
  528                  struct componentname *cnp, struct componentname *cn,
  529                  struct thread *td, char *path, int pathlen, u_long nameiop)
  530 {
  531         int     error;
  532 
  533         cn->cn_namelen = pathlen;
  534         cn->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK);
  535         bcopy(path, cn->cn_pnbuf, pathlen);
  536         cn->cn_pnbuf[pathlen] = '\0';
  537 
  538         cn->cn_nameiop = nameiop;
  539         cn->cn_flags = (LOCKPARENT | LOCKLEAF | HASBUF | SAVENAME | ISLASTCN);
  540         cn->cn_lkflags = LK_EXCLUSIVE;
  541         cn->cn_thread = td;
  542         cn->cn_cred = cnp->cn_cred;
  543 
  544         cn->cn_nameptr = cn->cn_pnbuf;
  545 
  546         if (nameiop == DELETE)
  547                 cn->cn_flags |= (cnp->cn_flags & (DOWHITEOUT | SAVESTART));
  548         else if (RENAME == nameiop)
  549                 cn->cn_flags |= (cnp->cn_flags & SAVESTART);
  550         else if (nameiop == CREATE)
  551                 cn->cn_flags |= NOCACHE;
  552 
  553         vref(dvp);
  554         VOP_UNLOCK(dvp);
  555 
  556         if ((error = relookup(dvp, vpp, cn))) {
  557                 uma_zfree(namei_zone, cn->cn_pnbuf);
  558                 cn->cn_flags &= ~HASBUF;
  559                 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
  560         } else
  561                 vrele(dvp);
  562 
  563         return (error);
  564 }
  565 
  566 /*
  567  * relookup for CREATE namei operation.
  568  *
  569  * dvp is unionfs vnode. dvp should be locked.
  570  *
  571  * If it called 'unionfs_copyfile' function by unionfs_link etc,
  572  * VOP_LOOKUP information is broken.
  573  * So it need relookup in order to create link etc.
  574  */
  575 int
  576 unionfs_relookup_for_create(struct vnode *dvp, struct componentname *cnp,
  577                             struct thread *td)
  578 {
  579         int     error;
  580         struct vnode *udvp;
  581         struct vnode *vp;
  582         struct componentname cn;
  583 
  584         udvp = UNIONFSVPTOUPPERVP(dvp);
  585         vp = NULLVP;
  586 
  587         error = unionfs_relookup(udvp, &vp, cnp, &cn, td, cnp->cn_nameptr,
  588             strlen(cnp->cn_nameptr), CREATE);
  589         if (error)
  590                 return (error);
  591 
  592         if (vp != NULLVP) {
  593                 if (udvp == vp)
  594                         vrele(vp);
  595                 else
  596                         vput(vp);
  597 
  598                 error = EEXIST;
  599         }
  600 
  601         if (cn.cn_flags & HASBUF) {
  602                 uma_zfree(namei_zone, cn.cn_pnbuf);
  603                 cn.cn_flags &= ~HASBUF;
  604         }
  605 
  606         if (!error) {
  607                 cn.cn_flags |= (cnp->cn_flags & HASBUF);
  608                 cnp->cn_flags = cn.cn_flags;
  609         }
  610 
  611         return (error);
  612 }
  613 
  614 /*
  615  * relookup for DELETE namei operation.
  616  *
  617  * dvp is unionfs vnode. dvp should be locked.
  618  */
  619 int
  620 unionfs_relookup_for_delete(struct vnode *dvp, struct componentname *cnp,
  621                             struct thread *td)
  622 {
  623         int     error;
  624         struct vnode *udvp;
  625         struct vnode *vp;
  626         struct componentname cn;
  627 
  628         udvp = UNIONFSVPTOUPPERVP(dvp);
  629         vp = NULLVP;
  630 
  631         error = unionfs_relookup(udvp, &vp, cnp, &cn, td, cnp->cn_nameptr,
  632             strlen(cnp->cn_nameptr), DELETE);
  633         if (error)
  634                 return (error);
  635 
  636         if (vp == NULLVP)
  637                 error = ENOENT;
  638         else {
  639                 if (udvp == vp)
  640                         vrele(vp);
  641                 else
  642                         vput(vp);
  643         }
  644 
  645         if (cn.cn_flags & HASBUF) {
  646                 uma_zfree(namei_zone, cn.cn_pnbuf);
  647                 cn.cn_flags &= ~HASBUF;
  648         }
  649 
  650         if (!error) {
  651                 cn.cn_flags |= (cnp->cn_flags & HASBUF);
  652                 cnp->cn_flags = cn.cn_flags;
  653         }
  654 
  655         return (error);
  656 }
  657 
  658 /*
  659  * relookup for RENAME namei operation.
  660  *
  661  * dvp is unionfs vnode. dvp should be locked.
  662  */
  663 int
  664 unionfs_relookup_for_rename(struct vnode *dvp, struct componentname *cnp,
  665                             struct thread *td)
  666 {
  667         int error;
  668         struct vnode *udvp;
  669         struct vnode *vp;
  670         struct componentname cn;
  671 
  672         udvp = UNIONFSVPTOUPPERVP(dvp);
  673         vp = NULLVP;
  674 
  675         error = unionfs_relookup(udvp, &vp, cnp, &cn, td, cnp->cn_nameptr,
  676             strlen(cnp->cn_nameptr), RENAME);
  677         if (error)
  678                 return (error);
  679 
  680         if (vp != NULLVP) {
  681                 if (udvp == vp)
  682                         vrele(vp);
  683                 else
  684                         vput(vp);
  685         }
  686 
  687         if (cn.cn_flags & HASBUF) {
  688                 uma_zfree(namei_zone, cn.cn_pnbuf);
  689                 cn.cn_flags &= ~HASBUF;
  690         }
  691 
  692         if (!error) {
  693                 cn.cn_flags |= (cnp->cn_flags & HASBUF);
  694                 cnp->cn_flags = cn.cn_flags;
  695         }
  696 
  697         return (error);
  698 
  699 }
  700 
  701 /*
  702  * Update the unionfs_node.
  703  * 
  704  * uvp is new locked upper vnode. unionfs vnode's lock will be exchanged to the
  705  * uvp's lock and lower's lock will be unlocked.
  706  */
  707 static void
  708 unionfs_node_update(struct unionfs_node *unp, struct vnode *uvp,
  709                     struct thread *td)
  710 {
  711         unsigned        count, lockrec;
  712         struct vnode   *vp;
  713         struct vnode   *lvp;
  714         struct vnode   *dvp;
  715 
  716         vp = UNIONFSTOV(unp);
  717         lvp = unp->un_lowervp;
  718         ASSERT_VOP_ELOCKED(lvp, "unionfs_node_update");
  719         dvp = unp->un_dvp;
  720 
  721         /*
  722          * lock update
  723          */
  724         VI_LOCK(vp);
  725         unp->un_uppervp = uvp;
  726         vp->v_vnlock = uvp->v_vnlock;
  727         VI_UNLOCK(vp);
  728         lockrec = lvp->v_vnlock->lk_recurse;
  729         for (count = 0; count < lockrec; count++)
  730                 vn_lock(uvp, LK_EXCLUSIVE | LK_CANRECURSE | LK_RETRY);
  731 
  732         /*
  733          * cache update
  734          */
  735         if (unp->un_path != NULL && dvp != NULLVP && vp->v_type == VDIR) {
  736                 static struct unionfs_node_hashhead *hd;
  737 
  738                 VI_LOCK(dvp);
  739                 hd = unionfs_get_hashhead(dvp, unp->un_path);
  740                 LIST_REMOVE(unp, un_hash);
  741                 LIST_INSERT_HEAD(hd, unp, un_hash);
  742                 VI_UNLOCK(dvp);
  743         }
  744 }
  745 
  746 /*
  747  * Create a new shadow dir.
  748  * 
  749  * udvp should be locked on entry and will be locked on return.
  750  * 
  751  * If no error returned, unp will be updated.
  752  */
  753 int
  754 unionfs_mkshadowdir(struct unionfs_mount *ump, struct vnode *udvp,
  755                     struct unionfs_node *unp, struct componentname *cnp,
  756                     struct thread *td)
  757 {
  758         int             error;
  759         struct vnode   *lvp;
  760         struct vnode   *uvp;
  761         struct vattr    va;
  762         struct vattr    lva;
  763         struct componentname cn;
  764         struct mount   *mp;
  765         struct ucred   *cred;
  766         struct ucred   *credbk;
  767         struct uidinfo *rootinfo;
  768 
  769         if (unp->un_uppervp != NULLVP)
  770                 return (EEXIST);
  771 
  772         lvp = unp->un_lowervp;
  773         uvp = NULLVP;
  774         credbk = cnp->cn_cred;
  775 
  776         /* Authority change to root */
  777         rootinfo = uifind((uid_t)0);
  778         cred = crdup(cnp->cn_cred);
  779         /*
  780          * The calls to chgproccnt() are needed to compensate for change_ruid()
  781          * calling chgproccnt().
  782          */
  783         chgproccnt(cred->cr_ruidinfo, 1, 0);
  784         change_euid(cred, rootinfo);
  785         change_ruid(cred, rootinfo);
  786         change_svuid(cred, (uid_t)0);
  787         uifree(rootinfo);
  788         cnp->cn_cred = cred;
  789 
  790         memset(&cn, 0, sizeof(cn));
  791 
  792         if ((error = VOP_GETATTR(lvp, &lva, cnp->cn_cred)))
  793                 goto unionfs_mkshadowdir_abort;
  794 
  795         if ((error = unionfs_relookup(udvp, &uvp, cnp, &cn, td, cnp->cn_nameptr, cnp->cn_namelen, CREATE)))
  796                 goto unionfs_mkshadowdir_abort;
  797         if (uvp != NULLVP) {
  798                 if (udvp == uvp)
  799                         vrele(uvp);
  800                 else
  801                         vput(uvp);
  802 
  803                 error = EEXIST;
  804                 goto unionfs_mkshadowdir_free_out;
  805         }
  806 
  807         if ((error = vn_start_write(udvp, &mp, V_WAIT | PCATCH)))
  808                 goto unionfs_mkshadowdir_free_out;
  809         unionfs_create_uppervattr_core(ump, &lva, &va, td);
  810 
  811         error = VOP_MKDIR(udvp, &uvp, &cn, &va);
  812 
  813         if (!error) {
  814                 unionfs_node_update(unp, uvp, td);
  815 
  816                 /*
  817                  * XXX The bug which cannot set uid/gid was corrected.
  818                  * Ignore errors.
  819                  */
  820                 va.va_type = VNON;
  821                 VOP_SETATTR(uvp, &va, cn.cn_cred);
  822         }
  823         vn_finished_write(mp);
  824 
  825 unionfs_mkshadowdir_free_out:
  826         if (cn.cn_flags & HASBUF) {
  827                 uma_zfree(namei_zone, cn.cn_pnbuf);
  828                 cn.cn_flags &= ~HASBUF;
  829         }
  830 
  831 unionfs_mkshadowdir_abort:
  832         cnp->cn_cred = credbk;
  833         chgproccnt(cred->cr_ruidinfo, -1, 0);
  834         crfree(cred);
  835 
  836         return (error);
  837 }
  838 
  839 /*
  840  * Create a new whiteout.
  841  * 
  842  * dvp should be locked on entry and will be locked on return.
  843  */
  844 int
  845 unionfs_mkwhiteout(struct vnode *dvp, struct componentname *cnp,
  846                    struct thread *td, char *path)
  847 {
  848         int             error;
  849         struct vnode   *wvp;
  850         struct componentname cn;
  851         struct mount   *mp;
  852 
  853         if (path == NULL)
  854                 path = cnp->cn_nameptr;
  855 
  856         wvp = NULLVP;
  857         if ((error = unionfs_relookup(dvp, &wvp, cnp, &cn, td, path, strlen(path), CREATE)))
  858                 return (error);
  859         if (wvp != NULLVP) {
  860                 if (cn.cn_flags & HASBUF) {
  861                         uma_zfree(namei_zone, cn.cn_pnbuf);
  862                         cn.cn_flags &= ~HASBUF;
  863                 }
  864                 if (dvp == wvp)
  865                         vrele(wvp);
  866                 else
  867                         vput(wvp);
  868 
  869                 return (EEXIST);
  870         }
  871 
  872         if ((error = vn_start_write(dvp, &mp, V_WAIT | PCATCH)))
  873                 goto unionfs_mkwhiteout_free_out;
  874         error = VOP_WHITEOUT(dvp, &cn, CREATE);
  875 
  876         vn_finished_write(mp);
  877 
  878 unionfs_mkwhiteout_free_out:
  879         if (cn.cn_flags & HASBUF) {
  880                 uma_zfree(namei_zone, cn.cn_pnbuf);
  881                 cn.cn_flags &= ~HASBUF;
  882         }
  883 
  884         return (error);
  885 }
  886 
  887 /*
  888  * Create a new vnode for create a new shadow file.
  889  * 
  890  * If an error is returned, *vpp will be invalid, otherwise it will hold a
  891  * locked, referenced and opened vnode.
  892  * 
  893  * unp is never updated.
  894  */
  895 static int
  896 unionfs_vn_create_on_upper(struct vnode **vpp, struct vnode *udvp,
  897                            struct unionfs_node *unp, struct vattr *uvap,
  898                            struct thread *td)
  899 {
  900         struct unionfs_mount *ump;
  901         struct vnode   *vp;
  902         struct vnode   *lvp;
  903         struct ucred   *cred;
  904         struct vattr    lva;
  905         int             fmode;
  906         int             error;
  907         struct componentname cn;
  908 
  909         ump = MOUNTTOUNIONFSMOUNT(UNIONFSTOV(unp)->v_mount);
  910         vp = NULLVP;
  911         lvp = unp->un_lowervp;
  912         cred = td->td_ucred;
  913         fmode = FFLAGS(O_WRONLY | O_CREAT | O_TRUNC | O_EXCL);
  914         error = 0;
  915 
  916         if ((error = VOP_GETATTR(lvp, &lva, cred)) != 0)
  917                 return (error);
  918         unionfs_create_uppervattr_core(ump, &lva, uvap, td);
  919 
  920         if (unp->un_path == NULL)
  921                 panic("unionfs: un_path is null");
  922 
  923         cn.cn_namelen = strlen(unp->un_path);
  924         cn.cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK);
  925         bcopy(unp->un_path, cn.cn_pnbuf, cn.cn_namelen + 1);
  926         cn.cn_nameiop = CREATE;
  927         cn.cn_flags = (LOCKPARENT | LOCKLEAF | HASBUF | SAVENAME | ISLASTCN);
  928         cn.cn_lkflags = LK_EXCLUSIVE;
  929         cn.cn_thread = td;
  930         cn.cn_cred = cred;
  931         cn.cn_nameptr = cn.cn_pnbuf;
  932 
  933         vref(udvp);
  934         if ((error = relookup(udvp, &vp, &cn)) != 0)
  935                 goto unionfs_vn_create_on_upper_free_out2;
  936         vrele(udvp);
  937 
  938         if (vp != NULLVP) {
  939                 if (vp == udvp)
  940                         vrele(vp);
  941                 else
  942                         vput(vp);
  943                 error = EEXIST;
  944                 goto unionfs_vn_create_on_upper_free_out1;
  945         }
  946 
  947         if ((error = VOP_CREATE(udvp, &vp, &cn, uvap)) != 0)
  948                 goto unionfs_vn_create_on_upper_free_out1;
  949 
  950         if ((error = VOP_OPEN(vp, fmode, cred, td, NULL)) != 0) {
  951                 vput(vp);
  952                 goto unionfs_vn_create_on_upper_free_out1;
  953         }
  954         error = VOP_ADD_WRITECOUNT(vp, 1);
  955         CTR3(KTR_VFS, "%s: vp %p v_writecount increased to %d",  __func__, vp,
  956             vp->v_writecount);
  957         if (error == 0) {
  958                 *vpp = vp;
  959         } else {
  960                 VOP_CLOSE(vp, fmode, cred, td);
  961         }
  962 
  963 unionfs_vn_create_on_upper_free_out1:
  964         VOP_UNLOCK(udvp);
  965 
  966 unionfs_vn_create_on_upper_free_out2:
  967         if (cn.cn_flags & HASBUF) {
  968                 uma_zfree(namei_zone, cn.cn_pnbuf);
  969                 cn.cn_flags &= ~HASBUF;
  970         }
  971 
  972         return (error);
  973 }
  974 
  975 /*
  976  * Copy from lvp to uvp.
  977  * 
  978  * lvp and uvp should be locked and opened on entry and will be locked and
  979  * opened on return.
  980  */
  981 static int
  982 unionfs_copyfile_core(struct vnode *lvp, struct vnode *uvp,
  983                       struct ucred *cred, struct thread *td)
  984 {
  985         int             error;
  986         off_t           offset;
  987         int             count;
  988         int             bufoffset;
  989         char           *buf;
  990         struct uio      uio;
  991         struct iovec    iov;
  992 
  993         error = 0;
  994         memset(&uio, 0, sizeof(uio));
  995 
  996         uio.uio_td = td;
  997         uio.uio_segflg = UIO_SYSSPACE;
  998         uio.uio_offset = 0;
  999 
 1000         buf = malloc(MAXBSIZE, M_TEMP, M_WAITOK);
 1001 
 1002         while (error == 0) {
 1003                 offset = uio.uio_offset;
 1004 
 1005                 uio.uio_iov = &iov;
 1006                 uio.uio_iovcnt = 1;
 1007                 iov.iov_base = buf;
 1008                 iov.iov_len = MAXBSIZE;
 1009                 uio.uio_resid = iov.iov_len;
 1010                 uio.uio_rw = UIO_READ;
 1011 
 1012                 if ((error = VOP_READ(lvp, &uio, 0, cred)) != 0)
 1013                         break;
 1014                 if ((count = MAXBSIZE - uio.uio_resid) == 0)
 1015                         break;
 1016 
 1017                 bufoffset = 0;
 1018                 while (bufoffset < count) {
 1019                         uio.uio_iov = &iov;
 1020                         uio.uio_iovcnt = 1;
 1021                         iov.iov_base = buf + bufoffset;
 1022                         iov.iov_len = count - bufoffset;
 1023                         uio.uio_offset = offset + bufoffset;
 1024                         uio.uio_resid = iov.iov_len;
 1025                         uio.uio_rw = UIO_WRITE;
 1026 
 1027                         if ((error = VOP_WRITE(uvp, &uio, 0, cred)) != 0)
 1028                                 break;
 1029 
 1030                         bufoffset += (count - bufoffset) - uio.uio_resid;
 1031                 }
 1032 
 1033                 uio.uio_offset = offset + bufoffset;
 1034         }
 1035 
 1036         free(buf, M_TEMP);
 1037 
 1038         return (error);
 1039 }
 1040 
 1041 /*
 1042  * Copy file from lower to upper.
 1043  * 
 1044  * If you need copy of the contents, set 1 to docopy. Otherwise, set 0 to
 1045  * docopy.
 1046  * 
 1047  * If no error returned, unp will be updated.
 1048  */
 1049 int
 1050 unionfs_copyfile(struct unionfs_node *unp, int docopy, struct ucred *cred,
 1051                  struct thread *td)
 1052 {
 1053         int             error;
 1054         struct mount   *mp;
 1055         struct vnode   *udvp;
 1056         struct vnode   *lvp;
 1057         struct vnode   *uvp;
 1058         struct vattr    uva;
 1059 
 1060         lvp = unp->un_lowervp;
 1061         uvp = NULLVP;
 1062 
 1063         if ((UNIONFSTOV(unp)->v_mount->mnt_flag & MNT_RDONLY))
 1064                 return (EROFS);
 1065         if (unp->un_dvp == NULLVP)
 1066                 return (EINVAL);
 1067         if (unp->un_uppervp != NULLVP)
 1068                 return (EEXIST);
 1069         udvp = VTOUNIONFS(unp->un_dvp)->un_uppervp;
 1070         if (udvp == NULLVP)
 1071                 return (EROFS);
 1072         if ((udvp->v_mount->mnt_flag & MNT_RDONLY))
 1073                 return (EROFS);
 1074 
 1075         error = VOP_ACCESS(lvp, VREAD, cred, td);
 1076         if (error != 0)
 1077                 return (error);
 1078 
 1079         if ((error = vn_start_write(udvp, &mp, V_WAIT | PCATCH)) != 0)
 1080                 return (error);
 1081         error = unionfs_vn_create_on_upper(&uvp, udvp, unp, &uva, td);
 1082         if (error != 0) {
 1083                 vn_finished_write(mp);
 1084                 return (error);
 1085         }
 1086 
 1087         if (docopy != 0) {
 1088                 error = VOP_OPEN(lvp, FREAD, cred, td, NULL);
 1089                 if (error == 0) {
 1090                         error = unionfs_copyfile_core(lvp, uvp, cred, td);
 1091                         VOP_CLOSE(lvp, FREAD, cred, td);
 1092                 }
 1093         }
 1094         VOP_CLOSE(uvp, FWRITE, cred, td);
 1095         VOP_ADD_WRITECOUNT_CHECKED(uvp, -1);
 1096         CTR3(KTR_VFS, "%s: vp %p v_writecount decreased to %d", __func__, uvp,
 1097             uvp->v_writecount);
 1098 
 1099         vn_finished_write(mp);
 1100 
 1101         if (error == 0) {
 1102                 /* Reset the attributes. Ignore errors. */
 1103                 uva.va_type = VNON;
 1104                 VOP_SETATTR(uvp, &uva, cred);
 1105         }
 1106 
 1107         unionfs_node_update(unp, uvp, td);
 1108 
 1109         return (error);
 1110 }
 1111 
 1112 /*
 1113  * It checks whether vp can rmdir. (check empty)
 1114  *
 1115  * vp is unionfs vnode.
 1116  * vp should be locked.
 1117  */
 1118 int
 1119 unionfs_check_rmdir(struct vnode *vp, struct ucred *cred, struct thread *td)
 1120 {
 1121         int             error;
 1122         int             eofflag;
 1123         int             lookuperr;
 1124         struct vnode   *uvp;
 1125         struct vnode   *lvp;
 1126         struct vnode   *tvp;
 1127         struct vattr    va;
 1128         struct componentname cn;
 1129         /*
 1130          * The size of buf needs to be larger than DIRBLKSIZ.
 1131          */
 1132         char            buf[256 * 6];
 1133         struct dirent  *dp;
 1134         struct dirent  *edp;
 1135         struct uio      uio;
 1136         struct iovec    iov;
 1137 
 1138         ASSERT_VOP_ELOCKED(vp, "unionfs_check_rmdir");
 1139 
 1140         eofflag = 0;
 1141         uvp = UNIONFSVPTOUPPERVP(vp);
 1142         lvp = UNIONFSVPTOLOWERVP(vp);
 1143 
 1144         /* check opaque */
 1145         if ((error = VOP_GETATTR(uvp, &va, cred)) != 0)
 1146                 return (error);
 1147         if (va.va_flags & OPAQUE)
 1148                 return (0);
 1149 
 1150         /* open vnode */
 1151 #ifdef MAC
 1152         if ((error = mac_vnode_check_open(cred, vp, VEXEC|VREAD)) != 0)
 1153                 return (error);
 1154 #endif
 1155         if ((error = VOP_ACCESS(vp, VEXEC|VREAD, cred, td)) != 0)
 1156                 return (error);
 1157         if ((error = VOP_OPEN(vp, FREAD, cred, td, NULL)) != 0)
 1158                 return (error);
 1159 
 1160         uio.uio_rw = UIO_READ;
 1161         uio.uio_segflg = UIO_SYSSPACE;
 1162         uio.uio_td = td;
 1163         uio.uio_offset = 0;
 1164 
 1165 #ifdef MAC
 1166         error = mac_vnode_check_readdir(td->td_ucred, lvp);
 1167 #endif
 1168         while (!error && !eofflag) {
 1169                 iov.iov_base = buf;
 1170                 iov.iov_len = sizeof(buf);
 1171                 uio.uio_iov = &iov;
 1172                 uio.uio_iovcnt = 1;
 1173                 uio.uio_resid = iov.iov_len;
 1174 
 1175                 error = VOP_READDIR(lvp, &uio, cred, &eofflag, NULL, NULL);
 1176                 if (error != 0)
 1177                         break;
 1178                 if (eofflag == 0 && uio.uio_resid == sizeof(buf)) {
 1179 #ifdef DIAGNOSTIC
 1180                         panic("bad readdir response from lower FS.");
 1181 #endif
 1182                         break;
 1183                 }
 1184 
 1185                 edp = (struct dirent*)&buf[sizeof(buf) - uio.uio_resid];
 1186                 for (dp = (struct dirent*)buf; !error && dp < edp;
 1187                      dp = (struct dirent*)((caddr_t)dp + dp->d_reclen)) {
 1188                         if (dp->d_type == DT_WHT || dp->d_fileno == 0 ||
 1189                             (dp->d_namlen == 1 && dp->d_name[0] == '.') ||
 1190                             (dp->d_namlen == 2 && !bcmp(dp->d_name, "..", 2)))
 1191                                 continue;
 1192 
 1193                         cn.cn_namelen = dp->d_namlen;
 1194                         cn.cn_pnbuf = NULL;
 1195                         cn.cn_nameptr = dp->d_name;
 1196                         cn.cn_nameiop = LOOKUP;
 1197                         cn.cn_flags = (LOCKPARENT | LOCKLEAF | SAVENAME | RDONLY | ISLASTCN);
 1198                         cn.cn_lkflags = LK_EXCLUSIVE;
 1199                         cn.cn_thread = td;
 1200                         cn.cn_cred = cred;
 1201 
 1202                         /*
 1203                          * check entry in lower.
 1204                          * Sometimes, readdir function returns
 1205                          * wrong entry.
 1206                          */
 1207                         lookuperr = VOP_LOOKUP(lvp, &tvp, &cn);
 1208 
 1209                         if (!lookuperr)
 1210                                 vput(tvp);
 1211                         else
 1212                                 continue; /* skip entry */
 1213 
 1214                         /*
 1215                          * check entry
 1216                          * If it has no exist/whiteout entry in upper,
 1217                          * directory is not empty.
 1218                          */
 1219                         cn.cn_flags = (LOCKPARENT | LOCKLEAF | SAVENAME | RDONLY | ISLASTCN);
 1220                         lookuperr = VOP_LOOKUP(uvp, &tvp, &cn);
 1221 
 1222                         if (!lookuperr)
 1223                                 vput(tvp);
 1224 
 1225                         /* ignore exist or whiteout entry */
 1226                         if (!lookuperr ||
 1227                             (lookuperr == ENOENT && (cn.cn_flags & ISWHITEOUT)))
 1228                                 continue;
 1229 
 1230                         error = ENOTEMPTY;
 1231                 }
 1232         }
 1233 
 1234         /* close vnode */
 1235         VOP_CLOSE(vp, FREAD, cred, td);
 1236 
 1237         return (error);
 1238 }
 1239 
 1240 #ifdef DIAGNOSTIC
 1241 
 1242 struct vnode   *
 1243 unionfs_checkuppervp(struct vnode *vp, char *fil, int lno)
 1244 {
 1245         struct unionfs_node *unp;
 1246 
 1247         unp = VTOUNIONFS(vp);
 1248 
 1249 #ifdef notyet
 1250         if (vp->v_op != unionfs_vnodeop_p) {
 1251                 printf("unionfs_checkuppervp: on non-unionfs-node.\n");
 1252 #ifdef KDB
 1253                 kdb_enter(KDB_WHY_UNIONFS,
 1254                     "unionfs_checkuppervp: on non-unionfs-node.\n");
 1255 #endif
 1256                 panic("unionfs_checkuppervp");
 1257         }
 1258 #endif
 1259         return (unp->un_uppervp);
 1260 }
 1261 
 1262 struct vnode   *
 1263 unionfs_checklowervp(struct vnode *vp, char *fil, int lno)
 1264 {
 1265         struct unionfs_node *unp;
 1266 
 1267         unp = VTOUNIONFS(vp);
 1268 
 1269 #ifdef notyet
 1270         if (vp->v_op != unionfs_vnodeop_p) {
 1271                 printf("unionfs_checklowervp: on non-unionfs-node.\n");
 1272 #ifdef KDB
 1273                 kdb_enter(KDB_WHY_UNIONFS,
 1274                     "unionfs_checklowervp: on non-unionfs-node.\n");
 1275 #endif
 1276                 panic("unionfs_checklowervp");
 1277         }
 1278 #endif
 1279         return (unp->un_lowervp);
 1280 }
 1281 #endif

Cache object: 27cff2341b2b19fe03ada01a9445a3d3


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