qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/9] v2: Fixes, new way of discovering ports
@ 2010-03-23 14:30 Amit Shah
  2010-03-23 14:30 ` [Qemu-devel] [PATCH 1/9] virtio-serial-bus: save/load: Ensure target has enough ports Amit Shah
  2010-03-23 14:57 ` [Qemu-devel] Re: [PATCH 0/9] v2: Fixes, new way of discovering ports Juan Quintela
  0 siblings, 2 replies; 12+ messages in thread
From: Amit Shah @ 2010-03-23 14:30 UTC (permalink / raw)
  To: qemu list; +Cc: Amit Shah, quintela, Gerd Hoffmann, Michael S. Tsirkin

Hello,

These patches rework the way ports are announced to the guests. A
control message is used to let the guest know a new port is
added. Initial port discovery and port hot-plug work via this way now.

This was done to have the host and guest port numbering in sync to
avoid surprises after several hotplug/unplug operations and
migrations.

The ability to assign a particular port number to ports is also added
so that management software can control the placement of ports.

The other patches to handle scatter/gather for guest data and
migration fixes remain the same.

Please review.

Amit Shah (9):
  virtio-serial-bus: save/load: Ensure target has enough ports
  virtio-serial-bus: save/load: Ensure nr_ports on src and dest are
    same.
  virtio-serial: Remove redundant check for 0-sized write request
  virtio-serial: Update copyright year to 2010
  virtio-serial: save/load: Ensure we have hot-plugged ports
    instantiated
  virtio-serial-bus: Use control messages to notify guest of new ports
  virtio-serial-bus: Let the guest know of host connection changes
    after migration
  virtio-serial: Handle scatter-gather buffers for control messages
  virtio-serial: Handle scatter/gather input from the guest

 hw/virtio-console.c    |    4 +-
 hw/virtio-serial-bus.c |  245 +++++++++++++++++++++++++++++++++++++-----------
 hw/virtio-serial.h     |   19 ++--
 3 files changed, 205 insertions(+), 63 deletions(-)

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [Qemu-devel] [PATCH 1/9] virtio-serial-bus: save/load: Ensure target has enough ports
  2010-03-23 14:30 [Qemu-devel] [PATCH 0/9] v2: Fixes, new way of discovering ports Amit Shah
@ 2010-03-23 14:30 ` Amit Shah
  2010-03-23 14:30   ` [Qemu-devel] [PATCH 2/9] virtio-serial-bus: save/load: Ensure nr_ports on src and dest are same Amit Shah
  2010-03-23 14:57 ` [Qemu-devel] Re: [PATCH 0/9] v2: Fixes, new way of discovering ports Juan Quintela
  1 sibling, 1 reply; 12+ messages in thread
From: Amit Shah @ 2010-03-23 14:30 UTC (permalink / raw)
  To: qemu list; +Cc: Amit Shah, quintela, Gerd Hoffmann, Michael S. Tsirkin

The target could be started with max_nr_ports for a virtio-serial device
lesser than what was available on the source machine. Fail the migration
in such a case.

Signed-off-by: Amit Shah <amit.shah@redhat.com>
Reported-by: Juan Quintela <quintela@redhat.com>
---
 hw/virtio-serial-bus.c |   10 +++++++++-
 1 files changed, 9 insertions(+), 1 deletions(-)

diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
index 17c1ec1..36985a1 100644
--- a/hw/virtio-serial-bus.c
+++ b/hw/virtio-serial-bus.c
@@ -374,6 +374,8 @@ static void virtio_serial_save(QEMUFile *f, void *opaque)
 
     /* Items in struct VirtIOSerial */
 
+    qemu_put_be32s(f, &s->bus->max_nr_ports);
+
     /* Do this because we might have hot-unplugged some ports */
     nr_active_ports = 0;
     QTAILQ_FOREACH(port, &s->ports, next)
@@ -399,7 +401,7 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
 {
     VirtIOSerial *s = opaque;
     VirtIOSerialPort *port;
-    uint32_t nr_active_ports;
+    uint32_t max_nr_ports, nr_active_ports;
     unsigned int i;
 
     if (version_id > 2) {
@@ -420,6 +422,12 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
 
     /* Items in struct VirtIOSerial */
 
+    qemu_get_be32s(f, &max_nr_ports);
+    if (max_nr_ports > s->bus->max_nr_ports) {
+        /* Source could have more ports than us. Fail migration. */
+        return -EINVAL;
+    }
+
     qemu_get_be32s(f, &nr_active_ports);
 
     /* Items in struct VirtIOSerialPort */
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [Qemu-devel] [PATCH 2/9] virtio-serial-bus: save/load: Ensure nr_ports on src and dest are same.
  2010-03-23 14:30 ` [Qemu-devel] [PATCH 1/9] virtio-serial-bus: save/load: Ensure target has enough ports Amit Shah
@ 2010-03-23 14:30   ` Amit Shah
  2010-03-23 14:30     ` [Qemu-devel] [PATCH 3/9] virtio-serial: Remove redundant check for 0-sized write request Amit Shah
  0 siblings, 1 reply; 12+ messages in thread
