Skip to content

Commit

Permalink
CHROMIUM: virtwl: send foreign id support
Browse files Browse the repository at this point in the history
This change is needed to support sending virtualized host resources
across virtio wayland connections. Initially, only virtio gpu resources
are supported.

Ensure that the host has processed the create request before trying
to send it otherwise there is a race where the send can occur before
the create is processed.

BUG=chromium:875998,chromium:892342
TEST=wayland-simple-egl
     eyes repeatedly does not fail

Change-Id: I4f7ceff45f048cffcb87ce065feefd455578e6e3
Signed-off-by: Zach Reizner <zachr@google.com>
Signed-off-by: David Riley <davidriley@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1351812
Reviewed-by: Zach Reizner <zachr@chromium.org>
  • Loading branch information
zachreizner authored and chrome-bot committed Jan 8, 2019
1 parent cea7ac7 commit 11a93b7
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 17 deletions.
127 changes: 110 additions & 17 deletions drivers/virtio/virtio_wl.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include <linux/cdev.h>
#include <linux/compat.h>
#include <linux/completion.h>
#include <linux/dma-buf.h>
#include <linux/err.h>
#include <linux/fdtable.h>
#include <linux/file.h>
Expand All @@ -58,8 +59,13 @@
#include <linux/virtio.h>
#include <linux/virtio_wl.h>

#include <drm/virtio_drm.h>
#include <uapi/linux/dma-buf.h>

#ifdef CONFIG_DRM_VIRTIO_GPU
#define SEND_VIRTGPU_RESOURCES
#endif

#define VFD_ILLEGAL_SIGN_BIT 0x80000000
#define VFD_HOST_VFD_ID_BIT 0x40000000

Expand Down Expand Up @@ -684,17 +690,64 @@ static ssize_t virtwl_vfd_recv(struct file *filp, char __user *buffer,
return read_count;
}

static int encode_vfd_ids(struct virtwl_vfd **vfds, size_t vfd_count,
__le32 *vfd_ids)
{
size_t i;

for (i = 0; i < vfd_count; i++) {
if (vfds[i])
vfd_ids[i] = cpu_to_le32(vfds[i]->id);
else
return -EBADFD;
}
return 0;
}

#ifdef SEND_VIRTGPU_RESOURCES
static int encode_vfd_ids_foreign(struct virtwl_vfd **vfds,
struct dma_buf **virtgpu_dma_bufs,
size_t vfd_count,
struct virtio_wl_ctrl_vfd_send_vfd *vfd_ids)
{
size_t i;
int ret;

for (i = 0; i < vfd_count; i++) {
if (vfds[i]) {
vfd_ids[i].kind = VIRTIO_WL_CTRL_VFD_SEND_KIND_LOCAL;
vfd_ids[i].id = cpu_to_le32(vfds[i]->id);
} else if (virtgpu_dma_bufs[i]) {
ret = virtio_gpu_dma_buf_to_handle(virtgpu_dma_bufs[i],
false,
&vfd_ids[i].id);
if (ret)
return ret;
vfd_ids[i].kind = VIRTIO_WL_CTRL_VFD_SEND_KIND_VIRTGPU;
} else {
return -EBADFD;
}
}
return 0;
}
#endif

static int virtwl_vfd_send(struct file *filp, const char __user *buffer,
u32 len, int *vfd_fds)
{
struct virtwl_vfd *vfd = filp->private_data;
struct virtwl_info *vi = vfd->vi;
struct fd vfd_files[VIRTWL_SEND_MAX_ALLOCS] = { { 0 } };
struct virtwl_vfd *vfds[VIRTWL_SEND_MAX_ALLOCS] = { 0 };
#ifdef SEND_VIRTGPU_RESOURCES
struct dma_buf *virtgpu_dma_bufs[VIRTWL_SEND_MAX_ALLOCS] = { 0 };
bool foreign_id = false;
#endif
size_t vfd_count = 0;
size_t post_send_size;
size_t vfd_ids_size;
size_t ctrl_send_size;
struct virtio_wl_ctrl_vfd_send *ctrl_send;
__le32 *vfd_ids;
u8 *vfd_ids;
u8 *out_buffer;
struct completion finish_completion;
struct scatterlist out_sg;
Expand All @@ -715,45 +768,82 @@ static int virtwl_vfd_send(struct file *filp, const char __user *buffer,
ret = -EBADFD;
goto put_files;
}
vfd_files[i] = vfd_file;

vfds[i] = vfd_file.file->private_data;
if (!vfds[i] || !vfds[i]->id) {
if (vfd_file.file->f_op == &virtwl_vfd_fops) {
vfd_files[i] = vfd_file;

vfds[i] = vfd_file.file->private_data;
if (vfds[i] && vfds[i]->id) {
vfd_count++;
continue;
}

ret = -EINVAL;
goto put_files;
} else {
#ifdef SEND_VIRTGPU_RESOURCES
struct dma_buf *dma_buf =
dma_buf_get(vfd_fds[i]);
if (dma_buf) {
fdput(vfd_file);
virtgpu_dma_bufs[i] = dma_buf;
foreign_id = true;
vfd_count++;
continue;
}
#endif
fdput(vfd_file);
ret = -EINVAL;
goto put_files;
}

vfd_count++;
}
}

