summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2026-08-21 13:56:44 +0100
committerMark Brown <broonie@kernel.org>2026-08-21 13:56:44 +0100
commitac8420416e13c022d9495dfe9aa8388fb1c3ca39 (patch)
treef2bda564c7b2e8402667d050edfe9fba550e7167 /drivers
parent5a91bf467b12a0973d8a6634e8c9b7a4918828c5 (diff)
parentf3d3bb6e63ceddb85bf640fab8c2fa621b706ab1 (diff)
downloadlinux-next-ac8420416e13c022d9495dfe9aa8388fb1c3ca39.tar.gz
linux-next-ac8420416e13c022d9495dfe9aa8388fb1c3ca39.zip
Merge branch 'fs-next' of linux-next
Diffstat (limited to 'drivers')
-rw-r--r--drivers/block/ublk_drv.c22
-rw-r--r--drivers/mtd/ubi/attach.c4
-rw-r--r--drivers/mtd/ubi/build.c48
-rw-r--r--drivers/mtd/ubi/cdev.c2
-rw-r--r--drivers/mtd/ubi/fastmap-wl.c8
-rw-r--r--drivers/mtd/ubi/fastmap.c6
-rw-r--r--drivers/mtd/ubi/io.c11
-rw-r--r--drivers/mtd/ubi/ubi.h25
-rw-r--r--drivers/mtd/ubi/wl.c54
9 files changed, 108 insertions, 72 deletions
diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
index 4d17ed264da1..6c5bec7da97c 100644
--- a/drivers/block/ublk_drv.c
+++ b/drivers/block/ublk_drv.c
@@ -1699,8 +1699,8 @@ ublk_auto_buf_register(const struct ublk_queue *ubq, struct request *req,
{
int ret;
- ret = io_buffer_register_bvec(cmd, req, ublk_io_release,
- io->buf.auto_reg.index, issue_flags);
+ ret = io_buffer_register_request(cmd, req, ublk_io_release,
+ io->buf.auto_reg.index, issue_flags);
if (ret) {
if (io->buf.auto_reg.flags & UBLK_AUTO_BUF_REG_FALLBACK) {
ublk_auto_buf_reg_fallback(ubq, req->tag);
@@ -1909,7 +1909,7 @@ static noinline void ublk_batch_dispatch_fail(struct ublk_queue *ubq,
ublk_io_unlock(io);
if (index != -1)
- io_buffer_unregister_bvec(data->cmd, index,
+ io_buffer_unregister(data->cmd, index,
data->issue_flags);
}
@@ -3192,8 +3192,8 @@ static int ublk_register_io_buf(struct io_uring_cmd *cmd,
if (!req)
return -EINVAL;
- ret = io_buffer_register_bvec(cmd, req, ublk_io_release, index,
- issue_flags);
+ ret = io_buffer_register_request(cmd, req, ublk_io_release, index,
+ issue_flags);
if (ret) {
ublk_put_req_ref(io, req);
return ret;
@@ -3224,8 +3224,8 @@ ublk_daemon_register_io_buf(struct io_uring_cmd *cmd,
if (!ublk_dev_support_zero_copy(ub) || !blk_rq_has_data(req))
return -EINVAL;
- ret = io_buffer_register_bvec(cmd, req, ublk_io_release, index,
- issue_flags);
+ ret = io_buffer_register_request(cmd, req, ublk_io_release, index,
+ issue_flags);
if (ret)
return ret;
@@ -3240,7 +3240,7 @@ static int ublk_unregister_io_buf(struct io_uring_cmd *cmd,
if (!(ub->dev_info.flags & UBLK_F_SUPPORT_ZERO_COPY))
return -EINVAL;
- return io_buffer_unregister_bvec(cmd, index, issue_flags);
+ return io_buffer_unregister(cmd, index, issue_flags);
}
static int ublk_check_fetch_buf(const struct ublk_device *ub, __u64 buf_addr)
@@ -3384,7 +3384,7 @@ static int ublk_ch_uring_cmd_local(struct io_uring_cmd *cmd,
goto out;
/*
- * io_buffer_unregister_bvec() doesn't access the ubq or io,
+ * io_buffer_unregister() doesn't access the ubq or io,
* so no need to validate the q_id, tag, or task
*/
if (_IOC_NR(cmd_op) == UBLK_IO_UNREGISTER_IO_BUF)
@@ -3456,7 +3456,7 @@ static int ublk_ch_uring_cmd_local(struct io_uring_cmd *cmd,
req = ublk_fill_io_cmd(io, cmd);
ublk_apply_io_buf(ub, io, cmd, addr, &auto_buf, &buf_idx);
if (buf_idx != UBLK_INVALID_BUF_IDX)
- io_buffer_unregister_bvec(cmd, buf_idx, issue_flags);
+ io_buffer_unregister(cmd, buf_idx, issue_flags);
compl = ublk_need_complete_req(ub, io);
if (req_op(req) == REQ_OP_ZONE_APPEND)
@@ -3801,7 +3801,7 @@ static int ublk_batch_commit_io(struct ublk_queue *ubq,
}
if (buf_idx != UBLK_INVALID_BUF_IDX)
- io_buffer_unregister_bvec(data->cmd, buf_idx, data->issue_flags);
+ io_buffer_unregister(data->cmd, buf_idx, data->issue_flags);
if (req_op(req) == REQ_OP_ZONE_APPEND)
req->__sector = ublk_batch_zone_lba(uc, elem);
if (compl)
diff --git a/drivers/mtd/ubi/attach.c b/drivers/mtd/ubi/attach.c
index 0fa115cbf3ad..0ce7ff7400d3 100644
--- a/drivers/mtd/ubi/attach.c
+++ b/drivers/mtd/ubi/attach.c
@@ -771,7 +771,7 @@ void ubi_remove_av(struct ubi_attach_info *ai, struct ubi_ainf_volume *av)
static int early_erase_peb(struct ubi_device *ubi,
const struct ubi_attach_info *ai, int pnum, int ec)
{
- int err;
+ int err, torture = 0;
struct ubi_ec_hdr *ec_hdr;
if ((long long)ec >= UBI_MAX_ERASECOUNTER) {
@@ -790,7 +790,7 @@ static int early_erase_peb(struct ubi_device *ubi,
ec_hdr->ec = cpu_to_be64(ec);
- err = ubi_io_sync_erase(ubi, pnum, 0);
+ err = ubi_io_sync_erase(ubi, pnum, &torture);
if (err < 0)
goto out_free;
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 674ad87809df..910e6b0ff5e7 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -36,7 +36,7 @@
#define MTD_PARAM_LEN_MAX 64
/* Maximum number of comma-separated items in the 'mtd=' parameter */
-#define MTD_PARAM_MAX_COUNT 6
+#define MTD_PARAM_MAX_COUNT 7
/* Maximum value for the number of bad PEBs per 1024 PEBs */
#define MAX_MTD_UBI_BEB_LIMIT 768
@@ -56,6 +56,7 @@
* @max_beb_per1024: maximum expected number of bad PEBs per 1024 PEBs
* @enable_fm: enable fastmap when value is non-zero
* @need_resv_pool: reserve pool->max_size pebs when value is none-zero
+ * @wl_threshold: wear-leveling threshold, 0 means use CONFIG_MTD_UBI_WL_THRESHOLD
*/
struct mtd_dev_param {
char name[MTD_PARAM_LEN_MAX];
@@ -64,6 +65,7 @@ struct mtd_dev_param {
int max_beb_per1024;
int enable_fm;
int need_resv_pool;
+ int wl_threshold;
};
/* Numbers of elements set in the @mtd_dev_param array */
@@ -832,6 +834,8 @@ static int autoresize(struct ubi_device *ubi, int vol_id)
* @max_beb_per1024: maximum expected number of bad PEB per 1024 PEBs
* @disable_fm: whether disable fastmap
* @need_resv_pool: whether reserve pebs to fill fm_pool
+ * @wl_threshold: wear-leveling threshold for this UBI device; 0 means use
+ * %CONFIG_MTD_UBI_WL_THRESHOLD; accepted range is 2-65536
*
* This function attaches MTD device @mtd_dev to UBI and assign @ubi_num number
* to the newly created UBI device, unless @ubi_num is %UBI_DEV_NUM_AUTO, in
@@ -848,7 +852,7 @@ static int autoresize(struct ubi_device *ubi, int vol_id)
*/
int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
int vid_hdr_offset, int max_beb_per1024, bool disable_fm,
- bool need_resv_pool)
+ bool need_resv_pool, int wl_threshold)
{
struct ubi_device *ubi;
int i, err;
@@ -859,6 +863,15 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
if (!max_beb_per1024)
max_beb_per1024 = CONFIG_MTD_UBI_BEB_LIMIT;
+ if (!wl_threshold)
+ wl_threshold = CONFIG_MTD_UBI_WL_THRESHOLD;
+
+ if (wl_threshold < 2 || wl_threshold > 65536) {
+ pr_err("ubi: bad wear-leveling threshold %d\n",
+ wl_threshold);
+ return -EINVAL;
+ }
+
/*
* Check if we already have the same MTD device attached.
*
@@ -944,6 +957,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
ubi->ubi_num = ubi_num;
ubi->vid_hdr_offset = vid_hdr_offset;
ubi->autoresize_vol_id = -1;
+ ubi->wl_threshold = wl_threshold;
+ ubi->wl_free_max_diff = wl_threshold * 2;
#ifdef CONFIG_MTD_UBI_FASTMAP
ubi->fm_pool.used = ubi->fm_pool.size = 0;
@@ -1044,7 +1059,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
ubi->vol_count - UBI_INT_VOL_COUNT, UBI_INT_VOL_COUNT,
ubi->vtbl_slots);
ubi_msg(ubi, "max/mean erase counter: %d/%d, WL threshold: %d, image sequence number: %u",
- ubi->max_ec, ubi->mean_ec, CONFIG_MTD_UBI_WL_THRESHOLD,
+ ubi->max_ec, ubi->mean_ec, ubi->wl_threshold,
ubi->image_seq);
ubi_msg(ubi, "available PEBs: %d, total reserved PEBs: %d, PEBs reserved for bad PEB handling: %d",
ubi->avail_pebs, ubi->rsvd_pebs, ubi->beb_rsvd_pebs);
@@ -1105,6 +1120,7 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
ubi->ref_count -= 1;
if (ubi->ref_count) {
if (!anyway) {
+ put_device(&ubi->dev);
spin_unlock(&ubi_devices_lock);
return -EBUSY;
}
@@ -1247,7 +1263,7 @@ static void ubi_notify_add(struct mtd_info *mtd)
/* called while holding mtd_table_mutex */
mutex_lock_nested(&ubi_devices_mutex, SINGLE_DEPTH_NESTING);
- err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, 0, 0, false, false);
+ err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, 0, 0, false, false, 0);
mutex_unlock(&ubi_devices_mutex);
if (err < 0)
__put_mtd_device(mtd);
@@ -1289,7 +1305,8 @@ static int __init ubi_init_attach(void)
err = ubi_attach_mtd_dev(mtd, p->ubi_num,
p->vid_hdr_offs, p->max_beb_per1024,
p->enable_fm == 0,
- p->need_resv_pool != 0);
+ p->need_resv_pool != 0,
+ p->wl_threshold);
mutex_unlock(&ubi_devices_mutex);
if (err < 0) {
pr_err("UBI error: cannot attach mtd%d\n",
@@ -1317,10 +1334,10 @@ static int __init ubi_init_attach(void)
return 0;
out_detach:
- for (k = 0; k < i; k++)
+ for (k = 0; k < UBI_MAX_DEVICES; k++)
if (ubi_devices[k]) {
mutex_lock(&ubi_devices_mutex);
- ubi_detach_mtd_dev(ubi_devices[k]->ubi_num, 1);
+ ubi_detach_mtd_dev(k, 1);
mutex_unlock(&ubi_devices_mutex);
}
return err;
@@ -1569,12 +1586,24 @@ static int ubi_mtd_param_parse(const char *val, const struct kernel_param *kp)
} else
p->need_resv_pool = 0;
+ token = tokens[6];
+ if (token) {
+ int err = kstrtoint(token, 10, &p->wl_threshold);
+
+ if (err) {
+ pr_err("UBI error: bad value for wl_threshold parameter: %s\n",
+ token);
+ return -EINVAL;
+ }
+ } else
+ p->wl_threshold = 0;
+
mtd_devs += 1;
return 0;
}
module_param_call(mtd, ubi_mtd_param_parse, NULL, NULL, 0400);
-MODULE_PARM_DESC(mtd, "MTD devices to attach. Parameter format: mtd=<name|num|path>[,<vid_hdr_offs>[,max_beb_per1024[,ubi_num]]].\n"
+MODULE_PARM_DESC(mtd, "MTD devices to attach. Parameter format: mtd=<name|num|path>[,<vid_hdr_offs>[,max_beb_per1024[,ubi_num[,enable_fm[,need_resv_pool[,wl_threshold]]]]]].\n"
"Multiple \"mtd\" parameters may be specified.\n"
"MTD devices may be specified by their number, name, or path to the MTD character device node.\n"
"Optional \"vid_hdr_offs\" parameter specifies UBI VID header position to be used by UBI. (default value if 0)\n"
@@ -1587,9 +1616,10 @@ MODULE_PARM_DESC(mtd, "MTD devices to attach. Parameter format: mtd=<name|num|pa
"Example 1: mtd=/dev/mtd0 - attach MTD device /dev/mtd0.\n"
"Example 2: mtd=content,1984 mtd=4 - attach MTD device with name \"content\" using VID header offset 1984, and MTD device number 4 with default VID header offset.\n"
"Example 3: mtd=/dev/mtd1,0,25 - attach MTD device /dev/mtd1 using default VID header offset and reserve 25*nand_size_in_blocks/1024 erase blocks for bad block handling.\n"
+ "\t(e.g. if the NAND *chipset* has 4096 PEB, 100 will be reserved for this UBI device).\n"
"Example 4: mtd=/dev/mtd1,0,0,5 - attach MTD device /dev/mtd1 to UBI 5 and using default values for the other fields.\n"
"example 5: mtd=1,0,0,5 mtd=2,0,0,6,1 - attach MTD device /dev/mtd1 to UBI 5 and disable fastmap; attach MTD device /dev/mtd2 to UBI 6 and enable fastmap.(only works when fastmap is enabled and fm_autoconvert=Y).\n"
- "\t(e.g. if the NAND *chipset* has 4096 PEB, 100 will be reserved for this UBI device).");
+ "Example 6: mtd=/dev/mtd0,0,0,0,0,0,256 mtd=/dev/mtd1,0,0,0,0,0,4096 - attach MTD device /dev/mtd0 with wear-leveling threshold 256, and MTD device /dev/mtd1 with threshold 4096.\n");
#ifdef CONFIG_MTD_UBI_FASTMAP
module_param(fm_autoconvert, bool, 0644);
MODULE_PARM_DESC(fm_autoconvert, "Set this parameter to enable fastmap automatically on images without a fastmap.");
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index fd39030dbf89..54acd8394d67 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -1112,7 +1112,7 @@ static long ctrl_cdev_ioctl(struct file *file, unsigned int cmd,
mutex_lock(&ubi_devices_mutex);
err = ubi_attach_mtd_dev(mtd, req.ubi_num, req.vid_hdr_offset,
req.max_beb_per1024, !!req.disable_fm,
- !!req.need_resv_pool);
+ !!req.need_resv_pool, req.wl_threshold);
mutex_unlock(&ubi_devices_mutex);
if (err < 0)
put_mtd_device(mtd);
diff --git a/drivers/mtd/ubi/fastmap-wl.c b/drivers/mtd/ubi/fastmap-wl.c
index a0f750411f9d..e24bb6b18e90 100644
--- a/drivers/mtd/ubi/fastmap-wl.c
+++ b/drivers/mtd/ubi/fastmap-wl.c
@@ -238,7 +238,7 @@ void ubi_refill_pools_and_lock(struct ubi_device *ubi)
if (left_free <= 0)
break;
- e = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF,
+ e = find_wl_entry(ubi, &ubi->free, ubi->wl_free_max_diff,
!can_fill_pools(ubi, left_free));
self_check_in_wl_tree(ubi, e, &ubi->free);
rb_erase(&e->u.rb, &ubi->free);
@@ -392,18 +392,18 @@ static bool need_wear_leveling(struct ubi_device *ubi)
if (!e) {
if (!ubi->free.rb_node)
return false;
- e = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF, 0);
+ e = find_wl_entry(ubi, &ubi->free, ubi->wl_free_max_diff, 0);
ec = e->ec;
} else {
ec = e->ec;
if (ubi->free.rb_node) {
- e = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF, 0);
+ e = find_wl_entry(ubi, &ubi->free, ubi->wl_free_max_diff, 0);
ec = max(ec, e->ec);
}
}
e = rb_entry(rb_first(&ubi->used), struct ubi_wl_entry, u.rb);
- return ec - e->ec >= UBI_WL_THRESHOLD;
+ return ec - e->ec >= ubi->wl_threshold;
}
/* get_peb_for_wl - returns a PEB to be used internally by the WL sub-system.
diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c
index 3bce1b4d8464..3f9fb7c181ff 100644
--- a/drivers/mtd/ubi/fastmap.c
+++ b/drivers/mtd/ubi/fastmap.c
@@ -1526,7 +1526,8 @@ int ubi_update_fastmap(struct ubi_device *ubi)
if (!tmp_e) {
if (old_fm && old_fm->e[i]) {
- ret = ubi_sync_erase(ubi, old_fm->e[i], 0);
+ ret = ubi_sync_erase(ubi, old_fm->e[i],
+ &old_fm->to_be_tortured[i]);
if (ret < 0) {
ubi_err(ubi, "could not erase old fastmap PEB");
@@ -1578,7 +1579,8 @@ int ubi_update_fastmap(struct ubi_device *ubi)
if (old_fm) {
/* no fresh anchor PEB was found, reuse the old one */
if (!tmp_e) {
- ret = ubi_sync_erase(ubi, old_fm->e[0], 0);
+ ret = ubi_sync_erase(ubi, old_fm->e[0],
+ &old_fm->to_be_tortured[0]);
if (ret < 0) {
ubi_err(ubi, "could not erase old anchor PEB");
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index 915eb64cb001..d70d1313ad4e 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -519,8 +519,10 @@ error:
/**
* ubi_io_sync_erase - synchronously erase a physical eraseblock.
* @ubi: UBI device description object
- * @pnum: physical eraseblock number to erase
- * @torture: if this physical eraseblock has to be tortured
+ * @pnum: the physical eraseblock number to erase
+ * @torture: if this physical eraseblock has to be tortured; cleared to zero
+ * once the torture test has completed successfully so that a retry
+ * of the erase does not torture the physical eraseblock again
*
* This function synchronously erases physical eraseblock @pnum. If @torture
* flag is not zero, the physical eraseblock is checked by means of writing
@@ -532,7 +534,7 @@ error:
* codes in case of other errors. Note, %-EIO means that the physical
* eraseblock is bad.
*/
-int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture)
+int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int *torture)
{
int err, ret = 0;
@@ -560,10 +562,11 @@ int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture)
return err;
}
- if (torture) {
+ if (*torture) {
ret = torture_peb(ubi, pnum);
if (ret < 0)
return ret;
+ *torture = 0;
}
err = do_sync_erase(ubi, pnum);
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index af466cd83ae0..8a9ac60ff2f4 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -516,6 +516,22 @@ struct ubi_debug_info {
* @bgt_thread: background thread description object
* @thread_enabled: if the background thread is enabled
* @bgt_name: background thread name
+ * @wl_threshold: Maximum difference between two erase counters. If this
+ * threshold is exceeded, the WL sub-system starts moving
+ * data from used physical eraseblocks with low erase
+ * counter to free physical eraseblocks with high erase counter.
+ * @wl_free_max_diff: When a physical eraseblock is moved, the WL sub-system
+ * has to pick the target physical eraseblock to move to.
+ * The simplest way would be just to pick the one with the
+ * highest erase counter. But in certain workloads this
+ * could lead to an unlimited wear of one or few physical
+ * eraseblock. Indeed, imagine a situation when the picked
+ * physical eraseblock is constantly erased after the
+ * data is written to it. So, we have a constant which
+ * limits the highest erase counter of the free physical
+ * eraseblock to pick. Namely, the WL sub-system does not
+ * pick eraseblocks with erase counter greater than the
+ * lowest erase counter plus @wl_free_max_diff.
*
* @flash_size: underlying MTD device size (in bytes)
* @peb_count: count of physical eraseblocks on the MTD device
@@ -623,6 +639,8 @@ struct ubi_device {
struct task_struct *bgt_thread;
int thread_enabled;
char bgt_name[sizeof(UBI_BGT_NAME_PATTERN)+2];
+ int wl_threshold;
+ int wl_free_max_diff;
/* I/O sub-system's stuff */
long long flash_size;
@@ -901,7 +919,7 @@ int self_check_eba(struct ubi_device *ubi, struct ubi_attach_info *ai_fastmap,
struct ubi_attach_info *ai_scan);
/* wl.c */
-int ubi_sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, int torture);
+int ubi_sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, int *torture);
int ubi_wl_get_peb(struct ubi_device *ubi);
int ubi_wl_put_peb(struct ubi_device *ubi, int vol_id, int lnum,
int pnum, int torture);
@@ -923,7 +941,7 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
int len);
int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
int len);
-int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture);
+int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int *torture);
int ubi_io_is_bad(const struct ubi_device *ubi, int pnum);
int ubi_io_mark_bad(const struct ubi_device *ubi, int pnum);
int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
@@ -938,7 +956,8 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
/* build.c */
int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
int vid_hdr_offset, int max_beb_per1024,
- bool disable_fm, bool need_resv_pool);
+ bool disable_fm, bool need_resv_pool,
+ int wl_threshold);
int ubi_detach_mtd_dev(int ubi_num, int anyway);
struct ubi_device *ubi_get_device(int ubi_num);
void ubi_put_device(struct ubi_device *ubi);
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index e3705db8e570..5a0db928a90e 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -96,27 +96,6 @@
#define WL_RESERVED_PEBS 1
/*
- * Maximum difference between two erase counters. If this threshold is
- * exceeded, the WL sub-system starts moving data from used physical
- * eraseblocks with low erase counter to free physical eraseblocks with high
- * erase counter.
- */
-#define UBI_WL_THRESHOLD CONFIG_MTD_UBI_WL_THRESHOLD
-
-/*
- * When a physical eraseblock is moved, the WL sub-system has to pick the target
- * physical eraseblock to move to. The simplest way would be just to pick the
- * one with the highest erase counter. But in certain workloads this could lead
- * to an unlimited wear of one or few physical eraseblock. Indeed, imagine a
- * situation when the picked physical eraseblock is constantly erased after the
- * data is written to it. So, we have a constant which limits the highest erase
- * counter of the free physical eraseblock to pick. Namely, the WL sub-system
- * does not pick eraseblocks with erase counter greater than the lowest erase
- * counter plus %WL_FREE_MAX_DIFF.
- */
-#define WL_FREE_MAX_DIFF (2*UBI_WL_THRESHOLD)
-
-/*
* Maximum number of consecutive background thread failures which is enough to
* switch to read-only mode.
*/
@@ -358,7 +337,7 @@ static struct ubi_wl_entry *find_wl_entry(struct ubi_device *ubi,
*
* This function looks for a wear leveling entry with medium erase counter,
* but not greater or equivalent than the lowest erase counter plus
- * %WL_FREE_MAX_DIFF/2.
+ * @ubi->wl_free_max_diff/2.
*/
static struct ubi_wl_entry *find_mean_wl_entry(struct ubi_device *ubi,
struct rb_root *root)
@@ -368,7 +347,7 @@ static struct ubi_wl_entry *find_mean_wl_entry(struct ubi_device *ubi,
first = rb_entry(rb_first(root), struct ubi_wl_entry, u.rb);
last = rb_entry(rb_last(root), struct ubi_wl_entry, u.rb);
- if (last->ec - first->ec < WL_FREE_MAX_DIFF) {
+ if (last->ec - first->ec < ubi->wl_free_max_diff) {
e = rb_entry(root->rb_node, struct ubi_wl_entry, u.rb);
/*
@@ -379,7 +358,7 @@ static struct ubi_wl_entry *find_mean_wl_entry(struct ubi_device *ubi,
*/
e = may_reserve_for_fm(ubi, e, root);
} else
- e = find_wl_entry(ubi, root, WL_FREE_MAX_DIFF/2, 0);
+ e = find_wl_entry(ubi, root, ubi->wl_free_max_diff/2, 0);
return e;
}
@@ -443,12 +422,14 @@ static int prot_queue_del(struct ubi_device *ubi, int pnum)
* ubi_sync_erase - synchronously erase a physical eraseblock.
* @ubi: UBI device description object
* @e: the physical eraseblock to erase
- * @torture: if the physical eraseblock has to be tortured
+ * @torture: if the physical eraseblock has to be tortured; cleared to zero
+ * once the torture test has completed successfully so that a retry
+ * of the erase does not torture the physical eraseblock again
*
* This function returns zero in case of success and a negative error code in
* case of failure.
*/
-int ubi_sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, int torture)
+int ubi_sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, int *torture)
{
int err;
struct ubi_ec_hdr *ec_hdr;
@@ -706,7 +687,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
#ifdef CONFIG_MTD_UBI_FASTMAP
e1 = find_anchor_wl_entry(&ubi->used);
if (e1 && ubi->fm_anchor &&
- (ubi->fm_anchor->ec - e1->ec >= UBI_WL_THRESHOLD)) {
+ (ubi->fm_anchor->ec - e1->ec >= ubi->wl_threshold)) {
ubi->fm_do_produce_anchor = 1;
/*
* fm_anchor is no longer considered a good anchor.
@@ -743,7 +724,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
if (!e2)
goto out_cancel;
- if (!(e2->ec - e1->ec >= UBI_WL_THRESHOLD)) {
+ if (!(e2->ec - e1->ec >= ubi->wl_threshold)) {
dbg_wl("no WL needed: min used EC %d, max free EC %d",
e1->ec, e2->ec);
@@ -1056,12 +1037,12 @@ static int ensure_wear_leveling(struct ubi_device *ubi, int nested)
* We schedule wear-leveling only if the difference between the
* lowest erase counter of used physical eraseblocks and a high
* erase counter of free physical eraseblocks is greater than
- * %UBI_WL_THRESHOLD.
+ * @ubi->wl_threshold.
*/
e1 = rb_entry(rb_first(&ubi->used), struct ubi_wl_entry, u.rb);
- e2 = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF, 0);
+ e2 = find_wl_entry(ubi, &ubi->free, ubi->wl_free_max_diff, 0);
- if (!(e2->ec - e1->ec >= UBI_WL_THRESHOLD))
+ if (!(e2->ec - e1->ec >= ubi->wl_threshold))
goto out_unlock;
#endif
dbg_wl("schedule wear-leveling");
@@ -1113,7 +1094,7 @@ static int __erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk)
dbg_wl("erase PEB %d EC %d LEB %d:%d",
pnum, e->ec, wl_wrk->vol_id, wl_wrk->lnum);
- err = ubi_sync_erase(ubi, e, wl_wrk->torture);
+ err = ubi_sync_erase(ubi, e, &wl_wrk->torture);
if (!err) {
spin_lock(&ubi->wl_lock);
@@ -1150,7 +1131,8 @@ static int __erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk)
int err1;
/* Re-schedule the LEB for erasure */
- err1 = schedule_erase(ubi, e, vol_id, lnum, 0, true);
+ err1 = schedule_erase(ubi, e, vol_id, lnum, wl_wrk->torture,
+ true);
if (err1) {
spin_lock(&ubi->wl_lock);
wl_entry_destroy(ubi, e);
@@ -1757,7 +1739,7 @@ static void shutdown_work(struct ubi_device *ubi)
static int erase_aeb(struct ubi_device *ubi, struct ubi_ainf_peb *aeb, bool sync)
{
struct ubi_wl_entry *e;
- int err;
+ int err, torture = 0;
e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
if (!e)
@@ -1768,7 +1750,7 @@ static int erase_aeb(struct ubi_device *ubi, struct ubi_ainf_peb *aeb, bool sync
ubi->lookuptbl[e->pnum] = e;
if (sync) {
- err = ubi_sync_erase(ubi, e, false);
+ err = ubi_sync_erase(ubi, e, &torture);
if (err)
goto out_free;
@@ -2090,7 +2072,7 @@ static struct ubi_wl_entry *get_peb_for_wl(struct ubi_device *ubi)
{
struct ubi_wl_entry *e;
- e = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF, 0);
+ e = find_wl_entry(ubi, &ubi->free, ubi->wl_free_max_diff, 0);
self_check_in_wl_tree(ubi, e, &ubi->free);
ubi->free_count--;
ubi_assert(ubi->free_count >= 0);