summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVivek Goyal <vgoyal@redhat.com>2016-02-22 09:28:34 -0500
committerSeung-Woo Kim <sw0312.kim@samsung.com>2024-02-23 18:03:25 +0900
commite6c6af31eb8024ee5aeeef2da905149cbec0a882 (patch)
treec12af08273ae2fb6d4d446b96b5e64d6e8644007
parenta7f897be74021d5c60fc1861048fd3c8d27ad5c6 (diff)
downloademulator-kernel-e6c6af31eb8024ee5aeeef2da905149cbec0a882.tar.gz
emulator-kernel-e6c6af31eb8024ee5aeeef2da905149cbec0a882.tar.bz2
emulator-kernel-e6c6af31eb8024ee5aeeef2da905149cbec0a882.zip
ovl: Ensure upper filesystem supports d_type
commit 45aebeaf4f67468f76bedf62923a576a519a9b68 upstream. 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> Signed-off-by: SZ Lin (林上智) <sz.lin@moxa.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> [sw0312.kim: cherry-pick linux-4.4.y commit d5e678942de3 to fix smack deny issue on overlayfs] Signed-off-by: Seung-Woo Kim <sw0312.kim@samsung.com> Change-Id: I870cf090c0e52313208718fe87a3e4f7e7a3da08
-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 c319d5eaabcf..28316b292b8a 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -163,6 +163,7 @@ extern const struct file_operations ovl_dir_operations;
int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list);
void ovl_cleanup_whiteouts(struct dentry *upper, struct list_head *list);
void ovl_cache_free(struct list_head *list);
+int ovl_check_d_type_supported(struct path *realpath);
/* inode.c */
int ovl_setattr(struct dentry *dentry, struct iattr *attr);
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
index 299a6e1d6b77..0c59955c4653 100644
--- a/fs/overlayfs/readdir.c
+++ b/fs/overlayfs/readdir.c
@@ -43,6 +43,7 @@ struct ovl_readdir_data {
struct ovl_cache_entry *first_maybe_whiteout;
int count;
int err;
+ bool d_type_supported;
};
struct ovl_dir_file {
@@ -581,3 +582,39 @@ void ovl_cleanup_whiteouts(struct dentry *upper, struct list_head *list)
}
mutex_unlock(&upper->d_inode->i_mutex);
}
+
+static int ovl_check_d_type(struct dir_context *ctx, const char *name,
+ int namelen, loff_t offset, u64 ino,
+ unsigned int d_type)
+{
+ struct ovl_readdir_data *rdd =
+ container_of(ctx, struct ovl_readdir_data, ctx);
+
+ /* Even if d_type is not supported, DT_DIR is returned for . and .. */
+ if (!strncmp(name, ".", namelen) || !strncmp(name, "..", namelen))
+ return 0;
+
+ if (d_type != DT_UNKNOWN)
+ rdd->d_type_supported = true;
+
+ return 0;
+}
+
+/*
+ * Returns 1 if d_type is supported, 0 not supported/unknown. Negative values
+ * if error is encountered.
+ */
+int ovl_check_d_type_supported(struct path *realpath)
+{
+ int err;
+ struct ovl_readdir_data rdd = {
+ .ctx.actor = ovl_check_d_type,
+ .d_type_supported = false,
+ };
+
+ err = ovl_dir_read(realpath, &rdd);
+ if (err)
+ return err;
+
+ return rdd.d_type_supported;
+}
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index d70208c0de84..2de4e3a7d6e7 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -1054,6 +1054,21 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
sb->s_flags |= MS_RDONLY;
ufs->workdir = NULL;
}
+
+ /*
+ * Upper should support d_type, else whiteouts are visible.
+ * Given workdir and upper are on same fs, we can do
+ * iterate_dir() on workdir.
+ */
+ err = ovl_check_d_type_supported(&workpath);
+ if (err < 0)
+ goto out_put_workdir;
+
+ if (!err) {
+ pr_err("overlayfs: upper fs needs to support d_type.\n");
+ err = -EINVAL;
+ goto out_put_workdir;
+ }
}
err = -ENOMEM;