From: Amit Shah @ 2010-03-23 14:30 UTC (permalink / raw)
  To: qemu list; +Cc: Amit Shah, quintela, Gerd Hoffmann, Michael S. Tsirkin

The number of ports on the source as well as the destination machines
should match. If they don't, it means some ports that got hotplugged on
the source aren't instantiated on the destination. Or that ports that
were hot-unplugged on the source are created on the destination.

Signed-off-by: Amit Shah <amit.shah@redhat.com>
Reported-by: Juan Quintela <quintela@redhat.com>
---
 hw/virtio-serial-bus.c |   18 ++++++++++++++++--
 1 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
index 36985a1..f43d1fc 100644
--- a/hw/virtio-serial-bus.c
+++ b/hw/virtio-serial-bus.c
@@ -401,7 +401,7 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
 {
     VirtIOSerial *s = opaque;
     VirtIOSerialPort *port;
-    uint32_t max_nr_ports, nr_active_ports;
+    uint32_t max_nr_ports, nr_active_ports, nr_ports;
     unsigned int i;
 
     if (version_id > 2) {
@@ -418,7 +418,21 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
     /* The config space */
     qemu_get_be16s(f, &s->config.cols);
     qemu_get_be16s(f, &s->config.rows);
-    s->config.nr_ports = qemu_get_be32(f);
+    nr_ports = qemu_get_be32(f);
+
+    if (nr_ports != s->config.nr_ports) {
+        /*
+         * Source hot-plugged/unplugged ports and we don't have all of
+         * them here.
+         *
+         * Note: This condition cannot check for all hotplug/unplug
+         * events: eg, if one port was hot-plugged and one was
+         * unplugged, the nr_ports remains the same but the port id's
+         * would have changed and we won't catch it here. A later
+         * check for !find_port_by_id() will confirm if this happened.
+         */
+        return -EINVAL;
+    }
 
     /* Items in struct VirtIOSerial */
 
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [Qemu-devel] [PATCH 3/9] virtio-serial: Remove redundant check for 0-sized write request
  2010-03-23 14:30   ` [Qemu-devel] [PATCH 2/9] virtio-serial-bus: save/load: Ensure nr_ports on src and dest are same Amit Shah
@ 2010-03-23 14:30     ` Amit Shah
  2010-03-23 14:30       ` [Qemu-devel] [PATCH 4/9] virtio-serial: Update copyright year to 2010 Amit Shah
  0 siblings, 1 reply; 12+ messages in thread
From: Amit Shah @ 2010-03-23 14:30 UTC (permalink / raw)
  To: qemu list; +Cc: Amit Shah, quintela, Gerd Hoffmann, Michael S. Tsirkin

The check for a 0-sized write request to a guest port is not necessary;
the while loop below won't be executed in this case and all will be
fine.

Signed-off-by: Amit Shah <amit.shah@redhat.com>
---
 hw/virtio-serial-bus.c |    3 ---
 1 files changed, 0 insertions(+), 3 deletions(-)

diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
index f43d1fc..7e9df96 100644
--- a/hw/virtio-serial-bus.c
+++ b/hw/virtio-serial-bus.c
@@ -83,9 +83,6 @@ static size_t write_to_port(VirtIOSerialPort *port,
     if (!virtio_queue_ready(vq)) {
         return 0;
     }
-    if (!size) {
-        return 0;
-    }
 
     while (offset < size) {
         int i;
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [Qemu-devel] [PATCH 4/9] virtio-serial: Update copyright year to 2010
  2010-03-23 14:30     ` [Qemu-devel] [PATCH 3/9] virtio-serial: Remove redundant check for 0-sized write request Amit Shah
@ 2010-03-23 14:30       ` Amit Shah
  2010-03-23 14:30         ` [Qemu-devel] [PATCH 5/9] virtio-serial: save/load: Ensure we have hot-plugged ports instantiated Amit Shah
  0 siblings, 1 reply; 12+ messages in thread
From: Amit Shah @ 2010-03-23 14:30 UTC (permalink / raw)
  To: qemu list; +Cc: Amit Shah, quintela, Gerd Hoffmann, Michael S. Tsirkin

Signed-off-by: Amit Shah <amit.shah@redhat.com>
---
 hw/virtio-console.c    |    2 +-
 hw/virtio-serial-bus.c |    2 +-
 hw/virtio-serial.h     |    2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/hw/virtio-console.c b/hw/virtio-console.c
index bd44ec6..e915491 100644
--- a/hw/virtio-console.c
+++ b/hw/virtio-console.c
@@ -1,7 +1,7 @@
 /*
  * Virtio Console and Generic Serial Port Devices
  *
- * Copyright Red Hat, Inc. 2009
+ * Copyright Red Hat, Inc. 2009, 2010
  *
  * Authors:
  *  Amit Shah <amit.shah@redhat.com>
diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
index 7e9df96..bf7899c 100644
--- a/hw/virtio-serial-bus.c
+++ b/hw/virtio-serial-bus.c
@@ -1,7 +1,7 @@
 /*
  * A bus for connecting virtio serial and console ports
  *
- * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2009, 2010 Red Hat, Inc.
  *
  * Author(s):
  *  Amit Shah <amit.shah@redhat.com>
diff --git a/hw/virtio-serial.h b/hw/virtio-serial.h
index f297b00..632d31b 100644
--- a/hw/virtio-serial.h
+++ b/hw/virtio-serial.h
@@ -2,7 +2,7 @@
  * Virtio Serial / Console Support
  *
  * Copyright IBM, Corp. 2008
- * Copyright Red Hat, Inc. 2009
+ * Copyright Red Hat, Inc. 2009, 2010
  *
  * Authors:
  *  Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [Qemu-devel] [PATCH 5/9] virtio-serial: save/load: Ensure we have hot-plugged ports instantiated
  2010-03-23 14:30       ` [Qemu-devel] [PATCH 4/9] virtio-serial: Update copyright year to 2010 Amit Shah
@ 2010-03-23 14:30         ` Amit Shah
  2010-03-23 14:30           ` [Qemu-devel] [PATCH 6/9] virtio-serial-bus: Use control messages to notify guest of new ports Amit Shah
  0 siblings, 1 reply; 12+ messages in thread
From: Amit Shah @ 2010-03-23 14:30 UTC (permalink / raw)
  To: qemu list; +Cc: Amit Shah, quintela, Gerd Hoffmann, Michael S. Tsirkin

If some ports that were hot-plugged on the source are not available on
the destination, fail migration instead of trying to deref a NULL
pointer.

Signed-off-by: Amit Shah <amit.shah@redhat.com>
Reported-by: Juan Quintela <quintela@redhat.com>
---
 hw/virtio-serial-bus.c |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
index bf7899c..e8eb5aa 100644
--- a/hw/virtio-serial-bus.c
+++ b/hw/virtio-serial-bus.c
@@ -447,6 +447,13 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
 
         id = qemu_get_be32(f);
         port = find_port_by_id(s, id);
+        if (!port) {
+            /*
+             * The requested port was hot-plugged on the source but we
+             * don't have it
+             */
+            return -EINVAL;
+        }
 
         port->guest_connected = qemu_get_byte(f);
     }
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [Qemu-devel] [PATCH 6/9] virtio-serial-bus: Use control messages to notify guest of new ports
  2010-03-23 14:30         ` [Qemu-devel] [PATCH 5/9] virtio-serial: save/load: Ensure we have hot-plugged ports instantiated Amit Shah
@ 2010-03-23 14:30           ` Amit Shah
  2010-03-23 14:30             ` [Qemu-devel] [PATCH 7/9] virtio-serial-bus: Let the guest know of host connection changes after migration Amit Shah
  0 siblings, 1 reply; 12+ messages in thread
From: Amit Shah @ 2010-03-23 14:30 UTC (permalink / raw)
  To: qemu list; +Cc: Amit Shah, quintela, Gerd Hoffmann, Michael S. Tsirkin

Allow the port 'id's to be set by a user on the command line. This is
needed by management apps that will want a stable port numbering scheme
for hot-plug/unplug and migration.

Since the port numbers are shared with the guest (to identify ports in
control messages), we just send a control message to the guest
indicating addition of new ports (hot-plug) or notifying the guest of
the available ports when the guest sends us a DEVICE_READY control
message.

Signed-off-by: Amit Shah <amit.shah@redhat.com>
---
 hw/virtio-console.c    |    2 +
 hw/virtio-serial-bus.c |  182 +++++++++++++++++++++++++++++++-----------------
 hw/virtio-serial.h     |   17 +++--
 3 files changed, 130 insertions(+), 71 deletions(-)

diff --git a/hw/virtio-console.c b/hw/virtio-console.c
index e915491..bbbb6b8 100644
--- a/hw/virtio-console.c
+++ b/hw/virtio-console.c
@@ -99,6 +99,7 @@ static VirtIOSerialPortInfo virtconsole_info = {
     .exit          = virtconsole_exitfn,
     .qdev.props = (Property[]) {
         DEFINE_PROP_UINT8("is_console", VirtConsole, port.is_console, 1),
+        DEFINE_PROP_UINT32("nr", VirtConsole, port.id, VIRTIO_CONSOLE_BAD_ID),
         DEFINE_PROP_CHR("chardev", VirtConsole, chr),
         DEFINE_PROP_STRING("name", VirtConsole, port.name),
         DEFINE_PROP_END_OF_LIST(),
@@ -133,6 +134,7 @@ static VirtIOSerialPortInfo virtserialport_info = {
     .init          = virtserialport_initfn,
     .exit          = virtconsole_exitfn,
     .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("nr", VirtConsole, port.id, VIRTIO_CONSOLE_BAD_ID),
         DEFINE_PROP_CHR("chardev", VirtConsole, chr),
         DEFINE_PROP_STRING("name", VirtConsole, port.name),
         DEFINE_PROP_END_OF_LIST(),
diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
index e8eb5aa..dd50f2d 100644
--- a/hw/virtio-serial-bus.c
+++ b/hw/virtio-serial-bus.c
@@ -41,6 +41,10 @@ struct VirtIOSerial {
     VirtIOSerialBus *bus;
 
     QTAILQ_HEAD(, VirtIOSerialPort) ports;
+
+    /* bitmap for identifying active ports */
+    uint32_t *ports_map;
+
     struct virtio_console_config config;
 };
 
@@ -48,6 +52,10 @@ static VirtIOSerialPort *find_port_by_id(VirtIOSerial *vser, uint32_t id)
 {
     VirtIOSerialPort *port;
 
+    if (id == VIRTIO_CONSOLE_BAD_ID) {
+        return NULL;
+    }
+
     QTAILQ_FOREACH(port, &vser->ports, next) {
         if (port->id == id)
             return port;
@@ -205,14 +213,25 @@ static void handle_control_message(VirtIOSerial *vser, void *buf)
     size_t buffer_len;
 
     gcpkt = buf;
-    port = find_port_by_id(vser, ldl_p(&gcpkt->id));
-    if (!port)
-        return;
 
     cpkt.event = lduw_p(&gcpkt->event);
     cpkt.value = lduw_p(&gcpkt->value);
 
+    port = find_port_by_id(vser, ldl_p(&gcpkt->id));
+    if (!port && cpkt.event != VIRTIO_CONSOLE_DEVICE_READY)
+        return;
+
     switch(cpkt.event) {
+    case VIRTIO_CONSOLE_DEVICE_READY:
+        /*
+         * The device is up, we can now tell the device about all the
+         * ports we have here.
+         */
+        QTAILQ_FOREACH(port, &vser->ports, next) {
+            send_control_event(port, VIRTIO_CONSOLE_PORT_ADD, 1);
+        }
+        break;
+
     case VIRTIO_CONSOLE_PORT_READY:
         /*
          * Now that we know the guest asked for the port name, we're
@@ -367,13 +386,16 @@ static void virtio_serial_save(QEMUFile *f, void *opaque)
     /* The config space */
     qemu_put_be16s(f, &s->config.cols);
     qemu_put_be16s(f, &s->config.rows);
-    qemu_put_be32s(f, &s->config.nr_ports);
 
-    /* Items in struct VirtIOSerial */
+    qemu_put_be32s(f, &s->config.max_nr_ports);
+
+    /* The ports map */
 
-    qemu_put_be32s(f, &s->bus->max_nr_ports);
+    qemu_put_buffer(f, (uint8_t *)s->ports_map,
+                    sizeof(uint32_t) * (s->config.max_nr_ports + 31) / 32);
+
+    /* Ports */
 
-    /* Do this because we might have hot-unplugged some ports */
     nr_active_ports = 0;
     QTAILQ_FOREACH(port, &s->ports, next)
         nr_active_ports++;
@@ -384,11 +406,6 @@ static void virtio_serial_save(QEMUFile *f, void *opaque)
      * Items in struct VirtIOSerialPort.
      */
     QTAILQ_FOREACH(port, &s->ports, next) {
-        /*
-         * We put the port number because we may not have an active
-         * port at id 0 that's reserved for a console port, or in case
-         * of ports that might have gotten unplugged
-         */
         qemu_put_be32s(f, &port->id);
         qemu_put_byte(f, port->guest_connected);
     }
@@ -398,7 +415,8 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
 {
     VirtIOSerial *s = opaque;
     VirtIOSerialPort *port;
-    uint32_t max_nr_ports, nr_active_ports, nr_ports;
+    size_t ports_map_size;
+    uint32_t max_nr_ports, nr_active_ports, *ports_map;
     unsigned int i;
 
     if (version_id > 2) {
@@ -415,29 +433,28 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
     /* The config space */
     qemu_get_be16s(f, &s->config.cols);
     qemu_get_be16s(f, &s->config.rows);
-    nr_ports = qemu_get_be32(f);
 
-    if (nr_ports != s->config.nr_ports) {
-        /*
-         * Source hot-plugged/unplugged ports and we don't have all of
-         * them here.
-         *
-         * Note: This condition cannot check for all hotplug/unplug
-         * events: eg, if one port was hot-plugged and one was
-         * unplugged, the nr_ports remains the same but the port id's
-         * would have changed and we won't catch it here. A later
-         * check for !find_port_by_id() will confirm if this happened.
-         */
+    qemu_get_be32s(f, &max_nr_ports);
+    if (max_nr_ports > s->config.max_nr_ports) {
+        /* Source could have had more ports than us. Fail migration. */
         return -EINVAL;
     }
 
-    /* Items in struct VirtIOSerial */
+    ports_map_size = sizeof(uint32_t) * (max_nr_ports + 31) / 32;
+    ports_map = qemu_malloc(ports_map_size);
+    qemu_get_buffer(f, (uint8_t *)ports_map, ports_map_size);
 
-    qemu_get_be32s(f, &max_nr_ports);
-    if (max_nr_ports > s->bus->max_nr_ports) {
-        /* Source could have more ports than us. Fail migration. */
-        return -EINVAL;
+    for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
+        if (ports_map[i] != s->ports_map[i]) {
+            /*
+             * Ports active on source and destination don't
+             * match. Fail migration.
+             */
+            qemu_free(ports_map);
+            return -EINVAL;
+        }
     }
+    qemu_free(ports_map);
 
     qemu_get_be32s(f, &nr_active_ports);
 
@@ -447,20 +464,11 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
 
         id = qemu_get_be32(f);
         port = find_port_by_id(s, id);
-        if (!port) {
-            /*
-             * The requested port was hot-plugged on the source but we
-             * don't have it
-             */
-            return -EINVAL;
-        }
 
         port->guest_connected = qemu_get_byte(f);
     }
-
     return 0;
 }
-
 static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent);
 
 static struct BusInfo virtser_bus_info = {
@@ -492,6 +500,50 @@ static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
                    indent, "", port->host_connected);
 }
 
+/* This function is only used if a port id is not provided by the user */
+static uint32_t find_free_port_id(VirtIOSerial *vser)
+{
+    unsigned int i;
+
+    for (i = 0; i < (vser->config.max_nr_ports + 31) / 32; i++) {
+        uint32_t map, bit;
+
+        map = vser->ports_map[i];
+        bit = ffs(~map);
+        if (bit) {
+            return (bit - 1) + i * 32;
+        }
+    }
+    return VIRTIO_CONSOLE_BAD_ID;
+}
+
+static void mark_port_added(VirtIOSerial *vser, uint32_t port_id)
+{
+    unsigned int i;
+
+    i = port_id / 32;
+    vser->ports_map[i] |= 1U << (port_id % 32);
+}
+
+static void add_port(VirtIOSerial *vser, uint32_t port_id)
+{
+    mark_port_added(vser, port_id);
+
+    send_control_event(find_port_by_id(vser, port_id),
+                       VIRTIO_CONSOLE_PORT_ADD, 1);
+}
+
+static void remove_port(VirtIOSerial *vser, uint32_t port_id)
+{
+    unsigned int i;
+
+    i = port_id / 32;
+    vser->ports_map[i] &= ~(1U << (port_id % 32));
+
+    send_control_event(find_port_by_id(vser, port_id),
+                       VIRTIO_CONSOLE_PORT_REMOVE, 1);
+}
+
 static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
 {
     VirtIOSerialDevice *dev = DO_UPCAST(VirtIOSerialDevice, qdev, qdev);
@@ -510,19 +562,36 @@ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
      */
     plugging_port0 = port->is_console && !find_port_by_id(port->vser, 0);
 
-    if (port->vser->config.nr_ports == bus->max_nr_ports && !plugging_port0) {
-        error_report("virtio-serial-bus: Maximum device limit reached");
+    if (find_port_by_id(port->vser, port->id)) {
+        error_report("virtio-serial-bus: A port already exists at id %u\n",
+                     port->id);
         return -1;
     }
-    dev->info = info;
 
+    if (plugging_port0) {
+        port->id = 0;
+    }
+
+    if (port->id == VIRTIO_CONSOLE_BAD_ID) {
+        port->id = find_free_port_id(port->vser);
+        if (port->id == VIRTIO_CONSOLE_BAD_ID) {
+            error_report("virtio-serial-bus: Maximum device limit reached\n");
+            return -1;
+        }
+    }
+
+    if (port->id >= port->vser->config.max_nr_ports) {
+        error_report("virtio-serial-bus: Out-of-range port id specified, max. allowed: %u\n",
+                     port->vser->config.max_nr_ports - 1);
+        return -1;
+    }
+
+    dev->info = info;
     ret = info->init(dev);
     if (ret) {
         return ret;
     }
 
-    port->id = plugging_port0 ? 0 : port->vser->config.nr_ports++;
-
     if (!use_multiport(port->vser)) {
         /*
          * Allow writes to guest in this case; we have no way of
@@ -535,6 +604,8 @@ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
     port->ivq = port->vser->ivqs[port->id];
     port->ovq = port->vser->ovqs[port->id];
 
+    add_port(port->vser, port->id);
+
     /* Send an update to the guest about this new port added */
     virtio_notify_config(&port->vser->vdev);
 
@@ -547,26 +618,8 @@ static int virtser_port_qdev_exit(DeviceState *qdev)
     VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
     VirtIOSerial *vser = port->vser;
 
-    send_control_event(port, VIRTIO_CONSOLE_PORT_REMOVE, 1);
+    remove_port(port->vser, port->id);
 
-    /*
-     * Don't decrement nr_ports here; thus we keep a linearly
-     * increasing port id. Not utilising an id again saves us a couple
-     * of complications:
-     *
-     * - Not having to bother about sending the port id to the guest
-     *   kernel on hotplug or on addition of new ports; the guest can
-     *   also linearly increment the port number. This is preferable
-     *   because the config space won't have the need to store a
-     *   ports_map.
-     *
-     * - Extra state to be stored for all the "holes" that got created
-     *   so that we keep filling in the ids from the least available
-     *   index.
-     *
-     * When such a functionality is desired, a control message to add
-     * a port can be introduced.
-     */
     QTAILQ_REMOVE(&vser->ports, port, next);
 
     if (port->info->exit)
@@ -626,11 +679,12 @@ VirtIODevice *virtio_serial_init(DeviceState *dev, uint32_t max_nr_ports)
     }
 
     vser->config.max_nr_ports = max_nr_ports;
+    vser->ports_map = qemu_mallocz((max_nr_ports + 31) / 32);
     /*
      * Reserve location 0 for a console port for backward compat
      * (old kernel, new qemu)
      */
-    vser->config.nr_ports = 1;
+    mark_port_added(vser, 0);
 
     vser->vdev.get_features = get_features;
     vser->vdev.get_config = get_config;
diff --git a/hw/virtio-serial.h b/hw/virtio-serial.h
index 632d31b..f023873 100644
--- a/hw/virtio-serial.h
+++ b/hw/virtio-serial.h
@@ -27,6 +27,8 @@
 /* Features supported */
 #define VIRTIO_CONSOLE_F_MULTIPORT	1
 
+#define VIRTIO_CONSOLE_BAD_ID           (~(uint32_t)0)
+
 struct virtio_console_config {
     /*
      * These two fields are used by VIRTIO_CONSOLE_F_SIZE which
@@ -36,7 +38,6 @@ struct virtio_console_config {
     uint16_t rows;
 
     uint32_t max_nr_ports;
-    uint32_t nr_ports;
 } __attribute__((packed));
 
 struct virtio_console_control {
@@ -46,12 +47,14 @@ struct virtio_console_control {
 };
 
 /* Some events for the internal messages (control packets) */
-#define VIRTIO_CONSOLE_PORT_READY	0
-#define VIRTIO_CONSOLE_CONSOLE_PORT	1
-#define VIRTIO_CONSOLE_RESIZE		2
-#define VIRTIO_CONSOLE_PORT_OPEN	3
-#define VIRTIO_CONSOLE_PORT_NAME	4
-#define VIRTIO_CONSOLE_PORT_REMOVE	5
+#define VIRTIO_CONSOLE_DEVICE_READY	0
+#define VIRTIO_CONSOLE_PORT_ADD		1
+#define VIRTIO_CONSOLE_PORT_REMOVE	2
+#define VIRTIO_CONSOLE_PORT_READY	3
+#define VIRTIO_CONSOLE_CONSOLE_PORT	4
+#define VIRTIO_CONSOLE_RESIZE		5
+#define VIRTIO_CONSOLE_PORT_OPEN	6
+#define VIRTIO_CONSOLE_PORT_NAME	7
 
 /* == In-qemu interface == */
 
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [Qemu-devel] [PATCH 7/9] virtio-serial-bus: Let the guest know of host connection changes after migration
  2010-03-23 14:30           ` [Qemu-devel] [PATCH 6/9] virtio-serial-bus: Use control messages to notify guest of new ports Amit Shah
