Skip to content

Commit 45aebea

Browse files
rhvgoyalszmi
authored andcommitted
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>
1 parent fb5bb2c commit 45aebea

File tree

3 files changed

+53
-0
lines changed

3 files changed

+53
-0
lines changed

fs/overlayfs/overlayfs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ extern const struct file_operations ovl_dir_operations;
166166
int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list);
167167
void ovl_cleanup_whiteouts(struct dentry *upper, struct list_head *list);
168168
void ovl_cache_free(struct list_head *list);
169+
int ovl_check_d_type_supported(struct path *realpath);
169170

170171
/* inode.c */
171172
int ovl_setattr(struct dentry *dentry, struct iattr *attr);

fs/overlayfs/readdir.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ struct ovl_readdir_data {
4343
struct ovl_cache_entry *first_maybe_whiteout;
4444
int count;
4545
int err;
46+
bool d_type_supported;
4647
};
4748

4849
struct ovl_dir_file {
@@ -577,3 +578,39 @@ void ovl_cleanup_whiteouts(struct dentry *upper, struct list_head *list)
577578
}
578579
inode_unlock(upper->d_inode);
579580
}
581+
582+
static 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+
*/
603+
int 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+
}

fs/overlayfs/super.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,6 +1029,21 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
10291029
sb->s_flags |= MS_RDONLY;
10301030
ufs->workdir = NULL;
10311031
}
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+
}
10321047
}
10331048

10341049
err = -ENOMEM;

0 commit comments

Comments
 (0)