|
@@ -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);
|