Commit d1595119 authored by Amir Goldstein's avatar Amir Goldstein Committed by Miklos Szeredi

ovl: check for emptiness of redirect dir

Before introducing redirect_dir feature, the condition
!ovl_lower_positive(dentry) for a directory, implied that it is a pure
upper directory, which may be removed if empty.

Now that directory can be redirect, it is possible that upper does not
cover any lower (i.e. !ovl_lower_positive(dentry)), but the directory is a
merge (with redirected path) and maybe non empty.

Check for this case in ovl_remove_upper().

This change fixes the following test case from rename-pop-dir.py
of unionmount-testsuite:

    """Remove dir and rename old name"""
    d = ctx.non_empty_dir()
    d2 = ctx.no_dir()

    ctx.rmdir(d, err=ENOTEMPTY)
    ctx.rename(d, d2)
    ctx.rmdir(d, err=ENOENT)
    ctx.rmdir(d2, err=ENOTEMPTY)

./run --ov rename-pop-dir
/mnt/a/no_dir103: Expected error (Directory not empty) was not produced
Signed-off-by: default avatarAmir Goldstein <amir73il@gmail.com>
Signed-off-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
parent a6c60655
...@@ -674,8 +674,17 @@ static int ovl_remove_upper(struct dentry *dentry, bool is_dir) ...@@ -674,8 +674,17 @@ static int ovl_remove_upper(struct dentry *dentry, bool is_dir)
struct dentry *upperdir = ovl_dentry_upper(dentry->d_parent); struct dentry *upperdir = ovl_dentry_upper(dentry->d_parent);
struct inode *dir = upperdir->d_inode; struct inode *dir = upperdir->d_inode;
struct dentry *upper; struct dentry *upper;
struct dentry *opaquedir = NULL;
int err; int err;
/* Redirect dir can be !ovl_lower_positive && OVL_TYPE_MERGE */
if (is_dir && ovl_dentry_get_redirect(dentry)) {
opaquedir = ovl_check_empty_and_clear(dentry);
err = PTR_ERR(opaquedir);
if (IS_ERR(opaquedir))
goto out;
}
inode_lock_nested(dir, I_MUTEX_PARENT); inode_lock_nested(dir, I_MUTEX_PARENT);
upper = lookup_one_len(dentry->d_name.name, upperdir, upper = lookup_one_len(dentry->d_name.name, upperdir,
dentry->d_name.len); dentry->d_name.len);
...@@ -684,14 +693,15 @@ static int ovl_remove_upper(struct dentry *dentry, bool is_dir) ...@@ -684,14 +693,15 @@ static int ovl_remove_upper(struct dentry *dentry, bool is_dir)
goto out_unlock; goto out_unlock;
err = -ESTALE; err = -ESTALE;
if (upper == ovl_dentry_upper(dentry)) { if ((opaquedir && upper != opaquedir) ||
(!opaquedir && upper != ovl_dentry_upper(dentry)))
goto out_dput_upper;
if (is_dir) if (is_dir)
err = vfs_rmdir(dir, upper); err = vfs_rmdir(dir, upper);
else else
err = vfs_unlink(dir, upper, NULL); err = vfs_unlink(dir, upper, NULL);
ovl_dentry_version_inc(dentry->d_parent); ovl_dentry_version_inc(dentry->d_parent);
}
dput(upper);
/* /*
* Keeping this dentry hashed would mean having to release * Keeping this dentry hashed would mean having to release
...@@ -701,9 +711,12 @@ static int ovl_remove_upper(struct dentry *dentry, bool is_dir) ...@@ -701,9 +711,12 @@ static int ovl_remove_upper(struct dentry *dentry, bool is_dir)
*/ */
if (!err) if (!err)
d_drop(dentry); d_drop(dentry);
out_dput_upper:
dput(upper);
out_unlock: out_unlock:
inode_unlock(dir); inode_unlock(dir);
dput(opaquedir);
out:
return err; return err;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment