Commit 04788507 authored by Mikulas Patocka's avatar Mikulas Patocka Committed by Alasdair G Kergon
Browse files

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: default avatarMikulas Patocka <mpatocka@redhat.com>
Reviewed-by: default avatarTakahiro Yasui <tyasui@redhat.com>
Tested-by: default avatarTakahiro Yasui <tyasui@redhat.com>
Signed-off-by: default avatarAlasdair G Kergon <agk@redhat.com>
parent 64b30c46
Loading
Loading
Loading
Loading
+41 −0
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ struct mirror_set {
	struct bio_list reads;
	struct bio_list writes;
	struct bio_list failures;
	struct bio_list holds;	/* bios are waiting until suspend */

	struct dm_region_hash *rh;
	struct dm_kcopyd_client *kcopyd_client;
@@ -450,6 +451,27 @@ static void map_region(struct dm_io_region *io, struct mirror *m,
	io->count = bio->bi_size >> 9;
}

static void hold_bio(struct mirror_set *ms, struct bio *bio)
{
	/*
	 * If device is suspended, complete the bio.
	 */
	if (atomic_read(&ms->suspend)) {
		if (dm_noflush_suspending(ms->ti))
			bio_endio(bio, DM_ENDIO_REQUEUE);
		else
			bio_endio(bio, -EIO);
		return;
	}

	/*
	 * Hold bio until the suspend is complete.
	 */
	spin_lock_irq(&ms->lock);
	bio_list_add(&ms->holds, bio);
	spin_unlock_irq(&ms->lock);
}

/*-----------------------------------------------------------------
 * Reads
 *---------------------------------------------------------------*/
@@ -1225,6 +1247,9 @@ static void mirror_presuspend(struct dm_target *ti)
	struct mirror_set *ms = (struct mirror_set *) ti->private;
	struct dm_dirty_log *log = dm_rh_dirty_log(ms->rh);

	struct bio_list holds;
	struct bio *bio;

	atomic_set(&ms->suspend, 1);

	/*
@@ -1247,6 +1272,22 @@ static void mirror_presuspend(struct dm_target *ti)
	 * we know that all of our I/O has been pushed.
	 */
	flush_workqueue(ms->kmirrord_wq);

	/*
	 * Now set ms->suspend is set and the workqueue flushed, no more
	 * entries can be added to ms->hold list, so process it.
	 *
	 * Bios can still arrive concurrently with or after this
	 * presuspend function, but they cannot join the hold list
	 * because ms->suspend is set.
	 */
	spin_lock_irq(&ms->lock);
	holds = ms->holds;
	bio_list_init(&ms->holds);
	spin_unlock_irq(&ms->lock);

	while ((bio = bio_list_pop(&holds)))
		hold_bio(ms, bio);
}

static void mirror_postsuspend(struct dm_target *ti)