diff options
| -rw-r--r-- | Documentation/md.txt | 11 | ||||
| -rw-r--r-- | drivers/md/md.c | 27 | ||||
| -rw-r--r-- | drivers/md/raid1.c | 2 | ||||
| -rw-r--r-- | drivers/md/raid10.c | 11 | ||||
| -rw-r--r-- | drivers/md/raid5.c | 3 | ||||
| -rw-r--r-- | drivers/md/raid6main.c | 3 | ||||
| -rw-r--r-- | include/linux/raid/md_k.h | 4 |
7 files changed, 57 insertions, 4 deletions
diff --git a/Documentation/md.txt b/Documentation/md.txt index fd43fd2cad2f..a3eadf8e1701 100644 --- a/Documentation/md.txt +++ b/Documentation/md.txt | |||
| @@ -222,6 +222,17 @@ Each directory contains: | |||
| 222 | of being recoverred to | 222 | of being recoverred to |
| 223 | This list make grow in future. | 223 | This list make grow in future. |
| 224 | 224 | ||
| 225 | errors | ||
| 226 | An approximate count of read errors that have been detected on | ||
| 227 | this device but have not caused the device to be evicted from | ||
| 228 | the array (either because they were corrected or because they | ||
| 229 | happened while the array was read-only). When using version-1 | ||
| 230 | metadata, this value persists across restarts of the array. | ||
| 231 | |||
| 232 | This value can be written while assembling an array thus | ||
| 233 | providing an ongoing count for arrays with metadata managed by | ||
| 234 | userspace. | ||
| 235 | |||
| 225 | 236 | ||
| 226 | An active md device will also contain and entry for each active device | 237 | An active md device will also contain and entry for each active device |
| 227 | in the array. These are named | 238 | in the array. These are named |
diff --git a/drivers/md/md.c b/drivers/md/md.c index 594d8c312e6a..32a4e2311e43 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c | |||
| @@ -1000,6 +1000,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version) | |||
| 1000 | } | 1000 | } |
| 1001 | rdev->preferred_minor = 0xffff; | 1001 | rdev->preferred_minor = 0xffff; |
| 1002 | rdev->data_offset = le64_to_cpu(sb->data_offset); | 1002 | rdev->data_offset = le64_to_cpu(sb->data_offset); |
| 1003 | atomic_set(&rdev->corrected_errors, le32_to_cpu(sb->cnt_corrected_read)); | ||
| 1003 | 1004 | ||
| 1004 | rdev->sb_size = le32_to_cpu(sb->max_dev) * 2 + 256; | 1005 | rdev->sb_size = le32_to_cpu(sb->max_dev) * 2 + 256; |
| 1005 | bmask = queue_hardsect_size(rdev->bdev->bd_disk->queue)-1; | 1006 | bmask = queue_hardsect_size(rdev->bdev->bd_disk->queue)-1; |
| @@ -1139,6 +1140,8 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev) | |||
| 1139 | else | 1140 | else |
| 1140 | sb->resync_offset = cpu_to_le64(0); | 1141 | sb->resync_offset = cpu_to_le64(0); |
| 1141 | 1142 | ||
| 1143 | sb->cnt_corrected_read = atomic_read(&rdev->corrected_errors); | ||
| 1144 | |||
| 1142 | if (mddev->bitmap && mddev->bitmap_file == NULL) { | 1145 | if (mddev->bitmap && mddev->bitmap_file == NULL) { |
| 1143 | sb->bitmap_offset = cpu_to_le32((__u32)mddev->bitmap_offset); | 1146 | sb->bitmap_offset = cpu_to_le32((__u32)mddev->bitmap_offset); |
| 1144 | sb->feature_map = cpu_to_le32(MD_FEATURE_BITMAP_OFFSET); | 1147 | sb->feature_map = cpu_to_le32(MD_FEATURE_BITMAP_OFFSET); |
| @@ -1592,9 +1595,30 @@ super_show(mdk_rdev_t *rdev, char *page) | |||
| 1592 | } | 1595 | } |
| 1593 | static struct rdev_sysfs_entry rdev_super = __ATTR_RO(super); | 1596 | static struct rdev_sysfs_entry rdev_super = __ATTR_RO(super); |
| 1594 | 1597 | ||
| 1598 | static ssize_t | ||
| 1599 | errors_show(mdk_rdev_t *rdev, char *page) | ||
| 1600 | { | ||
| 1601 | return sprintf(page, "%d\n", atomic_read(&rdev->corrected_errors)); | ||
| 1602 | } | ||
| 1603 | |||
| 1604 | static ssize_t | ||
| 1605 | errors_store(mdk_rdev_t *rdev, const char *buf, size_t len) | ||
| 1606 | { | ||
| 1607 | char *e; | ||
| 1608 | unsigned long n = simple_strtoul(buf, &e, 10); | ||
| 1609 | if (*buf && (*e == 0 || *e == '\n')) { | ||
| 1610 | atomic_set(&rdev->corrected_errors, n); | ||
| 1611 | return len; | ||
| 1612 | } | ||
| 1613 | return -EINVAL; | ||
| 1614 | } | ||
| 1615 | static struct rdev_sysfs_entry rdev_errors = | ||
| 1616 | __ATTR(errors, 0644, errors_show, errors_store); | ||
| 1617 | |||
| 1595 | static struct attribute *rdev_default_attrs[] = { | 1618 | static struct attribute *rdev_default_attrs[] = { |
| 1596 | &rdev_state.attr, | 1619 | &rdev_state.attr, |
| 1597 | &rdev_super.attr, | 1620 | &rdev_super.attr, |
| 1621 | &rdev_errors.attr, | ||
| 1598 | NULL, | 1622 | NULL, |
| 1599 | }; | 1623 | }; |
| 1600 | static ssize_t | 1624 | static ssize_t |
| @@ -1674,6 +1698,7 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi | |||
| 1674 | rdev->data_offset = 0; | 1698 | rdev->data_offset = 0; |
| 1675 | atomic_set(&rdev->nr_pending, 0); | 1699 | atomic_set(&rdev->nr_pending, 0); |
| 1676 | atomic_set(&rdev->read_errors, 0); | 1700 | atomic_set(&rdev->read_errors, 0); |
| 1701 | atomic_set(&rdev->corrected_errors, 0); | ||
| 1677 | 1702 | ||
| 1678 | size = rdev->bdev->bd_inode->i_size >> BLOCK_SIZE_BITS; | 1703 | size = rdev->bdev->bd_inode->i_size >> BLOCK_SIZE_BITS; |
| 1679 | if (!size) { | 1704 | if (!size) { |
| @@ -4729,7 +4754,7 @@ static int set_ro(const char *val, struct kernel_param *kp) | |||
| 4729 | int num = simple_strtoul(val, &e, 10); | 4754 | int num = simple_strtoul(val, &e, 10); |
| 4730 | if (*val && (*e == '\0' || *e == '\n')) { | 4755 | if (*val && (*e == '\0' || *e == '\n')) { |
| 4731 | start_readonly = num; | 4756 | start_readonly = num; |
| 4732 | return 0;; | 4757 | return 0; |
| 4733 | } | 4758 | } |
| 4734 | return -EINVAL; | 4759 | return -EINVAL; |
| 4735 | } | 4760 | } |
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 181c9616d5f1..a06ff91f27e2 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c | |||
| @@ -1265,6 +1265,7 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio) | |||
| 1265 | if (r1_bio->bios[d]->bi_end_io != end_sync_read) | 1265 | if (r1_bio->bios[d]->bi_end_io != end_sync_read) |
| 1266 | continue; | 1266 | continue; |
| 1267 | rdev = conf->mirrors[d].rdev; | 1267 | rdev = conf->mirrors[d].rdev; |
| 1268 | atomic_add(s, &rdev->corrected_errors); | ||
| 1268 | if (sync_page_io(rdev->bdev, | 1269 | if (sync_page_io(rdev->bdev, |
| 1269 | sect + rdev->data_offset, | 1270 | sect + rdev->data_offset, |
| 1270 | s<<9, | 1271 | s<<9, |
| @@ -1463,6 +1464,7 @@ static void raid1d(mddev_t *mddev) | |||
| 1463 | d = conf->raid_disks; | 1464 | d = conf->raid_disks; |
| 1464 | d--; | 1465 | d--; |
| 1465 | rdev = conf->mirrors[d].rdev; | 1466 | rdev = conf->mirrors[d].rdev; |
| 1467 | atomic_add(s, &rdev->corrected_errors); | ||
| 1466 | if (rdev && | 1468 | if (rdev && |
| 1467 | test_bit(In_sync, &rdev->flags)) { | 1469 | test_bit(In_sync, &rdev->flags)) { |
| 1468 | if (sync_page_io(rdev->bdev, | 1470 | if (sync_page_io(rdev->bdev, |
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 201dc7168a5f..9e658e519a27 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c | |||
| @@ -1122,9 +1122,13 @@ static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error) | |||
| 1122 | 1122 | ||
| 1123 | if (test_bit(BIO_UPTODATE, &bio->bi_flags)) | 1123 | if (test_bit(BIO_UPTODATE, &bio->bi_flags)) |
| 1124 | set_bit(R10BIO_Uptodate, &r10_bio->state); | 1124 | set_bit(R10BIO_Uptodate, &r10_bio->state); |
| 1125 | else if (!test_bit(MD_RECOVERY_SYNC, &conf->mddev->recovery)) | 1125 | else { |
| 1126 | md_error(r10_bio->mddev, | 1126 | atomic_add(r10_bio->sectors, |
| 1127 | conf->mirrors[d].rdev); | 1127 | &conf->mirrors[d].rdev->corrected_errors); |
| 1128 | if (!test_bit(MD_RECOVERY_SYNC, &conf->mddev->recovery)) | ||
| 1129 | md_error(r10_bio->mddev, | ||
| 1130 | conf->mirrors[d].rdev); | ||
| 1131 | } | ||
| 1128 | 1132 | ||
| 1129 | /* for reconstruct, we always reschedule after a read. | 1133 | /* for reconstruct, we always reschedule after a read. |
| 1130 | * for resync, only after all reads | 1134 | * for resync, only after all reads |
| @@ -1430,6 +1434,7 @@ static void raid10d(mddev_t *mddev) | |||
| 1430 | sl--; | 1434 | sl--; |
| 1431 | d = r10_bio->devs[sl].devnum; | 1435 | d = r10_bio->devs[sl].devnum; |
| 1432 | rdev = conf->mirrors[d].rdev; | 1436 | rdev = conf->mirrors[d].rdev; |
| 1437 | atomic_add(s, &rdev->corrected_errors); | ||
| 1433 | if (rdev && | 1438 | if (rdev && |
| 1434 | test_bit(In_sync, &rdev->flags)) { | 1439 | test_bit(In_sync, &rdev->flags)) { |
| 1435 | if (sync_page_io(rdev->bdev, | 1440 | if (sync_page_io(rdev->bdev, |
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 9cc844f455bf..54f4a9847e38 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c | |||
| @@ -1400,6 +1400,9 @@ static void handle_stripe(struct stripe_head *sh) | |||
| 1400 | bi->bi_io_vec[0].bv_offset = 0; | 1400 | bi->bi_io_vec[0].bv_offset = 0; |
| 1401 | bi->bi_size = STRIPE_SIZE; | 1401 | bi->bi_size = STRIPE_SIZE; |
| 1402 | bi->bi_next = NULL; | 1402 | bi->bi_next = NULL; |
| 1403 | if (rw == WRITE && | ||
| 1404 | test_bit(R5_ReWrite, &sh->dev[i].flags)) | ||
| 1405 | atomic_add(STRIPE_SECTORS, &rdev->corrected_errors); | ||
| 1403 | generic_make_request(bi); | 1406 | generic_make_request(bi); |
| 1404 | } else { | 1407 | } else { |
| 1405 | if (rw == 1) | 1408 | if (rw == 1) |
diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c index 84dd875bb2f6..8c823d686a60 100644 --- a/drivers/md/raid6main.c +++ b/drivers/md/raid6main.c | |||
| @@ -1562,6 +1562,9 @@ static void handle_stripe(struct stripe_head *sh, struct page *tmp_page) | |||
| 1562 | bi->bi_io_vec[0].bv_offset = 0; | 1562 | bi->bi_io_vec[0].bv_offset = 0; |
| 1563 | bi->bi_size = STRIPE_SIZE; | 1563 | bi->bi_size = STRIPE_SIZE; |
| 1564 | bi->bi_next = NULL; | 1564 | bi->bi_next = NULL; |
| 1565 | if (rw == WRITE && | ||
| 1566 | test_bit(R5_ReWrite, &sh->dev[i].flags)) | ||
| 1567 | atomic_add(STRIPE_SECTORS, &rdev->corrected_errors); | ||
| 1565 | generic_make_request(bi); | 1568 | generic_make_request(bi); |
| 1566 | } else { | 1569 | } else { |
| 1567 | if (rw == 1) | 1570 | if (rw == 1) |
diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h index 686463115438..68b929c079ab 100644 --- a/include/linux/raid/md_k.h +++ b/include/linux/raid/md_k.h | |||
| @@ -95,6 +95,10 @@ struct mdk_rdev_s | |||
| 95 | atomic_t read_errors; /* number of consecutive read errors that | 95 | atomic_t read_errors; /* number of consecutive read errors that |
| 96 | * we have tried to ignore. | 96 | * we have tried to ignore. |
| 97 | */ | 97 | */ |
| 98 | atomic_t corrected_errors; /* number of corrected read errors, | ||
| 99 | * for reporting to userspace and storing | ||
| 100 | * in superblock. | ||
| 101 | */ | ||
| 98 | }; | 102 | }; |
| 99 | 103 | ||
| 100 | struct mddev_s | 104 | struct mddev_s |
