summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2019-05-21 18:13:55 +0200
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2019-05-22 13:04:26 +0200
commit0f6519d43c37d5a855a6c9be52148908c15c3c9d (patch)
tree756ca6c884a601240ad656d01be7973d41baf202
parent0307afc681e1078dd14c202b0e9be5fd09a06a38 (diff)
downloadsystemd-0f6519d43c37d5a855a6c9be52148908c15c3c9d.tar.gz
loop-util: invoke LOOP_CTL_GET_FREE in a loop
if we don't call it in a loop the device it tells us to open might already be gone, taken by somebody else racing against us. Hence try a few times.
-rw-r--r--src/shared/loop-util.c33
1 files changed, 23 insertions, 10 deletions
diff --git a/src/shared/loop-util.c b/src/shared/loop-util.c
index bf426eb8bc..22525d5c63 100644
--- a/src/shared/loop-util.c
+++ b/src/shared/loop-util.c
@@ -18,6 +18,7 @@ int loop_device_make(int fd, int open_flags, LoopDevice **ret) {
_cleanup_close_ int control = -1, loop = -1;
_cleanup_free_ char *loopdev = NULL;
+ unsigned n_attempts = 0;
struct stat st;
LoopDevice *d;
int nr, r;
@@ -60,19 +61,31 @@ int loop_device_make(int fd, int open_flags, LoopDevice **ret) {
if (control < 0)
return -errno;
- nr = ioctl(control, LOOP_CTL_GET_FREE);
- if (nr < 0)
- return -errno;
+ /* Loop around LOOP_CTL_GET_FREE, since at the moment we attempt to open the returned device it might
+ * be gone already, taken by somebody else racing against us. */
+ for (;;) {
+ nr = ioctl(control, LOOP_CTL_GET_FREE);
+ if (nr < 0)
+ return -errno;
- if (asprintf(&loopdev, "/dev/loop%i", nr) < 0)
- return -ENOMEM;
+ if (asprintf(&loopdev, "/dev/loop%i", nr) < 0)
+ return -ENOMEM;
- loop = open(loopdev, O_CLOEXEC|O_NONBLOCK|O_NOCTTY|open_flags);
- if (loop < 0)
- return -errno;
+ loop = open(loopdev, O_CLOEXEC|O_NONBLOCK|O_NOCTTY|open_flags);
+ if (loop < 0)
+ return -errno;
+ if (ioctl(loop, LOOP_SET_FD, fd) < 0) {
+ if (errno != EBUSY)
+ return -errno;
- if (ioctl(loop, LOOP_SET_FD, fd) < 0)
- return -errno;
+ if (++n_attempts >= 64) /* Give up eventually */
+ return -EBUSY;
+ } else
+ break;
+
+ loopdev = mfree(loopdev);
+ loop = safe_close(loop);
+ }
if (ioctl(loop, LOOP_SET_STATUS64, &info) < 0)
return -errno;