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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list