From: Lennart Poettering Date: Tue, 5 Apr 2022 16:56:47 +0000 (+0200) Subject: loop-util: take a LOCK_EX BSD file lock on control device while we acquire a loopback... X-Git-Tag: v251-rc2~165^2~6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cc53046620ac193a2d963761ff30a2bb4bf6ddb0;p=thirdparty%2Fsystemd.git loop-util: take a LOCK_EX BSD file lock on control device while we acquire a loopback device --- diff --git a/src/shared/loop-util.c b/src/shared/loop-util.c index e5c7acb4708..4f9c2de5773 100644 --- a/src/shared/loop-util.c +++ b/src/shared/loop-util.c @@ -514,6 +514,17 @@ static int loop_device_make_internal( for (unsigned n_attempts = 0;;) { _cleanup_close_ int loop = -1; + /* Let's take a lock on the control device first. On a busy system, where many programs + * attempt to allocate a loopback device at the same time, we might otherwise keep looping + * around relatively heavy operations: asking for a free loopback device, then opening it, + * validating it, attaching something to it. Let's serialize this whole operation, to make + * unnecessary busywork less likely. Note that this is just something we do to optimize our + * own code (and whoever else decides to use LOCK_EX locks for this), taking this lock is not + * necessary, it just means it's less likely we have to iterate through this loop again and + * again if our own code races against our own code. */ + if (flock(control, LOCK_EX) < 0) + return -errno; + nr = ioctl(control, LOOP_CTL_GET_FREE); if (nr < 0) return -errno; @@ -542,6 +553,11 @@ static int loop_device_make_internal( return r; } + /* OK, this didn't work, let's try again a bit later, but first release the lock on the + * control device */ + if (flock(control, LOCK_UN) < 0) + return -errno; + if (++n_attempts >= 64) /* Give up eventually */ return -EBUSY;