[dm-devel] [PATCH] dm-bufio: avoid a possible deadlock due to lock ordering

Mikulas Patocka mpatocka at redhat.com
Sun Apr 30 21:33:26 UTC 2017


The function __get_memory_limit tests if dm_bufio_cache_size changed and
calls __cache_size_refresh if it did. It takes dm_bufio_clients_lock while
it already holds the client lock. However, lock ordering is violated
because in the function cleanup_old_buffers dm_bufio_clients_lock is taken
before the client lock.

This results in a possible deadlock and lockdep engine warning.

This patch fixes the deadlock by changing mutex_lock to mutex_trylock. If
the lock can't be taken, it will be re-checked next time when a new buffer
is be allocated. The patch also adds "unlikely" to the if confition, so
that the optimizer assumes that the condition is false.

Signed-off-by: Mikulas Patocka <mpatocka at redhat.com>
Cc: stable at vger.kernel.org

---
 drivers/md/dm-bufio.c |    9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

Index: linux-2.6/drivers/md/dm-bufio.c
===================================================================
--- linux-2.6.orig/drivers/md/dm-bufio.c
+++ linux-2.6/drivers/md/dm-bufio.c
@@ -959,10 +959,11 @@ static void __get_memory_limit(struct dm
 {
 	unsigned long buffers;
 
-	if (ACCESS_ONCE(dm_bufio_cache_size) != dm_bufio_cache_size_latch) {
-		mutex_lock(&dm_bufio_clients_lock);
-		__cache_size_refresh();
-		mutex_unlock(&dm_bufio_clients_lock);
+	if (unlikely(ACCESS_ONCE(dm_bufio_cache_size) != dm_bufio_cache_size_latch)) {
+		if (mutex_trylock(&dm_bufio_clients_lock)) {
+			__cache_size_refresh();
+			mutex_unlock(&dm_bufio_clients_lock);
+		}
 	}
 
 	buffers = dm_bufio_cache_size_per_client >>




More information about the dm-devel mailing list