[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:
committed by
Linus Torvalds
parent
5d55fdf949
commit
33184048dc
@@ -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 {
|
|||||||
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,
|
|||||||
|
|
||||||
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)
|
|||||||
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, ®->delayed_bios);
|
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);
|
up(&rh->recovery_count);
|
||||||
mempool_free(reg, rh->region_pool);
|
mempool_free(reg, rh->region_pool);
|
||||||
}
|
}
|
||||||
@@ -502,13 +507,23 @@ 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);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns any quiesced regions.
|
* Returns any quiesced regions.
|
||||||
*/
|
*/
|
||||||
@@ -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");
|
||||||
|
Reference in New Issue
Block a user