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
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
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,7 +986,6 @@ 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;
wake_up_process(ubi->bgt_thread);
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)
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)
{
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)
{
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 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
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,8 +783,7 @@ 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, "
dbg_bld("no EC header found at PEB %d, "
"only 0xFF bytes", pnum);
if (!read_err)
return UBI_IO_FF;
......@@ -769,8 +799,8 @@ 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 "
}
dbg_bld("bad magic number at PEB %d: %08x instead of "
"%08x", pnum, magic, UBI_EC_HDR_MAGIC);
return UBI_IO_BAD_HDR;
}
......@@ -783,8 +813,8 @@ 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 "
}
dbg_bld("bad EC header CRC at PEB %d, calculated "
"%#08x, read %#08x", pnum, crc, hdr_crc);
if (!read_err)
......@@ -1008,8 +1038,7 @@ 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, "
dbg_bld("no VID header found at PEB %d, "
"only 0xFF bytes", pnum);
if (!read_err)
return UBI_IO_FF;
......@@ -1021,8 +1050,8 @@ 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 "
}
dbg_bld("bad magic number at PEB %d: %08x instead of "
"%08x", pnum, magic, UBI_VID_HDR_MAGIC);
return UBI_IO_BAD_HDR;
}
......@@ -1035,8 +1064,8 @@ 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, "
}
dbg_bld("bad CRC at PEB %d, calculated %#08x, "
"read %#08x", pnum, crc, hdr_crc);
if (!read_err)
return UBI_IO_BAD_HDR;
......@@ -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.
* 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 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
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 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
/**
* 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 @@ static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si)
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 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si)
return err;
}
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
#ifdef CONFIG_MTD_UBI_DEBUG
/**
* paranoid_vtbl_check - check volume table.
......@@ -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)
{
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 @@ 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)
{
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 */
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