Repository navigation
Conversation
When an existing swap partition is active on a target disk, lsblk reports '[SWAP]' in its mountpoints array. Previously, DeviceHandler.umount_all_existing() called umount() on LINUX_SWAP partitions, causing umount() to execute 'umount -R [SWAP]' (which fails with exit code 32) and leaving swap active on the device so subsequent partition table modifications fail with 'Device or resource busy'. Add a swapoff() helper in archinstall.lib.disk.utils, call it for LINUX_SWAP partitions in umount_all_existing(), and filter out '[SWAP]' in umount().
17594da to
b15f2d8
Compare
|
Not sure about the policy here with tests, we used not to add too many and just rely on repro then re-run. |
xander-lin
left a comment
There was a problem hiding this comment.
Thanks — the swap branch in umount_all_existing() is correct, and a plain swap partition is handled now. Below is why the filter in umount() does not cover the same failure, and the layouts the patch cannot reach.
1. [SWAP] reaches the model through two paths, and the filter is downstream of both
Filtering at utils.py:179 addresses the last consumer of the marker. It is not the only one, and it is not the one that fires first.
Path A — via mountpoint. For an active swap partition lsblk reports mountpoints == ['[SWAP]'], and _PartitionInfo.from_partition() copies that straight into the model (models/device.py:620). from_existing_partition() then takes the first entry as the mountpoint (models/device.py:969), and Installer._mount_partition() checks if part_mod.mountpoint: before it ever reaches elif part_mod.is_swap(): (installer.py:377, :394). On this branch, installing onto a disk whose swap was left active produces:
mount: /mnt/[SWAP]: unknown filesystem type 'swap'
DiskError: Could not mount /dev/loop1p2
The swap branch in _mount_partition is therefore dead code for any partition that was active at scan time — is_swap() is true, but the mountpoint branch wins.
Path B — via mountpoints. Luks2.lock() iterates the child's mountpoints and passes each one to umount() (luks.py:173-175), which is the only call site in the tree that hands umount() a mountpoint rather than a device. umount() then calls get_lsblk_info() on that value (utils.py:177) before the filter on line 179 is evaluated, so the marker raises there first.
Both paths come from the same place: a formatted string from lsblk is being carried in fields that are supposed to hold paths. Sanitising mountpoint and mountpoints at the LsblkInfo boundary leaves no consumer to guard, and covers path A and path B at once.
2. swapoff() decides state from the same display string
lsblk_info = get_lsblk_info(path)
if Path('[SWAP]') not in lsblk_info.mountpoints:
returnlsblk prints [SWAP] for a swap partition but only the mount path for a swap file, so this returns silently for swapfiles — and a silent return from a cleanup helper is indistinguishable from "nothing to do". The kernel reports the state directly: /proc/swaps lists the area itself in its first column (/dev/dm-0, /mnt/swapfile), which is also what swapon --show=NAME returns. Deciding from that keeps the answer independent of how lsblk chooses to render something.
3. lock() closes the mapper without deactivating swap
Deactivating swap is a precondition for cryptsetup close, not only for umount. lock() unwinds mounts and closes in the same loop (luks.py:171-179), so a mapper that still has swap on it fails at close. The same loop also cannot reach LVM-on-LUKS, where the swap sits on a logical volume one level below the mapper — there children is the LV set and the loop's single level does not go deeper.
4. Scope note
umount_all_existing() iterates the partitions found on the physical device rather than the ones in the layout; that predates this PR and I am not asking to change the granularity here. It is worth stating explicitly, though: swap or LUKS containers outside the final layout are deactivated by cleanup and never re-activated, and genfstab takes its swap entries from /proc/swaps, so "deactivated" is an intermediate state rather than a result.
Related
#4745 ("Handle active swap on existing partitions", open since Aug 31) targets the same cleanup and sanitises LsblkInfo, which is the boundary described above. Two implementations for the same bug should probably be consolidated rather than merged separately.
None of this blocks the unencrypted-swap fix. If the layouts above are out of scope for #4235, the Fixes should stay open until they are covered.
PR Description:
When an existing swap partition is active on a target disk,
lsblk --jsonreports"[SWAP]"in itsmountpointslist.Previously,
DeviceHandler.umount_all_existing()passedFilesystemType.LINUX_SWAPpartitions toumount(partition.path, recursive=True), which attempted to executeumount -R [SWAP](failing with exit code 32) and never disabled active swap on the partition—causing subsequentpartedoperations to fail withDevice or resource busy.This PR:
swapoff()helper inarchinstall.lib.disk.utilsthat disables swap when[SWAP]is present inlsblk_info.mountpoints.swapoff(partition.path)forFilesystemType.LINUX_SWAPpartitions inDeviceHandler.umount_all_existing().Path('[SWAP]')inumount()so pseudo-mountpoints are never passed toumount.tests/test_swapoff_existing.py.Tests and Checks