This patch does the last magic to be able to create storage volumes when using 
a disk as backend
--- libvirt-0.6.4.patches/src/storage_backend_disk.c	2009-06-23 18:17:30.885038000 +0200
+++ libvirt-0.6.4/src/storage_backend_disk.c	2009-06-24 10:08:23.499326000 +0200
@@ -381,47 +381,246 @@ virStorageBackendDiskBuildPool(virConnec
 
     return 0;
 }
+/**
+ * Maps internal libvirt volume disk format to parted fs_type
+ */
+static void
+virStorageBackendDiskVolFormatToPartedFormat(int volFormat, char* partedFormat)
+{
+    switch (volFormat) {
+        case VIR_STORAGE_VOL_DISK_LINUX:
+        case VIR_STORAGE_VOL_DISK_LINUX_LVM:
+        case VIR_STORAGE_VOL_DISK_LINUX_RAID:
+            /* lvm and raid is set by flags */
+            sprintf(partedFormat, "ext2");
+            break;
+        case VIR_STORAGE_VOL_DISK_FAT16:
+            sprintf(partedFormat, "fat16");
+            break;
+        case VIR_STORAGE_VOL_DISK_FAT32:
+            sprintf(partedFormat, "fat32");
+            break;
+        case VIR_STORAGE_VOL_DISK_LINUX_SWAP:
+            sprintf(partedFormat, "linux-swap");
+            break;
+        case VIR_STORAGE_VOL_DISK_EXTENDED:
+            sprintf(partedFormat, "extended");
+            break;
+        default:
+            break;
+        }
+}
 
+/**
+ * Decides what kind of partition type that should be created.
+ * Important when the partition table is of msdos type
+ */
 static int
