diff options
| author | Mark Brown <broonie@kernel.org> | 2026-08-21 13:56:44 +0100 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2026-08-21 13:56:44 +0100 |
| commit | ac8420416e13c022d9495dfe9aa8388fb1c3ca39 (patch) | |
| tree | f2bda564c7b2e8402667d050edfe9fba550e7167 /drivers | |
| parent | 5a91bf467b12a0973d8a6634e8c9b7a4918828c5 (diff) | |
| parent | f3d3bb6e63ceddb85bf640fab8c2fa621b706ab1 (diff) | |
| download | linux-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.c | 22 | ||||
| -rw-r--r-- | drivers/mtd/ubi/attach.c | 4 | ||||
| -rw-r--r-- | drivers/mtd/ubi/build.c | 48 | ||||
| -rw-r--r-- | drivers/mtd/ubi/cdev.c | 2 | ||||
| -rw-r--r-- | drivers/mtd/ubi/fastmap-wl.c | 8 | ||||
| -rw-r--r-- | drivers/mtd/ubi/fastmap.c | 6 | ||||
| -rw-r--r-- | drivers/mtd/ubi/io.c | 11 | ||||
| -rw-r--r-- | drivers/mtd/ubi/ubi.h | 25 | ||||
| -rw-r--r-- | drivers/mtd/ubi/wl.c | 54 |
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); |
