Add a simple proxy implementation of init_dma_buf_io_ctx() forwarding
the call to a new struct block_device_operations operation. Also reject
dma-buf backed iterators for buffered IO.

Reviewed-by: Christoph Hellwig <[email protected]>
[pavel: reject dma-buf without O_DIRECT]
Signed-off-by: Pavel Begunkov <[email protected]>
---
 block/fops.c           | 24 ++++++++++++++++++++++++
 include/linux/blkdev.h |  2 ++
 2 files changed, 26 insertions(+)

diff --git a/block/fops.c b/block/fops.c
index 827dc9eecba7..6c6700df943c 100644
--- a/block/fops.c
+++ b/block/fops.c
@@ -730,6 +730,9 @@ blkdev_direct_write(struct kiocb *iocb, struct iov_iter 
*from)
 
 static ssize_t blkdev_buffered_write(struct kiocb *iocb, struct iov_iter *from)
 {
+       if (unlikely(iov_iter_is_dmabuf_map(from)))
+               return -EOPNOTSUPP;
+
        return iomap_file_buffered_write(iocb, from, &blkdev_iomap_ops, NULL,
                        NULL);
 }
@@ -855,6 +858,11 @@ static ssize_t blkdev_read_iter(struct kiocb *iocb, struct 
iov_iter *to)
                if (ret < 0 || !count)
                        goto reexpand;
        }
+       if (unlikely(iov_iter_is_dmabuf_map(to))) {
+               if (!ret)
+                       ret = -EOPNOTSUPP;
+               goto reexpand;
+       }
 
        /*
         * Take i_rwsem and invalidate_lock to avoid racing with set_blocksize
@@ -958,6 +966,21 @@ static int blkdev_mmap_prepare(struct vm_area_desc *desc)
        return generic_file_mmap_prepare(desc);
 }
 
+static int blkdev_init_dma_buf_io_ctx(struct file *file,
+                                     struct dma_buf_io_ctx *ctx)
+{
+       struct block_device *bdev = file_bdev(file);
+       struct gendisk *disk = bdev->bd_disk;
+
+       if (!(file->f_flags & O_DIRECT))
+               return -EINVAL;
+       if (!disk->fops->init_dma_buf_io_ctx)
+               return -EOPNOTSUPP;
+       if (bdev_has_integrity_csum(bdev))
+               return -EOPNOTSUPP;
+       return disk->fops->init_dma_buf_io_ctx(bdev, ctx);
+}
+
 const struct file_operations def_blk_fops = {
        .open           = blkdev_open,
        .release        = blkdev_release,
@@ -976,6 +999,7 @@ const struct file_operations def_blk_fops = {
        .fallocate      = blkdev_fallocate,
        .uring_cmd      = blkdev_uring_cmd,
        .fop_flags      = FOP_BUFFER_RASYNC | FOP_DONTCACHE,
+       .init_dma_buf_io_ctx = blkdev_init_dma_buf_io_ctx,
 };
 
 static __init int blkdev_init(void)
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index d003a9d2d1f6..2d5c30823aab 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -1599,6 +1599,8 @@ struct block_device_operations {
        /* returns the length of the identifier or a negative errno: */
        int (*get_unique_id)(struct gendisk *disk, u8 id[16],
                        enum blk_unique_id id_type);
+       int (*init_dma_buf_io_ctx)(struct block_device *,
+                                  struct dma_buf_io_ctx *);
        struct module *owner;
        const struct pr_ops *pr_ops;
 
-- 
2.54.0


Reply via email to