diff mbox

[2/7] A framework for holding bios until suspend

Message ID Pine.LNX.4.64.0911180710370.21358@hs20-bc2-1.build.redhat.com (mailing list archive)
State Accepted, archived
Delegated to: Alasdair Kergon
Headers show

Commit Message

Mikulas Patocka Nov. 18, 2009, 12:11 p.m. UTC
None
diff mbox

Patch

Index: linux-2.6.31-fast-new/drivers/md/dm-raid1.c
===================================================================
--- linux-2.6.31-fast-new.orig/drivers/md/dm-raid1.c	2009-10-06 18:15:10.000000000 +0200
+++ linux-2.6.31-fast-new/drivers/md/dm-raid1.c	2009-10-06 18:15:14.000000000 +0200
@@ -57,6 +57,7 @@  struct mirror_set {
 	struct bio_list reads;
 	struct bio_list writes;
 	struct bio_list failures;
+	struct bio_list hold;	/* bios are waiting until suspend */
 
 	struct dm_region_hash *rh;
 	struct dm_kcopyd_client *kcopyd_client;
@@ -415,6 +416,20 @@  static void map_region(struct dm_io_regi
 	io->count = bio->bi_size >> 9;
 }
 
+static void hold_bio(struct mirror_set *ms, struct bio *bio)
+{
+	if (atomic_read(&ms->suspend)) {
+		if (dm_noflush_suspending(ms->ti))
+			bio_endio(bio, DM_ENDIO_REQUEUE);
+		else
+			bio_endio(bio, -EIO);
+	} else {
+		spin_lock_irq(&ms->lock);
+		bio_list_add(&ms->hold, bio);
+		spin_unlock_irq(&ms->lock);
+	}
+}
+
 /*-----------------------------------------------------------------
  * Reads
  *---------------------------------------------------------------*/
@@ -760,6 +775,7 @@  static void do_mirror(struct work_struct
 	bio_list_init(&ms->reads);
 	bio_list_init(&ms->writes);
 	bio_list_init(&ms->failures);
+	bio_list_init(&ms->hold);
 	spin_unlock_irqrestore(&ms->lock, flags);
 
 	dm_rh_update_states(ms->rh, errors_handled(ms));
@@ -1192,6 +1208,9 @@  static void mirror_presuspend(struct dm_
 	struct mirror_set *ms = (struct mirror_set *) ti->private;
 	struct dm_dirty_log *log = dm_rh_dirty_log(ms->rh);
 
+	struct bio_list hold;
+	struct bio *bio;
+
 	atomic_set(&ms->suspend, 1);
 
 	/*
@@ -1214,6 +1233,23 @@  static void mirror_presuspend(struct dm_
 	 * we know that all of our I/O has been pushed.
 	 */
 	flush_workqueue(ms->kmirrord_wq);
+
+	/*
+	 * Once we set ms->suspend and flush the workqueue,
+	 * no more entries are being added to ms->hold list.
+	 * Process the list now.
+	 *
+	 * (note that bios can still arive concurrently with
+	 * or after presuspend, but they are never put to
+	 * hold list because of ms->suspend != 0).
+	 */
+	spin_lock_irq(&ms->lock);
+	hold = ms->hold;
+	bio_list_init(&ms->hold);
+	spin_unlock_irq(&ms->lock);
+
+	while ((bio = bio_list_pop(&hold)))
+		hold_bio(ms, bio);
 }
 
 static void mirror_postsuspend(struct dm_target *ti)