loop-util: don't reuse partition fd when partscan needed
Some devices (e.g. android phones running pmOS) cannot have their OEM partition table altered without breaking the firmware, so the distros's partitions live inside a nested GPT carved into one of the OEM partitions. Exposing these subpartitions requires wrapping the outer partition in a loop device with partscan enabled, since the kernel does not go into nested partition tables. systemd already detects this case in udev-builtin-blkid (ID_PART_GPT_AUTO_ROOT_DISK_NEEDS_LOOP) and acts on with systemd-loop@.service, but this fails towards the end. loop_device_make_internal has an optimization where if the input is already a block device with a matching sector size, it skips creating a loop and just hands back the original fd. That's fine for whole disks but wrong for partitions, which don't support partscan, so this causes dissect_image to fail with EPROTONOSUPPORT. This patch changes the behavior to only take the shortcut when the input is a whole disk, or when partscan was not requested. Co-Authored-By: Clayton Craft <clayton@craftyguy.net>
This commit is contained in:
committed by
Luca Boccassi
parent
d0f726ed8f
commit
47d408163b
@@ -538,4 +538,37 @@ TEST(sector_size_mismatch) {
|
||||
loop = loop_device_unref(loop);
|
||||
}
|
||||
|
||||
TEST(partscan_required) {
|
||||
_cleanup_(loop_device_unrefp) LoopDevice *block_loop = NULL, *loop = NULL;
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
|
||||
if (have_effective_cap(CAP_SYS_ADMIN) <= 0) {
|
||||
log_tests_skipped("not running privileged");
|
||||
return;
|
||||
}
|
||||
|
||||
if (detect_container() != 0 || running_in_chroot() != 0) {
|
||||
log_tests_skipped("Test not supported in a container/chroot, requires udev/uevent notifications");
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT_OK(make_test_image(&fd));
|
||||
|
||||
/* Set up a backing loop device without LO_FLAGS_PARTSCAN. */
|
||||
ASSERT_OK(loop_device_make(fd, O_RDWR, 0, UINT64_MAX, 0, 0, LOCK_EX, &block_loop));
|
||||
ASSERT_TRUE(block_loop->created);
|
||||
ASSERT_OK(loop_device_flock(block_loop, LOCK_SH));
|
||||
|
||||
/* Without LO_FLAGS_PARTSCAN: shortcut should be taken (reuse existing loop). */
|
||||
ASSERT_OK(loop_device_make(block_loop->fd, O_RDWR, 0, UINT64_MAX, 0, 0, LOCK_SH, &loop));
|
||||
ASSERT_FALSE(loop->created);
|
||||
loop = loop_device_unref(loop);
|
||||
|
||||
/* With LO_FLAGS_PARTSCAN: backing loop has partscan disabled, so a new loop device with
|
||||
* partscan must be created. */
|
||||
ASSERT_OK(loop_device_make(block_loop->fd, O_RDWR, 0, UINT64_MAX, 0, LO_FLAGS_PARTSCAN, LOCK_SH, &loop));
|
||||
ASSERT_TRUE(loop->created);
|
||||
loop = loop_device_unref(loop);
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN_WITH_INTRO(LOG_DEBUG, intro);
|
||||
|
||||
Reference in New Issue
Block a user