@ 2010-03-23 14:30             ` Amit Shah
  2010-03-23 14:30               ` [Qemu-devel] [PATCH 8/9] virtio-serial: Handle scatter-gather buffers for control messages Amit Shah
  0 siblings, 1 reply; 12+ messages in thread
From: Amit Shah @ 2010-03-23 14:30 UTC (permalink / raw)
  To: qemu list; +Cc: Amit Shah, quintela, Gerd Hoffmann, Michael S. Tsirkin

If the host connection to a port is closed on the destination machine
after migration, when the connection was open on the source, the host
has to be informed of that.

Similar for a host connection open on the destination.

Signed-off-by: Amit Shah <amit.shah@redhat.com>
---
 hw/virtio-serial-bus.c |   11 +++++++++++
 1 files changed, 11 insertions(+), 0 deletions(-)

diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
index dd50f2d..6d12c10 100644
--- a/hw/virtio-serial-bus.c
+++ b/hw/virtio-serial-bus.c
@@ -408,6 +408,7 @@ static void virtio_serial_save(QEMUFile *f, void *opaque)
     QTAILQ_FOREACH(port, &s->ports, next) {
         qemu_put_be32s(f, &port->id);
         qemu_put_byte(f, port->guest_connected);
+        qemu_put_byte(f, port->host_connected);
     }
 }
 
