Commit 1dc1eed4 authored by Miklos Szeredi's avatar Miklos Szeredi
Browse files

ovl: fix IOCB_DIRECT if underlying fs doesn't support direct IO



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: default avatarHuang Jianan <huangjianan@oppo.com>
Fixes: 16914e6f ("ovl: add ovl_read_iter()")
Cc: <stable@vger.kernel.org> # v4.19
Tested-by: default avatarHuang Jianan <huangjianan@oppo.com>
Signed-off-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
parent a295aef6
Loading
Loading
Loading
Loading
+14 −1
Original line number Diff line number Diff line
@@ -296,6 +296,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,
@@ -320,7 +326,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;
@@ -349,6 +355,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);

@@ -384,6 +396,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: