[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 @@
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 @@
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 @@
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: