From: Lennart Poettering Date: Mon, 24 Aug 2020 16:11:06 +0000 (+0200) Subject: loop-util: LOOP_CONFIGURE ignores lo_sizelimit X-Git-Tag: v247-rc1~369^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=refs%2Fpull%2F16676%2Fhead;p=thirdparty%2Fsystemd.git loop-util: LOOP_CONFIGURE ignores lo_sizelimit 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!) --- diff --git a/src/shared/loop-util.c b/src/shared/loop-util.c index fb88f51849a..fcbd5a5f79f 100644 --- a/src/shared/loop-util.c +++ b/src/shared/loop-util.c @@ -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);