From: zhangyi (F) Date: Tue, 31 Oct 2017 20:57:00 +0000 (+0200) Subject: ovl: simplify ovl_check_empty_and_clear() X-Git-Tag: v4.15-rc1~63^2~27 X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=commitdiff_plain;h=95e598e7ace2d89717cc3370c2126570667e2007;p=linux.git ovl: simplify ovl_check_empty_and_clear() 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) Signed-off-by: Amir Goldstein Signed-off-by: Miklos Szeredi --- diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index cc961a3bd3bd..4edef400fe51 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c @@ -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: diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c index 95d12755f847..a5ad5b33b599 100644 --- a/fs/overlayfs/readdir.c +++ b/fs/overlayfs/readdir.c @@ -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);