]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/md/dm-raid.c
Merge tag 'pci-v3.16-changes-2' of git://git.kernel.org/pub/scm/linux/kernel/git...
[karo-tx-linux.git] / drivers / md / dm-raid.c
index 1d3fe1a40a9bfdaea27bdaeb44208443f08f2d95..4880b69e2e9ecb3ea873d514580345a05edcea8a 100644 (file)
@@ -380,7 +380,7 @@ static int validate_region_size(struct raid_set *rs, unsigned long region_size)
 static int validate_raid_redundancy(struct raid_set *rs)
 {
        unsigned i, rebuild_cnt = 0;
-       unsigned rebuilds_per_group, copies, d;
+       unsigned rebuilds_per_group = 0, copies, d;
        unsigned group_size, last_group_start;
 
        for (i = 0; i < rs->md.raid_disks; i++)
@@ -504,7 +504,7 @@ static int parse_raid_params(struct raid_set *rs, char **argv,
         * First, parse the in-order required arguments
         * "chunk_size" is the only argument of this type.
         */
-       if ((strict_strtoul(argv[0], 10, &value) < 0)) {
+       if ((kstrtoul(argv[0], 10, &value) < 0)) {
                rs->ti->error = "Bad chunk size";
                return -EINVAL;
        } else if (rs->raid_type->level == 1) {
@@ -585,7 +585,7 @@ static int parse_raid_params(struct raid_set *rs, char **argv,
                        continue;
                }
 
-               if (strict_strtoul(argv[i], 10, &value) < 0) {
+               if (kstrtoul(argv[i], 10, &value) < 0) {
                        rs->ti->error = "Bad numerical argument given in raid params";
                        return -EINVAL;
                }
@@ -1181,7 +1181,7 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv)
        argv++;
 
        /* number of RAID parameters */
-       if (strict_strtoul(argv[0], 10, &num_raid_params) < 0) {
+       if (kstrtoul(argv[0], 10, &num_raid_params) < 0) {
                ti->error = "Cannot understand number of RAID parameters";
                return -EINVAL;
        }
@@ -1194,7 +1194,7 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv)
                return -EINVAL;
        }
 
-       if ((strict_strtoul(argv[num_raid_params], 10, &num_raid_devs) < 0) ||
+       if ((kstrtoul(argv[num_raid_params], 10, &num_raid_devs) < 0) ||
            (num_raid_devs >= INT_MAX)) {
                ti->error = "Cannot understand number of raid devices";
                return -EINVAL;
@@ -1388,6 +1388,7 @@ static void raid_status(struct dm_target *ti, status_type_t type,
                 *   performing a "check" of the array.
                 */
                DMEMIT(" %llu",
+                      (strcmp(rs->md.last_sync_action, "check")) ? 0 :
                       (unsigned long long)
                       atomic64_read(&rs->md.resync_mismatches));
                break;
@@ -1572,6 +1573,62 @@ static void raid_postsuspend(struct dm_target *ti)
        mddev_suspend(&rs->md);
 }
 
+static void attempt_restore_of_faulty_devices(struct raid_set *rs)
+{
+       int i;
+       uint64_t failed_devices, cleared_failed_devices = 0;
+       unsigned long flags;
+       struct dm_raid_superblock *sb;
+       struct md_rdev *r;
+
+       for (i = 0; i < rs->md.raid_disks; i++) {
+               r = &rs->dev[i].rdev;
+               if (test_bit(Faulty, &r->flags) && r->sb_page &&
+                   sync_page_io(r, 0, r->sb_size, r->sb_page, READ, 1)) {
+                       DMINFO("Faulty %s device #%d has readable super block."
+                              "  Attempting to revive it.",
+                              rs->raid_type->name, i);
+
+                       /*
+                        * Faulty bit may be set, but sometimes the array can
+                        * be suspended before the personalities can respond
+                        * by removing the device from the array (i.e. calling
+                        * 'hot_remove_disk').  If they haven't yet removed
+                        * the failed device, its 'raid_disk' number will be
+                        * '>= 0' - meaning we must call this function
+                        * ourselves.
+                        */
+                       if ((r->raid_disk >= 0) &&
+                           (r->mddev->pers->hot_remove_disk(r->mddev, r) != 0))
+                               /* Failed to revive this device, try next */
+                               continue;
+
+                       r->raid_disk = i;
+                       r->saved_raid_disk = i;
+                       flags = r->flags;
+                       clear_bit(Faulty, &r->flags);
+                       clear_bit(WriteErrorSeen, &r->flags);
+                       clear_bit(In_sync, &r->flags);
+                       if (r->mddev->pers->hot_add_disk(r->mddev, r)) {
+                               r->raid_disk = -1;
+                               r->saved_raid_disk = -1;
+                               r->flags = flags;
+                       } else {
+                               r->recovery_offset = 0;
+                               cleared_failed_devices |= 1 << i;
+                       }
+               }
+       }
+       if (cleared_failed_devices) {
+               rdev_for_each(r, &rs->md) {
+                       sb = page_address(r->sb_page);
+                       failed_devices = le64_to_cpu(sb->failed_devices);
+                       failed_devices &= ~cleared_failed_devices;
+                       sb->failed_devices = cpu_to_le64(failed_devices);
+               }
+       }
+}
+
 static void raid_resume(struct dm_target *ti)
 {
        struct raid_set *rs = ti->private;
@@ -1580,6 +1637,13 @@ static void raid_resume(struct dm_target *ti)
        if (!rs->bitmap_loaded) {
                bitmap_load(&rs->md);
                rs->bitmap_loaded = 1;
+       } else {
+               /*
+                * A secondary resume while the device is active.
+                * Take this opportunity to check whether any failed
+                * devices are reachable again.
+                */
+               attempt_restore_of_faulty_devices(rs);
        }
 
        clear_bit(MD_RECOVERY_FROZEN, &rs->md.recovery);
@@ -1588,7 +1652,7 @@ static void raid_resume(struct dm_target *ti)
 
 static struct target_type raid_target = {
        .name = "raid",
-       .version = {1, 5, 0},
+       .version = {1, 5, 2},
        .module = THIS_MODULE,
        .ctr = raid_ctr,
        .dtr = raid_dtr,