Merge branch 'linux-next' of git://git.infradead.org/ubi-2.6
* 'linux-next' of git://git.infradead.org/ubi-2.6: UBI: clarify the volume notification types' doc UBI: remove dead code UBI: dump stack when switching to R/O mode UBI: fix oops in error path UBI: switch debugging tests knobs to debugfs UBI: make it possible to use struct ubi_device in debug.h UBI: prepare debugging stuff to further debugfs conversion UBI: use debugfs for the extra checks knobs UBI: change the interface of a debugging check function
This commit is contained in:
Коммит
eadc3875eb
|
@ -953,10 +953,14 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
|
||||||
if (!ubi->peb_buf2)
|
if (!ubi->peb_buf2)
|
||||||
goto out_free;
|
goto out_free;
|
||||||
|
|
||||||
|
err = ubi_debugging_init_dev(ubi);
|
||||||
|
if (err)
|
||||||
|
goto out_free;
|
||||||
|
|
||||||
err = attach_by_scanning(ubi);
|
err = attach_by_scanning(ubi);
|
||||||
if (err) {
|
if (err) {
|
||||||
dbg_err("failed to attach by scanning, error %d", err);
|
dbg_err("failed to attach by scanning, error %d", err);
|
||||||
goto out_free;
|
goto out_debugging;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ubi->autoresize_vol_id != -1) {
|
if (ubi->autoresize_vol_id != -1) {
|
||||||
|
@ -969,12 +973,16 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
|
||||||
if (err)
|
if (err)
|
||||||
goto out_detach;
|
goto out_detach;
|
||||||
|
|
||||||
|
err = ubi_debugfs_init_dev(ubi);
|
||||||
|
if (err)
|
||||||
|
goto out_uif;
|
||||||
|
|
||||||
ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name);
|
ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name);
|
||||||
if (IS_ERR(ubi->bgt_thread)) {
|
if (IS_ERR(ubi->bgt_thread)) {
|
||||||
err = PTR_ERR(ubi->bgt_thread);
|
err = PTR_ERR(ubi->bgt_thread);
|
||||||
ubi_err("cannot spawn \"%s\", error %d", ubi->bgt_name,
|
ubi_err("cannot spawn \"%s\", error %d", ubi->bgt_name,
|
||||||
err);
|
err);
|
||||||
goto out_uif;
|
goto out_debugfs;
|
||||||
}
|
}
|
||||||
|
|
||||||
ubi_msg("attached mtd%d to ubi%d", mtd->index, ubi_num);
|
ubi_msg("attached mtd%d to ubi%d", mtd->index, ubi_num);
|
||||||
|
@ -1008,12 +1016,18 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
|
||||||
ubi_notify_all(ubi, UBI_VOLUME_ADDED, NULL);
|
ubi_notify_all(ubi, UBI_VOLUME_ADDED, NULL);
|
||||||
return ubi_num;
|
return ubi_num;
|
||||||
|
|
||||||
|
out_debugfs:
|
||||||
|
ubi_debugfs_exit_dev(ubi);
|
||||||
out_uif:
|
out_uif:
|
||||||
|
get_device(&ubi->dev);
|
||||||
|
ubi_assert(ref);
|
||||||
uif_close(ubi);
|
uif_close(ubi);
|
||||||
out_detach:
|
out_detach:
|
||||||
ubi_wl_close(ubi);
|
ubi_wl_close(ubi);
|
||||||
free_internal_volumes(ubi);
|
free_internal_volumes(ubi);
|
||||||
vfree(ubi->vtbl);
|
vfree(ubi->vtbl);
|
||||||
|
out_debugging:
|
||||||
|
ubi_debugging_exit_dev(ubi);
|
||||||
out_free:
|
out_free:
|
||||||
vfree(ubi->peb_buf1);
|
vfree(ubi->peb_buf1);
|
||||||
vfree(ubi->peb_buf2);
|
vfree(ubi->peb_buf2);
|
||||||
|
@ -1080,11 +1094,13 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
|
||||||
*/
|
*/
|
||||||
get_device(&ubi->dev);
|
get_device(&ubi->dev);
|
||||||
|
|
||||||
|
ubi_debugfs_exit_dev(ubi);
|
||||||
uif_close(ubi);
|
uif_close(ubi);
|
||||||
ubi_wl_close(ubi);
|
ubi_wl_close(ubi);
|
||||||
free_internal_volumes(ubi);
|
free_internal_volumes(ubi);
|
||||||
vfree(ubi->vtbl);
|
vfree(ubi->vtbl);
|
||||||
put_mtd_device(ubi->mtd);
|
put_mtd_device(ubi->mtd);
|
||||||
|
ubi_debugging_exit_dev(ubi);
|
||||||
vfree(ubi->peb_buf1);
|
vfree(ubi->peb_buf1);
|
||||||
vfree(ubi->peb_buf2);
|
vfree(ubi->peb_buf2);
|
||||||
ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num);
|
ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num);
|
||||||
|
@ -1199,6 +1215,11 @@ static int __init ubi_init(void)
|
||||||
if (!ubi_wl_entry_slab)
|
if (!ubi_wl_entry_slab)
|
||||||
goto out_dev_unreg;
|
goto out_dev_unreg;
|
||||||
|
|
||||||
|
err = ubi_debugfs_init();
|
||||||
|
if (err)
|
||||||
|
goto out_slab;
|
||||||
|
|
||||||
|
|
||||||
/* Attach MTD devices */
|
/* Attach MTD devices */
|
||||||
for (i = 0; i < mtd_devs; i++) {
|
for (i = 0; i < mtd_devs; i++) {
|
||||||
struct mtd_dev_param *p = &mtd_dev_param[i];
|
struct mtd_dev_param *p = &mtd_dev_param[i];
|
||||||
|
@ -1247,6 +1268,8 @@ out_detach:
|
||||||
ubi_detach_mtd_dev(ubi_devices[k]->ubi_num, 1);
|
ubi_detach_mtd_dev(ubi_devices[k]->ubi_num, 1);
|
||||||
mutex_unlock(&ubi_devices_mutex);
|
mutex_unlock(&ubi_devices_mutex);
|
||||||
}
|
}
|
||||||
|
ubi_debugfs_exit();
|
||||||
|
out_slab:
|
||||||
kmem_cache_destroy(ubi_wl_entry_slab);
|
kmem_cache_destroy(ubi_wl_entry_slab);
|
||||||
out_dev_unreg:
|
out_dev_unreg:
|
||||||
misc_deregister(&ubi_ctrl_cdev);
|
misc_deregister(&ubi_ctrl_cdev);
|
||||||
|
@ -1270,6 +1293,7 @@ static void __exit ubi_exit(void)
|
||||||
ubi_detach_mtd_dev(ubi_devices[i]->ubi_num, 1);
|
ubi_detach_mtd_dev(ubi_devices[i]->ubi_num, 1);
|
||||||
mutex_unlock(&ubi_devices_mutex);
|
mutex_unlock(&ubi_devices_mutex);
|
||||||
}
|
}
|
||||||
|
ubi_debugfs_exit();
|
||||||
kmem_cache_destroy(ubi_wl_entry_slab);
|
kmem_cache_destroy(ubi_wl_entry_slab);
|
||||||
misc_deregister(&ubi_ctrl_cdev);
|
misc_deregister(&ubi_ctrl_cdev);
|
||||||
class_remove_file(ubi_class, &ubi_version);
|
class_remove_file(ubi_class, &ubi_version);
|
||||||
|
|
|
@ -27,17 +27,9 @@
|
||||||
#ifdef CONFIG_MTD_UBI_DEBUG
|
#ifdef CONFIG_MTD_UBI_DEBUG
|
||||||
|
|
||||||
#include "ubi.h"
|
#include "ubi.h"
|
||||||
|
#include <linux/debugfs.h>
|
||||||
|
#include <linux/uaccess.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/moduleparam.h>
|
|
||||||
|
|
||||||
unsigned int ubi_chk_flags;
|
|
||||||
unsigned int ubi_tst_flags;
|
|
||||||
|
|
||||||
module_param_named(debug_chks, ubi_chk_flags, uint, S_IRUGO | S_IWUSR);
|
|
||||||
module_param_named(debug_tsts, ubi_chk_flags, uint, S_IRUGO | S_IWUSR);
|
|
||||||
|
|
||||||
MODULE_PARM_DESC(debug_chks, "Debug check flags");
|
|
||||||
MODULE_PARM_DESC(debug_tsts, "Debug special test flags");
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ubi_dbg_dump_ec_hdr - dump an erase counter header.
|
* ubi_dbg_dump_ec_hdr - dump an erase counter header.
|
||||||
|
@ -239,4 +231,261 @@ out:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ubi_debugging_init_dev - initialize debugging for an UBI device.
|
||||||
|
* @ubi: UBI device description object
|
||||||
|
*
|
||||||
|
* This function initializes debugging-related data for UBI device @ubi.
|
||||||
|
* Returns zero in case of success and a negative error code in case of
|
||||||
|
* failure.
|
||||||
|
*/
|
||||||
|
int ubi_debugging_init_dev(struct ubi_device *ubi)
|
||||||
|
{
|
||||||
|
ubi->dbg = kzalloc(sizeof(struct ubi_debug_info), GFP_KERNEL);
|
||||||
|
if (!ubi->dbg)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ubi_debugging_exit_dev - free debugging data for an UBI device.
|
||||||
|
* @ubi: UBI device description object
|
||||||
|
*/
|
||||||
|
void ubi_debugging_exit_dev(struct ubi_device *ubi)
|
||||||
|
{
|
||||||
|
kfree(ubi->dbg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Root directory for UBI stuff in debugfs. Contains sub-directories which
|
||||||
|
* contain the stuff specific to particular UBI devices.
|
||||||
|
*/
|
||||||
|
static struct dentry *dfs_rootdir;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ubi_debugfs_init - create UBI debugfs directory.
|
||||||
|
*
|
||||||
|
* Create UBI debugfs directory. Returns zero in case of success and a negative
|
||||||
|
* error code in case of failure.
|
||||||
|
*/
|
||||||
|
int ubi_debugfs_init(void)
|
||||||
|
{
|
||||||
|
dfs_rootdir = debugfs_create_dir("ubi", NULL);
|
||||||
|
if (IS_ERR_OR_NULL(dfs_rootdir)) {
|
||||||
|
int err = dfs_rootdir ? -ENODEV : PTR_ERR(dfs_rootdir);
|
||||||
|
|
||||||
|
ubi_err("cannot create \"ubi\" debugfs directory, error %d\n",
|
||||||
|
err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ubi_debugfs_exit - remove UBI debugfs directory.
|
||||||
|
*/
|
||||||
|
void ubi_debugfs_exit(void)
|
||||||
|
{
|
||||||
|
debugfs_remove(dfs_rootdir);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read an UBI debugfs file */
|
||||||
|
static ssize_t dfs_file_read(struct file *file, char __user *user_buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
unsigned long ubi_num = (unsigned long)file->private_data;
|
||||||
|
struct dentry *dent = file->f_path.dentry;
|
||||||
|
struct ubi_device *ubi;
|
||||||
|
struct ubi_debug_info *d;
|
||||||
|
char buf[3];
|
||||||
|
int val;
|
||||||
|
|
||||||
|
ubi = ubi_get_device(ubi_num);
|
||||||
|
if (!ubi)
|
||||||
|
return -ENODEV;
|
||||||
|
d = ubi->dbg;
|
||||||
|
|
||||||
|
if (dent == d->dfs_chk_gen)
|
||||||
|
val = d->chk_gen;
|
||||||
|
else if (dent == d->dfs_chk_io)
|
||||||
|
val = d->chk_io;
|
||||||
|
else if (dent == d->dfs_disable_bgt)
|
||||||
|
val = d->disable_bgt;
|
||||||
|
else if (dent == d->dfs_emulate_bitflips)
|
||||||
|
val = d->emulate_bitflips;
|
||||||
|
else if (dent == d->dfs_emulate_io_failures)
|
||||||
|
val = d->emulate_io_failures;
|
||||||
|
else {
|
||||||
|
count = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val)
|
||||||
|
buf[0] = '1';
|
||||||
|
else
|
||||||
|
buf[0] = '0';
|
||||||
|
buf[1] = '\n';
|
||||||
|
buf[2] = 0x00;
|
||||||
|
|
||||||
|
count = simple_read_from_buffer(user_buf, count, ppos, buf, 2);
|
||||||
|
|
||||||
|
out:
|
||||||
|
ubi_put_device(ubi);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write an UBI debugfs file */
|
||||||
|
static ssize_t dfs_file_write(struct file *file, const char __user *user_buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
unsigned long ubi_num = (unsigned long)file->private_data;
|
||||||
|
struct dentry *dent = file->f_path.dentry;
|
||||||
|
struct ubi_device *ubi;
|
||||||
|
struct ubi_debug_info *d;
|
||||||
|
size_t buf_size;
|
||||||
|
char buf[8];
|
||||||
|
int val;
|
||||||
|
|
||||||
|
ubi = ubi_get_device(ubi_num);
|
||||||
|
if (!ubi)
|
||||||
|
return -ENODEV;
|
||||||
|
d = ubi->dbg;
|
||||||
|
|
||||||
|
buf_size = min_t(size_t, count, (sizeof(buf) - 1));
|
||||||
|
if (copy_from_user(buf, user_buf, buf_size)) {
|
||||||
|
count = -EFAULT;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf[0] == '1')
|
||||||
|
val = 1;
|
||||||
|
else if (buf[0] == '0')
|
||||||
|
val = 0;
|
||||||
|
else {
|
||||||
|
count = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dent == d->dfs_chk_gen)
|
||||||
|
d->chk_gen = val;
|
||||||
|
else if (dent == d->dfs_chk_io)
|
||||||
|
d->chk_io = val;
|
||||||
|
else if (dent == d->dfs_disable_bgt)
|
||||||
|
d->disable_bgt = val;
|
||||||
|
else if (dent == d->dfs_emulate_bitflips)
|
||||||
|
d->emulate_bitflips = val;
|
||||||
|
else if (dent == d->dfs_emulate_io_failures)
|
||||||
|
d->emulate_io_failures = val;
|
||||||
|
else
|
||||||
|
count = -EINVAL;
|
||||||
|
|
||||||
|
out:
|
||||||
|
ubi_put_device(ubi);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int default_open(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
if (inode->i_private)
|
||||||
|
file->private_data = inode->i_private;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* File operations for all UBI debugfs files */
|
||||||
|
static const struct file_operations dfs_fops = {
|
||||||
|
.read = dfs_file_read,
|
||||||
|
.write = dfs_file_write,
|
||||||
|
.open = default_open,
|
||||||
|
.llseek = no_llseek,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ubi_debugfs_init_dev - initialize debugfs for an UBI device.
|
||||||
|
* @ubi: UBI device description object
|
||||||
|
*
|
||||||
|
* This function creates all debugfs files for UBI device @ubi. Returns zero in
|
||||||
|
* case of success and a negative error code in case of failure.
|
||||||
|
*/
|
||||||
|
int ubi_debugfs_init_dev(struct ubi_device *ubi)
|
||||||
|
{
|
||||||
|
int err, n;
|
||||||
|
unsigned long ubi_num = ubi->ubi_num;
|
||||||
|
const char *fname;
|
||||||
|
struct dentry *dent;
|
||||||
|
struct ubi_debug_info *d = ubi->dbg;
|
||||||
|
|
||||||
|
n = snprintf(d->dfs_dir_name, UBI_DFS_DIR_LEN + 1, UBI_DFS_DIR_NAME,
|
||||||
|
ubi->ubi_num);
|
||||||
|
if (n == UBI_DFS_DIR_LEN) {
|
||||||
|
/* The array size is too small */
|
||||||
|
fname = UBI_DFS_DIR_NAME;
|
||||||
|
dent = ERR_PTR(-EINVAL);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
fname = d->dfs_dir_name;
|
||||||
|
dent = debugfs_create_dir(fname, dfs_rootdir);
|
||||||
|
if (IS_ERR_OR_NULL(dent))
|
||||||
|
goto out;
|
||||||
|
d->dfs_dir = dent;
|
||||||
|
|
||||||
|
fname = "chk_gen";
|
||||||
|
dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
|
||||||
|
&dfs_fops);
|
||||||
|
if (IS_ERR_OR_NULL(dent))
|
||||||
|
goto out_remove;
|
||||||
|
d->dfs_chk_gen = dent;
|
||||||
|
|
||||||
|
fname = "chk_io";
|
||||||
|
dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
|
||||||
|
&dfs_fops);
|
||||||
|
if (IS_ERR_OR_NULL(dent))
|
||||||
|
goto out_remove;
|
||||||
|
d->dfs_chk_io = dent;
|
||||||
|
|
||||||
|
fname = "tst_disable_bgt";
|
||||||
|
dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
|
||||||
|
&dfs_fops);
|
||||||
|
if (IS_ERR_OR_NULL(dent))
|
||||||
|
goto out_remove;
|
||||||
|
d->dfs_disable_bgt = dent;
|
||||||
|
|
||||||
|
fname = "tst_emulate_bitflips";
|
||||||
|
dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
|
||||||
|
&dfs_fops);
|
||||||
|
if (IS_ERR_OR_NULL(dent))
|
||||||
|
goto out_remove;
|
||||||
|
d->dfs_emulate_bitflips = dent;
|
||||||
|
|
||||||
|
fname = "tst_emulate_io_failures";
|
||||||
|
dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
|
||||||
|
&dfs_fops);
|
||||||
|
if (IS_ERR_OR_NULL(dent))
|
||||||
|
goto out_remove;
|
||||||
|
d->dfs_emulate_io_failures = dent;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out_remove:
|
||||||
|
debugfs_remove_recursive(d->dfs_dir);
|
||||||
|
out:
|
||||||
|
err = dent ? PTR_ERR(dent) : -ENODEV;
|
||||||
|
ubi_err("cannot create \"%s\" debugfs file or directory, error %d\n",
|
||||||
|
fname, err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dbg_debug_exit_dev - free all debugfs files corresponding to device @ubi
|
||||||
|
* @ubi: UBI device description object
|
||||||
|
*/
|
||||||
|
void ubi_debugfs_exit_dev(struct ubi_device *ubi)
|
||||||
|
{
|
||||||
|
debugfs_remove_recursive(ubi->dbg->dfs_dir);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_MTD_UBI_DEBUG */
|
#endif /* CONFIG_MTD_UBI_DEBUG */
|
||||||
|
|
|
@ -21,14 +21,6 @@
|
||||||
#ifndef __UBI_DEBUG_H__
|
#ifndef __UBI_DEBUG_H__
|
||||||
#define __UBI_DEBUG_H__
|
#define __UBI_DEBUG_H__
|
||||||
|
|
||||||
struct ubi_ec_hdr;
|
|
||||||
struct ubi_vid_hdr;
|
|
||||||
struct ubi_volume;
|
|
||||||
struct ubi_vtbl_record;
|
|
||||||
struct ubi_scan_volume;
|
|
||||||
struct ubi_scan_leb;
|
|
||||||
struct ubi_mkvol_req;
|
|
||||||
|
|
||||||
#ifdef CONFIG_MTD_UBI_DEBUG
|
#ifdef CONFIG_MTD_UBI_DEBUG
|
||||||
#include <linux/random.h>
|
#include <linux/random.h>
|
||||||
|
|
||||||
|
@ -71,86 +63,103 @@ void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv);
|
||||||
void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type);
|
void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type);
|
||||||
void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req);
|
void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req);
|
||||||
void ubi_dbg_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len);
|
void ubi_dbg_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len);
|
||||||
|
|
||||||
extern unsigned int ubi_chk_flags;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Debugging check flags.
|
|
||||||
*
|
|
||||||
* UBI_CHK_GEN: general checks
|
|
||||||
* UBI_CHK_IO: check writes and erases
|
|
||||||
*/
|
|
||||||
enum {
|
|
||||||
UBI_CHK_GEN = 0x1,
|
|
||||||
UBI_CHK_IO = 0x2,
|
|
||||||
};
|
|
||||||
|
|
||||||
int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len);
|
int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len);
|
||||||
int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum,
|
int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum,
|
||||||
int offset, int len);
|
int offset, int len);
|
||||||
|
int ubi_debugging_init_dev(struct ubi_device *ubi);
|
||||||
extern unsigned int ubi_tst_flags;
|
void ubi_debugging_exit_dev(struct ubi_device *ubi);
|
||||||
|
int ubi_debugfs_init(void);
|
||||||
|
void ubi_debugfs_exit(void);
|
||||||
|
int ubi_debugfs_init_dev(struct ubi_device *ubi);
|
||||||
|
void ubi_debugfs_exit_dev(struct ubi_device *ubi);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Special testing flags.
|
* The UBI debugfs directory name pattern and maximum name length (3 for "ubi"
|
||||||
*
|
* + 2 for the number plus 1 for the trailing zero byte.
|
||||||
* UBIFS_TST_DISABLE_BGT: disable the background thread
|
|
||||||
* UBI_TST_EMULATE_BITFLIPS: emulate bit-flips
|
|
||||||
* UBI_TST_EMULATE_WRITE_FAILURES: emulate write failures
|
|
||||||
* UBI_TST_EMULATE_ERASE_FAILURES: emulate erase failures
|
|
||||||
*/
|
*/
|
||||||
enum {
|
#define UBI_DFS_DIR_NAME "ubi%d"
|
||||||
UBI_TST_DISABLE_BGT = 0x1,
|
#define UBI_DFS_DIR_LEN (3 + 2 + 1)
|
||||||
UBI_TST_EMULATE_BITFLIPS = 0x2,
|
|
||||||
UBI_TST_EMULATE_WRITE_FAILURES = 0x4,
|
/**
|
||||||
UBI_TST_EMULATE_ERASE_FAILURES = 0x8,
|
* struct ubi_debug_info - debugging information for an UBI device.
|
||||||
|
*
|
||||||
|
* @chk_gen: if UBI general extra checks are enabled
|
||||||
|
* @chk_io: if UBI I/O extra checks are enabled
|
||||||
|
* @disable_bgt: disable the background task for testing purposes
|
||||||
|
* @emulate_bitflips: emulate bit-flips for testing purposes
|
||||||
|
* @emulate_io_failures: emulate write/erase failures for testing purposes
|
||||||
|
* @dfs_dir_name: name of debugfs directory containing files of this UBI device
|
||||||
|
* @dfs_dir: direntry object of the UBI device debugfs directory
|
||||||
|
* @dfs_chk_gen: debugfs knob to enable UBI general extra checks
|
||||||
|
* @dfs_chk_io: debugfs knob to enable UBI I/O extra checks
|
||||||
|
* @dfs_disable_bgt: debugfs knob to disable the background task
|
||||||
|
* @dfs_emulate_bitflips: debugfs knob to emulate bit-flips
|
||||||
|
* @dfs_emulate_io_failures: debugfs knob to emulate write/erase failures
|
||||||
|
*/
|
||||||
|
struct ubi_debug_info {
|
||||||
|
unsigned int chk_gen:1;
|
||||||
|
unsigned int chk_io:1;
|
||||||
|
unsigned int disable_bgt:1;
|
||||||
|
unsigned int emulate_bitflips:1;
|
||||||
|
unsigned int emulate_io_failures:1;
|
||||||
|
char dfs_dir_name[UBI_DFS_DIR_LEN + 1];
|
||||||
|
struct dentry *dfs_dir;
|
||||||
|
struct dentry *dfs_chk_gen;
|
||||||
|
struct dentry *dfs_chk_io;
|
||||||
|
struct dentry *dfs_disable_bgt;
|
||||||
|
struct dentry *dfs_emulate_bitflips;
|
||||||
|
struct dentry *dfs_emulate_io_failures;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ubi_dbg_is_bgt_disabled - if the background thread is disabled.
|
* ubi_dbg_is_bgt_disabled - if the background thread is disabled.
|
||||||
|
* @ubi: UBI device description object
|
||||||
*
|
*
|
||||||
* Returns non-zero if the UBI background thread is disabled for testing
|
* Returns non-zero if the UBI background thread is disabled for testing
|
||||||
* purposes.
|
* purposes.
|
||||||
*/
|
*/
|
||||||
static inline int ubi_dbg_is_bgt_disabled(void)
|
static inline int ubi_dbg_is_bgt_disabled(const struct ubi_device *ubi)
|
||||||
{
|
{
|
||||||
return ubi_tst_flags & UBI_TST_DISABLE_BGT;
|
return ubi->dbg->disable_bgt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ubi_dbg_is_bitflip - if it is time to emulate a bit-flip.
|
* ubi_dbg_is_bitflip - if it is time to emulate a bit-flip.
|
||||||
|
* @ubi: UBI device description object
|
||||||
*
|
*
|
||||||
* Returns non-zero if a bit-flip should be emulated, otherwise returns zero.
|
* Returns non-zero if a bit-flip should be emulated, otherwise returns zero.
|
||||||
*/
|
*/
|
||||||
static inline int ubi_dbg_is_bitflip(void)
|
static inline int ubi_dbg_is_bitflip(const struct ubi_device *ubi)
|
||||||
{
|
{
|
||||||
if (ubi_tst_flags & UBI_TST_EMULATE_BITFLIPS)
|
if (ubi->dbg->emulate_bitflips)
|
||||||
return !(random32() % 200);
|
return !(random32() % 200);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ubi_dbg_is_write_failure - if it is time to emulate a write failure.
|
* ubi_dbg_is_write_failure - if it is time to emulate a write failure.
|
||||||
|
* @ubi: UBI device description object
|
||||||
*
|
*
|
||||||
* Returns non-zero if a write failure should be emulated, otherwise returns
|
* Returns non-zero if a write failure should be emulated, otherwise returns
|
||||||
* zero.
|
* zero.
|
||||||
*/
|
*/
|
||||||
static inline int ubi_dbg_is_write_failure(void)
|
static inline int ubi_dbg_is_write_failure(const struct ubi_device *ubi)
|
||||||
{
|
{
|
||||||
if (ubi_tst_flags & UBI_TST_EMULATE_WRITE_FAILURES)
|
if (ubi->dbg->emulate_io_failures)
|
||||||
return !(random32() % 500);
|
return !(random32() % 500);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ubi_dbg_is_erase_failure - if its time to emulate an erase failure.
|
* ubi_dbg_is_erase_failure - if its time to emulate an erase failure.
|
||||||
|
* @ubi: UBI device description object
|
||||||
*
|
*
|
||||||
* Returns non-zero if an erase failure should be emulated, otherwise returns
|
* Returns non-zero if an erase failure should be emulated, otherwise returns
|
||||||
* zero.
|
* zero.
|
||||||
*/
|
*/
|
||||||
static inline int ubi_dbg_is_erase_failure(void)
|
static inline int ubi_dbg_is_erase_failure(const struct ubi_device *ubi)
|
||||||
{
|
{
|
||||||
if (ubi_tst_flags & UBI_TST_EMULATE_ERASE_FAILURES)
|
if (ubi->dbg->emulate_io_failures)
|
||||||
return !(random32() % 400);
|
return !(random32() % 400);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -201,11 +210,6 @@ static inline void ubi_dbg_dump_flash(struct ubi_device *ubi,
|
||||||
static inline void
|
static inline void
|
||||||
ubi_dbg_print_hex_dump(const char *l, const char *ps, int pt, int r,
|
ubi_dbg_print_hex_dump(const char *l, const char *ps, int pt, int r,
|
||||||
int g, const void *b, size_t len, bool a) { return; }
|
int g, const void *b, size_t len, bool a) { return; }
|
||||||
|
|
||||||
static inline int ubi_dbg_is_bgt_disabled(void) { return 0; }
|
|
||||||
static inline int ubi_dbg_is_bitflip(void) { return 0; }
|
|
||||||
static inline int ubi_dbg_is_write_failure(void) { return 0; }
|
|
||||||
static inline int ubi_dbg_is_erase_failure(void) { return 0; }
|
|
||||||
static inline int ubi_dbg_check_all_ff(struct ubi_device *ubi,
|
static inline int ubi_dbg_check_all_ff(struct ubi_device *ubi,
|
||||||
int pnum, int offset,
|
int pnum, int offset,
|
||||||
int len) { return 0; }
|
int len) { return 0; }
|
||||||
|
@ -213,5 +217,20 @@ static inline int ubi_dbg_check_write(struct ubi_device *ubi,
|
||||||
const void *buf, int pnum,
|
const void *buf, int pnum,
|
||||||
int offset, int len) { return 0; }
|
int offset, int len) { return 0; }
|
||||||
|
|
||||||
|
static inline int ubi_debugging_init_dev(struct ubi_device *ubi) { return 0; }
|
||||||
|
static inline void ubi_debugging_exit_dev(struct ubi_device *ubi) { return; }
|
||||||
|
static inline int ubi_debugfs_init(void) { return 0; }
|
||||||
|
static inline void ubi_debugfs_exit(void) { return; }
|
||||||
|
static inline int ubi_debugfs_init_dev(struct ubi_device *ubi) { return 0; }
|
||||||
|
static inline void ubi_debugfs_exit_dev(struct ubi_device *ubi) { return; }
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
ubi_dbg_is_bgt_disabled(const struct ubi_device *ubi) { return 0; }
|
||||||
|
static inline int ubi_dbg_is_bitflip(const struct ubi_device *ubi) { return 0; }
|
||||||
|
static inline int
|
||||||
|
ubi_dbg_is_write_failure(const struct ubi_device *ubi) { return 0; }
|
||||||
|
static inline int
|
||||||
|
ubi_dbg_is_erase_failure(const struct ubi_device *ubi) { return 0; }
|
||||||
|
|
||||||
#endif /* !CONFIG_MTD_UBI_DEBUG */
|
#endif /* !CONFIG_MTD_UBI_DEBUG */
|
||||||
#endif /* !__UBI_DEBUG_H__ */
|
#endif /* !__UBI_DEBUG_H__ */
|
||||||
|
|
|
@ -212,7 +212,7 @@ retry:
|
||||||
} else {
|
} else {
|
||||||
ubi_assert(len == read);
|
ubi_assert(len == read);
|
||||||
|
|
||||||
if (ubi_dbg_is_bitflip()) {
|
if (ubi_dbg_is_bitflip(ubi)) {
|
||||||
dbg_gen("bit-flip (emulated)");
|
dbg_gen("bit-flip (emulated)");
|
||||||
err = UBI_IO_BITFLIPS;
|
err = UBI_IO_BITFLIPS;
|
||||||
}
|
}
|
||||||
|
@ -281,7 +281,7 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ubi_dbg_is_write_failure()) {
|
if (ubi_dbg_is_write_failure(ubi)) {
|
||||||
dbg_err("cannot write %d bytes to PEB %d:%d "
|
dbg_err("cannot write %d bytes to PEB %d:%d "
|
||||||
"(emulated)", len, pnum, offset);
|
"(emulated)", len, pnum, offset);
|
||||||
ubi_dbg_dump_stack();
|
ubi_dbg_dump_stack();
|
||||||
|
@ -396,7 +396,7 @@ retry:
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
if (ubi_dbg_is_erase_failure()) {
|
if (ubi_dbg_is_erase_failure(ubi)) {
|
||||||
dbg_err("cannot erase PEB %d (emulated)", pnum);
|
dbg_err("cannot erase PEB %d (emulated)", pnum);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
@ -1146,7 +1146,7 @@ static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (!(ubi_chk_flags & UBI_CHK_IO))
|
if (!ubi->dbg->chk_io)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err = ubi_io_is_bad(ubi, pnum);
|
err = ubi_io_is_bad(ubi, pnum);
|
||||||
|
@ -1173,7 +1173,7 @@ static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
|
||||||
int err;
|
int err;
|
||||||
uint32_t magic;
|
uint32_t magic;
|
||||||
|
|
||||||
if (!(ubi_chk_flags & UBI_CHK_IO))
|
if (!ubi->dbg->chk_io)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
magic = be32_to_cpu(ec_hdr->magic);
|
magic = be32_to_cpu(ec_hdr->magic);
|
||||||
|
@ -1211,7 +1211,7 @@ static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum)
|
||||||
uint32_t crc, hdr_crc;
|
uint32_t crc, hdr_crc;
|
||||||
struct ubi_ec_hdr *ec_hdr;
|
struct ubi_ec_hdr *ec_hdr;
|
||||||
|
|
||||||
if (!(ubi_chk_flags & UBI_CHK_IO))
|
if (!ubi->dbg->chk_io)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
|
ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
|
||||||
|
@ -1255,7 +1255,7 @@ static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum,
|
||||||
int err;
|
int err;
|
||||||
uint32_t magic;
|
uint32_t magic;
|
||||||
|
|
||||||
if (!(ubi_chk_flags & UBI_CHK_IO))
|
if (!ubi->dbg->chk_io)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
magic = be32_to_cpu(vid_hdr->magic);
|
magic = be32_to_cpu(vid_hdr->magic);
|
||||||
|
@ -1296,7 +1296,7 @@ static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
|
||||||
struct ubi_vid_hdr *vid_hdr;
|
struct ubi_vid_hdr *vid_hdr;
|
||||||
void *p;
|
void *p;
|
||||||
|
|
||||||
if (!(ubi_chk_flags & UBI_CHK_IO))
|
if (!ubi->dbg->chk_io)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
|
vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
|
||||||
|
@ -1348,7 +1348,7 @@ int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum,
|
||||||
void *buf1;
|
void *buf1;
|
||||||
loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
|
loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
|
||||||
|
|
||||||
if (!(ubi_chk_flags & UBI_CHK_IO))
|
if (!ubi->dbg->chk_io)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
buf1 = __vmalloc(len, GFP_NOFS, PAGE_KERNEL);
|
buf1 = __vmalloc(len, GFP_NOFS, PAGE_KERNEL);
|
||||||
|
@ -1412,7 +1412,7 @@ int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len)
|
||||||
void *buf;
|
void *buf;
|
||||||
loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
|
loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
|
||||||
|
|
||||||
if (!(ubi_chk_flags & UBI_CHK_IO))
|
if (!ubi->dbg->chk_io)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
buf = __vmalloc(len, GFP_NOFS, PAGE_KERNEL);
|
buf = __vmalloc(len, GFP_NOFS, PAGE_KERNEL);
|
||||||
|
|
|
@ -1347,7 +1347,7 @@ static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si)
|
||||||
struct ubi_scan_leb *seb, *last_seb;
|
struct ubi_scan_leb *seb, *last_seb;
|
||||||
uint8_t *buf;
|
uint8_t *buf;
|
||||||
|
|
||||||
if (!(ubi_chk_flags & UBI_CHK_GEN))
|
if (!ubi->dbg->chk_gen)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -44,7 +44,6 @@
|
||||||
|
|
||||||
#include "ubi-media.h"
|
#include "ubi-media.h"
|
||||||
#include "scan.h"
|
#include "scan.h"
|
||||||
#include "debug.h"
|
|
||||||
|
|
||||||
/* Maximum number of supported UBI devices */
|
/* Maximum number of supported UBI devices */
|
||||||
#define UBI_MAX_DEVICES 32
|
#define UBI_MAX_DEVICES 32
|
||||||
|
@ -390,6 +389,8 @@ struct ubi_wl_entry;
|
||||||
* @peb_buf2: another buffer of PEB size used for different purposes
|
* @peb_buf2: another buffer of PEB size used for different purposes
|
||||||
* @buf_mutex: protects @peb_buf1 and @peb_buf2
|
* @buf_mutex: protects @peb_buf1 and @peb_buf2
|
||||||
* @ckvol_mutex: serializes static volume checking when opening
|
* @ckvol_mutex: serializes static volume checking when opening
|
||||||
|
*
|
||||||
|
* @dbg: debugging information for this UBI device
|
||||||
*/
|
*/
|
||||||
struct ubi_device {
|
struct ubi_device {
|
||||||
struct cdev cdev;
|
struct cdev cdev;
|
||||||
|
@ -472,8 +473,12 @@ struct ubi_device {
|
||||||
void *peb_buf2;
|
void *peb_buf2;
|
||||||
struct mutex buf_mutex;
|
struct mutex buf_mutex;
|
||||||
struct mutex ckvol_mutex;
|
struct mutex ckvol_mutex;
|
||||||
|
|
||||||
|
struct ubi_debug_info *dbg;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
extern struct kmem_cache *ubi_wl_entry_slab;
|
extern struct kmem_cache *ubi_wl_entry_slab;
|
||||||
extern const struct file_operations ubi_ctrl_cdev_operations;
|
extern const struct file_operations ubi_ctrl_cdev_operations;
|
||||||
extern const struct file_operations ubi_cdev_operations;
|
extern const struct file_operations ubi_cdev_operations;
|
||||||
|
@ -662,6 +667,7 @@ static inline void ubi_ro_mode(struct ubi_device *ubi)
|
||||||
if (!ubi->ro_mode) {
|
if (!ubi->ro_mode) {
|
||||||
ubi->ro_mode = 1;
|
ubi->ro_mode = 1;
|
||||||
ubi_warn("switch to read-only mode");
|
ubi_warn("switch to read-only mode");
|
||||||
|
ubi_dbg_dump_stack();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -871,7 +871,7 @@ static int paranoid_check_volumes(struct ubi_device *ubi)
|
||||||
{
|
{
|
||||||
int i, err = 0;
|
int i, err = 0;
|
||||||
|
|
||||||
if (!(ubi_chk_flags & UBI_CHK_GEN))
|
if (!ubi->dbg->chk_gen)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (i = 0; i < ubi->vtbl_slots; i++) {
|
for (i = 0; i < ubi->vtbl_slots; i++) {
|
||||||
|
|
|
@ -307,8 +307,7 @@ static int create_vtbl(struct ubi_device *ubi, struct ubi_scan_info *si,
|
||||||
{
|
{
|
||||||
int err, tries = 0;
|
int err, tries = 0;
|
||||||
static struct ubi_vid_hdr *vid_hdr;
|
static struct ubi_vid_hdr *vid_hdr;
|
||||||
struct ubi_scan_volume *sv;
|
struct ubi_scan_leb *new_seb;
|
||||||
struct ubi_scan_leb *new_seb, *old_seb = NULL;
|
|
||||||
|
|
||||||
ubi_msg("create volume table (copy #%d)", copy + 1);
|
ubi_msg("create volume table (copy #%d)", copy + 1);
|
||||||
|
|
||||||
|
@ -316,15 +315,6 @@ static int create_vtbl(struct ubi_device *ubi, struct ubi_scan_info *si,
|
||||||
if (!vid_hdr)
|
if (!vid_hdr)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/*
|
|
||||||
* Check if there is a logical eraseblock which would have to contain
|
|
||||||
* this volume table copy was found during scanning. It has to be wiped
|
|
||||||
* out.
|
|
||||||
*/
|
|
||||||
sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOLUME_ID);
|
|
||||||
if (sv)
|
|
||||||
old_seb = ubi_scan_find_seb(sv, copy);
|
|
||||||
|
|
||||||
retry:
|
retry:
|
||||||
new_seb = ubi_scan_get_free_peb(ubi, si);
|
new_seb = ubi_scan_get_free_peb(ubi, si);
|
||||||
if (IS_ERR(new_seb)) {
|
if (IS_ERR(new_seb)) {
|
||||||
|
@ -351,8 +341,8 @@ retry:
|
||||||
goto write_error;
|
goto write_error;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* And add it to the scanning information. Don't delete the old
|
* And add it to the scanning information. Don't delete the old version
|
||||||
* @old_seb as it will be deleted and freed in 'ubi_scan_add_used()'.
|
* of this LEB as it will be deleted and freed in 'ubi_scan_add_used()'.
|
||||||
*/
|
*/
|
||||||
err = ubi_scan_add_used(ubi, si, new_seb->pnum, new_seb->ec,
|
err = ubi_scan_add_used(ubi, si, new_seb->pnum, new_seb->ec,
|
||||||
vid_hdr, 0);
|
vid_hdr, 0);
|
||||||
|
@ -876,7 +866,7 @@ out_free:
|
||||||
*/
|
*/
|
||||||
static void paranoid_vtbl_check(const struct ubi_device *ubi)
|
static void paranoid_vtbl_check(const struct ubi_device *ubi)
|
||||||
{
|
{
|
||||||
if (!(ubi_chk_flags & UBI_CHK_GEN))
|
if (!ubi->dbg->chk_gen)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (vtbl_check(ubi, ubi->vtbl)) {
|
if (vtbl_check(ubi, ubi->vtbl)) {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
/*
|
/*
|
||||||
|
* @ubi: UBI device description object
|
||||||
* Copyright (c) International Business Machines Corp., 2006
|
* Copyright (c) International Business Machines Corp., 2006
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
@ -163,12 +164,14 @@ struct ubi_work {
|
||||||
|
|
||||||
#ifdef CONFIG_MTD_UBI_DEBUG
|
#ifdef CONFIG_MTD_UBI_DEBUG
|
||||||
static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec);
|
static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec);
|
||||||
static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e,
|
static int paranoid_check_in_wl_tree(const struct ubi_device *ubi,
|
||||||
|
struct ubi_wl_entry *e,
|
||||||
struct rb_root *root);
|
struct rb_root *root);
|
||||||
static int paranoid_check_in_pq(struct ubi_device *ubi, struct ubi_wl_entry *e);
|
static int paranoid_check_in_pq(const struct ubi_device *ubi,
|
||||||
|
struct ubi_wl_entry *e);
|
||||||
#else
|
#else
|
||||||
#define paranoid_check_ec(ubi, pnum, ec) 0
|
#define paranoid_check_ec(ubi, pnum, ec) 0
|
||||||
#define paranoid_check_in_wl_tree(e, root)
|
#define paranoid_check_in_wl_tree(ubi, e, root)
|
||||||
#define paranoid_check_in_pq(ubi, e) 0
|
#define paranoid_check_in_pq(ubi, e) 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -449,7 +452,7 @@ retry:
|
||||||
BUG();
|
BUG();
|
||||||
}
|
}
|
||||||
|
|
||||||
paranoid_check_in_wl_tree(e, &ubi->free);
|
paranoid_check_in_wl_tree(ubi, e, &ubi->free);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Move the physical eraseblock to the protection queue where it will
|
* Move the physical eraseblock to the protection queue where it will
|
||||||
|
@ -613,7 +616,7 @@ static void schedule_ubi_work(struct ubi_device *ubi, struct ubi_work *wrk)
|
||||||
list_add_tail(&wrk->list, &ubi->works);
|
list_add_tail(&wrk->list, &ubi->works);
|
||||||
ubi_assert(ubi->works_count >= 0);
|
ubi_assert(ubi->works_count >= 0);
|
||||||
ubi->works_count += 1;
|
ubi->works_count += 1;
|
||||||
if (ubi->thread_enabled && !ubi_dbg_is_bgt_disabled())
|
if (ubi->thread_enabled && !ubi_dbg_is_bgt_disabled(ubi))
|
||||||
wake_up_process(ubi->bgt_thread);
|
wake_up_process(ubi->bgt_thread);
|
||||||
spin_unlock(&ubi->wl_lock);
|
spin_unlock(&ubi->wl_lock);
|
||||||
}
|
}
|
||||||
|
@ -712,7 +715,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
|
||||||
e1->ec, e2->ec);
|
e1->ec, e2->ec);
|
||||||
goto out_cancel;
|
goto out_cancel;
|
||||||
}
|
}
|
||||||
paranoid_check_in_wl_tree(e1, &ubi->used);
|
paranoid_check_in_wl_tree(ubi, e1, &ubi->used);
|
||||||
rb_erase(&e1->u.rb, &ubi->used);
|
rb_erase(&e1->u.rb, &ubi->used);
|
||||||
dbg_wl("move PEB %d EC %d to PEB %d EC %d",
|
dbg_wl("move PEB %d EC %d to PEB %d EC %d",
|
||||||
e1->pnum, e1->ec, e2->pnum, e2->ec);
|
e1->pnum, e1->ec, e2->pnum, e2->ec);
|
||||||
|
@ -721,12 +724,12 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
|
||||||
scrubbing = 1;
|
scrubbing = 1;
|
||||||
e1 = rb_entry(rb_first(&ubi->scrub), struct ubi_wl_entry, u.rb);
|
e1 = rb_entry(rb_first(&ubi->scrub), struct ubi_wl_entry, u.rb);
|
||||||
e2 = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF);
|
e2 = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF);
|
||||||
paranoid_check_in_wl_tree(e1, &ubi->scrub);
|
paranoid_check_in_wl_tree(ubi, e1, &ubi->scrub);
|
||||||
rb_erase(&e1->u.rb, &ubi->scrub);
|
rb_erase(&e1->u.rb, &ubi->scrub);
|
||||||
dbg_wl("scrub PEB %d to PEB %d", e1->pnum, e2->pnum);
|
dbg_wl("scrub PEB %d to PEB %d", e1->pnum, e2->pnum);
|
||||||
}
|
}
|
||||||
|
|
||||||
paranoid_check_in_wl_tree(e2, &ubi->free);
|
paranoid_check_in_wl_tree(ubi, e2, &ubi->free);
|
||||||
rb_erase(&e2->u.rb, &ubi->free);
|
rb_erase(&e2->u.rb, &ubi->free);
|
||||||
ubi->move_from = e1;
|
ubi->move_from = e1;
|
||||||
ubi->move_to = e2;
|
ubi->move_to = e2;
|
||||||
|
@ -1169,13 +1172,13 @@ retry:
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
if (in_wl_tree(e, &ubi->used)) {
|
if (in_wl_tree(e, &ubi->used)) {
|
||||||
paranoid_check_in_wl_tree(e, &ubi->used);
|
paranoid_check_in_wl_tree(ubi, e, &ubi->used);
|
||||||
rb_erase(&e->u.rb, &ubi->used);
|
rb_erase(&e->u.rb, &ubi->used);
|
||||||
} else if (in_wl_tree(e, &ubi->scrub)) {
|
} else if (in_wl_tree(e, &ubi->scrub)) {
|
||||||
paranoid_check_in_wl_tree(e, &ubi->scrub);
|
paranoid_check_in_wl_tree(ubi, e, &ubi->scrub);
|
||||||
rb_erase(&e->u.rb, &ubi->scrub);
|
rb_erase(&e->u.rb, &ubi->scrub);
|
||||||
} else if (in_wl_tree(e, &ubi->erroneous)) {
|
} else if (in_wl_tree(e, &ubi->erroneous)) {
|
||||||
paranoid_check_in_wl_tree(e, &ubi->erroneous);
|
paranoid_check_in_wl_tree(ubi, e, &ubi->erroneous);
|
||||||
rb_erase(&e->u.rb, &ubi->erroneous);
|
rb_erase(&e->u.rb, &ubi->erroneous);
|
||||||
ubi->erroneous_peb_count -= 1;
|
ubi->erroneous_peb_count -= 1;
|
||||||
ubi_assert(ubi->erroneous_peb_count >= 0);
|
ubi_assert(ubi->erroneous_peb_count >= 0);
|
||||||
|
@ -1242,7 +1245,7 @@ retry:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in_wl_tree(e, &ubi->used)) {
|
if (in_wl_tree(e, &ubi->used)) {
|
||||||
paranoid_check_in_wl_tree(e, &ubi->used);
|
paranoid_check_in_wl_tree(ubi, e, &ubi->used);
|
||||||
rb_erase(&e->u.rb, &ubi->used);
|
rb_erase(&e->u.rb, &ubi->used);
|
||||||
} else {
|
} else {
|
||||||
int err;
|
int err;
|
||||||
|
@ -1364,7 +1367,7 @@ int ubi_thread(void *u)
|
||||||
|
|
||||||
spin_lock(&ubi->wl_lock);
|
spin_lock(&ubi->wl_lock);
|
||||||
if (list_empty(&ubi->works) || ubi->ro_mode ||
|
if (list_empty(&ubi->works) || ubi->ro_mode ||
|
||||||
!ubi->thread_enabled || ubi_dbg_is_bgt_disabled()) {
|
!ubi->thread_enabled || ubi_dbg_is_bgt_disabled(ubi)) {
|
||||||
set_current_state(TASK_INTERRUPTIBLE);
|
set_current_state(TASK_INTERRUPTIBLE);
|
||||||
spin_unlock(&ubi->wl_lock);
|
spin_unlock(&ubi->wl_lock);
|
||||||
schedule();
|
schedule();
|
||||||
|
@ -1579,7 +1582,7 @@ static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec)
|
||||||
long long read_ec;
|
long long read_ec;
|
||||||
struct ubi_ec_hdr *ec_hdr;
|
struct ubi_ec_hdr *ec_hdr;
|
||||||
|
|
||||||
if (!(ubi_chk_flags & UBI_CHK_GEN))
|
if (!ubi->dbg->chk_gen)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
|
ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
|
||||||
|
@ -1609,16 +1612,18 @@ out_free:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* paranoid_check_in_wl_tree - check that wear-leveling entry is in WL RB-tree.
|
* paranoid_check_in_wl_tree - check that wear-leveling entry is in WL RB-tree.
|
||||||
|
* @ubi: UBI device description object
|
||||||
* @e: the wear-leveling entry to check
|
* @e: the wear-leveling entry to check
|
||||||
* @root: the root of the tree
|
* @root: the root of the tree
|
||||||
*
|
*
|
||||||
* This function returns zero if @e is in the @root RB-tree and %-EINVAL if it
|
* This function returns zero if @e is in the @root RB-tree and %-EINVAL if it
|
||||||
* is not.
|
* is not.
|
||||||
*/
|
*/
|
||||||
static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e,
|
static int paranoid_check_in_wl_tree(const struct ubi_device *ubi,
|
||||||
|
struct ubi_wl_entry *e,
|
||||||
struct rb_root *root)
|
struct rb_root *root)
|
||||||
{
|
{
|
||||||
if (!(ubi_chk_flags & UBI_CHK_GEN))
|
if (!ubi->dbg->chk_gen)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (in_wl_tree(e, root))
|
if (in_wl_tree(e, root))
|
||||||
|
@ -1638,12 +1643,13 @@ static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e,
|
||||||
*
|
*
|
||||||
* This function returns zero if @e is in @ubi->pq and %-EINVAL if it is not.
|
* This function returns zero if @e is in @ubi->pq and %-EINVAL if it is not.
|
||||||
*/
|
*/
|
||||||
static int paranoid_check_in_pq(struct ubi_device *ubi, struct ubi_wl_entry *e)
|
static int paranoid_check_in_pq(const struct ubi_device *ubi,
|
||||||
|
struct ubi_wl_entry *e)
|
||||||
{
|
{
|
||||||
struct ubi_wl_entry *p;
|
struct ubi_wl_entry *p;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!(ubi_chk_flags & UBI_CHK_GEN))
|
if (!ubi->dbg->chk_gen)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (i = 0; i < UBI_PROT_QUEUE_LEN; ++i)
|
for (i = 0; i < UBI_PROT_QUEUE_LEN; ++i)
|
||||||
|
|
|
@ -155,12 +155,14 @@ struct ubi_device_info {
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* enum - volume notification types.
|
* Volume notification types.
|
||||||
* @UBI_VOLUME_ADDED: volume has been added
|
* @UBI_VOLUME_ADDED: a volume has been added (an UBI device was attached or a
|
||||||
* @UBI_VOLUME_REMOVED: start volume volume
|
* volume was created)
|
||||||
* @UBI_VOLUME_RESIZED: volume size has been re-sized
|
* @UBI_VOLUME_REMOVED: a volume has been removed (an UBI device was detached
|
||||||
* @UBI_VOLUME_RENAMED: volume name has been re-named
|
* or a volume was removed)
|
||||||
* @UBI_VOLUME_UPDATED: volume name has been updated
|
* @UBI_VOLUME_RESIZED: a volume has been re-sized
|
||||||
|
* @UBI_VOLUME_RENAMED: a volume has been re-named
|
||||||
|
* @UBI_VOLUME_UPDATED: data has been written to a volume
|
||||||
*
|
*
|
||||||
* These constants define which type of event has happened when a volume
|
* These constants define which type of event has happened when a volume
|
||||||
* notification function is invoked.
|
* notification function is invoked.
|
||||||
|
|
Загрузка…
Ссылка в новой задаче