losetup: avoid infinite busy loop
issue report: if i run the heavy duty test from #16859 a couple of times I can get the loopback layer in the kernel into a state where there's a loopback block device allocated, that you can open, but where both LOOP_CLR_FD and _SET_FD fail with EBUSY. and /dev/loop-control still returns it as the next free one... weird state util-linux losetup when called to allocate a new device then freezes This commit: * restrict number of attempts to 16 * use 200000ms sleep between attempts * add note about non-atomic loop device setup to the man page Reported-by: Lennart Poettering <lennart@poettering.net> Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
parent
a83bea2d3d
commit
3ff6fb802d
|
@ -68,6 +68,13 @@ It's possible to create more independent loop devices for the same backing
|
|||
file.
|
||||
.B This setup may be dangerous, can cause data loss, corruption and overwrites.
|
||||
Use \fB\-\-nooverlap\fR with \fB\-\-find\fR during setup to avoid this problem.
|
||||
.sp
|
||||
The loop device setup is not an atomic operation when used with \fB\-\-find\fP, and
|
||||
.B losetup
|
||||
does not protect this operation by any lock. The number of attempts is
|
||||
internally restricted to a maximum of 16. It is recommended to use for example
|
||||
.BR flock (1)
|
||||
to avoid a collision in heavily parallel use cases.
|
||||
|
||||
.SH OPTIONS
|
||||
The \fIsize\fR and \fIoffset\fR
|
||||
|
@ -177,6 +184,11 @@ returns 0 on success, nonzero on failure. When
|
|||
displays the status of a loop device, it returns 1 if the device
|
||||
is not configured and 2 if an error occurred which prevented
|
||||
determining the status of the device.
|
||||
.SH NOTES
|
||||
Since version 2.37
|
||||
.B losetup
|
||||
uses LOOP_CONFIGURE ioctl to setup a new loop device by one ioctl call. The
|
||||
old versions use LOOP_SET_FD and LOOP_SET_STATUS64 ioctls to do the same.
|
||||
|
||||
.SH ENVIRONMENT
|
||||
.IP LOOPDEV_DEBUG=all
|
||||
|
|
|
@ -476,7 +476,7 @@ static int create_loop(struct loopdev_cxt *lc,
|
|||
uint64_t blocksize)
|
||||
{
|
||||
int hasdev = loopcxt_has_device(lc);
|
||||
int rc = 0;
|
||||
int rc = 0, ntries = 0;
|
||||
|
||||
/* losetup --find --noverlap file.img */
|
||||
if (!hasdev && nooverlap) {
|
||||
|
@ -572,8 +572,12 @@ static int create_loop(struct loopdev_cxt *lc,
|
|||
rc = loopcxt_setup_device(lc);
|
||||
if (rc == 0)
|
||||
break; /* success */
|
||||
if (errno == EBUSY && !hasdev)
|
||||
|
||||
if (errno == EBUSY && !hasdev && ntries < 16) {
|
||||
xusleep(200000);
|
||||
ntries++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* errors */
|
||||
errpre = hasdev && loopcxt_get_fd(lc) < 0 ?
|
||||
|
|
Loading…
Reference in New Issue