[PATCH 1/4] ubi: Expose mean erase counter in sysfs

Rickard Andersson rickard.andersson at axis.com
Fri Oct 4 01:22:05 PDT 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 a
mean erase counter value gives 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 value only when it is 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/build.c | 44 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 30be4ed68fad..8bdfc51cacb1 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -131,6 +131,8 @@ static struct device_attribute dev_volumes_count =
 	__ATTR(volumes_count, S_IRUGO, dev_attribute_show, NULL);
 static struct device_attribute dev_max_ec =
 	__ATTR(max_ec, S_IRUGO, dev_attribute_show, NULL);
+static struct device_attribute dev_mean_ec =
+	__ATTR(mean_ec, S_IRUGO, dev_attribute_show, NULL);
 static struct device_attribute dev_reserved_for_bad =
 	__ATTR(reserved_for_bad, S_IRUGO, dev_attribute_show, NULL);
 static struct device_attribute dev_bad_peb_count =
@@ -340,6 +342,45 @@ int ubi_major2num(int major)
 	return ubi_num;
 }
 
+/**
+ * ubi_calc_mean_ec - calculate mean erase counter value.
+ * @ubi: UBI device description object
+ *
+ * Returns the mean value of the all blocks of the device.
+ * Returns zero if it was not possible to calculate the mean value.
+ */
+int ubi_calc_mean_ec(struct ubi_device *ubi)
+{
+	struct ubi_wl_entry *wl;
+	int peb;
+	int ec_count = 0;
+	int mean_ec = 0;
+	uint64_t ec_sum = 0;
+
+	for (peb = 0; peb < ubi->peb_count; peb++) {
+		int err;
+
+		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++;
+		}
+
+		spin_unlock(&ubi->wl_lock);
+	}
+
+	if (ec_count > 0)
+		mean_ec = div_u64(ec_sum, ec_count);
+
+	return mean_ec;
+}
+
 /* "Show" method for files in '/<sysfs>/class/ubi/ubiX/' */
 static ssize_t dev_attribute_show(struct device *dev,
 				  struct device_attribute *attr, char *buf)
@@ -369,6 +410,8 @@ static ssize_t dev_attribute_show(struct device *dev,
 		ret = sprintf(buf, "%d\n", ubi->vol_count - UBI_INT_VOL_COUNT);
 	else if (attr == &dev_max_ec)
 		ret = sprintf(buf, "%d\n", ubi->max_ec);
+	else if (attr == &dev_mean_ec)
+		ret = sprintf(buf, "%d\n", ubi_calc_mean_ec(ubi));
 	else if (attr == &dev_reserved_for_bad)
 		ret = sprintf(buf, "%d\n", ubi->beb_rsvd_pebs);
 	else if (attr == &dev_bad_peb_count)
@@ -395,6 +438,7 @@ static struct attribute *ubi_dev_attrs[] = {
 	&dev_total_eraseblocks.attr,
 	&dev_volumes_count.attr,
 	&dev_max_ec.attr,
+	&dev_mean_ec.attr,
 	&dev_reserved_for_bad.attr,
 	&dev_bad_peb_count.attr,
 	&dev_max_vol_count.attr,
-- 
2.30.2




More information about the linux-mtd mailing list