sky2: dont enable PME legacy mode
[safe/jmp/linux-2.6] / drivers / md / dm-raid1.c
index 0253130..ad779bd 100644 (file)
@@ -69,6 +69,7 @@ struct mirror_set {
        region_t nr_regions;
        int in_sync;
        int log_failure;
+       int leg_failure;
        atomic_t suspend;
 
        atomic_t default_mirror;        /* Default mirror */
@@ -181,6 +182,17 @@ static void set_default_mirror(struct mirror *m)
        atomic_set(&ms->default_mirror, m - m0);
 }
 
+static struct mirror *get_valid_mirror(struct mirror_set *ms)
+{
+       struct mirror *m;
+
+       for (m = ms->mirror; m < ms->mirror + ms->nr_mirrors; m++)
+               if (!atomic_read(&m->error_count))
+                       return m;
+
+       return NULL;
+}
+
 /* fail_mirror
  * @m: mirror device to fail
  * @error_type: one of the enum's, DM_RAID1_*_ERROR
@@ -200,6 +212,8 @@ static void fail_mirror(struct mirror *m, enum dm_raid1_error error_type)
        struct mirror_set *ms = m->ms;
        struct mirror *new;
 
+       ms->leg_failure = 1;
+
        /*
         * error_count is used for nothing more than a
         * simple way to tell if a device has encountered
@@ -226,13 +240,10 @@ static void fail_mirror(struct mirror *m, enum dm_raid1_error error_type)
                goto out;
        }
 
-       for (new = ms->mirror; new < ms->mirror + ms->nr_mirrors; new++)
-               if (!atomic_read(&new->error_count)) {
-                       set_default_mirror(new);
-                       break;
-               }
-
-       if (unlikely(new == ms->mirror + ms->nr_mirrors))
+       new = get_valid_mirror(ms);
+       if (new)
+               set_default_mirror(new);
+       else
                DMWARN("All sides of mirror have failed.");
 
 out:
@@ -570,7 +581,6 @@ static void write_callback(unsigned long error, void *context)
        unsigned i, ret = 0;
        struct bio *bio = (struct bio *) context;
        struct mirror_set *ms;
-       int uptodate = 0;
        int should_wake = 0;
        unsigned long flags;
 
@@ -583,36 +593,27 @@ static void write_callback(unsigned long error, void *context)
         * This way we handle both writes to SYNC and NOSYNC
         * regions with the same code.
         */
-       if (likely(!error))
-               goto out;
+       if (likely(!error)) {
+               bio_endio(bio, ret);
+               return;
+       }
 
        for (i = 0; i < ms->nr_mirrors; i++)
                if (test_bit(i, &error))
                        fail_mirror(ms->mirror + i, DM_RAID1_WRITE_ERROR);
-               else
-                       uptodate = 1;
 
-       if (unlikely(!uptodate)) {
-               DMERR("All replicated volumes dead, failing I/O");
-               /* None of the writes succeeded, fail the I/O. */
-               ret = -EIO;
-       } else if (errors_handled(ms)) {
-               /*
-                * Need to raise event.  Since raising
-                * events can block, we need to do it in
-                * the main thread.
-                */
-               spin_lock_irqsave(&ms->lock, flags);
-               if (!ms->failures.head)
-                       should_wake = 1;
-               bio_list_add(&ms->failures, bio);
-               spin_unlock_irqrestore(&ms->lock, flags);
-               if (should_wake)
-                       wakeup_mirrord(ms);
-               return;
-       }
-out:
-       bio_endio(bio, ret);
+       /*
+        * Need to raise event.  Since raising
+        * events can block, we need to do it in
+        * the main thread.
+        */
+       spin_lock_irqsave(&ms->lock, flags);
+       if (!ms->failures.head)
+               should_wake = 1;
+       bio_list_add(&ms->failures, bio);
+       spin_unlock_irqrestore(&ms->lock, flags);
+       if (should_wake)
+               wakeup_mirrord(ms);
 }
 
 static void do_write(struct mirror_set *ms, struct bio *bio)
@@ -736,8 +737,12 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes)
                dm_rh_delay(ms->rh, bio);
 
        while ((bio = bio_list_pop(&nosync))) {
-               map_bio(get_default_mirror(ms), bio);
-               generic_make_request(bio);
+               if (unlikely(ms->leg_failure) && errors_handled(ms))
+                       hold_bio(ms, bio);
+               else {
+                       map_bio(get_default_mirror(ms), bio);
+                       generic_make_request(bio);
+               }
        }
 }
 
@@ -765,14 +770,26 @@ static void do_failures(struct mirror_set *ms, struct bio_list *failures)
         * for us to treat them the same and requeue them
         * as well.
         */
-
        while ((bio = bio_list_pop(failures))) {
-               if (ms->log_failure)
-                       hold_bio(ms, bio);
-               else {
+               if (!ms->log_failure) {
                        ms->in_sync = 0;
-                       dm_rh_mark_nosync(ms->rh, bio, bio->bi_size, 0);
+                       dm_rh_mark_nosync(ms->rh, bio);
                }
+
+               /*
+                * If all the legs are dead, fail the I/O.
+                * If we have been told to handle errors, hold the bio
+                * and wait for userspace to deal with the problem.
+                * Otherwise pretend that the I/O succeeded. (This would
+                * be wrong if the failed leg returned after reboot and
+                * got replicated back to the good legs.)
+                */
+               if (!get_valid_mirror(ms))
+                       bio_endio(bio, -EIO);
+               else if (errors_handled(ms))
+                       hold_bio(ms, bio);
+               else
+                       bio_endio(bio, 0);
        }
 }
 
@@ -832,12 +849,17 @@ static struct mirror_set *alloc_context(unsigned int nr_mirrors,
        }
 
        spin_lock_init(&ms->lock);
+       bio_list_init(&ms->reads);
+       bio_list_init(&ms->writes);
+       bio_list_init(&ms->failures);
+       bio_list_init(&ms->holds);
 
        ms->ti = ti;
        ms->nr_mirrors = nr_mirrors;
        ms->nr_regions = dm_sector_div_up(ti->len, region_size);
        ms->in_sync = 0;
        ms->log_failure = 0;
+       ms->leg_failure = 0;
        atomic_set(&ms->suspend, 0);
        atomic_set(&ms->default_mirror, DEFAULT_MIRROR);