aboutsummaryrefslogtreecommitdiffstats
path: root/fs/overlayfs/readdir.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/overlayfs/readdir.c')
-rw-r--r--fs/overlayfs/readdir.c53
1 files changed, 45 insertions, 8 deletions
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
index fdaf28f75e12..6ec1e43a9a54 100644
--- a/fs/overlayfs/readdir.c
+++ b/fs/overlayfs/readdir.c
@@ -36,13 +36,14 @@ struct ovl_dir_cache {
36 36
37struct ovl_readdir_data { 37struct ovl_readdir_data {
38 struct dir_context ctx; 38 struct dir_context ctx;
39 bool is_merge; 39 bool is_lowest;
40 struct rb_root root; 40 struct rb_root root;
41 struct list_head *list; 41 struct list_head *list;
42 struct list_head middle; 42 struct list_head middle;
43 struct ovl_cache_entry *first_maybe_whiteout; 43 struct ovl_cache_entry *first_maybe_whiteout;
44 int count; 44 int count;
45 int err; 45 int err;
46 bool d_type_supported;
46}; 47};
47 48
48struct ovl_dir_file { 49struct ovl_dir_file {
@@ -139,9 +140,9 @@ static int ovl_cache_entry_add_rb(struct ovl_readdir_data *rdd,
139 return 0; 140 return 0;
140} 141}
141 142
142static int ovl_fill_lower(struct ovl_readdir_data *rdd, 143static int ovl_fill_lowest(struct ovl_readdir_data *rdd,
143 const char *name, int namelen, 144 const char *name, int namelen,
144 loff_t offset, u64 ino, unsigned int d_type) 145 loff_t offset, u64 ino, unsigned int d_type)
145{ 146{
146 struct ovl_cache_entry *p; 147 struct ovl_cache_entry *p;
147 148
@@ -193,10 +194,10 @@ static int ovl_fill_merge(struct dir_context *ctx, const char *name,
193 container_of(ctx, struct ovl_readdir_data, ctx); 194 container_of(ctx, struct ovl_readdir_data, ctx);
194 195
195 rdd->count++; 196 rdd->count++;
196 if (!rdd->is_merge) 197 if (!rdd->is_lowest)
197 return ovl_cache_entry_add_rb(rdd, name, namelen, ino, d_type); 198 return ovl_cache_entry_add_rb(rdd, name, namelen, ino, d_type);
198 else 199 else
199 return ovl_fill_lower(rdd, name, namelen, offset, ino, d_type); 200 return ovl_fill_lowest(rdd, name, namelen, offset, ino, d_type);
200} 201}
201 202
202static int ovl_check_whiteouts(struct dentry *dir, struct ovl_readdir_data *rdd) 203static int ovl_check_whiteouts(struct dentry *dir, struct ovl_readdir_data *rdd)
@@ -289,7 +290,7 @@ static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list)
289 .ctx.actor = ovl_fill_merge, 290 .ctx.actor = ovl_fill_merge,
290 .list = list, 291 .list = list,
291 .root = RB_ROOT, 292 .root = RB_ROOT,
292 .is_merge = false, 293 .is_lowest = false,
293 }; 294 };
294 int idx, next; 295 int idx, next;
295 296
@@ -306,7 +307,7 @@ static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list)
306 * allows offsets to be reasonably constant 307 * allows offsets to be reasonably constant
307 */ 308 */
308 list_add(&rdd.middle, rdd.list); 309 list_add(&rdd.middle, rdd.list);
309 rdd.is_merge = true; 310 rdd.is_lowest = true;
310 err = ovl_dir_read(&realpath, &rdd); 311 err = ovl_dir_read(&realpath, &rdd);
311 list_del(&rdd.middle); 312 list_del(&rdd.middle);
312 } 313 }
@@ -577,3 +578,39 @@ void ovl_cleanup_whiteouts(struct dentry *upper, struct list_head *list)
577 } 578 }
578 inode_unlock(upper->d_inode); 579 inode_unlock(upper->d_inode);
579} 580}
581
582static int ovl_check_d_type(struct dir_context *ctx, const char *name,
583 int namelen, loff_t offset, u64 ino,
584 unsigned int d_type)
585{
586 struct ovl_readdir_data *rdd =
587 container_of(ctx, struct ovl_readdir_data, ctx);
588
589 /* Even if d_type is not supported, DT_DIR is returned for . and .. */
590 if (!strncmp(name, ".", namelen) || !strncmp(name, "..", namelen))
591 return 0;
592
593 if (d_type != DT_UNKNOWN)
594 rdd->d_type_supported = true;
595
596 return 0;
597}
598
599/*
600 * Returns 1 if d_type is supported, 0 not supported/unknown. Negative values
601 * if error is encountered.
602 */
603int ovl_check_d_type_supported(struct path *realpath)
604{
605 int err;
606 struct ovl_readdir_data rdd = {
607 .ctx.actor = ovl_check_d_type,
608 .d_type_supported = false,
609 };
610
611 err = ovl_dir_read(realpath, &rdd);
612 if (err)
613 return err;
614
615 return rdd.d_type_supported;
616}