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.
This commit is contained in:
Thomas Stallinger 2026-09-01 12:00:55 +02:00
parent ebd827ee2f
commit 5b9d3fdf6a
2 changed files with 106 additions and 8 deletions

View File

@ -46,12 +46,61 @@ image_deploy_partition_path() {
# an, siehe dortiger Kommentar zu bios_grub). Gibt "BOOT_PART ROOT_PART" # an, siehe dortiger Kommentar zu bios_grub). Gibt "BOOT_PART ROOT_PART"
# auf stdout aus - BOOT_PART ist bei BIOS leer (die biosgrub-Partition # auf stdout aus - BOOT_PART ist bei BIOS leer (die biosgrub-Partition
# braucht kein Dateisystem/keinen Mountpunkt). # 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() { image_deploy_partition() {
local disk="$1" local disk="$1"
local is_efi="$2" local is_efi="$2"
parted --script "${disk}" mklabel gpt || _image_deploy_release_disk "${disk}"
{ image_deploy_fatal "mklabel gpt fehlgeschlagen auf ${disk}"; return 1; }
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 if [[ "${is_efi}" == "true" ]]; then
parted --script "${disk}" mkpart ESP fat32 1MiB 513MiB && 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; } { image_deploy_fatal "Partitionierung (BIOS) fehlgeschlagen auf ${disk}"; return 1; }
fi fi
partprobe "${disk}" 2>/dev/null || true _image_deploy_settle_partitions "${disk}" ||
udevadm settle { image_deploy_fatal "Kernel konnte die neuen Partitionen auf ${disk} nicht uebernehmen."; return 1; }
local part1 part2 local part1 part2
part1="$(image_deploy_partition_path "${disk}" 1)" part1="$(image_deploy_partition_path "${disk}" 1)"

View File

@ -46,12 +46,61 @@ image_deploy_partition_path() {
# an, siehe dortiger Kommentar zu bios_grub). Gibt "BOOT_PART ROOT_PART" # an, siehe dortiger Kommentar zu bios_grub). Gibt "BOOT_PART ROOT_PART"
# auf stdout aus - BOOT_PART ist bei BIOS leer (die biosgrub-Partition # auf stdout aus - BOOT_PART ist bei BIOS leer (die biosgrub-Partition
# braucht kein Dateisystem/keinen Mountpunkt). # 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() { image_deploy_partition() {
local disk="$1" local disk="$1"
local is_efi="$2" local is_efi="$2"
parted --script "${disk}" mklabel gpt || _image_deploy_release_disk "${disk}"
{ image_deploy_fatal "mklabel gpt fehlgeschlagen auf ${disk}"; return 1; }
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 if [[ "${is_efi}" == "true" ]]; then
parted --script "${disk}" mkpart ESP fat32 1MiB 513MiB && 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; } { image_deploy_fatal "Partitionierung (BIOS) fehlgeschlagen auf ${disk}"; return 1; }
fi fi
partprobe "${disk}" 2>/dev/null || true _image_deploy_settle_partitions "${disk}" ||
udevadm settle { image_deploy_fatal "Kernel konnte die neuen Partitionen auf ${disk} nicht uebernehmen."; return 1; }
local part1 part2 local part1 part2
part1="$(image_deploy_partition_path "${disk}" 1)" part1="$(image_deploy_partition_path "${disk}" 1)"