aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVivek Goyal <vgoyal@redhat.com>2016-02-22 09:28:34 -0500
committerMiklos Szeredi <miklos@szeredi.hu>2016-03-21 12:31:45 -0400
commit45aebeaf4f67468f76bedf62923a576a519a9b68 (patch)
treeae92aff7e8351c838975e1401bf510bece7fa09b
parentfb5bb2c3b73df060d588b6521de5ab03589283f7 (diff)
ovl: Ensure upper filesystem supports d_type
In some instances xfs has been created with ftype=0 and there if a file on lower fs is removed, overlay leaves a whiteout in upper fs but that whiteout does not get filtered out and is visible to overlayfs users. And reason it does not get filtered out because upper filesystem does not report file type of whiteout as DT_CHR during iterate_dir(). So it seems to be a requirement that upper filesystem support d_type for overlayfs to work properly. Do this check during mount and fail if d_type is not supported. Suggested-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Vivek Goyal <vgoyal@redhat.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
-rw-r--r--fs/overlayfs/overlayfs.h1
-rw-r--r--fs/overlayfs/readdir.c37
-rw-r--r--fs/overlayfs/super.c15
3 files changed, 53 insertions, 0 deletions
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index 99b4168c36ff..6a7090f4a441 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -166,6 +166,7 @@ extern const struct file_operations ovl_dir_operations;
166int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list); 166int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list);
167void ovl_cleanup_whiteouts(struct dentry *upper, struct list_head *list); 167void ovl_cleanup_whiteouts(struct dentry *upper, struct list_head *list);
168void ovl_cache_free(struct list_head *list); 168void ovl_cache_free(struct list_head *list);
169int ovl_check_d_type_supported(struct path *realpath);
169 170
170/* inode.c */ 171/* inode.c */
171int ovl_setattr(struct dentry *dentry, struct iattr *attr); 172int ovl_setattr(struct dentry *dentry, struct iattr *attr);
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
index fdaf28f75e12..18d0a1625220 100644
--- a/fs/overlayfs/readdir.c
+++ b/fs/overlayfs/readdir.c
@@ -43,6 +43,7 @@ struct ovl_readdir_data {
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 {
@@ -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}
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index 6b0111ae2ceb..ef64984c9bbc 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -1029,6 +1029,21 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
1029 sb->s_flags |= MS_RDONLY; 1029 sb->s_flags |= MS_RDONLY;
1030 ufs->workdir = NULL; 1030 ufs->workdir = NULL;
1031 } 1031 }
1032
1033 /*
1034 * Upper should support d_type, else whiteouts are visible.
1035 * Given workdir and upper are on same fs, we can do
1036 * iterate_dir() on workdir.
1037 */
1038 err = ovl_check_d_type_supported(&workpath);
1039 if (err < 0)
1040 goto out_put_workdir;
1041
1042 if (!err) {
1043 pr_err("overlayfs: upper fs needs to support d_type.\n");
1044 err = -EINVAL;
1045 goto out_put_workdir;
1046 }
1032 } 1047 }
1033 1048
1034 err = -ENOMEM; 1049 err = -ENOMEM;