A framework for holding bios until suspend and then resubmitting them with either DM_ENDIO_REQUEUE (if the suspend was noflush) or terminating them with -EIO. The bio can be held with the function hold_bio. So far it is unused, it will be used in later patches. Signed-off-by: Mikulas Patocka --- drivers/md/dm-raid1.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) 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)