diff options
author | Lennart Poettering <lennart@poettering.net> | 2019-05-21 18:13:55 +0200 |
---|---|---|
committer | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2019-05-22 13:04:26 +0200 |
commit | 0f6519d43c37d5a855a6c9be52148908c15c3c9d (patch) | |
tree | 756ca6c884a601240ad656d01be7973d41baf202 | |
parent | 0307afc681e1078dd14c202b0e9be5fd09a06a38 (diff) | |
download | systemd-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.c | 33 |
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; |