diff --git a/packages/system/virt/src/image_prep/mod.rs b/packages/system/virt/src/image_prep/mod.rs index c35aef3..c9a4ee1 100644 --- a/packages/system/virt/src/image_prep/mod.rs +++ b/packages/system/virt/src/image_prep/mod.rs @@ -184,8 +184,17 @@ modprobe nbd max_part=63 NBD=\"\" for i in $(seq 0 15); do DEV=\"/dev/nbd$i\" + # Skip devices that have any mounted partitions (avoid reusing in-use NBDs) + if findmnt -rn -S \"$DEV\" >/dev/null 2>&1 || \ + findmnt -rn -S \"${{DEV}}p1\" >/dev/null 2>&1 || \ + findmnt -rn -S \"${{DEV}}p14\" >/dev/null 2>&1 || \ + findmnt -rn -S \"${{DEV}}p15\" >/dev/null 2>&1 || \ + findmnt -rn -S \"${{DEV}}p16\" >/dev/null 2>&1; then + continue + fi + # Ensure it's not connected (ignore errors if already disconnected) qemu-nbd --disconnect \"$DEV\" >/dev/null 2>&1 || true - if qemu-nbd --connect=\"$DEV\" \"$WORK\"; then + if qemu-nbd --format=qcow2 --connect=\"$DEV\" \"$WORK\"; then NBD=\"$DEV\" break fi @@ -195,13 +204,22 @@ if [ -z \"$NBD\" ]; then exit 1 fi +echo \"Selected NBD: $NBD\" + # Settle and probe partitions udevadm settle >/dev/null 2>&1 || true +blockdev --rereadpt \"$NBD\" >/dev/null 2>&1 || true partprobe \"$NBD\" >/dev/null 2>&1 || true -for t in 1 2 3 4 5 6 7 8 9 10; do - [ -b \"${{NBD}}p1\" ] && break - sleep 0.3 +for t in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; do + if [ -b \"${{NBD}}p1\" ]; then + sz=$(blockdev --getsize64 \"${{NBD}}p1\" 2>/dev/null || echo 0) + if [ \"$sz\" -gt 0 ]; then + break + fi + fi + sleep 0.4 udevadm settle >/dev/null 2>&1 || true + blockdev --rereadpt \"$NBD\" >/dev/null 2>&1 || true partprobe \"$NBD\" >/dev/null 2>&1 || true done @@ -216,6 +234,8 @@ else exit 33 fi +echo \"ROOT_DEV=$ROOT_DEV BOOT_DEV=$BOOT_DEV\" + if [ ! -b \"$ROOT_DEV\" ]; then echo \"Root partition not found: $ROOT_DEV\" >&2 exit 32 @@ -230,9 +250,49 @@ cleanup() {{ }} trap cleanup EXIT -# Mount and mutate -mount \"$ROOT_DEV\" \"$MNT_ROOT\" -mount \"$BOOT_DEV\" \"$MNT_BOOT\" +# Ensure partitions are readable before mounting +for t in 1 2 3 4 5 6 7 8; do + szr=$(blockdev --getsize64 \"$ROOT_DEV\" 2>/dev/null || echo 0) + szb=$(blockdev --getsize64 \"$BOOT_DEV\" 2>/dev/null || echo 0) + if [ \"$szr\" -gt 0 ] && [ \"$szb\" -gt 0 ] && blkid \"$ROOT_DEV\" >/dev/null 2>&1; then + break + fi + sleep 0.4 + udevadm settle >/dev/null 2>&1 || true + blockdev --rereadpt \"$NBD\" >/dev/null 2>&1 || true + partprobe \"$NBD\" >/dev/null 2>&1 || true +done + +# Mount and mutate (with retries to avoid races) +mounted_root=0 +for t in 1 2 3 4 5 6 7 8 9 10; do + if mount \"$ROOT_DEV\" \"$MNT_ROOT\"; then + mounted_root=1 + break + fi + sleep 0.5 + udevadm settle >/dev/null 2>&1 || true + partprobe \"$NBD\" >/dev/null 2>&1 || true +done +if [ \"$mounted_root\" -ne 1 ]; then + echo \"Failed to mount root $ROOT_DEV\" >&2 + exit 32 +fi + +mounted_boot=0 +for t in 1 2 3 4 5; do + if mount \"$BOOT_DEV\" \"$MNT_BOOT\"; then + mounted_boot=1 + break + fi + sleep 0.5 + udevadm settle >/dev/null 2>&1 || true + partprobe \"$NBD\" >/dev/null 2>&1 || true +done +if [ \"$mounted_boot\" -ne 1 ]; then + echo \"Failed to mount boot $BOOT_DEV\" >&2 + exit 33 +fi # Change UUIDs (best-effort) tune2fs -U random \"$ROOT_DEV\" || true @@ -287,9 +347,15 @@ if [ \"{disable_ci_net}\" = \"true\" ]; then echo \"network: {{config: disabled}}\" > \"$MNT_ROOT/etc/cloud/cloud.cfg.d/99-disable-network-config.cfg\" fi -# Convert prepared image to raw +# Convert prepared image to raw (ensure source not locked) +umount \"$MNT_BOOT\" 2>/dev/null || true +umount \"$MNT_ROOT\" 2>/dev/null || true +if [ -n \"$NBD\" ]; then + qemu-nbd --disconnect \"$NBD\" 2>/dev/null || true + rmmod nbd 2>/dev/null || true +fi rm -f \"$RAW\" -qemu-img convert -O raw \"$WORK\" \"$RAW\" +qemu-img convert -U -f qcow2 -O raw \"$WORK\" \"$RAW\" # Output result triple echo \"$RAW|$ROOT_UUID|$BOOT_UUID\"