431f30630a
Synch with IBS qemu: includes xen patches, security patches, some spec file cleanup, and finally getting qemu-bridge-helper working right. Also temporarily disable librbd dependency in OBS until staging impact concerns get resolved. OBS-URL: https://build.opensuse.org/request/show/416912 OBS-URL: https://build.opensuse.org/package/show/Virtualization/qemu?expand=0&rev=309
211 lines
7.0 KiB
Diff
211 lines
7.0 KiB
Diff
From afb94bcc5bbb8b58f8c96821caaab268f96cabdb Mon Sep 17 00:00:00 2001
|
|
From: Juergen Gross <jgross@suse.com>
|
|
Date: Wed, 27 Jul 2016 08:17:41 +0200
|
|
Subject: [PATCH] xen: drain submit queue in xen-usb before removing device
|
|
|
|
When unplugging a device in the Xen pvusb backend drain the submit
|
|
queue before deallocation of the control structures. Otherwise there
|
|
will be bogus memory accesses when I/O contracts are finished.
|
|
|
|
Correlated to this issue is the handling of cancel requests: a packet
|
|
cancelled will still lead to the call of complete, so add a flag
|
|
to the request indicating it should be just dropped on complete.
|
|
|
|
Signed-off-by: Juergen Gross <jgross@suse.com>
|
|
Signed-off-by: Bruce Rogers <brogers@suse.com>
|
|
---
|
|
hw/usb/xen-usb.c | 95 ++++++++++++++++++++++++++++++++++++--------------------
|
|
1 file changed, 61 insertions(+), 34 deletions(-)
|
|
|
|
diff --git a/hw/usb/xen-usb.c b/hw/usb/xen-usb.c
|
|
index 664df04..6f4b99d 100644
|
|
--- a/hw/usb/xen-usb.c
|
|
+++ b/hw/usb/xen-usb.c
|
|
@@ -94,6 +94,8 @@ struct usbback_req {
|
|
void *buffer;
|
|
void *isoc_buffer;
|
|
struct libusb_transfer *xfer;
|
|
+
|
|
+ bool cancelled;
|
|
};
|
|
|
|
struct usbback_hotplug {
|
|
@@ -304,20 +306,23 @@ static void usbback_do_response(struct usbback_req *usbback_req, int32_t status,
|
|
usbback_req->isoc_buffer = NULL;
|
|
}
|
|
|
|
- res = RING_GET_RESPONSE(&usbif->urb_ring, usbif->urb_ring.rsp_prod_pvt);
|
|
- res->id = usbback_req->req.id;
|
|
- res->status = status;
|
|
- res->actual_length = actual_length;
|
|
- res->error_count = error_count;
|
|
- res->start_frame = 0;
|
|
- usbif->urb_ring.rsp_prod_pvt++;
|
|
- RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&usbif->urb_ring, notify);
|
|
-
|
|
- if (notify) {
|
|
- xen_be_send_notify(xendev);
|
|
+ if (usbif->urb_sring) {
|
|
+ res = RING_GET_RESPONSE(&usbif->urb_ring, usbif->urb_ring.rsp_prod_pvt);
|
|
+ res->id = usbback_req->req.id;
|
|
+ res->status = status;
|
|
+ res->actual_length = actual_length;
|
|
+ res->error_count = error_count;
|
|
+ res->start_frame = 0;
|
|
+ usbif->urb_ring.rsp_prod_pvt++;
|
|
+ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&usbif->urb_ring, notify);
|
|
+
|
|
+ if (notify) {
|
|
+ xen_be_send_notify(xendev);
|
|
+ }
|
|
}
|
|
|
|
- usbback_put_req(usbback_req);
|
|
+ if (!usbback_req->cancelled)
|
|
+ usbback_put_req(usbback_req);
|
|
}
|
|
|
|
static void usbback_do_response_ret(struct usbback_req *usbback_req,
|
|
@@ -369,15 +374,14 @@ static void usbback_set_address(struct usbback_info *usbif,
|
|
}
|
|
}
|
|
|
|
-static bool usbback_cancel_req(struct usbback_req *usbback_req)
|
|
+static void usbback_cancel_req(struct usbback_req *usbback_req)
|
|
{
|
|
- bool ret = false;
|
|
-
|
|
if (usb_packet_is_inflight(&usbback_req->packet)) {
|
|
usb_cancel_packet(&usbback_req->packet);
|
|
- ret = true;
|
|
+ QTAILQ_REMOVE(&usbback_req->stub->submit_q, usbback_req, q);
|
|
+ usbback_req->cancelled = true;
|
|
+ usbback_do_response_ret(usbback_req, -EPROTO);
|
|
}
|
|
- return ret;
|
|
}
|
|
|
|
static void usbback_process_unlink_req(struct usbback_req *usbback_req)
|
|
@@ -394,7 +398,7 @@ static void usbback_process_unlink_req(struct usbback_req *usbback_req)
|
|
devnum = usbif_pipedevice(usbback_req->req.pipe);
|
|
if (unlikely(devnum == 0)) {
|
|
usbback_req->stub = usbif->ports +
|
|
- usbif_pipeportnum(usbback_req->req.pipe);
|
|
+ usbif_pipeportnum(usbback_req->req.pipe) - 1;
|
|
if (unlikely(!usbback_req->stub)) {
|
|
ret = -ENODEV;
|
|
goto fail_response;
|
|
@@ -409,9 +413,7 @@ static void usbback_process_unlink_req(struct usbback_req *usbback_req)
|
|
|
|
QTAILQ_FOREACH(unlink_req, &usbback_req->stub->submit_q, q) {
|
|
if (unlink_req->req.id == id) {
|
|
- if (usbback_cancel_req(unlink_req)) {
|
|
- usbback_do_response_ret(unlink_req, -EPROTO);
|
|
- }
|
|
+ usbback_cancel_req(unlink_req);
|
|
break;
|
|
}
|
|
}
|
|
@@ -684,6 +686,31 @@ static void usbback_hotplug_enq(struct usbback_info *usbif, unsigned port)
|
|
usbback_hotplug_notify(usbif);
|
|
}
|
|
|
|
+static void usbback_portid_drain(struct usbback_info *usbif, unsigned port)
|
|
+{
|
|
+ struct usbback_req *req, *tmp;
|
|
+ bool sched = false;
|
|
+
|
|
+ QTAILQ_FOREACH_SAFE(req, &usbif->ports[port - 1].submit_q, q, tmp) {
|
|
+ usbback_cancel_req(req);
|
|
+ sched = true;
|
|
+ }
|
|
+
|
|
+ if (sched)
|
|
+ qemu_bh_schedule(usbif->bh);
|
|
+}
|
|
+
|
|
+static void usbback_portid_detach(struct usbback_info *usbif, unsigned port)
|
|
+{
|
|
+ if (!usbif->ports[port - 1].attached)
|
|
+ return;
|
|
+
|
|
+ usbif->ports[port - 1].speed = USBIF_SPEED_NONE;
|
|
+ usbif->ports[port - 1].attached = false;
|
|
+ usbback_portid_drain(usbif, port);
|
|
+ usbback_hotplug_enq(usbif, port);
|
|
+}
|
|
+
|
|
static void usbback_portid_remove(struct usbback_info *usbif, unsigned port)
|
|
{
|
|
USBPort *p;
|
|
@@ -697,9 +724,7 @@ static void usbback_portid_remove(struct usbback_info *usbif, unsigned port)
|
|
|
|
object_unparent(OBJECT(usbif->ports[port - 1].dev));
|
|
usbif->ports[port - 1].dev = NULL;
|
|
- usbif->ports[port - 1].speed = USBIF_SPEED_NONE;
|
|
- usbif->ports[port - 1].attached = false;
|
|
- usbback_hotplug_enq(usbif, port);
|
|
+ usbback_portid_detach(usbif, port);
|
|
|
|
TR_BUS(&usbif->xendev, "port %d removed\n", port);
|
|
}
|
|
@@ -804,7 +829,6 @@ static void usbback_process_port(struct usbback_info *usbif, unsigned port)
|
|
static void usbback_disconnect(struct XenDevice *xendev)
|
|
{
|
|
struct usbback_info *usbif;
|
|
- struct usbback_req *req, *tmp;
|
|
unsigned int i;
|
|
|
|
TR_BUS(xendev, "start\n");
|
|
@@ -823,12 +847,8 @@ static void usbback_disconnect(struct XenDevice *xendev)
|
|
}
|
|
|
|
for (i = 0; i < usbif->num_ports; i++) {
|
|
- if (!usbif->ports[i].dev) {
|
|
- continue;
|
|
- }
|
|
- QTAILQ_FOREACH_SAFE(req, &usbif->ports[i].submit_q, q, tmp) {
|
|
- usbback_cancel_req(req);
|
|
- }
|
|
+ if (usbif->ports[i].dev)
|
|
+ usbback_portid_drain(usbif, i + 1);
|
|
}
|
|
|
|
TR_BUS(xendev, "finished\n");
|
|
@@ -947,8 +967,7 @@ static void xen_bus_detach(USBPort *port)
|
|
|
|
usbif = port->opaque;
|
|
TR_BUS(&usbif->xendev, "\n");
|
|
- usbif->ports[port->index].attached = false;
|
|
- usbback_hotplug_enq(usbif, port->index + 1);
|
|
+ usbback_portid_detach(usbif, port->index + 1);
|
|
}
|
|
|
|
static void xen_bus_child_detach(USBPort *port, USBDevice *child)
|
|
@@ -961,9 +980,16 @@ static void xen_bus_child_detach(USBPort *port, USBDevice *child)
|
|
|
|
static void xen_bus_complete(USBPort *port, USBPacket *packet)
|
|
{
|
|
+ struct usbback_req *usbback_req;
|
|
struct usbback_info *usbif;
|
|
|
|
- usbif = port->opaque;
|
|
+ usbback_req = container_of(packet, struct usbback_req, packet);
|
|
+ if (usbback_req->cancelled) {
|
|
+ g_free(usbback_req);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ usbif = usbback_req->usbif;
|
|
TR_REQ(&usbif->xendev, "\n");
|
|
usbback_packet_complete(packet);
|
|
}
|
|
@@ -1040,6 +1066,7 @@ static int usbback_free(struct XenDevice *xendev)
|
|
}
|
|
|
|
usb_bus_release(&usbif->bus);
|
|
+ object_unparent(OBJECT(&usbif->bus));
|
|
|
|
TR_BUS(xendev, "finished\n");
|
|
|