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 nameidata nd;
  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(&nd.ni_cnd, 0, sizeof(struct componentname));
  791         NDPREINIT(&nd);
  792 
  793         if ((error = VOP_GETATTR(lvp, &lva, cnp->cn_cred)))
  794                 goto unionfs_mkshadowdir_abort;
  795 
  796         if ((error = unionfs_relookup(udvp, &uvp, cnp, &nd.ni_cnd, td,
  797             cnp->cn_nameptr, cnp->cn_namelen, CREATE)))
  798                 goto unionfs_mkshadowdir_abort;
  799         if (uvp != NULLVP) {
  800                 if (udvp == uvp)
  801                         vrele(uvp);
  802                 else
  803                         vput(uvp);
  804 
  805                 error = EEXIST;
  806                 goto unionfs_mkshadowdir_free_out;
  807         }
  808 
  809         if ((error = vn_start_write(udvp, &mp, V_WAIT | PCATCH)))
  810                 goto unionfs_mkshadowdir_free_out;
  811         unionfs_create_uppervattr_core(ump, &lva, &va, td);
  812 
  813         error = VOP_MKDIR(udvp, &uvp, &nd.ni_cnd, &va);
  814 
  815         if (!error) {
  816                 unionfs_node_update(unp, uvp, td);
  817 
  818                 /*
  819                  * XXX The bug which cannot set uid/gid was corrected.
  820                  * Ignore errors.
  821                  */
  822                 va.va_type = VNON;
  823                 VOP_SETATTR(uvp, &va, nd.ni_cnd.cn_cred);
  824         }
  825         vn_finished_write(mp);
  826 
  827 unionfs_mkshadowdir_free_out:
  828         if (nd.ni_cnd.cn_flags & HASBUF) {
  829                 uma_zfree(namei_zone, nd.ni_cnd.cn_pnbuf);
  830                 nd.ni_cnd.cn_flags &= ~HASBUF;
  831         }
  832 
  833 unionfs_mkshadowdir_abort:
  834         cnp->cn_cred = credbk;
  835         chgproccnt(cred->cr_ruidinfo, -1, 0);
  836         crfree(cred);
  837 
  838         return (error);
  839 }
  840 
  841 /*
  842  * Create a new whiteout.
  843  * 
  844  * dvp should be locked on entry and will be locked on return.
  845  */
  846 int
  847 unionfs_mkwhiteout(struct vnode *dvp, struct componentname *cnp,
  848                    struct thread *td, char *path)
  849 {
  850         int             error;
  851         struct vnode   *wvp;
  852         struct nameidata nd;
  853         struct mount   *mp;
  854 
  855         if (path == NULL)
  856                 path = cnp->cn_nameptr;
  857 
  858         wvp = NULLVP;
  859         NDPREINIT(&nd);
  860         if ((error = unionfs_relookup(dvp, &wvp, cnp, &nd.ni_cnd, td, path,
  861             strlen(path), CREATE)))
  862                 return (error);
  863         if (wvp != NULLVP) {
  864                 if (nd.ni_cnd.cn_flags & HASBUF) {
  865                         uma_zfree(namei_zone, nd.ni_cnd.cn_pnbuf);
  866                         nd.ni_cnd.cn_flags &= ~HASBUF;
  867                 }
  868                 if (dvp == wvp)
  869                         vrele(wvp);
  870                 else
  871                         vput(wvp);
  872 
  873                 return (EEXIST);
  874         }
  875 
  876         if ((error = vn_start_write(dvp, &mp, V_WAIT | PCATCH)))
  877                 goto unionfs_mkwhiteout_free_out;
  878         error = VOP_WHITEOUT(dvp, &nd.ni_cnd, CREATE);
  879 
  880         vn_finished_write(mp);
  881 
  882 unionfs_mkwhiteout_free_out:
  883         if (nd.ni_cnd.cn_flags & HASBUF) {
  884                 uma_zfree(namei_zone, nd.ni_cnd.cn_pnbuf);
  885                 nd.ni_cnd.cn_flags &= ~HASBUF;
  886         }
  887 
  888         return (error);
  889 }
  890 
  891 /*
  892  * Create a new vnode for create a new shadow file.
  893  * 
  894  * If an error is returned, *vpp will be invalid, otherwise it will hold a
  895  * locked, referenced and opened vnode.
  896  * 
  897  * unp is never updated.
  898  */
  899 static int
  900 unionfs_vn_create_on_upper(struct vnode **vpp, struct vnode *udvp,
  901                            struct unionfs_node *unp, struct vattr *uvap,
  902                            struct thread *td)
  903 {
  904         struct unionfs_mount *ump;
  905         struct vnode   *vp;
  906         struct vnode   *lvp;
  907         struct ucred   *cred;
  908         struct vattr    lva;
  909         int             fmode;
  910         int             error;
  911         struct nameidata nd;
  912 
  913         ump = MOUNTTOUNIONFSMOUNT(UNIONFSTOV(unp)->v_mount);
  914         vp = NULLVP;
  915         lvp = unp->un_lowervp;
  916         cred = td->td_ucred;
  917         fmode = FFLAGS(O_WRONLY | O_CREAT | O_TRUNC | O_EXCL);
  918         error = 0;
  919 
  920         if ((error = VOP_GETATTR(lvp, &lva, cred)) != 0)
  921                 return (error);
  922         unionfs_create_uppervattr_core(ump, &lva, uvap, td);
  923 
  924         if (unp->un_path == NULL)
  925                 panic("unionfs: un_path is null");
  926 
  927         nd.ni_cnd.cn_namelen = strlen(unp->un_path);
  928         nd.ni_cnd.cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK);
  929         bcopy(unp->un_path, nd.ni_cnd.cn_pnbuf, nd.ni_cnd.cn_namelen + 1);
  930         nd.ni_cnd.cn_nameiop = CREATE;
  931         nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | HASBUF | SAVENAME |
  932             ISLASTCN;
  933         nd.ni_cnd.cn_lkflags = LK_EXCLUSIVE;
  934         nd.ni_cnd.cn_thread = td;
  935         nd.ni_cnd.cn_cred = cred;
  936         nd.ni_cnd.cn_nameptr = nd.ni_cnd.cn_pnbuf;
  937         NDPREINIT(&nd);
  938 
  939         vref(udvp);
  940         if ((error = relookup(udvp, &vp, &nd.ni_cnd)) != 0)
  941                 goto unionfs_vn_create_on_upper_free_out2;
  942         vrele(udvp);
  943 
  944         if (vp != NULLVP) {
  945                 if (vp == udvp)
  946                         vrele(vp);
  947                 else
  948                         vput(vp);
  949                 error = EEXIST;
  950                 goto unionfs_vn_create_on_upper_free_out1;
  951         }
  952 
  953         if ((error = VOP_CREATE(udvp, &vp, &nd.ni_cnd, uvap)) != 0)
  954                 goto unionfs_vn_create_on_upper_free_out1;
  955 
  956         if ((error = VOP_OPEN(vp, fmode, cred, td, NULL)) != 0) {
  957                 vput(vp);
  958                 goto unionfs_vn_create_on_upper_free_out1;
  959         }
  960         error = VOP_ADD_WRITECOUNT(vp, 1);
  961         CTR3(KTR_VFS, "%s: vp %p v_writecount increased to %d",  __func__, vp,
  962             vp->v_writecount);
  963         if (error == 0) {
  964                 *vpp = vp;
  965         } else {
  966                 VOP_CLOSE(vp, fmode, cred, td);
  967         }
  968 
  969 unionfs_vn_create_on_upper_free_out1:
  970         VOP_UNLOCK(udvp);
  971 
  972 unionfs_vn_create_on_upper_free_out2:
  973         if (nd.ni_cnd.cn_flags & HASBUF) {
  974                 uma_zfree(namei_zone, nd.ni_cnd.cn_pnbuf);
  975                 nd.ni_cnd.cn_flags &= ~HASBUF;
  976         }
  977 
  978         return (error);
  979 }
  980 
  981 /*
  982  * Copy from lvp to uvp.
  983  * 
  984  * lvp and uvp should be locked and opened on entry and will be locked and
  985  * opened on return.
  986  */
  987 static int
  988 unionfs_copyfile_core(struct vnode *lvp, struct vnode *uvp,
  989                       struct ucred *cred, struct thread *td)
  990 {
  991         int             error;
  992         off_t           offset;
  993         int             count;
  994         int             bufoffset;
  995         char           *buf;
  996         struct uio      uio;
  997         struct iovec    iov;
  998 
  999         error = 0;
 1000         memset(&uio, 0, sizeof(uio));
 1001 
 1002         uio.uio_td = td;
 1003         uio.uio_segflg = UIO_SYSSPACE;
 1004         uio.uio_offset = 0;
 1005 
 1006         buf = malloc(MAXBSIZE, M_TEMP, M_WAITOK);
 1007 
 1008         while (error == 0) {
 1009                 offset = uio.uio_offset;
 1010 
 1011                 uio.uio_iov = &iov;
 1012                 uio.uio_iovcnt = 1;
 1013                 iov.iov_base = buf;
 1014                 iov.iov_len = MAXBSIZE;
 1015                 uio.uio_resid = iov.iov_len;
 1016                 uio.uio_rw = UIO_READ;
 1017 
 1018                 if ((error = VOP_READ(lvp, &uio, 0, cred)) != 0)
 1019                         break;
 1020                 if ((count = MAXBSIZE - uio.uio_resid) == 0)
 1021                         break;
 1022 
 1023                 bufoffset = 0;
 1024                 while (bufoffset < count) {
 1025                         uio.uio_iov = &iov;
 1026                         uio.uio_iovcnt = 1;
 1027                         iov.iov_base = buf + bufoffset;
 1028                         iov.iov_len = count - bufoffset;
 1029                         uio.uio_offset = offset + bufoffset;
 1030                         uio.uio_resid = iov.iov_len;
 1031                         uio.uio_rw = UIO_WRITE;
 1032 
 1033                         if ((error = VOP_WRITE(uvp, &uio, 0, cred)) != 0)
 1034                                 break;
 1035 
 1036                         bufoffset += (count - bufoffset) - uio.uio_resid;
 1037                 }
 1038 
 1039                 uio.uio_offset = offset + bufoffset;
 1040         }
 1041 
 1042         free(buf, M_TEMP);
 1043 
 1044         return (error);
 1045 }
 1046 
 1047 /*
 1048  * Copy file from lower to upper.
 1049  * 
 1050  * If you need copy of the contents, set 1 to docopy. Otherwise, set 0 to
 1051  * docopy.
 1052  * 
 1053  * If no error returned, unp will be updated.
 1054  */
 1055 int
 1056 unionfs_copyfile(struct unionfs_node *unp, int docopy, struct ucred *cred,
 1057                  struct thread *td)
 1058 {
 1059         int             error;
 1060         struct mount   *mp;
 1061         struct vnode   *udvp;
 1062         struct vnode   *lvp;
 1063         struct vnode   *uvp;
 1064         struct vattr    uva;
 1065 
 1066         lvp = unp->un_lowervp;
 1067         uvp = NULLVP;
 1068 
 1069         if ((UNIONFSTOV(unp)->v_mount->mnt_flag & MNT_RDONLY))
 1070                 return (EROFS);
 1071         if (unp->un_dvp == NULLVP)
 1072                 return (EINVAL);
 1073         if (unp->un_uppervp != NULLVP)
 1074                 return (EEXIST);
 1075         udvp = VTOUNIONFS(unp->un_dvp)->un_uppervp;
 1076         if (udvp == NULLVP)
 1077                 return (EROFS);
 1078         if ((udvp->v_mount->mnt_flag & MNT_RDONLY))
 1079                 return (EROFS);
 1080 
 1081         error = VOP_ACCESS(lvp, VREAD, cred, td);
 1082         if (error != 0)
 1083                 return (error);
 1084 
 1085         if ((error = vn_start_write(udvp, &mp, V_WAIT | PCATCH)) != 0)
 1086                 return (error);
 1087         error = unionfs_vn_create_on_upper(&uvp, udvp, unp, &uva, td);
 1088         if (error != 0) {
 1089                 vn_finished_write(mp);
 1090                 return (error);
 1091         }
 1092 
 1093         if (docopy != 0) {
 1094                 error = VOP_OPEN(lvp, FREAD, cred, td, NULL);
 1095                 if (error == 0) {
 1096                         error = unionfs_copyfile_core(lvp, uvp, cred, td);
 1097                         VOP_CLOSE(lvp, FREAD, cred, td);
 1098                 }
 1099         }
 1100         VOP_CLOSE(uvp, FWRITE, cred, td);
 1101         VOP_ADD_WRITECOUNT_CHECKED(uvp, -1);
 1102         CTR3(KTR_VFS, "%s: vp %p v_writecount decreased to %d", __func__, uvp,
 1103             uvp->v_writecount);
 1104 
 1105         vn_finished_write(mp);
 1106 
 1107         if (error == 0) {
 1108                 /* Reset the attributes. Ignore errors. */
 1109                 uva.va_type = VNON;
 1110                 VOP_SETATTR(uvp, &uva, cred);
 1111         }
 1112 
 1113         unionfs_node_update(unp, uvp, td);
 1114 
 1115         return (error);
 1116 }
 1117 
 1118 /*
 1119  * It checks whether vp can rmdir. (check empty)
 1120  *
 1121  * vp is unionfs vnode.
 1122  * vp should be locked.
 1123  */
 1124 int
 1125 unionfs_check_rmdir(struct vnode *vp, struct ucred *cred, struct thread *td)
 1126 {
 1127         int             error;
 1128         int             eofflag;
 1129         int             lookuperr;
 1130         struct vnode   *uvp;
 1131         struct vnode   *lvp;
 1132         struct vnode   *tvp;
 1133         struct vattr    va;
 1134         struct componentname cn;
 1135         /*
 1136          * The size of buf needs to be larger than DIRBLKSIZ.
 1137          */
 1138         char            buf[256 * 6];
 1139         struct dirent  *dp;
 1140         struct dirent  *edp;
 1141         struct uio      uio;
 1142         struct iovec    iov;
 1143 
 1144         ASSERT_VOP_ELOCKED(vp, "unionfs_check_rmdir");
 1145 
 1146         eofflag = 0;
 1147         uvp = UNIONFSVPTOUPPERVP(vp);
 1148         lvp = UNIONFSVPTOLOWERVP(vp);
 1149 
 1150         /* check opaque */
 1151         if ((error = VOP_GETATTR(uvp, &va, cred)) != 0)
 1152                 return (error);
 1153         if (va.va_flags & OPAQUE)
 1154                 return (0);
 1155 
 1156         /* open vnode */
 1157 #ifdef MAC
 1158         if ((error = mac_vnode_check_open(cred, vp, VEXEC|VREAD)) != 0)
 1159                 return (error);
 1160 #endif
 1161         if ((error = VOP_ACCESS(vp, VEXEC|VREAD, cred, td)) != 0)
 1162                 return (error);
 1163         if ((error = VOP_OPEN(vp, FREAD, cred, td, NULL)) != 0)
 1164                 return (error);
 1165 
 1166         uio.uio_rw = UIO_READ;
 1167         uio.uio_segflg = UIO_SYSSPACE;
 1168         uio.uio_td = td;
 1169         uio.uio_offset = 0;
 1170 
 1171 #ifdef MAC
 1172         error = mac_vnode_check_readdir(td->td_ucred, lvp);
 1173 #endif
 1174         while (!error && !eofflag) {
 1175                 iov.iov_base = buf;
 1176                 iov.iov_len = sizeof(buf);
 1177                 uio.uio_iov = &iov;
 1178                 uio.uio_iovcnt = 1;
 1179                 uio.uio_resid = iov.iov_len;
 1180 
 1181                 error = VOP_READDIR(lvp, &uio, cred, &eofflag, NULL, NULL);
 1182                 if (error != 0)
 1183                         break;
 1184                 if (eofflag == 0 && uio.uio_resid == sizeof(buf)) {
 1185 #ifdef DIAGNOSTIC
 1186                         panic("bad readdir response from lower FS.");
 1187 #endif
 1188                         break;
 1189                 }
 1190 
 1191                 edp = (struct dirent*)&buf[sizeof(buf) - uio.uio_resid];
 1192                 for (dp = (struct dirent*)buf; !error && dp < edp;
 1193                      dp = (struct dirent*)((caddr_t)dp + dp->d_reclen)) {
 1194                         if (dp->d_type == DT_WHT || dp->d_fileno == 0 ||
 1195                             (dp->d_namlen == 1 && dp->d_name[0] == '.') ||
 1196                             (dp->d_namlen == 2 && !bcmp(dp->d_name, "..", 2)))
 1197                                 continue;
 1198 
 1199                         cn.cn_namelen = dp->d_namlen;
 1200                         cn.cn_pnbuf = NULL;
 1201                         cn.cn_nameptr = dp->d_name;
 1202                         cn.cn_nameiop = LOOKUP;
 1203                         cn.cn_flags = (LOCKPARENT | LOCKLEAF | SAVENAME | RDONLY | ISLASTCN);
 1204                         cn.cn_lkflags = LK_EXCLUSIVE;
 1205                         cn.cn_thread = td;
 1206                         cn.cn_cred = cred;
 1207 
 1208                         /*
 1209                          * check entry in lower.
 1210                          * Sometimes, readdir function returns
 1211                          * wrong entry.
 1212                          */
 1213                         lookuperr = VOP_LOOKUP(lvp, &tvp, &cn);
 1214 
 1215                         if (!lookuperr)
 1216                                 vput(tvp);
 1217                         else
 1218                                 continue; /* skip entry */
 1219 
 1220                         /*
 1221                          * check entry
 1222                          * If it has no exist/whiteout entry in upper,
 1223                          * directory is not empty.
 1224                          */
 1225                         cn.cn_flags = (LOCKPARENT | LOCKLEAF | SAVENAME | RDONLY | ISLASTCN);
 1226                         lookuperr = VOP_LOOKUP(uvp, &tvp, &cn);
 1227 
 1228                         if (!lookuperr)
 1229                                 vput(tvp);
 1230 
 1231                         /* ignore exist or whiteout entry */
 1232                         if (!lookuperr ||
 1233                             (lookuperr == ENOENT && (cn.cn_flags & ISWHITEOUT)))
 1234                                 continue;
 1235 
 1236                         error = ENOTEMPTY;
 1237                 }
 1238         }
 1239 
 1240         /* close vnode */
 1241         VOP_CLOSE(vp, FREAD, cred, td);
 1242 
 1243         return (error);
 1244 }
 1245 
 1246 #ifdef DIAGNOSTIC
 1247 
 1248 struct vnode   *
 1249 unionfs_checkuppervp(struct vnode *vp, char *fil, int lno)
 1250 {
 1251         struct unionfs_node *unp;
 1252 
 1253         unp = VTOUNIONFS(vp);
 1254 
 1255 #ifdef notyet
 1256         if (vp->v_op != unionfs_vnodeop_p) {
 1257                 printf("unionfs_checkuppervp: on non-unionfs-node.\n");
 1258 #ifdef KDB
 1259                 kdb_enter(KDB_WHY_UNIONFS,
 1260                     "unionfs_checkuppervp: on non-unionfs-node.\n");
 1261 #endif
 1262                 panic("unionfs_checkuppervp");
 1263         }
 1264 #endif
 1265         return (unp->un_uppervp);
 1266 }
 1267 
 1268 struct vnode   *
 1269 unionfs_checklowervp(struct vnode *vp, char *fil, int lno)
 1270 {
 1271         struct unionfs_node *unp;
 1272 
 1273         unp = VTOUNIONFS(vp);
 1274 
 1275 #ifdef notyet
 1276         if (vp->v_op != unionfs_vnodeop_p) {
 1277                 printf("unionfs_checklowervp: on non-unionfs-node.\n");
 1278 #ifdef KDB
 1279                 kdb_enter(KDB_WHY_UNIONFS,
 1280                     "unionfs_checklowervp: on non-unionfs-node.\n");
 1281 #endif
 1282                 panic("unionfs_checklowervp");
 1283         }
 1284 #endif
 1285         return (unp->un_lowervp);
 1286 }
 1287 #endif

Cache object: 9af2e6315eb142c0834d725a32098d96


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