Alinear el final de las particiones "resto-del-disco" a MiB

parted marca como misaligned las particiones cuyo final no cae en la rejilla
de 1 MiB. En la VM los discos miden GiB exactos y el final encaja; en hardware
real el tamano no es multiplo de MiB (p.ej. 250_059_350_016 B), asi que
terminar en total-1MiB dejaba la particion fuera de rejilla.

usable_end() redondea el final hacia abajo a MiB (se pierden <2 MiB). Aplica a
/ (btrfs) y a /home. Los starts ya estaban en rejilla. Cubre cualquier sector
size. Anade casos al --selftest.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-26 21:45:42 +02:00
co-authored by Claude Opus 4.8
parent 72a8f4a3b9
commit 45dd2e34e2
+15 -2
View File
@@ -33,6 +33,13 @@ except ImportError:
MiB = 1024 ** 2 MiB = 1024 ** 2
END_MARGIN = MiB # deja 1 MiB al final para la cabecera GPT de respaldo END_MARGIN = MiB # deja 1 MiB al final para la cabecera GPT de respaldo
def usable_end(total):
# Final alineado a la rejilla de 1 MiB. Los discos reales tienen tamanos que
# no son multiplo de MiB (p.ej. 250_059_350_016 B), asi que terminar en
# total-END_MARGIN deja la particion fuera de rejilla y parted la marca como
# "misaligned". Redondeamos el final hacia abajo a MiB (se pierden <2 MiB).
return ((int(total) - END_MARGIN) // MiB) * MiB
def part(status, ptype, start_b, len_b, ss, fs=None, mnt=None, flags=()): def part(status, ptype, start_b, len_b, ss, fs=None, mnt=None, flags=()):
return PartitionModification( return PartitionModification(
status=status, type=ptype, status=status, type=ptype,
@@ -48,7 +55,7 @@ def nvme_mods(dev):
esp_start, esp_len = 1 * MiB, 511 * MiB # 1 -> 512 MiB esp_start, esp_len = 1 * MiB, 511 * MiB # 1 -> 512 MiB
boot_start, boot_len = 512 * MiB, 1024 * MiB # 512 -> 1536 MiB boot_start, boot_len = 512 * MiB, 1024 * MiB # 512 -> 1536 MiB
root_start = boot_start + boot_len # 1536 MiB root_start = boot_start + boot_len # 1536 MiB
root_len = total - root_start - END_MARGIN root_len = usable_end(total) - root_start
return DeviceModification(device=dev, wipe=True, partitions=[ return DeviceModification(device=dev, wipe=True, partitions=[
part(ModificationStatus.CREATE, PartitionType.PRIMARY, esp_start, esp_len, ss, part(ModificationStatus.CREATE, PartitionType.PRIMARY, esp_start, esp_len, ss,
FilesystemType.FAT32, "/boot/efi", (PartitionFlag.BOOT, PartitionFlag.ESP)), FilesystemType.FAT32, "/boot/efi", (PartitionFlag.BOOT, PartitionFlag.ESP)),
@@ -64,7 +71,7 @@ def sda_mods(dev):
start = 1 * MiB start = 1 * MiB
return DeviceModification(device=dev, wipe=True, partitions=[ return DeviceModification(device=dev, wipe=True, partitions=[
part(ModificationStatus.CREATE, PartitionType.PRIMARY, start, part(ModificationStatus.CREATE, PartitionType.PRIMARY, start,
total - start - END_MARGIN, ss, FilesystemType.EXT4, "/home"), usable_end(total) - start, ss, FilesystemType.EXT4, "/home"),
]) ])
def pick_fixed(lsblk_out): def pick_fixed(lsblk_out):
@@ -119,6 +126,12 @@ def _selftest():
assert pick_fixed(two) == ["/dev/nvme0n1", "/dev/sda"], pick_fixed(two) assert pick_fixed(two) == ["/dev/nvme0n1", "/dev/sda"], pick_fixed(two)
# solo USB conectado -> sin discos fijos (main aborta) # solo USB conectado -> sin discos fijos (main aborta)
assert pick_fixed("sdb 1 disk\nsr0 1 rom") == [] assert pick_fixed("sdb 1 disk\nsr0 1 rom") == []
# final alineado: disco "feo" -> end multiplo de MiB, dentro del disco
real = 250_059_350_016 # SSD 250G tipico, no multiplo de MiB
e = usable_end(real)
assert e % MiB == 0 and 0 < e <= real - END_MARGIN, e
# disco MiB-exacto (VM 40G) -> pierde justo END_MARGIN, nada mas
assert usable_end(40 * 1024 * MiB) == 40 * 1024 * MiB - MiB
print("ok") print("ok")
if __name__ == "__main__": if __name__ == "__main__":