qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH 2/4] libvhost-user: support many virtqueues


From: Marc-André Lureau
Subject: Re: [Qemu-devel] [PATCH 2/4] libvhost-user: support many virtqueues
Date: Fri, 21 Jun 2019 15:48:36 +0200

Hi

On Fri, Jun 21, 2019 at 11:40 AM Stefan Hajnoczi <address@hidden> wrote:
>
> Currently libvhost-user is hardcoded to at most 8 virtqueues.  The
> device backend should decide the number of virtqueues, not
> libvhost-user.  This is important for multiqueue device backends where
> the guest driver needs an accurate number of virtqueues.
>
> This change breaks libvhost-user and libvhost-user-glib API stability.
> There is no stability guarantee yet, so make this change now and update
> all in-tree library users.
>
> This patch touches up vhost-user-blk, vhost-user-gpu, vhost-user-input,
> vhost-user-scsi, and vhost-user-bridge.  If the device has a fixed
> number of queues that exact number is used.  Otherwise the previous
> default of 8 virtqueues is used.
>
> vu_init() and vug_init() can now fail if malloc() returns NULL.  I
> considered aborting with an error in libvhost-user but it should be safe
> to instantiate new vhost-user instances at runtime without risk of
> terminating the process.  Therefore callers need to handle the vu_init()
> failure now.
>
> vhost-user-blk and vhost-user-scsi duplicate virtqueue index checks that
> are already performed by libvhost-user.  This code would need to be
> modified to use max_queues but remove it completely instead since it's
> redundant.
>
> Signed-off-by: Stefan Hajnoczi <address@hidden>
> ---
>  contrib/libvhost-user/libvhost-user-glib.h |  2 +-
>  contrib/libvhost-user/libvhost-user.h      | 10 ++++--
>  contrib/libvhost-user/libvhost-user-glib.c | 12 +++++--
>  contrib/libvhost-user/libvhost-user.c      | 32 ++++++++++++-----
>  contrib/vhost-user-blk/vhost-user-blk.c    | 16 +++++----
>  contrib/vhost-user-gpu/main.c              |  9 ++++-
>  contrib/vhost-user-input/main.c            | 11 +++++-
>  contrib/vhost-user-scsi/vhost-user-scsi.c  | 21 +++++------
>  tests/vhost-user-bridge.c                  | 42 ++++++++++++++--------
>  9 files changed, 104 insertions(+), 51 deletions(-)
>
> diff --git a/contrib/libvhost-user/libvhost-user-glib.h 
> b/contrib/libvhost-user/libvhost-user-glib.h
> index d3200f3afc..64d539d93a 100644
> --- a/contrib/libvhost-user/libvhost-user-glib.h
> +++ b/contrib/libvhost-user/libvhost-user-glib.h
> @@ -25,7 +25,7 @@ typedef struct VugDev {
>      GSource *src;
>  } VugDev;
>
> -void vug_init(VugDev *dev, int socket,
> +bool vug_init(VugDev *dev, uint16_t max_queues, int socket,
>                vu_panic_cb panic, const VuDevIface *iface);
>  void vug_deinit(VugDev *dev);
>
> diff --git a/contrib/libvhost-user/libvhost-user.h 
> b/contrib/libvhost-user/libvhost-user.h
> index 3b888ff0a5..46b600799b 100644
> --- a/contrib/libvhost-user/libvhost-user.h
> +++ b/contrib/libvhost-user/libvhost-user.h
> @@ -25,7 +25,6 @@
>  #define VHOST_USER_F_PROTOCOL_FEATURES 30
>  #define VHOST_LOG_PAGE 4096
>
> -#define VHOST_MAX_NR_VIRTQUEUE 8
>  #define VIRTQUEUE_MAX_SIZE 1024
>
>  #define VHOST_MEMORY_MAX_NREGIONS 8
> @@ -353,7 +352,7 @@ struct VuDev {
>      int sock;
>      uint32_t nregions;
>      VuDevRegion regions[VHOST_MEMORY_MAX_NREGIONS];
> -    VuVirtq vq[VHOST_MAX_NR_VIRTQUEUE];
> +    VuVirtq *vq;
>      VuDevInflightInfo inflight_info;
>      int log_call_fd;
>      int slave_fd;
> @@ -362,6 +361,7 @@ struct VuDev {
>      uint64_t features;
>      uint64_t protocol_features;
>      bool broken;
> +    uint16_t max_queues;
>
>      /* @set_watch: add or update the given fd to the watch set,
>       * call cb when condition is met */
> @@ -391,6 +391,7 @@ typedef struct VuVirtqElement {
>  /**
>   * vu_init:
>   * @dev: a VuDev context
> + * @max_queues: maximum number of virtqueues
>   * @socket: the socket connected to vhost-user master
>   * @panic: a panic callback
>   * @set_watch: a set_watch callback
> @@ -398,8 +399,11 @@ typedef struct VuVirtqElement {
>   * @iface: a VuDevIface structure with vhost-user device callbacks
>   *
>   * Intializes a VuDev vhost-user context.
> + *
> + * Returns: true on success, false on failure.
>   **/
> -void vu_init(VuDev *dev,
> +bool vu_init(VuDev *dev,
> +             uint16_t max_queues,
>               int socket,
>               vu_panic_cb panic,
>               vu_set_watch_cb set_watch,
> diff --git a/contrib/libvhost-user/libvhost-user-glib.c 
> b/contrib/libvhost-user/libvhost-user-glib.c
> index 42660a1b36..99edd2f3de 100644
> --- a/contrib/libvhost-user/libvhost-user-glib.c
> +++ b/contrib/libvhost-user/libvhost-user-glib.c
> @@ -131,18 +131,24 @@ static void vug_watch(VuDev *dev, int condition, void 
> *data)
>      }
>  }
>
> -void
> -vug_init(VugDev *dev, int socket,
> +bool
> +vug_init(VugDev *dev, uint16_t max_queues, int socket,
>           vu_panic_cb panic, const VuDevIface *iface)
>  {
>      g_assert(dev);
>      g_assert(iface);
>
> -    vu_init(&dev->parent, socket, panic, set_watch, remove_watch, iface);
> +    if (!vu_init(&dev->parent, max_queues, socket, panic, set_watch,
> +                 remove_watch, iface)) {
> +        return false;
> +    }
> +
>      dev->fdmap = g_hash_table_new_full(NULL, NULL, NULL,
>                                         (GDestroyNotify) g_source_destroy);
>
>      dev->src = vug_source_new(dev, socket, G_IO_IN, vug_watch, NULL);
> +
> +    return true;
>  }
>
>  void
> diff --git a/contrib/libvhost-user/libvhost-user.c 
> b/contrib/libvhost-user/libvhost-user.c
> index a8657c7af2..0c88431e8f 100644
> --- a/contrib/libvhost-user/libvhost-user.c
> +++ b/contrib/libvhost-user/libvhost-user.c
> @@ -493,9 +493,9 @@ vu_get_features_exec(VuDev *dev, VhostUserMsg *vmsg)
>  static void
>  vu_set_enable_all_rings(VuDev *dev, bool enabled)
>  {
> -    int i;
> +    uint16_t i;
>
> -    for (i = 0; i < VHOST_MAX_NR_VIRTQUEUE; i++) {
> +    for (i = 0; i < dev->max_queues; i++) {
>          dev->vq[i].enable = enabled;
>      }
>  }
> @@ -916,7 +916,7 @@ vu_check_queue_msg_file(VuDev *dev, VhostUserMsg *vmsg)
>  {
>      int index = vmsg->payload.u64 & VHOST_USER_VRING_IDX_MASK;
>
> -    if (index >= VHOST_MAX_NR_VIRTQUEUE) {
> +    if (index >= dev->max_queues) {
>          vmsg_close_fds(vmsg);
>          vu_panic(dev, "Invalid queue index: %u", index);
>          return false;
> @@ -1213,7 +1213,7 @@ vu_set_vring_enable_exec(VuDev *dev, VhostUserMsg *vmsg)
>      DPRINT("State.index: %d\n", index);
>      DPRINT("State.enable:   %d\n", enable);
>
> -    if (index >= VHOST_MAX_NR_VIRTQUEUE) {
> +    if (index >= dev->max_queues) {
>          vu_panic(dev, "Invalid vring_enable index: %u", index);
>          return false;
>      }
> @@ -1582,7 +1582,7 @@ vu_deinit(VuDev *dev)
>      }
>      dev->nregions = 0;
>
> -    for (i = 0; i < VHOST_MAX_NR_VIRTQUEUE; i++) {
> +    for (i = 0; i < dev->max_queues; i++) {
>          VuVirtq *vq = &dev->vq[i];
>
>          if (vq->call_fd != -1) {
> @@ -1627,18 +1627,23 @@ vu_deinit(VuDev *dev)
>      if (dev->sock != -1) {
>          close(dev->sock);
>      }
> +
> +    free(dev->vq);
> +    dev->vq = NULL;
>  }
>
> -void
> +bool
>  vu_init(VuDev *dev,
> +        uint16_t max_queues,
>          int socket,
>          vu_panic_cb panic,
>          vu_set_watch_cb set_watch,
>          vu_remove_watch_cb remove_watch,
>          const VuDevIface *iface)
>  {
> -    int i;
> +    uint16_t i;
>
> +    assert(max_queues > 0);
>      assert(socket >= 0);
>      assert(set_watch);
>      assert(remove_watch);
> @@ -1654,18 +1659,27 @@ vu_init(VuDev *dev,
>      dev->iface = iface;
>      dev->log_call_fd = -1;
>      dev->slave_fd = -1;
> -    for (i = 0; i < VHOST_MAX_NR_VIRTQUEUE; i++) {
> +
> +    dev->vq = malloc(max_queues * sizeof(dev->vq[0]));
> +    if (!dev->vq) {
> +        DPRINT("%s: failed to malloc virtqueues\n", __func__);
> +        return false;
> +    }
> +
> +    for (i = 0; i < max_queues; i++) {
>          dev->vq[i] = (VuVirtq) {
>              .call_fd = -1, .kick_fd = -1, .err_fd = -1,
>              .notification = true,
>          };
>      }
> +
> +    return true;
>  }
>
>  VuVirtq *
>  vu_get_queue(VuDev *dev, int qidx)
>  {
> -    assert(qidx < VHOST_MAX_NR_VIRTQUEUE);
> +    assert(qidx < dev->max_queues);
>      return &dev->vq[qidx];
>  }
>
> diff --git a/contrib/vhost-user-blk/vhost-user-blk.c 
> b/contrib/vhost-user-blk/vhost-user-blk.c
> index 86a3987744..ae61034656 100644
> --- a/contrib/vhost-user-blk/vhost-user-blk.c
> +++ b/contrib/vhost-user-blk/vhost-user-blk.c
> @@ -25,6 +25,10 @@
>  #include <sys/ioctl.h>
>  #endif
>
> +enum {
> +    VHOST_USER_BLK_MAX_QUEUES = 8,
> +};

why do you use enum,(and not const int) ? (similarly for other devices)

other than than
Reviewed-by: Marc-André Lureau <address@hidden>


> +
>  struct virtio_blk_inhdr {
>      unsigned char status;
>  };
> @@ -334,12 +338,6 @@ static void vub_process_vq(VuDev *vu_dev, int idx)
>      VuVirtq *vq;
>      int ret;
>
> -    if ((idx < 0) || (idx >= VHOST_MAX_NR_VIRTQUEUE)) {
> -        fprintf(stderr, "VQ Index out of range: %d\n", idx);
> -        vub_panic_cb(vu_dev, NULL);
> -        return;
> -    }
> -
>      gdev = container_of(vu_dev, VugDev, parent);
>      vdev_blk = container_of(gdev, VubDev, parent);
>      assert(vdev_blk);
> @@ -631,7 +629,11 @@ int main(int argc, char **argv)
>          vdev_blk->enable_ro = true;
>      }
>
> -    vug_init(&vdev_blk->parent, csock, vub_panic_cb, &vub_iface);
> +    if (!vug_init(&vdev_blk->parent, VHOST_USER_BLK_MAX_QUEUES, csock,
> +                  vub_panic_cb, &vub_iface)) {
> +        fprintf(stderr, "Failed to initialized libvhost-user-glib\n");
> +        goto err;
> +    }
>
>      g_main_loop_run(vdev_blk->loop);
>
> diff --git a/contrib/vhost-user-gpu/main.c b/contrib/vhost-user-gpu/main.c
> index 04b753046f..b45d2019b4 100644
> --- a/contrib/vhost-user-gpu/main.c
> +++ b/contrib/vhost-user-gpu/main.c
> @@ -25,6 +25,10 @@
>  #include "virgl.h"
>  #include "vugbm.h"
>
> +enum {
> +    VHOST_USER_GPU_MAX_QUEUES = 2,
> +};
> +
>  struct virtio_gpu_simple_resource {
>      uint32_t resource_id;
>      uint32_t width;
> @@ -1169,7 +1173,10 @@ main(int argc, char *argv[])
>          exit(EXIT_FAILURE);
>      }
>
> -    vug_init(&g.dev, fd, vg_panic, &vuiface);
> +    if (!vug_init(&g.dev, VHOST_USER_GPU_MAX_QUEUES, fd, vg_panic, 
> &vuiface)) {
> +        g_printerr("Failed to initialize libvhost-user-glib.\n");
> +        exit(EXIT_FAILURE);
> +    }
>
>      loop = g_main_loop_new(NULL, FALSE);
>      g_main_loop_run(loop);
> diff --git a/contrib/vhost-user-input/main.c b/contrib/vhost-user-input/main.c
> index 8b4e7d2536..449fd2171a 100644
> --- a/contrib/vhost-user-input/main.c
> +++ b/contrib/vhost-user-input/main.c
> @@ -17,6 +17,10 @@
>  #include "standard-headers/linux/virtio_input.h"
>  #include "qapi/error.h"
>
> +enum {
> +    VHOST_USER_INPUT_MAX_QUEUES = 2,
> +};
> +
>  typedef struct virtio_input_event virtio_input_event;
>  typedef struct virtio_input_config virtio_input_config;
>
> @@ -384,7 +388,12 @@ main(int argc, char *argv[])
>          g_printerr("Invalid vhost-user socket.\n");
>          exit(EXIT_FAILURE);
>      }
> -    vug_init(&vi.dev, fd, vi_panic, &vuiface);
> +
> +    if (!vug_init(&vi.dev, VHOST_USER_INPUT_MAX_QUEUES, fd, vi_panic,
> +                  &vuiface)) {
> +        g_printerr("Failed to initialize libvhost-user-glib.\n");
> +        exit(EXIT_FAILURE);
> +    }
>
>      loop = g_main_loop_new(NULL, FALSE);
>      g_main_loop_run(loop);
> diff --git a/contrib/vhost-user-scsi/vhost-user-scsi.c 
> b/contrib/vhost-user-scsi/vhost-user-scsi.c
> index 496dd6e693..0fc14d7899 100644
> --- a/contrib/vhost-user-scsi/vhost-user-scsi.c
> +++ b/contrib/vhost-user-scsi/vhost-user-scsi.c
> @@ -19,6 +19,10 @@
>
>  #define VUS_ISCSI_INITIATOR "iqn.2016-11.com.nutanix:vhost-user-scsi"
>
> +enum {
> +    VHOST_USER_SCSI_MAX_QUEUES = 8,
> +};
> +
>  typedef struct VusIscsiLun {
>      struct iscsi_context *iscsi_ctx;
>      int iscsi_lun;
> @@ -231,11 +235,6 @@ static void vus_proc_req(VuDev *vu_dev, int idx)
>
>      gdev = container_of(vu_dev, VugDev, parent);
>      vdev_scsi = container_of(gdev, VusDev, parent);
> -    if (idx < 0 || idx >= VHOST_MAX_NR_VIRTQUEUE) {
> -        g_warning("VQ Index out of range: %d", idx);
> -        vus_panic_cb(vu_dev, NULL);
> -        return;
> -    }
>
>      vq = vu_get_queue(vu_dev, idx);
>      if (!vq) {
> @@ -295,12 +294,6 @@ static void vus_queue_set_started(VuDev *vu_dev, int 
> idx, bool started)
>
>      assert(vu_dev);
>
> -    if (idx < 0 || idx >= VHOST_MAX_NR_VIRTQUEUE) {
> -        g_warning("VQ Index out of range: %d", idx);
> -        vus_panic_cb(vu_dev, NULL);
> -        return;
> -    }
> -
>      vq = vu_get_queue(vu_dev, idx);
>
>      if (idx == 0 || idx == 1) {
> @@ -398,7 +391,11 @@ int main(int argc, char **argv)
>          goto err;
>      }
>
> -    vug_init(&vdev_scsi->parent, csock, vus_panic_cb, &vus_iface);
> +    if (!vug_init(&vdev_scsi->parent, VHOST_USER_SCSI_MAX_QUEUES, csock,
> +                  vus_panic_cb, &vus_iface)) {
> +        g_printerr("Failed to initialize libvhost-user-glib\n");
> +        goto err;
> +    }
>
>      g_main_loop_run(vdev_scsi->loop);
>
> diff --git a/tests/vhost-user-bridge.c b/tests/vhost-user-bridge.c
> index 0bb03af0e5..c4e350e1f5 100644
> --- a/tests/vhost-user-bridge.c
> +++ b/tests/vhost-user-bridge.c
> @@ -45,6 +45,10 @@
>          } \
>      } while (0)
>
> +enum {
> +    VHOST_USER_BRIDGE_MAX_QUEUES = 8,
> +};
> +
>  typedef void (*CallbackFunc)(int sock, void *ctx);
>
>  typedef struct Event {
> @@ -512,12 +516,16 @@ vubr_accept_cb(int sock, void *ctx)
>      }
>      DPRINT("Got connection from remote peer on sock %d\n", conn_fd);
>
> -    vu_init(&dev->vudev,
> -            conn_fd,
> -            vubr_panic,
> -            vubr_set_watch,
> -            vubr_remove_watch,
> -            &vuiface);
> +    if (!vu_init(&dev->vudev,
> +                 VHOST_USER_BRIDGE_MAX_QUEUES,
> +                 conn_fd,
> +                 vubr_panic,
> +                 vubr_set_watch,
> +                 vubr_remove_watch,
> +                 &vuiface)) {
> +        fprintf(stderr, "Failed to initialize libvhost-user\n");
> +        exit(1);
> +    }
>
>      dispatcher_add(&dev->dispatcher, conn_fd, ctx, vubr_receive_cb);
>      dispatcher_remove(&dev->dispatcher, sock);
> @@ -560,12 +568,18 @@ vubr_new(const char *path, bool client)
>          if (connect(dev->sock, (struct sockaddr *)&un, len) == -1) {
>              vubr_die("connect");
>          }
> -        vu_init(&dev->vudev,
> -                dev->sock,
> -                vubr_panic,
> -                vubr_set_watch,
> -                vubr_remove_watch,
> -                &vuiface);
> +
> +        if (!vu_init(&dev->vudev,
> +                     VHOST_USER_BRIDGE_MAX_QUEUES,
> +                     dev->sock,
> +                     vubr_panic,
> +                     vubr_set_watch,
> +                     vubr_remove_watch,
> +                     &vuiface)) {
> +            fprintf(stderr, "Failed to initialize libvhost-user\n");
> +            exit(1);
> +        }
> +
>          cb = vubr_receive_cb;
>      }
>
> @@ -584,7 +598,7 @@ static void *notifier_thread(void *arg)
>      int qidx;
>
>      while (true) {
> -        for (qidx = 0; qidx < VHOST_MAX_NR_VIRTQUEUE; qidx++) {
> +        for (qidx = 0; qidx < VHOST_USER_BRIDGE_MAX_QUEUES; qidx++) {
>              uint16_t *n = vubr->notifier.addr + pagesize * qidx;
>
>              if (*n == qidx) {
> @@ -616,7 +630,7 @@ vubr_host_notifier_setup(VubrDev *dev)
>      void *addr;
>      int fd;
>
> -    length = getpagesize() * VHOST_MAX_NR_VIRTQUEUE;
> +    length = getpagesize() * VHOST_USER_BRIDGE_MAX_QUEUES;
>
>      fd = mkstemp(template);
>      if (fd < 0) {
> --
> 2.21.0
>



reply via email to

[Prev in Thread] Current Thread [Next in Thread]