summaryrefslogtreecommitdiff
path: root/drivers/mtd/ubi/build.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/ubi/build.c')
-rw-r--r--drivers/mtd/ubi/build.c62
1 files changed, 62 insertions, 0 deletions
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 27de0463226e..9b7bc6326fa2 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -125,6 +125,9 @@ struct class ubi_class = {
static ssize_t dev_attribute_show(struct device *dev,
struct device_attribute *attr, char *buf);
+static ssize_t dev_attribute_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count);
/* UBI device attributes (correspond to files in '/<sysfs>/class/ubi/ubiX') */
static struct device_attribute dev_eraseblock_size =
@@ -149,6 +152,13 @@ static struct device_attribute dev_bgt_enabled =
__ATTR(bgt_enabled, S_IRUGO, dev_attribute_show, NULL);
static struct device_attribute dev_mtd_num =
__ATTR(mtd_num, S_IRUGO, dev_attribute_show, NULL);
+static struct device_attribute dev_mtd_trigger_scrub =
+ __ATTR(scrub_all, S_IRUGO | S_IWUSR,
+ dev_attribute_show, dev_attribute_store);
+static struct device_attribute dev_mtd_max_scrub_sqnum =
+ __ATTR(scrub_max_sqnum, S_IRUGO, dev_attribute_show, NULL);
+static struct device_attribute dev_mtd_min_scrub_sqnum =
+ __ATTR(scrub_min_sqnum, S_IRUGO, dev_attribute_show, NULL);
/**
* ubi_volume_notify - send a volume change notification.
@@ -341,6 +351,17 @@ int ubi_major2num(int major)
return ubi_num;
}
+static unsigned long long get_max_sqnum(struct ubi_device *ubi)
+{
+ unsigned long long max_sqnum;
+
+ spin_lock(&ubi->ltree_lock);
+ max_sqnum = ubi->global_sqnum - 1;
+ spin_unlock(&ubi->ltree_lock);
+
+ return max_sqnum;
+}
+
/* "Show" method for files in '/<sysfs>/class/ubi/ubiX/' */
static ssize_t dev_attribute_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -385,6 +406,12 @@ static ssize_t dev_attribute_show(struct device *dev,
ret = sprintf(buf, "%d\n", ubi->thread_enabled);
else if (attr == &dev_mtd_num)
ret = sprintf(buf, "%d\n", ubi->mtd->index);
+ else if (attr == &dev_mtd_trigger_scrub)
+ ret = sprintf(buf, "%d\n", atomic_read(&ubi->scrub_work_count));
+ else if (attr == &dev_mtd_max_scrub_sqnum)
+ ret = sprintf(buf, "%llu\n", get_max_sqnum(ubi));
+ else if (attr == &dev_mtd_min_scrub_sqnum)
+ ret = sprintf(buf, "%llu\n", ubi_wl_scrub_get_min_sqnum(ubi));
else
ret = -EINVAL;
@@ -404,10 +431,45 @@ static struct attribute *ubi_dev_attrs[] = {
&dev_min_io_size.attr,
&dev_bgt_enabled.attr,
&dev_mtd_num.attr,
+ &dev_mtd_trigger_scrub.attr,
+ &dev_mtd_max_scrub_sqnum.attr,
+ &dev_mtd_min_scrub_sqnum.attr,
NULL
};
ATTRIBUTE_GROUPS(ubi_dev);
+static ssize_t dev_attribute_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ struct ubi_device *ubi;
+ unsigned long long scrub_sqnum;
+
+ ubi = container_of(dev, struct ubi_device, dev);
+ ubi = ubi_get_device(ubi->ubi_num);
+ if (!ubi)
+ return -ENODEV;
+
+ if (attr == &dev_mtd_trigger_scrub) {
+ if (kstrtoull(buf, 10, &scrub_sqnum)) {
+ ret = -EINVAL;
+ goto out;
+ }
+ if (!ubi->lookuptbl) {
+ pr_err("lookuptbl is null");
+ goto out;
+ }
+ ret = ubi_wl_scrub_all(ubi, scrub_sqnum);
+ if (ret == 0)
+ ret = count;
+ }
+
+out:
+ ubi_put_device(ubi);
+ return ret;
+}
+
static void dev_release(struct device *dev)
{
struct ubi_device *ubi = container_of(dev, struct ubi_device, dev);