xen/blkback: fix tear-down issues
Handle tearing down a blkback that hasn't been fully initialized. This requires carefully checking that fields are allocated before trying to access them. Also communication memory is allocated before setting XBBF_RING_CONNECTED, so gating it's freeing on XBBF_RING_CONNECTED being set is wrong and will lead to memory leaks. Also stop using xbb_disconnect() in error paths. Use xenbus_dev_fatal and let the normal disconnection procedure take care of the cleanup. Reported by: Ze Dupsys <zedupsys@gmail.com> Sponsored by: Citrix Systems R&D
This commit is contained in:
parent
f3d54ded28
commit
137381ca60
@ -2774,19 +2774,12 @@ xbb_free_communication_mem(struct xbb_softc *xbb)
|
|||||||
static int
|
static int
|
||||||
xbb_disconnect(struct xbb_softc *xbb)
|
xbb_disconnect(struct xbb_softc *xbb)
|
||||||
{
|
{
|
||||||
struct gnttab_unmap_grant_ref ops[XBB_MAX_RING_PAGES];
|
|
||||||
struct gnttab_unmap_grant_ref *op;
|
|
||||||
u_int ring_idx;
|
|
||||||
int error;
|
|
||||||
|
|
||||||
DPRINTF("\n");
|
DPRINTF("\n");
|
||||||
|
|
||||||
if ((xbb->flags & XBBF_RING_CONNECTED) == 0)
|
|
||||||
return (0);
|
|
||||||
|
|
||||||
mtx_unlock(&xbb->lock);
|
mtx_unlock(&xbb->lock);
|
||||||
xen_intr_unbind(&xbb->xen_intr_handle);
|
xen_intr_unbind(&xbb->xen_intr_handle);
|
||||||
taskqueue_drain(xbb->io_taskqueue, &xbb->io_task);
|
if (xbb->io_taskqueue != NULL)
|
||||||
|
taskqueue_drain(xbb->io_taskqueue, &xbb->io_task);
|
||||||
mtx_lock(&xbb->lock);
|
mtx_lock(&xbb->lock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2796,19 +2789,28 @@ xbb_disconnect(struct xbb_softc *xbb)
|
|||||||
if (xbb->active_request_count != 0)
|
if (xbb->active_request_count != 0)
|
||||||
return (EAGAIN);
|
return (EAGAIN);
|
||||||
|
|
||||||
for (ring_idx = 0, op = ops;
|
if (xbb->flags & XBBF_RING_CONNECTED) {
|
||||||
ring_idx < xbb->ring_config.ring_pages;
|
struct gnttab_unmap_grant_ref ops[XBB_MAX_RING_PAGES];
|
||||||
ring_idx++, op++) {
|
struct gnttab_unmap_grant_ref *op;
|
||||||
op->host_addr = xbb->ring_config.gnt_addr
|
unsigned int ring_idx;
|
||||||
+ (ring_idx * PAGE_SIZE);
|
int error;
|
||||||
op->dev_bus_addr = xbb->ring_config.bus_addr[ring_idx];
|
|
||||||
op->handle = xbb->ring_config.handle[ring_idx];
|
|
||||||
}
|
|
||||||
|
|
||||||
error = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, ops,
|
for (ring_idx = 0, op = ops;
|
||||||
xbb->ring_config.ring_pages);
|
ring_idx < xbb->ring_config.ring_pages;
|
||||||
if (error != 0)
|
ring_idx++, op++) {
|
||||||
panic("Grant table op failed (%d)", error);
|
op->host_addr = xbb->ring_config.gnt_addr
|
||||||
|
+ (ring_idx * PAGE_SIZE);
|
||||||
|
op->dev_bus_addr = xbb->ring_config.bus_addr[ring_idx];
|
||||||
|
op->handle = xbb->ring_config.handle[ring_idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
error = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, ops,
|
||||||
|
xbb->ring_config.ring_pages);
|
||||||
|
if (error != 0)
|
||||||
|
panic("Grant table op failed (%d)", error);
|
||||||
|
|
||||||
|
xbb->flags &= ~XBBF_RING_CONNECTED;
|
||||||
|
}
|
||||||
|
|
||||||
xbb_free_communication_mem(xbb);
|
xbb_free_communication_mem(xbb);
|
||||||
|
|
||||||
@ -2839,7 +2841,6 @@ xbb_disconnect(struct xbb_softc *xbb)
|
|||||||
xbb->request_lists = NULL;
|
xbb->request_lists = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
xbb->flags &= ~XBBF_RING_CONNECTED;
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2963,7 +2964,6 @@ xbb_connect_ring(struct xbb_softc *xbb)
|
|||||||
INTR_TYPE_BIO | INTR_MPSAFE,
|
INTR_TYPE_BIO | INTR_MPSAFE,
|
||||||
&xbb->xen_intr_handle);
|
&xbb->xen_intr_handle);
|
||||||
if (error) {
|
if (error) {
|
||||||
(void)xbb_disconnect(xbb);
|
|
||||||
xenbus_dev_fatal(xbb->dev, error, "binding event channel");
|
xenbus_dev_fatal(xbb->dev, error, "binding event channel");
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
@ -3338,6 +3338,13 @@ xbb_connect(struct xbb_softc *xbb)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
error = xbb_publish_backend_info(xbb);
|
||||||
|
if (error != 0) {
|
||||||
|
xenbus_dev_fatal(xbb->dev, error,
|
||||||
|
"Unable to publish device information");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
error = xbb_alloc_requests(xbb);
|
error = xbb_alloc_requests(xbb);
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
/* Specific errors are reported by xbb_alloc_requests(). */
|
/* Specific errors are reported by xbb_alloc_requests(). */
|
||||||
@ -3359,16 +3366,6 @@ xbb_connect(struct xbb_softc *xbb)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xbb_publish_backend_info(xbb) != 0) {
|
|
||||||
/*
|
|
||||||
* If we can't publish our data, we cannot participate
|
|
||||||
* in this connection, and waiting for a front-end state
|
|
||||||
* change will not help the situation.
|
|
||||||
*/
|
|
||||||
(void)xbb_disconnect(xbb);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ready for I/O. */
|
/* Ready for I/O. */
|
||||||
xenbus_set_state(xbb->dev, XenbusStateConnected);
|
xenbus_set_state(xbb->dev, XenbusStateConnected);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user