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);