summary refs log tree commit diff stats
path: root/hw/block/xen-block.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/block/xen-block.c')
-rw-r--r--hw/block/xen-block.c70
1 files changed, 70 insertions, 0 deletions
diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c
index d27a2865bc..3a963b0383 100644
--- a/hw/block/xen-block.c
+++ b/hw/block/xen-block.c
@@ -21,6 +21,24 @@ static char *xen_block_get_name(XenDevice *xendev, Error **errp)
     return g_strdup_printf("%lu", vdev->number);
 }
 
+static void xen_block_disconnect(XenDevice *xendev, Error **errp)
+{
+    XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
+    const char *type = object_get_typename(OBJECT(blockdev));
+    XenBlockVdev *vdev = &blockdev->props.vdev;
+
+    trace_xen_block_disconnect(type, vdev->disk, vdev->partition);
+}
+
+static void xen_block_connect(XenDevice *xendev, Error **errp)
+{
+    XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
+    const char *type = object_get_typename(OBJECT(blockdev));
+    XenBlockVdev *vdev = &blockdev->props.vdev;
+
+    trace_xen_block_connect(type, vdev->disk, vdev->partition);
+}
+
 static void xen_block_unrealize(XenDevice *xendev, Error **errp)
 {
     XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
@@ -35,6 +53,9 @@ static void xen_block_unrealize(XenDevice *xendev, Error **errp)
 
     trace_xen_block_unrealize(type, vdev->disk, vdev->partition);
 
+    /* Disconnect from the frontend in case this has not already happened */
+    xen_block_disconnect(xendev, NULL);
+
     if (blockdev_class->unrealize) {
         blockdev_class->unrealize(blockdev, errp);
     }
@@ -64,6 +85,54 @@ static void xen_block_realize(XenDevice *xendev, Error **errp)
     }
 }
 
+static void xen_block_frontend_changed(XenDevice *xendev,
+                                       enum xenbus_state frontend_state,
+                                       Error **errp)
+{
+    enum xenbus_state backend_state = xen_device_backend_get_state(xendev);
+    Error *local_err = NULL;
+
+    switch (frontend_state) {
+    case XenbusStateInitialised:
+    case XenbusStateConnected:
+        if (backend_state == XenbusStateConnected) {
+            break;
+        }
+
+        xen_block_disconnect(xendev, &local_err);
+        if (local_err) {
+            error_propagate(errp, local_err);
+            break;
+        }
+
+        xen_block_connect(xendev, &local_err);
+        if (local_err) {
+            error_propagate(errp, local_err);
+            break;
+        }
+
+        xen_device_backend_set_state(xendev, XenbusStateConnected);
+        break;
+
+    case XenbusStateClosing:
+        xen_device_backend_set_state(xendev, XenbusStateClosing);
+        break;
+
+    case XenbusStateClosed:
+        xen_block_disconnect(xendev, &local_err);
+        if (local_err) {
+            error_propagate(errp, local_err);
+            break;
+        }
+
+        xen_device_backend_set_state(xendev, XenbusStateClosed);
+        break;
+
+    default:
+        break;
+    }
+}
+
 static char *disk_to_vbd_name(unsigned int disk)
 {
     char *name, *prefix = (disk >= 26) ?
@@ -272,6 +341,7 @@ static void xen_block_class_init(ObjectClass *class, void *data)
 
     xendev_class->get_name = xen_block_get_name;
     xendev_class->realize = xen_block_realize;
+    xendev_class->frontend_changed = xen_block_frontend_changed;
     xendev_class->unrealize = xen_block_unrealize;
 
     dev_class->props = xen_block_props;