summaryrefslogtreecommitdiffstats
path: root/fs/overlayfs
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2014-12-13 00:59:44 +0100
committerMiklos Szeredi <mszeredi@suse.cz>2014-12-13 00:59:44 +0100
commit9d7459d834c28f55c82f1737f638a6c90e0c0e0f (patch)
treef84ddaacf935a2bc411b79e637cd73e109a56225 /fs/overlayfs
parent5ef88da56a77bfb3b9631f5e5775f3bff86b6219 (diff)
downloadlinux-9d7459d834c28f55c82f1737f638a6c90e0c0e0f.tar.bz2
ovl: multi-layer readdir
If multiple lower layers exist, merge them as well in readdir according to the same rules as merging upper with lower. I.e. take whiteouts and opaque directories into account on all but the lowers layer. Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Diffstat (limited to 'fs/overlayfs')
-rw-r--r--fs/overlayfs/readdir.c43
-rw-r--r--fs/overlayfs/super.c3
2 files changed, 24 insertions, 22 deletions
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
index 481e44873b65..dfef6ca53dfe 100644
--- a/fs/overlayfs/readdir.c
+++ b/fs/overlayfs/readdir.c
@@ -261,35 +261,34 @@ static void ovl_dir_reset(struct file *file)
static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list)
{
int err;
- struct path lowerpath;
- struct path upperpath;
+ struct path realpath;
struct ovl_readdir_data rdd = {
.ctx.actor = ovl_fill_merge,
.list = list,
.root = RB_ROOT,
.is_merge = false,
};
-
- ovl_path_lower(dentry, &lowerpath);
- ovl_path_upper(dentry, &upperpath);
-
- if (upperpath.dentry) {
- rdd.dir = upperpath.dentry;
- err = ovl_dir_read(&upperpath, &rdd);
- if (err)
- goto out;
- }
- if (lowerpath.dentry) {
- /*
- * Insert lowerpath entries before upperpath ones, this allows
- * offsets to be reasonably constant
- */
- list_add(&rdd.middle, rdd.list);
- rdd.is_merge = true;
- err = ovl_dir_read(&lowerpath, &rdd);
- list_del(&rdd.middle);
+ int idx, next;
+
+ for (idx = 0; idx != -1; idx = next) {
+ next = ovl_path_next(idx, dentry, &realpath);
+
+ if (next != -1) {
+ rdd.dir = realpath.dentry;
+ err = ovl_dir_read(&realpath, &rdd);
+ if (err)
+ break;
+ } else {
+ /*
+ * Insert lowest layer entries before upper ones, this
+ * allows offsets to be reasonably constant
+ */
+ list_add(&rdd.middle, rdd.list);
+ rdd.is_merge = true;
+ err = ovl_dir_read(&realpath, &rdd);
+ list_del(&rdd.middle);
+ }
}
-out:
return err;
}
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index 07e4c576e93e..c245043aa1b9 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -81,6 +81,9 @@ enum ovl_path_type ovl_path_type(struct dentry *dentry)
} else if (!oe->opaque) {
type |= __OVL_PATH_PURE;
}
+ } else {
+ if (oe->numlower > 1)
+ type |= __OVL_PATH_MERGE;
}
return type;
}