From 0c96c5ca509fb7186aeedbe333041db69dffd72a Mon Sep 17 00:00:00 2001 From: John Eckersberg Date: Sun, 1 Nov 2026 16:31:13 -0500 Subject: [PATCH] tests: Use lazy umount in tmt tests umount can fail with "target is busy" right after bootc install/bootupd (see #2177). Use `umount -l` as suggested there. The unmounts in test-composefs-separate-boot.nu and the first one in test-install-outside-container.nu stay strict because the underlying device/image is repartitioned and reformatted right after. Assisted-by: AI Signed-off-by: John Eckersberg --- tmt/tests/booted/test-composefs-uki-addons.nu | 8 ++++---- tmt/tests/booted/test-install-composefs-native.nu | 2 +- tmt/tests/booted/test-install-karg-delete.nu | 2 +- tmt/tests/booted/test-install-no-boot-dir.nu | 2 +- tmt/tests/booted/test-install-outside-container.nu | 14 +++++++------- .../booted/test-install-shared-propagation.nu | 2 +- .../booted/test-install-to-filesystem-var-mount.sh | 2 +- tmt/tests/booted/test-multi-device-esp.nu | 10 +++++----- 8 files changed, 21 insertions(+), 21 deletions(-) diff --git a/tmt/tests/booted/test-composefs-uki-addons.nu b/tmt/tests/booted/test-composefs-uki-addons.nu index 665b50ac21..a87db250f5 100644 --- a/tmt/tests/booted/test-composefs-uki-addons.nu +++ b/tmt/tests/booted/test-composefs-uki-addons.nu @@ -93,7 +93,7 @@ def second_boot [] { # A switch/upgrade must *stage* the global addon under loader/addons.staged # and leave the live loader/addons dir untouched until the next boot. # Remount the ESP so our view is coherent with the mount bootc wrote through. - umount /var/tmp/efi + umount -l /var/tmp/efi mount /dev/disk/by-partlabel/EFI-SYSTEM /var/tmp/efi assert ("/var/tmp/efi/loader/addons.staged/bootc_composefs-global-cmdline.addon.efi" | path exists) "Global addon should be staged under loader/addons.staged" @@ -166,7 +166,7 @@ def third_boot [] { # The switch above staged a deployment and carried the global addon forward # into loader/addons.staged, while the live loader/addons is left intact. # Remount the ESP for a view coherent with bootc's own mount. - umount /var/tmp/efi + umount -l /var/tmp/efi mount /dev/disk/by-partlabel/EFI-SYSTEM /var/tmp/efi assert ("/var/tmp/efi/loader/addons.staged/bootc_composefs-global-cmdline.addon.efi" | path exists) "Global addon should be staged after switch" @@ -183,7 +183,7 @@ def third_boot [] { assert ($remove_result.exit_code == 0) "Removing the staged global addon should succeed" assert ($remove_result.stdout | str contains "last staged global addon") "Should warn about removing the last staged global addon" - umount /var/tmp/efi + umount -l /var/tmp/efi mount /dev/disk/by-partlabel/EFI-SYSTEM /var/tmp/efi assert (not ("/var/tmp/efi/loader/addons.staged" | path exists)) "loader/addons.staged must be deleted after removing the last staged global addon" @@ -193,7 +193,7 @@ def third_boot [] { # check. With a deployment staged, `add` writes back into loader/addons.staged. bootc uki-addon add global-cmdline global - umount /var/tmp/efi + umount -l /var/tmp/efi mount /dev/disk/by-partlabel/EFI-SYSTEM /var/tmp/efi assert ("/var/tmp/efi/loader/addons.staged/bootc_composefs-global-cmdline.addon.efi" | path exists) "Global addon should be re-staged" diff --git a/tmt/tests/booted/test-install-composefs-native.nu b/tmt/tests/booted/test-install-composefs-native.nu index 1a96ef8c56..00b4774ddf 100644 --- a/tmt/tests/booted/test-install-composefs-native.nu +++ b/tmt/tests/booted/test-install-composefs-native.nu @@ -62,7 +62,7 @@ def install [image: string, ...args: string] { let dropin = glob $"($MNT)/state/deploy/*/etc/tmpfiles.d/bootc-root-ssh.conf" | append (glob $"($MNT)/ostree/deploy/*/deploy/*/etc/tmpfiles.d/bootc-root-ssh.conf") | each {|p| {content: (open --raw $p | decode utf-8), mode: (stat -c %a $p | str trim)}} - umount $MNT + umount -l $MNT rm -f $DISK assert equal $dropin [{content: $"f~ /var/roothome/.ssh/authorized_keys 600 root root - ($KEY | encode base64)\n", mode: "644"}] "root ssh drop-in" match [$composefs $ostree] { diff --git a/tmt/tests/booted/test-install-karg-delete.nu b/tmt/tests/booted/test-install-karg-delete.nu index ca9364333a..9829c7fe29 100644 --- a/tmt/tests/booted/test-install-karg-delete.nu +++ b/tmt/tests/booted/test-install-karg-delete.nu @@ -41,7 +41,7 @@ let foo_found = ($entries | find "foo" | is-empty) assert $foo_found "Found foo in bootloader entries, but it should have been deleted" # Clean up -umount /var/mnt +umount -l /var/mnt rm -rf disk.img tap ok diff --git a/tmt/tests/booted/test-install-no-boot-dir.nu b/tmt/tests/booted/test-install-no-boot-dir.nu index 82494abb50..01b4b70f0d 100644 --- a/tmt/tests/booted/test-install-no-boot-dir.nu +++ b/tmt/tests/booted/test-install-no-boot-dir.nu @@ -27,7 +27,7 @@ def main [] { tap run_install $"bootc install to-filesystem --disable-selinux --bootloader=none --source-imgref ($target_image) /var/mnt" - umount /var/mnt + umount -l /var/mnt rm -f disk.img tap ok diff --git a/tmt/tests/booted/test-install-outside-container.nu b/tmt/tests/booted/test-install-outside-container.nu index 71ad75c8e9..af1565bea8 100644 --- a/tmt/tests/booted/test-install-outside-container.nu +++ b/tmt/tests/booted/test-install-outside-container.nu @@ -169,8 +169,8 @@ if $source_is_uki { null } catch {|err| $err } - do { umount $target_esp } | complete | ignore - do { umount $target_root } | complete | ignore + do { umount -l $target_esp } | complete | ignore + do { umount -l $target_root } | complete | ignore do { losetup -d $loop } | complete | ignore if $inspection_error != null { error make { msg: $"installed target inspection failed: ($inspection_error)" } @@ -217,7 +217,7 @@ for path in [$dest ($dest | path join etc) ($dest | path join var)] { for path in [root-sentinel usr/sentinel etc/sentinel var/sentinel] { assert_write_denied ($dest | path join $path) } -umount -R $dest +umount -R -l $dest rm ($dest | path join preexisting) # By default only /etc and /var are writable. @@ -231,7 +231,7 @@ for path in [root-sentinel usr/sentinel] { } "etc sentinel" | save ($dest | path join etc/sentinel) "var sentinel" | save ($dest | path join var/sentinel) -umount -R $dest +umount -R -l $dest # The writes must land in the deployment's persistent state on the sysroot. let state = if (tap is_composefs) { @@ -250,7 +250,7 @@ if not (tap is_composefs) { bootc install mount --sysroot $sysroot --latest $dest mkdir ($dest | path join etc/ostree) "[etc]\ntransient = true\n" | save -f ($dest | path join etc/ostree/prepare-root.conf) - umount -R $dest + umount -R -l $dest bootc install mount --sysroot $sysroot --latest $dest let etc = ($dest | path join etc) @@ -258,11 +258,11 @@ if not (tap is_composefs) { assert equal $fstype "overlay" "transient /etc must be an overlay" assert (not ($etc | path join sentinel | path exists)) "transient /etc must not show the persistent copy" "transient" | save ($etc | path join transient-sentinel) - umount -R $dest + umount -R -l $dest assert (not ($deployment | path join etc/transient-sentinel | path exists)) "transient /etc writes must not persist" } -umount $sysroot +umount -l $sysroot losetup -d $loop tap ok diff --git a/tmt/tests/booted/test-install-shared-propagation.nu b/tmt/tests/booted/test-install-shared-propagation.nu index 36d9d5dfe0..69e6eb9dc1 100644 --- a/tmt/tests/booted/test-install-shared-propagation.nu +++ b/tmt/tests/booted/test-install-shared-propagation.nu @@ -34,7 +34,7 @@ def main [] { bootc install to-filesystem --disable-selinux --bootloader=none --source-imgref ($target_image) /var/mnt if findmnt /run/bootc/storage; then echo 'error: /run/bootc/storage mount leaked'; exit 1; fi" - umount /var/mnt + umount -l /var/mnt rm -f disk.img tap ok diff --git a/tmt/tests/booted/test-install-to-filesystem-var-mount.sh b/tmt/tests/booted/test-install-to-filesystem-var-mount.sh index 3953f6a9ee..347d1d3b1d 100644 --- a/tmt/tests/booted/test-install-to-filesystem-var-mount.sh +++ b/tmt/tests/booted/test-install-to-filesystem-var-mount.sh @@ -94,7 +94,7 @@ echo "Using loop device: $LOOP_DEV" cleanup() { set +e echo "Cleaning up..." - umount -R /var/mnt/target 2>/dev/null + umount -R -l /var/mnt/target 2>/dev/null vgchange -an BL 2>/dev/null vgremove -f BL 2>/dev/null losetup -d "$LOOP_DEV" 2>/dev/null diff --git a/tmt/tests/booted/test-multi-device-esp.nu b/tmt/tests/booted/test-multi-device-esp.nu index acf5bff4ff..91c2ba0345 100644 --- a/tmt/tests/booted/test-multi-device-esp.nu +++ b/tmt/tests/booted/test-multi-device-esp.nu @@ -37,7 +37,7 @@ const ROOT_TYPE = "4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709" # Cleanup function for LVM and loop devices def cleanup [vg_name: string, loops: list, mountpoint: string] { # Unmount if mounted - do { umount $mountpoint } | complete | ignore + do { umount -l $mountpoint } | complete | ignore do { rmdir $mountpoint } | complete | ignore # Deactivate and remove LVM @@ -126,7 +126,7 @@ def setup_disk_with_root [ # Simple cleanup for non-LVM scenarios (single loop device, no VG) def cleanup_simple [loop: string, mountpoint: string] { - do { umount $mountpoint } | complete | ignore + do { umount -l $mountpoint } | complete | ignore do { rmdir $mountpoint } | complete | ignore if ($loop | path exists) { @@ -143,14 +143,14 @@ def validate_esp [esp_partition: string] { # Check for EFI directory with bootloader files let efi_dir = $"($esp_mount)/EFI" if not ($efi_dir | path exists) { - umount $esp_mount + umount -l $esp_mount rmdir $esp_mount error make {msg: $"ESP validation failed: EFI directory not found on ($esp_partition)"} } # Verify there's actual content in EFI (not just empty) let efi_contents = (ls $efi_dir | length) - umount $esp_mount + umount -l $esp_mount rmdir $esp_mount if $efi_contents == 0 { @@ -164,7 +164,7 @@ def with_esp [esp_partition: string, f: closure] { mkdir $esp_mount mount $esp_partition $esp_mount let r = (do $f $esp_mount) - umount $esp_mount + umount -l $esp_mount rmdir $esp_mount $r }