This pull request contains updates for UBI and UBIFS:

UBI:
 - New interface to dump detailed erase counters
 - Fixes around wear-leveling
 
 UBIFS:
 - Minor cleanups
 - Fix for TNC dumping code
 -----BEGIN PGP SIGNATURE-----
 
 iQJKBAABCAA0FiEEdgfidid8lnn52cLTZvlZhesYu8EFAmeb8cgWHHJpY2hhcmRA
 c2lnbWEtc3Rhci5hdAAKCRBm+VmF6xi7wRUPEADos2ZdLleilKSAuPV6osItbNjo
 UAkwFAu4suQMzChZv4V/b7uisu1vBQiOMGiqCZQdU6aIzSUsUlqNQSn8L3f6cPD1
 P9Kae1SNCFdlmrfiaduWyxHsl1pxBDfXQ8qt3hcVpNf3LEuYJfu25Fefqavg9IvI
 Egp0Akk89C4AzNoHUDhzCp8oHAV0nwX5kBN8SVc28G6sb/SQG6+1kU9Op+d6qjoX
 8UTfeyETkDIzpx+wjl4bn5o4lagtaJqS/TI6UfhE736KjPUnGK0oEWoHA6AGCqu4
 E158pqYh69LHTQ7Wxo7wQ+9Pc9xoE2qTrKUF5b/u9GzsbHMtd4q/pg9Aa8OOcZur
 ir7pjrRqGkybYGfnhs/b/9Jq7rr7nQNl0j413nmNHb3Wf9+qjwmxYvPQusd6/bLr
 nHfRymIGCXhuOqgB37t+F+iuQkwfnatVJHJ+Q0r8pJ35LgXj/+PTKZycYF5Jg72q
 tcth9CXoVCF78e6AJX6GioSOfBUMA5EXK8bqWKr20ZHPbVP8W7gOg7G8PFoNOnj+
 KiRMvOqXavPUCcrRxDbp1T50NC+dQYX0FuyCtjuX5vH+0YpgdgvA0trkGPOgMeqw
 x6py7J+u7jhCWoVecw2DL4ZwEdr4QcvEiTra8i+v4PyRkdrUZenuty+pbeSnUsNk
 rHKJZkie9Z2xycLJAA==
 =bgVN
 -----END PGP SIGNATURE-----

Merge tag 'ubifs-for-linus-6.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs

Pull UBI and UBIFS updates from Richard Weinberger:
 "UBI:
   - New interface to dump detailed erase counters
   - Fixes around wear-leveling

  UBIFS:
   - Minor cleanups
   - Fix for TNC dumping code"

* tag 'ubifs-for-linus-6.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs:
  ubi: ubi_get_ec_info: Fix compiling error 'cast specifies array type'
  ubi: Implement ioctl for detailed erase counters
  ubi: Expose interface for detailed erase counters
  ubifs: skip dumping tnc tree when zroot is null
  ubi: Revert "ubi: wl: Close down wear-leveling before nand is suspended"
  ubifs: ubifs_dump_leb: remove return from end of void function
  ubifs: dump_lpt_leb: remove return at end of void function
  ubi: Add a check for ubi_num
This commit is contained in:
Linus Torvalds 2025-01-30 18:27:02 -08:00
commit 350130afc2
7 changed files with 117 additions and 35 deletions

View File

