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

Cache object: cbfd5e0bde6fea98bd92be306caa3f56


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