[PATCH] dm: raid1: fix waiting for io on suspend
All device-mapper targets must complete outstanding I/O before suspending. The mirror target generates I/O in its recovery phase and fails to wait for it. It needs to be tracked so we can ensure that it has completed before we suspend. [akpm@osdl.org: cleanup] Signed-off-by: Jonathan E Brassow <jbrassow@redhat.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com> Cc: <dm-devel@redhat.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
5d55fdf949
commit
33184048dc
|
@ -24,6 +24,7 @@
|
|||
|
||||
static struct workqueue_struct *_kmirrord_wq;
|
||||
static struct work_struct _kmirrord_work;
|
||||
static DECLARE_WAIT_QUEUE_HEAD(_kmirrord_recovery_stopped);
|
||||
|
||||
static inline void wake(void)
|
||||
{
|
||||
|
@ -83,6 +84,7 @@ struct region_hash {
|
|||
struct list_head *buckets;
|
||||
|
||||
spinlock_t region_lock;
|
||||
atomic_t recovery_in_flight;
|
||||
struct semaphore recovery_count;
|
||||
struct list_head clean_regions;
|
||||
struct list_head quiesced_regions;
|
||||
|
@ -191,6 +193,7 @@ static int rh_init(struct region_hash *rh, struct mirror_set *ms,
|
|||
|
||||
spin_lock_init(&rh->region_lock);
|
||||
sema_init(&rh->recovery_count, 0);
|
||||
atomic_set(&rh->recovery_in_flight, 0);
|
||||
INIT_LIST_HEAD(&rh->clean_regions);
|
||||
INIT_LIST_HEAD(&rh->quiesced_regions);
|
||||
INIT_LIST_HEAD(&rh->recovered_regions);
|
||||
|
@ -382,6 +385,8 @@ static void rh_update_states(struct region_hash *rh)
|
|||
rh->log->type->clear_region(rh->log, reg->key);
|
||||
rh->log->type->complete_resync_work(rh->log, reg->key, 1);
|
||||
dispatch_bios(rh->ms, ®->delayed_bios);
|
||||
if (atomic_dec_and_test(&rh->recovery_in_flight))
|
||||
wake_up_all(&_kmirrord_recovery_stopped);
|
||||
up(&rh->recovery_count);
|
||||
mempool_free(reg, rh->region_pool);
|
||||
}
|
||||
|
@ -502,11 +507,21 @@ static int __rh_recovery_prepare(struct region_hash *rh)
|
|||
|
||||
static void rh_recovery_prepare(struct region_hash *rh)
|
||||
{
|
||||
while (!down_trylock(&rh->recovery_count))
|
||||
/* Extra reference to avoid race with rh_stop_recovery */
|
||||
atomic_inc(&rh->recovery_in_flight);
|
||||
|
||||
while (!down_trylock(&rh->recovery_count)) {
|
||||
atomic_inc(&rh->recovery_in_flight);
|
||||
if (__rh_recovery_prepare(rh) <= 0) {
|
||||
atomic_dec(&rh->recovery_in_flight);
|
||||
up(&rh->recovery_count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Drop the extra reference */
|
||||
if (atomic_dec_and_test(&rh->recovery_in_flight))
|
||||
wake_up_all(&_kmirrord_recovery_stopped);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1177,6 +1192,11 @@ static void mirror_postsuspend(struct dm_target *ti)
|
|||
struct dirty_log *log = ms->rh.log;
|
||||
|
||||
rh_stop_recovery(&ms->rh);
|
||||
|
||||
/* Wait for all I/O we generated to complete */
|
||||
wait_event(_kmirrord_recovery_stopped,
|
||||
!atomic_read(&ms->rh.recovery_in_flight));
|
||||
|
||||
if (log->type->suspend && log->type->suspend(log))
|
||||
/* FIXME: need better error handling */
|
||||
DMWARN("log suspend failed");
|
||||
|
|
Loading…
Reference in New Issue