--- /dev/null
+From b09a30a9a4119d76185d3d21bb36497906ed5f34 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 Jan 2020 20:49:29 +0800
+Subject: ovl: add splice file read write helper
+
+From: Murphy Zhou <jencce.kernel@gmail.com>
+
+[ Upstream commit 1a980b8cbf0059a5308eea61522f232fd03002e2 ]
+
+Now overlayfs falls back to use default file splice read
+and write, which is not compatiple with overlayfs, returning
+EFAULT. xfstests generic/591 can reproduce part of this.
+
+Tested this patch with xfstests auto group tests.
+
+Signed-off-by: Murphy Zhou <jencce.kernel@gmail.com>
+Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/overlayfs/file.c | 47 +++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 47 insertions(+)
+
+diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c
+index 7a08a576f7b2..ab5e92897270 100644
+--- a/fs/overlayfs/file.c
++++ b/fs/overlayfs/file.c
+@@ -9,6 +9,9 @@
+ #include <linux/xattr.h>
+ #include <linux/uio.h>
+ #include <linux/uaccess.h>
++#include <linux/splice.h>
++#include <linux/mm.h>
++#include <linux/fs.h>
+ #include "overlayfs.h"
+
+ static char ovl_whatisit(struct inode *inode, struct inode *realinode)
+@@ -293,6 +296,48 @@ static ssize_t ovl_write_iter(struct kiocb *iocb, struct iov_iter *iter)
+ return ret;
+ }
+
++static ssize_t ovl_splice_read(struct file *in, loff_t *ppos,
++ struct pipe_inode_info *pipe, size_t len,
++ unsigned int flags)
++{
++ ssize_t ret;
++ struct fd real;
++ const struct cred *old_cred;
++
++ ret = ovl_real_fdget(in, &real);
++ if (ret)
++ return ret;
++
++ old_cred = ovl_override_creds(file_inode(in)->i_sb);
++ ret = generic_file_splice_read(real.file, ppos, pipe, len, flags);
++ revert_creds(old_cred);
++
++ ovl_file_accessed(in);
++ fdput(real);
++ return ret;
++}
++
++static ssize_t
++ovl_splice_write(struct pipe_inode_info *pipe, struct file *out,
++ loff_t *ppos, size_t len, unsigned int flags)
++{
++ struct fd real;
++ const struct cred *old_cred;
++ ssize_t ret;
++
++ ret = ovl_real_fdget(out, &real);
++ if (ret)
++ return ret;
++
++ old_cred = ovl_override_creds(file_inode(out)->i_sb);
++ ret = iter_file_splice_write(pipe, real.file, ppos, len, flags);
++ revert_creds(old_cred);
++
++ ovl_file_accessed(out);
++ fdput(real);
++ return ret;
++}
++
+ static int ovl_fsync(struct file *file, loff_t start, loff_t end, int datasync)
+ {
+ struct fd real;
+@@ -649,6 +694,8 @@ const struct file_operations ovl_file_operations = {
+ .fadvise = ovl_fadvise,
+ .unlocked_ioctl = ovl_ioctl,
+ .compat_ioctl = ovl_compat_ioctl,
++ .splice_read = ovl_splice_read,
++ .splice_write = ovl_splice_write,
+
+ .copy_file_range = ovl_copy_file_range,
+ .remap_file_range = ovl_remap_file_range,
+--
+2.30.2
+