[PATCH 2/4] Add support for explicit start/end sectors in partition requests. (#881025)

David Lehman dlehman at redhat.com
Thu Jul 18 14:13:45 UTC 2013


---
 blivet/devices.py      |  24 ++++++++--
 blivet/partitioning.py | 121 +++++++++++++++++++++++++++----------------------
 2 files changed, 87 insertions(+), 58 deletions(-)

diff --git a/blivet/devices.py b/blivet/devices.py
index cae4b6a..5b6b3df 100644
--- a/blivet/devices.py
+++ b/blivet/devices.py
@@ -1093,7 +1093,7 @@ class PartitionDevice(StorageDevice):
     defaultSize = 500
 
     def __init__(self, name, format=None,
-                 size=None, grow=False, maxsize=None,
+                 size=None, grow=False, maxsize=None, start=None, end=None,
                  major=None, minor=None, bootable=None,
                  sysfsPath='', parents=None, exists=False,
                  partType=None, primary=False, weight=0):
@@ -1121,9 +1121,14 @@ class PartitionDevice(StorageDevice):
                     grow -- whether or not to grow the partition
                     maxsize -- max size for growable partitions (in MB)
                     size -- the device's size (in MB)
+                    start -- start sector (see note, below)
+                    end -- end sector (see note, below)
                     bootable -- whether the partition is bootable
                     parents -- a list of potential containing disks
                     weight -- an initial sorting weight to assign
+
+            NOTE: If start/end sectors are specified they will not be adjusted
+                  for optimal alignment. It is up to the caller to do that.
         """
         self.req_disks = []
         self.req_partType = None
@@ -1134,6 +1139,8 @@ class PartitionDevice(StorageDevice):
         self.req_base_size = 0
         self.req_max_size = 0
         self.req_base_weight = 0
+        self.req_start_sector = None
+        self.req_end_sector = None
 
         self._bootable = False
 
@@ -1182,8 +1189,12 @@ class PartitionDevice(StorageDevice):
             #     PartitionRequest class and pass one to this constructor
             #     for new partitions.
             if not self._size:
-                # default size for new partition requests
-                self._size = self.defaultSize
+                if start is not None and end is not None:
+                    self._size = 0
+                else:
+                    # default size for new partition requests
+                    self._size = self.defaultSize
+
             self.req_name = name
             self.req_partType = partType
             self.req_primary = primary
@@ -1199,15 +1210,20 @@ class PartitionDevice(StorageDevice):
 
             self.req_base_weight = weight
 
+            self.req_start_sector = start
+            self.req_end_sector = end
+
     def __repr__(self):
         s = StorageDevice.__repr__(self)
         s += ("  grow = %(grow)s  max size = %(maxsize)s  bootable = %(bootable)s\n"
-              "  part type = %(partType)s  primary = %(primary)s\n"
+              "  part type = %(partType)s  primary = %(primary)s"
+              "  start sector = %(start)s  end sector = %(end)s\n"
               "  partedPartition = %(partedPart)s\n"
               "  disk = %(disk)s\n" %
               {"grow": self.req_grow, "maxsize": self.req_max_size,
                "bootable": self.bootable, "partType": self.partType,
                "primary": self.req_primary,
+               "start": self.req_start_sector, "end": self.req_end_sector,
                "partedPart": self.partedPartition, "disk": self.disk})
 
         if self.partedPartition:
diff --git a/blivet/partitioning.py b/blivet/partitioning.py
index d703d9e..a72c556 100644
--- a/blivet/partitioning.py
+++ b/blivet/partitioning.py
@@ -342,6 +342,16 @@ def partitionCompare(part1, part2):
     """
     ret = 0
 
+    # start sector overrides all other sorting factors
+    part1_start = part1.req_start_sector
+    part2_start = part2.req_start_sector
+    if part1_start is not None and part2_start is None:
+        return -1
+    elif part1_start is None and part2_start is not None:
+        return 1
+    elif part1_start is not None and part2_start is not None:
+        return cmp(part1_start, part2_start)
+
     if part1.req_base_weight:
         ret -= part1.req_base_weight
 
@@ -445,7 +455,7 @@ def getNextPartitionType(disk, no_primary=None):
 
     return part_type
 
-def getBestFreeSpaceRegion(disk, part_type, req_size,
+def getBestFreeSpaceRegion(disk, part_type, req_size, start=None,
                            boot=None, best_free=None, grow=None):
     """ Return the "best" free region on the specified disk.
 
@@ -474,40 +484,29 @@ def getBestFreeSpaceRegion(disk, part_type, req_size,
                     (boolean)
             best_free -- current best free region for this partition
             grow -- indicates whether this is a growable request
+            start -- requested start sector for the partition
 
     """
     log.debug("getBestFreeSpaceRegion: disk=%s part_type=%d req_size=%dMB "
-              "boot=%s best=%s grow=%s" %
-              (disk.device.path, part_type, req_size, boot, best_free, grow))
+              "boot=%s best=%s grow=%s start=%s" %
+              (disk.device.path, part_type, req_size, boot, best_free, grow,
+               start))
     extended = disk.getExtendedPartition()
 
-    for _range in disk.getFreeSpaceRegions():
+    for free_geom in disk.getFreeSpaceRegions():
+        log.debug("checking %d-%d (%d MB)" % (free_geom.start, free_geom.end,
+                                              free_geom.getSize()))
+        if start is not None and not free_geom.containsSector(start):
+            log.debug("free region does not contain requested start sector")
+            continue
+
         if extended:
-            # find out if there is any overlap between this region and the
-            # extended partition
-            log.debug("looking for intersection between extended (%d-%d) and free (%d-%d)" %
-                    (extended.geometry.start, extended.geometry.end, _range.start, _range.end))
-
-            # parted.Geometry.overlapsWith can handle this
-            try:
-                free_geom = extended.geometry.intersect(_range)
-            except ArithmeticError:
-                # this freespace region does not lie within the extended
-                # partition's geometry
-                free_geom = None
-
-            if (free_geom and part_type == parted.PARTITION_NORMAL) or \
-               (not free_geom and part_type == parted.PARTITION_LOGICAL):
+            in_extended = extended.geometry.contains(free_geom)
+            if ((in_extended and part_type == parted.PARTITION_NORMAL) or
+                (not in_extended and part_type == parted.PARTITION_LOGICAL)):
                 log.debug("free region not suitable for request")
                 continue
 
-            if part_type == parted.PARTITION_NORMAL:
-                # we're allocating a primary and the region is not within
-                # the extended, so we use the original region
-                free_geom = _range
-        else:
-            free_geom = _range
-
         if free_geom.start > disk.maxPartitionStartSector:
             log.debug("free range start sector beyond max for new partitions")
             continue
@@ -599,7 +598,7 @@ def removeNewPartitions(disks, partitions):
             log.debug("removing empty extended partition from %s" % disk.name)
             disk.format.partedDisk.removePartition(extended)
 
-def addPartition(disklabel, free, part_type, size):
+def addPartition(disklabel, free, part_type, size, start=None, end=None):
     """ Return new partition after adding it to the specified disk.
 
         Arguments:
@@ -609,38 +608,44 @@ def addPartition(disklabel, free, part_type, size):
             part_type -- partition type (parted.PARTITION_* constant)
             size -- size (in MB) of the new partition
 
-        The new partition will be aligned.
+        The new partition will be aligned unless start/end sectors are provided.
 
         Return value is a parted.Partition instance.
 
     """
-    start = free.start
-    if not disklabel.alignment.isAligned(free, start):
-        start = disklabel.alignment.alignNearest(free, start)
+    if start is not None:
+        if end is None:
+            end = start + \
+                  sizeToSectors(size, disklabel.partedDevice.sectorSize) - 1
+    else:
+        start = free.start
 
-    if disklabel.labelType == "sun" and start == 0:
-        start = disklabel.alignment.alignUp(free, start)
+        if not disklabel.alignment.isAligned(free, start):
+            start = disklabel.alignment.alignNearest(free, start)
 
-    if part_type == parted.PARTITION_LOGICAL:
-        # make room for logical partition's metadata
-        start += disklabel.alignment.grainSize
+        if disklabel.labelType == "sun" and start == 0:
+            start = disklabel.alignment.alignUp(free, start)
 
-    if start != free.start:
-        log.debug("adjusted start sector from %d to %d" % (free.start, start))
+        if part_type == parted.PARTITION_LOGICAL:
+            # make room for logical partition's metadata
+            start += disklabel.alignment.grainSize
 
-    if part_type == parted.PARTITION_EXTENDED:
-        end = free.end
-        length = end - start + 1
-    else:
-        # size is in MB
-        length = sizeToSectors(size, disklabel.partedDevice.sectorSize)
-        end = start + length - 1
+        if start != free.start:
+            log.debug("adjusted start sector from %d to %d" % (free.start, start))
+
+        if part_type == parted.PARTITION_EXTENDED:
+            end = free.end
+            length = end - start + 1
+        else:
+            # size is in MB
+            length = sizeToSectors(size, disklabel.partedDevice.sectorSize)
+            end = start + length - 1
 
-    if not disklabel.endAlignment.isAligned(free, end):
-        end = disklabel.endAlignment.alignNearest(free, end)
-        log.debug("adjusted length from %d to %d" % (length, end - start + 1))
-        if start > end:
-            raise PartitioningError(_("unable to allocate aligned partition"))
+        if not disklabel.endAlignment.isAligned(free, end):
+            end = disklabel.endAlignment.alignNearest(free, end)
+            log.debug("adjusted length from %d to %d" % (length, end - start + 1))
+            if start > end:
+                raise PartitioningError(_("unable to allocate aligned partition"))
 
     new_geom = parted.Geometry(device=disklabel.partedDevice,
                                start=start,
@@ -869,11 +874,12 @@ def allocatePartitions(storage, disks, partitions, freespace):
 
         log.debug("allocating partition: %s ; id: %d ; disks: %s ;\n"
                   "boot: %s ; primary: %s ; size: %dMB ; grow: %s ; "
-                  "max_size: %s" % (_part.name, _part.id,
+                  "max_size: %s ; start: %s ; end: %s" % (_part.name, _part.id,
                                     [d.name for d in req_disks],
                                     boot, _part.req_primary,
                                     _part.req_size, _part.req_grow,
-                                    _part.req_max_size))
+                                    _part.req_max_size, _part.req_start_sector,
+                                    _part.req_end_sector))
         free = None
         use_disk = None
         part_type = None
@@ -914,6 +920,7 @@ def allocatePartitions(storage, disks, partitions, freespace):
             best = getBestFreeSpaceRegion(disklabel.partedDisk,
                                           new_part_type,
                                           _part.req_size,
+                                          start=_part.req_start_sector,
                                           best_free=current_free,
                                           boot=boot,
                                           grow=_part.req_grow)
@@ -928,6 +935,7 @@ def allocatePartitions(storage, disks, partitions, freespace):
                     best = getBestFreeSpaceRegion(disklabel.partedDisk,
                                                   new_part_type,
                                                   _part.req_size,
+                                                  start=_part.req_start_sector,
                                                   best_free=current_free,
                                                   boot=boot,
                                                   grow=_part.req_grow)
@@ -963,6 +971,7 @@ def allocatePartitions(storage, disks, partitions, freespace):
                                 _free = getBestFreeSpaceRegion(disklabel.partedDisk,
                                                                _part_type,
                                                                _part.req_size,
+                                                               start=_part.req_start_sector,
                                                                boot=boot,
                                                                grow=_part.req_grow)
                                 if not _free:
@@ -977,7 +986,9 @@ def allocatePartitions(storage, disks, partitions, freespace):
                             temp_part = addPartition(disklabel,
                                                      _free,
                                                      _part_type,
-                                                     _part.req_size)
+                                                     _part.req_size,
+                                                     _part.req_start_sector,
+                                                     _part.req_end_sector)
                             _part.partedPartition = temp_part
                             _part.disk = _disk
                             temp_parts.append(_part)
@@ -1067,13 +1078,15 @@ def allocatePartitions(storage, disks, partitions, freespace):
             free = getBestFreeSpaceRegion(disklabel.partedDisk,
                                           part_type,
                                           _part.req_size,
+                                          start=_part.req_start_sector,
                                           boot=boot,
                                           grow=_part.req_grow)
             if not free:
                 raise PartitioningError(_("not enough free space after "
                                         "creating extended partition"))
 
-        partition = addPartition(disklabel, free, part_type, _part.req_size)
+        partition = addPartition(disklabel, free, part_type, _part.req_size,
+                                 _part.req_start_sector, _part.req_end_sector)
         log.debug("created partition %s of %dMB and added it to %s" %
                 (partition.getDeviceNodeName(), partition.getSize(),
                  disklabel.device))
-- 
1.8.1.4



More information about the anaconda-patches mailing list