aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMikulas Patocka <mpatocka@redhat.com>2009-12-10 18:52:03 -0500
committerAlasdair G Kergon <agk@redhat.com>2009-12-10 18:52:03 -0500
commit04788507686d184d8166918b70ef52311bc36dcb (patch)
treec17fb1f8f9ac8d2a137f9c523d059f5918940c93
parent64b30c46e866bbff8a9e17883a18636adc358455 (diff)
dm raid1: add framework to hold bios during suspend
Add framework to delay bios until a suspend and then resubmit them with either DM_ENDIO_REQUEUE (if the suspend was noflush) or complete them with -EIO. I/O barrier support will use this. Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Reviewed-by: Takahiro Yasui <tyasui@redhat.com> Tested-by: Takahiro Yasui <tyasui@redhat.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com>
-rw-r--r--drivers/md/dm-raid1.c41
1 files changed, 41 insertions, 0 deletions
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index 85c8704c67bb..895cce75eee9 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -58,6 +58,7 @@ struct mirror_set {
58 struct bio_list reads; 58 struct bio_list reads;
59 struct bio_list writes; 59 struct bio_list writes;
60 struct bio_list failures; 60 struct bio_list failures;
61 struct bio_list holds; /* bios are waiting until suspend */
61 62
62 struct dm_region_hash *rh; 63 struct dm_region_hash *rh;
63 struct dm_kcopyd_client *kcopyd_client; 64 struct dm_kcopyd_client *kcopyd_client;
@@ -450,6 +451,27 @@ static void map_region(struct dm_io_region *io, struct mirror *m,
450 io->count = bio->bi_size >> 9; 451 io->count = bio->bi_size >> 9;
451} 452}
452 453
454static void hold_bio(struct mirror_set *ms, struct bio *bio)
455{
456 /*
457 * If device is suspended, complete the bio.
458 */
459 if (atomic_read(&ms->suspend)) {
460 if (dm_noflush_suspending(ms->ti))
461 bio_endio(bio, DM_ENDIO_REQUEUE);
462 else
463 bio_endio(bio, -EIO);
464 return;
465 }
466
467 /*
468 * Hold bio until the suspend is complete.
469 */
470 spin_lock_irq(&ms->lock);
471 bio_list_add(&ms->holds, bio);
472 spin_unlock_irq(&ms->lock);
473}
474
453/*----------------------------------------------------------------- 475/*-----------------------------------------------------------------
454 * Reads 476 * Reads
455 *---------------------------------------------------------------*/ 477 *---------------------------------------------------------------*/
@@ -1225,6 +1247,9 @@ static void mirror_presuspend(struct dm_target *ti)
1225 struct mirror_set *ms = (struct mirror_set *) ti->private; 1247 struct mirror_set *ms = (struct mirror_set *) ti->private;
1226 struct dm_dirty_log *log = dm_rh_dirty_log(ms->rh); 1248 struct dm_dirty_log *log = dm_rh_dirty_log(ms->rh);
1227 1249
1250 struct bio_list holds;
1251 struct bio *bio;
1252
1228 atomic_set(&ms->suspend, 1); 1253 atomic_set(&ms->suspend, 1);
1229 1254
1230 /* 1255 /*
@@ -1247,6 +1272,22 @@ static void mirror_presuspend(struct dm_target *ti)
1247 * we know that all of our I/O has been pushed. 1272 * we know that all of our I/O has been pushed.
1248 */ 1273 */
1249 flush_workqueue(ms->kmirrord_wq); 1274 flush_workqueue(ms->kmirrord_wq);
1275
1276 /*
1277 * Now set ms->suspend is set and the workqueue flushed, no more
1278 * entries can be added to ms->hold list, so process it.
1279 *
1280 * Bios can still arrive concurrently with or after this
1281 * presuspend function, but they cannot join the hold list
1282 * because ms->suspend is set.
1283 */
1284 spin_lock_irq(&ms->lock);
1285 holds = ms->holds;
1286 bio_list_init(&ms->holds);
1287 spin_unlock_irq(&ms->lock);
1288
1289 while ((bio = bio_list_pop(&holds)))
1290 hold_bio(ms, bio);
1250} 1291}
1251 1292
1252static void mirror_postsuspend(struct dm_target *ti) 1293static void mirror_postsuspend(struct dm_target *ti)