From: Daan De Meyer Date: Mon, 30 Mar 2026 13:51:48 +0000 (+0000) Subject: loop-util: use auto-detect open mode for loop device setup X-Git-Tag: v261-rc1~675 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=614509699a258154b3d08b76cb2fe30d4ed746dd;p=thirdparty%2Fsystemd.git 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). --- diff --git a/src/dissect/dissect.c b/src/dissect/dissect.c index bcfd7f5a816..26fa1aa1a38 100644 --- a/src/dissect/dissect.c +++ b/src/dissect/dissect.c @@ -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) diff --git a/src/mountfsd/mountwork.c b/src/mountfsd/mountwork.c index f3f80b1c274..3856e9da94c 100644 --- a/src/mountfsd/mountwork.c +++ b/src/mountfsd/mountwork.c @@ -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, diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 1740ab4d6eb..a778a25aa5e 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -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, diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index 4a8d4a5c0e0..94d6f0545d4 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -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, diff --git a/src/shared/loop-util.c b/src/shared/loop-util.c index 8c924296488..fbed79bb2ec 100644 --- a/src/shared/loop-util.c +++ b/src/shared/loop-util.c @@ -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); diff --git a/src/shared/mstack.c b/src/shared/mstack.c index e5dcd91e525..32e95fd2309 100644 --- a/src/shared/mstack.c +++ b/src/shared/mstack.c @@ -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,