Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d70a1a19 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "ubi: Add scrub_all support to UBI"

parents ab396044 ec242d21
Loading
Loading
Loading
Loading
+15 −2
Original line number Original line Diff line number Diff line
@@ -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;
	}
	}
+5 −4
Original line number Original line Diff line number Diff line
@@ -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')
@@ -141,12 +141,12 @@ static int __init ubiblock_set_param(const char *val,
		ret = kstrtoint(tokens[1], 10, &param->vol_id);
		ret = kstrtoint(tokens[1], 10, &param->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;
	}
	}
@@ -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;


+95 −16
Original line number Original line Diff line number Diff line
@@ -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);


@@ -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 =
@@ -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.
@@ -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)
@@ -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;


@@ -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);
@@ -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
@@ -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')
@@ -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) {
+11 −0
Original line number Original line Diff line number Diff line
@@ -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;
@@ -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;
}
}


+13 −1
Original line number Original line Diff line number Diff line
@@ -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
@@ -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;
};
};


/**
/**
@@ -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;
@@ -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