@@ -461,11 +462,21 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
     /* Items in struct VirtIOSerialPort */
     for (i = 0; i < nr_active_ports; i++) {
         uint32_t id;
+        bool host_connected;
 
         id = qemu_get_be32(f);
         port = find_port_by_id(s, id);
 
         port->guest_connected = qemu_get_byte(f);
+        host_connected = qemu_get_byte(f);
+        if (host_connected != port->host_connected) {
+            /*
+             * We have to let the guest know of the host connection
+             * status change
+             */
+            send_control_event(port, VIRTIO_CONSOLE_PORT_OPEN,
+                               port->host_connected);
+        }
     }
     return 0;
 }
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [Qemu-devel] [PATCH 8/9] virtio-serial: Handle scatter-gather buffers for control messages
  2010-03-23 14:30             ` [Qemu-devel] [PATCH 7/9] virtio-serial-bus: Let the guest know of host connection changes after migration Amit Shah
@ 2010-03-23 14:30               ` Amit Shah
  2010-03-23 14:30                 ` [Qemu-devel] [PATCH 9/9] virtio-serial: Handle scatter/gather input from the guest Amit Shah
  0 siblings, 1 reply; 12+ messages in thread
From: Amit Shah @ 2010-03-23 14:30 UTC (permalink / raw)
  To: qemu list
  Cc: Amit Shah, Avi Kivity, quintela, Gerd Hoffmann,
	Michael S. Tsirkin

Current control messages are small enough to not be split into multiple
buffers but we could run into such a situation in the future or a
malicious guest could cause such a situation.

So handle the entire iov request for control messages.

Also ensure the size of the control request is >= what we expect
otherwise we risk accessing memory that we don't own.

Signed-off-by: Amit Shah <amit.shah@redhat.com>
CC: Avi Kivity <avi@redhat.com>
Reported-by: Avi Kivity <avi@redhat.com>
---
 hw/virtio-serial-bus.c |   44 +++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 41 insertions(+), 3 deletions(-)

diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
index 6d12c10..fe976ec 100644
--- a/hw/virtio-serial-bus.c
+++ b/hw/virtio-serial-bus.c
@@ -205,7 +205,7 @@ size_t virtio_serial_guest_ready(VirtIOSerialPort *port)
 }
 
 /* Guest wants to notify us of some event */
-static void handle_control_message(VirtIOSerial *vser, void *buf)
+static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
 {
     struct VirtIOSerialPort *port;
     struct virtio_console_control cpkt, *gcpkt;
@@ -214,6 +214,11 @@ static void handle_control_message(VirtIOSerial *vser, void *buf)
 
     gcpkt = buf;
 
+    if (len < sizeof(cpkt)) {
+        /* The guest sent an invalid control packet */
+        return;
+    }
+
     cpkt.event = lduw_p(&gcpkt->event);
     cpkt.value = lduw_p(&gcpkt->value);
 
@@ -297,12 +302,45 @@ static void control_out(VirtIODevice *vdev, VirtQueue *vq)
 {
     VirtQueueElement elem;
     VirtIOSerial *vser;
+    uint8_t *buf;
+    size_t len;
 
     vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
 
+    len = 0;
+    buf = NULL;
     while (virtqueue_pop(vq, &elem)) {
-        handle_control_message(vser, elem.out_sg[0].iov_base);
-        virtqueue_push(vq, &elem, elem.out_sg[0].iov_len);
+        unsigned int i;
+        size_t cur_len, offset;
+
+        cur_len = 0;
+        for (i = 0; i < elem.out_num; i++) {
+            cur_len += elem.out_sg[i].iov_len;
+        }
+        /*
+         * Allocate a new buf only if we didn't have one previously or
+         * if the size of the buf differs
+         */
+        if (cur_len != len) {
+            if (len) {
+                qemu_free(buf);
+            }
+            buf = qemu_malloc(cur_len);
+        }
+
+        offset = 0;
+        for (i = 0; i < elem.out_num; i++) {
+            memcpy(buf + offset, elem.out_sg[i].iov_base,
+                   elem.out_sg[i].iov_len);
+            offset += elem.out_sg[i].iov_len;
+        }
+        len = cur_len;
+
+        handle_control_message(vser, buf, len);
+        virtqueue_push(vq, &elem, len);
+    }
+    if (len) {
+        qemu_free(buf);
     }
     virtio_notify(vdev, vq);
 }
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [Qemu-devel] [PATCH 9/9] virtio-serial: Handle scatter/gather input from the guest
  2010-03-23 14:30               ` [Qemu-devel] [PATCH 8/9] virtio-serial: Handle scatter-gather buffers for control messages Amit Shah
