From adac87eab918a11e0d607318d9d2ee0ebccb4c2f Mon Sep 17 00:00:00 2001 From: Krishna Konda Date: Thu, 10 Dec 2020 12:42:30 +0530 Subject: [PATCH] mtd: Collect bad block count for ecc stats lazily Normally bad block counts for ECC stats are collected during boot time. This can be done lazily when the ECCGETSTATS ioctl is invoked on the partition. This can significantly decrease boot time, depending on the size of the partition. Also rescanning on every ioctl invocation helps in having the latest bad block count rather than depending on the count that is collected during boot. Change-Id: I43d7a769a1d4ef769823d0b5bbe132adb474f892 Signed-off-by: Murali Palnati Signed-off-by: Krishna Konda Signed-off-by: Nikhilesh Reddy Signed-off-by: Pradeep P V K Signed-off-by: Sarthak Garg --- drivers/mtd/Kconfig | 11 +++++++++++ drivers/mtd/mtdchar.c | 3 +++ drivers/mtd/mtdpart.c | 36 +++++++++++++++++++++++----------- include/linux/mtd/partitions.h | 1 + 4 files changed, 40 insertions(+), 11 deletions(-) diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 42d401ea60ee..151571f760c8 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -193,6 +193,17 @@ config MTD_PARTITIONED_MASTER the parent of the partition device be the master device, rather than what lies behind the master. +config MTD_LAZYECCSTATS + bool "MTD Lazy ECC Stats collection support" + default y + help + Normally bad block counts for ECC stats are collected at boot time. + This option delays the badblock stats collection until ECCGETSTATS + ioctl is invoked on the partition. + + This can significantly decrease boot times depending on the size of + the partition. If unsure, say 'N'. + source "drivers/mtd/chips/Kconfig" source "drivers/mtd/maps/Kconfig" diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 48832f9b215c..dcec39905adc 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -971,6 +971,9 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg) case ECCGETSTATS: { +#ifdef CONFIG_MTD_LAZYECCSTATS + part_fill_badblockstats(mtd); +#endif if (copy_to_user(argp, &mtd->ecc_stats, sizeof(struct mtd_ecc_stats))) return -EFAULT; diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 7328c066c5ba..ee3a17fe87c3 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -317,6 +317,28 @@ static inline void free_partition(struct mtd_part *p) kfree(p); } +void part_fill_badblockstats(struct mtd_info *mtd) +{ + uint64_t offs = 0; + struct mtd_info *parent; + struct mtd_part *part = mtd_to_part(mtd); + + parent = part->parent; + + if (parent->_block_isbad) { + mtd->ecc_stats.badblocks = 0; + mtd->ecc_stats.bbtblocks = 0; + + while (offs < mtd->size) { + if (mtd_block_isreserved(parent, offs + part->offset)) + mtd->ecc_stats.bbtblocks++; + else if (mtd_block_isbad(parent, offs + part->offset)) + mtd->ecc_stats.badblocks++; + offs += mtd->erasesize; + } + } +} + static struct mtd_part *allocate_partition(struct mtd_info *parent, const struct mtd_partition *part, int partno, uint64_t cur_offset) @@ -537,17 +559,9 @@ static struct mtd_part *allocate_partition(struct mtd_info *parent, slave->mtd.ecc_strength = parent->ecc_strength; slave->mtd.bitflip_threshold = parent->bitflip_threshold; - if (parent->_block_isbad) { - uint64_t offs = 0; - - while (offs < slave->mtd.size) { - if (mtd_block_isreserved(parent, offs + slave->offset)) - slave->mtd.ecc_stats.bbtblocks++; - else if (mtd_block_isbad(parent, offs + slave->offset)) - slave->mtd.ecc_stats.badblocks++; - offs += slave->mtd.erasesize; - } - } +#ifndef CONFIG_MTD_LAZYECCSTATS + part_fill_badblockstats(&(slave->mtd)); +#endif out_register: return slave; diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h index 11cb0c50cd84..aa2b92bc6c53 100644 --- a/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h @@ -68,6 +68,7 @@ struct mtd_part_parser_data { unsigned long origin; }; +void part_fill_badblockstats(struct mtd_info *mtd); /* * Functions dealing with the various ways of partitioning the space