]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
ovl: simplify ovl_check_empty_and_clear()
authorzhangyi (F) <yi.zhang@huawei.com>
Tue, 31 Oct 2017 20:57:00 +0000 (22:57 +0200)
committerMiklos Szeredi <mszeredi@redhat.com>
Thu, 9 Nov 2017 09:23:27 +0000 (10:23 +0100)
Filter out non-whiteout non-upper entries from list of merge dir entries
while checking if merge dir is empty in ovl_check_empty_dir().
The remaining work for ovl_clear_empty() is to clear all entries on the
list.

[amir: split patch from rmdir bug fix]

Signed-off-by: zhangyi (F) <yi.zhang@huawei.com>
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
fs/overlayfs/dir.c
fs/overlayfs/readdir.c

index cc961a3bd3bdec34fcace34553f9e8cfb319db25..4edef400fe51f03e05c72eb8ce9dd82d76db4406 100644 (file)
@@ -300,7 +300,6 @@ static struct dentry *ovl_check_empty_and_clear(struct dentry *dentry)
 {
        int err;
        struct dentry *ret = NULL;
-       enum ovl_path_type type = ovl_path_type(dentry);
        LIST_HEAD(list);
 
        err = ovl_check_empty_dir(dentry, &list);
@@ -313,13 +312,13 @@ static struct dentry *ovl_check_empty_and_clear(struct dentry *dentry)
         * When removing an empty opaque directory, then it makes no sense to
         * replace it with an exact replica of itself.
         *
-        * If no upperdentry then skip clearing whiteouts.
+        * If upperdentry has whiteouts, clear them.
         *
         * Can race with copy-up, since we don't hold the upperdir mutex.
         * Doesn't matter, since copy-up can't create a non-empty directory
         * from an empty one.
         */
-       if (OVL_TYPE_UPPER(type) && OVL_TYPE_MERGE(type))
+       if (!list_empty(&list))
                ret = ovl_clear_empty(dentry, &list);
 
 out_free:
index 95d12755f847cc0e7058f631a220180583e08d47..a5ad5b33b5990e80cedde71c5134f2fbf7f701dd 100644 (file)
@@ -26,6 +26,7 @@ struct ovl_cache_entry {
        struct list_head l_node;
        struct rb_node node;
        struct ovl_cache_entry *next_maybe_whiteout;
+       bool is_upper;
        bool is_whiteout;
        char name[];
 };
@@ -158,6 +159,7 @@ static struct ovl_cache_entry *ovl_cache_entry_new(struct ovl_readdir_data *rdd,
        /* Defer setting d_ino for upper entry to ovl_iterate() */
        if (ovl_calc_d_ino(rdd, p))
                p->ino = 0;
+       p->is_upper = rdd->is_upper;
        p->is_whiteout = false;
 
        if (d_type == DT_CHR) {
@@ -851,7 +853,7 @@ const struct file_operations ovl_dir_operations = {
 int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list)
 {
        int err;
-       struct ovl_cache_entry *p;
+       struct ovl_cache_entry *p, *n;
        struct rb_root root = RB_ROOT;
 
        err = ovl_dir_read_merged(dentry, list, &root);
@@ -860,18 +862,29 @@ int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list)
 
        err = 0;
 
-       list_for_each_entry(p, list, l_node) {
-               if (p->is_whiteout)
-                       continue;
+       list_for_each_entry_safe(p, n, list, l_node) {
+               /*
+                * Select whiteouts in upperdir, they should
+                * be cleared when deleting this directory.
+                */
+               if (p->is_whiteout) {
+                       if (p->is_upper)
+                               continue;
+                       goto del_entry;
+               }
 
                if (p->name[0] == '.') {
                        if (p->len == 1)
-                               continue;
+                               goto del_entry;
                        if (p->len == 2 && p->name[1] == '.')
-                               continue;
+                               goto del_entry;
                }
                err = -ENOTEMPTY;
                break;
+
+del_entry:
+               list_del(&p->l_node);
+               kfree(p);
        }
 
        return err;
@@ -885,7 +898,7 @@ void ovl_cleanup_whiteouts(struct dentry *upper, struct list_head *list)
        list_for_each_entry(p, list, l_node) {
                struct dentry *dentry;
 
-               if (!p->is_whiteout)
+               if (WARN_ON(!p->is_whiteout || !p->is_upper))
                        continue;
 
                dentry = lookup_one_len(p->name, upper, p->len);