]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
loop-util: use auto-detect open mode for loop device setup
authorDaan De Meyer <daan@amutable.com>
Mon, 30 Mar 2026 13:51:48 +0000 (13:51 +0000)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Wed, 1 Apr 2026 08:02:15 +0000 (10:02 +0200)
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).

src/dissect/dissect.c
src/mountfsd/mountwork.c
src/nspawn/nspawn.c
src/shared/dissect-image.c
src/shared/loop-util.c
src/shared/mstack.c

index bcfd7f5a816e12ccb4bcaf992e83c19d5d40eb4b..26fa1aa1a383e4ba6553c87b175da6577aaf7da7 100644 (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)
index f3f80b1c2742859bfdd9f9cf4d919e0e86a0075f..3856e9da94c0464ba6d2849294b6687a4944aba1 100644 (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,
index 1740ab4d6eb18e0d189ba24e4e682ca180554f71..a778a25aa5e0e5ddf0279411bf388dac9dc4fc2c 100644 (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,
index 4a8d4a5c0e021ebf2b3b2a2bfbccfeb92d80538a..94d6f0545d4e1e0615e581ececdd340a59463ca1 100644 (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,
index 8c924296488d2e88484b879aa2280488817fa225..fbed79bb2ec16efc56a89c86fb69ddc0ab11d6b0 100644 (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);
index e5dcd91e525a92d67d4b1623c2bc76cabf46e1d1..32e95fd23096e6cb76684239a22d2178ccdc1947 100644 (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,