Yes, this is an old bug.  :)

If anyone is interested, here's my own solution to this problem; the
idea is simply to add some randomness to the interval between locking
attempts.

In my experience with a 4-in-1 device, the first interval is scattered
enough for all attempts to go through on the first retry.  Still, a
12-in-1 device or a slower system may require some more wiggle room; I
left the maximum number of retries to 3, which now translates to a total
wait time of up to 7 seconds.

This should also alleviate (but not resolve) #658028 ("Udev should not
wait for mounting").

>From d246ff9b4e622af3d18c93b2f612de336a204ca5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Bri=C3=A8re?= <[email protected]>
Date: Mon, 29 Sep 2014 16:35:46 -0400
Subject: [PATCH] Add some randomness to the interval between locking attempts

This ensures that when several instances of usbmount are launched at the
same time (which is often the case for N-in-1 memory card readers),
their attempts to acquire the lock will be scattered, to avoid competing
with each other.
---
 usbmount | 50 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 49 insertions(+), 1 deletion(-)

diff --git a/usbmount b/usbmount
index ee297bb..67e376e 100755
--- a/usbmount
+++ b/usbmount
@@ -75,11 +75,59 @@ fi
 umask 022
 
 
+# lockfile_create_random <retry-count> <lockfile-create-arguments>
+#
+# Like lockfile-create(1), but with a variable amount of time between
+# attempts.  Each retry attempt will be delayed by a random amount of time
+# between 0 and 2^(N-1) seconds for the Nth retry, up to <retry-count> times.
+#
+# All <lockfile-create-arguments> will be passed as-is to lockfile-create.
+
+lockfile_create_random() {
+	RETRY_COUNT=$1
+	shift
+
+	# Maximum (integer) number of seconds before the next attempt
+	MAX_WAIT=1
+
+	# Attempt to acquire the lock (capturing any error message)
+	until ERR_MSG="$(lockfile-create --retry 0 "$@" 2>&1)"; do
+		RETVAL=$?
+
+		# Abort on any error other than L_MAXTRYS
+		if [ $RETVAL -ne 4 ]; then
+			# Rethrow the error message output by lockfile-create
+			log err "$ERR_MSG"
+			return $RETVAL
+		fi
+		# Also quit on L_MAXTRYS after the maximum number of attempts
+		if [ $RETRY_COUNT -eq 0 ]; then
+			return $RETVAL
+		fi
+
+		# Generate a random (32-bit) number -- copied from (thanks!):
+		# http://www.linuxquestions.org/questions/programming-9/shell-script-random-variable-4088/#post2975909
+		RAND=$(dd if=/dev/urandom count=1 2>/dev/null | cksum | cut -f1 -d" ")
+		# Turn it into a decimal number between 0 and $MAX_WAIT
+		# (Granted, the resulting value is not *truly* random.  <g>)
+		SLEEP_TIME=$(expr $RAND % $MAX_WAIT).$(expr $RAND % 1000)
+
+		log debug "lock unavailable; sleeping $SLEEP_TIME seconds before retrying"
+		sleep $SLEEP_TIME
+
+		MAX_WAIT=$(expr $MAX_WAIT \* 2)
+		RETRY_COUNT=$(expr $RETRY_COUNT - 1)
+	done
+
+	# Lock successfully acquired
+	return 0
+}
+
 if [ "$1" = add ]; then
 
     # Acquire lock.
     log debug "trying to acquire lock /var/run/usbmount/.mount.lock"
-    lockfile-create --retry 3 /var/run/usbmount/.mount || \
+    lockfile_create_random 3 /var/run/usbmount/.mount || \
 	{ log err "cannot acquire lock /var/run/usbmount/.mount.lock"; exit 1; }
     trap '( lockfile-remove /var/run/usbmount/.mount )' 0
     log debug "acquired lock /var/run/usbmount/.mount.lock"
-- 
2.1.1

Reply via email to