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

Cache object: 3adc17c7829edfba9c58acbd6acb584b


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