diff options
author | Richard W.M. Jones <rjones@redhat.com> | 2012-10-08 17:26:53 +0100 |
---|---|---|
committer | Richard W.M. Jones <rjones@redhat.com> | 2012-10-09 09:45:42 +0100 |
commit | 0a85fbc946d7838366c35c0425efddb1a91f593c (patch) | |
tree | bfc621b7075d563a37fdaafda05b594c0522c9c6 /src | |
parent | 18b7f09f366d518050f467d0944c81c82fd5e39e (diff) | |
download | libguestfs-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_NR | 2 | ||||
-rw-r--r-- | src/guestfs-internal.h | 1 | ||||
-rw-r--r-- | src/guestfs.pod | 10 | ||||
-rw-r--r-- | src/launch-libvirt.c | 35 | ||||
-rw-r--r-- | src/launch.c | 54 |
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) |