Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=f44db678edcc6f4c2779ac43f63f0b9dfa28b724
Commit:     f44db678edcc6f4c2779ac43f63f0b9dfa28b724
Parent:     d0d444c7d48c14d59f665887c758fde248f1cb37
Author:     Jonathan Brassow <[EMAIL PROTECTED]>
AuthorDate: Thu Jul 12 17:29:04 2007 +0100
Committer:  Linus Torvalds <[EMAIL PROTECTED]>
CommitDate: Thu Jul 12 15:01:08 2007 -0700

    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 <[EMAIL PROTECTED]>
    Signed-off-by: Alasdair G Kergon <[EMAIL PROTECTED]>
    Signed-off-by: Linus Torvalds <[EMAIL PROTECTED]>
---
 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 04dce7a..dee4221 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -24,6 +24,7 @@
 #define DM_IO_PAGES 64
 
 #define DM_RAID1_HANDLE_ERRORS 0x01
+#define errors_handled(p)      ((p)->features & DM_RAID1_HANDLE_ERRORS)
 
 static DECLARE_WAIT_QUEUE_HEAD(_kmirrord_recovery_stopped);
 
@@ -85,6 +86,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 {
@@ -204,6 +206,7 @@ static int rh_init(struct region_hash *rh, struct 
mirror_set *ms,
        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));
@@ -368,6 +371,7 @@ static void rh_update_states(struct region_hash *rh)
 
        LIST_HEAD(clean);
        LIST_HEAD(recovered);
+       LIST_HEAD(failed_recovered);
 
        /*
         * Quickly grab the lists.
@@ -389,6 +393,15 @@ static void rh_update_states(struct region_hash *rh)
                list_for_each_entry (reg, &recovered, list)
                        list_del(&reg->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(&reg->hash_list);
+       }
+
        spin_unlock(&rh->region_lock);
        write_unlock_irq(&rh->hash_lock);
 
@@ -403,6 +416,11 @@ static void rh_update_states(struct region_hash *rh)
                mempool_free(reg, rh->region_pool);
        }
 
+       list_for_each_entry_safe(reg, next, &failed_recovered, list) {
+               complete_resync_work(reg, errors_handled(rh->ms) ? 0 : 1);
+               mempool_free(reg, rh->region_pool);
+       }
+
        list_for_each_entry_safe(reg, next, &clean, list) {
                rh->log->type->clear_region(rh->log, reg->key);
                mempool_free(reg, rh->region_pool);
@@ -555,13 +573,17 @@ static struct region *rh_recovery_start(struct 
region_hash *rh)
        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(&reg->list, &reg->rh->recovered_regions);
+       if (success)
+               list_add(&reg->list, &reg->rh->recovered_regions);
+       else {
+               reg->state = RH_NOSYNC;
+               list_add(&reg->list, &reg->rh->failed_recovered_regions);
+       }
        spin_unlock_irq(&rh->region_lock);
 
        wake(rh->ms);
@@ -633,7 +655,14 @@ static void recovery_complete(int read_err, unsigned int 
write_err,
 {
        struct region *reg = (struct region *) context;
 
-       /* FIXME: better error handling */
+       if (read_err)
+               /* Read error means the failure of default mirror. */
+               DMERR_LIMIT("Unable to read primary mirror during recovery");
+
+       if (write_err)
+               DMERR_LIMIT("Write error during recovery (error = 0x%x)",
+                           write_err);
+
        rh_recovery_end(reg, !(read_err || write_err));
 }
 
@@ -1145,6 +1174,15 @@ static int mirror_ctr(struct dm_target *ti, unsigned int 
argc, char **argv)
        argv += args_used;
        argc -= args_used;
 
+       /*
+        * Any read-balancing addition depends on the
+        * DM_RAID1_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 be inaccurate.
+        */
+
        if (argc) {
                ti->error = "Too many mirror arguments";
                free_context(ms, ti, ms->nr_mirrors);
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to