[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH 5/5] create storage volumes, take 2



Here is a updated patch that defines a enum for mapping parition code to parted's fs-type.

/Henrik
--- libvirt-0.6.4.patches/src/storage_conf.h	2009-06-23 18:05:39.054877000 +0200
+++ libvirt-0.6.4/src/storage_conf.h	2009-06-25 18:24:46.374696000 +0200
@@ -460,4 +460,22 @@ enum virStorageVolTypeDisk {
     VIR_STORAGE_VOL_DISK_TYPE_LAST,
 };
 
+/*
+ * Mapping of Parted fs-types
+ * MUST be kept in the same order
+ * as virStorageVolFormatDisk
+ */
+enum virStoragePartedFsType {
+    VIR_STORAGE_PARTED_FS_TYPE_NONE = 0,
+    VIR_STORAGE_PARTED_FS_TYPE_LINUX,
+    VIR_STORAGE_PARTED_FS_TYPE_FAT16,
+    VIR_STORAGE_PARTED_FS_TYPE_FAT32,
+    VIR_STORAGE_PARTED_FS_TYPE_LINUX_SWAP,
+    VIR_STORAGE_PARTED_FS_TYPE_LINUX_LVM,
+    VIR_STORAGE_PARTED_FS_TYPE_LINUX_RAID,
+    VIR_STORAGE_PARTED_FS_TYPE_EXTENDED,
+    VIR_STORAGE_PARTED_FS_TYPE_LAST,
+};
+VIR_ENUM_DECL(virStoragePartedFsType)
+
 #endif /* __VIR_STORAGE_CONF_H__ */
--- libvirt-0.6.4.patches/src/storage_conf.c	2009-06-23 13:07:20.684649000 +0200
+++ libvirt-0.6.4/src/storage_conf.c	2009-06-25 18:22:46.136945000 +0200
@@ -93,6 +93,12 @@ VIR_ENUM_IMPL(virStorageVolFormatFileSys
               "cloop", "cow", "dmg", "iso",
               "qcow", "qcow2", "vmdk", "vpc")
 
+VIR_ENUM_IMPL(virStoragePartedFsType,
+              VIR_STORAGE_PARTED_FS_TYPE_LAST,
+              "none", "ext2", "fat16",
+              "fat32", "linux-swap",
+              "ext2", "ext2",
+              "extended")
 
 typedef const char *(*virStorageVolFormatToString)(int format);
 typedef int (*virStorageVolFormatFromString)(const char *format);
--- libvirt-0.6.4.patches/src/libvirt_private.syms	2009-06-23 13:07:38.206045000 +0200
+++ libvirt-0.6.4/src/libvirt_private.syms	2009-06-26 12:06:30.517758000 +0200
@@ -287,6 +287,7 @@ virStoragePoolFormatFileSystemNetTypeToS
 virStorageVolFormatFileSystemTypeToString;
 virStorageVolFormatFileSystemTypeFromString;
 virStoragePoolTypeFromString;
+virStoragePartedFsTypeTypeToString;
 virStoragePoolObjLock;
 virStoragePoolObjUnlock;
 
--- 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-26 12:44:42.478755000 +0200
@@ -382,46 +382,218 @@ virStorageBackendDiskBuildPool(virConnec
     return 0;
 }
 
+/**
+ * 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) {
+        const char *partedFormat = virStoragePartedFsTypeTypeToString(vol->target.format);
+        if(partedFormat == NULL) {
+           virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                 "%s", _("Invalid partition type"));
+           return -1;
+        }
+        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;
+                 }
+            }
+            sprintf(partFormat, "%s", partedFormat);
+        } 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:
+                         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) {
+                                  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 +603,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;

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]