diff mbox series

[RESEND,v6,19/36] multi-process: Connect Proxy Object with device in the remote process

Message ID fc69772e2a3c5269052c3f1994045a3b3689f949.1587614626.git.elena.ufimtseva@oracle.com
State New
Headers show
Series [RESEND,v6,01/36] memory: alloc RAM from file at offset | expand

Commit Message

Elena Ufimtseva April 23, 2020, 4:13 a.m. UTC
From: Jagannathan Raman <jag.raman@oracle.com>

Send a message to the remote process to connect PCI device with the
corresponding Proxy object in QEMU

Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com>
Signed-off-by: John G Johnson <john.g.johnson@oracle.com>
Signed-off-by: Jagannathan Raman <jag.raman@oracle.com>
---
 hw/proxy/qemu-proxy.c    | 34 +++++++++++++++++++++++++++++++
 include/io/mpqemu-link.h |  5 +++++
 io/mpqemu-link.c         |  3 +++
 remote/remote-main.c     | 43 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 85 insertions(+)

Comments

Stefan Hajnoczi May 12, 2020, 12:54 p.m. UTC | #1
On Wed, Apr 22, 2020 at 09:13:54PM -0700, elena.ufimtseva@oracle.com wrote:
> From: Jagannathan Raman <jag.raman@oracle.com>
> 
> Send a message to the remote process to connect PCI device with the
> corresponding Proxy object in QEMU

The CONNECT_DEV message is no longer necessary with a 1 socket per
device architecture. Connecting to a specific UNIX domain socket (e.g.
vm001/lsi-scsi-1.sock) already identifies which device the proxy wishes
to talk to.

Each device should have an mpqemu link that accepts client connections.
You can either do that in the main loop or you can use IOThread to run
dedicated per-device threads.

> 
> Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com>
> Signed-off-by: John G Johnson <john.g.johnson@oracle.com>
> Signed-off-by: Jagannathan Raman <jag.raman@oracle.com>
> ---
>  hw/proxy/qemu-proxy.c    | 34 +++++++++++++++++++++++++++++++
>  include/io/mpqemu-link.h |  5 +++++
>  io/mpqemu-link.c         |  3 +++
>  remote/remote-main.c     | 43 ++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 85 insertions(+)
> 
> diff --git a/hw/proxy/qemu-proxy.c b/hw/proxy/qemu-proxy.c
> index 40bf56fd37..9b5e429a88 100644
> --- a/hw/proxy/qemu-proxy.c
> +++ b/hw/proxy/qemu-proxy.c
> @@ -17,11 +17,45 @@
>  static void proxy_set_socket(Object *obj, const char *str, Error **errp)
>  {
>      PCIProxyDev *pdev = PCI_PROXY_DEV(obj);
> +    DeviceState *dev = DEVICE(obj);
> +    MPQemuMsg msg = { 0 };
> +    int wait, fd[2];
>  
>      pdev->socket = atoi(str);
>  
>      mpqemu_init_channel(pdev->mpqemu_link, &pdev->mpqemu_link->com,
>                          pdev->socket);
> +
> +    if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd)) {
> +        error_setg(errp, "Failed to create socket for device channel");
> +        return;
> +    }

This extra connection can be removed. The reasons for having it have
gone away now that there is just 1 device per socket.

> +
> +    wait = GET_REMOTE_WAIT;
> +
> +    msg.cmd = CONNECT_DEV;
> +    msg.bytestream = 1;
> +    msg.data2 = (uint8_t *)g_strdup(dev->id);
> +    msg.size = sizeof(msg.data2);

The g_strdup() is unnecessary, dev->id can be used directly.

Should msg.size be strlen(dev->id) instead of sizeof(msg.data2)?

