From: Miklos Szeredi Date: Mon, 27 Sep 2021 09:23:57 +0000 (+0200) Subject: ovl: fix IOCB_DIRECT if underlying fs doesn't support direct IO X-Git-Tag: v5.10.79~403 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1bc2f315a215585f8bc07257542e67373c86e801;p=platform%2Fkernel%2Flinux-rpi.git ovl: fix IOCB_DIRECT if underlying fs doesn't support direct IO 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 Fixes: 16914e6fc7e1 ("ovl: add ovl_read_iter()") Cc: # v4.19 Tested-by: Huang Jianan Signed-off-by: Miklos Szeredi Signed-off-by: Greg Kroah-Hartman --- diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c index 5c5c397..f713577 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: