ovl: fix IOCB_DIRECT if underlying fs doesn't support direct IO
authorMiklos Szeredi <mszeredi@redhat.com>
Mon, 27 Sep 2021 09:23:57 +0000 (11:23 +0200)
committerMiklos Szeredi <mszeredi@redhat.com>
Tue, 28 Sep 2021 07:16:12 +0000 (09:16 +0200)
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>
fs/overlayfs/file.c

index d081faa..c88ac57 100644 (file)
@@ -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: