From 5adeefbeecf5fef8152202c528f11f59f2804741 Mon Sep 17 00:00:00 2001 From: Harald Sitter Date: Tue, 5 Nov 2024 21:10:06 +0100 Subject: [PATCH] rebuild the image with final sizes after shrinking the btrfs it will have dangling space at the end. we'll split the image into its partitions with actual filesystem sizes (i.e. the new btrfs size) and then re-assmble the image using the partitions as copyblocks. this gives us a tightly packed image --- build.sh | 3 +++ mkosi.repart-rebuild/00-esp.conf | 7 ++++++ mkosi.repart-rebuild/50-root.conf | 8 +++++++ mkosi.repart-rebuild/README.md | 9 +++++++ mkosi.repart/50-root.conf | 1 + part-rebuild.py | 40 +++++++++++++++++++++++++++++++ 6 files changed, 68 insertions(+) create mode 100644 mkosi.repart-rebuild/00-esp.conf create mode 100644 mkosi.repart-rebuild/50-root.conf create mode 100644 mkosi.repart-rebuild/README.md create mode 100755 part-rebuild.py diff --git a/build.sh b/build.sh index e6d5446..ef795b4 100755 --- a/build.sh +++ b/build.sh @@ -130,6 +130,9 @@ fi cp -v "${OUTPUT}_live.efi" "${OUTPUT}/efi-template/EFI/Linux/$EFI" systemd-repart --no-pager --empty=allow --size=auto --dry-run=no --root="${OUTPUT}" --definitions=mkosi.repart --defer-partitions=root "$IMG" +# Finally rebuild the actual image file with appropriate partition sizing. In particular with squeezed btrfs. +./part-rebuild.py "$IMG" + # TODO before accepting new uploads perform sanity checks on the artifacts (e.g. the tar being well formed) chmod go+r ./*.efi # efi images are 700, make them readable so the server can serve them ls -lah diff --git a/mkosi.repart-rebuild/00-esp.conf b/mkosi.repart-rebuild/00-esp.conf new file mode 100644 index 0000000..0015dd0 --- /dev/null +++ b/mkosi.repart-rebuild/00-esp.conf @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL +# SPDX-FileCopyrightText: 2023 Harald Sitter + +[Partition] +Type=esp +SplitName=esp +CopyBlocks=/esp.raw diff --git a/mkosi.repart-rebuild/50-root.conf b/mkosi.repart-rebuild/50-root.conf new file mode 100644 index 0000000..ac439c8 --- /dev/null +++ b/mkosi.repart-rebuild/50-root.conf @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL +# SPDX-FileCopyrightText: 2023 Harald Sitter + +[Partition] +Type=root +Label=KDEOSLive +SplitName=root +CopyBlocks=/KDEOSLive.raw diff --git a/mkosi.repart-rebuild/README.md b/mkosi.repart-rebuild/README.md new file mode 100644 index 0000000..c3995d7 --- /dev/null +++ b/mkosi.repart-rebuild/README.md @@ -0,0 +1,9 @@ + + +This isn't actually used by mkosi but named like it so it is next to the actual mkosi directory. +The configs in here simply pick up split partitions from the original repart run into a rebuild run. + +Also see part-rebuild.py diff --git a/mkosi.repart/50-root.conf b/mkosi.repart/50-root.conf index 7a50cae..d91fb4c 100644 --- a/mkosi.repart/50-root.conf +++ b/mkosi.repart/50-root.conf @@ -5,6 +5,7 @@ Type=root Format=btrfs SizeMinBytes=1G +# Do not use spaces. We need to extract this later as a file path. Label=KDEOSLive SplitName=root # NOTE: the FS isn't read only because we have mutable subvolumes. Individual subvolumes may be readonly though. diff --git a/part-rebuild.py b/part-rebuild.py new file mode 100755 index 0000000..153328d --- /dev/null +++ b/part-rebuild.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 + +# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL +# SPDX-FileCopyrightText: 2024 Harald Sitter + +# Rebuilds the image using appropriate partition sizes. + +import json +import math +import subprocess +from subprocess import check_output +import sys +import os + +RAW = sys.argv[1] + +# Load the partition table +out = check_output(["sfdisk", "--json", RAW]) +data = json.loads(out) +partitiontable = data["partitiontable"] +sectorsize = partitiontable["sectorsize"] +partitions = partitiontable["partitions"] + +# Find the root partition +root_partition = None +for index, partition in enumerate(partitions): + if partition["name"] == "KDEOSLive": + root_partition = partition + +# Update its size to what it actually is on the filesystem level +btrfs = json.loads(open("btrfs.json").read()) +root_partition["size"] = math.ceil(btrfs['size'] / sectorsize) + +# Fish out the partitions with appropriate skip and count values (i.e. the actual filesystem sizes) +for index, partition in enumerate(partitions): + subprocess.run(["dd", f"if={RAW}", f"of={partition["name"]}.raw", f"bs={sectorsize}", f"skip={partition["start"]}", f"count={partition["size"]}"], check=True) + +# Then reassemble them into a new image using those squeezed partition images. +open(RAW, "w").close() +subprocess.run(["systemd-repart", "--empty=allow", "--dry-run=no", "--definitions=mkosi.repart-rebuild", "--root", os.getcwd(), RAW], check=True)