aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md
diff options
context:
space:
mode:
authorJonathan Brassow <jbrassow@redhat.com>2007-07-12 12:29:04 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-12 18:01:08 -0400
commitf44db678edcc6f4c2779ac43f63f0b9dfa28b724 (patch)
treebbd835d00ca6ed0805c5c7331ebc5dd7978d299c /drivers/md
parentd0d444c7d48c14d59f665887c758fde248f1cb37 (diff)
dm raid1: handle resync failures
Device-mapper mirroring currently takes a best effort approach to recovery - failures during mirror synchronization are completely ignored. This means that regions are marked 'in-sync' and 'clean' and removed from the hash list. Future reads and writes that query the region will incorrectly interpret the region as in-sync. This patch handles failures during the recovery process. If a failure occurs, the region is marked as 'not-in-sync' (aka RH_NOSYNC) and added to a new list 'failed_recovered_regions'. Regions on the 'failed_recovered_regions' list are not marked as 'clean' upon removal from the list. Furthermore, if the DM_RAID1_HANDLE_ERRORS flag is set, the region is marked as 'not-in-sync'. This action prevents any future read-balancing from choosing an invalid device because of the 'not-in-sync' status. If "handle_errors" is not specified when creating a mirror (leaving the DM_RAID1_HANDLE_ERRORS flag unset), failures will be ignored exactly as they would be without this patch. This is to preserve backwards compatibility with user-space tools, such as 'pvmove'. However, since future read-balancing policies will rely on the correct sync status of a region, a user must choose "handle_errors" when using read-balancing. Signed-off-by: Jonathan Brassow <jbrassow@redhat.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/md')
-rw-r--r--drivers/md/dm-raid1.c44
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
28static DECLARE_WAIT_QUEUE_HEAD(_kmirrord_recovery_stopped); 29static 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
90enum { 92enum {
@@ -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(&reg->hash_list); 394 list_del(&reg->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(&reg->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 */
559static void rh_recovery_end(struct region *reg, int success) 576static 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(&reg->list, &reg->rh->recovered_regions); 581 if (success)
582 list_add(&reg->list, &reg->rh->recovered_regions);
583 else {
584 reg->state = RH_NOSYNC;
585 list_add(&reg->list, &reg->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);