[dm-devel] [PATCH] dm-integrity: fix deadlock with overlapping I/O

Mikulas Patocka mpatocka at redhat.com
Fri Apr 5 19:26:39 UTC 2019


Hi

I've found quite a serious bug in dm-integrity - it will deadlock when 
processing overlapping bios.

Please send this patch to Linus.

Mikulas



From: Mikulas Patocka <mpatocka at redhat.com>

dm-integrity could deadlock with overlapping I/O, the bug was introduced
by a patch 724376a04d1a ("dm integrity: implement fair range locks").
Apparently, few users use overlapping I/O, so the bug went undetected for
so long.

In order to fix the bug, we fix the typos in the function ranges_overlap
and we remove a flawed ranges_overlap check in remove_range_unlocked. This
condition could leave unprocessed bios hanging on wait_list forever.

Signed-off-by: Mikulas Patocka <mpatocka at redhat.com>
Cc: stable at vger.kernel.org	# v4.19+
Fixes: 724376a04d1a ("dm integrity: implement fair range locks")

---
 drivers/md/dm-integrity.c |    4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

Index: linux-2.6/drivers/md/dm-integrity.c
===================================================================
--- linux-2.6.orig/drivers/md/dm-integrity.c	2019-04-05 19:48:13.000000000 +0200
+++ linux-2.6/drivers/md/dm-integrity.c	2019-04-05 20:04:22.000000000 +0200
@@ -878,7 +878,7 @@ static void copy_from_journal(struct dm_
 static bool ranges_overlap(struct dm_integrity_range *range1, struct dm_integrity_range *range2)
 {
 	return range1->logical_sector < range2->logical_sector + range2->n_sectors &&
-	       range2->logical_sector + range2->n_sectors > range2->logical_sector;
+	       range1->logical_sector + range1->n_sectors > range2->logical_sector;
 }
 
 static bool add_new_range(struct dm_integrity_c *ic, struct dm_integrity_range *new_range, bool check_waiting)
@@ -924,8 +924,6 @@ static void remove_range_unlocked(struct
 		struct dm_integrity_range *last_range =
 			list_first_entry(&ic->wait_list, struct dm_integrity_range, wait_entry);
 		struct task_struct *last_range_task;
-		if (!ranges_overlap(range, last_range))
-			break;
 		last_range_task = last_range->task;
 		list_del(&last_range->wait_entry);
 		if (!add_new_range(ic, last_range, false)) {




More information about the dm-devel mailing list