summaryrefslogtreecommitdiff
path: root/src/shared/loop-util.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2022-09-01 12:32:48 +0200
committerLennart Poettering <lennart@poettering.net>2022-09-01 20:41:08 +0200
commit3a6ed1e19d2929270e8cd11375d5d34072336450 (patch)
treeebdb61d9b4bb94e4696668e4b5a844f5e52deb14 /src/shared/loop-util.c
parentff27ef4b598ca6b26381c6abc124641a228f0d85 (diff)
downloadsystemd-3a6ed1e19d2929270e8cd11375d5d34072336450.tar.gz
loop-util: when clearing a loopback device delete partitions first, and take BSD lock
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.
Diffstat (limited to 'src/shared/loop-util.c')
-rw-r--r--src/shared/loop-util.c20
1 files changed, 18 insertions, 2 deletions
diff --git a/src/shared/loop-util.c b/src/shared/loop-util.c
index 724e05b7d2..d6999ffa75 100644
--- a/src/shared/loop-util.c
+++ b/src/shared/loop-util.c
@@ -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);