summaryrefslogtreecommitdiffstats
path: root/src/launch-libvirt.c
diff options
context:
space:
mode:
authorRichard W.M. Jones <rjones@redhat.com>2012-10-05 14:56:35 +0100
committerRichard W.M. Jones <rjones@redhat.com>2012-10-08 20:04:53 +0100
commit18b7f09f366d518050f467d0944c81c82fd5e39e (patch)
tree6f89801dec73c60eb05cc01160544d76782e454a /src/launch-libvirt.c
parent7786d56db8c22413949f98ef6b15fe0ea367d195 (diff)
downloadlibguestfs-18b7f09f366d518050f467d0944c81c82fd5e39e.tar.gz
libguestfs-18b7f09f366d518050f467d0944c81c82fd5e39e.tar.xz
libguestfs-18b7f09f366d518050f467d0944c81c82fd5e39e.zip
Add support for hotplugging (adding disks) to the libvirt attach-method.
When libvirt is used, we can allow disks to be hotplugged. guestfs_add_drive can be called after launch to hot-add a disk. When a disk is hot-added, we first ask libvirt to add the disk to the appliance, then we make an internal call into the appliance to get it to wait for the disk to appear (ie. udev_settle ()). Hot-added disks are tracked in the g->drives array. This also adds a test.
Diffstat (limited to 'src/launch-libvirt.c')
-rw-r--r--src/launch-libvirt.c99
1 files changed, 90 insertions, 9 deletions
diff --git a/src/launch-libvirt.c b/src/launch-libvirt.c
index aa1c39f2..3eab5676 100644
--- a/src/launch-libvirt.c
+++ b/src/launch-libvirt.c
@@ -135,14 +135,6 @@ launch_libvirt (guestfs_h *g, const char *libvirt_uri)
struct drive *drv;
size_t i;
- /* At present you must add drives before starting the appliance. In
- * future when we enable hotplugging you won't need to do this.
- */
- if (!g->nr_drives) {
- error (g, _("you must call guestfs_add_drive before guestfs_launch"));
- return -1;
- }
-
/* XXX: It should be possible to make this work. */
if (g->direct) {
error (g, _("direct mode flag is not supported yet for libvirt attach method"));
@@ -1376,6 +1368,89 @@ max_disks_libvirt (guestfs_h *g)
return 255;
}
+static xmlChar *construct_libvirt_xml_hot_add_disk (guestfs_h *g, struct drive *drv, size_t drv_index);
+
+/* Hot-add a drive. Note the appliance is up when this is called. */
+static int
+hot_add_drive_libvirt (guestfs_h *g, struct drive *drv, size_t drv_index)
+{
+ virConnectPtr conn = g->virt.connv;
+ virDomainPtr dom = g->virt.domv;
+ xmlChar *xml = NULL;
+
+ if (!conn || !dom) {
+ /* This is essentially an internal error if it happens. */
+ error (g, "%s: conn == NULL or dom == NULL", __func__);
+ return -1;
+ }
+
+ /* Create overlay for read-only drive. This works around lack of
+ * support for <transient/> disks in libvirt.
+ */
+ if (make_qcow2_overlay_for_drive (g, drv) == -1)
+ return -1;
+
+ /* Create the XML for the new disk. */
+ xml = construct_libvirt_xml_hot_add_disk (g, drv, drv_index);
+ if (xml == NULL)
+ return -1;
+
+ /* Attach it. */
+ if (virDomainAttachDeviceFlags (dom, (char *) xml,
+ VIR_DOMAIN_DEVICE_MODIFY_LIVE) == -1) {
+ libvirt_error (g, _("could not attach disk to libvirt domain"));
+ goto error;
+ }
+
+ free (xml);
+ return 0;
+
+ error:
+ free (xml);
+ return -1;
+}
+
+static xmlChar *
+construct_libvirt_xml_hot_add_disk (guestfs_h *g, struct drive *drv,
+ size_t drv_index)
+{
+ xmlChar *ret = NULL;
+ xmlBufferPtr xb = NULL;
+ xmlOutputBufferPtr ob;
+ xmlTextWriterPtr xo = NULL;
+
+ XMLERROR (NULL, xb = xmlBufferCreate ());
+ XMLERROR (NULL, ob = xmlOutputBufferCreateBuffer (xb, NULL));
+ XMLERROR (NULL, xo = xmlNewTextWriter (ob));
+
+ XMLERROR (-1, xmlTextWriterSetIndent (xo, 1));
+ XMLERROR (-1, xmlTextWriterSetIndentString (xo, BAD_CAST " "));
+ XMLERROR (-1, xmlTextWriterStartDocument (xo, NULL, NULL, NULL));
+
+ if (construct_libvirt_xml_disk (g, xo, drv, drv_index) == -1)
+ goto err;
+
+ XMLERROR (-1, xmlTextWriterEndDocument (xo));
+ XMLERROR (NULL, ret = xmlBufferDetach (xb)); /* caller frees ret */
+
+ debug (g, "hot-add disk XML:\n%s", ret);
+
+ err:
+ if (xo)
+ xmlFreeTextWriter (xo); /* frees 'ob' too */
+ if (xb)
+ xmlBufferFree (xb);
+
+ return ret;
+}
+
+struct attach_ops attach_ops_libvirt = {
+ .launch = launch_libvirt,
+ .shutdown = shutdown_libvirt,
+ .max_disks = max_disks_libvirt,
+ .hot_add_drive = hot_add_drive_libvirt,
+};
+
#else /* no libvirt or libxml2 at compile time */
#define NOT_IMPL(r) \
@@ -1403,10 +1478,16 @@ max_disks_libvirt (guestfs_h *g)
NOT_IMPL (-1);
}
-#endif /* no libvirt or libxml2 at compile time */
+static int
+hot_add_drive_libvirt (guestfs_h *g, struct drive *drv, size_t drv_index)
+{
+ NOT_IMPL (-1);
+}
struct attach_ops attach_ops_libvirt = {
.launch = launch_libvirt,
.shutdown = shutdown_libvirt,
.max_disks = max_disks_libvirt,
};
+
+#endif /* no libvirt or libxml2 at compile time */