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 |