From 5b9d3fdf6ad4c9c38cc4e2016dfb1c7b59e0a4d5 Mon Sep 17 00:00:00 2001 From: Thomas Stallinger Date: Tue, 1 Sep 2026 12:00:55 +0200 Subject: [PATCH] fix(installer): Zielplatte vor dem Partitionieren freigeben + Kernel-Neueinlesen mit Wiederholung Live auf echter Hardware gefunden (01.09.2026): "Error: Partition(s) 1 on /dev/sda have been written, but we have been unable to inform the Kernel of the change, probably because it/they are in use." - parted schreibt die neue GPT-Tabelle zwar trotzdem, meldet aber einen Fehler, wenn eine alte Partition (Swap, gemountetes Dateisystem vom vorherigen Betriebssystem auf dieser Platte) noch belegt ist. In QEMU mit stets frischen Testplatten nie aufgetreten - reale Kundenhardware hat aber fast immer schon ein Vorleben auf der Platte. Zwei neue Bausteine in image_deploy_partition(): - _image_deploy_release_disk(): unmountet/deaktiviert Swap auf allen vorhandenen Partitionen der Zielplatte, bevor ueberhaupt mklabel aufgerufen wird. - _image_deploy_settle_partitions(): wiederholt partprobe/udevadm settle bis zu 5x statt nach einem einzigen Versuch aufzugeben, sowohl nach mklabel als auch nach dem Anlegen der eigentlichen Partitionen. Zusaetzlich wird nach mklabel explizit verifiziert, dass wirklich ein gueltiges GPT-Label vorliegt (parted print), statt parteds Exit-Code fuer den Kernel-Info-Schritt blind als Gesamtfehlschlag zu werten. Lokal verifiziert: einmal komplett durchinstalliert (frische Platte), dann OHNE die Platte zurueckzusetzen ein zweites Mal auf dieselbe, bereits mit einem echten System belegte Platte installiert - lief sauber durch, keine Kernel-Fehlermeldung mehr. --- .../opt/tuxflotte/scripts/lib/image_deploy.sh | 57 +++++++++++++++++-- scripts/lib/image_deploy.sh | 57 +++++++++++++++++-- 2 files changed, 106 insertions(+), 8 deletions(-) diff --git a/boot-medium/config/includes.chroot/opt/tuxflotte/scripts/lib/image_deploy.sh b/boot-medium/config/includes.chroot/opt/tuxflotte/scripts/lib/image_deploy.sh index efc732e..7ac8498 100644 --- a/boot-medium/config/includes.chroot/opt/tuxflotte/scripts/lib/image_deploy.sh +++ b/boot-medium/config/includes.chroot/opt/tuxflotte/scripts/lib/image_deploy.sh @@ -46,12 +46,61 @@ image_deploy_partition_path() { # an, siehe dortiger Kommentar zu bios_grub). Gibt "BOOT_PART ROOT_PART" # auf stdout aus - BOOT_PART ist bei BIOS leer (die biosgrub-Partition # braucht kein Dateisystem/keinen Mountpunkt). +# Vorhandene Partitionen der Zielplatte vor dem Neupartitionieren freigeben +# (unmounten, Swap deaktivieren) - live auf echter Hardware gefunden +# (01.09.2026): parted schreibt eine neue Partitionstabelle zwar trotzdem +# auf die Platte, meldet aber einen Fehler ("...have been unable to inform +# the Kernel of the change... probably because it/they are in use"), wenn +# eine alte Partition (z.B. Swap oder ein gemountetes Dateisystem vom +# vorherigen Betriebssystem auf dieser Platte) noch belegt ist. In QEMU mit +# stets frischen Testplatten nie aufgetreten - reale Kundenhardware hat +# aber fast immer schon ein Vorleben auf der Platte. +_image_deploy_release_disk() { + local disk="$1" + local part + + for part in "${disk}"?*; do + [[ -b "${part}" ]] || continue + swapoff "${part}" 2>/dev/null || true + umount --recursive "${part}" 2>/dev/null || true + done +} + +# Manche Kernel-/Platten-Kombinationen brauchen mehrere Anlaeufe, bis das +# Neueinlesen der Partitionstabelle (BLKRRPART) greift, gerade direkt nach +# einem mklabel auf einer zuvor belegten Platte - deshalb mehrfach +# probieren statt nach einem einzigen partprobe-Aufruf aufzugeben. +_image_deploy_settle_partitions() { + local disk="$1" + local attempt + + for attempt in 1 2 3 4 5; do + if partprobe "${disk}" 2>/dev/null; then + udevadm settle + return 0 + fi + sleep 1 + done + + udevadm settle + return 1 +} + image_deploy_partition() { local disk="$1" local is_efi="$2" - parted --script "${disk}" mklabel gpt || - { image_deploy_fatal "mklabel gpt fehlgeschlagen auf ${disk}"; return 1; } + _image_deploy_release_disk "${disk}" + + if ! parted --script "${disk}" mklabel gpt; then + image_deploy_log "parted meldete einen Fehler beim Anlegen der Partitionstabelle auf ${disk} (haeufig: eine alte Partition war noch belegt) - pruefe, ob der Kernel die neue Tabelle trotzdem uebernimmt." + fi + + _image_deploy_settle_partitions "${disk}" || + { image_deploy_fatal "Kernel konnte die neue Partitionstabelle auf ${disk} auch nach mehreren Versuchen nicht uebernehmen."; return 1; } + + parted --script "${disk}" print 2>/dev/null | grep -q "Partition Table: gpt" || + { image_deploy_fatal "Nach dem Partitionieren liegt kein gueltiges GPT-Label auf ${disk} vor."; return 1; } if [[ "${is_efi}" == "true" ]]; then parted --script "${disk}" mkpart ESP fat32 1MiB 513MiB && @@ -65,8 +114,8 @@ image_deploy_partition() { { image_deploy_fatal "Partitionierung (BIOS) fehlgeschlagen auf ${disk}"; return 1; } fi - partprobe "${disk}" 2>/dev/null || true - udevadm settle + _image_deploy_settle_partitions "${disk}" || + { image_deploy_fatal "Kernel konnte die neuen Partitionen auf ${disk} nicht uebernehmen."; return 1; } local part1 part2 part1="$(image_deploy_partition_path "${disk}" 1)" diff --git a/scripts/lib/image_deploy.sh b/scripts/lib/image_deploy.sh index efc732e..7ac8498 100644 --- a/scripts/lib/image_deploy.sh +++ b/scripts/lib/image_deploy.sh @@ -46,12 +46,61 @@ image_deploy_partition_path() { # an, siehe dortiger Kommentar zu bios_grub). Gibt "BOOT_PART ROOT_PART" # auf stdout aus - BOOT_PART ist bei BIOS leer (die biosgrub-Partition # braucht kein Dateisystem/keinen Mountpunkt). +# Vorhandene Partitionen der Zielplatte vor dem Neupartitionieren freigeben +# (unmounten, Swap deaktivieren) - live auf echter Hardware gefunden +# (01.09.2026): parted schreibt eine neue Partitionstabelle zwar trotzdem +# auf die Platte, meldet aber einen Fehler ("...have been unable to inform +# the Kernel of the change... probably because it/they are in use"), wenn +# eine alte Partition (z.B. Swap oder ein gemountetes Dateisystem vom +# vorherigen Betriebssystem auf dieser Platte) noch belegt ist. In QEMU mit +# stets frischen Testplatten nie aufgetreten - reale Kundenhardware hat +# aber fast immer schon ein Vorleben auf der Platte. +_image_deploy_release_disk() { + local disk="$1" + local part + + for part in "${disk}"?*; do + [[ -b "${part}" ]] || continue + swapoff "${part}" 2>/dev/null || true + umount --recursive "${part}" 2>/dev/null || true + done +} + +# Manche Kernel-/Platten-Kombinationen brauchen mehrere Anlaeufe, bis das +# Neueinlesen der Partitionstabelle (BLKRRPART) greift, gerade direkt nach +# einem mklabel auf einer zuvor belegten Platte - deshalb mehrfach +# probieren statt nach einem einzigen partprobe-Aufruf aufzugeben. +_image_deploy_settle_partitions() { + local disk="$1" + local attempt + + for attempt in 1 2 3 4 5; do + if partprobe "${disk}" 2>/dev/null; then + udevadm settle + return 0 + fi + sleep 1 + done + + udevadm settle + return 1 +} + image_deploy_partition() { local disk="$1" local is_efi="$2" - parted --script "${disk}" mklabel gpt || - { image_deploy_fatal "mklabel gpt fehlgeschlagen auf ${disk}"; return 1; } + _image_deploy_release_disk "${disk}" + + if ! parted --script "${disk}" mklabel gpt; then + image_deploy_log "parted meldete einen Fehler beim Anlegen der Partitionstabelle auf ${disk} (haeufig: eine alte Partition war noch belegt) - pruefe, ob der Kernel die neue Tabelle trotzdem uebernimmt." + fi + + _image_deploy_settle_partitions "${disk}" || + { image_deploy_fatal "Kernel konnte die neue Partitionstabelle auf ${disk} auch nach mehreren Versuchen nicht uebernehmen."; return 1; } + + parted --script "${disk}" print 2>/dev/null | grep -q "Partition Table: gpt" || + { image_deploy_fatal "Nach dem Partitionieren liegt kein gueltiges GPT-Label auf ${disk} vor."; return 1; } if [[ "${is_efi}" == "true" ]]; then parted --script "${disk}" mkpart ESP fat32 1MiB 513MiB && @@ -65,8 +114,8 @@ image_deploy_partition() { { image_deploy_fatal "Partitionierung (BIOS) fehlgeschlagen auf ${disk}"; return 1; } fi - partprobe "${disk}" 2>/dev/null || true - udevadm settle + _image_deploy_settle_partitions "${disk}" || + { image_deploy_fatal "Kernel konnte die neuen Partitionen auf ${disk} nicht uebernehmen."; return 1; } local part1 part2 part1="$(image_deploy_partition_path "${disk}" 1)"