|
@@ -316,21 +316,37 @@ static inline int ovl_dir_read(struct path *realpath,
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Can we iterate real dir directly?
|
|
|
+ *
|
|
|
+ * Non-merge dir may contain whiteouts from a time it was a merge upper, before
|
|
|
+ * lower dir was removed under it and possibly before it was rotated from upper
|
|
|
+ * to lower layer.
|
|
|
+ */
|
|
|
+static bool ovl_dir_is_real(struct dentry *dir)
|
|
|
+{
|
|
|
+ return !ovl_test_flag(OVL_WHITEOUTS, d_inode(dir));
|
|
|
+}
|
|
|
+
|
|
|
static void ovl_dir_reset(struct file *file)
|
|
|
{
|
|
|
struct ovl_dir_file *od = file->private_data;
|
|
|
struct ovl_dir_cache *cache = od->cache;
|
|
|
struct dentry *dentry = file->f_path.dentry;
|
|
|
- enum ovl_path_type type = ovl_path_type(dentry);
|
|
|
+ bool is_real;
|
|
|
|
|
|
if (cache && ovl_dentry_version_get(dentry) != cache->version) {
|
|
|
ovl_cache_put(od, dentry);
|
|
|
od->cache = NULL;
|
|
|
od->cursor = NULL;
|
|
|
}
|
|
|
- WARN_ON(!od->is_real && !OVL_TYPE_MERGE(type));
|
|
|
- if (od->is_real && OVL_TYPE_MERGE(type))
|
|
|
+ is_real = ovl_dir_is_real(dentry);
|
|
|
+ if (od->is_real != is_real) {
|
|
|
+ /* is_real can only become false when dir is copied up */
|
|
|
+ if (WARN_ON(is_real))
|
|
|
+ return;
|
|
|
od->is_real = false;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list,
|
|
@@ -816,7 +832,7 @@ static int ovl_dir_open(struct inode *inode, struct file *file)
|
|
|
return PTR_ERR(realfile);
|
|
|
}
|
|
|
od->realfile = realfile;
|
|
|
- od->is_real = !OVL_TYPE_MERGE(type);
|
|
|
+ od->is_real = ovl_dir_is_real(file->f_path.dentry);
|
|
|
od->is_upper = OVL_TYPE_UPPER(type);
|
|
|
file->private_data = od;
|
|
|
|