Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

dm raid1: use timer



This patch replaces the schedule() in the main kmirrord thread with a timer.
The schedule() could introduce an unwanted delay when work is ready to be
processed.

The code instead calls wake() when there's work to be done immediately, and
delayed_wake() after a failure to give a short delay before retrying.

Signed-off-by: default avatarMikulas Patocka <mpatocka@redhat.com>
Signed-off-by: default avatarAlasdair G Kergon <agk@redhat.com>
parent a765e20e
Loading
Loading
Loading
Loading
+28 −20
Original line number Diff line number Diff line
@@ -154,6 +154,9 @@ struct mirror_set {

	struct workqueue_struct *kmirrord_wq;
	struct work_struct kmirrord_work;
	struct timer_list timer;
	unsigned long timer_pending;

	struct work_struct trigger_event;

	unsigned int nr_mirrors;
@@ -178,6 +181,25 @@ static void wake(struct mirror_set *ms)
	queue_work(ms->kmirrord_wq, &ms->kmirrord_work);
}

static void delayed_wake_fn(unsigned long data)
{
	struct mirror_set *ms = (struct mirror_set *) data;

	clear_bit(0, &ms->timer_pending);
	wake(ms);
}

static void delayed_wake(struct mirror_set *ms)
{
	if (test_and_set_bit(0, &ms->timer_pending))
		return;

	ms->timer.expires = jiffies + HZ / 5;
	ms->timer.data = (unsigned long) ms;
	ms->timer.function = delayed_wake_fn;
	add_timer(&ms->timer);
}

/* FIXME move this */
static void queue_bio(struct mirror_set *ms, struct bio *bio, int rw);

@@ -1180,6 +1202,7 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes)
		spin_lock_irq(&ms->lock);
		bio_list_merge(&ms->failures, &sync);
		spin_unlock_irq(&ms->lock);
		wake(ms);
	} else
		while ((bio = bio_list_pop(&sync)))
			do_write(ms, bio);
@@ -1239,7 +1262,7 @@ static void do_failures(struct mirror_set *ms, struct bio_list *failures)
	bio_list_merge(&ms->failures, failures);
	spin_unlock_irq(&ms->lock);

	wake(ms);
	delayed_wake(ms);
}

static void trigger_event(struct work_struct *work)
@@ -1253,7 +1276,7 @@ static void trigger_event(struct work_struct *work)
/*-----------------------------------------------------------------
 * kmirrord
 *---------------------------------------------------------------*/
static int _do_mirror(struct work_struct *work)
static void do_mirror(struct work_struct *work)
{
	struct mirror_set *ms =container_of(work, struct mirror_set,
					    kmirrord_work);
@@ -1274,24 +1297,6 @@ static int _do_mirror(struct work_struct *work)
	do_reads(ms, &reads);
	do_writes(ms, &writes);
	do_failures(ms, &failures);

	return (ms->failures.head) ? 1 : 0;
}

static void do_mirror(struct work_struct *work)
{
	/*
	 * If _do_mirror returns 1, we give it
	 * another shot.  This helps for cases like
	 * 'suspend' where we call flush_workqueue
	 * and expect all work to be finished.  If
	 * a failure happens during a suspend, we
	 * couldn't issue a 'wake' because it would
	 * not be honored.  Therefore, we return '1'
	 * from _do_mirror, and retry here.
	 */
	while (_do_mirror(work))
		schedule();
}


@@ -1545,6 +1550,8 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
		goto err_free_context;
	}
	INIT_WORK(&ms->kmirrord_work, do_mirror);
	init_timer(&ms->timer);
	ms->timer_pending = 0;
	INIT_WORK(&ms->trigger_event, trigger_event);

	r = parse_features(ms, argc, argv, &args_used);
@@ -1587,6 +1594,7 @@ static void mirror_dtr(struct dm_target *ti)
{
	struct mirror_set *ms = (struct mirror_set *) ti->private;

	del_timer_sync(&ms->timer);
	flush_workqueue(ms->kmirrord_wq);
	dm_kcopyd_client_destroy(ms->kcopyd_client);
	destroy_workqueue(ms->kmirrord_wq);