[virtio_magma] Support magma_query_returns_buffer2 Change-Id: Icbd985d148c3ee3e2704904d7c0a102f692eea4b
diff --git a/drivers/virtio/virtio_magma.c b/drivers/virtio/virtio_magma.c index 98b4344..ef3db43 100644 --- a/drivers/virtio/virtio_magma.c +++ b/drivers/virtio/virtio_magma.c
@@ -651,7 +651,7 @@ static int virtmagma_buffer_fd_mmap(struct file *filp, max_map_size = PAGE_ALIGN(priv->buffer_size); if (vma->vm_pgoff * PAGE_SIZE + vm_size > max_map_size) { - pr_warn("virtmagma: user tried to mmap with offset (%ld) and size (%ld) exceededing the buffer's size (%ld)", + pr_warn("virtmagma: user tried to mmap with offset (%ld) and size (%ld) exceeding the buffer's size (%ld)", vma->vm_pgoff * PAGE_SIZE, vm_size, max_map_size); return -EINVAL; } @@ -1732,6 +1732,76 @@ static int virtmagma_command_magma_get_buffer_handle( return ret; } +static int virtmagma_command_magma_query_returns_buffer2( + struct virtmagma_instance *instance, + struct virtmagma_virtio_command *command) +{ + struct virtmagma_buffer_fd_priv *priv; + struct virtio_magma_query_returns_buffer2_ctrl *request = + command->request_ptr; + struct virtio_magma_query_returns_buffer2_resp *response = + command->response_ptr; + uint64_t buffer_size; + uint32_t buffer_handle; + int ret; + + /* Reallocate response buffer with additional space for buffer size; + note that response_size is not modified, as we only want the response struct + itself to be copied back to the user by our caller. + Memory will be freed by caller. + */ + response = kzalloc(sizeof(*response) + sizeof(uint64_t), GFP_KERNEL); + if (!response) + return -ENOMEM; + + command->response_ptr = response; + + if (!COMMAND_OK(command, request, response)) + return -EINVAL; + + ret = vq_out_send_sync(instance->vi, command); + if (ret) + return ret; + + ret = virtmagma_check_expected_response_type(request, response); + if (ret) + return ret; + + if (response->result_return) { + pr_warn("virtmagma: magma_query_returns_buffer2 returned %d", + (int32_t)response->result_return); + return 0; /* the ioctl is still successful */ + } + + buffer_handle = response->handle_out; + buffer_size = *(uint64_t*)(response + 1); + + priv = kzalloc(sizeof(struct virtmagma_buffer_fd_priv), GFP_KERNEL); + if (!priv) { + virtmagma_release_handle(instance->vi, buffer_handle); + return -ENOMEM; + } + + mutex_init(&priv->mutex_lock); + + priv->vi = instance->vi; + priv->buffer_handle = buffer_handle; + priv->buffer_size = buffer_size; + + ret = anon_inode_getfd("[virtmagma]", &virtmagma_buffer_fd_fops, priv, + O_RDWR); + if (ret < 0) { + pr_err("virtmagma: failed to create fd: %d", ret); + virtmagma_release_handle(instance->vi, buffer_handle); + kfree(priv); + return ret; + } + + response->handle_out = ret; + + return 0; +} + static int virtmagma_ioctl_handshake(struct file *filp, void __user *ptr) { struct virtmagma_ioctl_args_handshake ioctl_args; @@ -1878,6 +1948,9 @@ int virtmagma_ioctl_magma_command(struct file *filp, void __user *ptr) ret = virtmagma_command_magma_virt_get_image_info(instance, &command); break; + case VIRTIO_MAGMA_CMD_QUERY_RETURNS_BUFFER2: + ret = virtmagma_command_magma_query_returns_buffer2(instance, &command); + break; /* pass-through handlers */ case VIRTIO_MAGMA_CMD_QUERY2: case VIRTIO_MAGMA_CMD_GET_ERROR: