Skip to content

Commit 01099f6

Browse files
Rickard Anderssonrichardweinberger
authored andcommitted
ubi: Implement ioctl for detailed erase counters
Currently, "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. Also some use cases can wear the erase blocks of the fastmap area more heavily than other parts of flash. Providing detailed erase counter values give a better understanding of the overall flash wear and is needed to be able to calculate for example expected life time. There exists more detailed info in debugfs, but this information is only available for debug builds. Signed-off-by: Rickard Andersson <rickard.andersson@axis.com> Tested-by: Zhihao Cheng <chengzhihao1@huawei.com> Reviewed-by: Zhihao Cheng <chengzhihao1@huawei.com> Signed-off-by: Richard Weinberger <richard@nod.at>
1 parent 3156ceb commit 01099f6

File tree

1 file changed

+69
-0
lines changed

1 file changed

+69
-0
lines changed

drivers/mtd/ubi/cdev.c

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,69 @@ static int rename_volumes(struct ubi_device *ubi,
828828
return err;
829829
}
830830

831+
static int ubi_get_ec_info(struct ubi_device *ubi, struct ubi_ecinfo_req __user *ureq)
832+
{
833+
struct ubi_ecinfo_req req;
834+
struct ubi_wl_entry *wl;
835+
int read_cnt;
836+
int peb;
837+
int end_peb;
838+
839+
/* Copy the input arguments */
840+
if (copy_from_user(&req, ureq, sizeof(struct ubi_ecinfo_req)))
841+
return -EFAULT;
842+
843+
/* Check input arguments */
844+
if (req.length <= 0 || req.start < 0 || req.start >= ubi->peb_count)
845+
return -EINVAL;
846+
847+
if (check_add_overflow(req.start, req.length, &end_peb))
848+
return -EINVAL;
849+
850+
if (end_peb > ubi->peb_count)
851+
end_peb = ubi->peb_count;
852+
853+
/* Check access rights before filling erase_counters array */
854+
if (!access_ok(ureq->erase_counters, (end_peb-req.start) * sizeof(int32_t)))
855+
return -EFAULT;
856+
857+
/* Fill erase counter array */
858+
read_cnt = 0;
859+
for (peb = req.start; peb < end_peb; read_cnt++, peb++) {
860+
int ec;
861+
862+
if (ubi_io_is_bad(ubi, peb)) {
863+
if (__put_user(UBI_UNKNOWN, ureq->erase_counters+read_cnt))
864+
return -EFAULT;
865+
866+
continue;
867+
}
868+
869+
spin_lock(&ubi->wl_lock);
870+
871+
wl = ubi->lookuptbl[peb];
872+
if (wl)
873+
ec = wl->ec;
874+
else
875+
ec = UBI_UNKNOWN;
876+
877+
spin_unlock(&ubi->wl_lock);
878+
879+
if (__put_user(ec, ureq->erase_counters+read_cnt))
880+
return -EFAULT;
881+
882+
}
883+
884+
/* Return actual read length */
885+
req.read_length = read_cnt;
886+
887+
/* Copy everything except erase counter array */
888+
if (copy_to_user(ureq, &req, sizeof(struct ubi_ecinfo_req)))
889+
return -EFAULT;
890+
891+
return 0;
892+
}
893+
831894
static long ubi_cdev_ioctl(struct file *file, unsigned int cmd,
832895
unsigned long arg)
833896
{
@@ -991,6 +1054,12 @@ static long ubi_cdev_ioctl(struct file *file, unsigned int cmd,
9911054
break;
9921055
}
9931056

1057+
case UBI_IOCECNFO:
1058+
{
1059+
err = ubi_get_ec_info(ubi, argp);
1060+
break;
1061+
}
1062+
9941063
default:
9951064
err = -ENOTTY;
9961065
break;

0 commit comments

Comments
 (0)