diff options
Diffstat (limited to 'drivers/md/dm-raid1.c')
| -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"); |
