summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRichard W.M. Jones <rjones@redhat.com>2012-10-08 17:26:53 +0100
committerRichard W.M. Jones <rjones@redhat.com>2012-10-09 09:45:42 +0100
commit0a85fbc946d7838366c35c0425efddb1a91f593c (patch)
treebfc621b7075d563a37fdaafda05b594c0522c9c6 /src
parent18b7f09f366d518050f467d0944c81c82fd5e39e (diff)
downloadlibguestfs-0a85fbc946d7838366c35c0425efddb1a91f593c.tar.gz
libguestfs-0a85fbc946d7838366c35c0425efddb1a91f593c.tar.xz
libguestfs-0a85fbc946d7838366c35c0425efddb1a91f593c.zip
Add support for hotplugging (removing disks).
New API: remove-drive. Note because of a bug in fuser, this only works with psmisc >= 22.20. This also updates the hotplugging tests.
Diffstat (limited to 'src')
-rw-r--r--src/MAX_PROC_NR2
-rw-r--r--src/guestfs-internal.h1
-rw-r--r--src/guestfs.pod10
-rw-r--r--src/launch-libvirt.c35
-rw-r--r--src/launch.c54
5 files changed, 98 insertions, 4 deletions
diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR
index 5b0cffbc..ba300673 100644
--- a/src/MAX_PROC_NR
+++ b/src/MAX_PROC_NR
@@ -1 +1 @@
-370
+372
diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h
index db9818c3..273900ef 100644
--- a/src/guestfs-internal.h
+++ b/src/guestfs-internal.h
@@ -169,6 +169,7 @@ struct attach_ops {
/* Hotplugging drives. */
int (*hot_add_drive) (guestfs_h *g, struct drive *drv, size_t drv_index);
+ int (*hot_remove_drive) (guestfs_h *g, struct drive *drv, size_t drv_index);
};
extern struct attach_ops attach_ops_appliance;
extern struct attach_ops attach_ops_libvirt;
diff --git a/src/guestfs.pod b/src/guestfs.pod
index 624e743e..0dbc30f1 100644
--- a/src/guestfs.pod
+++ b/src/guestfs.pod
@@ -606,9 +606,9 @@ download etc. instead.
=head2 HOTPLUGGING
-In libguestfs E<ge> 1.20, you may add drives after calling
-L</guestfs_launch>. There are some restrictions, see below.
-This is called I<hotplugging>.
+In libguestfs E<ge> 1.20, you may add drives and remove after calling
+L</guestfs_launch>. There are some restrictions, see below. This is
+called I<hotplugging>.
Only a subset of the attach-method backends support hotplugging
(currently only the libvirt attach-method has support). It also
@@ -629,6 +629,10 @@ so that the newly added disk has a predictable name. For example:
if (guestfs_part_disk ("/dev/disk/guestfs/newdisk", "mbr") == -1)
error ("partitioning of hot-added disk failed");
+To hot-remove a disk, call L</guestfs_remove_drive>. You can call
+this before or after L</guestfs_launch>. You can only remove disks
+that were previously added with a label.
+
Backends that support hotplugging do not require that you add
E<ge> 1 disk before calling launch. When hotplugging is supported
you don't need to add any disks.
diff --git a/src/launch-libvirt.c b/src/launch-libvirt.c
index 3eab5676..5b7897d7 100644
--- a/src/launch-libvirt.c
+++ b/src/launch-libvirt.c
@@ -1410,6 +1410,40 @@ hot_add_drive_libvirt (guestfs_h *g, struct drive *drv, size_t drv_index)
return -1;
}
+/* Hot-remove a drive. Note the appliance is up when this is called. */
+static int
+hot_remove_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;
+ }
+
+ /* Re-create the XML for the disk. */
+ xml = construct_libvirt_xml_hot_add_disk (g, drv, drv_index);
+ if (xml == NULL)
+ return -1;
+
+ /* Detach it. */
+ if (virDomainDetachDeviceFlags (dom, (char *) xml,
+ VIR_DOMAIN_DEVICE_MODIFY_LIVE) == -1) {
+ libvirt_error (g, _("could not detach disk from 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)
@@ -1449,6 +1483,7 @@ struct attach_ops attach_ops_libvirt = {
.shutdown = shutdown_libvirt,
.max_disks = max_disks_libvirt,
.hot_add_drive = hot_add_drive_libvirt,
+ .hot_remove_drive = hot_remove_drive_libvirt,
};
#else /* no libvirt or libxml2 at compile time */
diff --git a/src/launch.c b/src/launch.c
index a4e10fef..cc45a10b 100644
--- a/src/launch.c
+++ b/src/launch.c
@@ -452,6 +452,60 @@ guestfs__add_cdrom (guestfs_h *g, const char *filename)
return guestfs__config (g, "-cdrom", filename);
}
+/* Depending on whether we are hotplugging or not, this function
+ * does slightly different things: If not hotplugging, then the
+ * drive just disappears as if it had never been added. The later
+ * drives "move up" to fill the space. When hotplugging we have to
+ * do some complex stuff, and we usually end up leaving an empty
+ * (NULL) slot in the g->drives vector.
+ */
+int
+guestfs__remove_drive (guestfs_h *g, const char *label)
+{
+ size_t i;
+ struct drive *drv;
+
+ ITER_DRIVES (g, i, drv) {
+ if (drv->disk_label && STREQ (label, drv->disk_label))
+ goto found;
+ }
+ error (g, _("disk with label '%s' not found"), label);
+ return -1;
+
+ found:
+ if (g->state == CONFIG) { /* Not hotplugging. */
+ free_drive_struct (drv);
+
+ g->nr_drives--;
+ for (; i < g->nr_drives; ++i)
+ g->drives[i] = g->drives[i+1];
+
+ return 0;
+ }
+ else { /* Hotplugging. */
+ if (!g->attach_ops || !g->attach_ops->hot_remove_drive) {
+ error (g, _("the current attach-method does not support hotplugging drives"));
+ return -1;
+ }
+
+ if (guestfs_internal_hot_remove_drive_precheck (g, label) == -1)
+ return -1;
+
+ if (g->attach_ops->hot_remove_drive (g, drv, i) == -1)
+ return -1;
+
+ free_drive_struct (drv);
+ g->drives[i] = NULL;
+ if (i == g->nr_drives-1)
+ g->nr_drives--;
+
+ if (guestfs_internal_hot_remove_drive (g, label) == -1)
+ return -1;
+
+ return 0;
+ }
+}
+
int
guestfs__config (guestfs_h *g,
const char *qemu_param, const char *qemu_value)