From: Lennart Poettering Date: Tue, 13 Oct 2020 12:37:39 +0000 (+0200) Subject: loop-util: wait a random time before trying again X-Git-Tag: v247-rc1~13^2~1 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=b202ec20688cd0abe3f4b2e35cf6002c8bc45189;p=thirdparty%2Fsystemd.git loop-util: wait a random time before trying again 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) --- diff --git a/src/shared/loop-util.c b/src/shared/loop-util.c index 091a304755f..1c92fdbf5f0 100644 --- a/src/shared/loop-util.c +++ b/src/shared/loop-util.c @@ -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);