diff options
Diffstat (limited to 'drivers/md')
-rw-r--r-- | drivers/md/dm-raid1.c | 22 |
1 files changed, 21 insertions, 1 deletions
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index 659224cb7c53..48a653b3f518 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c | |||
@@ -24,6 +24,7 @@ | |||
24 | 24 | ||
25 | static struct workqueue_struct *_kmirrord_wq; | 25 | static struct workqueue_struct *_kmirrord_wq; |
26 | static struct work_struct _kmirrord_work; | 26 | static struct work_struct _kmirrord_work; |
27 | static DECLARE_WAIT_QUEUE_HEAD(_kmirrord_recovery_stopped); | ||
27 | 28 | ||
28 | static inline void wake(void) | 29 | static inline void wake(void) |
29 | { | 30 | { |
@@ -83,6 +84,7 @@ struct region_hash { | |||
83 | struct list_head *buckets; | 84 | struct list_head *buckets; |
84 | 85 | ||
85 | spinlock_t region_lock; | 86 | spinlock_t region_lock; |
87 | atomic_t recovery_in_flight; | ||
86 | struct semaphore recovery_count; | 88 | struct semaphore recovery_count; |
87 | struct list_head clean_regions; | 89 | struct list_head clean_regions; |
88 | struct list_head quiesced_regions; | 90 | struct list_head quiesced_regions; |
@@ -191,6 +193,7 @@ static int rh_init(struct region_hash *rh, struct mirror_set *ms, | |||
191 | 193 | ||
192 | spin_lock_init(&rh->region_lock); | 194 | spin_lock_init(&rh->region_lock); |
193 | sema_init(&rh->recovery_count, 0); | 195 | sema_init(&rh->recovery_count, 0); |
196 | atomic_set(&rh->recovery_in_flight, 0); | ||
194 | INIT_LIST_HEAD(&rh->clean_regions); | 197 | INIT_LIST_HEAD(&rh->clean_regions); |
195 | INIT_LIST_HEAD(&rh->quiesced_regions); | 198 | INIT_LIST_HEAD(&rh->quiesced_regions); |
196 | INIT_LIST_HEAD(&rh->recovered_regions); | 199 | INIT_LIST_HEAD(&rh->recovered_regions); |
@@ -382,6 +385,8 @@ static void rh_update_states(struct region_hash *rh) | |||
382 | rh->log->type->clear_region(rh->log, reg->key); | 385 | rh->log->type->clear_region(rh->log, reg->key); |
383 | rh->log->type->complete_resync_work(rh->log, reg->key, 1); | 386 | rh->log->type->complete_resync_work(rh->log, reg->key, 1); |
384 | dispatch_bios(rh->ms, ®->delayed_bios); | 387 | dispatch_bios(rh->ms, ®->delayed_bios); |
388 | if (atomic_dec_and_test(&rh->recovery_in_flight)) | ||
389 | wake_up_all(&_kmirrord_recovery_stopped); | ||
385 | up(&rh->recovery_count); | 390 | up(&rh->recovery_count); |
386 | mempool_free(reg, rh->region_pool); | 391 | mempool_free(reg, rh->region_pool); |
387 | } | 392 | } |
@@ -502,11 +507,21 @@ static int __rh_recovery_prepare(struct region_hash *rh) | |||
502 | 507 | ||
503 | static void rh_recovery_prepare(struct region_hash *rh) | 508 | static void rh_recovery_prepare(struct region_hash *rh) |
504 | { | 509 | { |
505 | while (!down_trylock(&rh->recovery_count)) | 510 | /* Extra reference to avoid race with rh_stop_recovery */ |
511 | atomic_inc(&rh->recovery_in_flight); | ||
512 | |||
513 | while (!down_trylock(&rh->recovery_count)) { | ||
514 | atomic_inc(&rh->recovery_in_flight); | ||
506 | if (__rh_recovery_prepare(rh) <= 0) { | 515 | if (__rh_recovery_prepare(rh) <= 0) { |
516 | atomic_dec(&rh->recovery_in_flight); | ||
507 | up(&rh->recovery_count); | 517 | up(&rh->recovery_count); |
508 | break; | 518 | break; |
509 | } | 519 | } |
520 | } | ||
521 | |||
522 | /* Drop the extra reference */ | ||
523 | if (atomic_dec_and_test(&rh->recovery_in_flight)) | ||
524 | wake_up_all(&_kmirrord_recovery_stopped); | ||
510 | } | 525 | } |
511 | 526 | ||
512 | /* | 527 | /* |
@@ -1177,6 +1192,11 @@ static void mirror_postsuspend(struct dm_target *ti) | |||
1177 | struct dirty_log *log = ms->rh.log; | 1192 | struct dirty_log *log = ms->rh.log; |
1178 | 1193 | ||
1179 | rh_stop_recovery(&ms->rh); | 1194 | rh_stop_recovery(&ms->rh); |
1195 | |||
1196 | /* Wait for all I/O we generated to complete */ | ||
1197 | wait_event(_kmirrord_recovery_stopped, | ||
1198 | !atomic_read(&ms->rh.recovery_in_flight)); | ||
1199 | |||
1180 | if (log->type->suspend && log->type->suspend(log)) | 1200 | if (log->type->suspend && log->type->suspend(log)) |
1181 | /* FIXME: need better error handling */ | 1201 | /* FIXME: need better error handling */ |
1182 | DMWARN("log suspend failed"); | 1202 | DMWARN("log suspend failed"); |