Merge branch 'linux-next' of git://git.infradead.org/ubi-2.6
* 'linux-next' of git://git.infradead.org/ubi-2.6: UBI: make tests modes dynamic UBI: make self-checks dynamic UBI: make debugging messages dynamic UBI: remove UBI_IO_DEBUG macro UBI: kill debugging buffer UBI: allocate erase checking buffer on demand UBI: allocate write checking buffer on demand UBI: always re-read in case of read failures UBI: cleanup comments about corrupted PEBs UBI: add slab cache for ubi_scan_leb objects UBI: use raw mtd read function in debugging code UBI: try to reveal buggy MTD drivers UBI: add a commentary about allocating VID header buffer on stack UBI: cleanup LEB start calculations UBI: fix NOR erase preparation quirk
This commit is contained in:
commit
fd57ed0219
@ -52,6 +52,12 @@ config MTD_UBI_GLUEBI
|
||||
work on top of UBI. Do not enable this unless you use legacy
|
||||
software.
|
||||
|
||||
source "drivers/mtd/ubi/Kconfig.debug"
|
||||
config MTD_UBI_DEBUG
|
||||
bool "UBI debugging"
|
||||
depends on SYSFS
|
||||
select DEBUG_FS
|
||||
select KALLSYMS_ALL if KALLSYMS && DEBUG_KERNEL
|
||||
help
|
||||
This option enables UBI debugging.
|
||||
|
||||
endif # MTD_UBI
|
||||
|
@ -1,73 +0,0 @@
|
||||
comment "UBI debugging options"
|
||||
|
||||
config MTD_UBI_DEBUG
|
||||
bool "UBI debugging"
|
||||
depends on SYSFS
|
||||
select DEBUG_FS
|
||||
select KALLSYMS_ALL if KALLSYMS && DEBUG_KERNEL
|
||||
help
|
||||
This option enables UBI debugging.
|
||||
|
||||
if MTD_UBI_DEBUG
|
||||
|
||||
config MTD_UBI_DEBUG_MSG
|
||||
bool "UBI debugging messages"
|
||||
help
|
||||
This option enables UBI debugging messages.
|
||||
|
||||
config MTD_UBI_DEBUG_PARANOID
|
||||
bool "Extra self-checks"
|
||||
help
|
||||
This option enables extra checks in UBI code. Note this slows UBI down
|
||||
significantly.
|
||||
|
||||
config MTD_UBI_DEBUG_DISABLE_BGT
|
||||
bool "Do not enable the UBI background thread"
|
||||
help
|
||||
This option switches the background thread off by default. The thread
|
||||
may be also be enabled/disabled via UBI sysfs.
|
||||
|
||||
config MTD_UBI_DEBUG_EMULATE_BITFLIPS
|
||||
bool "Emulate flash bit-flips"
|
||||
help
|
||||
This option emulates bit-flips with probability 1/50, which in turn
|
||||
causes scrubbing. Useful for debugging and stressing UBI.
|
||||
|
||||
config MTD_UBI_DEBUG_EMULATE_WRITE_FAILURES
|
||||
bool "Emulate flash write failures"
|
||||
help
|
||||
This option emulates write failures with probability 1/100. Useful for
|
||||
debugging and testing how UBI handlines errors.
|
||||
|
||||
config MTD_UBI_DEBUG_EMULATE_ERASE_FAILURES
|
||||
bool "Emulate flash erase failures"
|
||||
help
|
||||
This option emulates erase failures with probability 1/100. Useful for
|
||||
debugging and testing how UBI handlines errors.
|
||||
|
||||
comment "Additional UBI debugging messages"
|
||||
|
||||
config MTD_UBI_DEBUG_MSG_BLD
|
||||
bool "Additional UBI initialization and build messages"
|
||||
help
|
||||
This option enables detailed UBI initialization and device build
|
||||
debugging messages.
|
||||
|
||||
config MTD_UBI_DEBUG_MSG_EBA
|
||||
bool "Eraseblock association unit messages"
|
||||
help
|
||||
This option enables debugging messages from the UBI eraseblock
|
||||
association unit.
|
||||
|
||||
config MTD_UBI_DEBUG_MSG_WL
|
||||
bool "Wear-leveling unit messages"
|
||||
help
|
||||
This option enables debugging messages from the UBI wear-leveling
|
||||
unit.
|
||||
|
||||
config MTD_UBI_DEBUG_MSG_IO
|
||||
bool "Input/output unit messages"
|
||||
help
|
||||
This option enables debugging messages from the UBI input/output unit.
|
||||
|
||||
endif # MTD_UBI_DEBUG
|
@ -711,7 +711,7 @@ static int io_init(struct ubi_device *ubi)
|
||||
}
|
||||
|
||||
/* Similar for the data offset */
|
||||
ubi->leb_start = ubi->vid_hdr_offset + UBI_EC_HDR_SIZE;
|
||||
ubi->leb_start = ubi->vid_hdr_offset + UBI_VID_HDR_SIZE;
|
||||
ubi->leb_start = ALIGN(ubi->leb_start, ubi->min_io_size);
|
||||
|
||||
dbg_msg("vid_hdr_offset %d", ubi->vid_hdr_offset);
|
||||
@ -923,6 +923,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
|
||||
spin_lock_init(&ubi->volumes_lock);
|
||||
|
||||
ubi_msg("attaching mtd%d to ubi%d", mtd->index, ubi_num);
|
||||
dbg_msg("sizeof(struct ubi_scan_leb) %zu", sizeof(struct ubi_scan_leb));
|
||||
dbg_msg("sizeof(struct ubi_wl_entry) %zu", sizeof(struct ubi_wl_entry));
|
||||
|
||||
err = io_init(ubi);
|
||||
if (err)
|
||||
@ -937,13 +939,6 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
|
||||
if (!ubi->peb_buf2)
|
||||
goto out_free;
|
||||
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
|
||||
mutex_init(&ubi->dbg_buf_mutex);
|
||||
ubi->dbg_peb_buf = vmalloc(ubi->peb_size);
|
||||
if (!ubi->dbg_peb_buf)
|
||||
goto out_free;
|
||||
#endif
|
||||
|
||||
err = attach_by_scanning(ubi);
|
||||
if (err) {
|
||||
dbg_err("failed to attach by scanning, error %d", err);
|
||||
@ -991,8 +986,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
|
||||
* checks @ubi->thread_enabled. Otherwise we may fail to wake it up.
|
||||
*/
|
||||
spin_lock(&ubi->wl_lock);
|
||||
if (!DBG_DISABLE_BGT)
|
||||
ubi->thread_enabled = 1;
|
||||
ubi->thread_enabled = 1;
|
||||
wake_up_process(ubi->bgt_thread);
|
||||
spin_unlock(&ubi->wl_lock);
|
||||
|
||||
@ -1009,9 +1003,6 @@ out_detach:
|
||||
out_free:
|
||||
vfree(ubi->peb_buf1);
|
||||
vfree(ubi->peb_buf2);
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
|
||||
vfree(ubi->dbg_peb_buf);
|
||||
#endif
|
||||
if (ref)
|
||||
put_device(&ubi->dev);
|
||||
else
|
||||
@ -1082,9 +1073,6 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
|
||||
put_mtd_device(ubi->mtd);
|
||||
vfree(ubi->peb_buf1);
|
||||
vfree(ubi->peb_buf2);
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
|
||||
vfree(ubi->dbg_peb_buf);
|
||||
#endif
|
||||
ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num);
|
||||
put_device(&ubi->dev);
|
||||
return 0;
|
||||
|
@ -27,6 +27,20 @@
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG
|
||||
|
||||
#include "ubi.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
|
||||
unsigned int ubi_msg_flags;
|
||||
unsigned int ubi_chk_flags;
|
||||
unsigned int ubi_tst_flags;
|
||||
|
||||
module_param_named(debug_msgs, ubi_msg_flags, uint, S_IRUGO | S_IWUSR);
|
||||
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_msgs, "Debug message type flags");
|
||||
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.
|
||||
|
@ -38,6 +38,11 @@
|
||||
printk(KERN_DEBUG "UBI DBG (pid %d): %s: " fmt "\n", \
|
||||
current->pid, __func__, ##__VA_ARGS__)
|
||||
|
||||
#define dbg_do_msg(typ, fmt, ...) do { \
|
||||
if (ubi_msg_flags & typ) \
|
||||
dbg_msg(fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define ubi_dbg_dump_stack() dump_stack()
|
||||
|
||||
struct ubi_ec_hdr;
|
||||
@ -57,62 +62,88 @@ 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_flash(struct ubi_device *ubi, int pnum, int offset, int len);
|
||||
|
||||
extern unsigned int ubi_msg_flags;
|
||||
|
||||
/*
|
||||
* Debugging message type flags (must match msg_type_names in debug.c).
|
||||
*
|
||||
* UBI_MSG_GEN: general messages
|
||||
* UBI_MSG_EBA: journal messages
|
||||
* UBI_MSG_WL: mount messages
|
||||
* UBI_MSG_IO: commit messages
|
||||
* UBI_MSG_BLD: LEB find messages
|
||||
*/
|
||||
enum {
|
||||
UBI_MSG_GEN = 0x1,
|
||||
UBI_MSG_EBA = 0x2,
|
||||
UBI_MSG_WL = 0x4,
|
||||
UBI_MSG_IO = 0x8,
|
||||
UBI_MSG_BLD = 0x10,
|
||||
};
|
||||
|
||||
#define ubi_dbg_print_hex_dump(l, ps, pt, r, g, b, len, a) \
|
||||
print_hex_dump(l, ps, pt, r, g, b, len, a)
|
||||
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG_MSG
|
||||
/* General debugging messages */
|
||||
#define dbg_gen(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define dbg_gen(fmt, ...) ({})
|
||||
#endif
|
||||
#define dbg_gen(fmt, ...) dbg_do_msg(UBI_MSG_GEN, fmt, ##__VA_ARGS__)
|
||||
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG_MSG_EBA
|
||||
/* Messages from the eraseblock association sub-system */
|
||||
#define dbg_eba(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define dbg_eba(fmt, ...) ({})
|
||||
#endif
|
||||
#define dbg_eba(fmt, ...) dbg_do_msg(UBI_MSG_EBA, fmt, ##__VA_ARGS__)
|
||||
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG_MSG_WL
|
||||
/* Messages from the wear-leveling sub-system */
|
||||
#define dbg_wl(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define dbg_wl(fmt, ...) ({})
|
||||
#endif
|
||||
#define dbg_wl(fmt, ...) dbg_do_msg(UBI_MSG_WL, fmt, ##__VA_ARGS__)
|
||||
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG_MSG_IO
|
||||
/* Messages from the input/output sub-system */
|
||||
#define dbg_io(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define dbg_io(fmt, ...) ({})
|
||||
#endif
|
||||
#define dbg_io(fmt, ...) dbg_do_msg(UBI_MSG_IO, fmt, ##__VA_ARGS__)
|
||||
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG_MSG_BLD
|
||||
/* Initialization and build messages */
|
||||
#define dbg_bld(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
|
||||
#define UBI_IO_DEBUG 1
|
||||
#else
|
||||
#define dbg_bld(fmt, ...) ({})
|
||||
#define UBI_IO_DEBUG 0
|
||||
#endif
|
||||
#define dbg_bld(fmt, ...) dbg_do_msg(UBI_MSG_BLD, fmt, ##__VA_ARGS__)
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
|
||||
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 offset, int len);
|
||||
#else
|
||||
#define ubi_dbg_check_all_ff(ubi, pnum, offset, len) 0
|
||||
#define ubi_dbg_check_write(ubi, buf, pnum, offset, len) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG_DISABLE_BGT
|
||||
#define DBG_DISABLE_BGT 1
|
||||
#else
|
||||
#define DBG_DISABLE_BGT 0
|
||||
#endif
|
||||
extern unsigned int ubi_tst_flags;
|
||||
|
||||
/*
|
||||
* Special testing flags.
|
||||
*
|
||||
* 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 {
|
||||
UBI_TST_DISABLE_BGT = 0x1,
|
||||
UBI_TST_EMULATE_BITFLIPS = 0x2,
|
||||
UBI_TST_EMULATE_WRITE_FAILURES = 0x4,
|
||||
UBI_TST_EMULATE_ERASE_FAILURES = 0x8,
|
||||
};
|
||||
|
||||
/**
|
||||
* ubi_dbg_is_bgt_disabled - if the background thread is disabled.
|
||||
*
|
||||
* Returns non-zero if the UBI background thread is disabled for testing
|
||||
* purposes.
|
||||
*/
|
||||
static inline int ubi_dbg_is_bgt_disabled(void)
|
||||
{
|
||||
return ubi_tst_flags & UBI_TST_DISABLE_BGT;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG_EMULATE_BITFLIPS
|
||||
/**
|
||||
* ubi_dbg_is_bitflip - if it is time to emulate a bit-flip.
|
||||
*
|
||||
@ -120,13 +151,11 @@ int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum,
|
||||
*/
|
||||
static inline int ubi_dbg_is_bitflip(void)
|
||||
{
|
||||
return !(random32() % 200);
|
||||
if (ubi_tst_flags & UBI_TST_EMULATE_BITFLIPS)
|
||||
return !(random32() % 200);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define ubi_dbg_is_bitflip() 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG_EMULATE_WRITE_FAILURES
|
||||
/**
|
||||
* ubi_dbg_is_write_failure - if it is time to emulate a write failure.
|
||||
*
|
||||
@ -135,13 +164,11 @@ static inline int ubi_dbg_is_bitflip(void)
|
||||
*/
|
||||
static inline int ubi_dbg_is_write_failure(void)
|
||||
{
|
||||
return !(random32() % 500);
|
||||
if (ubi_tst_flags & UBI_TST_EMULATE_WRITE_FAILURES)
|
||||
return !(random32() % 500);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define ubi_dbg_is_write_failure() 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG_EMULATE_ERASE_FAILURES
|
||||
/**
|
||||
* ubi_dbg_is_erase_failure - if its time to emulate an erase failure.
|
||||
*
|
||||
@ -150,11 +177,10 @@ static inline int ubi_dbg_is_write_failure(void)
|
||||
*/
|
||||
static inline int ubi_dbg_is_erase_failure(void)
|
||||
{
|
||||
if (ubi_tst_flags & UBI_TST_EMULATE_ERASE_FAILURES)
|
||||
return !(random32() % 400);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define ubi_dbg_is_erase_failure() 0
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
@ -177,8 +203,7 @@ static inline int ubi_dbg_is_erase_failure(void)
|
||||
#define ubi_dbg_dump_flash(ubi, pnum, offset, len) ({})
|
||||
#define ubi_dbg_print_hex_dump(l, ps, pt, r, g, b, len, a) ({})
|
||||
|
||||
#define UBI_IO_DEBUG 0
|
||||
#define DBG_DISABLE_BGT 0
|
||||
#define ubi_dbg_is_bgt_disabled() 0
|
||||
#define ubi_dbg_is_bitflip() 0
|
||||
#define ubi_dbg_is_write_failure() 0
|
||||
#define ubi_dbg_is_erase_failure() 0
|
||||
|
@ -91,7 +91,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include "ubi.h"
|
||||
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG
|
||||
static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum);
|
||||
static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum);
|
||||
static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
|
||||
@ -146,6 +146,28 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/*
|
||||
* Deliberately corrupt the buffer to improve robustness. Indeed, if we
|
||||
* do not do this, the following may happen:
|
||||
* 1. The buffer contains data from previous operation, e.g., read from
|
||||
* another PEB previously. The data looks like expected, e.g., if we
|
||||
* just do not read anything and return - the caller would not
|
||||
* notice this. E.g., if we are reading a VID header, the buffer may
|
||||
* contain a valid VID header from another PEB.
|
||||
* 2. The driver is buggy and returns us success or -EBADMSG or
|
||||
* -EUCLEAN, but it does not actually put any data to the buffer.
|
||||
*
|
||||
* This may confuse UBI or upper layers - they may think the buffer
|
||||
* contains valid data while in fact it is just old data. This is
|
||||
* especially possible because UBI (and UBIFS) relies on CRC, and
|
||||
* treats data as correct even in case of ECC errors if the CRC is
|
||||
* correct.
|
||||
*
|
||||
* Try to prevent this situation by changing the first byte of the
|
||||
* buffer.
|
||||
*/
|
||||
*((uint8_t *)buf) ^= 0xFF;
|
||||
|
||||
addr = (loff_t)pnum * ubi->peb_size + offset;
|
||||
retry:
|
||||
err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);
|
||||
@ -166,7 +188,7 @@ retry:
|
||||
return UBI_IO_BITFLIPS;
|
||||
}
|
||||
|
||||
if (read != len && retries++ < UBI_IO_RETRIES) {
|
||||
if (retries++ < UBI_IO_RETRIES) {
|
||||
dbg_io("error %d%s while reading %d bytes from PEB %d:%d,"
|
||||
" read only %zd bytes, retry",
|
||||
err, errstr, len, pnum, offset, read);
|
||||
@ -480,6 +502,13 @@ static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
|
||||
size_t written;
|
||||
loff_t addr;
|
||||
uint32_t data = 0;
|
||||
/*
|
||||
* Note, we cannot generally define VID header buffers on stack,
|
||||
* because of the way we deal with these buffers (see the header
|
||||
* comment in this file). But we know this is a NOR-specific piece of
|
||||
* code, so we can do this. But yes, this is error-prone and we should
|
||||
* (pre-)allocate VID header buffer instead.
|
||||
*/
|
||||
struct ubi_vid_hdr vid_hdr;
|
||||
|
||||
/*
|
||||
@ -507,11 +536,13 @@ static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
|
||||
* PEB.
|
||||
*/
|
||||
err1 = ubi_io_read_vid_hdr(ubi, pnum, &vid_hdr, 0);
|
||||
if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR) {
|
||||
if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR ||
|
||||
err1 == UBI_IO_FF) {
|
||||
struct ubi_ec_hdr ec_hdr;
|
||||
|
||||
err1 = ubi_io_read_ec_hdr(ubi, pnum, &ec_hdr, 0);
|
||||
if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR)
|
||||
if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR ||
|
||||
err1 == UBI_IO_FF)
|
||||
/*
|
||||
* Both VID and EC headers are corrupted, so we can
|
||||
* safely erase this PEB and not afraid that it will be
|
||||
@ -752,9 +783,8 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
|
||||
if (verbose)
|
||||
ubi_warn("no EC header found at PEB %d, "
|
||||
"only 0xFF bytes", pnum);
|
||||
else if (UBI_IO_DEBUG)
|
||||
dbg_msg("no EC header found at PEB %d, "
|
||||
"only 0xFF bytes", pnum);
|
||||
dbg_bld("no EC header found at PEB %d, "
|
||||
"only 0xFF bytes", pnum);
|
||||
if (!read_err)
|
||||
return UBI_IO_FF;
|
||||
else
|
||||
@ -769,9 +799,9 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
|
||||
ubi_warn("bad magic number at PEB %d: %08x instead of "
|
||||
"%08x", pnum, magic, UBI_EC_HDR_MAGIC);
|
||||
ubi_dbg_dump_ec_hdr(ec_hdr);
|
||||
} else if (UBI_IO_DEBUG)
|
||||
dbg_msg("bad magic number at PEB %d: %08x instead of "
|
||||
"%08x", pnum, magic, UBI_EC_HDR_MAGIC);
|
||||
}
|
||||
dbg_bld("bad magic number at PEB %d: %08x instead of "
|
||||
"%08x", pnum, magic, UBI_EC_HDR_MAGIC);
|
||||
return UBI_IO_BAD_HDR;
|
||||
}
|
||||
|
||||
@ -783,9 +813,9 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
|
||||
ubi_warn("bad EC header CRC at PEB %d, calculated "
|
||||
"%#08x, read %#08x", pnum, crc, hdr_crc);
|
||||
ubi_dbg_dump_ec_hdr(ec_hdr);
|
||||
} else if (UBI_IO_DEBUG)
|
||||
dbg_msg("bad EC header CRC at PEB %d, calculated "
|
||||
"%#08x, read %#08x", pnum, crc, hdr_crc);
|
||||
}
|
||||
dbg_bld("bad EC header CRC at PEB %d, calculated "
|
||||
"%#08x, read %#08x", pnum, crc, hdr_crc);
|
||||
|
||||
if (!read_err)
|
||||
return UBI_IO_BAD_HDR;
|
||||
@ -1008,9 +1038,8 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
|
||||
if (verbose)
|
||||
ubi_warn("no VID header found at PEB %d, "
|
||||
"only 0xFF bytes", pnum);
|
||||
else if (UBI_IO_DEBUG)
|
||||
dbg_msg("no VID header found at PEB %d, "
|
||||
"only 0xFF bytes", pnum);
|
||||
dbg_bld("no VID header found at PEB %d, "
|
||||
"only 0xFF bytes", pnum);
|
||||
if (!read_err)
|
||||
return UBI_IO_FF;
|
||||
else
|
||||
@ -1021,9 +1050,9 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
|
||||
ubi_warn("bad magic number at PEB %d: %08x instead of "
|
||||
"%08x", pnum, magic, UBI_VID_HDR_MAGIC);
|
||||
ubi_dbg_dump_vid_hdr(vid_hdr);
|
||||
} else if (UBI_IO_DEBUG)
|
||||
dbg_msg("bad magic number at PEB %d: %08x instead of "
|
||||
"%08x", pnum, magic, UBI_VID_HDR_MAGIC);
|
||||
}
|
||||
dbg_bld("bad magic number at PEB %d: %08x instead of "
|
||||
"%08x", pnum, magic, UBI_VID_HDR_MAGIC);
|
||||
return UBI_IO_BAD_HDR;
|
||||
}
|
||||
|
||||
@ -1035,9 +1064,9 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
|
||||
ubi_warn("bad CRC at PEB %d, calculated %#08x, "
|
||||
"read %#08x", pnum, crc, hdr_crc);
|
||||
ubi_dbg_dump_vid_hdr(vid_hdr);
|
||||
} else if (UBI_IO_DEBUG)
|
||||
dbg_msg("bad CRC at PEB %d, calculated %#08x, "
|
||||
"read %#08x", pnum, crc, hdr_crc);
|
||||
}
|
||||
dbg_bld("bad CRC at PEB %d, calculated %#08x, "
|
||||
"read %#08x", pnum, crc, hdr_crc);
|
||||
if (!read_err)
|
||||
return UBI_IO_BAD_HDR;
|
||||
else
|
||||
@ -1097,7 +1126,7 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG
|
||||
|
||||
/**
|
||||
* paranoid_check_not_bad - ensure that a physical eraseblock is not bad.
|
||||
@ -1111,6 +1140,9 @@ static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!(ubi_chk_flags & UBI_CHK_IO))
|
||||
return 0;
|
||||
|
||||
err = ubi_io_is_bad(ubi, pnum);
|
||||
if (!err)
|
||||
return err;
|
||||
@ -1135,6 +1167,9 @@ static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
|
||||
int err;
|
||||
uint32_t magic;
|
||||
|
||||
if (!(ubi_chk_flags & UBI_CHK_IO))
|
||||
return 0;
|
||||
|
||||
magic = be32_to_cpu(ec_hdr->magic);
|
||||
if (magic != UBI_EC_HDR_MAGIC) {
|
||||
ubi_err("bad magic %#08x, must be %#08x",
|
||||
@ -1170,6 +1205,9 @@ static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum)
|
||||
uint32_t crc, hdr_crc;
|
||||
struct ubi_ec_hdr *ec_hdr;
|
||||
|
||||
if (!(ubi_chk_flags & UBI_CHK_IO))
|
||||
return 0;
|
||||
|
||||
ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
|
||||
if (!ec_hdr)
|
||||
return -ENOMEM;
|
||||
@ -1211,6 +1249,9 @@ static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum,
|
||||
int err;
|
||||
uint32_t magic;
|
||||
|
||||
if (!(ubi_chk_flags & UBI_CHK_IO))
|
||||
return 0;
|
||||
|
||||
magic = be32_to_cpu(vid_hdr->magic);
|
||||
if (magic != UBI_VID_HDR_MAGIC) {
|
||||
ubi_err("bad VID header magic %#08x at PEB %d, must be %#08x",
|
||||
@ -1249,6 +1290,9 @@ static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
|
||||
struct ubi_vid_hdr *vid_hdr;
|
||||
void *p;
|
||||
|
||||
if (!(ubi_chk_flags & UBI_CHK_IO))
|
||||
return 0;
|
||||
|
||||
vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
|
||||
if (!vid_hdr)
|
||||
return -ENOMEM;
|
||||
@ -1294,15 +1338,26 @@ int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum,
|
||||
int offset, int len)
|
||||
{
|
||||
int err, i;
|
||||
size_t read;
|
||||
void *buf1;
|
||||
loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
|
||||
|
||||
mutex_lock(&ubi->dbg_buf_mutex);
|
||||
err = ubi_io_read(ubi, ubi->dbg_peb_buf, pnum, offset, len);
|
||||
if (err)
|
||||
goto out_unlock;
|
||||
if (!(ubi_chk_flags & UBI_CHK_IO))
|
||||
return 0;
|
||||
|
||||
buf1 = __vmalloc(len, GFP_KERNEL | GFP_NOFS, PAGE_KERNEL);
|
||||
if (!buf1) {
|
||||
ubi_err("cannot allocate memory to check writes");
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf1);
|
||||
if (err && err != -EUCLEAN)
|
||||
goto out_free;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
uint8_t c = ((uint8_t *)buf)[i];
|
||||
uint8_t c1 = ((uint8_t *)ubi->dbg_peb_buf)[i];
|
||||
uint8_t c1 = ((uint8_t *)buf1)[i];
|
||||
int dump_len;
|
||||
|
||||
if (c == c1)
|
||||
@ -1319,17 +1374,17 @@ int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum,
|
||||
ubi_msg("hex dump of the read buffer from %d to %d",
|
||||
i, i + dump_len);
|
||||
print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
|
||||
ubi->dbg_peb_buf + i, dump_len, 1);
|
||||
buf1 + i, dump_len, 1);
|
||||
ubi_dbg_dump_stack();
|
||||
err = -EINVAL;
|
||||
goto out_unlock;
|
||||
goto out_free;
|
||||
}
|
||||
mutex_unlock(&ubi->dbg_buf_mutex);
|
||||
|
||||
vfree(buf1);
|
||||
return 0;
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&ubi->dbg_buf_mutex);
|
||||
out_free:
|
||||
vfree(buf1);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -1348,36 +1403,44 @@ int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len)
|
||||
{
|
||||
size_t read;
|
||||
int err;
|
||||
void *buf;
|
||||
loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
|
||||
|
||||
mutex_lock(&ubi->dbg_buf_mutex);
|
||||
err = ubi->mtd->read(ubi->mtd, addr, len, &read, ubi->dbg_peb_buf);
|
||||
if (!(ubi_chk_flags & UBI_CHK_IO))
|
||||
return 0;
|
||||
|
||||
buf = __vmalloc(len, GFP_KERNEL | GFP_NOFS, PAGE_KERNEL);
|
||||
if (!buf) {
|
||||
ubi_err("cannot allocate memory to check for 0xFFs");
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);
|
||||
if (err && err != -EUCLEAN) {
|
||||
ubi_err("error %d while reading %d bytes from PEB %d:%d, "
|
||||
"read %zd bytes", err, len, pnum, offset, read);
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = ubi_check_pattern(ubi->dbg_peb_buf, 0xFF, len);
|
||||
err = ubi_check_pattern(buf, 0xFF, len);
|
||||
if (err == 0) {
|
||||
ubi_err("flash region at PEB %d:%d, length %d does not "
|
||||
"contain all 0xFF bytes", pnum, offset, len);
|
||||
goto fail;
|
||||
}
|
||||
mutex_unlock(&ubi->dbg_buf_mutex);
|
||||
|
||||
vfree(buf);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
ubi_err("paranoid check failed for PEB %d", pnum);
|
||||
ubi_msg("hex dump of the %d-%d region", offset, offset + len);
|
||||
print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
|
||||
ubi->dbg_peb_buf, len, 1);
|
||||
print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1);
|
||||
err = -EINVAL;
|
||||
error:
|
||||
ubi_dbg_dump_stack();
|
||||
mutex_unlock(&ubi->dbg_buf_mutex);
|
||||
vfree(buf);
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */
|
||||
#endif /* CONFIG_MTD_UBI_DEBUG */
|
||||
|
@ -39,32 +39,46 @@
|
||||
* eraseblocks are put to the @free list and the physical eraseblock to be
|
||||
* erased are put to the @erase list.
|
||||
*
|
||||
* About corruptions
|
||||
* ~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* UBI protects EC and VID headers with CRC-32 checksums, so it can detect
|
||||
* whether the headers are corrupted or not. Sometimes UBI also protects the
|
||||
* data with CRC-32, e.g., when it executes the atomic LEB change operation, or
|
||||
* when it moves the contents of a PEB for wear-leveling purposes.
|
||||
*
|
||||
* UBI tries to distinguish between 2 types of corruptions.
|
||||
* 1. Corruptions caused by power cuts. These are harmless and expected
|
||||
* corruptions and UBI tries to handle them gracefully, without printing too
|
||||
* many warnings and error messages. The idea is that we do not lose
|
||||
* important data in these case - we may lose only the data which was being
|
||||
* written to the media just before the power cut happened, and the upper
|
||||
* layers (e.g., UBIFS) are supposed to handle these situations. UBI puts
|
||||
* these PEBs to the head of the @erase list and they are scheduled for
|
||||
* erasure.
|
||||
*
|
||||
* 1. Corruptions caused by power cuts. These are expected corruptions and UBI
|
||||
* tries to handle them gracefully, without printing too many warnings and
|
||||
* error messages. The idea is that we do not lose important data in these case
|
||||
* - we may lose only the data which was being written to the media just before
|
||||
* the power cut happened, and the upper layers (e.g., UBIFS) are supposed to
|
||||
* handle such data losses (e.g., by using the FS journal).
|
||||
*
|
||||
* When UBI detects a corruption (CRC-32 mismatch) in a PEB, and it looks like
|
||||
* the reason is a power cut, UBI puts this PEB to the @erase list, and all
|
||||
* PEBs in the @erase list are scheduled for erasure later.
|
||||
*
|
||||
* 2. Unexpected corruptions which are not caused by power cuts. During
|
||||
* scanning, such PEBs are put to the @corr list and UBI preserves them.
|
||||
* Obviously, this lessens the amount of available PEBs, and if at some
|
||||
* point UBI runs out of free PEBs, it switches to R/O mode. UBI also loudly
|
||||
* informs about such PEBs every time the MTD device is attached.
|
||||
* scanning, such PEBs are put to the @corr list and UBI preserves them.
|
||||
* Obviously, this lessens the amount of available PEBs, and if at some point
|
||||
* UBI runs out of free PEBs, it switches to R/O mode. UBI also loudly informs
|
||||
* about such PEBs every time the MTD device is attached.
|
||||
*
|
||||
* However, it is difficult to reliably distinguish between these types of
|
||||
* corruptions and UBI's strategy is as follows. UBI assumes (2.) if the VID
|
||||
* header is corrupted and the data area does not contain all 0xFFs, and there
|
||||
* were not bit-flips or integrity errors while reading the data area. Otherwise
|
||||
* UBI assumes (1.). The assumptions are:
|
||||
* o if the data area contains only 0xFFs, there is no data, and it is safe
|
||||
* to just erase this PEB.
|
||||
* o if the data area has bit-flips and data integrity errors (ECC errors on
|
||||
* corruptions and UBI's strategy is as follows. UBI assumes corruption type 2
|
||||
* if the VID header is corrupted and the data area does not contain all 0xFFs,
|
||||
* and there were no bit-flips or integrity errors while reading the data area.
|
||||
* Otherwise UBI assumes corruption type 1. So the decision criteria are as
|
||||
* follows.
|
||||
* o If the data area contains only 0xFFs, there is no data, and it is safe
|
||||
* to just erase this PEB - this is corruption type 1.
|
||||
* o If the data area has bit-flips or data integrity errors (ECC errors on
|
||||
* NAND), it is probably a PEB which was being erased when power cut
|
||||
* happened.
|
||||
* happened, so this is corruption type 1. However, this is just a guess,
|
||||
* which might be wrong.
|
||||
* o Otherwise this it corruption type 2.
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
@ -74,7 +88,7 @@
|
||||
#include <linux/random.h>
|
||||
#include "ubi.h"
|
||||
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG
|
||||
static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si);
|
||||
#else
|
||||
#define paranoid_check_si(ubi, si) 0
|
||||
@ -115,7 +129,7 @@ static int add_to_list(struct ubi_scan_info *si, int pnum, int ec, int to_head,
|
||||
} else
|
||||
BUG();
|
||||
|
||||
seb = kmalloc(sizeof(struct ubi_scan_leb), GFP_KERNEL);
|
||||
seb = kmem_cache_alloc(si->scan_leb_slab, GFP_KERNEL);
|
||||
if (!seb)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -144,7 +158,7 @@ static int add_corrupted(struct ubi_scan_info *si, int pnum, int ec)
|
||||
|
||||
dbg_bld("add to corrupted: PEB %d, EC %d", pnum, ec);
|
||||
|
||||
seb = kmalloc(sizeof(struct ubi_scan_leb), GFP_KERNEL);
|
||||
seb = kmem_cache_alloc(si->scan_leb_slab, GFP_KERNEL);
|
||||
if (!seb)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -553,7 +567,7 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
seb = kmalloc(sizeof(struct ubi_scan_leb), GFP_KERNEL);
|
||||
seb = kmem_cache_alloc(si->scan_leb_slab, GFP_KERNEL);
|
||||
if (!seb)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -1152,9 +1166,15 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
|
||||
si->volumes = RB_ROOT;
|
||||
|
||||
err = -ENOMEM;
|
||||
si->scan_leb_slab = kmem_cache_create("ubi_scan_leb_slab",
|
||||
sizeof(struct ubi_scan_leb),
|
||||
0, 0, NULL);
|
||||
if (!si->scan_leb_slab)
|
||||
goto out_si;
|
||||
|
||||
ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
|
||||
if (!ech)
|
||||
goto out_si;
|
||||
goto out_slab;
|
||||
|
||||
vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
|
||||
if (!vidh)
|
||||
@ -1215,6 +1235,8 @@ out_vidh:
|
||||
ubi_free_vid_hdr(ubi, vidh);
|
||||
out_ech:
|
||||
kfree(ech);
|
||||
out_slab:
|
||||
kmem_cache_destroy(si->scan_leb_slab);
|
||||
out_si:
|
||||
ubi_scan_destroy_si(si);
|
||||
return ERR_PTR(err);
|
||||
@ -1223,11 +1245,12 @@ out_si:
|
||||
/**
|
||||
* destroy_sv - free the scanning volume information
|
||||
* @sv: scanning volume information
|
||||
* @si: scanning information
|
||||
*
|
||||
* This function destroys the volume RB-tree (@sv->root) and the scanning
|
||||
* volume information.
|
||||
*/
|
||||
static void destroy_sv(struct ubi_scan_volume *sv)
|
||||
static void destroy_sv(struct ubi_scan_info *si, struct ubi_scan_volume *sv)
|
||||
{
|
||||
struct ubi_scan_leb *seb;
|
||||
struct rb_node *this = sv->root.rb_node;
|
||||
@ -1247,7 +1270,7 @@ static void destroy_sv(struct ubi_scan_volume *sv)
|
||||
this->rb_right = NULL;
|
||||
}
|
||||
|
||||
kfree(seb);
|
||||
kmem_cache_free(si->scan_leb_slab, seb);
|
||||
}
|
||||
}
|
||||
kfree(sv);
|
||||
@ -1265,19 +1288,19 @@ void ubi_scan_destroy_si(struct ubi_scan_info *si)
|
||||
|
||||
list_for_each_entry_safe(seb, seb_tmp, &si->alien, u.list) {
|
||||
list_del(&seb->u.list);
|
||||
kfree(seb);
|
||||
kmem_cache_free(si->scan_leb_slab, seb);
|
||||
}
|
||||
list_for_each_entry_safe(seb, seb_tmp, &si->erase, u.list) {
|
||||
list_del(&seb->u.list);
|
||||
kfree(seb);
|
||||
kmem_cache_free(si->scan_leb_slab, seb);
|
||||
}
|
||||
list_for_each_entry_safe(seb, seb_tmp, &si->corr, u.list) {
|
||||
list_del(&seb->u.list);
|
||||
kfree(seb);
|
||||
kmem_cache_free(si->scan_leb_slab, seb);
|
||||
}
|
||||
list_for_each_entry_safe(seb, seb_tmp, &si->free, u.list) {
|
||||
list_del(&seb->u.list);
|
||||
kfree(seb);
|
||||
kmem_cache_free(si->scan_leb_slab, seb);
|
||||
}
|
||||
|
||||
/* Destroy the volume RB-tree */
|
||||
@ -1298,14 +1321,15 @@ void ubi_scan_destroy_si(struct ubi_scan_info *si)
|
||||
rb->rb_right = NULL;
|
||||
}
|
||||
|
||||
destroy_sv(sv);
|
||||
destroy_sv(si, sv);
|
||||
}
|
||||
}
|
||||
|
||||
kmem_cache_destroy(si->scan_leb_slab);
|
||||
kfree(si);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG
|
||||
|
||||
/**
|
||||
* paranoid_check_si - check the scanning information.
|
||||
@ -1323,6 +1347,9 @@ static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si)
|
||||
struct ubi_scan_leb *seb, *last_seb;
|
||||
uint8_t *buf;
|
||||
|
||||
if (!(ubi_chk_flags & UBI_CHK_GEN))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* At first, check that scanning information is OK.
|
||||
*/
|
||||
@ -1575,4 +1602,4 @@ out:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */
|
||||
#endif /* CONFIG_MTD_UBI_DEBUG */
|
||||
|
@ -109,6 +109,7 @@ struct ubi_scan_volume {
|
||||
* @mean_ec: mean erase counter value
|
||||
* @ec_sum: a temporary variable used when calculating @mean_ec
|
||||
* @ec_count: a temporary variable used when calculating @mean_ec
|
||||
* @scan_leb_slab: slab cache for &struct ubi_scan_leb objects
|
||||
*
|
||||
* This data structure contains the result of scanning and may be used by other
|
||||
* UBI sub-systems to build final UBI data structures, further error-recovery
|
||||
@ -134,6 +135,7 @@ struct ubi_scan_info {
|
||||
int mean_ec;
|
||||
uint64_t ec_sum;
|
||||
int ec_count;
|
||||
struct kmem_cache *scan_leb_slab;
|
||||
};
|
||||
|
||||
struct ubi_device;
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/ubi.h>
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
#include "ubi-media.h"
|
||||
#include "scan.h"
|
||||
@ -387,8 +388,6 @@ struct ubi_wl_entry;
|
||||
* @peb_buf2: another buffer of PEB size used for different purposes
|
||||
* @buf_mutex: protects @peb_buf1 and @peb_buf2
|
||||
* @ckvol_mutex: serializes static volume checking when opening
|
||||
* @dbg_peb_buf: buffer of PEB size used for debugging
|
||||
* @dbg_buf_mutex: protects @dbg_peb_buf
|
||||
*/
|
||||
struct ubi_device {
|
||||
struct cdev cdev;
|
||||
@ -470,10 +469,6 @@ struct ubi_device {
|
||||
void *peb_buf2;
|
||||
struct mutex buf_mutex;
|
||||
struct mutex ckvol_mutex;
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
|
||||
void *dbg_peb_buf;
|
||||
struct mutex dbg_buf_mutex;
|
||||
#endif
|
||||
};
|
||||
|
||||
extern struct kmem_cache *ubi_wl_entry_slab;
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include "ubi.h"
|
||||
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG
|
||||
static int paranoid_check_volumes(struct ubi_device *ubi);
|
||||
#else
|
||||
#define paranoid_check_volumes(ubi) 0
|
||||
@ -711,7 +711,7 @@ void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol)
|
||||
volume_sysfs_close(vol);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG
|
||||
|
||||
/**
|
||||
* paranoid_check_volume - check volume information.
|
||||
@ -876,6 +876,9 @@ static int paranoid_check_volumes(struct ubi_device *ubi)
|
||||
{
|
||||
int i, err = 0;
|
||||
|
||||
if (!(ubi_chk_flags & UBI_CHK_GEN))
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < ubi->vtbl_slots; i++) {
|
||||
err = paranoid_check_volume(ubi, i);
|
||||
if (err)
|
||||
|
@ -62,7 +62,7 @@
|
||||
#include <asm/div64.h>
|
||||
#include "ubi.h"
|
||||
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG
|
||||
static void paranoid_vtbl_check(const struct ubi_device *ubi);
|
||||
#else
|
||||
#define paranoid_vtbl_check(ubi)
|
||||
@ -868,7 +868,7 @@ out_free:
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG
|
||||
|
||||
/**
|
||||
* paranoid_vtbl_check - check volume table.
|
||||
@ -876,10 +876,13 @@ out_free:
|
||||
*/
|
||||
static void paranoid_vtbl_check(const struct ubi_device *ubi)
|
||||
{
|
||||
if (!(ubi_chk_flags & UBI_CHK_GEN))
|
||||
return;
|
||||
|
||||
if (vtbl_check(ubi, ubi->vtbl)) {
|
||||
ubi_err("paranoid check failed");
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */
|
||||
#endif /* CONFIG_MTD_UBI_DEBUG */
|
||||
|
@ -161,7 +161,7 @@ struct ubi_work {
|
||||
int torture;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG
|
||||
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,
|
||||
struct rb_root *root);
|
||||
@ -613,7 +613,7 @@ static void schedule_ubi_work(struct ubi_device *ubi, struct ubi_work *wrk)
|
||||
list_add_tail(&wrk->list, &ubi->works);
|
||||
ubi_assert(ubi->works_count >= 0);
|
||||
ubi->works_count += 1;
|
||||
if (ubi->thread_enabled)
|
||||
if (ubi->thread_enabled && !ubi_dbg_is_bgt_disabled())
|
||||
wake_up_process(ubi->bgt_thread);
|
||||
spin_unlock(&ubi->wl_lock);
|
||||
}
|
||||
@ -1364,7 +1364,7 @@ int ubi_thread(void *u)
|
||||
|
||||
spin_lock(&ubi->wl_lock);
|
||||
if (list_empty(&ubi->works) || ubi->ro_mode ||
|
||||
!ubi->thread_enabled) {
|
||||
!ubi->thread_enabled || ubi_dbg_is_bgt_disabled()) {
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
spin_unlock(&ubi->wl_lock);
|
||||
schedule();
|
||||
@ -1561,7 +1561,7 @@ void ubi_wl_close(struct ubi_device *ubi)
|
||||
kfree(ubi->lookuptbl);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG
|
||||
|
||||
/**
|
||||
* paranoid_check_ec - make sure that the erase counter of a PEB is correct.
|
||||
@ -1578,6 +1578,9 @@ static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec)
|
||||
long long read_ec;
|
||||
struct ubi_ec_hdr *ec_hdr;
|
||||
|
||||
if (!(ubi_chk_flags & UBI_CHK_GEN))
|
||||
return 0;
|
||||
|
||||
ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
|
||||
if (!ec_hdr)
|
||||
return -ENOMEM;
|
||||
@ -1614,6 +1617,9 @@ out_free:
|
||||
static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e,
|
||||
struct rb_root *root)
|
||||
{
|
||||
if (!(ubi_chk_flags & UBI_CHK_GEN))
|
||||
return 0;
|
||||
|
||||
if (in_wl_tree(e, root))
|
||||
return 0;
|
||||
|
||||
@ -1636,6 +1642,9 @@ static int paranoid_check_in_pq(struct ubi_device *ubi, struct ubi_wl_entry *e)
|
||||
struct ubi_wl_entry *p;
|
||||
int i;
|
||||
|
||||
if (!(ubi_chk_flags & UBI_CHK_GEN))
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < UBI_PROT_QUEUE_LEN; ++i)
|
||||
list_for_each_entry(p, &ubi->pq[i], u.list)
|
||||
if (p == e)
|
||||
@ -1646,4 +1655,5 @@ static int paranoid_check_in_pq(struct ubi_device *ubi, struct ubi_wl_entry *e)
|
||||
ubi_dbg_dump_stack();
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */
|
||||
|
||||
#endif /* CONFIG_MTD_UBI_DEBUG */
|
||||
|
Loading…
x
Reference in New Issue
Block a user