]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
loop-util: wait a random time before trying again
authorLennart Poettering <lennart@poettering.net>
Tue, 13 Oct 2020 12:37:39 +0000 (14:37 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 22 Oct 2020 12:58:28 +0000 (14:58 +0200)
Let's try to make collisions when multiple clients want to use the same
device less likely, by sleeping a random time on collision.

The loop device allocation protocol is inherently collision prone:
first, a program asks which is the next free loop device, then it tries
to acquire it, in a separate, unsynchronized setp. If many peers do this
all at the same time, they'll likely all collide when trying to
acquire the device, so that they need to ask for a free device again and
again.

Let's make this a little less prone to collisions, reducing the number
of failing attempts: whenever we notice a collision we'll now wait
short and randomized time, making it more likely another peer succeeds.

(This also adds a similar logic when retrying LOOP_SET_STATUS64, but
with a slightly altered calculation, since there we definitely want to
wait a bit, under all cases)

src/shared/loop-util.c

index 091a304755f0279150df2dabf257f91818b4570f..1c92fdbf5f0c2116a87e87a16346c5060c6343f2 100644 (file)
@@ -24,6 +24,7 @@
 #include "loop-util.h"
 #include "missing_loop.h"
 #include "parse-util.h"
+#include "random-util.h"
 #include "stat-util.h"
 #include "stdio-util.h"
 #include "string-util.h"
@@ -248,7 +249,10 @@ static int loop_configure(
                         goto fail;
                 }
 
-                (void) usleep(50 * USEC_PER_MSEC);
+                /* Sleep some random time, but at least 10ms, at most 250ms. Increase the delay the more
+                 * failed attempts we see */
+                (void) usleep(UINT64_C(10) * USEC_PER_MSEC +
+                              random_u64() % (UINT64_C(240) * USEC_PER_MSEC * n_attempts/64));
         }
 
         return 0;
@@ -414,6 +418,11 @@ int loop_device_make(
                         return -EBUSY;
 
                 loopdev = mfree(loopdev);
+
+                /* Wait some random time, to make collision less likely. Let's pick a random time in the
+                 * range 0ms…250ms, linearly scaled by the number of failed attempts. */
+                (void) usleep(random_u64() % (UINT64_C(10) * USEC_PER_MSEC +
+                                              UINT64_C(240) * USEC_PER_MSEC * n_attempts/64));
         }
 
         d = new(LoopDevice, 1);