]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
loop-util: take a LOCK_EX BSD file lock on control device while we acquire a loopback...
authorLennart Poettering <lennart@poettering.net>
Tue, 5 Apr 2022 16:56:47 +0000 (18:56 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 7 Apr 2022 16:55:58 +0000 (18:55 +0200)
src/shared/loop-util.c

index e5c7acb4708ffa202d9820e020f8cab6fed41737..4f9c2de5773c08a353f748bac51c1e3c41625979 100644 (file)
@@ -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;