[PATCH 5/5] UBI: Expose UBI statistics interface
Richard Weinberger
richard at nod.at
Thu Nov 5 14:56:57 PST 2015
UBI_IOCSTATS allows userspace to query read and erase
counters and can take action.
Signed-off-by: Richard Weinberger <richard at nod.at>
---
drivers/mtd/ubi/cdev.c | 23 +++++++++++++++++
drivers/mtd/ubi/ubi.h | 1 +
drivers/mtd/ubi/wl.c | 61 +++++++++++++++++++++++++++++++++++++++++++++
include/uapi/mtd/ubi-user.h | 16 ++++++++++++
4 files changed, 101 insertions(+)
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index f500451..ab58c5f 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -992,6 +992,29 @@ static long ubi_cdev_ioctl(struct file *file, unsigned int cmd,
err = ubi_bitrot_check(ubi, pnum, 1);
break;
}
+ /* Get UBI stats */
+ case UBI_IOCSTATS:
+ {
+ struct ubi_stats_req *req;
+ struct ubi_stats_req __user *ureq = argp;
+
+ req = kmalloc(sizeof(struct ubi_stats_req), GFP_KERNEL);
+ if (!req) {
+ err = -ENOMEM;
+ break;
+ }
+
+ err = copy_from_user(req, argp, sizeof(struct ubi_stats_req));
+ if (err) {
+ kfree(req);
+ err = -EFAULT;
+ break;
+ }
+
+ err = ubi_wl_report_stats(ubi, req, ureq->stats);
+ kfree(req);
+ break;
+ }
default:
err = -ENOTTY;
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index 9bfede0..c6c2964 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -865,6 +865,7 @@ void ubi_refill_pools(struct ubi_device *ubi);
int ubi_ensure_anchor_pebs(struct ubi_device *ubi);
int ubi_bitrot_check(struct ubi_device *ubi, int pnum, int force_scrub);
void ubi_wl_update_rc(struct ubi_device *ubi, int pnum);
+int ubi_wl_report_stats(struct ubi_device *ubi, struct ubi_stats_req *req, struct ubi_stats_entry __user *se);
/* io.c */
int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index 43466d4..90b715e 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -102,6 +102,7 @@
#include <linux/crc32.h>
#include <linux/freezer.h>
#include <linux/kthread.h>
+#include <linux/uaccess.h>
#include "ubi.h"
#include "wl.h"
@@ -482,6 +483,66 @@ static void ubi_wl_get_rc(struct ubi_wl_entry *e, struct ubi_stats_entry *se)
#endif
}
+static int ubi_wl_fill_stats_entry(struct ubi_device *ubi,
+ struct ubi_stats_entry *se, int pnum)
+{
+ struct ubi_wl_entry *e;
+
+ spin_lock(&ubi->wl_lock);
+ e = ubi->lookuptbl[pnum];
+ if (e) {
+ se->pnum = pnum;
+ se->ec = e->ec;
+ ubi_wl_get_rc(e, se);
+ }
+ spin_unlock(&ubi->wl_lock);
+
+ return e ? 0 : -1;
+}
+
+
+int ubi_wl_report_stats(struct ubi_device *ubi, struct ubi_stats_req *req,
+ struct ubi_stats_entry __user *se)
+{
+ int i, pnum, peb_end, peb_start;
+ struct ubi_stats_entry tmp_se;
+ size_t write_len;
+ int n = 0;
+
+ pnum = req->req_pnum;
+ if (pnum != -1) {
+ if (pnum < 0 || pnum >= ubi->peb_count)
+ return -EINVAL;
+
+ peb_start = pnum;
+ peb_end = pnum + 1;
+ write_len = sizeof(*se);
+ } else {
+ peb_start = 0;
+ peb_end = ubi->peb_count;
+ write_len = sizeof(*se) * ubi->good_peb_count;
+ }
+
+ if (write_len > req->req_len - sizeof(*req))
+ return -EFAULT;
+
+ if (!access_ok(VERIFY_WRITE, se, req->req_len - sizeof(*req) + write_len))
+ return -EFAULT;
+
+ for (i = peb_start; i < peb_end; i++) {
+ if (ubi_wl_fill_stats_entry(ubi, &tmp_se, i) == 0) {
+ if (__copy_to_user(se, &tmp_se, sizeof(tmp_se)))
+ return -EFAULT;
+
+ se++;
+ n++;
+ }
+ }
+
+ return n;
+}
+
+
/**
* sync_erase - synchronously erase a physical eraseblock.
* @ubi: UBI device description object
diff --git a/include/uapi/mtd/ubi-user.h b/include/uapi/mtd/ubi-user.h
index 6e1ec98..8610440 100644
--- a/include/uapi/mtd/ubi-user.h
+++ b/include/uapi/mtd/ubi-user.h
@@ -173,6 +173,8 @@
#define UBI_IOCRPEB _IOW(UBI_IOC_MAGIC, 4, __s32)
#define UBI_IOCSPEB _IOW(UBI_IOC_MAGIC, 5, __s32)
+#define UBI_IOCSTATS _IOW(UBI_IOC_MAGIC, 6, struct ubi_stats_req)
+
/* ioctl commands of the UBI control character device */
#define UBI_CTRL_IOC_MAGIC 'o'
@@ -445,4 +447,18 @@ struct ubi_blkcreate_req {
__s8 padding[128];
} __packed;
+struct ubi_stats_entry {
+ __s32 pnum;
+ __s32 ec;
+ __s32 rc;
+ __s32 padding;
+} __packed;
+
+struct ubi_stats_req {
+ __s32 req_len;
+ __s32 req_pnum;
+ __s32 padding[2];
+ struct ubi_stats_entry stats[0];
+} __packed;
+
#endif /* __UBI_USER_H__ */
--
1.8.4.5
More information about the linux-mtd
mailing list