> +    msg.num_fds = 2;
> +    msg.fds[0] = wait;
> +    msg.fds[1] = fd[1];
> +
> +    mpqemu_msg_send(&msg, pdev->mpqemu_link->com);
> +
> +    if (wait_for_remote(wait)) {
> +        error_setg(errp, "Failed to connect device to the remote");
> +        close(fd[0]);
> +    } else {
> +        mpqemu_init_channel(pdev->mpqemu_link, &pdev->mpqemu_link->dev,
> +                            fd[0]);
> +    }
> +
> +    PUT_REMOTE_WAIT(wait);
> +
> +    close(fd[1]);
> +
> +    g_free(msg.data2);
>  }
>  
>  static void proxy_init(Object *obj)
> diff --git a/include/io/mpqemu-link.h b/include/io/mpqemu-link.h
> index 73cc59b874..ebae9afc45 100644
> --- a/include/io/mpqemu-link.h
> +++ b/include/io/mpqemu-link.h
> @@ -38,6 +38,7 @@
>  typedef enum {
>      INIT = 0,
>      SYNC_SYSMEM,
> +    CONNECT_DEV,
>      MAX,
>  } mpqemu_cmd_t;
>  
> @@ -120,8 +121,12 @@ struct MPQemuLinkState {
>      GMainLoop *loop;
>  
>      MPQemuChannel *com;
> +    MPQemuChannel *dev;
>  
>      mpqemu_link_callback callback;
> +
> +    void *opaque;
> +    QemuThread thread;
>  };
>  
>  MPQemuLinkState *mpqemu_link_create(void);
> diff --git a/io/mpqemu-link.c b/io/mpqemu-link.c
> index 3f81cef96e..f780b65181 100644
> --- a/io/mpqemu-link.c
> +++ b/io/mpqemu-link.c
> @@ -46,6 +46,9 @@ MPQemuLinkState *mpqemu_link_create(void)
>      MPQemuLinkState *link = MPQEMU_LINK(object_new(TYPE_MPQEMU_LINK));
>  
>      link->com = NULL;
> +    link->dev = NULL;
> +
> +    link->opaque = NULL;
>  
>      return link;
>  }
> diff --git a/remote/remote-main.c b/remote/remote-main.c
> index dbd6ad2529..f541baae6a 100644
> --- a/remote/remote-main.c
> +++ b/remote/remote-main.c
> @@ -35,6 +35,9 @@
>  #include "exec/ramlist.h"
>  #include "remote/remote-common.h"
>  
> +static void process_msg(GIOCondition cond, MPQemuLinkState *link,
> +                        MPQemuChannel *chan);
> +
>  static MPQemuLinkState *mpqemu_link;
>  
>  gchar *print_pid_exec(gchar *str)
> @@ -48,6 +51,43 @@ gchar *print_pid_exec(gchar *str)
>      return str;
>  }
>  
> +#define LINK_TO_DEV(link) ((PCIDevice *)link->opaque)
> +
> +static gpointer dev_thread(gpointer data)
> +{
> +    MPQemuLinkState *link = data;
> +
> +    mpqemu_start_coms(link, link->dev);
> +
> +    return NULL;
> +}
> +
> +static void process_connect_dev_msg(MPQemuMsg *msg)
> +{
> +    char *devid = (char *)msg->data2;

Input validation is missing for this message. We may not have data2 or
it may not have a NUL-terminator.

> +    MPQemuLinkState *link = NULL;
> +    DeviceState *dev = NULL;
> +    int wait = msg->fds[0];

msg->num_fds wasn't checked.

> +    int ret = 0;
> +
> +    dev = qdev_find_recursive(sysbus_get_default(), devid);
> +    if (!dev) {
> +        ret = 0xff;
> +        goto exit;
> +    }
> +
> +    link = mpqemu_link_create();
> +    link->opaque = (void *)PCI_DEVICE(dev);

Missing check to see if dev is a PCIDevice subclass.
diff mbox series

Patch

diff --git a/hw/proxy/qemu-proxy.c b/hw/proxy/qemu-proxy.c
index 40bf56fd37..9b5e429a88 100644
--- a/hw/proxy/qemu-proxy.c
+++ b/hw/proxy/qemu-proxy.c
@@ -17,11 +17,45 @@ 
 static void proxy_set_socket(Object *obj, const char *str, Error **errp)
 {
     PCIProxyDev *pdev = PCI_PROXY_DEV(obj);
+    DeviceState *dev = DEVICE(obj);
+    MPQemuMsg msg = { 0 };
+    int wait, fd[2];
 
     pdev->socket = atoi(str);
 
     mpqemu_init_channel(pdev->mpqemu_link, &pdev->mpqemu_link->com,
                         pdev->socket);
+
+    if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd)) {
+        error_setg(errp, "Failed to create socket for device channel");
+        return;
+    }
+
+    wait = GET_REMOTE_WAIT;
+
+    msg.cmd = CONNECT_DEV;
+    msg.bytestream = 1;
+    msg.data2 = (uint8_t *)g_strdup(dev->id);
+    msg.size = sizeof(msg.data2);
+    msg.num_fds = 2;
+    msg.fds[0] = wait;
+    msg.fds[1] = fd[1];
+
+    mpqemu_msg_send(&msg, pdev->mpqemu_link->com);
+
+    if (wait_for_remote(wait)) {
+        error_setg(errp, "Failed to connect device to the remote");
+        close(fd[0]);
+    } else {
+        mpqemu_init_channel(pdev->mpqemu_link, &pdev->mpqemu_link->dev,
+                            fd[0]);
+    }
+
+    PUT_REMOTE_WAIT(wait);
+
+    close(fd[1]);
+
+    g_free(msg.data2);
 }
 
 static void proxy_init(Object *obj)
