Loading drivers/mtd/ubi/attach.c +15 −2 Original line number Original line Diff line number Diff line Loading @@ -821,9 +821,22 @@ struct ubi_ainf_peb *ubi_early_get_peb(struct ubi_device *ubi, int err = 0; int err = 0; struct ubi_ainf_peb *aeb, *tmp_aeb; struct ubi_ainf_peb *aeb, *tmp_aeb; if (!list_empty(&ai->free)) { list_for_each_entry_safe(aeb, tmp_aeb, &ai->free, u.list) { aeb = list_entry(ai->free.next, struct ubi_ainf_peb, u.list); list_del(&aeb->u.list); list_del(&aeb->u.list); if (aeb->ec == UBI_UNKNOWN) { ubi_err(ubi, "PEB %d in freelist has unknown EC", aeb->pnum); aeb->ec = ai->mean_ec; } err = early_erase_peb(ubi, ai, aeb->pnum, aeb->ec+1); if (err) { ubi_err(ubi, "Erase failed for PEB %d in freelist", aeb->pnum); list_add(&aeb->u.list, &ai->erase); continue; } aeb->ec += 1; dbg_bld("return free PEB %d, EC %d", aeb->pnum, aeb->ec); dbg_bld("return free PEB %d, EC %d", aeb->pnum, aeb->ec); return aeb; return aeb; } } Loading drivers/mtd/ubi/block.c +5 −4 Original line number Original line Diff line number Diff line Loading @@ -121,7 +121,7 @@ static int __init ubiblock_set_param(const char *val, return -EINVAL; return -EINVAL; } } strcpy(buf, val); strlcpy(buf, val, sizeof(buf)); /* Get rid of the final newline */ /* Get rid of the final newline */ if (buf[len - 1] == '\n') if (buf[len - 1] == '\n') Loading @@ -141,12 +141,12 @@ static int __init ubiblock_set_param(const char *val, ret = kstrtoint(tokens[1], 10, ¶m->vol_id); ret = kstrtoint(tokens[1], 10, ¶m->vol_id); if (ret < 0) { if (ret < 0) { param->vol_id = -1; param->vol_id = -1; strcpy(param->name, tokens[1]); strlcpy(param->name, tokens[1], UBIBLOCK_PARAM_LEN+1); } } } else { } else { /* One parameter: must be device path */ /* One parameter: must be device path */ strcpy(param->name, tokens[0]); strlcpy(param->name, tokens[0], UBIBLOCK_PARAM_LEN+1); param->ubi_num = -1; param->ubi_num = -1; param->vol_id = -1; param->vol_id = -1; } } Loading Loading @@ -412,7 +412,8 @@ int ubiblock_create(struct ubi_volume_info *vi) goto out_put_disk; goto out_put_disk; } } gd->private_data = dev; gd->private_data = dev; sprintf(gd->disk_name, "ubiblock%d_%d", dev->ubi_num, dev->vol_id); scnprintf(gd->disk_name, DISK_NAME_LEN, "ubiblock%d_%d", dev->ubi_num, dev->vol_id); set_capacity(gd, disk_capacity); set_capacity(gd, disk_capacity); dev->gd = gd; dev->gd = gd; Loading drivers/mtd/ubi/build.c +95 −16 Original line number Original line Diff line number Diff line Loading @@ -95,7 +95,7 @@ static DEFINE_SPINLOCK(ubi_devices_lock); static ssize_t version_show(struct class *class, struct class_attribute *attr, static ssize_t version_show(struct class *class, struct class_attribute *attr, char *buf) char *buf) { { return sprintf(buf, "%d\n", UBI_VERSION); return scnprintf(buf, sizeof(int), "%d\n", UBI_VERSION); } } static CLASS_ATTR_RO(version); static CLASS_ATTR_RO(version); Loading @@ -114,6 +114,9 @@ struct class ubi_class = { static ssize_t dev_attribute_show(struct device *dev, static ssize_t dev_attribute_show(struct device *dev, struct device_attribute *attr, char *buf); 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') */ /* UBI device attributes (correspond to files in '/<sysfs>/class/ubi/ubiX') */ static struct device_attribute dev_eraseblock_size = static struct device_attribute dev_eraseblock_size = Loading @@ -140,6 +143,13 @@ static struct device_attribute dev_mtd_num = __ATTR(mtd_num, S_IRUGO, dev_attribute_show, NULL); __ATTR(mtd_num, S_IRUGO, dev_attribute_show, NULL); static struct device_attribute dev_ro_mode = static struct device_attribute dev_ro_mode = __ATTR(ro_mode, S_IRUGO, dev_attribute_show, NULL); __ATTR(ro_mode, S_IRUGO, dev_attribute_show, NULL); static struct device_attribute dev_mtd_trigger_scrub = __ATTR(scrub_all, 0644, dev_attribute_show, dev_attribute_store); static struct device_attribute dev_mtd_max_scrub_sqnum = __ATTR(scrub_max_sqnum, 0444, dev_attribute_show, NULL); static struct device_attribute dev_mtd_min_scrub_sqnum = __ATTR(scrub_min_sqnum, 0444, dev_attribute_show, NULL); /** /** * ubi_volume_notify - send a volume change notification. * ubi_volume_notify - send a volume change notification. Loading Loading @@ -332,6 +342,17 @@ int ubi_major2num(int major) return ubi_num; 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/' */ /* "Show" method for files in '/<sysfs>/class/ubi/ubiX/' */ static ssize_t dev_attribute_show(struct device *dev, static ssize_t dev_attribute_show(struct device *dev, struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf) Loading @@ -355,29 +376,50 @@ static ssize_t dev_attribute_show(struct device *dev, return -ENODEV; return -ENODEV; if (attr == &dev_eraseblock_size) if (attr == &dev_eraseblock_size) ret = sprintf(buf, "%d\n", ubi->leb_size); ret = scnprintf(buf, sizeof(int), "%d\n", ubi->leb_size); else if (attr == &dev_avail_eraseblocks) else if (attr == &dev_avail_eraseblocks) ret = sprintf(buf, "%d\n", ubi->avail_pebs); ret = scnprintf(buf, sizeof(int), "%d\n", ubi->avail_pebs); else if (attr == &dev_total_eraseblocks) else if (attr == &dev_total_eraseblocks) ret = sprintf(buf, "%d\n", ubi->good_peb_count); ret = scnprintf(buf, sizeof(int), "%d\n", ubi->good_peb_count); else if (attr == &dev_volumes_count) else if (attr == &dev_volumes_count) ret = sprintf(buf, "%d\n", ubi->vol_count - UBI_INT_VOL_COUNT); ret = scnprintf(buf, sizeof(int), "%d\n", ubi->vol_count - UBI_INT_VOL_COUNT); else if (attr == &dev_max_ec) else if (attr == &dev_max_ec) ret = sprintf(buf, "%d\n", ubi->max_ec); ret = scnprintf(buf, sizeof(int), "%d\n", ubi->max_ec); else if (attr == &dev_reserved_for_bad) else if (attr == &dev_reserved_for_bad) ret = sprintf(buf, "%d\n", ubi->beb_rsvd_pebs); ret = scnprintf(buf, sizeof(int), "%d\n", ubi->beb_rsvd_pebs); else if (attr == &dev_bad_peb_count) else if (attr == &dev_bad_peb_count) ret = sprintf(buf, "%d\n", ubi->bad_peb_count); ret = scnprintf(buf, sizeof(int), "%d\n", ubi->bad_peb_count); else if (attr == &dev_max_vol_count) else if (attr == &dev_max_vol_count) ret = sprintf(buf, "%d\n", ubi->vtbl_slots); ret = scnprintf(buf, sizeof(int), "%d\n", ubi->vtbl_slots); else if (attr == &dev_min_io_size) else if (attr == &dev_min_io_size) ret = sprintf(buf, "%d\n", ubi->min_io_size); ret = scnprintf(buf, sizeof(int), "%d\n", ubi->min_io_size); else if (attr == &dev_bgt_enabled) else if (attr == &dev_bgt_enabled) ret = sprintf(buf, "%d\n", ubi->thread_enabled); ret = scnprintf(buf, sizeof(int), "%d\n", ubi->thread_enabled); else if (attr == &dev_mtd_num) else if (attr == &dev_mtd_num) ret = sprintf(buf, "%d\n", ubi->mtd->index); ret = scnprintf(buf, sizeof(int), "%d\n", ubi->mtd->index); else if (attr == &dev_ro_mode) else if (attr == &dev_ro_mode) ret = sprintf(buf, "%d\n", ubi->ro_mode); ret = scnprintf(buf, sizeof(int), "%d\n", ubi->ro_mode); else if (attr == &dev_mtd_trigger_scrub) ret = scnprintf(buf, sizeof(int), "%d\n", atomic_read(&ubi->scrub_work_count)); else if (attr == &dev_mtd_max_scrub_sqnum) ret = scnprintf(buf, sizeof(unsigned long long), "%llu\n", get_max_sqnum(ubi)); else if (attr == &dev_mtd_min_scrub_sqnum) ret = scnprintf(buf, sizeof(unsigned long long), "%llu\n", ubi_wl_scrub_get_min_sqnum(ubi)); else else ret = -EINVAL; ret = -EINVAL; Loading @@ -398,10 +440,46 @@ static struct attribute *ubi_dev_attrs[] = { &dev_bgt_enabled.attr, &dev_bgt_enabled.attr, &dev_mtd_num.attr, &dev_mtd_num.attr, &dev_ro_mode.attr, &dev_ro_mode.attr, &dev_mtd_trigger_scrub.attr, &dev_mtd_max_scrub_sqnum.attr, &dev_mtd_min_scrub_sqnum.attr, NULL NULL }; }; ATTRIBUTE_GROUPS(ubi_dev); 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 = 0; 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\n"); ret = -ENOENT; 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) static void dev_release(struct device *dev) { { struct ubi_device *ubi = container_of(dev, struct ubi_device, dev); struct ubi_device *ubi = container_of(dev, struct ubi_device, dev); Loading Loading @@ -438,7 +516,8 @@ static int uif_init(struct ubi_device *ubi) int i, err; int i, err; dev_t dev; dev_t dev; sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num); scnprintf(ubi->ubi_name, sizeof(UBI_NAME_STR) + 5, UBI_NAME_STR "%d", ubi->ubi_num); /* /* * Major numbers for the UBI character devices are allocated * Major numbers for the UBI character devices are allocated Loading Loading @@ -1376,7 +1455,7 @@ static int ubi_mtd_param_parse(const char *val, const struct kernel_param *kp) return 0; return 0; } } strcpy(buf, val); strlcpy(buf, val, sizeof(buf)); /* Get rid of the final newline */ /* Get rid of the final newline */ if (buf[len - 1] == '\n') if (buf[len - 1] == '\n') Loading @@ -1391,7 +1470,7 @@ static int ubi_mtd_param_parse(const char *val, const struct kernel_param *kp) } } p = &mtd_dev_param[mtd_devs]; p = &mtd_dev_param[mtd_devs]; strcpy(&p->name[0], tokens[0]); strlcpy(&p->name[0], tokens[0], MTD_PARAM_LEN_MAX); token = tokens[1]; token = tokens[1]; if (token) { if (token) { Loading drivers/mtd/ubi/io.c +11 −0 Original line number Original line Diff line number Diff line Loading @@ -1056,6 +1056,15 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum, dbg_io("write VID header to PEB %d", pnum); dbg_io("write VID header to PEB %d", pnum); ubi_assert(pnum >= 0 && pnum < ubi->peb_count); ubi_assert(pnum >= 0 && pnum < ubi->peb_count); /* * Re-erase the PEB before using it. This should minimize any issues * from decay of charge in this block. */ if (ubi->wl_is_inited) { err = ubi_wl_re_erase_peb(ubi, pnum); if (err) return err; } err = self_check_peb_ec_hdr(ubi, pnum); err = self_check_peb_ec_hdr(ubi, pnum); if (err) if (err) return err; return err; Loading @@ -1074,6 +1083,8 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum, err = ubi_io_write(ubi, p, pnum, ubi->vid_hdr_aloffset, err = ubi_io_write(ubi, p, pnum, ubi->vid_hdr_aloffset, ubi->vid_hdr_alsize); ubi->vid_hdr_alsize); if (!err && ubi->wl_is_inited) ubi_wl_update_peb_sqnum(ubi, pnum, vid_hdr); return err; return err; } } Loading drivers/mtd/ubi/ubi.h +13 −1 Original line number Original line Diff line number Diff line Loading @@ -170,6 +170,8 @@ struct ubi_vid_io_buf { * @u.list: link in the protection queue * @u.list: link in the protection queue * @ec: erase counter * @ec: erase counter * @pnum: physical eraseblock number * @pnum: physical eraseblock number * @tagged_scrub_all: if the entry is tagged for scrub all * @sqnum: The sequence number of the vol header. * * * This data structure is used in the WL sub-system. Each physical eraseblock * This data structure is used in the WL sub-system. Each physical eraseblock * has a corresponding &struct wl_entry object which may be kept in different * has a corresponding &struct wl_entry object which may be kept in different Loading @@ -182,6 +184,8 @@ struct ubi_wl_entry { } u; } u; int ec; int ec; int pnum; int pnum; unsigned int tagged_scrub_all:1; unsigned long long sqnum; }; }; /** /** Loading Loading @@ -625,6 +629,9 @@ struct ubi_device { struct task_struct *bgt_thread; struct task_struct *bgt_thread; int thread_enabled; int thread_enabled; char bgt_name[sizeof(UBI_BGT_NAME_PATTERN)+2]; char bgt_name[sizeof(UBI_BGT_NAME_PATTERN)+2]; bool scrub_in_progress; atomic_t scrub_work_count; int wl_is_inited; /* I/O sub-system's stuff */ /* I/O sub-system's stuff */ long long flash_size; long long flash_size; Loading Loading @@ -919,7 +926,12 @@ int ubi_is_erase_work(struct ubi_work *wrk); void ubi_refill_pools(struct ubi_device *ubi); void ubi_refill_pools(struct ubi_device *ubi); int ubi_ensure_anchor_pebs(struct ubi_device *ubi); int ubi_ensure_anchor_pebs(struct ubi_device *ubi); int ubi_bitflip_check(struct ubi_device *ubi, int pnum, int force_scrub); int ubi_bitflip_check(struct ubi_device *ubi, int pnum, int force_scrub); ssize_t ubi_wl_scrub_all(struct ubi_device *ubi, unsigned long long scrub_sqnum); void ubi_wl_update_peb_sqnum(struct ubi_device *ubi, int pnum, struct ubi_vid_hdr *vid_hdr); unsigned long long ubi_wl_scrub_get_min_sqnum(struct ubi_device *ubi); int ubi_wl_re_erase_peb(struct ubi_device *ubi, int pnum); /* io.c */ /* io.c */ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset, int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset, int len); int len); Loading Loading
drivers/mtd/ubi/attach.c +15 −2 Original line number Original line Diff line number Diff line Loading @@ -821,9 +821,22 @@ struct ubi_ainf_peb *ubi_early_get_peb(struct ubi_device *ubi, int err = 0; int err = 0; struct ubi_ainf_peb *aeb, *tmp_aeb; struct ubi_ainf_peb *aeb, *tmp_aeb; if (!list_empty(&ai->free)) { list_for_each_entry_safe(aeb, tmp_aeb, &ai->free, u.list) { aeb = list_entry(ai->free.next, struct ubi_ainf_peb, u.list); list_del(&aeb->u.list); list_del(&aeb->u.list); if (aeb->ec == UBI_UNKNOWN) { ubi_err(ubi, "PEB %d in freelist has unknown EC", aeb->pnum); aeb->ec = ai->mean_ec; } err = early_erase_peb(ubi, ai, aeb->pnum, aeb->ec+1); if (err) { ubi_err(ubi, "Erase failed for PEB %d in freelist", aeb->pnum); list_add(&aeb->u.list, &ai->erase); continue; } aeb->ec += 1; dbg_bld("return free PEB %d, EC %d", aeb->pnum, aeb->ec); dbg_bld("return free PEB %d, EC %d", aeb->pnum, aeb->ec); return aeb; return aeb; } } Loading
drivers/mtd/ubi/block.c +5 −4 Original line number Original line Diff line number Diff line Loading @@ -121,7 +121,7 @@ static int __init ubiblock_set_param(const char *val, return -EINVAL; return -EINVAL; } } strcpy(buf, val); strlcpy(buf, val, sizeof(buf)); /* Get rid of the final newline */ /* Get rid of the final newline */ if (buf[len - 1] == '\n') if (buf[len - 1] == '\n') Loading @@ -141,12 +141,12 @@ static int __init ubiblock_set_param(const char *val, ret = kstrtoint(tokens[1], 10, ¶m->vol_id); ret = kstrtoint(tokens[1], 10, ¶m->vol_id); if (ret < 0) { if (ret < 0) { param->vol_id = -1; param->vol_id = -1; strcpy(param->name, tokens[1]); strlcpy(param->name, tokens[1], UBIBLOCK_PARAM_LEN+1); } } } else { } else { /* One parameter: must be device path */ /* One parameter: must be device path */ strcpy(param->name, tokens[0]); strlcpy(param->name, tokens[0], UBIBLOCK_PARAM_LEN+1); param->ubi_num = -1; param->ubi_num = -1; param->vol_id = -1; param->vol_id = -1; } } Loading Loading @@ -412,7 +412,8 @@ int ubiblock_create(struct ubi_volume_info *vi) goto out_put_disk; goto out_put_disk; } } gd->private_data = dev; gd->private_data = dev; sprintf(gd->disk_name, "ubiblock%d_%d", dev->ubi_num, dev->vol_id); scnprintf(gd->disk_name, DISK_NAME_LEN, "ubiblock%d_%d", dev->ubi_num, dev->vol_id); set_capacity(gd, disk_capacity); set_capacity(gd, disk_capacity); dev->gd = gd; dev->gd = gd; Loading
drivers/mtd/ubi/build.c +95 −16 Original line number Original line Diff line number Diff line Loading @@ -95,7 +95,7 @@ static DEFINE_SPINLOCK(ubi_devices_lock); static ssize_t version_show(struct class *class, struct class_attribute *attr, static ssize_t version_show(struct class *class, struct class_attribute *attr, char *buf) char *buf) { { return sprintf(buf, "%d\n", UBI_VERSION); return scnprintf(buf, sizeof(int), "%d\n", UBI_VERSION); } } static CLASS_ATTR_RO(version); static CLASS_ATTR_RO(version); Loading @@ -114,6 +114,9 @@ struct class ubi_class = { static ssize_t dev_attribute_show(struct device *dev, static ssize_t dev_attribute_show(struct device *dev, struct device_attribute *attr, char *buf); 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') */ /* UBI device attributes (correspond to files in '/<sysfs>/class/ubi/ubiX') */ static struct device_attribute dev_eraseblock_size = static struct device_attribute dev_eraseblock_size = Loading @@ -140,6 +143,13 @@ static struct device_attribute dev_mtd_num = __ATTR(mtd_num, S_IRUGO, dev_attribute_show, NULL); __ATTR(mtd_num, S_IRUGO, dev_attribute_show, NULL); static struct device_attribute dev_ro_mode = static struct device_attribute dev_ro_mode = __ATTR(ro_mode, S_IRUGO, dev_attribute_show, NULL); __ATTR(ro_mode, S_IRUGO, dev_attribute_show, NULL); static struct device_attribute dev_mtd_trigger_scrub = __ATTR(scrub_all, 0644, dev_attribute_show, dev_attribute_store); static struct device_attribute dev_mtd_max_scrub_sqnum = __ATTR(scrub_max_sqnum, 0444, dev_attribute_show, NULL); static struct device_attribute dev_mtd_min_scrub_sqnum = __ATTR(scrub_min_sqnum, 0444, dev_attribute_show, NULL); /** /** * ubi_volume_notify - send a volume change notification. * ubi_volume_notify - send a volume change notification. Loading Loading @@ -332,6 +342,17 @@ int ubi_major2num(int major) return ubi_num; 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/' */ /* "Show" method for files in '/<sysfs>/class/ubi/ubiX/' */ static ssize_t dev_attribute_show(struct device *dev, static ssize_t dev_attribute_show(struct device *dev, struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf) Loading @@ -355,29 +376,50 @@ static ssize_t dev_attribute_show(struct device *dev, return -ENODEV; return -ENODEV; if (attr == &dev_eraseblock_size) if (attr == &dev_eraseblock_size) ret = sprintf(buf, "%d\n", ubi->leb_size); ret = scnprintf(buf, sizeof(int), "%d\n", ubi->leb_size); else if (attr == &dev_avail_eraseblocks) else if (attr == &dev_avail_eraseblocks) ret = sprintf(buf, "%d\n", ubi->avail_pebs); ret = scnprintf(buf, sizeof(int), "%d\n", ubi->avail_pebs); else if (attr == &dev_total_eraseblocks) else if (attr == &dev_total_eraseblocks) ret = sprintf(buf, "%d\n", ubi->good_peb_count); ret = scnprintf(buf, sizeof(int), "%d\n", ubi->good_peb_count); else if (attr == &dev_volumes_count) else if (attr == &dev_volumes_count) ret = sprintf(buf, "%d\n", ubi->vol_count - UBI_INT_VOL_COUNT); ret = scnprintf(buf, sizeof(int), "%d\n", ubi->vol_count - UBI_INT_VOL_COUNT); else if (attr == &dev_max_ec) else if (attr == &dev_max_ec) ret = sprintf(buf, "%d\n", ubi->max_ec); ret = scnprintf(buf, sizeof(int), "%d\n", ubi->max_ec); else if (attr == &dev_reserved_for_bad) else if (attr == &dev_reserved_for_bad) ret = sprintf(buf, "%d\n", ubi->beb_rsvd_pebs); ret = scnprintf(buf, sizeof(int), "%d\n", ubi->beb_rsvd_pebs); else if (attr == &dev_bad_peb_count) else if (attr == &dev_bad_peb_count) ret = sprintf(buf, "%d\n", ubi->bad_peb_count); ret = scnprintf(buf, sizeof(int), "%d\n", ubi->bad_peb_count); else if (attr == &dev_max_vol_count) else if (attr == &dev_max_vol_count) ret = sprintf(buf, "%d\n", ubi->vtbl_slots); ret = scnprintf(buf, sizeof(int), "%d\n", ubi->vtbl_slots); else if (attr == &dev_min_io_size) else if (attr == &dev_min_io_size) ret = sprintf(buf, "%d\n", ubi->min_io_size); ret = scnprintf(buf, sizeof(int), "%d\n", ubi->min_io_size); else if (attr == &dev_bgt_enabled) else if (attr == &dev_bgt_enabled) ret = sprintf(buf, "%d\n", ubi->thread_enabled); ret = scnprintf(buf, sizeof(int), "%d\n", ubi->thread_enabled); else if (attr == &dev_mtd_num) else if (attr == &dev_mtd_num) ret = sprintf(buf, "%d\n", ubi->mtd->index); ret = scnprintf(buf, sizeof(int), "%d\n", ubi->mtd->index); else if (attr == &dev_ro_mode) else if (attr == &dev_ro_mode) ret = sprintf(buf, "%d\n", ubi->ro_mode); ret = scnprintf(buf, sizeof(int), "%d\n", ubi->ro_mode); else if (attr == &dev_mtd_trigger_scrub) ret = scnprintf(buf, sizeof(int), "%d\n", atomic_read(&ubi->scrub_work_count)); else if (attr == &dev_mtd_max_scrub_sqnum) ret = scnprintf(buf, sizeof(unsigned long long), "%llu\n", get_max_sqnum(ubi)); else if (attr == &dev_mtd_min_scrub_sqnum) ret = scnprintf(buf, sizeof(unsigned long long), "%llu\n", ubi_wl_scrub_get_min_sqnum(ubi)); else else ret = -EINVAL; ret = -EINVAL; Loading @@ -398,10 +440,46 @@ static struct attribute *ubi_dev_attrs[] = { &dev_bgt_enabled.attr, &dev_bgt_enabled.attr, &dev_mtd_num.attr, &dev_mtd_num.attr, &dev_ro_mode.attr, &dev_ro_mode.attr, &dev_mtd_trigger_scrub.attr, &dev_mtd_max_scrub_sqnum.attr, &dev_mtd_min_scrub_sqnum.attr, NULL NULL }; }; ATTRIBUTE_GROUPS(ubi_dev); 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 = 0; 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\n"); ret = -ENOENT; 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) static void dev_release(struct device *dev) { { struct ubi_device *ubi = container_of(dev, struct ubi_device, dev); struct ubi_device *ubi = container_of(dev, struct ubi_device, dev); Loading Loading @@ -438,7 +516,8 @@ static int uif_init(struct ubi_device *ubi) int i, err; int i, err; dev_t dev; dev_t dev; sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num); scnprintf(ubi->ubi_name, sizeof(UBI_NAME_STR) + 5, UBI_NAME_STR "%d", ubi->ubi_num); /* /* * Major numbers for the UBI character devices are allocated * Major numbers for the UBI character devices are allocated Loading Loading @@ -1376,7 +1455,7 @@ static int ubi_mtd_param_parse(const char *val, const struct kernel_param *kp) return 0; return 0; } } strcpy(buf, val); strlcpy(buf, val, sizeof(buf)); /* Get rid of the final newline */ /* Get rid of the final newline */ if (buf[len - 1] == '\n') if (buf[len - 1] == '\n') Loading @@ -1391,7 +1470,7 @@ static int ubi_mtd_param_parse(const char *val, const struct kernel_param *kp) } } p = &mtd_dev_param[mtd_devs]; p = &mtd_dev_param[mtd_devs]; strcpy(&p->name[0], tokens[0]); strlcpy(&p->name[0], tokens[0], MTD_PARAM_LEN_MAX); token = tokens[1]; token = tokens[1]; if (token) { if (token) { Loading
drivers/mtd/ubi/io.c +11 −0 Original line number Original line Diff line number Diff line Loading @@ -1056,6 +1056,15 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum, dbg_io("write VID header to PEB %d", pnum); dbg_io("write VID header to PEB %d", pnum); ubi_assert(pnum >= 0 && pnum < ubi->peb_count); ubi_assert(pnum >= 0 && pnum < ubi->peb_count); /* * Re-erase the PEB before using it. This should minimize any issues * from decay of charge in this block. */ if (ubi->wl_is_inited) { err = ubi_wl_re_erase_peb(ubi, pnum); if (err) return err; } err = self_check_peb_ec_hdr(ubi, pnum); err = self_check_peb_ec_hdr(ubi, pnum); if (err) if (err) return err; return err; Loading @@ -1074,6 +1083,8 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum, err = ubi_io_write(ubi, p, pnum, ubi->vid_hdr_aloffset, err = ubi_io_write(ubi, p, pnum, ubi->vid_hdr_aloffset, ubi->vid_hdr_alsize); ubi->vid_hdr_alsize); if (!err && ubi->wl_is_inited) ubi_wl_update_peb_sqnum(ubi, pnum, vid_hdr); return err; return err; } } Loading
drivers/mtd/ubi/ubi.h +13 −1 Original line number Original line Diff line number Diff line Loading @@ -170,6 +170,8 @@ struct ubi_vid_io_buf { * @u.list: link in the protection queue * @u.list: link in the protection queue * @ec: erase counter * @ec: erase counter * @pnum: physical eraseblock number * @pnum: physical eraseblock number * @tagged_scrub_all: if the entry is tagged for scrub all * @sqnum: The sequence number of the vol header. * * * This data structure is used in the WL sub-system. Each physical eraseblock * This data structure is used in the WL sub-system. Each physical eraseblock * has a corresponding &struct wl_entry object which may be kept in different * has a corresponding &struct wl_entry object which may be kept in different Loading @@ -182,6 +184,8 @@ struct ubi_wl_entry { } u; } u; int ec; int ec; int pnum; int pnum; unsigned int tagged_scrub_all:1; unsigned long long sqnum; }; }; /** /** Loading Loading @@ -625,6 +629,9 @@ struct ubi_device { struct task_struct *bgt_thread; struct task_struct *bgt_thread; int thread_enabled; int thread_enabled; char bgt_name[sizeof(UBI_BGT_NAME_PATTERN)+2]; char bgt_name[sizeof(UBI_BGT_NAME_PATTERN)+2]; bool scrub_in_progress; atomic_t scrub_work_count; int wl_is_inited; /* I/O sub-system's stuff */ /* I/O sub-system's stuff */ long long flash_size; long long flash_size; Loading Loading @@ -919,7 +926,12 @@ int ubi_is_erase_work(struct ubi_work *wrk); void ubi_refill_pools(struct ubi_device *ubi); void ubi_refill_pools(struct ubi_device *ubi); int ubi_ensure_anchor_pebs(struct ubi_device *ubi); int ubi_ensure_anchor_pebs(struct ubi_device *ubi); int ubi_bitflip_check(struct ubi_device *ubi, int pnum, int force_scrub); int ubi_bitflip_check(struct ubi_device *ubi, int pnum, int force_scrub); ssize_t ubi_wl_scrub_all(struct ubi_device *ubi, unsigned long long scrub_sqnum); void ubi_wl_update_peb_sqnum(struct ubi_device *ubi, int pnum, struct ubi_vid_hdr *vid_hdr); unsigned long long ubi_wl_scrub_get_min_sqnum(struct ubi_device *ubi); int ubi_wl_re_erase_peb(struct ubi_device *ubi, int pnum); /* io.c */ /* io.c */ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset, int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset, int len); int len); Loading