From: Milan Broz <[email-masked]>

When processing the second part of a split bio resubmitted to the same
device we should skip the bookkeeping and avoid requesting io_lock
recursively.  Also fix a possible deadlock if the wait loop gets
interrupted.

Signed-off-by: Milan Broz <[email-masked]>
Signed-off-by: Alasdair G Kergon <[email-masked]>
---
 drivers/md/dm.c |   25 +++++++++++++++++++++----
 1 files changed, 21 insertions(+), 4 deletions(-)

Index: linux/drivers/md/dm.c
===================================================================
--- linux.orig/drivers/md/dm.c	2007-07-11 14:36:41.000000000 +0100
+++ linux/drivers/md/dm.c	2007-07-11 14:36:41.000000000 +0100
@@ -566,6 +566,12 @@ static int clone2_endio(struct bio *bio,
 	return error;
 }
 
+static int is_clone2(struct mapped_device *md, struct bio *bio)
+{
+	return (bio->bi_end_io == clone2_endio &&
+		bio->bi_private == md);
+}
+
 static sector_t max_io_len(struct mapped_device *md,
 			   sector_t sector, struct dm_target *ti)
 {
@@ -819,6 +825,15 @@ static int dm_request(request_queue_t *q
 		return 0;
 	}
 
+	/*
+	 * If this is the second part of a split bio,
+	 * always map it immediately.
+	 */
+	if (is_clone2(md, bio)) {
+		r = __split_bio(md, bio);
+		goto out_req;
+	}
+
 	down_read(&md->io_lock);
 
 	disk_stat_inc(dm_disk(md), ios[rw]);
@@ -1267,10 +1282,11 @@ EXPORT_SYMBOL_GPL(dm_put);
 /*
  * Process the deferred bios
  */
-static void __flush_deferred_io(struct mapped_device *md, struct bio *c)
+static void flush_deferred_io(struct mapped_device *md, struct bio *c)
 {
 	struct bio *n;
 
+	down_read(&md->io_lock);
 	while (c) {
 		n = c->bi_next;
 		c->bi_next = NULL;
@@ -1278,6 +1294,7 @@ static void __flush_deferred_io(struct m
 			bio_io_error(c, c->bi_size);
 		c = n;
 	}
+	up_read(&md->io_lock);
 }
 
 /*
@@ -1438,8 +1455,8 @@ int dm_suspend(struct mapped_device *md,
 	if (atomic_read(&md->pending)) {
 		clear_bit(DMF_BLOCK_IO, &md->flags);
 		def = bio_list_get(&md->deferred);
-		__flush_deferred_io(md, def);
 		up_write(&md->io_lock);
+		flush_deferred_io(md, def);
 		unlock_fs(md);
 		goto out; /* pushback list is already flushed, so skip flush */
 	}
@@ -1466,8 +1483,8 @@ flush_and_out:
 		spin_unlock_irqrestore(&md->pushback_lock, flags);
 
 		def = bio_list_get(&md->deferred);
-		__flush_deferred_io(md, def);
 		up_write(&md->io_lock);
+		flush_deferred_io(md, def);
 	}
 
 out:
@@ -1505,8 +1522,8 @@ int dm_resume(struct mapped_device *md)
 	clear_bit(DMF_BLOCK_IO, &md->flags);
 
 	def = bio_list_get(&md->deferred);
-	__flush_deferred_io(md, def);
 	up_write(&md->io_lock);
+	flush_deferred_io(md, def);
 
 	unlock_fs(md);