brassow We used to take a best effort approach to recovery - failures during a resync were completely ignored. This meant that regions where marked 'in-sync' and 'clean' and removed from the hash list. Future reads and writes that query the region would 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_FEATURE_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. Note that if the DM_FEATURE_HANDLE_ERRORS flag is not present, the region will still be marked 'in-sync' (although it remains 'dirty'). 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, you can not simultaneously have read-balancing and not have the DM_FEATURE_HANDLE_ERRORS flag. This has been noted in a comment. Index: linux-2.6.18.1/drivers/md/dm-raid1.c =================================================================== --- linux-2.6.18.1.orig/drivers/md/dm-raid1.c 2006-11-06 11:50:42.000000000 -0600 +++ linux-2.6.18.1/drivers/md/dm-raid1.c 2006-11-06 14:08:11.000000000 -0600 @@ -89,6 +89,7 @@ struct region_hash { struct list_head clean_regions; struct list_head quiesced_regions; struct list_head recovered_regions; + struct list_head failed_recovered_regions; }; enum { @@ -202,6 +203,7 @@ static int rh_init(struct region_hash *r INIT_LIST_HEAD(&rh->clean_regions); INIT_LIST_HEAD(&rh->quiesced_regions); INIT_LIST_HEAD(&rh->recovered_regions); + INIT_LIST_HEAD(&rh->failed_recovered_regions); rh->region_pool = mempool_create_kmalloc_pool(MIN_REGIONS, sizeof(struct region)); @@ -366,6 +368,7 @@ static void rh_update_states(struct regi LIST_HEAD(clean); LIST_HEAD(recovered); + LIST_HEAD(failed_recovered); /* * Quickly grab the lists. @@ -389,6 +392,15 @@ static void rh_update_states(struct regi list_for_each_entry (reg, &recovered, list) list_del(®->hash_list); } + + if (!list_empty(&rh->failed_recovered_regions)) { + list_splice(&rh->failed_recovered_regions, &failed_recovered); + INIT_LIST_HEAD(&rh->failed_recovered_regions); + + list_for_each_entry (reg, &failed_recovered, list) + list_del(®->hash_list); + } + spin_unlock(&rh->region_lock); write_unlock_irq(&rh->hash_lock); @@ -403,6 +415,14 @@ static void rh_update_states(struct regi mempool_free(reg, rh->region_pool); } + list_for_each_entry_safe (reg, next, &failed_recovered, list) { + if (rh->ms->feature_flags & DM_FEATURE_HANDLE_ERRORS) + complete_resync_work(reg, 0); + else + complete_resync_work(reg, 1); + mempool_free(reg, rh->region_pool); + } + if (!list_empty(&recovered)) rh->log->type->flush(rh->log); @@ -554,13 +574,17 @@ static struct region *rh_recovery_start( return reg; } -/* FIXME: success ignored for now */ static void rh_recovery_end(struct region *reg, int success) { struct region_hash *rh = reg->rh; spin_lock_irq(&rh->region_lock); - list_add(®->list, ®->rh->recovered_regions); + if (success) + list_add(®->list, ®->rh->recovered_regions); + else { + reg->state = RH_NOSYNC; + list_add(®->list, ®->rh->failed_recovered_regions); + } spin_unlock_irq(&rh->region_lock); wake(); @@ -632,7 +656,15 @@ static void recovery_complete(int read_e { struct region *reg = (struct region *) context; - /* FIXME: better error handling */ + /* FIXME: don't spray the console */ + if (read_err) + /* Read error means the failure of default mirror. */ + DMERR("Unable to read from primary mirror during recovery"); + + if (write_err) + DMERR("Write error during recovery (error = 0x%x)", + write_err); + rh_recovery_end(reg, !(read_err || write_err)); } @@ -1160,6 +1192,15 @@ static int mirror_ctr(struct dm_target * argv += args_used; argc -= args_used; + /* + * Note: Any read-balancing addition depends on the + * DM_FEATURES_HANDLE_ERRORS flag being present. + * This is because the decision to balance depends + * on the sync state of a region. If the above + * flag is not present, we ignore errors; and + * the sync state may not properly be reflected. + */ + if (argc) { ti->error = "Wrong number of mirror arguments"; free_context(ms, ti, ms->nr_mirrors); -- dm-devel mailing list dm-devel@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/dm-devel