[libvirt] [PATCH v2 3/4] qemu: drop disk definition if missing and reorder per-device boot sequence

Guannan Ren gren at redhat.com
Tue Mar 19 13:55:15 UTC 2013


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




More information about the libvir-list mailing list