| #include "dma-buf.h" | |
| static inline void io_release_dmabuf(void *priv) | |
| { | |
| struct io_buf_dma *bd = priv; | |
| fput(bd->target_file); | |
| dma_buf_io_ctx_release(bd->ctx); | |
| kfree(bd); | |
| } | |
| int __io_register_dmabuf(struct io_ring_ctx *ctx, | |
| struct io_uring_regbuf_desc *desc, | |
| struct io_mapped_ubuf *imu) | |
| { | |
| struct io_buf_dma *bd = NULL; | |
| struct file *target_file = NULL; | |
| struct dma_buf *dmabuf = NULL; | |
| int ret; | |
| /* | |
| * We have to drop the dma-buf map early when IO is finished. Disable | |
| * IOPOLL for now as we can't wait potentially infintely for a task | |
| * to do that. | |
| */ | |
| if (ctx->flags & IORING_SETUP_IOPOLL) | |
| return -EOPNOTSUPP; | |
| if (desc->uaddr || desc->size) | |
| return -EINVAL; | |
| bd = kzalloc(sizeof(*bd), GFP_KERNEL); | |
| if (!bd) | |
| return -ENOMEM; | |
| target_file = fget(desc->target_fd); | |
| if (!target_file) { | |
| ret = -EBADF; | |
| goto err; | |
| } | |
| dmabuf = dma_buf_get(desc->dmabuf_fd); | |
| if (IS_ERR(dmabuf)) { | |
| ret = PTR_ERR(dmabuf); | |
| dmabuf = NULL; | |
| goto err; | |
| } | |
| ret = io_validate_user_buf_range(0, dmabuf->size); | |
| if (ret) | |
| goto err; | |
| ret = dma_buf_io_ctx_create(target_file, dmabuf, DMA_BIDIRECTIONAL, | |
| &bd->ctx); | |
| if (ret) | |
| goto err; | |
| bd->target_file = target_file; | |
| imu->len = dmabuf->size; | |
| imu->release = io_release_dmabuf; | |
| imu->priv = bd; | |
| imu->flags = IO_REGBUF_F_DMABUF; | |
| imu->dir = IO_BUF_DEST | IO_BUF_SOURCE; | |
| dma_buf_put(dmabuf); | |
| return 0; | |
| err: | |
| kfree(bd); | |
| if (target_file) | |
| fput(target_file); | |
| if (dmabuf) | |
| dma_buf_put(dmabuf); | |
| return ret; | |
| } | |