@ 2010-03-23 14:30                 ` Amit Shah
  2010-03-23 15:49                   ` [Qemu-devel] " Amit Shah
  0 siblings, 1 reply; 12+ messages in thread
From: Amit Shah @ 2010-03-23 14:30 UTC (permalink / raw)
  To: qemu list
  Cc: Amit Shah, Avi Kivity, quintela, Gerd Hoffmann,
	Michael S. Tsirkin

Current guests don't send more than one iov but it can change later.
Ensure we handle that case.

Signed-off-by: Amit Shah <amit.shah@redhat.com>
CC: Avi Kivity <avi@redhat.com>
---
 hw/virtio-serial-bus.c |   22 +++++++++++++++-------
 1 files changed, 15 insertions(+), 7 deletions(-)

diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
index fe976ec..2ca3c0a 100644
--- a/hw/virtio-serial-bus.c
+++ b/hw/virtio-serial-bus.c
@@ -355,11 +355,12 @@ static void handle_output(VirtIODevice *vdev, VirtQueue *vq)
 
     while (virtqueue_pop(vq, &elem)) {
         VirtIOSerialPort *port;
-        size_t ret;
+        size_t len;
+        unsigned int i;
 
+        len = 0;
         port = find_port_by_vq(vser, vq);
         if (!port) {
-            ret = 0;
             goto next_buf;
         }
 
@@ -369,16 +370,23 @@ static void handle_output(VirtIODevice *vdev, VirtQueue *vq)
          * with it. Just ignore the data in that case.
          */
         if (!port->info->have_data) {
-            ret = 0;
             goto next_buf;
         }
 
-        /* The guest always sends only one sg */
-        ret = port->info->have_data(port, elem.out_sg[0].iov_base,
-                                    elem.out_sg[0].iov_len);
+        for (i = 0; i < elem.out_num; i++) {
+            size_t ret;
+
+            ret = port->info->have_data(port, elem.out_sg[0].iov_base,
+                                        elem.out_sg[0].iov_len);
+            if (ret < elem.out_sg[0].iov_len) {
+                /* We couldn't write the entire iov; stop processing now */
+                break;
+            }
+            len += ret;
+        }
 
     next_buf:
-        virtqueue_push(vq, &elem, ret);
+        virtqueue_push(vq, &elem, len);
     }
     virtio_notify(vdev, vq);
 }
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [Qemu-devel] Re: [PATCH 0/9] v2: Fixes, new way of discovering ports
  2010-03-23 14:30 [Qemu-devel] [PATCH 0/9] v2: Fixes, new way of discovering ports Amit Shah
  2010-03-23 14:30 ` [Qemu-devel] [PATCH 1/9] virtio-serial-bus: save/load: Ensure target has enough ports Amit Shah
@ 2010-03-23 14:57 ` Juan Quintela
  1 sibling, 0 replies; 12+ messages in thread
