aboutsummaryrefslogtreecommitdiff
path: root/fs/overlayfs/readdir.c
diff options
context:
space:
mode:
authorGravatar Amir Goldstein <amir73il@gmail.com> 2020-09-29 15:28:47 +0800
committerGravatar Miklos Szeredi <mszeredi@redhat.com> 2020-10-06 15:38:14 +0200
commit61536bed2149b082748f8a38c593d915ff3e5957 (patch)
tree650bd20e89098381d36658935b3554ccee1b33ee /fs/overlayfs/readdir.c
parentovl: rearrange ovl_can_list() (diff)
downloadlinux-61536bed2149b082748f8a38c593d915ff3e5957.tar.gz
linux-61536bed2149b082748f8a38c593d915ff3e5957.tar.bz2
linux-61536bed2149b082748f8a38c593d915ff3e5957.zip
ovl: support [S|G]ETFLAGS and FS[S|G]ETXATTR ioctls for directories
[S|G]ETFLAGS and FS[S|G]ETXATTR ioctls are applicable to both files and directories, so add ioctl operations to dir as well. We teach ovl_real_fdget() to get the realfile of directories which use a different type of file->private_data. Ifdef away compat ioctl implementation to conform to standard practice. With this change, xfstest generic/079 which tests these ioctls on files and directories passes. Signed-off-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Xiao Yang <yangx.jy@cn.fujitsu.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Diffstat (limited to 'fs/overlayfs/readdir.c')
-rw-r--r--fs/overlayfs/readdir.c44
1 files changed, 35 insertions, 9 deletions
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
index 596002054ac6..01620ebae1bd 100644
--- a/fs/overlayfs/readdir.c
+++ b/fs/overlayfs/readdir.c
@@ -840,7 +840,7 @@ out_unlock:
return res;
}
-static struct file *ovl_dir_open_realfile(struct file *file,
+static struct file *ovl_dir_open_realfile(const struct file *file,
struct path *realpath)
{
struct file *res;
@@ -853,19 +853,22 @@ static struct file *ovl_dir_open_realfile(struct file *file,
return res;
}
-static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end,
- int datasync)
+/*
+ * Like ovl_real_fdget(), returns upperfile if dir was copied up since open.
+ * Unlike ovl_real_fdget(), this caches upperfile in file->private_data.
+ *
+ * TODO: use same abstract type for file->private_data of dir and file so
+ * upperfile could also be cached for files as well.
+ */
+struct file *ovl_dir_real_file(const struct file *file, bool want_upper)
{
+
struct ovl_dir_file *od = file->private_data;
struct dentry *dentry = file->f_path.dentry;
struct file *realfile = od->realfile;
- /* Nothing to sync for lower */
if (!OVL_TYPE_UPPER(ovl_path_type(dentry)))
- return 0;
-
- if (!ovl_should_sync(OVL_FS(dentry->d_sb)))
- return 0;
+ return want_upper ? NULL : realfile;
/*
* Need to check if we started out being a lower dir, but got copied up
@@ -884,7 +887,7 @@ static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end,
if (!od->upperfile) {
if (IS_ERR(realfile)) {
inode_unlock(inode);
- return PTR_ERR(realfile);
+ return realfile;
}
smp_store_release(&od->upperfile, realfile);
} else {
@@ -897,6 +900,25 @@ static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end,
}
}
+ return realfile;
+}
+
+static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end,
+ int datasync)
+{
+ struct file *realfile;
+ int err;
+
+ if (!ovl_should_sync(OVL_FS(file->f_path.dentry->d_sb)))
+ return 0;
+
+ realfile = ovl_dir_real_file(file, true);
+ err = PTR_ERR_OR_ZERO(realfile);
+
+ /* Nothing to sync for lower */
+ if (!realfile || err)
+ return err;
+
return vfs_fsync_range(realfile, start, end, datasync);
}
@@ -949,6 +971,10 @@ const struct file_operations ovl_dir_operations = {
.llseek = ovl_dir_llseek,
.fsync = ovl_dir_fsync,
.release = ovl_dir_release,
+ .unlocked_ioctl = ovl_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = ovl_compat_ioctl,
+#endif
};
int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list)