From 393f81befec825bfb4f59949d9586f81674a2d34 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sep 08 2012 14:06:35 +0000 Subject: Fix crash on (seamless) migration - Sync usbredir live migration patches with upstream --- diff --git a/0216-qxl-Ignore-set_client_capabilities-pre-post-migrate.patch b/0216-qxl-Ignore-set_client_capabilities-pre-post-migrate.patch new file mode 100644 index 0000000..3391970 --- /dev/null +++ b/0216-qxl-Ignore-set_client_capabilities-pre-post-migrate.patch @@ -0,0 +1,41 @@ +From 68d246d6a904e0a851c521a08a18187598e1c696 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Fri, 7 Sep 2012 21:29:22 +0200 +Subject: [PATCH] qxl: Ignore set_client_capabilities pre/post migrate + +The recent introduction of set_client_capabilities has broken +(seamless) migration by trying to call qxl_send_events pre (seamless +incoming) and post (*) migration, triggering the following assert: +qxl_send_events: Assertion `qemu_spice_display_is_running(&d->ssd)' failed. + +The solution is easy, pre migration the guest will have already received +the client caps on the migration source side, and post migration there no +longer is a guest, so we can simply ignore the set_client_capabilities call +in both those scenarios. + +*) Post migration, so not fatal for to the migration itself, but still a crash + +Signed-off-by: Hans de Goede +--- + hw/qxl.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 045432e..1b400f1 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -953,6 +953,11 @@ static void interface_set_client_capabilities(QXLInstance *sin, + { + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + ++ if (runstate_check(RUN_STATE_INMIGRATE) || ++ runstate_check(RUN_STATE_POSTMIGRATE)) { ++ return; ++ } ++ + qxl->shadow_rom.client_present = client_present; + memcpy(qxl->shadow_rom.client_capabilities, caps, sizeof(caps)); + qxl->rom->client_present = client_present; +-- +1.7.12 + diff --git a/0361-usb-Migrate-over-device-speed-and-speedmask.patch b/0361-usb-Migrate-over-device-speed-and-speedmask.patch deleted file mode 100644 index d775b9c..0000000 --- a/0361-usb-Migrate-over-device-speed-and-speedmask.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 6ba840c192897029895930a504527d4350b88d26 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Thu, 6 Sep 2012 15:34:19 +0200 -Subject: [PATCH 361/366] usb: Migrate over device speed and speedmask - -Signed-off-by: Hans de Goede ---- - hw/usb.h | 4 ++-- - hw/usb/bus.c | 2 ++ - 2 files changed, 4 insertions(+), 2 deletions(-) - -diff --git a/hw/usb.h b/hw/usb.h -index 48c8926..918af99 100644 ---- a/hw/usb.h -+++ b/hw/usb.h -@@ -204,9 +204,9 @@ struct USBDevice { - uint32_t flags; - - /* Actual connected speed */ -- int speed; -+ int32_t speed; - /* Supported speeds, not in info because it may be variable (hostdevs) */ -- int speedmask; -+ int32_t speedmask; - uint8_t addr; - char product_desc[32]; - int auto_attach; -diff --git a/hw/usb/bus.c b/hw/usb/bus.c -index b649360..223c1df 100644 ---- a/hw/usb/bus.c -+++ b/hw/usb/bus.c -@@ -55,6 +55,8 @@ const VMStateDescription vmstate_usb_device = { - .minimum_version_id = 1, - .post_load = usb_device_post_load, - .fields = (VMStateField []) { -+ VMSTATE_INT32(speed, USBDevice), -+ VMSTATE_INT32(speedmask, USBDevice), - VMSTATE_UINT8(addr, USBDevice), - VMSTATE_INT32(state, USBDevice), - VMSTATE_INT32(remote_wakeup, USBDevice), --- -1.7.12 - diff --git a/0361-usb-redir-Change-cancelled-packet-code-into-a-generi.patch b/0361-usb-redir-Change-cancelled-packet-code-into-a-generi.patch new file mode 100644 index 0000000..2efd733 --- /dev/null +++ b/0361-usb-redir-Change-cancelled-packet-code-into-a-generi.patch @@ -0,0 +1,184 @@ +From efbf5d06a89ec7b329d2aa15d3a6ea023b63c646 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Tue, 4 Sep 2012 14:18:34 +0200 +Subject: [PATCH 361/365] usb-redir: Change cancelled packet code into a + generic packet-id queue + +Signed-off-by: Hans de Goede +--- + hw/usb/redirect.c | 102 +++++++++++++++++++++++++++++++++++++----------------- + 1 file changed, 71 insertions(+), 31 deletions(-) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index 9cbcddb..08776d9 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -43,7 +43,6 @@ + #define EP2I(ep_address) (((ep_address & 0x80) >> 3) | (ep_address & 0x0f)) + #define I2EP(i) (((i & 0x10) << 3) | (i & 0x0f)) + +-typedef struct Cancelled Cancelled; + typedef struct USBRedirDevice USBRedirDevice; + + /* Struct to hold buffered packets (iso or int input packets) */ +@@ -69,6 +68,18 @@ struct endp_data { + int bufpq_target_size; + }; + ++struct PacketIdQueueEntry { ++ uint64_t id; ++ QTAILQ_ENTRY(PacketIdQueueEntry)next; ++}; ++ ++struct PacketIdQueue { ++ USBRedirDevice *dev; ++ const char *name; ++ QTAILQ_HEAD(, PacketIdQueueEntry) head; ++ int size; ++}; ++ + struct USBRedirDevice { + USBDevice dev; + /* Properties */ +@@ -86,7 +97,7 @@ struct USBRedirDevice { + int64_t next_attach_time; + struct usbredirparser *parser; + struct endp_data endpoint[MAX_ENDPOINTS]; +- QTAILQ_HEAD(, Cancelled) cancelled; ++ struct PacketIdQueue cancelled; + /* Data for device filtering */ + struct usb_redir_device_connect_header device_info; + struct usb_redir_interface_info_header interface_info; +@@ -94,11 +105,6 @@ struct USBRedirDevice { + int filter_rules_count; + }; + +-struct Cancelled { +- uint64_t id; +- QTAILQ_ENTRY(Cancelled)next; +-}; +- + static void usbredir_hello(void *priv, struct usb_redir_hello_header *h); + static void usbredir_device_connect(void *priv, + struct usb_redir_device_connect_header *device_connect); +@@ -249,37 +255,75 @@ static int usbredir_write(void *priv, uint8_t *data, int count) + * Cancelled and buffered packets helpers + */ + +-static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p) ++static void packet_id_queue_init(struct PacketIdQueue *q, ++ USBRedirDevice *dev, const char *name) + { +- USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); +- Cancelled *c; ++ q->dev = dev; ++ q->name = name; ++ QTAILQ_INIT(&q->head); ++ q->size = 0; ++} ++ ++static void packet_id_queue_add(struct PacketIdQueue *q, uint64_t id) ++{ ++ USBRedirDevice *dev = q->dev; ++ struct PacketIdQueueEntry *e; ++ ++ DPRINTF("adding packet id %"PRIu64" to %s queue\n", id, q->name); ++ ++ e = g_malloc0(sizeof(struct PacketIdQueueEntry)); ++ e->id = id; ++ QTAILQ_INSERT_TAIL(&q->head, e, next); ++ q->size++; ++} ++ ++static int packet_id_queue_remove(struct PacketIdQueue *q, uint64_t id) ++{ ++ USBRedirDevice *dev = q->dev; ++ struct PacketIdQueueEntry *e; ++ ++ QTAILQ_FOREACH(e, &q->head, next) { ++ if (e->id == id) { ++ DPRINTF("removing packet id %"PRIu64" from %s queue\n", ++ id, q->name); ++ QTAILQ_REMOVE(&q->head, e, next); ++ q->size--; ++ g_free(e); ++ return 1; ++ } ++ } ++ return 0; ++} ++ ++static void packet_id_queue_empty(struct PacketIdQueue *q) ++{ ++ USBRedirDevice *dev = q->dev; ++ struct PacketIdQueueEntry *e, *next_e; + +- DPRINTF("cancel packet id %"PRIu64"\n", p->id); ++ DPRINTF("removing %d packet-ids from %s queue\n", q->size, q->name); + +- c = g_malloc0(sizeof(Cancelled)); +- c->id = p->id; +- QTAILQ_INSERT_TAIL(&dev->cancelled, c, next); ++ QTAILQ_FOREACH_SAFE(e, &q->head, next, next_e) { ++ QTAILQ_REMOVE(&q->head, e, next); ++ g_free(e); ++ } ++ q->size = 0; ++} + ++static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p) ++{ ++ USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); ++ ++ packet_id_queue_add(&dev->cancelled, p->id); + usbredirparser_send_cancel_data_packet(dev->parser, p->id); + usbredirparser_do_write(dev->parser); + } + + static int usbredir_is_cancelled(USBRedirDevice *dev, uint64_t id) + { +- Cancelled *c; +- + if (!dev->dev.attached) { + return 1; /* Treat everything as cancelled after a disconnect */ + } +- +- QTAILQ_FOREACH(c, &dev->cancelled, next) { +- if (c->id == id) { +- QTAILQ_REMOVE(&dev->cancelled, c, next); +- g_free(c); +- return 1; +- } +- } +- return 0; ++ return packet_id_queue_remove(&dev->cancelled, id); + } + + static USBPacket *usbredir_find_packet_by_id(USBRedirDevice *dev, +@@ -942,7 +986,7 @@ static int usbredir_initfn(USBDevice *udev) + dev->chardev_close_bh = qemu_bh_new(usbredir_chardev_close_bh, dev); + dev->attach_timer = qemu_new_timer_ms(vm_clock, usbredir_do_attach, dev); + +- QTAILQ_INIT(&dev->cancelled); ++ packet_id_queue_init(&dev->cancelled, dev, "cancelled"); + for (i = 0; i < MAX_ENDPOINTS; i++) { + QTAILQ_INIT(&dev->endpoint[i].bufpq); + } +@@ -960,13 +1004,9 @@ static int usbredir_initfn(USBDevice *udev) + + static void usbredir_cleanup_device_queues(USBRedirDevice *dev) + { +- Cancelled *c, *next_c; + int i; + +- QTAILQ_FOREACH_SAFE(c, &dev->cancelled, next, next_c) { +- QTAILQ_REMOVE(&dev->cancelled, c, next); +- g_free(c); +- } ++ packet_id_queue_empty(&dev->cancelled); + for (i = 0; i < MAX_ENDPOINTS; i++) { + usbredir_free_bufpq(dev, I2EP(i)); + } +-- +1.7.12 + diff --git a/0362-usb-redir-Add-an-already_in_flight-packet-id-queue.patch b/0362-usb-redir-Add-an-already_in_flight-packet-id-queue.patch new file mode 100644 index 0000000..10c9aa3 --- /dev/null +++ b/0362-usb-redir-Add-an-already_in_flight-packet-id-queue.patch @@ -0,0 +1,119 @@ +From b422d151d0861ed346bed7cddb410a6b4c67711b Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Tue, 4 Sep 2012 17:03:54 +0200 +Subject: [PATCH 362/365] usb-redir: Add an already_in_flight packet-id queue + +After a live migration, the usb-hcd will re-queue all packets by +walking over the schedule in the guest memory again, but requests which +were encountered on the migration source before will already be in flight, +so these should *not* be re-send to the usbredir-host. + +This patch adds an already in flight packet ud queue, which will be filled by +the source before migration and then moved over to the migration dest, any +async handled packets are then checked against this queue to avoid sending +the same packet to the usbredir-host twice. + +Signed-off-by: Hans de Goede +--- + hw/usb/redirect.c | 43 +++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 43 insertions(+) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index 08776d9..1c8edd3 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -98,6 +98,7 @@ struct USBRedirDevice { + struct usbredirparser *parser; + struct endp_data endpoint[MAX_ENDPOINTS]; + struct PacketIdQueue cancelled; ++ struct PacketIdQueue already_in_flight; + /* Data for device filtering */ + struct usb_redir_device_connect_header device_info; + struct usb_redir_interface_info_header interface_info; +@@ -326,6 +327,34 @@ static int usbredir_is_cancelled(USBRedirDevice *dev, uint64_t id) + return packet_id_queue_remove(&dev->cancelled, id); + } + ++static void usbredir_fill_already_in_flight_from_ep(USBRedirDevice *dev, ++ struct USBEndpoint *ep) ++{ ++ static USBPacket *p; ++ ++ QTAILQ_FOREACH(p, &ep->queue, queue) { ++ packet_id_queue_add(&dev->already_in_flight, p->id); ++ } ++} ++ ++static void usbredir_fill_already_in_flight(USBRedirDevice *dev) ++{ ++ int ep; ++ struct USBDevice *udev = &dev->dev; ++ ++ usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_ctl); ++ ++ for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) { ++ usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_in[ep]); ++ usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_out[ep]); ++ } ++} ++ ++static int usbredir_already_in_flight(USBRedirDevice *dev, uint64_t id) ++{ ++ return packet_id_queue_remove(&dev->already_in_flight, id); ++} ++ + static USBPacket *usbredir_find_packet_by_id(USBRedirDevice *dev, + uint8_t ep, uint64_t id) + { +@@ -541,6 +570,10 @@ static int usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p, + + DPRINTF("bulk-out ep %02X len %zd id %"PRIu64"\n", ep, p->iov.size, p->id); + ++ if (usbredir_already_in_flight(dev, p->id)) { ++ return USB_RET_ASYNC; ++ } ++ + bulk_packet.endpoint = ep; + bulk_packet.length = p->iov.size; + bulk_packet.stream_id = 0; +@@ -621,6 +654,10 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev, + DPRINTF("interrupt-out ep %02X len %zd id %"PRIu64"\n", ep, + p->iov.size, p->id); + ++ if (usbredir_already_in_flight(dev, p->id)) { ++ return USB_RET_ASYNC; ++ } ++ + interrupt_packet.endpoint = ep; + interrupt_packet.length = p->iov.size; + +@@ -763,6 +800,10 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p, + USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); + struct usb_redir_control_packet_header control_packet; + ++ if (usbredir_already_in_flight(dev, p->id)) { ++ return USB_RET_ASYNC; ++ } ++ + /* Special cases for certain standard device requests */ + switch (request) { + case DeviceOutRequest | USB_REQ_SET_ADDRESS: +@@ -987,6 +1028,7 @@ static int usbredir_initfn(USBDevice *udev) + dev->attach_timer = qemu_new_timer_ms(vm_clock, usbredir_do_attach, dev); + + packet_id_queue_init(&dev->cancelled, dev, "cancelled"); ++ packet_id_queue_init(&dev->already_in_flight, dev, "already-in-flight"); + for (i = 0; i < MAX_ENDPOINTS; i++) { + QTAILQ_INIT(&dev->endpoint[i].bufpq); + } +@@ -1007,6 +1049,7 @@ static void usbredir_cleanup_device_queues(USBRedirDevice *dev) + int i; + + packet_id_queue_empty(&dev->cancelled); ++ packet_id_queue_empty(&dev->already_in_flight); + for (i = 0; i < MAX_ENDPOINTS; i++) { + usbredir_free_bufpq(dev, I2EP(i)); + } +-- +1.7.12 + diff --git a/0362-usb-redir-Change-cancelled-packet-code-into-a-generi.patch b/0362-usb-redir-Change-cancelled-packet-code-into-a-generi.patch deleted file mode 100644 index ee0c0f9..0000000 --- a/0362-usb-redir-Change-cancelled-packet-code-into-a-generi.patch +++ /dev/null @@ -1,184 +0,0 @@ -From 4d7d1b57fa5d3a950818e5dee459aefa4dc6ae27 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Tue, 4 Sep 2012 14:18:34 +0200 -Subject: [PATCH 362/366] usb-redir: Change cancelled packet code into a - generic packet-id queue - -Signed-off-by: Hans de Goede ---- - hw/usb/redirect.c | 102 +++++++++++++++++++++++++++++++++++++----------------- - 1 file changed, 71 insertions(+), 31 deletions(-) - -diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c -index 9cbcddb..08776d9 100644 ---- a/hw/usb/redirect.c -+++ b/hw/usb/redirect.c -@@ -43,7 +43,6 @@ - #define EP2I(ep_address) (((ep_address & 0x80) >> 3) | (ep_address & 0x0f)) - #define I2EP(i) (((i & 0x10) << 3) | (i & 0x0f)) - --typedef struct Cancelled Cancelled; - typedef struct USBRedirDevice USBRedirDevice; - - /* Struct to hold buffered packets (iso or int input packets) */ -@@ -69,6 +68,18 @@ struct endp_data { - int bufpq_target_size; - }; - -+struct PacketIdQueueEntry { -+ uint64_t id; -+ QTAILQ_ENTRY(PacketIdQueueEntry)next; -+}; -+ -+struct PacketIdQueue { -+ USBRedirDevice *dev; -+ const char *name; -+ QTAILQ_HEAD(, PacketIdQueueEntry) head; -+ int size; -+}; -+ - struct USBRedirDevice { - USBDevice dev; - /* Properties */ -@@ -86,7 +97,7 @@ struct USBRedirDevice { - int64_t next_attach_time; - struct usbredirparser *parser; - struct endp_data endpoint[MAX_ENDPOINTS]; -- QTAILQ_HEAD(, Cancelled) cancelled; -+ struct PacketIdQueue cancelled; - /* Data for device filtering */ - struct usb_redir_device_connect_header device_info; - struct usb_redir_interface_info_header interface_info; -@@ -94,11 +105,6 @@ struct USBRedirDevice { - int filter_rules_count; - }; - --struct Cancelled { -- uint64_t id; -- QTAILQ_ENTRY(Cancelled)next; --}; -- - static void usbredir_hello(void *priv, struct usb_redir_hello_header *h); - static void usbredir_device_connect(void *priv, - struct usb_redir_device_connect_header *device_connect); -@@ -249,37 +255,75 @@ static int usbredir_write(void *priv, uint8_t *data, int count) - * Cancelled and buffered packets helpers - */ - --static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p) -+static void packet_id_queue_init(struct PacketIdQueue *q, -+ USBRedirDevice *dev, const char *name) - { -- USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); -- Cancelled *c; -+ q->dev = dev; -+ q->name = name; -+ QTAILQ_INIT(&q->head); -+ q->size = 0; -+} -+ -+static void packet_id_queue_add(struct PacketIdQueue *q, uint64_t id) -+{ -+ USBRedirDevice *dev = q->dev; -+ struct PacketIdQueueEntry *e; -+ -+ DPRINTF("adding packet id %"PRIu64" to %s queue\n", id, q->name); -+ -+ e = g_malloc0(sizeof(struct PacketIdQueueEntry)); -+ e->id = id; -+ QTAILQ_INSERT_TAIL(&q->head, e, next); -+ q->size++; -+} -+ -+static int packet_id_queue_remove(struct PacketIdQueue *q, uint64_t id) -+{ -+ USBRedirDevice *dev = q->dev; -+ struct PacketIdQueueEntry *e; -+ -+ QTAILQ_FOREACH(e, &q->head, next) { -+ if (e->id == id) { -+ DPRINTF("removing packet id %"PRIu64" from %s queue\n", -+ id, q->name); -+ QTAILQ_REMOVE(&q->head, e, next); -+ q->size--; -+ g_free(e); -+ return 1; -+ } -+ } -+ return 0; -+} -+ -+static void packet_id_queue_empty(struct PacketIdQueue *q) -+{ -+ USBRedirDevice *dev = q->dev; -+ struct PacketIdQueueEntry *e, *next_e; - -- DPRINTF("cancel packet id %"PRIu64"\n", p->id); -+ DPRINTF("removing %d packet-ids from %s queue\n", q->size, q->name); - -- c = g_malloc0(sizeof(Cancelled)); -- c->id = p->id; -- QTAILQ_INSERT_TAIL(&dev->cancelled, c, next); -+ QTAILQ_FOREACH_SAFE(e, &q->head, next, next_e) { -+ QTAILQ_REMOVE(&q->head, e, next); -+ g_free(e); -+ } -+ q->size = 0; -+} - -+static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p) -+{ -+ USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); -+ -+ packet_id_queue_add(&dev->cancelled, p->id); - usbredirparser_send_cancel_data_packet(dev->parser, p->id); - usbredirparser_do_write(dev->parser); - } - - static int usbredir_is_cancelled(USBRedirDevice *dev, uint64_t id) - { -- Cancelled *c; -- - if (!dev->dev.attached) { - return 1; /* Treat everything as cancelled after a disconnect */ - } -- -- QTAILQ_FOREACH(c, &dev->cancelled, next) { -- if (c->id == id) { -- QTAILQ_REMOVE(&dev->cancelled, c, next); -- g_free(c); -- return 1; -- } -- } -- return 0; -+ return packet_id_queue_remove(&dev->cancelled, id); - } - - static USBPacket *usbredir_find_packet_by_id(USBRedirDevice *dev, -@@ -942,7 +986,7 @@ static int usbredir_initfn(USBDevice *udev) - dev->chardev_close_bh = qemu_bh_new(usbredir_chardev_close_bh, dev); - dev->attach_timer = qemu_new_timer_ms(vm_clock, usbredir_do_attach, dev); - -- QTAILQ_INIT(&dev->cancelled); -+ packet_id_queue_init(&dev->cancelled, dev, "cancelled"); - for (i = 0; i < MAX_ENDPOINTS; i++) { - QTAILQ_INIT(&dev->endpoint[i].bufpq); - } -@@ -960,13 +1004,9 @@ static int usbredir_initfn(USBDevice *udev) - - static void usbredir_cleanup_device_queues(USBRedirDevice *dev) - { -- Cancelled *c, *next_c; - int i; - -- QTAILQ_FOREACH_SAFE(c, &dev->cancelled, next, next_c) { -- QTAILQ_REMOVE(&dev->cancelled, c, next); -- g_free(c); -- } -+ packet_id_queue_empty(&dev->cancelled); - for (i = 0; i < MAX_ENDPOINTS; i++) { - usbredir_free_bufpq(dev, I2EP(i)); - } --- -1.7.12 - diff --git a/0363-usb-redir-Add-an-already_in_flight-packet-id-queue.patch b/0363-usb-redir-Add-an-already_in_flight-packet-id-queue.patch deleted file mode 100644 index 9fea679..0000000 --- a/0363-usb-redir-Add-an-already_in_flight-packet-id-queue.patch +++ /dev/null @@ -1,119 +0,0 @@ -From 4e0fcd7ef28b0ee06fd6f9d736dbdccefcf0b2bf Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Tue, 4 Sep 2012 17:03:54 +0200 -Subject: [PATCH 363/366] usb-redir: Add an already_in_flight packet-id queue - -After a live migration, the usb-hcd will re-queue all packets by -walking over the schedule in the guest memory again, but requests which -were encountered on the migration source before will already be in flight, -so these should *not* be re-send to the usbredir-host. - -This patch adds an already in flight packet ud queue, which will be filled by -the source before migration and then moved over to the migration dest, any -async handled packets are then checked against this queue to avoid sending -the same packet to the usbredir-host twice. - -Signed-off-by: Hans de Goede ---- - hw/usb/redirect.c | 43 +++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 43 insertions(+) - -diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c -index 08776d9..1c8edd3 100644 ---- a/hw/usb/redirect.c -+++ b/hw/usb/redirect.c -@@ -98,6 +98,7 @@ struct USBRedirDevice { - struct usbredirparser *parser; - struct endp_data endpoint[MAX_ENDPOINTS]; - struct PacketIdQueue cancelled; -+ struct PacketIdQueue already_in_flight; - /* Data for device filtering */ - struct usb_redir_device_connect_header device_info; - struct usb_redir_interface_info_header interface_info; -@@ -326,6 +327,34 @@ static int usbredir_is_cancelled(USBRedirDevice *dev, uint64_t id) - return packet_id_queue_remove(&dev->cancelled, id); - } - -+static void usbredir_fill_already_in_flight_from_ep(USBRedirDevice *dev, -+ struct USBEndpoint *ep) -+{ -+ static USBPacket *p; -+ -+ QTAILQ_FOREACH(p, &ep->queue, queue) { -+ packet_id_queue_add(&dev->already_in_flight, p->id); -+ } -+} -+ -+static void usbredir_fill_already_in_flight(USBRedirDevice *dev) -+{ -+ int ep; -+ struct USBDevice *udev = &dev->dev; -+ -+ usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_ctl); -+ -+ for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) { -+ usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_in[ep]); -+ usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_out[ep]); -+ } -+} -+ -+static int usbredir_already_in_flight(USBRedirDevice *dev, uint64_t id) -+{ -+ return packet_id_queue_remove(&dev->already_in_flight, id); -+} -+ - static USBPacket *usbredir_find_packet_by_id(USBRedirDevice *dev, - uint8_t ep, uint64_t id) - { -@@ -541,6 +570,10 @@ static int usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p, - - DPRINTF("bulk-out ep %02X len %zd id %"PRIu64"\n", ep, p->iov.size, p->id); - -+ if (usbredir_already_in_flight(dev, p->id)) { -+ return USB_RET_ASYNC; -+ } -+ - bulk_packet.endpoint = ep; - bulk_packet.length = p->iov.size; - bulk_packet.stream_id = 0; -@@ -621,6 +654,10 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev, - DPRINTF("interrupt-out ep %02X len %zd id %"PRIu64"\n", ep, - p->iov.size, p->id); - -+ if (usbredir_already_in_flight(dev, p->id)) { -+ return USB_RET_ASYNC; -+ } -+ - interrupt_packet.endpoint = ep; - interrupt_packet.length = p->iov.size; - -@@ -763,6 +800,10 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p, - USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); - struct usb_redir_control_packet_header control_packet; - -+ if (usbredir_already_in_flight(dev, p->id)) { -+ return USB_RET_ASYNC; -+ } -+ - /* Special cases for certain standard device requests */ - switch (request) { - case DeviceOutRequest | USB_REQ_SET_ADDRESS: -@@ -987,6 +1028,7 @@ static int usbredir_initfn(USBDevice *udev) - dev->attach_timer = qemu_new_timer_ms(vm_clock, usbredir_do_attach, dev); - - packet_id_queue_init(&dev->cancelled, dev, "cancelled"); -+ packet_id_queue_init(&dev->already_in_flight, dev, "already-in-flight"); - for (i = 0; i < MAX_ENDPOINTS; i++) { - QTAILQ_INIT(&dev->endpoint[i].bufpq); - } -@@ -1007,6 +1049,7 @@ static void usbredir_cleanup_device_queues(USBRedirDevice *dev) - int i; - - packet_id_queue_empty(&dev->cancelled); -+ packet_id_queue_empty(&dev->already_in_flight); - for (i = 0; i < MAX_ENDPOINTS; i++) { - usbredir_free_bufpq(dev, I2EP(i)); - } --- -1.7.12 - diff --git a/0363-usb-redir-Store-max_packet_size-in-endp_data.patch b/0363-usb-redir-Store-max_packet_size-in-endp_data.patch new file mode 100644 index 0000000..16f05d3 --- /dev/null +++ b/0363-usb-redir-Store-max_packet_size-in-endp_data.patch @@ -0,0 +1,38 @@ +From c9917c910cf59e2407bbf51770724c5ec17d9cd1 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Thu, 6 Sep 2012 20:52:36 +0200 +Subject: [PATCH 363/365] usb-redir: Store max_packet_size in endp_data + +So that we've a place to migrate it to / from to allow restoring it after +migration. + +Signed-off-by: Hans de Goede +--- + hw/usb/redirect.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index 1c8edd3..d8568ae 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -57,6 +57,7 @@ struct endp_data { + uint8_t type; + uint8_t interval; + uint8_t interface; /* bInterfaceNumber this ep belongs to */ ++ uint16_t max_packet_size; /* In bytes, not wMaxPacketSize format !! */ + uint8_t iso_started; + uint8_t iso_error; /* For reporting iso errors to the HC */ + uint8_t interrupt_started; +@@ -1305,7 +1306,8 @@ static void usbredir_ep_info(void *priv, + usb_ep->ifnum = dev->endpoint[i].interface; + if (usbredirparser_peer_has_cap(dev->parser, + usb_redir_cap_ep_info_max_packet_size)) { +- usb_ep->max_packet_size = ep_info->max_packet_size[i]; ++ dev->endpoint[i].max_packet_size = ++ usb_ep->max_packet_size = ep_info->max_packet_size[i]; + } + if (ep_info->type[i] == usb_redir_type_bulk) { + usb_ep->pipeline = true; +-- +1.7.12 + diff --git a/0364-usb-redir-Add-support-for-migration.patch b/0364-usb-redir-Add-support-for-migration.patch new file mode 100644 index 0000000..bcbbaab --- /dev/null +++ b/0364-usb-redir-Add-support-for-migration.patch @@ -0,0 +1,429 @@ +From 0d733a1280bdaba402c6efbfae116408d7c81bb0 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Wed, 5 Sep 2012 09:21:44 +0200 +Subject: [PATCH 364/365] usb-redir: Add support for migration + +Signed-off-by: Hans de Goede +--- + hw/usb/redirect.c | 349 +++++++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 346 insertions(+), 3 deletions(-) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index d8568ae..812096e 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -65,8 +65,8 @@ struct endp_data { + uint8_t bufpq_prefilled; + uint8_t bufpq_dropping_packets; + QTAILQ_HEAD(, buf_packet) bufpq; +- int bufpq_size; +- int bufpq_target_size; ++ int32_t bufpq_size; ++ int32_t bufpq_target_size; + }; + + struct PacketIdQueueEntry { +@@ -241,6 +241,11 @@ static int usbredir_write(void *priv, uint8_t *data, int count) + return 0; + } + ++ /* Don't send new data to the chardev until our state is fully synced */ ++ if (!runstate_check(RUN_STATE_RUNNING)) { ++ return 0; ++ } ++ + r = qemu_chr_fe_write(dev->cs, data, count); + + if (r < 0) { +@@ -868,6 +873,7 @@ static void usbredir_chardev_open(USBRedirDevice *dev) + { + uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, }; + char version[32]; ++ int flags = 0; + + /* Make sure any pending closes are handled (no-op if none pending) */ + usbredir_chardev_close_bh(dev); +@@ -903,7 +909,12 @@ static void usbredir_chardev_open(USBRedirDevice *dev) + usbredirparser_caps_set_cap(caps, usb_redir_cap_filter); + usbredirparser_caps_set_cap(caps, usb_redir_cap_ep_info_max_packet_size); + usbredirparser_caps_set_cap(caps, usb_redir_cap_64bits_ids); +- usbredirparser_init(dev->parser, version, caps, USB_REDIR_CAPS_SIZE, 0); ++ ++ if (runstate_check(RUN_STATE_INMIGRATE)) { ++ flags |= usbredirparser_fl_no_hello; ++ } ++ usbredirparser_init(dev->parser, version, caps, USB_REDIR_CAPS_SIZE, ++ flags); + usbredirparser_do_write(dev->parser); + } + +@@ -949,6 +960,11 @@ static int usbredir_chardev_can_read(void *opaque) + return 0; + } + ++ /* Don't read new data from the chardev until our state is fully synced */ ++ if (!runstate_check(RUN_STATE_RUNNING)) { ++ return 0; ++ } ++ + /* usbredir_parser_do_read will consume *all* data we give it */ + return 1024 * 1024; + } +@@ -1004,6 +1020,15 @@ static const QemuChrHandlers usbredir_chr_handlers = { + * init + destroy + */ + ++static void usbredir_vm_state_change(void *priv, int running, RunState state) ++{ ++ USBRedirDevice *dev = priv; ++ ++ if (state == RUN_STATE_RUNNING && dev->parser != NULL) { ++ usbredirparser_do_write(dev->parser); /* Flush any pending writes */ ++ } ++} ++ + static int usbredir_initfn(USBDevice *udev) + { + USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); +@@ -1041,6 +1066,7 @@ static int usbredir_initfn(USBDevice *udev) + qemu_chr_fe_open(dev->cs); + qemu_chr_add_handlers(dev->cs, &usbredir_chr_handlers, dev); + ++ qemu_add_vm_change_state_handler(usbredir_vm_state_change, dev); + add_boot_device_path(dev->bootindex, &udev->qdev, NULL); + return 0; + } +@@ -1530,6 +1556,322 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id, + } + } + ++/* ++ * Migration code ++ */ ++ ++static void usbredir_pre_save(void *priv) ++{ ++ USBRedirDevice *dev = priv; ++ ++ usbredir_fill_already_in_flight(dev); ++} ++ ++static int usbredir_post_load(void *priv, int version_id) ++{ ++ USBRedirDevice *dev = priv; ++ struct USBEndpoint *usb_ep; ++ int i; ++ ++ switch (dev->device_info.speed) { ++ case usb_redir_speed_low: ++ dev->dev.speed = USB_SPEED_LOW; ++ break; ++ case usb_redir_speed_full: ++ dev->dev.speed = USB_SPEED_FULL; ++ break; ++ case usb_redir_speed_high: ++ dev->dev.speed = USB_SPEED_HIGH; ++ break; ++ case usb_redir_speed_super: ++ dev->dev.speed = USB_SPEED_SUPER; ++ break; ++ default: ++ dev->dev.speed = USB_SPEED_FULL; ++ } ++ dev->dev.speedmask = (1 << dev->dev.speed); ++ ++ for (i = 0; i < MAX_ENDPOINTS; i++) { ++ usb_ep = usb_ep_get(&dev->dev, ++ (i & 0x10) ? USB_TOKEN_IN : USB_TOKEN_OUT, ++ i & 0x0f); ++ usb_ep->type = dev->endpoint[i].type; ++ usb_ep->ifnum = dev->endpoint[i].interface; ++ usb_ep->max_packet_size = dev->endpoint[i].max_packet_size; ++ if (dev->endpoint[i].type == usb_redir_type_bulk) { ++ usb_ep->pipeline = true; ++ } ++ } ++ return 0; ++} ++ ++/* For usbredirparser migration */ ++static void usbredir_put_parser(QEMUFile *f, void *priv, size_t unused) ++{ ++ USBRedirDevice *dev = priv; ++ uint8_t *data; ++ int len; ++ ++ if (dev->parser == NULL) { ++ qemu_put_be32(f, 0); ++ return; ++ } ++ ++ usbredirparser_serialize(dev->parser, &data, &len); ++ qemu_oom_check(data); ++ ++ qemu_put_be32(f, len); ++ qemu_put_buffer(f, data, len); ++ ++ free(data); ++} ++ ++static int usbredir_get_parser(QEMUFile *f, void *priv, size_t unused) ++{ ++ USBRedirDevice *dev = priv; ++ uint8_t *data; ++ int len, ret; ++ ++ len = qemu_get_be32(f); ++ if (len == 0) { ++ return 0; ++ } ++ ++ /* ++ * Our chardev should be open already at this point, otherwise ++ * the usbredir channel will be broken (ie spice without seamless) ++ */ ++ if (dev->parser == NULL) { ++ ERROR("get_parser called with closed chardev, failing migration\n"); ++ return -1; ++ } ++ ++ data = g_malloc(len); ++ qemu_get_buffer(f, data, len); ++ ++ ret = usbredirparser_unserialize(dev->parser, data, len); ++ ++ g_free(data); ++ ++ return ret; ++} ++ ++static const VMStateInfo usbredir_parser_vmstate_info = { ++ .name = "usb-redir-parser", ++ .put = usbredir_put_parser, ++ .get = usbredir_get_parser, ++}; ++ ++ ++/* For buffered packets (iso/irq) queue migration */ ++static void usbredir_put_bufpq(QEMUFile *f, void *priv, size_t unused) ++{ ++ struct endp_data *endp = priv; ++ struct buf_packet *bufp; ++ int remain = endp->bufpq_size; ++ ++ qemu_put_be32(f, endp->bufpq_size); ++ QTAILQ_FOREACH(bufp, &endp->bufpq, next) { ++ qemu_put_be32(f, bufp->len); ++ qemu_put_be32(f, bufp->status); ++ qemu_put_buffer(f, bufp->data, bufp->len); ++ remain--; ++ } ++ assert(remain == 0); ++} ++ ++static int usbredir_get_bufpq(QEMUFile *f, void *priv, size_t unused) ++{ ++ struct endp_data *endp = priv; ++ struct buf_packet *bufp; ++ int i; ++ ++ endp->bufpq_size = qemu_get_be32(f); ++ for (i = 0; i < endp->bufpq_size; i++) { ++ bufp = g_malloc(sizeof(struct buf_packet)); ++ bufp->len = qemu_get_be32(f); ++ bufp->status = qemu_get_be32(f); ++ bufp->data = qemu_oom_check(malloc(bufp->len)); /* regular malloc! */ ++ qemu_get_buffer(f, bufp->data, bufp->len); ++ QTAILQ_INSERT_TAIL(&endp->bufpq, bufp, next); ++ } ++ return 0; ++} ++ ++static const VMStateInfo usbredir_ep_bufpq_vmstate_info = { ++ .name = "usb-redir-bufpq", ++ .put = usbredir_put_bufpq, ++ .get = usbredir_get_bufpq, ++}; ++ ++ ++/* For endp_data migration */ ++static const VMStateDescription usbredir_ep_vmstate = { ++ .name = "usb-redir-ep", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .fields = (VMStateField []) { ++ VMSTATE_UINT8(type, struct endp_data), ++ VMSTATE_UINT8(interval, struct endp_data), ++ VMSTATE_UINT8(interface, struct endp_data), ++ VMSTATE_UINT16(max_packet_size, struct endp_data), ++ VMSTATE_UINT8(iso_started, struct endp_data), ++ VMSTATE_UINT8(iso_error, struct endp_data), ++ VMSTATE_UINT8(interrupt_started, struct endp_data), ++ VMSTATE_UINT8(interrupt_error, struct endp_data), ++ VMSTATE_UINT8(bufpq_prefilled, struct endp_data), ++ VMSTATE_UINT8(bufpq_dropping_packets, struct endp_data), ++ { ++ .name = "bufpq", ++ .version_id = 0, ++ .field_exists = NULL, ++ .size = 0, ++ .info = &usbredir_ep_bufpq_vmstate_info, ++ .flags = VMS_SINGLE, ++ .offset = 0, ++ }, ++ VMSTATE_INT32(bufpq_target_size, struct endp_data), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ ++ ++/* For PacketIdQueue migration */ ++static void usbredir_put_packet_id_q(QEMUFile *f, void *priv, size_t unused) ++{ ++ struct PacketIdQueue *q = priv; ++ USBRedirDevice *dev = q->dev; ++ struct PacketIdQueueEntry *e; ++ int remain = q->size; ++ ++ DPRINTF("put_packet_id_q %s size %d\n", q->name, q->size); ++ qemu_put_be32(f, q->size); ++ QTAILQ_FOREACH(e, &q->head, next) { ++ qemu_put_be64(f, e->id); ++ remain--; ++ } ++ assert(remain == 0); ++} ++ ++static int usbredir_get_packet_id_q(QEMUFile *f, void *priv, size_t unused) ++{ ++ struct PacketIdQueue *q = priv; ++ USBRedirDevice *dev = q->dev; ++ int i, size; ++ uint64_t id; ++ ++ size = qemu_get_be32(f); ++ DPRINTF("get_packet_id_q %s size %d\n", q->name, size); ++ for (i = 0; i < size; i++) { ++ id = qemu_get_be64(f); ++ packet_id_queue_add(q, id); ++ } ++ assert(q->size == size); ++ return 0; ++} ++ ++static const VMStateInfo usbredir_ep_packet_id_q_vmstate_info = { ++ .name = "usb-redir-packet-id-q", ++ .put = usbredir_put_packet_id_q, ++ .get = usbredir_get_packet_id_q, ++}; ++ ++static const VMStateDescription usbredir_ep_packet_id_queue_vmstate = { ++ .name = "usb-redir-packet-id-queue", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .fields = (VMStateField []) { ++ { ++ .name = "queue", ++ .version_id = 0, ++ .field_exists = NULL, ++ .size = 0, ++ .info = &usbredir_ep_packet_id_q_vmstate_info, ++ .flags = VMS_SINGLE, ++ .offset = 0, ++ }, ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ ++ ++/* For usb_redir_device_connect_header migration */ ++static const VMStateDescription usbredir_device_info_vmstate = { ++ .name = "usb-redir-device-info", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .fields = (VMStateField []) { ++ VMSTATE_UINT8(speed, struct usb_redir_device_connect_header), ++ VMSTATE_UINT8(device_class, struct usb_redir_device_connect_header), ++ VMSTATE_UINT8(device_subclass, struct usb_redir_device_connect_header), ++ VMSTATE_UINT8(device_protocol, struct usb_redir_device_connect_header), ++ VMSTATE_UINT16(vendor_id, struct usb_redir_device_connect_header), ++ VMSTATE_UINT16(product_id, struct usb_redir_device_connect_header), ++ VMSTATE_UINT16(device_version_bcd, ++ struct usb_redir_device_connect_header), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ ++ ++/* For usb_redir_interface_info_header migration */ ++static const VMStateDescription usbredir_interface_info_vmstate = { ++ .name = "usb-redir-interface-info", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .fields = (VMStateField []) { ++ VMSTATE_UINT32(interface_count, ++ struct usb_redir_interface_info_header), ++ VMSTATE_UINT8_ARRAY(interface, ++ struct usb_redir_interface_info_header, 32), ++ VMSTATE_UINT8_ARRAY(interface_class, ++ struct usb_redir_interface_info_header, 32), ++ VMSTATE_UINT8_ARRAY(interface_subclass, ++ struct usb_redir_interface_info_header, 32), ++ VMSTATE_UINT8_ARRAY(interface_protocol, ++ struct usb_redir_interface_info_header, 32), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ ++ ++/* And finally the USBRedirDevice vmstate itself */ ++static const VMStateDescription usbredir_vmstate = { ++ .name = "usb-redir", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .pre_save = usbredir_pre_save, ++ .post_load = usbredir_post_load, ++ .fields = (VMStateField []) { ++ VMSTATE_USB_DEVICE(dev, USBRedirDevice), ++ VMSTATE_TIMER(attach_timer, USBRedirDevice), ++ { ++ .name = "parser", ++ .version_id = 0, ++ .field_exists = NULL, ++ .size = 0, ++ .info = &usbredir_parser_vmstate_info, ++ .flags = VMS_SINGLE, ++ .offset = 0, ++ }, ++ VMSTATE_STRUCT_ARRAY(endpoint, USBRedirDevice, MAX_ENDPOINTS, 1, ++ usbredir_ep_vmstate, struct endp_data), ++ VMSTATE_STRUCT(cancelled, USBRedirDevice, 1, ++ usbredir_ep_packet_id_queue_vmstate, ++ struct PacketIdQueue), ++ VMSTATE_STRUCT(already_in_flight, USBRedirDevice, 1, ++ usbredir_ep_packet_id_queue_vmstate, ++ struct PacketIdQueue), ++ VMSTATE_STRUCT(device_info, USBRedirDevice, 1, ++ usbredir_device_info_vmstate, ++ struct usb_redir_device_connect_header), ++ VMSTATE_STRUCT(interface_info, USBRedirDevice, 1, ++ usbredir_interface_info_vmstate, ++ struct usb_redir_interface_info_header), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ + static Property usbredir_properties[] = { + DEFINE_PROP_CHR("chardev", USBRedirDevice, cs), + DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, 0), +@@ -1550,6 +1892,7 @@ static void usbredir_class_initfn(ObjectClass *klass, void *data) + uc->handle_reset = usbredir_handle_reset; + uc->handle_data = usbredir_handle_data; + uc->handle_control = usbredir_handle_control; ++ dc->vmsd = &usbredir_vmstate; + dc->props = usbredir_properties; + } + +-- +1.7.12 + diff --git a/0364-usb-redir-Store-max_packet_size-in-endp_data.patch b/0364-usb-redir-Store-max_packet_size-in-endp_data.patch deleted file mode 100644 index 6976b2c..0000000 --- a/0364-usb-redir-Store-max_packet_size-in-endp_data.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 372d6c55bbe5fb092ff9e96c72ff53bfd10fdede Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Thu, 6 Sep 2012 20:52:36 +0200 -Subject: [PATCH 364/366] usb-redir: Store max_packet_size in endp_data - -So that we've a place to migrate it to / from to allow restoring it after -migration. - -Signed-off-by: Hans de Goede ---- - hw/usb/redirect.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c -index 1c8edd3..d8568ae 100644 ---- a/hw/usb/redirect.c -+++ b/hw/usb/redirect.c -@@ -57,6 +57,7 @@ struct endp_data { - uint8_t type; - uint8_t interval; - uint8_t interface; /* bInterfaceNumber this ep belongs to */ -+ uint16_t max_packet_size; /* In bytes, not wMaxPacketSize format !! */ - uint8_t iso_started; - uint8_t iso_error; /* For reporting iso errors to the HC */ - uint8_t interrupt_started; -@@ -1305,7 +1306,8 @@ static void usbredir_ep_info(void *priv, - usb_ep->ifnum = dev->endpoint[i].interface; - if (usbredirparser_peer_has_cap(dev->parser, - usb_redir_cap_ep_info_max_packet_size)) { -- usb_ep->max_packet_size = ep_info->max_packet_size[i]; -+ dev->endpoint[i].max_packet_size = -+ usb_ep->max_packet_size = ep_info->max_packet_size[i]; - } - if (ep_info->type[i] == usb_redir_type_bulk) { - usb_ep->pipeline = true; --- -1.7.12 - diff --git a/0365-usb-redir-Add-chardev-open-close-debug-logging.patch b/0365-usb-redir-Add-chardev-open-close-debug-logging.patch new file mode 100644 index 0000000..4e2f75d --- /dev/null +++ b/0365-usb-redir-Add-chardev-open-close-debug-logging.patch @@ -0,0 +1,54 @@ +From 3efd9345ea643cf6f15776425213a92a442dd217 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Wed, 5 Sep 2012 15:56:57 +0200 +Subject: [PATCH 365/365] usb-redir: Add chardev open / close debug logging + +Signed-off-by: Hans de Goede +--- + hw/usb/redirect.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index 812096e..b03c412 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -864,6 +864,7 @@ static void usbredir_chardev_close_bh(void *opaque) + usbredir_device_disconnect(dev); + + if (dev->parser) { ++ DPRINTF("destroying usbredirparser\n"); + usbredirparser_destroy(dev->parser); + dev->parser = NULL; + } +@@ -879,6 +880,8 @@ static void usbredir_chardev_open(USBRedirDevice *dev) + usbredir_chardev_close_bh(dev); + qemu_bh_cancel(dev->chardev_close_bh); + ++ DPRINTF("creating usbredirparser\n"); ++ + strcpy(version, "qemu usb-redir guest "); + pstrcat(version, sizeof(version), qemu_get_version()); + +@@ -990,9 +993,11 @@ static void usbredir_chardev_event(void *opaque, int event) + + switch (event) { + case CHR_EVENT_OPENED: ++ DPRINTF("chardev open\n"); + usbredir_chardev_open(dev); + break; + case CHR_EVENT_CLOSED: ++ DPRINTF("chardev close\n"); + qemu_bh_schedule(dev->chardev_close_bh); + break; + } +@@ -1255,6 +1260,7 @@ static void usbredir_device_disconnect(void *priv) + qemu_del_timer(dev->attach_timer); + + if (dev->dev.attached) { ++ DPRINTF("detaching device\n"); + usb_device_detach(&dev->dev); + /* + * Delay next usb device attach to give the guest a chance to see +-- +1.7.12 + diff --git a/0365-usb-redir-Add-support-for-migration.patch b/0365-usb-redir-Add-support-for-migration.patch deleted file mode 100644 index 97b8ab2..0000000 --- a/0365-usb-redir-Add-support-for-migration.patch +++ /dev/null @@ -1,411 +0,0 @@ -From e6a683c844845c53bcf14f9fb3ea175331eaca0c Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Wed, 5 Sep 2012 09:21:44 +0200 -Subject: [PATCH 365/366] usb-redir: Add support for migration - -Signed-off-by: Hans de Goede ---- - hw/usb/redirect.c | 331 +++++++++++++++++++++++++++++++++++++++++++++++++++++- - 1 file changed, 328 insertions(+), 3 deletions(-) - -diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c -index d8568ae..8dbb722 100644 ---- a/hw/usb/redirect.c -+++ b/hw/usb/redirect.c -@@ -65,8 +65,8 @@ struct endp_data { - uint8_t bufpq_prefilled; - uint8_t bufpq_dropping_packets; - QTAILQ_HEAD(, buf_packet) bufpq; -- int bufpq_size; -- int bufpq_target_size; -+ int32_t bufpq_size; -+ int32_t bufpq_target_size; - }; - - struct PacketIdQueueEntry { -@@ -241,6 +241,11 @@ static int usbredir_write(void *priv, uint8_t *data, int count) - return 0; - } - -+ /* Don't send new data to the chardev until our state is fully synced */ -+ if (!runstate_check(RUN_STATE_RUNNING)) { -+ return 0; -+ } -+ - r = qemu_chr_fe_write(dev->cs, data, count); - - if (r < 0) { -@@ -868,6 +873,7 @@ static void usbredir_chardev_open(USBRedirDevice *dev) - { - uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, }; - char version[32]; -+ int flags = 0; - - /* Make sure any pending closes are handled (no-op if none pending) */ - usbredir_chardev_close_bh(dev); -@@ -903,7 +909,12 @@ static void usbredir_chardev_open(USBRedirDevice *dev) - usbredirparser_caps_set_cap(caps, usb_redir_cap_filter); - usbredirparser_caps_set_cap(caps, usb_redir_cap_ep_info_max_packet_size); - usbredirparser_caps_set_cap(caps, usb_redir_cap_64bits_ids); -- usbredirparser_init(dev->parser, version, caps, USB_REDIR_CAPS_SIZE, 0); -+ -+ if (runstate_check(RUN_STATE_INMIGRATE)) { -+ flags |= usbredirparser_fl_no_hello; -+ } -+ usbredirparser_init(dev->parser, version, caps, USB_REDIR_CAPS_SIZE, -+ flags); - usbredirparser_do_write(dev->parser); - } - -@@ -949,6 +960,11 @@ static int usbredir_chardev_can_read(void *opaque) - return 0; - } - -+ /* Don't read new data from the chardev until our state is fully synced */ -+ if (!runstate_check(RUN_STATE_RUNNING)) { -+ return 0; -+ } -+ - /* usbredir_parser_do_read will consume *all* data we give it */ - return 1024 * 1024; - } -@@ -1004,6 +1020,15 @@ static const QemuChrHandlers usbredir_chr_handlers = { - * init + destroy - */ - -+static void usbredir_vm_state_change(void *priv, int running, RunState state) -+{ -+ USBRedirDevice *dev = priv; -+ -+ if (state == RUN_STATE_RUNNING && dev->parser != NULL) { -+ usbredirparser_do_write(dev->parser); /* Flush any pending writes */ -+ } -+} -+ - static int usbredir_initfn(USBDevice *udev) - { - USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); -@@ -1041,6 +1066,7 @@ static int usbredir_initfn(USBDevice *udev) - qemu_chr_fe_open(dev->cs); - qemu_chr_add_handlers(dev->cs, &usbredir_chr_handlers, dev); - -+ qemu_add_vm_change_state_handler(usbredir_vm_state_change, dev); - add_boot_device_path(dev->bootindex, &udev->qdev, NULL); - return 0; - } -@@ -1530,6 +1556,304 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id, - } - } - -+/* -+ * Migration code -+ */ -+ -+static void usbredir_pre_save(void *priv) -+{ -+ USBRedirDevice *dev = priv; -+ -+ usbredir_fill_already_in_flight(dev); -+} -+ -+static int usbredir_post_load(void *priv, int version_id) -+{ -+ USBRedirDevice *dev = priv; -+ struct USBEndpoint *usb_ep; -+ int i; -+ -+ for (i = 0; i < MAX_ENDPOINTS; i++) { -+ usb_ep = usb_ep_get(&dev->dev, -+ (i & 0x10) ? USB_TOKEN_IN : USB_TOKEN_OUT, -+ i & 0x0f); -+ usb_ep->type = dev->endpoint[i].type; -+ usb_ep->ifnum = dev->endpoint[i].interface; -+ usb_ep->max_packet_size = dev->endpoint[i].max_packet_size; -+ if (dev->endpoint[i].type == usb_redir_type_bulk) { -+ usb_ep->pipeline = true; -+ } -+ } -+ return 0; -+} -+ -+/* For usbredirparser migration */ -+static void usbredir_put_parser(QEMUFile *f, void *priv, size_t unused) -+{ -+ USBRedirDevice *dev = priv; -+ uint8_t *data; -+ int len; -+ -+ if (dev->parser == NULL) { -+ qemu_put_be32(f, 0); -+ return; -+ } -+ -+ usbredirparser_serialize(dev->parser, &data, &len); -+ qemu_oom_check(data); -+ -+ qemu_put_be32(f, len); -+ qemu_put_buffer(f, data, len); -+ -+ free(data); -+} -+ -+static int usbredir_get_parser(QEMUFile *f, void *priv, size_t unused) -+{ -+ USBRedirDevice *dev = priv; -+ uint8_t *data; -+ int len, ret; -+ -+ len = qemu_get_be32(f); -+ if (len == 0) { -+ return 0; -+ } -+ -+ /* -+ * Our chardev should be open already at this point, otherwise -+ * the usbredir channel will be broken (ie spice without seamless) -+ */ -+ if (dev->parser == NULL) { -+ ERROR("get_parser called with closed chardev, failing migration\n"); -+ return -1; -+ } -+ -+ data = g_malloc(len); -+ qemu_get_buffer(f, data, len); -+ -+ ret = usbredirparser_unserialize(dev->parser, data, len); -+ -+ g_free(data); -+ -+ return ret; -+} -+ -+static const VMStateInfo usbredir_parser_vmstate_info = { -+ .name = "usb-redir-parser", -+ .put = usbredir_put_parser, -+ .get = usbredir_get_parser, -+}; -+ -+ -+/* For buffered packets (iso/irq) queue migration */ -+static void usbredir_put_bufpq(QEMUFile *f, void *priv, size_t unused) -+{ -+ struct endp_data *endp = priv; -+ struct buf_packet *bufp; -+ int remain = endp->bufpq_size; -+ -+ qemu_put_be32(f, endp->bufpq_size); -+ QTAILQ_FOREACH(bufp, &endp->bufpq, next) { -+ qemu_put_be32(f, bufp->len); -+ qemu_put_be32(f, bufp->status); -+ qemu_put_buffer(f, bufp->data, bufp->len); -+ remain--; -+ } -+ assert(remain == 0); -+} -+ -+static int usbredir_get_bufpq(QEMUFile *f, void *priv, size_t unused) -+{ -+ struct endp_data *endp = priv; -+ struct buf_packet *bufp; -+ int i; -+ -+ endp->bufpq_size = qemu_get_be32(f); -+ for (i = 0; i < endp->bufpq_size; i++) { -+ bufp = g_malloc(sizeof(struct buf_packet)); -+ bufp->len = qemu_get_be32(f); -+ bufp->status = qemu_get_be32(f); -+ bufp->data = qemu_oom_check(malloc(bufp->len)); /* regular malloc! */ -+ qemu_get_buffer(f, bufp->data, bufp->len); -+ QTAILQ_INSERT_TAIL(&endp->bufpq, bufp, next); -+ } -+ return 0; -+} -+ -+static const VMStateInfo usbredir_ep_bufpq_vmstate_info = { -+ .name = "usb-redir-bufpq", -+ .put = usbredir_put_bufpq, -+ .get = usbredir_get_bufpq, -+}; -+ -+ -+/* For endp_data migration */ -+static const VMStateDescription usbredir_ep_vmstate = { -+ .name = "usb-redir-ep", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .fields = (VMStateField []) { -+ VMSTATE_UINT8(type, struct endp_data), -+ VMSTATE_UINT8(interval, struct endp_data), -+ VMSTATE_UINT8(interface, struct endp_data), -+ VMSTATE_UINT16(max_packet_size, struct endp_data), -+ VMSTATE_UINT8(iso_started, struct endp_data), -+ VMSTATE_UINT8(iso_error, struct endp_data), -+ VMSTATE_UINT8(interrupt_started, struct endp_data), -+ VMSTATE_UINT8(interrupt_error, struct endp_data), -+ VMSTATE_UINT8(bufpq_prefilled, struct endp_data), -+ VMSTATE_UINT8(bufpq_dropping_packets, struct endp_data), -+ { -+ .name = "bufpq", -+ .version_id = 0, -+ .field_exists = NULL, -+ .size = 0, -+ .info = &usbredir_ep_bufpq_vmstate_info, -+ .flags = VMS_SINGLE, -+ .offset = 0, -+ }, -+ VMSTATE_INT32(bufpq_target_size, struct endp_data), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+ -+/* For PacketIdQueue migration */ -+static void usbredir_put_packet_id_q(QEMUFile *f, void *priv, size_t unused) -+{ -+ struct PacketIdQueue *q = priv; -+ USBRedirDevice *dev = q->dev; -+ struct PacketIdQueueEntry *e; -+ int remain = q->size; -+ -+ DPRINTF("put_packet_id_q %s size %d\n", q->name, q->size); -+ qemu_put_be32(f, q->size); -+ QTAILQ_FOREACH(e, &q->head, next) { -+ qemu_put_be64(f, e->id); -+ remain--; -+ } -+ assert(remain == 0); -+} -+ -+static int usbredir_get_packet_id_q(QEMUFile *f, void *priv, size_t unused) -+{ -+ struct PacketIdQueue *q = priv; -+ USBRedirDevice *dev = q->dev; -+ int i, size; -+ uint64_t id; -+ -+ size = qemu_get_be32(f); -+ DPRINTF("get_packet_id_q %s size %d\n", q->name, size); -+ for (i = 0; i < size; i++) { -+ id = qemu_get_be64(f); -+ packet_id_queue_add(q, id); -+ } -+ assert(q->size == size); -+ return 0; -+} -+ -+static const VMStateInfo usbredir_ep_packet_id_q_vmstate_info = { -+ .name = "usb-redir-packet-id-q", -+ .put = usbredir_put_packet_id_q, -+ .get = usbredir_get_packet_id_q, -+}; -+ -+static const VMStateDescription usbredir_ep_packet_id_queue_vmstate = { -+ .name = "usb-redir-packet-id-queue", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .fields = (VMStateField []) { -+ { -+ .name = "queue", -+ .version_id = 0, -+ .field_exists = NULL, -+ .size = 0, -+ .info = &usbredir_ep_packet_id_q_vmstate_info, -+ .flags = VMS_SINGLE, -+ .offset = 0, -+ }, -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+ -+/* For usb_redir_device_connect_header migration */ -+static const VMStateDescription usbredir_device_info_vmstate = { -+ .name = "usb-redir-device-info", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .fields = (VMStateField []) { -+ VMSTATE_UINT8(speed, struct usb_redir_device_connect_header), -+ VMSTATE_UINT8(device_class, struct usb_redir_device_connect_header), -+ VMSTATE_UINT8(device_subclass, struct usb_redir_device_connect_header), -+ VMSTATE_UINT8(device_protocol, struct usb_redir_device_connect_header), -+ VMSTATE_UINT16(vendor_id, struct usb_redir_device_connect_header), -+ VMSTATE_UINT16(product_id, struct usb_redir_device_connect_header), -+ VMSTATE_UINT16(device_version_bcd, -+ struct usb_redir_device_connect_header), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+ -+/* For usb_redir_interface_info_header migration */ -+static const VMStateDescription usbredir_interface_info_vmstate = { -+ .name = "usb-redir-interface-info", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .fields = (VMStateField []) { -+ VMSTATE_UINT32(interface_count, -+ struct usb_redir_interface_info_header), -+ VMSTATE_UINT8_ARRAY(interface, -+ struct usb_redir_interface_info_header, 32), -+ VMSTATE_UINT8_ARRAY(interface_class, -+ struct usb_redir_interface_info_header, 32), -+ VMSTATE_UINT8_ARRAY(interface_subclass, -+ struct usb_redir_interface_info_header, 32), -+ VMSTATE_UINT8_ARRAY(interface_protocol, -+ struct usb_redir_interface_info_header, 32), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+ -+/* And finally the USBRedirDevice vmstate itself */ -+static const VMStateDescription usbredir_vmstate = { -+ .name = "usb-redir", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .pre_save = usbredir_pre_save, -+ .post_load = usbredir_post_load, -+ .fields = (VMStateField []) { -+ VMSTATE_USB_DEVICE(dev, USBRedirDevice), -+ VMSTATE_TIMER(attach_timer, USBRedirDevice), -+ { -+ .name = "parser", -+ .version_id = 0, -+ .field_exists = NULL, -+ .size = 0, -+ .info = &usbredir_parser_vmstate_info, -+ .flags = VMS_SINGLE, -+ .offset = 0, -+ }, -+ VMSTATE_STRUCT_ARRAY(endpoint, USBRedirDevice, MAX_ENDPOINTS, 1, -+ usbredir_ep_vmstate, struct endp_data), -+ VMSTATE_STRUCT(cancelled, USBRedirDevice, 1, -+ usbredir_ep_packet_id_queue_vmstate, -+ struct PacketIdQueue), -+ VMSTATE_STRUCT(already_in_flight, USBRedirDevice, 1, -+ usbredir_ep_packet_id_queue_vmstate, -+ struct PacketIdQueue), -+ VMSTATE_STRUCT(device_info, USBRedirDevice, 1, -+ usbredir_device_info_vmstate, -+ struct usb_redir_device_connect_header), -+ VMSTATE_STRUCT(interface_info, USBRedirDevice, 1, -+ usbredir_interface_info_vmstate, -+ struct usb_redir_interface_info_header), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ - static Property usbredir_properties[] = { - DEFINE_PROP_CHR("chardev", USBRedirDevice, cs), - DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, 0), -@@ -1550,6 +1874,7 @@ static void usbredir_class_initfn(ObjectClass *klass, void *data) - uc->handle_reset = usbredir_handle_reset; - uc->handle_data = usbredir_handle_data; - uc->handle_control = usbredir_handle_control; -+ dc->vmsd = &usbredir_vmstate; - dc->props = usbredir_properties; - } - --- -1.7.12 - diff --git a/0366-usb-redir-Add-chardev-open-close-debug-logging.patch b/0366-usb-redir-Add-chardev-open-close-debug-logging.patch deleted file mode 100644 index 42719c9..0000000 --- a/0366-usb-redir-Add-chardev-open-close-debug-logging.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 93691f50a5200651f22e698cc29be0b1a020f5c5 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Wed, 5 Sep 2012 15:56:57 +0200 -Subject: [PATCH 366/366] usb-redir: Add chardev open / close debug logging - -Signed-off-by: Hans de Goede ---- - hw/usb/redirect.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c -index 8dbb722..95a2167 100644 ---- a/hw/usb/redirect.c -+++ b/hw/usb/redirect.c -@@ -864,6 +864,7 @@ static void usbredir_chardev_close_bh(void *opaque) - usbredir_device_disconnect(dev); - - if (dev->parser) { -+ DPRINTF("destroying usbredirparser\n"); - usbredirparser_destroy(dev->parser); - dev->parser = NULL; - } -@@ -879,6 +880,8 @@ static void usbredir_chardev_open(USBRedirDevice *dev) - usbredir_chardev_close_bh(dev); - qemu_bh_cancel(dev->chardev_close_bh); - -+ DPRINTF("creating usbredirparser\n"); -+ - strcpy(version, "qemu usb-redir guest "); - pstrcat(version, sizeof(version), qemu_get_version()); - -@@ -990,9 +993,11 @@ static void usbredir_chardev_event(void *opaque, int event) - - switch (event) { - case CHR_EVENT_OPENED: -+ DPRINTF("chardev open\n"); - usbredir_chardev_open(dev); - break; - case CHR_EVENT_CLOSED: -+ DPRINTF("chardev close\n"); - qemu_bh_schedule(dev->chardev_close_bh); - break; - } -@@ -1255,6 +1260,7 @@ static void usbredir_device_disconnect(void *priv) - qemu_del_timer(dev->attach_timer); - - if (dev->dev.attached) { -+ DPRINTF("detaching device\n"); - usb_device_detach(&dev->dev); - /* - * Delay next usb device attach to give the guest a chance to see --- -1.7.12 - diff --git a/qemu.spec b/qemu.spec index 452f280..9214282 100644 --- a/qemu.spec +++ b/qemu.spec @@ -37,7 +37,7 @@ Summary: QEMU is a FAST! processor emulator Name: qemu Version: 1.2.0 -Release: 1%{?dist} +Release: 2%{?dist} # Epoch because we pushed a qemu-1.0 package. AIUI this can't ever be dropped Epoch: 2 License: GPLv2+ and LGPLv2+ and BSD @@ -115,6 +115,7 @@ Patch212: 0212-spice-make-number-of-surfaces-runtime-configurable.patch Patch213: 0213-qxl-Add-set_client_capabilities-interface-to-QXLInte.patch Patch214: 0214-Remove-ifdef-QXL_COMMAND_FLAG_COMPAT_16BPP.patch Patch215: 0215-qxl-dont-update-invalid-area.patch +Patch216: 0216-qxl-Ignore-set_client_capabilities-pre-post-migrate.patch # Ugh, ton of USB bugfixes / preparation patches for usb-redir # live-migration which did not make 1.2.0 :| @@ -182,12 +183,11 @@ Patch0357: 0357-usb-host-allow-emulated-non-async-control-requests-w.patch Patch0358: 0358-ehci-Don-t-set-seen-to-0-when-removing-unseen-queue-.patch Patch0359: 0359-ehci-Walk-async-schedule-before-and-after-migration.patch Patch0360: 0360-ehci-Don-t-process-too-much-frames-in-1-timer-tick.patch -Patch0361: 0361-usb-Migrate-over-device-speed-and-speedmask.patch -Patch0362: 0362-usb-redir-Change-cancelled-packet-code-into-a-generi.patch -Patch0363: 0363-usb-redir-Add-an-already_in_flight-packet-id-queue.patch -Patch0364: 0364-usb-redir-Store-max_packet_size-in-endp_data.patch -Patch0365: 0365-usb-redir-Add-support-for-migration.patch -Patch0366: 0366-usb-redir-Add-chardev-open-close-debug-logging.patch +Patch0361: 0361-usb-redir-Change-cancelled-packet-code-into-a-generi.patch +Patch0362: 0362-usb-redir-Add-an-already_in_flight-packet-id-queue.patch +Patch0363: 0363-usb-redir-Store-max_packet_size-in-endp_data.patch +Patch0364: 0364-usb-redir-Add-support-for-migration.patch +Patch0365: 0365-usb-redir-Add-chardev-open-close-debug-logging.patch BuildRequires: SDL-devel BuildRequires: zlib-devel @@ -500,6 +500,7 @@ such as kvm_stat. %patch213 -p1 %patch214 -p1 %patch215 -p1 +%patch216 -p1 %patch301 -p1 %patch302 -p1 @@ -566,7 +567,6 @@ such as kvm_stat. %patch363 -p1 %patch364 -p1 %patch365 -p1 -%patch366 -p1 %build @@ -1046,6 +1046,10 @@ fi %{_mandir}/man1/qemu-img.1* %changelog +* Sat Sep 10 2012 Hans de Goede - 2:1.2.0-2 +- Fix crash on (seamless) migration +- Sync usbredir live migration patches with upstream + * Fri Sep 9 2012 Hans de Goede - 2:1.2.0-1 - New upstream release 1.2.0 final - Add support for Spice seamless migration