-virStorageBackendDiskCreateVol(virConnectPtr conn,
-                               virStoragePoolObjPtr pool,
-                               virStorageVolDefPtr vol)
+virStorageBackendDiskPartTypeToCreate(virStoragePoolObjPtr pool)
+{
+    if (pool->def->source.format == VIR_STORAGE_POOL_DISK_DOS) {
+        /* count primary and extended paritions,
+           can't be more than 3 to create a new primary partition */
+        int i;
+        int count = 0;
+        for (i = 0; i < pool->volumes.count; i++) {
+             if (pool->volumes.objs[i]->target.type == VIR_STORAGE_VOL_DISK_TYPE_PRIMARY ||
+                 pool->volumes.objs[i]->target.type == VIR_STORAGE_VOL_DISK_TYPE_EXTENDED) {
+                     count++;
+             }
+        }
+        if (count >= 4) {
+            return VIR_STORAGE_VOL_DISK_TYPE_LOGICAL;
+        }
+    }
+
+    /* for all other cases, all partitions are primary */
+    return VIR_STORAGE_VOL_DISK_TYPE_PRIMARY;
+}
+
+static int
+virStorageBackendDiskPartFormat(virConnectPtr conn, virStoragePoolObjPtr pool,
+                                virStorageVolDefPtr vol,
+                                char* partFormat)
+{
+    int i;
+    if (pool->def->source.format == VIR_STORAGE_POOL_DISK_DOS) {
+        char partedFormat[50];
+        if (vol->target.format == VIR_STORAGE_VOL_DISK_EXTENDED) {
+            /* make sure we don't have a extended partition already */
+            for (i = 0; i < pool->volumes.count; i++) {
+                 if (pool->volumes.objs[i]->target.format == VIR_STORAGE_VOL_DISK_EXTENDED) {
+                     virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                           "%s", _("extended partition already exists"));
+                     return -1;
+                 }
+            }
+            virStorageBackendDiskVolFormatToPartedFormat(vol->target.format, partFormat);
+
+        } else {
+            /* create primary partition as long as it is possible
+               and after that check if an extended partition exists
+               to create logical partitions. */
+            /* XXX Only support one extended partition */
+            switch (virStorageBackendDiskPartTypeToCreate(pool)) {
+                    case VIR_STORAGE_VOL_DISK_TYPE_PRIMARY:
+                         virStorageBackendDiskVolFormatToPartedFormat(vol->target.format, partedFormat);
+                         sprintf(partFormat, "primary %s", partedFormat);
+                         break;
+                    case VIR_STORAGE_VOL_DISK_TYPE_LOGICAL:
+                         /* make sure we have a extended partition */
+                         for (i = 0; i < pool->volumes.count; i++) {
+                              if (pool->volumes.objs[i]->target.format == VIR_STORAGE_VOL_DISK_EXTENDED) {
+                                  virStorageBackendDiskVolFormatToPartedFormat(vol->target.format, partedFormat);
+                                  sprintf(partFormat, "logical %s", partedFormat);
+                                  break;
+                              }
+                         }
+                         if (i == pool->volumes.count) {
+                             virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                                   "%s", _("no extended partition found and no primary partition available"));
+                             return -1;
+                         }
+                         break;
+                    default:
+                         break;
+            }
+        }
+    } else {
+        sprintf(partFormat, "primary");
+    }
+    return 0;
+}
+
+/**
+ * Aligns a new partition to nearest cylinder boundry
+ * when haveing a msdos partition table type 
+ * to avoid any problem with all ready existing
+ * partitions
+ */
+static int
+virStorageBackendDiskPartBoundries(virConnectPtr conn, 
+                                   virStoragePoolObjPtr pool,
+                                   unsigned long long *start, 
+                                   unsigned long long *end, 
+                                   unsigned long long allocation)
 {
     int i;
-    char start[100], end[100];
-    unsigned long long startOffset, endOffset, smallestSize = 0;
     int smallestExtent = -1;
+    unsigned long long smallestSize = 0;
+    unsigned long long extraBytes = 0;
+    unsigned long long alignedAllocation = allocation;
     virStoragePoolSourceDevicePtr dev = &pool->def->source.devices[0];
-    /* XXX customizable partition types */
+    unsigned long long cylinderSize = dev->geometry.heads * 
+                                      dev->geometry.sectors * SECTOR_SIZE;
+
+    DEBUG("find free area: allocation %llu,  cyl size %llu\n", allocation, cylinderSize);
+    int partType = virStorageBackendDiskPartTypeToCreate(pool);
+
+    /* how many extra bytes we have since we allocate 
+       aligned to the cylinder boundry */
+    extraBytes = cylinderSize - (allocation % cylinderSize);
+
+    for (i = 0 ; i < dev->nfreeExtent ; i++) {
+         unsigned long long size =
+             dev->freeExtents[i].end -
+             dev->freeExtents[i].start;
+         unsigned long long neededSize = allocation;
+
+         if (pool->def->source.format == VIR_STORAGE_POOL_DISK_DOS) {
+             /* align to cylinder boundry */
+             neededSize += extraBytes;
+             if ((*start % cylinderSize) > extraBytes) {
+                 /* add an extra cylinder if the offset can't fit within
+                    the extra bytes we have */
+                 neededSize += cylinderSize;
+             }
+             /* if we are creating a logical patition, we need one extra
+                block between partitions (or actually move start one block) */
+             if (partType == VIR_STORAGE_VOL_DISK_TYPE_LOGICAL) {
+                 size -= SECTOR_SIZE;
+             }
+         }
+         if (size > neededSize &&
+             (smallestSize == 0 ||
+             size < smallestSize)) {
+             /* for logical partition, the free extent
+                must be within a logical free area */
+             if (partType == VIR_STORAGE_VOL_DISK_TYPE_LOGICAL &&
+                 dev->freeExtents[i].type != VIR_STORAGE_FREE_LOGICAL) {
+                 continue;
+                 /* for primary partition, the free extent
+                    must not be within a logical free area */
+             } else if(partType == VIR_STORAGE_VOL_DISK_TYPE_PRIMARY &&
+                       dev->freeExtents[i].type != VIR_STORAGE_FREE_NORMAL) {
+                       continue;
+             }
+             smallestSize = size;
+             smallestExtent = i;
+             alignedAllocation = neededSize;
+         }
+    }
+
+    if (smallestExtent == -1) {
+        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                              "%s", _("no large enough free extent"));
+        return -1;
+    }
+
+    DEBUG("aligned alloc %llu\n", alignedAllocation);
+    *start = dev->freeExtents[smallestExtent].start;
+
+    if (partType == VIR_STORAGE_VOL_DISK_TYPE_LOGICAL) {
+        /* for logical partition, skip one block */
+        *start += SECTOR_SIZE;
+    }
+
+    *end = *start + alignedAllocation;
+    if (pool->def->source.format == VIR_STORAGE_POOL_DISK_DOS) {
+        /* adjust our allocation if start is not at a cylinder boundry */
+        *end -= (*start % cylinderSize);
+    }
+
+    /* counting in byte, we want the last byte of the current sector */
+    *end -= 1;
+    DEBUG("final aligned start %llu, end %llu\n", *start, *end);
+    return 0;
+}
+
+
+static int
+virStorageBackendDiskCreateVol(virConnectPtr conn,
+                               virStoragePoolObjPtr pool,
+                               virStorageVolDefPtr vol)
+{
+    char start[100], end[100], partFormat[100];
+    unsigned long long startOffset = 0, endOffset = 0;
     const char *cmdargv[] = {
         PARTED,
         pool->def->source.devices[0].path,
         "mkpart",
         "--script",
-        "ext2",
+        partFormat,
         start,
         end,
         NULL
     };
 
-    for (i = 0 ; i < dev->nfreeExtent ; i++) {
-        unsigned long long size =
-            dev->freeExtents[i].end -
-            dev->freeExtents[i].start;
-        if (size > vol->allocation &&
-            (smallestSize == 0 ||
-             size < smallestSize)) {
-            smallestSize = size;
-            smallestExtent = i;
+    if (virStorageBackendDiskPartFormat(conn, pool, vol, partFormat) != 0) {
+        return -1;
+    }
+
+    if (vol->key == NULL) {
+        /* XXX base off a unique key of the underlying disk */
+        if ((vol->key = strdup(vol->target.path)) == NULL) {
+            virReportOOMError(conn);
+            return -1;
         }
     }
-    if (smallestExtent == -1) {
-        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
-                              "%s", _("no large enough free extent"));
-        return -1;
+
+    if(virStorageBackendDiskPartBoundries(conn, pool, &startOffset, &endOffset, vol->allocation) != 0) {
+       return -1;
     }
-    startOffset = dev->freeExtents[smallestExtent].start;
-    endOffset = startOffset + vol->allocation;
 
     snprintf(start, sizeof(start)-1, "%lluB", startOffset);
     start[sizeof(start)-1] = '\0';
@@ -431,6 +630,9 @@ virStorageBackendDiskCreateVol(virConnec
     if (virRun(conn, cmdargv, NULL) < 0)
         return -1;
 
+    /* wait for device node to show up */
+    virStorageBackendWaitForDevices(conn);
+
     /* Blow away free extent info, as we're about to re-populate it */
     VIR_FREE(pool->def->source.devices[0].freeExtents);
     pool->def->source.devices[0].nfreeExtent = 0;
--
Libvir-list mailing list
Libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Reply via email to