2013-02-02 20:47:37 +00:00
|
|
|
From 7f3022f4ee2f83aeb0a1eea265f4bf9b4401096e Mon Sep 17 00:00:00 2001
|
2012-09-07 15:20:05 +00:00
|
|
|
From: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
Date: Tue, 4 Sep 2012 17:03:54 +0200
|
2012-10-28 18:05:07 +00:00
|
|
|
Subject: [PATCH] usb-redir: Add an already_in_flight packet-id queue
|
2012-09-07 15:20:05 +00:00
|
|
|
|
|
|
|
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 <hdegoede@redhat,com>
|
|
|
|
---
|
|
|
|
hw/usb/redirect.c | 43 +++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
1 file changed, 43 insertions(+)
|
|
|
|
|
|
|
|
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
|
2012-10-28 18:05:07 +00:00
|
|
|
index e2b8159..cdd705f 100644
|
2012-09-07 15:20:05 +00:00
|
|
|
--- 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;
|
2012-10-28 18:05:07 +00:00
|
|
|
@@ -328,6 +329,34 @@ static int usbredir_is_cancelled(USBRedirDevice *dev, uint64_t id)
|
2012-09-07 15:20:05 +00:00
|
|
|
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)
|
|
|
|
{
|
2012-10-28 18:05:07 +00:00
|
|
|
@@ -543,6 +572,10 @@ static int usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p,
|
2012-09-07 15:20:05 +00:00
|
|
|
|
|
|
|
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;
|
2012-10-28 18:05:07 +00:00
|
|
|
@@ -623,6 +656,10 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev,
|
2012-09-07 15:20:05 +00:00
|
|
|
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;
|
|
|
|
|
2012-10-28 18:05:07 +00:00
|
|
|
@@ -765,6 +802,10 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p,
|
2012-09-07 15:20:05 +00:00
|
|
|
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:
|
2012-10-28 18:05:07 +00:00
|
|
|
@@ -982,6 +1023,7 @@ static int usbredir_initfn(USBDevice *udev)
|
2012-09-07 15:20:05 +00:00
|
|
|
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);
|
|
|
|
}
|
2012-10-28 18:05:07 +00:00
|
|
|
@@ -1002,6 +1044,7 @@ static void usbredir_cleanup_device_queues(USBRedirDevice *dev)
|
2012-09-07 15:20:05 +00:00
|
|
|
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));
|
|
|
|
}
|