aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/md.txt11
-rw-r--r--drivers/md/md.c27
-rw-r--r--drivers/md/raid1.c2
-rw-r--r--drivers/md/raid10.c11
-rw-r--r--drivers/md/raid5.c3
-rw-r--r--drivers/md/raid6main.c3
-rw-r--r--include/linux/raid/md_k.h4
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
226An active md device will also contain and entry for each active device 237An active md device will also contain and entry for each active device
227in the array. These are named 238in 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}
1593static struct rdev_sysfs_entry rdev_super = __ATTR_RO(super); 1596static struct rdev_sysfs_entry rdev_super = __ATTR_RO(super);
1594 1597
1598static ssize_t
1599errors_show(mdk_rdev_t *rdev, char *page)
1600{
1601 return sprintf(page, "%d\n", atomic_read(&rdev->corrected_errors));
1602}
1603
1604static ssize_t
1605errors_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}
1615static struct rdev_sysfs_entry rdev_errors =
1616__ATTR(errors, 0644, errors_show, errors_store);
1617
1595static struct attribute *rdev_default_attrs[] = { 1618static 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};
1600static ssize_t 1624static 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
100struct mddev_s 104struct mddev_s