diff --git a/include/io/mpqemu-link.h b/include/io/mpqemu-link.h
index 73cc59b874..ebae9afc45 100644
--- a/include/io/mpqemu-link.h
+++ b/include/io/mpqemu-link.h
@@ -38,6 +38,7 @@ 
 typedef enum {
     INIT = 0,
     SYNC_SYSMEM,
+    CONNECT_DEV,
     MAX,
 } mpqemu_cmd_t;
 
@@ -120,8 +121,12 @@  struct MPQemuLinkState {
     GMainLoop *loop;
 
     MPQemuChannel *com;
+    MPQemuChannel *dev;
 
     mpqemu_link_callback callback;
+
+    void *opaque;
+    QemuThread thread;
 };
 
 MPQemuLinkState *mpqemu_link_create(void);
diff --git a/io/mpqemu-link.c b/io/mpqemu-link.c
index 3f81cef96e..f780b65181 100644
--- a/io/mpqemu-link.c
+++ b/io/mpqemu-link.c
@@ -46,6 +46,9 @@  MPQemuLinkState *mpqemu_link_create(void)
     MPQemuLinkState *link = MPQEMU_LINK(object_new(TYPE_MPQEMU_LINK));
 
     link->com = NULL;
+    link->dev = NULL;
+
+    link->opaque = NULL;
 
     return link;
 }
diff --git a/remote/remote-main.c b/remote/remote-main.c
index dbd6ad2529..f541baae6a 100644
--- a/remote/remote-main.c
+++ b/remote/remote-main.c
@@ -35,6 +35,9 @@ 
 #include "exec/ramlist.h"
 #include "remote/remote-common.h"
 
+static void process_msg(GIOCondition cond, MPQemuLinkState *link,
+                        MPQemuChannel *chan);
+
 static MPQemuLinkState *mpqemu_link;
 
 gchar *print_pid_exec(gchar *str)
@@ -48,6 +51,43 @@  gchar *print_pid_exec(gchar *str)
     return str;
 }
 
+#define LINK_TO_DEV(link) ((PCIDevice *)link->opaque)
+
+static gpointer dev_thread(gpointer data)
+{
+    MPQemuLinkState *link = data;
+
+    mpqemu_start_coms(link, link->dev);
+
+    return NULL;
+}
+
+static void process_connect_dev_msg(MPQemuMsg *msg)
+{
+    char *devid = (char *)msg->data2;
+    MPQemuLinkState *link = NULL;
+    DeviceState *dev = NULL;
+    int wait = msg->fds[0];
+    int ret = 0;
+
+    dev = qdev_find_recursive(sysbus_get_default(), devid);
+    if (!dev) {
+        ret = 0xff;
+        goto exit;
+    }
+
+    link = mpqemu_link_create();
+    link->opaque = (void *)PCI_DEVICE(dev);
+
+    mpqemu_init_channel(link, &link->dev, msg->fds[1]);
+    mpqemu_link_set_callback(link, process_msg);
+    qemu_thread_create(&link->thread, "dev_thread", dev_thread, link,
+                       QEMU_THREAD_JOINABLE);
+
+exit:
+    notify_proxy(wait, ret);
+}
+
 static void process_msg(GIOCondition cond, MPQemuLinkState *link,
                         MPQemuChannel *chan)
 {
@@ -72,6 +112,9 @@  static void process_msg(GIOCondition cond, MPQemuLinkState *link,
     switch (msg->cmd) {
     case INIT:
         break;
+    case CONNECT_DEV:
+        process_connect_dev_msg(msg);
+        break;
     default:
         error_setg(&err, "Unknown command in %s", print_pid_exec(pid_exec));
         goto finalize_loop;