[PATCH 2/2] ubi: Implement 'UBI_IOCECNFO' for reading erase counters
Rickard Andersson
rickard.andersson at axis.com
Thu Nov 21 02:21:57 PST 2024
Currently, only "max_ec" can be read from sysfs, which provides a
limited view of the flash device’s wear. In certain cases, such as
bugs in the wear-leveling algorithm, specific blocks can be worn down
more than others, resulting in uneven wear distribution. Providing
mean erase counter values give a better understanding of the overall
flash wear.
There exists more detailed info in debugfs, but this information is
only available for debug builds.
This patch calculates the mean and max values only when they are
requested. This calculation typically takes 2.7 ms for an UBI device
with 4091 blocks running on a single core Cortex-A9 at 792 MHz.
Signed-off-by: Rickard Andersson <rickard.andersson at axis.com>
---
drivers/mtd/ubi/cdev.c | 75 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 75 insertions(+)
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index 0d8f04cf03c5..2b3545826609 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -828,6 +828,75 @@ static int rename_volumes(struct ubi_device *ubi,
return err;
}
+static int ubi_get_info(struct ubi_device *ubi, void __user *argp)
+{
+ struct ubi_ecinfo_res info;
+ struct ubi_wl_entry *wl;
+ int peb;
+ int ec_count = 0;
+ int ec_count_fastmap = 0;
+ uint64_t ec_sum = 0;
+ uint64_t ec_sum_fastmap = 0;
+ int max_ec = 0;
+ int max_ec_data = 0;
+#ifdef CONFIG_MTD_UBI_FASTMAP
+ const bool fastmap = true;
+#else
+ const bool fastmap = false;
+#endif
+ memset(&info, 0, sizeof(info));
+
+ for (peb = 0; peb < ubi->peb_count; peb++) {
+ int err;
+
+ /*
+ * We have looped through the fastmap blocks, lets store fastmap data if
+ * fastmap is enabled.
+ */
+ if (fastmap && peb == UBI_FM_MAX_START) {
+ ec_sum_fastmap = ec_sum;
+ ec_count_fastmap = ec_count;
+ info.mean_ec_fastmap = div_u64(ec_sum_fastmap, ec_count_fastmap);
+ info.max_ec_fastmap = max_ec;
+ }
+
+ err = ubi_io_is_bad(ubi, peb);
+ if (err)
+ continue;
+
+ spin_lock(&ubi->wl_lock);
+
+ wl = ubi->lookuptbl[peb];
+ if (wl) {
+ ec_sum += wl->ec;
+ ec_count++;
+
+ if (max_ec < wl->ec)
+ max_ec = wl->ec;
+ if (fastmap && (peb >= UBI_FM_MAX_START) && (max_ec_data < wl->ec))
+ max_ec_data = wl->ec;
+ }
+
+ spin_unlock(&ubi->wl_lock);
+ }
+
+ if (ec_count > 0) {
+ info.max_ec = max_ec;
+ info.mean_ec = div_u64(ec_sum, ec_count);
+
+ if (fastmap && (ec_count > ec_count_fastmap)) {
+ info.mean_ec_data = div_u64(ec_sum - ec_sum_fastmap,
+ ec_count - ec_count_fastmap);
+ info.max_ec_data = max_ec_data;
+ }
+ }
+
+ if (copy_to_user(argp, &info, sizeof(info)))
+ return -EFAULT;
+
+ return 0;
+}
+
static long ubi_cdev_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
@@ -991,6 +1060,12 @@ static long ubi_cdev_ioctl(struct file *file, unsigned int cmd,
break;
}
+ case UBI_IOCECNFO:
+ {
+ err = ubi_get_info(ubi, argp);
+ break;
+ }
+
default:
err = -ENOTTY;
break;
--
2.30.2
More information about the linux-mtd
mailing list