]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
loop-util: LOOP_CONFIGURE ignores lo_sizelimit 16676/head
authorLennart Poettering <lennart@poettering.net>
Mon, 24 Aug 2020 16:11:06 +0000 (18:11 +0200)
committerLennart Poettering <lennart@poettering.net>
Mon, 24 Aug 2020 20:01:13 +0000 (22:01 +0200)
It appears LOOP_CONFIGURE in 5.8 is even more broken than initially
thought: it doesn't properly propgate lo_sizelimit to the block device
layer. :-(

Let's hence check the block device size immediately after issuing
LOOP_CONFIGURE, and if it doesn't match what we just set let's fallback
to the old ioctls.

This means LOOP_CONFIGURE currently works correctly only for the most
simply case: no partition table logic and no size limit. Sad!

(Kernel people should really be told about the concepts of tests and
even CI, one day!)

src/shared/loop-util.c

index fb88f51849a70f1e0fb8c3d4e59e77d81320c956..fcbd5a5f79ffea6dfb721beecf3b06460a3d3bf6 100644 (file)
@@ -47,17 +47,41 @@ static int loop_configure(int fd, const struct loop_config *c) {
                 if (!ERRNO_IS_NOT_SUPPORTED(errno) && errno != EINVAL)
                         return -errno;
         } else {
-                if (!FLAGS_SET(c->info.lo_flags, LO_FLAGS_PARTSCAN))
-                        return 0;
+                bool good = true;
 
-                /* Kernel 5.8 vanilla doesn't properly propagate the partition scanning flag into the
-                 * block device. Let's hence verify if things work correctly here before returning. */
+                if (c->info.lo_sizelimit != 0) {
+                        /* Kernel 5.8 vanilla doesn't properly propagate the size limit into the block
+                         * device. If it's used, let's immediately check if it had the desired effect
+                         * hence. And if not use classic LOOP_SET_STATUS64. */
+                        uint64_t z;
 
-                r = blockdev_partscan_enabled(fd);
-                if (r < 0)
-                        goto fail;
-                if (r > 0)
-                        return 0; /* All is good. */
+                        if (ioctl(fd, BLKGETSIZE64, &z) < 0) {
+                                r = -errno;
+                                goto fail;
+                        }
+
+                        if (z != c->info.lo_sizelimit) {
+                                log_debug("LOOP_CONFIGURE is broken, doesn't honour .lo_sizelimit. Falling back to LOOP_SET_STATUS64.");
+                                good = false;
+                        }
+                }
+
+                if (FLAGS_SET(c->info.lo_flags, LO_FLAGS_PARTSCAN)) {
+                        /* Kernel 5.8 vanilla doesn't properly propagate the partition scanning flag into the
+                         * block device. Let's hence verify if things work correctly here before
+                         * returning. */
+
+                        r = blockdev_partscan_enabled(fd);
+                        if (r < 0)
+                                goto fail;
+                        if (r == 0) {
+                                log_debug("LOOP_CONFIGURE is broken, doesn't honour LO_FLAGS_PARTSCAN. Falling back to LOOP_SET_STATUS64.");
+                                good = false;
+                        }
+                }
+
+                if (good)
+                        return 0;
 
                 /* Otherwise, undo the attachment and use the old APIs */
                 (void) ioctl(fd, LOOP_CLR_FD);