diff options
Diffstat (limited to 'drivers/md/dm-raid1.c')
| -rw-r--r-- | drivers/md/dm-raid1.c | 44 |
1 files changed, 41 insertions, 3 deletions
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index 04dce7a66494..dee4221caa73 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #define DM_IO_PAGES 64 | 24 | #define DM_IO_PAGES 64 |
| 25 | 25 | ||
| 26 | #define DM_RAID1_HANDLE_ERRORS 0x01 | 26 | #define DM_RAID1_HANDLE_ERRORS 0x01 |
| 27 | #define errors_handled(p) ((p)->features & DM_RAID1_HANDLE_ERRORS) | ||
| 27 | 28 | ||
| 28 | static DECLARE_WAIT_QUEUE_HEAD(_kmirrord_recovery_stopped); | 29 | static DECLARE_WAIT_QUEUE_HEAD(_kmirrord_recovery_stopped); |
| 29 | 30 | ||
| @@ -85,6 +86,7 @@ struct region_hash { | |||
| 85 | struct list_head clean_regions; | 86 | struct list_head clean_regions; |
| 86 | struct list_head quiesced_regions; | 87 | struct list_head quiesced_regions; |
| 87 | struct list_head recovered_regions; | 88 | struct list_head recovered_regions; |
| 89 | struct list_head failed_recovered_regions; | ||
| 88 | }; | 90 | }; |
| 89 | 91 | ||
| 90 | enum { | 92 | enum { |
| @@ -204,6 +206,7 @@ static int rh_init(struct region_hash *rh, struct mirror_set *ms, | |||
| 204 | INIT_LIST_HEAD(&rh->clean_regions); | 206 | INIT_LIST_HEAD(&rh->clean_regions); |
| 205 | INIT_LIST_HEAD(&rh->quiesced_regions); | 207 | INIT_LIST_HEAD(&rh->quiesced_regions); |
| 206 | INIT_LIST_HEAD(&rh->recovered_regions); | 208 | INIT_LIST_HEAD(&rh->recovered_regions); |
| 209 | INIT_LIST_HEAD(&rh->failed_recovered_regions); | ||
| 207 | 210 | ||
| 208 | rh->region_pool = mempool_create_kmalloc_pool(MIN_REGIONS, | 211 | rh->region_pool = mempool_create_kmalloc_pool(MIN_REGIONS, |
| 209 | sizeof(struct region)); | 212 | sizeof(struct region)); |
| @@ -368,6 +371,7 @@ static void rh_update_states(struct region_hash *rh) | |||
| 368 | 371 | ||
| 369 | LIST_HEAD(clean); | 372 | LIST_HEAD(clean); |
| 370 | LIST_HEAD(recovered); | 373 | LIST_HEAD(recovered); |
| 374 | LIST_HEAD(failed_recovered); | ||
| 371 | 375 | ||
| 372 | /* | 376 | /* |
| 373 | * Quickly grab the lists. | 377 | * Quickly grab the lists. |
| @@ -389,6 +393,15 @@ static void rh_update_states(struct region_hash *rh) | |||
| 389 | list_for_each_entry (reg, &recovered, list) | 393 | list_for_each_entry (reg, &recovered, list) |
| 390 | list_del(®->hash_list); | 394 | list_del(®->hash_list); |
| 391 | } | 395 | } |
| 396 | |||
| 397 | if (!list_empty(&rh->failed_recovered_regions)) { | ||
| 398 | list_splice(&rh->failed_recovered_regions, &failed_recovered); | ||
| 399 | INIT_LIST_HEAD(&rh->failed_recovered_regions); | ||
| 400 | |||
| 401 | list_for_each_entry(reg, &failed_recovered, list) | ||
| 402 | list_del(®->hash_list); | ||
| 403 | } | ||
| 404 | |||
| 392 | spin_unlock(&rh->region_lock); | 405 | spin_unlock(&rh->region_lock); |
| 393 | write_unlock_irq(&rh->hash_lock); | 406 | write_unlock_irq(&rh->hash_lock); |
| 394 | 407 | ||
| @@ -403,6 +416,11 @@ static void rh_update_states(struct region_hash *rh) | |||
| 403 | mempool_free(reg, rh->region_pool); | 416 | mempool_free(reg, rh->region_pool); |
| 404 | } | 417 | } |
| 405 | 418 | ||
| 419 | list_for_each_entry_safe(reg, next, &failed_recovered, list) { | ||
| 420 | complete_resync_work(reg, errors_handled(rh->ms) ? 0 : 1); | ||
| 421 | mempool_free(reg, rh->region_pool); | ||
| 422 | } | ||
| 423 | |||
| 406 | list_for_each_entry_safe(reg, next, &clean, list) { | 424 | list_for_each_entry_safe(reg, next, &clean, list) { |
| 407 | rh->log->type->clear_region(rh->log, reg->key); | 425 | rh->log->type->clear_region(rh->log, reg->key); |
| 408 | mempool_free(reg, rh->region_pool); | 426 | mempool_free(reg, rh->region_pool); |
| @@ -555,13 +573,17 @@ static struct region *rh_recovery_start(struct region_hash *rh) | |||
| 555 | return reg; | 573 | return reg; |
| 556 | } | 574 | } |
| 557 | 575 | ||
| 558 | /* FIXME: success ignored for now */ | ||
| 559 | static void rh_recovery_end(struct region *reg, int success) | 576 | static void rh_recovery_end(struct region *reg, int success) |
| 560 | { | 577 | { |
| 561 | struct region_hash *rh = reg->rh; | 578 | struct region_hash *rh = reg->rh; |
| 562 | 579 | ||
| 563 | spin_lock_irq(&rh->region_lock); | 580 | spin_lock_irq(&rh->region_lock); |
| 564 | list_add(®->list, ®->rh->recovered_regions); | 581 | if (success) |
| 582 | list_add(®->list, ®->rh->recovered_regions); | ||
| 583 | else { | ||
| 584 | reg->state = RH_NOSYNC; | ||
| 585 | list_add(®->list, ®->rh->failed_recovered_regions); | ||
| 586 | } | ||
| 565 | spin_unlock_irq(&rh->region_lock); | 587 | spin_unlock_irq(&rh->region_lock); |
| 566 | 588 | ||
| 567 | wake(rh->ms); | 589 | wake(rh->ms); |
| @@ -633,7 +655,14 @@ static void recovery_complete(int read_err, unsigned int write_err, | |||
| 633 | { | 655 | { |
| 634 | struct region *reg = (struct region *) context; | 656 | struct region *reg = (struct region *) context; |
| 635 | 657 | ||
| 636 | /* FIXME: better error handling */ | 658 | if (read_err) |
| 659 | /* Read error means the failure of default mirror. */ | ||
| 660 | DMERR_LIMIT("Unable to read primary mirror during recovery"); | ||
| 661 | |||
| 662 | if (write_err) | ||
| 663 | DMERR_LIMIT("Write error during recovery (error = 0x%x)", | ||
| 664 | write_err); | ||
| 665 | |||
| 637 | rh_recovery_end(reg, !(read_err || write_err)); | 666 | rh_recovery_end(reg, !(read_err || write_err)); |
| 638 | } | 667 | } |
| 639 | 668 | ||
| @@ -1145,6 +1174,15 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
| 1145 | argv += args_used; | 1174 | argv += args_used; |
| 1146 | argc -= args_used; | 1175 | argc -= args_used; |
| 1147 | 1176 | ||
| 1177 | /* | ||
| 1178 | * Any read-balancing addition depends on the | ||
| 1179 | * DM_RAID1_HANDLE_ERRORS flag being present. | ||
| 1180 | * This is because the decision to balance depends | ||
| 1181 | * on the sync state of a region. If the above | ||
| 1182 | * flag is not present, we ignore errors; and | ||
| 1183 | * the sync state may be inaccurate. | ||
| 1184 | */ | ||
| 1185 | |||
| 1148 | if (argc) { | 1186 | if (argc) { |
| 1149 | ti->error = "Too many mirror arguments"; | 1187 | ti->error = "Too many mirror arguments"; |
| 1150 | free_context(ms, ti, ms->nr_mirrors); | 1188 | free_context(ms, ti, ms->nr_mirrors); |