/* Empty writes always succeed. */
if (len == 0 && vfd_count == 0)
return 0;

post_send_size = vfd_count * sizeof(__le32) + len;
ctrl_send = kzalloc(sizeof(*ctrl_send) + post_send_size, GFP_KERNEL);
vfd_ids_size = vfd_count * sizeof(__le32);
#ifdef SEND_VIRTGPU_RESOURCES
if (foreign_id) {
vfd_ids_size = vfd_count *
sizeof(struct virtio_wl_ctrl_vfd_send_vfd);
}
#endif
ctrl_send_size = sizeof(*ctrl_send) + vfd_ids_size + len;
ctrl_send = kzalloc(ctrl_send_size, GFP_KERNEL);
if (!ctrl_send) {
ret = -ENOMEM;
goto put_files;
}

vfd_ids = (__le32 *)((u8 *)ctrl_send + sizeof(*ctrl_send));
out_buffer = (u8 *)vfd_ids + vfd_count * sizeof(__le32);
vfd_ids = (u8 *)ctrl_send + sizeof(*ctrl_send);
out_buffer = (u8 *)ctrl_send + ctrl_send_size - len;

ctrl_send->hdr.type = VIRTIO_WL_CMD_VFD_SEND;
#ifdef SEND_VIRTGPU_RESOURCES
if (foreign_id) {
ctrl_send->hdr.type = VIRTIO_WL_CMD_VFD_SEND_FOREIGN_ID;
ret = encode_vfd_ids_foreign(vfds, virtgpu_dma_bufs, vfd_count,
(struct virtio_wl_ctrl_vfd_send_vfd *)vfd_ids);
} else {
ret = encode_vfd_ids(vfds, vfd_count, (__le32 *)vfd_ids);
}
#else
ret = encode_vfd_ids(vfds, vfd_count, (__le32 *)vfd_ids);
#endif
if (ret)
goto free_ctrl_send;
ctrl_send->vfd_id = vfd->id;
ctrl_send->vfd_count = vfd_count;
for (i = 0; i < vfd_count; i++)
vfd_ids[i] = cpu_to_le32(vfds[i]->id);

if (copy_from_user(out_buffer, buffer, len)) {
ret = -EFAULT;
goto free_ctrl_send;
}

init_completion(&finish_completion);
sg_init_one(&out_sg, ctrl_send, sizeof(*ctrl_send) + post_send_size);
sg_init_one(&out_sg, ctrl_send, ctrl_send_size);
sg_init_one(&in_sg, ctrl_send, sizeof(struct virtio_wl_ctrl_hdr));

ret = vq_queue_out(vi, &out_sg, &in_sg, &finish_completion,
Expand All @@ -769,9 +859,12 @@ static int virtwl_vfd_send(struct file *filp, const char __user *buffer,
kfree(ctrl_send);
put_files:
for (i = 0; i < VIRTWL_SEND_MAX_ALLOCS; i++) {
if (!vfd_files[i].file)
continue;
fdput(vfd_files[i]);
if (vfd_files[i].file)
fdput(vfd_files[i]);
#ifdef SEND_VIRTGPU_RESOURCES
if (virtgpu_dma_bufs[i])
dma_buf_put(virtgpu_dma_bufs[i]);
#endif
}
return ret;
}
Expand Down
21 changes: 21 additions & 0 deletions include/uapi/linux/virtio_wl.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ enum virtio_wl_ctrl_type {
VIRTIO_WL_CMD_VFD_HUP, /* virtio_wl_ctrl_vfd */
VIRTIO_WL_CMD_VFD_NEW_DMABUF, /* virtio_wl_ctrl_vfd_new */
VIRTIO_WL_CMD_VFD_DMABUF_SYNC, /* virtio_wl_ctrl_vfd_dmabuf_sync */
VIRTIO_WL_CMD_VFD_SEND_FOREIGN_ID, /* virtio_wl_ctrl_vfd_send + data */

VIRTIO_WL_RESP_OK = 0x1000,
VIRTIO_WL_RESP_VFD_NEW = 0x1001, /* virtio_wl_ctrl_vfd_new */
Expand Down Expand Up @@ -91,10 +92,30 @@ struct virtio_wl_ctrl_vfd_new {
} dmabuf;
};


enum virtio_wl_ctrl_vfd_send_kind {
/* The id after this one indicates an ordinary vfd_id. */
VIRTIO_WL_CTRL_VFD_SEND_KIND_LOCAL,
/* The id after this one is a virtio-gpu resource id. */
VIRTIO_WL_CTRL_VFD_SEND_KIND_VIRTGPU,
};

struct virtio_wl_ctrl_vfd_send_vfd {
__le32 kind; /* virtio_wl_ctrl_vfd_send_kind */
__le32 id;
};

struct virtio_wl_ctrl_vfd_send {
struct virtio_wl_ctrl_hdr hdr;
__le32 vfd_id;
__le32 vfd_count; /* struct is followed by this many IDs */

/*
* If hdr.type == VIRTIO_WL_CMD_VFD_SEND_FOREIGN_ID, there is a
* vfd_count array of virtio_wl_ctrl_vfd_send_vfd. Otherwise, there is a
* vfd_count array of vfd_ids.
*/

/* the remainder is raw data */
};

Expand Down

0 comments on commit 11a93b7

Please sign in to comment.