Commit 33184048 authored by Jonathan E Brassow's avatar Jonathan E Brassow Committed by Linus Torvalds

[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: default avatarJonathan E Brassow <jbrassow@redhat.com>
Signed-off-by: default avatarAlasdair G Kergon <agk@redhat.com>
Cc: <dm-devel@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 5d55fdf9
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
static struct workqueue_struct *_kmirrord_wq; static struct workqueue_struct *_kmirrord_wq;
static struct work_struct _kmirrord_work; static struct work_struct _kmirrord_work;
static DECLARE_WAIT_QUEUE_HEAD(_kmirrord_recovery_stopped);
static inline void wake(void) static inline void wake(void)
{ {
...@@ -83,6 +84,7 @@ struct region_hash { ...@@ -83,6 +84,7 @@ struct region_hash {
struct list_head *buckets; struct list_head *buckets;
spinlock_t region_lock; spinlock_t region_lock;
atomic_t recovery_in_flight;
struct semaphore recovery_count; struct semaphore recovery_count;
struct list_head clean_regions; struct list_head clean_regions;
struct list_head quiesced_regions; struct list_head quiesced_regions;
...@@ -191,6 +193,7 @@ static int rh_init(struct region_hash *rh, struct mirror_set *ms, ...@@ -191,6 +193,7 @@ static int rh_init(struct region_hash *rh, struct mirror_set *ms,
spin_lock_init(&rh->region_lock); spin_lock_init(&rh->region_lock);
sema_init(&rh->recovery_count, 0); sema_init(&rh->recovery_count, 0);
atomic_set(&rh->recovery_in_flight, 0);
INIT_LIST_HEAD(&rh->clean_regions); INIT_LIST_HEAD(&rh->clean_regions);
INIT_LIST_HEAD(&rh->quiesced_regions); INIT_LIST_HEAD(&rh->quiesced_regions);
INIT_LIST_HEAD(&rh->recovered_regions); INIT_LIST_HEAD(&rh->recovered_regions);
...@@ -382,6 +385,8 @@ static void rh_update_states(struct region_hash *rh) ...@@ -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->clear_region(rh->log, reg->key);
rh->log->type->complete_resync_work(rh->log, reg->key, 1); rh->log->type->complete_resync_work(rh->log, reg->key, 1);
dispatch_bios(rh->ms, &reg->delayed_bios); dispatch_bios(rh->ms, &reg->delayed_bios);
if (atomic_dec_and_test(&rh->recovery_in_flight))
wake_up_all(&_kmirrord_recovery_stopped);
up(&rh->recovery_count); up(&rh->recovery_count);
mempool_free(reg, rh->region_pool); mempool_free(reg, rh->region_pool);
} }
...@@ -502,11 +507,21 @@ static int __rh_recovery_prepare(struct region_hash *rh) ...@@ -502,11 +507,21 @@ static int __rh_recovery_prepare(struct region_hash *rh)
static void 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) { if (__rh_recovery_prepare(rh) <= 0) {
atomic_dec(&rh->recovery_in_flight);
up(&rh->recovery_count); up(&rh->recovery_count);
break; 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) ...@@ -1177,6 +1192,11 @@ static void mirror_postsuspend(struct dm_target *ti)
struct dirty_log *log = ms->rh.log; struct dirty_log *log = ms->rh.log;
rh_stop_recovery(&ms->rh); 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)) if (log->type->suspend && log->type->suspend(log))
/* FIXME: need better error handling */ /* FIXME: need better error handling */
DMWARN("log suspend failed"); DMWARN("log suspend failed");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment