loop-util: use auto-detect open mode for loop device setup

When callers do not explicitly request read-only mode, pass open_flags
as -1 (auto-detect) instead of hardcoding O_RDWR. This enables the
existing O_RDWR-to-O_RDONLY retry logic in loop_device_make_by_path_at()
which falls back to O_RDONLY when opening the backing device with O_RDWR
fails with EROFS or similar errors.

Previously, callers passed O_RDWR explicitly when read-only mode was not
requested, which bypassed the retry logic entirely. This meant that
inherently read-only block devices (such as CD-ROMs) would fail to open
instead of gracefully falling back to read-only mode.

Also propagate the unresolved open_flags through
loop_device_make_by_path_at() into loop_device_make_internal() instead
of resolving it to O_RDWR early. For loop_device_make_by_path_memory(),
resolve to O_RDWR immediately since memfds are always writable.

In mstack, switch from loop_device_make() to
loop_device_make_by_path_at() with a NULL path, which reopens the
O_PATH file descriptor with the appropriate access mode. This is
necessary because the backing file descriptor is opened with O_PATH,
which prevents loop_device_make_internal() from auto-detecting the
access mode via fcntl(F_GETFL).
This commit is contained in:
Daan De Meyer
2026-04-01 10:02:15 +02:00
committed by Daan De Meyer
parent da69848791
commit 614509699a
6 changed files with 12 additions and 9 deletions
+1 -1
View File
@@ -2015,7 +2015,7 @@ static int run(int argc, char *argv[]) {
uint32_t loop_flags;
int open_flags;
open_flags = FLAGS_SET(arg_flags, DISSECT_IMAGE_DEVICE_READ_ONLY) ? O_RDONLY : O_RDWR;
open_flags = FLAGS_SET(arg_flags, DISSECT_IMAGE_DEVICE_READ_ONLY) ? O_RDONLY : -1;
loop_flags = FLAGS_SET(arg_flags, DISSECT_IMAGE_NO_PARTITION_TABLE) ? 0 : LO_FLAGS_PARTSCAN;
if (arg_in_memory)
+1 -1
View File
@@ -521,7 +521,7 @@ static int vl_method_mount_image(
r = loop_device_make(
image_fd,
p.read_only > 0 ? O_RDONLY : O_RDWR,
p.read_only > 0 ? O_RDONLY : -1,
0,
UINT64_MAX,
UINT32_MAX,
+1 -1
View File
@@ -6483,7 +6483,7 @@ static int run(int argc, char *argv[]) {
if (arg_userns_mode != USER_NAMESPACE_MANAGED) {
r = loop_device_make_by_path(
arg_image,
arg_read_only ? O_RDONLY : O_RDWR,
arg_read_only ? O_RDONLY : -1,
/* sector_size= */ UINT32_MAX,
FLAGS_SET(dissect_image_flags, DISSECT_IMAGE_NO_PARTITION_TABLE) ? 0 : LO_FLAGS_PARTSCAN,
LOCK_SH,
+1 -1
View File
@@ -4718,7 +4718,7 @@ int mount_image_privately_interactively(
r = loop_device_make_by_path(
image,
FLAGS_SET(flags, DISSECT_IMAGE_DEVICE_READ_ONLY) ? O_RDONLY : O_RDWR,
FLAGS_SET(flags, DISSECT_IMAGE_DEVICE_READ_ONLY) ? O_RDONLY : -1,
/* sector_size= */ UINT32_MAX,
FLAGS_SET(flags, DISSECT_IMAGE_NO_PARTITION_TABLE) ? 0 : LO_FLAGS_PARTSCAN,
LOCK_SH,
+5 -1
View File
@@ -773,9 +773,13 @@ int loop_device_make_by_path_memory(
int r;
assert(path);
assert(IN_SET(open_flags, O_RDWR, O_RDONLY));
assert(open_flags < 0 || IN_SET(open_flags, O_RDWR, O_RDONLY));
assert(ret);
/* memfds are always writable, so default to O_RDWR when auto-detecting. */
if (open_flags < 0)
open_flags = O_RDWR;
loop_flags &= ~LO_FLAGS_DIRECT_IO; /* memfds don't support O_DIRECT, hence LO_FLAGS_DIRECT_IO can't be used either */
fd = open(path, O_CLOEXEC|O_NONBLOCK|O_NOCTTY|O_RDONLY);
+3 -4
View File
@@ -576,11 +576,10 @@ int mstack_open_images(
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
_cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
r = loop_device_make(
r = loop_device_make_by_path_at(
m->what_fd,
FLAGS_SET(flags, MSTACK_RDONLY) ? O_RDONLY : O_RDWR,
/* offset= */ 0,
/* size= */ UINT64_MAX,
/* path= */ NULL,
FLAGS_SET(flags, MSTACK_RDONLY) ? O_RDONLY : -1,
/* sector_size= */ UINT32_MAX,
LO_FLAGS_PARTSCAN,
LOCK_SH,