From: Miklos Szeredi mszeredi@redhat.com
stable inclusion from stable-5.10.73 commit 1bc2f315a215585f8bc07257542e67373c86e801 bugzilla: 182983 https://gitee.com/openeuler/kernel/issues/I4I3M0
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
commit 1dc1eed46f9fa4cb8a07baa24fb44c96d6dd35c9 upstream.
Normally the check at open time suffices, but e.g loop device does set IOCB_DIRECT after doing its own checks (which are not sufficent for overlayfs).
Make sure we don't call the underlying filesystem read/write method with the IOCB_DIRECT if it's not supported.
Reported-by: Huang Jianan huangjianan@oppo.com Fixes: 16914e6fc7e1 ("ovl: add ovl_read_iter()") Cc: stable@vger.kernel.org # v4.19 Tested-by: Huang Jianan huangjianan@oppo.com Signed-off-by: Miklos Szeredi mszeredi@redhat.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Chen Jun chenjun102@huawei.com Acked-by: Weilong Chen chenweilong@huawei.com
Signed-off-by: Chen Jun chenjun102@huawei.com --- fs/overlayfs/file.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c index 5c5c3972ebd0..f7135777cb4e 100644 --- a/fs/overlayfs/file.c +++ b/fs/overlayfs/file.c @@ -301,6 +301,12 @@ static ssize_t ovl_read_iter(struct kiocb *iocb, struct iov_iter *iter) if (ret) return ret;
+ ret = -EINVAL; + if (iocb->ki_flags & IOCB_DIRECT && + (!real.file->f_mapping->a_ops || + !real.file->f_mapping->a_ops->direct_IO)) + goto out_fdput; + old_cred = ovl_override_creds(file_inode(file)->i_sb); if (is_sync_kiocb(iocb)) { ret = vfs_iter_read(real.file, iter, &iocb->ki_pos, @@ -325,7 +331,7 @@ static ssize_t ovl_read_iter(struct kiocb *iocb, struct iov_iter *iter) out: revert_creds(old_cred); ovl_file_accessed(file); - +out_fdput: fdput(real);
return ret; @@ -354,6 +360,12 @@ static ssize_t ovl_write_iter(struct kiocb *iocb, struct iov_iter *iter) if (ret) goto out_unlock;
+ ret = -EINVAL; + if (iocb->ki_flags & IOCB_DIRECT && + (!real.file->f_mapping->a_ops || + !real.file->f_mapping->a_ops->direct_IO)) + goto out_fdput; + if (!ovl_should_sync(OVL_FS(inode->i_sb))) ifl &= ~(IOCB_DSYNC | IOCB_SYNC);
@@ -389,6 +401,7 @@ static ssize_t ovl_write_iter(struct kiocb *iocb, struct iov_iter *iter) } out: revert_creds(old_cred); +out_fdput: fdput(real);
out_unlock: