loop-util: shortcut block device fd when it carries no partition table
663f0bf5cb stopped reusing the original block device fd whenever partition scanning was requested (LO_FLAGS_PARTSCAN) but couldn't be enabled on the device, so that nested partition tables on devices the kernel won't scan (e.g. the pmOS/android case) get exposed via a real loop device. However that also forced a pointless loop device for any partition that carries a file system directly, e.g. a btrfs subvolume mounted via MountImages=. For multi-device btrfs this is fatal: the kernel rejects seeing the same member via both the original partition and the loop device, and the mount fails. A loop device is only ever needed here to expose a nested partition table. So only refuse the shortcut when the device actually carries one, probed via gpt_probe(), instead of whenever partition scanning is disabled. Devices carrying a file system directly (or nothing) take the shortcut as before. Add an integration test to cover the failure scenario of the original issue. Fixes: https://github.com/systemd/systemd/issues/42520 Replaces: https://github.com/systemd/systemd/pull/42576 Follow-up for 663f0bf5cb79ecaf6dd71441ecdc9dc401e7eae6 Co-Authored-By: Luca Boccassi <luca.boccassi@gmail.com> Co-developed-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
committed by
Luca Boccassi
co-authored by
Luca Boccassi
parent
53f5f840c7
commit
3978b076af
@@ -26,6 +26,18 @@ typedef struct LoopDevice {
|
||||
/* Returns true if LoopDevice object is not actually a loopback device but some other block device we just wrap */
|
||||
#define LOOP_DEVICE_IS_FOREIGN(d) ((d)->nr < 0)
|
||||
|
||||
/* systemd-internal flags OR'd into the loop_flags argument of loop_device_make() and friends, in addition to
|
||||
* the kernel's LO_FLAGS_*. These live in high bits to stay clear of the kernel values and are masked out
|
||||
* before the flags reach the kernel.
|
||||
*
|
||||
* LOOP_DEVICE_MAY_POPULATE_PARTITION_TABLE: by default, when LO_FLAGS_PARTSCAN is requested but cannot be
|
||||
* enabled on the device and the device carries no partition table, we hand back the original fd instead of
|
||||
* allocating a loopback device — there's nothing to scan, and routing e.g. a multi-device btrfs member
|
||||
* through a loopback breaks it (https://github.com/systemd/systemd/issues/42520). Callers that might write a
|
||||
* (nested) partition table into the device and rely on partition scanning to pick it up afterwards must set
|
||||
* this flag to force a real loopback device even when the device is currently unpartitioned. */
|
||||
#define LOOP_DEVICE_MAY_POPULATE_PARTITION_TABLE (UINT32_C(1) << 16)
|
||||
|
||||
int loop_device_make(int fd, int open_flags, uint64_t offset, uint64_t size, uint32_t sector_size, uint32_t loop_flags, int lock_op, LoopDevice **ret);
|
||||
int loop_device_make_by_path_at(int dir_fd, const char *path, int open_flags, uint32_t sector_size, uint32_t loop_flags, int lock_op, LoopDevice **ret);
|
||||
static inline int loop_device_make_by_path(const char *path, int open_flags, uint32_t sector_size, uint32_t loop_flags, int lock_op, LoopDevice **ret) {
|
||||
|
||||
Reference in New Issue
Block a user