@ -1537,7 +1537,7 @@ static int ubi_mtd_param_parse(const char *val, const struct kernel_param *kp)
if (token) {
int err = kstrtoint(token, 10, &p->ubi_num);
if (err) {
if (err || p->ubi_num < UBI_DEV_NUM_AUTO) {
pr_err("UBI error: bad value for ubi_num parameter: %s\n",
token);
return -EINVAL;

View File

@ -828,6 +828,70 @@ out_free:
return err;
}
static int ubi_get_ec_info(struct ubi_device *ubi, struct ubi_ecinfo_req __user *ureq)
{
struct ubi_ecinfo_req req;
struct ubi_wl_entry *wl;
int read_cnt;
int peb;
int end_peb;
/* Copy the input arguments */
if (copy_from_user(&req, ureq, sizeof(struct ubi_ecinfo_req)))
return -EFAULT;
/* Check input arguments */
if (req.length <= 0 || req.start < 0 || req.start >= ubi->peb_count)
return -EINVAL;
if (check_add_overflow(req.start, req.length, &end_peb))
return -EINVAL;
if (end_peb > ubi->peb_count)
end_peb = ubi->peb_count;
/* Check access rights before filling erase_counters array */
if (!access_ok((void __user *)ureq->erase_counters,
(end_peb-req.start) * sizeof(int32_t)))
return -EFAULT;
/* Fill erase counter array */
read_cnt = 0;
for (peb = req.start; peb < end_peb; read_cnt++, peb++) {
int ec;
if (ubi_io_is_bad(ubi, peb)) {
if (__put_user(UBI_UNKNOWN, ureq->erase_counters+read_cnt))
return -EFAULT;
continue;
}
spin_lock(&ubi->wl_lock);
wl = ubi->lookuptbl[peb];
if (wl)
ec = wl->ec;
else
ec = UBI_UNKNOWN;
spin_unlock(&ubi->wl_lock);
if (__put_user(ec, ureq->erase_counters+read_cnt))
return -EFAULT;
}
/* Return actual read length */
req.read_length = read_cnt;
/* Copy everything except erase counter array */
if (copy_to_user(ureq, &req, sizeof(struct ubi_ecinfo_req)))
return -EFAULT;
return 0;
}
static long ubi_cdev_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
@ -991,6 +1055,12 @@ static long ubi_cdev_ioctl(struct file *file, unsigned int cmd,
break;
}
case UBI_IOCECNFO:
{
err = ubi_get_ec_info(ubi, argp);
break;
}
default:
err = -ENOTTY;
break;

View File

@ -549,7 +549,6 @@ struct ubi_debug_info {
* @peb_buf: a buffer of PEB size used for different purposes
* @buf_mutex: protects @peb_buf
* @ckvol_mutex: serializes static volume checking when opening
* @wl_reboot_notifier: close all wear-leveling work before reboot
*
* @dbg: debugging information for this UBI device
*/
@ -652,7 +651,6 @@ struct ubi_device {
void *peb_buf;
struct mutex buf_mutex;
struct mutex ckvol_mutex;
struct notifier_block wl_reboot_notifier;
struct ubi_debug_info dbg;
};

View File

@ -89,7 +89,6 @@
#include <linux/crc32.h>
#include <linux/freezer.h>
#include <linux/kthread.h>
#include <linux/reboot.h>
#include "ubi.h"
#include "wl.h"
@ -128,8 +127,6 @@ static int self_check_in_wl_tree(const struct ubi_device *ubi,
struct ubi_wl_entry *e, struct rb_root *root);
static int self_check_in_pq(const struct ubi_device *ubi,
struct ubi_wl_entry *e);
static int ubi_wl_reboot_notifier(struct notifier_block *n,
unsigned long state, void *cmd);
/**
* wl_tree_add - add a wear-leveling entry to a WL RB-tree.
@ -1953,13 +1950,6 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
if (!ubi->ro_mode && !ubi->fm_disabled)
ubi_ensure_anchor_pebs(ubi);
#endif
if (!ubi->wl_reboot_notifier.notifier_call) {
ubi->wl_reboot_notifier.notifier_call = ubi_wl_reboot_notifier;
ubi->wl_reboot_notifier.priority = 1; /* Higher than MTD */
register_reboot_notifier(&ubi->wl_reboot_notifier);
}
return 0;
out_free:
@ -2005,17 +1995,6 @@ void ubi_wl_close(struct ubi_device *ubi)
kfree(ubi->lookuptbl);
}
static int ubi_wl_reboot_notifier(struct notifier_block *n,
unsigned long state, void *cmd)
{
struct ubi_device *ubi;
ubi = container_of(n, struct ubi_device, wl_reboot_notifier);
ubi_wl_close(ubi);
return NOTIFY_DONE;
}
/**
* self_check_ec - make sure that the erase counter of a PEB is correct.
* @ubi: UBI device description object

View File

@ -863,7 +863,6 @@ void ubifs_dump_leb(const struct ubifs_info *c, int lnum)
out:
vfree(buf);
return;
}
void ubifs_dump_znode(const struct ubifs_info *c,
@ -946,16 +945,20 @@ void ubifs_dump_tnc(struct ubifs_info *c)
pr_err("\n");
pr_err("(pid %d) start dumping TNC tree\n", current->pid);
znode = ubifs_tnc_levelorder_next(c, c->zroot.znode, NULL);
level = znode->level;
pr_err("== Level %d ==\n", level);
while (znode) {
if (level != znode->level) {
level = znode->level;
pr_err("== Level %d ==\n", level);
if (c->zroot.znode) {
znode = ubifs_tnc_levelorder_next(c, c->zroot.znode, NULL);
level = znode->level;
pr_err("== Level %d ==\n", level);
while (znode) {
if (level != znode->level) {
level = znode->level;
pr_err("== Level %d ==\n", level);
}
ubifs_dump_znode(c, znode);
znode = ubifs_tnc_levelorder_next(c, c->zroot.znode, znode);
}
ubifs_dump_znode(c, znode);
znode = ubifs_tnc_levelorder_next(c, c->zroot.znode, znode);
} else {
pr_err("empty TNC tree in memory\n");
}
pr_err("(pid %d) finish dumping TNC tree\n", current->pid);
}

View File

@ -1932,7 +1932,6 @@ static void dump_lpt_leb(const struct ubifs_info *c, int lnum)
pr_err("(pid %d) finish dumping LEB %d\n", current->pid, lnum);
out:
vfree(buf);
return;
}
/**

View File

@ -175,6 +175,8 @@
#define UBI_IOCRPEB _IOW(UBI_IOC_MAGIC, 4, __s32)
/* Force scrubbing on the specified PEB */
#define UBI_IOCSPEB _IOW(UBI_IOC_MAGIC, 5, __s32)
/* Read detailed device erase counter information */
#define UBI_IOCECNFO _IOWR(UBI_IOC_MAGIC, 6, struct ubi_ecinfo_req)
/* ioctl commands of the UBI control character device */
@ -412,6 +414,37 @@ struct ubi_rnvol_req {
} ents[UBI_MAX_RNVOL];
} __packed;
/**
* struct ubi_ecinfo_req - a data structure used for requesting and receiving
* erase block counter information from a UBI device.
*
* @start: index of first physical erase block to read (in)
* @length: number of erase counters to read (in)
* @read_length: number of erase counters that was actually read (out)
* @padding: reserved for future, not used, has to be zeroed
* @erase_counters: array of erase counter values (out)
*
* This structure is used to retrieve erase counter information for a specified
* range of PEBs on a UBI device.
* Erase counters are read from @start and attempts to read @length number of
* erase counters.
* The retrieved values are stored in the @erase_counters array. It is the
* responsibility of the caller to allocate enough memory for storing @length
* elements in the @erase_counters array.
* If a block is bad or if the erase counter is unknown the corresponding value
* in the array will be set to -1.
* The @read_length field will indicate the number of erase counters actually
* read. Typically @read_length will be limited due to memory or the number of
* PEBs on the UBI device.
*/
struct ubi_ecinfo_req {
__s32 start;
__s32 length;
__s32 read_length;
__s8 padding[16];
__s32 erase_counters[];
} __packed;
/**
* struct ubi_leb_change_req - a data structure used in atomic LEB change
* requests.