]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
loop-util: when clearing a loopback device delete partitions first, and take BSD...
authorLennart Poettering <lennart@poettering.net>
Thu, 1 Sep 2022 10:32:48 +0000 (12:32 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 1 Sep 2022 18:41:08 +0000 (20:41 +0200)
Whenever we release a loopback device, let's first synchronously delete
all partitions, so that we know that's complete and not done
asynchronously in the background. Take a BSD lock on the device while
doing so, so that udev won't make the devices busy while we do this.

src/shared/loop-util.c

index 724e05b7d2f075e917aeb76e8c61e8fd8d6a7737..d6999ffa757106daa7ee15f9cae29ab42140204a 100644 (file)
@@ -697,6 +697,8 @@ int loop_device_make_by_path(
 }
 
 LoopDevice* loop_device_unref(LoopDevice *d) {
+        int r;
+
         if (!d)
                 return NULL;
 
@@ -706,9 +708,23 @@ LoopDevice* loop_device_unref(LoopDevice *d) {
                         log_debug_errno(errno, "Failed to sync loop block device, ignoring: %m");
 
                 if (d->nr >= 0 && !d->relinquished) {
-                        if (ioctl(d->fd, LOOP_CLR_FD) < 0)
-                                log_debug_errno(errno, "Failed to clear loop device: %m");
+                        /* We are supposed to clear the loopback device. Let's do this synchronously: lock
+                         * the device, manually remove all partitions and then clear it. This should ensure
+                         * udev doesn't concurrently access the devices, and we can be reasonably sure that
+                         * once we are done here the device is cleared and all its partition children
+                         * removed. Note that we lock our primary device fd here (and not a separate locking
+                         * fd, as we do during allocation, since we want to keep the lock all the way through
+                         * the LOOP_CLR_FD, but that call would fail if we had more than one fd open.) */
 
+                        if (flock(d->fd, LOCK_EX) < 0)
+                                log_debug_errno(errno, "Failed to lock loop block device, ignoring: %m");
+
+                        r = block_device_remove_all_partitions(d->fd);
+                        if (r < 0)
+                                log_debug_errno(r, "Failed to remove partitions of loopback block device, ignoring: %m");
+
+                        if (ioctl(d->fd, LOOP_CLR_FD) < 0)
+                                log_debug_errno(errno, "Failed to clear loop device, ignoring: %m");
                 }
 
                 safe_close(d->fd);