]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
losetup: avoid infinite busy loop
authorKarel Zak <kzak@redhat.com>
Tue, 13 Oct 2020 08:31:42 +0000 (10:31 +0200)
committerKarel Zak <kzak@redhat.com>
Tue, 13 Oct 2020 08:58:04 +0000 (10:58 +0200)
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>
sys-utils/losetup.8
sys-utils/losetup.c

index c3ff5fe06bfa2203042ae2aa2a8d8c3ec948bf7d..3d03e513f60a2b2b47c26de272e4bb0b30de5235 100644 (file)
@@ -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
index cc4d206b760f46bfcfb3f68b23443c4288e696c9..51baf1440847a1d440776602d8553f9611cd9123 100644 (file)
@@ -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 ?