diff options
author | Lennart Poettering <lennart@poettering.net> | 2022-09-01 12:32:48 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2022-09-01 20:41:08 +0200 |
commit | 3a6ed1e19d2929270e8cd11375d5d34072336450 (patch) | |
tree | ebdb61d9b4bb94e4696668e4b5a844f5e52deb14 /src/shared/loop-util.c | |
parent | ff27ef4b598ca6b26381c6abc124641a228f0d85 (diff) | |
download | systemd-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.c | 20 |
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); |