if (dev->state == XenbusStateConnected)
break;
+ /* Enforce precondition before potential leak point.
+ * blkif_disconnect() is idempotent.
+ */
+ blkif_disconnect(be->blkif);
+
err = connect_ring(be);
if (err)
break;
break;
/* fall through if not online */
case XenbusStateUnknown:
+ /* implies blkif_disconnect() via blkback_remove() */
device_unregister(&dev->dev);
break;
tap_update_blkif_status(be->blkif);
}
+
+static void blkif_disconnect(blkif_t *blkif)
+{
+ if (blkif->xenblkd) {
+ kthread_stop(blkif->xenblkd);
+ blkif->xenblkd = NULL;
+ }
+
+ /* idempotent */
+ tap_blkif_free(blkif);
+}
+
/**
* Callback received when the frontend's state changes.
*/
if (dev->state == XenbusStateConnected)
break;
+ /* Enforce precondition before potential leak point.
+ * blkif_disconnect() is idempotent.
+ */
+ blkif_disconnect(be->blkif);
+
err = connect_ring(be);
if (err)
break;
break;
case XenbusStateClosing:
- if (be->blkif->xenblkd) {
- kthread_stop(be->blkif->xenblkd);
- be->blkif->xenblkd = NULL;
- }
- tap_blkif_free(be->blkif);
+ blkif_disconnect(be->blkif);
xenbus_switch_state(dev, XenbusStateClosing);
break;
break;
/* fall through if not online */
case XenbusStateUnknown:
+ /* Implies the effects of blkif_disconnect() via
+ * blktap_remove().
+ */
device_unregister(&dev->dev);
break;
static int connect_rings(struct backend_info *);
static void connect(struct backend_info *);
static void backend_create_netif(struct backend_info *be);
+static void netback_disconnect(struct device *);
static int netback_remove(struct xenbus_device *dev)
{
netback_remove_accelerators(be, dev);
- if (be->netif) {
- kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
- netif_disconnect(be->netif);
- be->netif = NULL;
- }
+ netback_disconnect(&dev->dev);
kfree(be);
dev->dev.driver_data = NULL;
return 0;
}
+static void netback_disconnect(struct device *xbdev_dev)
+{
+ struct backend_info *be = xbdev_dev->driver_data;
+
+ if (be->netif) {
+ kobject_uevent(&xbdev_dev->kobj, KOBJ_OFFLINE);
+ netif_disconnect(be->netif);
+ be->netif = NULL;
+ }
+}
/**
* Entry point to this code when a new device is created. Allocate the basic
case XenbusStateConnected:
if (dev->state == XenbusStateConnected)
break;
+
+ /* Enforce precondition before potential leak point.
+ * netback_disconnect() is idempotent.
+ */
+ netback_disconnect(&dev->dev);
+
backend_create_netif(be);
if (be->netif)
connect(be);
break;
case XenbusStateClosing:
- if (be->netif) {
- kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
- netif_disconnect(be->netif);
- be->netif = NULL;
- }
+ netback_disconnect(&dev->dev);
xenbus_switch_state(dev, XenbusStateClosing);
break;
break;
/* fall through if not online */
case XenbusStateUnknown:
+ /* implies netback_disconnect() via netback_remove() */
device_unregister(&dev->dev);
break;