From: Juan Quintela @ 2010-03-23 14:57 UTC (permalink / raw)
  To: Amit Shah; +Cc: Michael S. Tsirkin, qemu list, Gerd Hoffmann

Amit Shah <amit.shah@redhat.com> wrote:
> Hello,
>
> These patches rework the way ports are announced to the guests. A
> control message is used to let the guest know a new port is
> added. Initial port discovery and port hot-plug work via this way now.
>
> This was done to have the host and guest port numbering in sync to
> avoid surprises after several hotplug/unplug operations and
> migrations.
>
> The ability to assign a particular port number to ports is also added
> so that management software can control the placement of ports.
>
> The other patches to handle scatter/gather for guest data and
> migration fixes remain the same.
>
> Please review.

Acked-by: Juan Quintela <quintela@redhat.com>

it fixes the migration troubles/questions that I raised.  From possible
NULL dereference to checking maximum numbers of ports.

Thanks, Juan.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [Qemu-devel] Re: [PATCH 9/9] virtio-serial: Handle scatter/gather input from the guest
  2010-03-23 14:30                 ` [Qemu-devel] [PATCH 9/9] virtio-serial: Handle scatter/gather input from the guest Amit Shah
@ 2010-03-23 15:49                   ` Amit Shah
  0 siblings, 0 replies; 12+ messages in thread
