With 'optional' startupPolicy set, when one or more disk are missing,
the qemu process drops their definitions and bootups the vm.
When the vm is using per-device boot elements, then we need to
reorder them in order to perform migrate successfully if necessary.
During the reordering, it uses virBitmapNextLastSetBit to find the
last set bit.
---
src/conf/domain_conf.c | 2 ++
src/conf/domain_conf.h | 1 +
src/qemu/qemu_domain.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++----
3 files changed, 86 insertions(+), 7 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 177faaa..069e702 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -10992,6 +10992,8 @@ virDomainDefParseXML(virCapsPtr caps,
if (virDomainDefAddImplicitControllers(def) < 0)
goto error;
+ /* Save the valid number of per-device boot */
+ def->os.nBootPerDevs = bootMapSize;
virBitmapFree(bootMap);
return def;
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 96f11ba..362f645 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1543,6 +1543,7 @@ struct _virDomainOSDef {
char *machine;
size_t nBootDevs;
int bootDevs[VIR_DOMAIN_BOOT_LAST];
+ unsigned long nBootPerDevs;
/* enum virDomainBootMenu */
int bootmenu;
char *init;
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index c79b05d..4594b2c 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -1791,30 +1791,89 @@ cleanup:
virObjectUnref(cfg);
}
+/* Reorder devices with per-device boot, make them contiguous */
+static int
+qemuDomainPerDevicesBootReorder(virDomainDefPtr def,
+ virBitmapPtr bitmap)
+{
+ size_t count;
+ size_t n;
+ int i = -1;
+
+ if (bitmap == NULL)
+ return 0;
+
+ count = virBitmapCountBits(bitmap);
+
+ while (count && count--) {
+ i = virBitmapNextLastSetBit(bitmap, i);
+ for (n = 0 ; n < def->ndisks ; n++) {
+ virDomainDiskDefPtr disk = def->disks[n];
+ if (disk->info.bootIndex > i + 1)
+ disk->info.bootIndex -= 1;
+ }
+
+ for (n = 0 ; n < def->nnets ; n++) {
+ virDomainNetDefPtr net = def->nets[n];
+ if (net->info.bootIndex > i + 1)
+ net->info.bootIndex -= 1;
+ }
+
+ for (n = 0 ; n < def->nhostdevs ; n++) {
+ virDomainHostdevDefPtr hostdev = def->hostdevs[n];
+ if (hostdev->info->bootIndex > i + 1)
+ hostdev->info->bootIndex -= 1;
+ }
+
+ for (n = 0 ; n < def->nredirdevs ; n++) {
+ virDomainRedirdevDefPtr redirdev = def->redirdevs[n];
+ if (redirdev->info.bootIndex > i + 1)
+ redirdev->info.bootIndex -= 1;
+ }
+ }
+
+ return 0;
+}
+
int
qemuDomainCheckDiskPresence(virQEMUDriverPtr driver,
virDomainObjPtr vm,
bool cold_boot)
{
int ret = -1;
- int i;
+ size_t i;
virDomainDiskDefPtr disk;
char uuid[VIR_UUID_STRING_BUFLEN];
virDomainEventPtr event = NULL;
+ virDomainDefPtr def = vm->def;
+ size_t count = def->ndisks;
+ unsigned long bootMapSize = def->os.nBootPerDevs;
+ size_t nextDisk = 0;
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+ virBitmapPtr bitmap = NULL;
+
+ virUUIDFormat(def->uuid, uuid);
- virUUIDFormat(vm->def->uuid, uuid);
+ if (bootMapSize) {
+ if (!(bitmap = virBitmapNew(bootMapSize))) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ }
- for (i = 0; i < vm->def->ndisks; i++) {
- disk = vm->def->disks[i];
+ for (i = 0; i < count; i++) {
+ disk = def->disks[nextDisk];
- if (!disk->startupPolicy || !disk->src)
+ if (!disk->startupPolicy || !disk->src) {
+ nextDisk++;
continue;
+ }
if (virFileAccessibleAs(disk->src, F_OK,
cfg->user,
cfg->group) >= 0) {
/* disk accessible */
+ nextDisk++;
continue;
}
@@ -1846,20 +1905,37 @@ qemuDomainCheckDiskPresence(virQEMUDriverPtr driver,
VIR_DEBUG("Dropping disk '%s' on domain '%s' (UUID
'%s') "
"due to inaccessible source '%s'",
- disk->dst, vm->def->name, uuid, disk->src);
+ disk->dst, def->name, uuid, disk->src);
event = virDomainEventDiskChangeNewFromObj(vm, disk->src, NULL,
disk->info.alias,
VIR_DOMAIN_EVENT_DISK_CHANGE_MISSING_ON_START);
if (event)
qemuDomainEventQueue(driver, event);
- VIR_FREE(disk->src);
+ /* For CDROM and Floppy disk, only drop source path.
+ * For Hard disk, drop its definition.
+ */
+ if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM ||
+ disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
+ VIR_FREE(disk->src);
+ nextDisk++;
+ } else {
+ if (bitmap && disk->info.bootIndex)
+ ignore_value(virBitmapSetBit(bitmap, disk->info.bootIndex - 1));
+
+ virDomainDiskDefFree(disk);
+ if (VIR_DELETE_ELEMENT(def->disks, nextDisk, def->ndisks) < 0)
+ goto cleanup;
+ }
}
+ qemuDomainPerDevicesBootReorder(def, bitmap);
+
ret = 0;
cleanup:
virObjectUnref(cfg);
+ virBitmapFree(bitmap);
return ret;
}
--
1.7.11.2