Commit fd57ed02 authored by Linus Torvalds's avatar Linus Torvalds

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
parents ca749e2a 28237e45
...@@ -52,6 +52,12 @@ config MTD_UBI_GLUEBI ...@@ -52,6 +52,12 @@ config MTD_UBI_GLUEBI
work on top of UBI. Do not enable this unless you use legacy work on top of UBI. Do not enable this unless you use legacy
software. 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 endif # MTD_UBI
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) ...@@ -711,7 +711,7 @@ static int io_init(struct ubi_device *ubi)
} }
/* Similar for the data offset */ /* 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); ubi->leb_start = ALIGN(ubi->leb_start, ubi->min_io_size);
dbg_msg("vid_hdr_offset %d", ubi->vid_hdr_offset); 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) ...@@ -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); spin_lock_init(&ubi->volumes_lock);
ubi_msg("attaching mtd%d to ubi%d", mtd->index, ubi_num); 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); err = io_init(ubi);
if (err) if (err)
...@@ -937,13 +939,6 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) ...@@ -937,13 +939,6 @@ 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;
#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); 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);
...@@ -991,8 +986,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) ...@@ -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. * checks @ubi->thread_enabled. Otherwise we may fail to wake it up.
*/ */
spin_lock(&ubi->wl_lock); spin_lock(&ubi->wl_lock);
if (!DBG_DISABLE_BGT) ubi->thread_enabled = 1;
ubi->thread_enabled = 1;
wake_up_process(ubi->bgt_thread); wake_up_process(ubi->bgt_thread);
spin_unlock(&ubi->wl_lock); spin_unlock(&ubi->wl_lock);
...@@ -1009,9 +1003,6 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) ...@@ -1009,9 +1003,6 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
out_free: out_free:
vfree(ubi->peb_buf1); vfree(ubi->peb_buf1);
vfree(ubi->peb_buf2); vfree(ubi->peb_buf2);
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
vfree(ubi->dbg_peb_buf);
#endif
if (ref) if (ref)
put_device(&ubi->dev); put_device(&ubi->dev);
else else
...@@ -1082,9 +1073,6 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway) ...@@ -1082,9 +1073,6 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
put_mtd_device(ubi->mtd); put_mtd_device(ubi->mtd);
vfree(ubi->peb_buf1); vfree(ubi->peb_buf1);
vfree(ubi->peb_buf2); 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); ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num);
put_device(&ubi->dev); put_device(&ubi->dev);
return 0; return 0;
......
...@@ -27,6 +27,20 @@ ...@@ -27,6 +27,20 @@
#ifdef CONFIG_MTD_UBI_DEBUG #ifdef CONFIG_MTD_UBI_DEBUG
#include "ubi.h" #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. * ubi_dbg_dump_ec_hdr - dump an erase counter header.
......
...@@ -38,6 +38,11 @@ ...@@ -38,6 +38,11 @@
printk(KERN_DEBUG "UBI DBG (pid %d): %s: " fmt "\n", \ printk(KERN_DEBUG "UBI DBG (pid %d): %s: " fmt "\n", \
current->pid, __func__, ##__VA_ARGS__) 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() #define ubi_dbg_dump_stack() dump_stack()
struct ubi_ec_hdr; struct ubi_ec_hdr;
...@@ -57,62 +62,88 @@ void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type); ...@@ -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_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_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) \ #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) print_hex_dump(l, ps, pt, r, g, b, len, a)
#ifdef CONFIG_MTD_UBI_DEBUG_MSG
/* General debugging messages */ /* General debugging messages */
#define dbg_gen(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) #define dbg_gen(fmt, ...) dbg_do_msg(UBI_MSG_GEN, fmt, ##__VA_ARGS__)
#else
#define dbg_gen(fmt, ...) ({})
#endif
#ifdef CONFIG_MTD_UBI_DEBUG_MSG_EBA
/* Messages from the eraseblock association sub-system */ /* Messages from the eraseblock association sub-system */
#define dbg_eba(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) #define dbg_eba(fmt, ...) dbg_do_msg(UBI_MSG_EBA, fmt, ##__VA_ARGS__)
#else
#define dbg_eba(fmt, ...) ({})
#endif
#ifdef CONFIG_MTD_UBI_DEBUG_MSG_WL
/* Messages from the wear-leveling sub-system */ /* Messages from the wear-leveling sub-system */
#define dbg_wl(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) #define dbg_wl(fmt, ...) dbg_do_msg(UBI_MSG_WL, fmt, ##__VA_ARGS__)
#else
#define dbg_wl(fmt, ...) ({})
#endif
#ifdef CONFIG_MTD_UBI_DEBUG_MSG_IO
/* Messages from the input/output sub-system */ /* Messages from the input/output sub-system */
#define dbg_io(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) #define dbg_io(fmt, ...) dbg_do_msg(UBI_MSG_IO, fmt, ##__VA_ARGS__)
#else
#define dbg_io(fmt, ...) ({})
#endif
#ifdef CONFIG_MTD_UBI_DEBUG_MSG_BLD
/* Initialization and build messages */ /* Initialization and build messages */
#define dbg_bld(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) #define dbg_bld(fmt, ...) dbg_do_msg(UBI_MSG_BLD, fmt, ##__VA_ARGS__)
#define UBI_IO_DEBUG 1
#else extern unsigned int ubi_chk_flags;
#define dbg_bld(fmt, ...) ({})
#define UBI_IO_DEBUG 0 /*
#endif * 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_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);
#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 extern unsigned int ubi_tst_flags;
#define DBG_DISABLE_BGT 1
#else /*
#define DBG_DISABLE_BGT 0 * Special testing flags.
#endif *
* 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. * 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, ...@@ -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) 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. * 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) ...@@ -135,13 +164,11 @@ static inline int ubi_dbg_is_bitflip(void)
*/ */
static inline int ubi_dbg_is_write_failure(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. * 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) ...@@ -150,11 +177,10 @@ static inline int ubi_dbg_is_write_failure(void)
*/ */
static inline int ubi_dbg_is_erase_failure(void) static inline int ubi_dbg_is_erase_failure(void)
{ {
if (ubi_tst_flags & UBI_TST_EMULATE_ERASE_FAILURES)
return !(random32() % 400); return !(random32() % 400);
return 0;
} }
#else
#define ubi_dbg_is_erase_failure() 0
#endif
#else #else
...@@ -177,8 +203,7 @@ static inline int ubi_dbg_is_erase_failure(void) ...@@ -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_dump_flash(ubi, pnum, offset, len) ({})
#define ubi_dbg_print_hex_dump(l, ps, pt, r, g, b, len, a) ({}) #define ubi_dbg_print_hex_dump(l, ps, pt, r, g, b, len, a) ({})
#define UBI_IO_DEBUG 0 #define ubi_dbg_is_bgt_disabled() 0
#define DBG_DISABLE_BGT 0
#define ubi_dbg_is_bitflip() 0 #define ubi_dbg_is_bitflip() 0
#define ubi_dbg_is_write_failure() 0 #define ubi_dbg_is_write_failure() 0
#define ubi_dbg_is_erase_failure() 0 #define ubi_dbg_is_erase_failure() 0
......
...@@ -91,7 +91,7 @@ ...@@ -91,7 +91,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include "ubi.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_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_peb_ec_hdr(const struct ubi_device *ubi, int pnum);
static int paranoid_check_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, ...@@ -146,6 +146,28 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
if (err) if (err)
return 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; addr = (loff_t)pnum * ubi->peb_size + offset;
retry: retry:
err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf); err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);
...@@ -166,7 +188,7 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset, ...@@ -166,7 +188,7 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
return UBI_IO_BITFLIPS; 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," dbg_io("error %d%s while reading %d bytes from PEB %d:%d,"
" read only %zd bytes, retry", " read only %zd bytes, retry",
err, errstr, len, pnum, offset, read); err, errstr, len, pnum, offset, read);
...@@ -480,6 +502,13 @@ static int nor_erase_prepare(struct ubi_device *ubi, int pnum) ...@@ -480,6 +502,13 @@ static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
size_t written; size_t written;
loff_t addr; loff_t addr;
uint32_t data = 0; 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; struct ubi_vid_hdr vid_hdr;
/* /*
...@@ -507,11 +536,13 @@ static int nor_erase_prepare(struct ubi_device *ubi, int pnum) ...@@ -507,11 +536,13 @@ static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
* PEB. * PEB.
*/ */
err1 = ubi_io_read_vid_hdr(ubi, pnum, &vid_hdr, 0); 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; struct ubi_ec_hdr ec_hdr;
err1 = ubi_io_read_ec_hdr(ubi, pnum, &ec_hdr, 0); 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 * Both VID and EC headers are corrupted, so we can
* safely erase this PEB and not afraid that it will be * 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, ...@@ -752,9 +783,8 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
if (verbose) if (verbose)
ubi_warn("no EC header found at PEB %d, " ubi_warn("no EC header found at PEB %d, "
"only 0xFF bytes", pnum); "only 0xFF bytes", pnum);
else if (UBI_IO_DEBUG) dbg_bld("no EC header found at PEB %d, "
dbg_msg("no EC header found at PEB %d, " "only 0xFF bytes", pnum);
"only 0xFF bytes", pnum);
if (!read_err) if (!read_err)
return UBI_IO_FF; return UBI_IO_FF;
else else
...@@ -769,9 +799,9 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, ...@@ -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 " ubi_warn("bad magic number at PEB %d: %08x instead of "
"%08x", pnum, magic, UBI_EC_HDR_MAGIC); "%08x", pnum, magic, UBI_EC_HDR_MAGIC);
ubi_dbg_dump_ec_hdr(ec_hdr); ubi_dbg_dump_ec_hdr(ec_hdr);
} else if (UBI_IO_DEBUG) }
dbg_msg("bad magic number at PEB %d: %08x instead of " dbg_bld("bad magic number at PEB %d: %08x instead of "
"%08x", pnum, magic, UBI_EC_HDR_MAGIC); "%08x", pnum, magic, UBI_EC_HDR_MAGIC);
return UBI_IO_BAD_HDR; return UBI_IO_BAD_HDR;
} }
...@@ -783,9 +813,9 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, ...@@ -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 " ubi_warn("bad EC header CRC at PEB %d, calculated "
"%#08x, read %#08x", pnum, crc, hdr_crc); "%#08x, read %#08x", pnum, crc, hdr_crc);
ubi_dbg_dump_ec_hdr(ec_hdr); ubi_dbg_dump_ec_hdr(ec_hdr);
} else if (UBI_IO_DEBUG) }
dbg_msg("bad EC header CRC at PEB %d, calculated " dbg_bld("bad EC header CRC at PEB %d, calculated "
"%#08x, read %#08x", pnum, crc, hdr_crc); "%#08x, read %#08x", pnum, crc, hdr_crc);
if (!read_err) if (!read_err)
return UBI_IO_BAD_HDR; return UBI_IO_BAD_HDR;
...@@ -1008,9 +1038,8 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, ...@@ -1008,9 +1038,8 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
if (verbose) if (verbose)
ubi_warn("no VID header found at PEB %d, " ubi_warn("no VID header found at PEB %d, "
"only 0xFF bytes", pnum); "only 0xFF bytes", pnum);
else if (UBI_IO_DEBUG) dbg_bld("no VID header found at PEB %d, "
dbg_msg("no VID header found at PEB %d, " "only 0xFF bytes", pnum);
"only 0xFF bytes", pnum);
if (!read_err) if (!read_err)
return UBI_IO_FF; return UBI_IO_FF;
else else
...@@ -1021,9 +1050,9 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, ...@@ -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 " ubi_warn("bad magic number at PEB %d: %08x instead of "
"%08x", pnum, magic, UBI_VID_HDR_MAGIC); "%08x", pnum, magic, UBI_VID_HDR_MAGIC);
ubi_dbg_dump_vid_hdr(vid_hdr); ubi_dbg_dump_vid_hdr(vid_hdr);
} else if (UBI_IO_DEBUG) }
dbg_msg("bad magic number at PEB %d: %08x instead of " dbg_bld("bad magic number at PEB %d: %08x instead of "
"%08x", pnum, magic, UBI_VID_HDR_MAGIC); "%08x", pnum, magic, UBI_VID_HDR_MAGIC);
return UBI_IO_BAD_HDR; return UBI_IO_BAD_HDR;
} }
...@@ -1035,9 +1064,9 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, ...@@ -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, " ubi_warn("bad CRC at PEB %d, calculated %#08x, "
"read %#08x", pnum, crc, hdr_crc); "read %#08x", pnum, crc, hdr_crc);
ubi_dbg_dump_vid_hdr(vid_hdr); ubi_dbg_dump_vid_hdr(vid_hdr);
} else if (UBI_IO_DEBUG) }
dbg_msg("bad CRC at PEB %d, calculated %#08x, " dbg_bld("bad CRC at PEB %d, calculated %#08x, "
"read %#08x", pnum, crc, hdr_crc); "read %#08x", pnum, crc, hdr_crc);
if (!read_err) if (!read_err)
return UBI_IO_BAD_HDR; return UBI_IO_BAD_HDR;
else else
...@@ -1097,7 +1126,7 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum, ...@@ -1097,7 +1126,7 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
return err; 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. * 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) ...@@ -1111,6 +1140,9 @@ static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum)
{ {
int err; int err;
if (!(ubi_chk_flags & UBI_CHK_IO))
return 0;
err = ubi_io_is_bad(ubi, pnum); err = ubi_io_is_bad(ubi, pnum);
if (!err) if (!err)
return err; return err;
...@@ -1135,6 +1167,9 @@ static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum, ...@@ -1135,6 +1167,9 @@ 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))
return 0;
magic = be32_to_cpu(ec_hdr->magic); magic = be32_to_cpu(ec_hdr->magic);
if (magic != UBI_EC_HDR_MAGIC) { if (magic != UBI_EC_HDR_MAGIC) {
ubi_err("bad magic %#08x, must be %#08x", 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) ...@@ -1170,6 +1205,9 @@ 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))
return 0;
ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS); ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
if (!ec_hdr) if (!ec_hdr)
return -ENOMEM; return -ENOMEM;
...@@ -1211,6 +1249,9 @@ static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum, ...@@ -1211,6 +1249,9 @@ 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))
return 0;
magic = be32_to_cpu(vid_hdr->magic); magic = be32_to_cpu(vid_hdr->magic);
if (magic != UBI_VID_HDR_MAGIC) { if (magic != UBI_VID_HDR_MAGIC) {
ubi_err("bad VID header magic %#08x at PEB %d, must be %#08x", 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) ...@@ -1249,6 +1290,9 @@ 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))
return 0;
vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
if (!vid_hdr) if (!vid_hdr)
return -ENOMEM; return -ENOMEM;
...@@ -1294,15 +1338,26 @@ int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum, ...@@ -1294,15 +1338,26 @@ int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum,
int offset, int len) int offset, int len)
{ {
int err, i; int err, i;
size_t read;
void *buf1;
loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
mutex_lock(&ubi->dbg_buf_mutex); if (!(ubi_chk_flags & UBI_CHK_IO))
err = ubi_io_read(ubi, ubi->dbg_peb_buf, pnum, offset, len); return 0;
if (err)
goto out_unlock; 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++) { for (i = 0; i < len; i++) {
uint8_t c = ((uint8_t *)buf)[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; int dump_len;
if (c == c1) if (c == c1)
...@@ -1319,17 +1374,17 @@ int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum, ...@@ -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", ubi_msg("hex dump of the read buffer from %d to %d",
i, i + dump_len); i, i + dump_len);
print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, 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(); ubi_dbg_dump_stack();
err = -EINVAL; err = -EINVAL;
goto out_unlock; goto out_free;
} }
mutex_unlock(&ubi->dbg_buf_mutex);
vfree(buf1);
return 0; return 0;
out_unlock: out_free:
mutex_unlock(&ubi->dbg_buf_mutex); vfree(buf1);
return err; return err;
} }
...@@ -1348,36 +1403,44 @@ int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len) ...@@ -1348,36 +1403,44 @@ int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len)
{ {
size_t read; size_t read;
int err; int err;
void *buf;
loff_t addr = (loff_t)pnum * ubi->peb_size + offset; loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
mutex_lock(&ubi->dbg_buf_mutex); if (!(ubi_chk_flags & UBI_CHK_IO))
err = ubi->mtd->read(ubi->mtd, addr, len, &read, ubi->dbg_peb_buf); 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) { if (err && err != -EUCLEAN) {
ubi_err("error %d while reading %d bytes from PEB %d:%d, " ubi_err("error %d while reading %d bytes from PEB %d:%d, "
"read %zd bytes", err, len, pnum, offset, read); "read %zd bytes", err, len, pnum, offset, read);
goto error; goto error;
} }
err = ubi_check_pattern(ubi->dbg_peb_buf, 0xFF, len); err = ubi_check_pattern(buf, 0xFF, len);
if (err == 0) { if (err == 0) {
ubi_err("flash region at PEB %d:%d, length %d does not " ubi_err("flash region at PEB %d:%d, length %d does not "
"contain all 0xFF bytes", pnum, offset, len); "contain all 0xFF bytes", pnum, offset, len);
goto fail; goto fail;
} }
mutex_unlock(&ubi->dbg_buf_mutex);
vfree(buf);
return 0; return 0;
fail: fail:
ubi_err("paranoid check failed for PEB %d", pnum); ubi_err("paranoid check failed for PEB %d", pnum);
ubi_msg("hex dump of the %d-%d region", offset, offset + len); ubi_msg("hex dump of the %d-%d region", offset, offset + len);
print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1);
ubi->dbg_peb_buf, len, 1);
err = -EINVAL; err = -EINVAL;
error: error:
ubi_dbg_dump_stack(); ubi_dbg_dump_stack();
mutex_unlock(&ubi->dbg_buf_mutex); vfree(buf);
return err; return err;
} }
#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */ #endif /* CONFIG_MTD_UBI_DEBUG */
...@@ -39,32 +39,46 @@ ...@@ -39,32 +39,46 @@
* eraseblocks are put to the @free list and the physical eraseblock to be * eraseblocks are put to the @free list and the physical eraseblock to be
* erased are put to the @erase list. * 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. * 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 * 1. Corruptions caused by power cuts. These are expected corruptions and UBI
* many warnings and error messages. The idea is that we do not lose * tries to handle them gracefully, without printing too many warnings and
* important data in these case - we may lose only the data which was being * error messages. The idea is that we do not lose important data in these case
* written to the media just before the power cut happened, and the upper * - we may lose only the data which was being written to the media just before
* layers (e.g., UBIFS) are supposed to handle these situations. UBI puts * the power cut happened, and the upper layers (e.g., UBIFS) are supposed to
* these PEBs to the head of the @erase list and they are scheduled for * handle such data losses (e.g., by using the FS journal).
* erasure. *
* 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 * 2. Unexpected corruptions which are not caused by power cuts. During
* scanning, such PEBs are put to the @corr list and UBI preserves them. * 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 * Obviously, this lessens the amount of available PEBs, and if at some point
* point UBI runs out of free PEBs, it switches to R/O mode. UBI also loudly * UBI runs out of free PEBs, it switches to R/O mode. UBI also loudly informs
* informs about such PEBs every time the MTD device is attached. * about such PEBs every time the MTD device is attached.
* *
* However, it is difficult to reliably distinguish between these types of * 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 * corruptions and UBI's strategy is as follows. UBI assumes corruption type 2
* header is corrupted and the data area does not contain all 0xFFs, and there * if the VID header is corrupted and the data area does not contain all 0xFFs,
* were not bit-flips or integrity errors while reading the data area. Otherwise * and there were no bit-flips or integrity errors while reading the data area.
* UBI assumes (1.). The assumptions are: * Otherwise UBI assumes corruption type 1. So the decision criteria are as
* o if the data area contains only 0xFFs, there is no data, and it is safe * follows.
* to just erase this PEB. * o If the data area contains only 0xFFs, there is no data, and it is safe
* o if the data area has bit-flips and data integrity errors (ECC errors on * 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 * 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> #include <linux/err.h>
...@@ -74,7 +88,7 @@ ...@@ -74,7 +88,7 @@
#include <linux/random.h> #include <linux/random.h>
#include "ubi.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); static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si);
#else #else
#define paranoid_check_si(ubi, si) 0 #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, ...@@ -115,7 +129,7 @@ static int add_to_list(struct ubi_scan_info *si, int pnum, int ec, int to_head,
} else } else
BUG(); BUG();
seb = kmalloc(sizeof(struct ubi_scan_leb), GFP_KERNEL); seb = kmem_cache_alloc(si->scan_leb_slab, GFP_KERNEL);
if (!seb) if (!seb)
return -ENOMEM; return -ENOMEM;
...@@ -144,7 +158,7 @@ static int add_corrupted(struct ubi_scan_info *si, int pnum, int ec) ...@@ -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); 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) if (!seb)
return -ENOMEM; return -ENOMEM;
...@@ -553,7 +567,7 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si, ...@@ -553,7 +567,7 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
if (err) if (err)
return err; return err;
seb = kmalloc(sizeof(struct ubi_scan_leb), GFP_KERNEL); seb = kmem_cache_alloc(si->scan_leb_slab, GFP_KERNEL);
if (!seb) if (!seb)
return -ENOMEM; return -ENOMEM;
...@@ -1152,9 +1166,15 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi) ...@@ -1152,9 +1166,15 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
si->volumes = RB_ROOT; si->volumes = RB_ROOT;
err = -ENOMEM; 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); ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
if (!ech) if (!ech)
goto out_si; goto out_slab;
vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL); vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
if (!vidh) if (!vidh)
...@@ -1215,6 +1235,8 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi) ...@@ -1215,6 +1235,8 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
ubi_free_vid_hdr(ubi, vidh); ubi_free_vid_hdr(ubi, vidh);
out_ech: out_ech:
kfree(ech); kfree(ech);
out_slab:
kmem_cache_destroy(si->scan_leb_slab);
out_si: out_si:
ubi_scan_destroy_si(si); ubi_scan_destroy_si(si);
return ERR_PTR(err); return ERR_PTR(err);
...@@ -1223,11 +1245,12 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi) ...@@ -1223,11 +1245,12 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
/** /**
* destroy_sv - free the scanning volume information * destroy_sv - free the scanning volume information
* @sv: scanning volume information * @sv: scanning volume information
* @si: scanning information
* *
* This function destroys the volume RB-tree (@sv->root) and the scanning * This function destroys the volume RB-tree (@sv->root) and the scanning
* volume information. * 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 ubi_scan_leb *seb;
struct rb_node *this = sv->root.rb_node; struct rb_node *this = sv->root.rb_node;
...@@ -1247,7 +1270,7 @@ static void destroy_sv(struct ubi_scan_volume *sv) ...@@ -1247,7 +1270,7 @@ static void destroy_sv(struct ubi_scan_volume *sv)
this->rb_right = NULL; this->rb_right = NULL;
} }
kfree(seb); kmem_cache_free(si->scan_leb_slab, seb);
} }
} }
kfree(sv); kfree(sv);
...@@ -1265,19 +1288,19 @@ void ubi_scan_destroy_si(struct ubi_scan_info *si) ...@@ -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_for_each_entry_safe(seb, seb_tmp, &si->alien, u.list) {
list_del(&seb->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_for_each_entry_safe(seb, seb_tmp, &si->erase, u.list) {
list_del(&seb->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_for_each_entry_safe(seb, seb_tmp, &si->corr, u.list) {
list_del(&seb->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_for_each_entry_safe(seb, seb_tmp, &si->free, u.list) {
list_del(&seb->u.list); list_del(&seb->u.list);
kfree(seb); kmem_cache_free(si->scan_leb_slab, seb);
} }
/* Destroy the volume RB-tree */ /* Destroy the volume RB-tree */
...@@ -1298,14 +1321,15 @@ void ubi_scan_destroy_si(struct ubi_scan_info *si) ...@@ -1298,14 +1321,15 @@ void ubi_scan_destroy_si(struct ubi_scan_info *si)
rb->rb_right = NULL; rb->rb_right = NULL;
} }
destroy_sv(sv); destroy_sv(si, sv);
} }
} }
kmem_cache_destroy(si->scan_leb_slab);
kfree(si); kfree(si);
} }
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID #ifdef CONFIG_MTD_UBI_DEBUG
/** /**
* paranoid_check_si - check the scanning information. * 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) ...@@ -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; struct ubi_scan_leb *seb, *last_seb;
uint8_t *buf; uint8_t *buf;
if (!(ubi_chk_flags & UBI_CHK_GEN))
return 0;
/* /*
* At first, check that scanning information is OK. * At first, check that scanning information is OK.
*/ */
...@@ -1575,4 +1602,4 @@ static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si) ...@@ -1575,4 +1602,4 @@ static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si)
return -EINVAL; return -EINVAL;
} }
#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */ #endif /* CONFIG_MTD_UBI_DEBUG */
...@@ -109,6 +109,7 @@ struct ubi_scan_volume { ...@@ -109,6 +109,7 @@ struct ubi_scan_volume {
* @mean_ec: mean erase counter value * @mean_ec: mean erase counter value
* @ec_sum: a temporary variable used when calculating @mean_ec * @ec_sum: a temporary variable used when calculating @mean_ec
* @ec_count: 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 * 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 * UBI sub-systems to build final UBI data structures, further error-recovery
...@@ -134,6 +135,7 @@ struct ubi_scan_info { ...@@ -134,6 +135,7 @@ struct ubi_scan_info {
int mean_ec; int mean_ec;
uint64_t ec_sum; uint64_t ec_sum;
int ec_count; int ec_count;
struct kmem_cache *scan_leb_slab;
}; };
struct ubi_device; struct ubi_device;
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#include <linux/mtd/ubi.h> #include <linux/mtd/ubi.h>
#include <asm/pgtable.h>
#include "ubi-media.h" #include "ubi-media.h"
#include "scan.h" #include "scan.h"
...@@ -387,8 +388,6 @@ struct ubi_wl_entry; ...@@ -387,8 +388,6 @@ 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_peb_buf: buffer of PEB size used for debugging
* @dbg_buf_mutex: protects @dbg_peb_buf
*/ */
struct ubi_device { struct ubi_device {
struct cdev cdev; struct cdev cdev;
...@@ -470,10 +469,6 @@ struct ubi_device { ...@@ -470,10 +469,6 @@ 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;
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
void *dbg_peb_buf;
struct mutex dbg_buf_mutex;
#endif
}; };
extern struct kmem_cache *ubi_wl_entry_slab; extern struct kmem_cache *ubi_wl_entry_slab;
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include "ubi.h" #include "ubi.h"
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID #ifdef CONFIG_MTD_UBI_DEBUG
static int paranoid_check_volumes(struct ubi_device *ubi); static int paranoid_check_volumes(struct ubi_device *ubi);
#else #else
#define paranoid_check_volumes(ubi) 0 #define paranoid_check_volumes(ubi) 0
...@@ -711,7 +711,7 @@ void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol) ...@@ -711,7 +711,7 @@ void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol)
volume_sysfs_close(vol); volume_sysfs_close(vol);
} }
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID #ifdef CONFIG_MTD_UBI_DEBUG
/** /**
* paranoid_check_volume - check volume information. * paranoid_check_volume - check volume information.
...@@ -876,6 +876,9 @@ static int paranoid_check_volumes(struct ubi_device *ubi) ...@@ -876,6 +876,9 @@ static int paranoid_check_volumes(struct ubi_device *ubi)
{ {
int i, err = 0; int i, err = 0;
if (!(ubi_chk_flags & UBI_CHK_GEN))
return 0;
for (i = 0; i < ubi->vtbl_slots; i++) { for (i = 0; i < ubi->vtbl_slots; i++) {
err = paranoid_check_volume(ubi, i); err = paranoid_check_volume(ubi, i);
if (err) if (err)
......
...@@ -62,7 +62,7 @@ ...@@ -62,7 +62,7 @@
#include <asm/div64.h> #include <asm/div64.h>
#include "ubi.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); static void paranoid_vtbl_check(const struct ubi_device *ubi);
#else #else
#define paranoid_vtbl_check(ubi) #define paranoid_vtbl_check(ubi)
...@@ -868,7 +868,7 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si) ...@@ -868,7 +868,7 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si)
return err; return err;
} }
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID #ifdef CONFIG_MTD_UBI_DEBUG
/** /**
* paranoid_vtbl_check - check volume table. * paranoid_vtbl_check - check volume table.
...@@ -876,10 +876,13 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si) ...@@ -876,10 +876,13 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si)
*/ */
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))
return;
if (vtbl_check(ubi, ubi->vtbl)) { if (vtbl_check(ubi, ubi->vtbl)) {
ubi_err("paranoid check failed"); ubi_err("paranoid check failed");
BUG(); BUG();
} }
} }
#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */ #endif /* CONFIG_MTD_UBI_DEBUG */
...@@ -161,7 +161,7 @@ struct ubi_work { ...@@ -161,7 +161,7 @@ struct ubi_work {
int torture; 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_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(struct ubi_wl_entry *e,
struct rb_root *root); struct rb_root *root);
...@@ -613,7 +613,7 @@ static void schedule_ubi_work(struct ubi_device *ubi, struct ubi_work *wrk) ...@@ -613,7 +613,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) if (ubi->thread_enabled && !ubi_dbg_is_bgt_disabled())
wake_up_process(ubi->bgt_thread); wake_up_process(ubi->bgt_thread);
spin_unlock(&ubi->wl_lock); spin_unlock(&ubi->wl_lock);
} }
...@@ -1364,7 +1364,7 @@ int ubi_thread(void *u) ...@@ -1364,7 +1364,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->thread_enabled || ubi_dbg_is_bgt_disabled()) {
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
spin_unlock(&ubi->wl_lock); spin_unlock(&ubi->wl_lock);
schedule(); schedule();
...@@ -1561,7 +1561,7 @@ void ubi_wl_close(struct ubi_device *ubi) ...@@ -1561,7 +1561,7 @@ void ubi_wl_close(struct ubi_device *ubi)
kfree(ubi->lookuptbl); 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. * 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) ...@@ -1578,6 +1578,9 @@ 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))
return 0;
ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS); ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
if (!ec_hdr) if (!ec_hdr)
return -ENOMEM; return -ENOMEM;
...@@ -1614,6 +1617,9 @@ static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec) ...@@ -1614,6 +1617,9 @@ 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(struct ubi_wl_entry *e,
struct rb_root *root) struct rb_root *root)
{ {
if (!(ubi_chk_flags & UBI_CHK_GEN))
return 0;
if (in_wl_tree(e, root)) if (in_wl_tree(e, root))
return 0; return 0;
...@@ -1636,6 +1642,9 @@ static int paranoid_check_in_pq(struct ubi_device *ubi, struct ubi_wl_entry *e) ...@@ -1636,6 +1642,9 @@ static int paranoid_check_in_pq(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))
return 0;
for (i = 0; i < UBI_PROT_QUEUE_LEN; ++i) for (i = 0; i < UBI_PROT_QUEUE_LEN; ++i)
list_for_each_entry(p, &ubi->pq[i], u.list) list_for_each_entry(p, &ubi->pq[i], u.list)
if (p == e) if (p == e)
...@@ -1646,4 +1655,5 @@ static int paranoid_check_in_pq(struct ubi_device *ubi, struct ubi_wl_entry *e) ...@@ -1646,4 +1655,5 @@ static int paranoid_check_in_pq(struct ubi_device *ubi, struct ubi_wl_entry *e)
ubi_dbg_dump_stack(); ubi_dbg_dump_stack();
return -EINVAL; return -EINVAL;
} }
#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */
#endif /* CONFIG_MTD_UBI_DEBUG */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment