Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

mtd: add ECC error accounting for each read request

Extend struct mtd_req_stats with two new fields holding the number of
corrected bitflips and uncorrectable errors detected during a read
operation. This is a prerequisite for ultimately passing those counters
to user space, where they can be useful to applications for making
better-informed choices about moving data around.

Unlike 'max_bitflips' (which is set - in a common code path - to the
return value of a function called while the MTD device's mutex is held),
these counters have to be maintained in each MTD driver which defines
the '_read_oob' callback because the statistics need to be calculated
while the MTD device's mutex is held.

Suggested-by: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Michał Kępień <kernel@kempniu.pl>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/20220629125737.14418-4-kernel@kempniu.pl

authored by

Michał Kępień and committed by
Miquel Raynal
7bea6056 745df179

+42
+8
drivers/mtd/devices/docg3.c
··· 871 871 u8 *buf = ops->datbuf; 872 872 size_t len, ooblen, nbdata, nboob; 873 873 u8 hwecc[DOC_ECC_BCH_SIZE], eccconf1; 874 + struct mtd_ecc_stats old_stats; 874 875 int max_bitflips = 0; 875 876 876 877 if (buf) ··· 896 895 ret = 0; 897 896 skip = from % DOC_LAYOUT_PAGE_SIZE; 898 897 mutex_lock(&docg3->cascade->lock); 898 + old_stats = mtd->ecc_stats; 899 899 while (ret >= 0 && (len > 0 || ooblen > 0)) { 900 900 calc_block_sector(from - skip, &block0, &block1, &page, &ofs, 901 901 docg3->reliable); ··· 968 966 } 969 967 970 968 out: 969 + if (ops->stats) { 970 + ops->stats->uncorrectable_errors += 971 + mtd->ecc_stats.failed - old_stats.failed; 972 + ops->stats->corrected_bitflips += 973 + mtd->ecc_stats.corrected - old_stats.corrected; 974 + } 971 975 mutex_unlock(&docg3->cascade->lock); 972 976 return ret; 973 977 err_in_read:
+12
drivers/mtd/nand/onenand/onenand_base.c
··· 1440 1440 struct mtd_oob_ops *ops) 1441 1441 { 1442 1442 struct onenand_chip *this = mtd->priv; 1443 + struct mtd_ecc_stats old_stats; 1443 1444 int ret; 1444 1445 1445 1446 switch (ops->mode) { ··· 1454 1453 } 1455 1454 1456 1455 onenand_get_device(mtd, FL_READING); 1456 + 1457 + old_stats = mtd->ecc_stats; 1458 + 1457 1459 if (ops->datbuf) 1458 1460 ret = ONENAND_IS_4KB_PAGE(this) ? 1459 1461 onenand_mlc_read_ops_nolock(mtd, from, ops) : 1460 1462 onenand_read_ops_nolock(mtd, from, ops); 1461 1463 else 1462 1464 ret = onenand_read_oob_nolock(mtd, from, ops); 1465 + 1466 + if (ops->stats) { 1467 + ops->stats->uncorrectable_errors += 1468 + mtd->ecc_stats.failed - old_stats.failed; 1469 + ops->stats->corrected_bitflips += 1470 + mtd->ecc_stats.corrected - old_stats.corrected; 1471 + } 1472 + 1463 1473 onenand_release_device(mtd); 1464 1474 1465 1475 return ret;
+10
drivers/mtd/nand/raw/nand_base.c
··· 3818 3818 struct mtd_oob_ops *ops) 3819 3819 { 3820 3820 struct nand_chip *chip = mtd_to_nand(mtd); 3821 + struct mtd_ecc_stats old_stats; 3821 3822 int ret; 3822 3823 3823 3824 ops->retlen = 0; ··· 3830 3829 3831 3830 nand_get_device(chip); 3832 3831 3832 + old_stats = mtd->ecc_stats; 3833 + 3833 3834 if (!ops->datbuf) 3834 3835 ret = nand_do_read_oob(chip, from, ops); 3835 3836 else 3836 3837 ret = nand_do_read_ops(chip, from, ops); 3838 + 3839 + if (ops->stats) { 3840 + ops->stats->uncorrectable_errors += 3841 + mtd->ecc_stats.failed - old_stats.failed; 3842 + ops->stats->corrected_bitflips += 3843 + mtd->ecc_stats.corrected - old_stats.corrected; 3844 + } 3837 3845 3838 3846 nand_release_device(chip); 3839 3847 return ret;
+10
drivers/mtd/nand/spi/core.c
··· 635 635 { 636 636 struct spinand_device *spinand = mtd_to_spinand(mtd); 637 637 struct nand_device *nand = mtd_to_nanddev(mtd); 638 + struct mtd_ecc_stats old_stats; 638 639 unsigned int max_bitflips = 0; 639 640 struct nand_io_iter iter; 640 641 bool disable_ecc = false; ··· 646 645 disable_ecc = true; 647 646 648 647 mutex_lock(&spinand->lock); 648 + 649 + old_stats = mtd->ecc_stats; 649 650 650 651 nanddev_io_for_each_page(nand, NAND_PAGE_READ, from, ops, &iter) { 651 652 if (disable_ecc) ··· 669 666 ret = 0; 670 667 ops->retlen += iter.req.datalen; 671 668 ops->oobretlen += iter.req.ooblen; 669 + } 670 + 671 + if (ops->stats) { 672 + ops->stats->uncorrectable_errors += 673 + mtd->ecc_stats.failed - old_stats.failed; 674 + ops->stats->corrected_bitflips += 675 + mtd->ecc_stats.corrected - old_stats.corrected; 672 676 } 673 677 674 678 mutex_unlock(&spinand->lock);
+2
include/linux/mtd/mtd.h
··· 41 41 }; 42 42 43 43 struct mtd_req_stats { 44 + unsigned int uncorrectable_errors; 45 + unsigned int corrected_bitflips; 44 46 unsigned int max_bitflips; 45 47 }; 46 48