From: Amit Shah @ 2010-03-23 15:49 UTC (permalink / raw)
  To: qemu list; +Cc: Avi Kivity, quintela, Gerd Hoffmann, Michael S. Tsirkin

On (Tue) Mar 23 2010 [20:00:19], Amit Shah wrote:
> @@ -369,16 +370,23 @@ static void handle_output(VirtIODevice *vdev, VirtQueue *vq)
>           * with it. Just ignore the data in that case.
>           */
>          if (!port->info->have_data) {
> -            ret = 0;
>              goto next_buf;
>          }
>  
> -        /* The guest always sends only one sg */
> -        ret = port->info->have_data(port, elem.out_sg[0].iov_base,
> -                                    elem.out_sg[0].iov_len);
> +        for (i = 0; i < elem.out_num; i++) {
> +            size_t ret;
> +
> +            ret = port->info->have_data(port, elem.out_sg[0].iov_base,
> +                                        elem.out_sg[0].iov_len);
> +            if (ret < elem.out_sg[0].iov_len) {
> +                /* We couldn't write the entire iov; stop processing now */
> +                break;

We should increment len here if ret > 0.

I'll post a followup patch that does this.

> +            }
> +            len += ret;
> +        }
>  
>      next_buf:
> -        virtqueue_push(vq, &elem, ret);
> +        virtqueue_push(vq, &elem, len);
>      }
>      virtio_notify(vdev, vq);
>  }
> -- 
> 1.6.2.5
> 

		Amit

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2010-03-23 15:52 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-03-23 14:30 [Qemu-devel] [PATCH 0/9] v2: Fixes, new way of discovering ports Amit Shah
2010-03-23 14:30 ` [Qemu-devel] [PATCH 1/9] virtio-serial-bus: save/load: Ensure target has enough ports Amit Shah
2010-03-23 14:30   ` [Qemu-devel] [PATCH 2/9] virtio-serial-bus: save/load: Ensure nr_ports on src and dest are same Amit Shah
2010-03-23 14:30     ` [Qemu-devel] [PATCH 3/9] virtio-serial: Remove redundant check for 0-sized write request Amit Shah
2010-03-23 14:30       ` [Qemu-devel] [PATCH 4/9] virtio-serial: Update copyright year to 2010 Amit Shah
2010-03-23 14:30         ` [Qemu-devel] [PATCH 5/9] virtio-serial: save/load: Ensure we have hot-plugged ports instantiated Amit Shah
2010-03-23 14:30           ` [Qemu-devel] [PATCH 6/9] virtio-serial-bus: Use control messages to notify guest of new ports Amit Shah
2010-03-23 14:30             ` [Qemu-devel] [PATCH 7/9] virtio-serial-bus: Let the guest know of host connection changes after migration Amit Shah
2010-03-23 14:30               ` [Qemu-devel] [PATCH 8/9] virtio-serial: Handle scatter-gather buffers for control messages Amit Shah
2010-03-23 14:30                 ` [Qemu-devel] [PATCH 9/9] virtio-serial: Handle scatter/gather input from the guest Amit Shah
2010-03-23 15:49                   ` [Qemu-devel] " Amit Shah
2010-03-23 14:57 ` [Qemu-devel] Re: [PATCH 0/9] v2: Fixes, new way of discovering ports Juan Quintela

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).