Resolves: rhbz#1181494 --- blivet/partitioning.py | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-)
diff --git a/blivet/partitioning.py b/blivet/partitioning.py index 9fd1819..5df0485 100644 --- a/blivet/partitioning.py +++ b/blivet/partitioning.py @@ -962,6 +962,12 @@ def doPartitioning(storage): % {"format": part.format.name, "minSize": part.format.minSize, "maxSize": part.format.maxSize})
+def align_size_for_disklabel(size, disklabel): + # Align the base size to the disk's grain size. + grain_size = Size(disklabel.alignment.grainSize) + grains, rem = divmod(size, grain_size) + return (grains * grain_size) + (grain_size if rem else Size(0)) + def allocatePartitions(storage, disks, partitions, freespace): """ Allocate partitions based on requested features.
@@ -1053,6 +1059,16 @@ def allocatePartitions(storage, disks, partitions, freespace):
log.debug("checking freespace on %s", _disk.name)
+ if _part.req_start_sector is None: + req_size = align_size_for_disklabel(_part.req_size, disklabel) + else: + # don't align size if start sector was specified + req_size = _part.req_size + + if req_size != _part.req_size: + log.debug("size %s rounded up to %s for disk %s", + _part.req_size, req_size, _disk.name) + new_part_type = getNextPartitionType(disklabel.partedDisk) if new_part_type is None: # can't allocate any more partitions on this disk @@ -1075,7 +1091,7 @@ def allocatePartitions(storage, disks, partitions, freespace):
best = getBestFreeSpaceRegion(disklabel.partedDisk, new_part_type, - _part.req_size, + req_size, start=_part.req_start_sector, best_free=current_free, boot=boot, @@ -1090,7 +1106,7 @@ def allocatePartitions(storage, disks, partitions, freespace): if new_part_type: best = getBestFreeSpaceRegion(disklabel.partedDisk, new_part_type, - _part.req_size, + req_size, start=_part.req_start_sector, best_free=current_free, boot=boot, @@ -1127,7 +1143,7 @@ def allocatePartitions(storage, disks, partitions, freespace):
_free = getBestFreeSpaceRegion(disklabel.partedDisk, _part_type, - _part.req_size, + req_size, start=_part.req_start_sector, boot=boot, grow=_part.req_grow) @@ -1144,7 +1160,7 @@ def allocatePartitions(storage, disks, partitions, freespace): temp_part = addPartition(disklabel, _free, _part_type, - _part.req_size, + req_size, _part.req_start_sector, _part.req_end_sector) except ArithmeticError as e: @@ -1226,6 +1242,11 @@ def allocatePartitions(storage, disks, partitions, freespace):
_disk = use_disk disklabel = _disk.format + if _part.req_start_sector is None: + aligned_size = align_size_for_disklabel(_part.req_size, disklabel) + else: + # not aligned + aligned_size = _part.req_size
# create the extended partition if needed if part_type == parted.PARTITION_EXTENDED and \ @@ -1240,7 +1261,7 @@ def allocatePartitions(storage, disks, partitions, freespace): log.debug("recalculating free space") free = getBestFreeSpaceRegion(disklabel.partedDisk, part_type, - _part.req_size, + aligned_size, start=_part.req_start_sector, boot=boot, grow=_part.req_grow) @@ -1248,7 +1269,7 @@ def allocatePartitions(storage, disks, partitions, freespace): 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, aligned_size, _part.req_start_sector, _part.req_end_sector) log.debug("created partition %s of %s and added it to %s", partition.getDeviceNodeName(),
By aligning the start sector of free regions we improve our ability to select an appropriate free region in which to place a new partition. When the start sector alignment is not taken into consideration the possibility arises that aligning the start sector will shrink the size of the free region below the requested size of the partition.
Related: rhbz#1181494 --- blivet/partitioning.py | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-)
diff --git a/blivet/partitioning.py b/blivet/partitioning.py index 5df0485..665d1a0 100644 --- a/blivet/partitioning.py +++ b/blivet/partitioning.py @@ -572,7 +572,8 @@ def getNextPartitionType(disk, no_primary=None): return part_type
def getBestFreeSpaceRegion(disk, part_type, req_size, start=None, - boot=None, best_free=None, grow=None): + boot=None, best_free=None, grow=None, + alignment=None): """ Return the "best" free region on the specified disk.
For non-boot partitions, we return the largest free region on the @@ -601,6 +602,8 @@ def getBestFreeSpaceRegion(disk, part_type, req_size, start=None, :type best_free: :class:`parted.Geometry` :keyword grow: indicates whether this is a growable request :type grow: bool + :keyword alignment: disk alignment requirements + :type alignment: :class:`parted.Alignment`
""" log.debug("getBestFreeSpaceRegion: disk=%s part_type=%d req_size=%s " @@ -608,8 +611,32 @@ def getBestFreeSpaceRegion(disk, part_type, req_size, start=None, disk.device.path, part_type, req_size, boot, best_free, grow, start) extended = disk.getExtendedPartition() + alignment = alignment or parted.Alignment(offset=0, grainSize=1)
for free_geom in disk.getFreeSpaceRegions(): + # align the start sector of the free region since we will be aligning + # the start sector of the partition + if start is not None and \ + not alignment.isAligned(free_geom, free_geom.start): + log.debug("aligning start sector of region %d-%d", free_geom.start, + free_geom.end) + try: + aligned_start = alignment.alignUp(free_geom, free_geom.start) + except ArithmeticError: + aligned_start = None + else: + # parted tends to align down when it cannot align up + if aligned_start < free_geom.start: + aligned_start = None + + if aligned_start is None: + log.debug("failed to align start sector -- skipping region") + continue + + free_geom = parted.Geometry(device=free_geom.device, + start=aligned_start, + end=free_geom.end) + log.debug("checking %d-%d (%s)", free_geom.start, free_geom.end, Size(free_geom.getLength(unit="B"))) if start is not None and not free_geom.containsSector(start): @@ -1095,7 +1122,8 @@ def allocatePartitions(storage, disks, partitions, freespace): start=_part.req_start_sector, best_free=current_free, boot=boot, - grow=_part.req_grow) + grow=_part.req_grow, + alignment=disklabel.alignment)
if best == free and not _part.req_primary and \ new_part_type == parted.PARTITION_NORMAL: @@ -1110,7 +1138,8 @@ def allocatePartitions(storage, disks, partitions, freespace): start=_part.req_start_sector, best_free=current_free, boot=boot, - grow=_part.req_grow) + grow=_part.req_grow, + alignment=disklabel.alignment)
if best and free != best: update = True @@ -1146,7 +1175,8 @@ def allocatePartitions(storage, disks, partitions, freespace): req_size, start=_part.req_start_sector, boot=boot, - grow=_part.req_grow) + grow=_part.req_grow, + alignment=disklabel.alignment) if not _free: log.info("not enough space after adding " "extended partition for growth test") @@ -1264,7 +1294,8 @@ def allocatePartitions(storage, disks, partitions, freespace): aligned_size, start=_part.req_start_sector, boot=boot, - grow=_part.req_grow) + grow=_part.req_grow, + alignment=disklabel.alignment) if not free: raise PartitioningError(_("not enough free space after " "creating extended partition"))
anaconda-patches@lists.fedorahosted.org