From cc53046620ac193a2d963761ff30a2bb4bf6ddb0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 5 Apr 2022 18:56:47 +0200 Subject: [PATCH] loop-util: take a LOCK_EX BSD file lock on control device while we acquire a loopback device --- src/shared/loop-util.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) 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; -- 2.47.3