From: Karel Zak Date: Tue, 13 Oct 2020 08:31:42 +0000 (+0200) Subject: losetup: avoid infinite busy loop X-Git-Tag: v2.37-rc1~429 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=3ff6fb802de1efafbd90af228f91461691ac190c;p=thirdparty%2Futil-linux.git 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 Signed-off-by: Karel Zak --- diff --git a/sys-utils/losetup.8 b/sys-utils/losetup.8 index c3ff5fe06b..3d03e513f6 100644 --- a/sys-utils/losetup.8 +++ b/sys-utils/losetup.8 @@ -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 diff --git a/sys-utils/losetup.c b/sys-utils/losetup.c index cc4d206b76..51baf14408 100644 --- a/sys-utils/losetup.c +++ b/sys-utils/losetup.c @@ -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 ?