+ if (*fd < 0)
+ return;
+
+ (void) ioctl(*fd, LOOP_CLR_FD);
+ (void) safe_close(*fd);
+}
+
+static int loop_configure(int fd, const struct loop_config *c) {
+ int r;
+
+ assert(fd >= 0);
+ assert(c);
+
+ if (ioctl(fd, LOOP_CONFIGURE, c) < 0) {
+ /* Do fallback only if LOOP_CONFIGURE is not supported, propagate all other errors. Note that
+ * the kernel is weird: non-existing ioctls currently return EINVAL rather than ENOTTY on
+ * loopback block devices. They should fix that in the kernel, but in the meantime we accept
+ * both here. */
+ if (!ERRNO_IS_NOT_SUPPORTED(errno) && errno != EINVAL)
+ return -errno;
+ } else {
+ if (!FLAGS_SET(c->info.lo_flags, LO_FLAGS_PARTSCAN))
+ return 0;
+
+ /* 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)
+ return 0; /* All is good. */
+
+ /* Otherwise, undo the attachment and use the old APIs */
+ (void) ioctl(fd, LOOP_CLR_FD);
+ }
+
+ if (ioctl(fd, LOOP_SET_FD, c->fd) < 0)
+ return -errno;
+
+ if (ioctl(fd, LOOP_SET_STATUS64, &c->info) < 0) {
+ r = -errno;
+ goto fail;