lkml.org 
[lkml]   [2009]   [Oct]   [21]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 12/41] union-mount: Allow removal of a directory
    Date
    From: Jan Blunck <jblunck@suse.de>

    do_whiteout() allows removal of a directory when it has whiteouts but
    is logically empty.

    XXX - This patch abuses readdir() to check if the union directory is
    logically empty - that is, all the entries are whiteouts (or "." or
    ".."). Currently, we have no clean VFS interface to ask the lower
    file system if a directory is empty.

    Fixes:
    - Add ->is_directory_empty() op
    - Add is_directory_empty flag to dentry (ugly dcache populate)
    - Ask underlying fs to remove it and look for an error return
    - (your idea here)

    Signed-off-by: Jan Blunck <jblunck@suse.de>
    Signed-off-by: Valerie Aurora <vaurora@redhat.com>
    ---
    fs/namei.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    1 files changed, 85 insertions(+), 0 deletions(-)

    diff --git a/fs/namei.c b/fs/namei.c
    index 5da1635..9a62c75 100644
    --- a/fs/namei.c
    +++ b/fs/namei.c
    @@ -2284,6 +2284,91 @@ int vfs_whiteout(struct inode *dir, struct dentry *dentry, int isdir)
    }

    /*
    + * This is abusing readdir to check if a union directory is logically empty.
    + * Al Viro barfed when he saw this, but Val said: "Well, at this point I'm
    + * aiming for working, pretty can come later"
    + */
    +static int filldir_is_empty(void *__buf, const char *name, int namlen,
    + loff_t offset, u64 ino, unsigned int d_type)
    +{
    + int *is_empty = (int *)__buf;
    +
    + switch (namlen) {
    + case 2:
    + if (name[1] != '.')
    + break;
    + case 1:
    + if (name[0] != '.')
    + break;
    + return 0;
    + }
    +
    + if (d_type == DT_WHT)
    + return 0;
    +
    + (*is_empty) = 0;
    + return 0;
    +}
    +
    +static int directory_is_empty(struct dentry *dentry, struct vfsmount *mnt)
    +{
    + struct file *file;
    + int err;
    + int is_empty = 1;
    +
    + BUG_ON(!S_ISDIR(dentry->d_inode->i_mode));
    +
    + /* references for the file pointer */
    + dget(dentry);
    + mntget(mnt);
    +
    + file = dentry_open(dentry, mnt, O_RDONLY, current_cred());
    + if (IS_ERR(file))
    + return 0;
    +
    + err = vfs_readdir(file, filldir_is_empty, &is_empty);
    +
    + fput(file);
    + return is_empty;
    +}
    +
    +static int do_whiteout(struct nameidata *nd, struct path *path, int isdir)
    +{
    + struct path safe = { .dentry = dget(nd->path.dentry),
    + .mnt = mntget(nd->path.mnt) };
    + struct dentry *dentry = path->dentry;
    + int err;
    +
    + err = may_whiteout(nd->path.dentry->d_inode, dentry, isdir);
    + if (err)
    + goto out;
    +
    + err = -ENOTEMPTY;
    + if (isdir && !directory_is_empty(path->dentry, path->mnt))
    + goto out;
    +
    + if (nd->path.dentry != dentry->d_parent) {
    + dentry = __lookup_hash(&path->dentry->d_name, nd->path.dentry,
    + nd);
    + err = PTR_ERR(dentry);
    + if (IS_ERR(dentry))
    + goto out;
    +
    + dput(path->dentry);
    + if (path->mnt != safe.mnt)
    + mntput(path->mnt);
    + path->mnt = nd->path.mnt;
    + path->dentry = dentry;
    + }
    +
    + err = vfs_whiteout(nd->path.dentry->d_inode, dentry, isdir);
    +
    +out:
    + path_put(&safe);
    + return err;
    +}
    +
    +/*
    * We try to drop the dentry early: we should have
    * a usage count of 2 if we're the only user of this
    * dentry, and if that is true (possibly after pruning
    --
    1.6.3.3


    \
     
     \ /
      Last update: 2009-10-21 21:25    [W:0.025 / U:60.784 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site