Merge branch 'linux-next' of git://git.infradead.org/ubi-2.6
* 'linux-next' of git://git.infradead.org/ubi-2.6: UBI: improve NOR flash erasure quirk UBI: introduce flash dump helper UBI: eliminate possible undefined behaviour UBI: print a warning if too many PEBs are corrupted UBI: amend NOR flash pre-erase quirk UBI: print a message if ECH is corrupted and VIDH is ok
This commit is contained in:
commit
0b887ef19d
|
@ -196,4 +196,36 @@ void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req)
|
||||||
printk(KERN_DEBUG "\t1st 16 characters of name: %s\n", nm);
|
printk(KERN_DEBUG "\t1st 16 characters of name: %s\n", nm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ubi_dbg_dump_flash - dump a region of flash.
|
||||||
|
* @ubi: UBI device description object
|
||||||
|
* @pnum: the physical eraseblock number to dump
|
||||||
|
* @offset: the starting offset within the physical eraseblock to dump
|
||||||
|
* @len: the length of the region to dump
|
||||||
|
*/
|
||||||
|
void ubi_dbg_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
size_t read;
|
||||||
|
void *buf;
|
||||||
|
loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
|
||||||
|
|
||||||
|
buf = vmalloc(len);
|
||||||
|
if (!buf)
|
||||||
|
return;
|
||||||
|
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 out;
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg_msg("dumping %d bytes of data from PEB %d, offset %d",
|
||||||
|
len, pnum, offset);
|
||||||
|
print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1);
|
||||||
|
out:
|
||||||
|
vfree(buf);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_MTD_UBI_DEBUG */
|
#endif /* CONFIG_MTD_UBI_DEBUG */
|
||||||
|
|
|
@ -55,6 +55,7 @@ void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx);
|
||||||
void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv);
|
void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv);
|
||||||
void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type);
|
void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type);
|
||||||
void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req);
|
void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req);
|
||||||
|
void ubi_dbg_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len);
|
||||||
|
|
||||||
#ifdef CONFIG_MTD_UBI_DEBUG_MSG
|
#ifdef CONFIG_MTD_UBI_DEBUG_MSG
|
||||||
/* General debugging messages */
|
/* General debugging messages */
|
||||||
|
@ -167,6 +168,7 @@ static inline int ubi_dbg_is_erase_failure(void)
|
||||||
#define ubi_dbg_dump_sv(sv) ({})
|
#define ubi_dbg_dump_sv(sv) ({})
|
||||||
#define ubi_dbg_dump_seb(seb, type) ({})
|
#define ubi_dbg_dump_seb(seb, type) ({})
|
||||||
#define ubi_dbg_dump_mkvol_req(req) ({})
|
#define ubi_dbg_dump_mkvol_req(req) ({})
|
||||||
|
#define ubi_dbg_dump_flash(ubi, pnum, offset, len) ({})
|
||||||
|
|
||||||
#define UBI_IO_DEBUG 0
|
#define UBI_IO_DEBUG 0
|
||||||
#define DBG_DISABLE_BGT 0
|
#define DBG_DISABLE_BGT 0
|
||||||
|
|
|
@ -269,6 +269,7 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
|
||||||
ubi_err("error %d while writing %d bytes to PEB %d:%d, written "
|
ubi_err("error %d while writing %d bytes to PEB %d:%d, written "
|
||||||
"%zd bytes", err, len, pnum, offset, written);
|
"%zd bytes", err, len, pnum, offset, written);
|
||||||
ubi_dbg_dump_stack();
|
ubi_dbg_dump_stack();
|
||||||
|
ubi_dbg_dump_flash(ubi, pnum, offset, len);
|
||||||
} else
|
} else
|
||||||
ubi_assert(written == len);
|
ubi_assert(written == len);
|
||||||
|
|
||||||
|
@ -475,30 +476,46 @@ out:
|
||||||
*/
|
*/
|
||||||
static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
|
static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
|
||||||
{
|
{
|
||||||
int err;
|
int err, err1;
|
||||||
size_t written;
|
size_t written;
|
||||||
loff_t addr;
|
loff_t addr;
|
||||||
uint32_t data = 0;
|
uint32_t data = 0;
|
||||||
|
struct ubi_vid_hdr vid_hdr;
|
||||||
|
|
||||||
addr = (loff_t)pnum * ubi->peb_size;
|
addr = (loff_t)pnum * ubi->peb_size + ubi->vid_hdr_aloffset;
|
||||||
err = ubi->mtd->write(ubi->mtd, addr, 4, &written, (void *)&data);
|
err = ubi->mtd->write(ubi->mtd, addr, 4, &written, (void *)&data);
|
||||||
if (err) {
|
if (!err) {
|
||||||
ubi_err("error %d while writing 4 bytes to PEB %d:%d, written "
|
addr -= ubi->vid_hdr_aloffset;
|
||||||
"%zd bytes", err, pnum, 0, written);
|
err = ubi->mtd->write(ubi->mtd, addr, 4, &written,
|
||||||
ubi_dbg_dump_stack();
|
(void *)&data);
|
||||||
return err;
|
if (!err)
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
addr += ubi->vid_hdr_aloffset;
|
/*
|
||||||
err = ubi->mtd->write(ubi->mtd, addr, 4, &written, (void *)&data);
|
* We failed to write to the media. This was observed with Spansion
|
||||||
if (err) {
|
* S29GL512N NOR flash. Most probably the eraseblock erasure was
|
||||||
ubi_err("error %d while writing 4 bytes to PEB %d:%d, written "
|
* interrupted at a very inappropriate moment, so it became unwritable.
|
||||||
"%zd bytes", err, pnum, ubi->vid_hdr_aloffset, written);
|
* In this case we probably anyway have garbage in this PEB.
|
||||||
ubi_dbg_dump_stack();
|
*/
|
||||||
return err;
|
err1 = ubi_io_read_vid_hdr(ubi, pnum, &vid_hdr, 0);
|
||||||
}
|
if (err1 == UBI_IO_BAD_VID_HDR)
|
||||||
|
/*
|
||||||
|
* The VID header is corrupted, so we can safely erase this
|
||||||
|
* PEB and not afraid that it will be treated as a valid PEB in
|
||||||
|
* case of an unclean reboot.
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
|
|
||||||
return 0;
|
/*
|
||||||
|
* The PEB contains a valid VID header, but we cannot invalidate it.
|
||||||
|
* Supposedly the flash media or the driver is screwed up, so return an
|
||||||
|
* error.
|
||||||
|
*/
|
||||||
|
ubi_err("cannot invalidate PEB %d, write returned %d read returned %d",
|
||||||
|
pnum, err, err1);
|
||||||
|
ubi_dbg_dump_flash(ubi, pnum, 0, ubi->peb_size);
|
||||||
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -75,9 +75,10 @@ static int add_to_list(struct ubi_scan_info *si, int pnum, int ec,
|
||||||
dbg_bld("add to free: PEB %d, EC %d", pnum, ec);
|
dbg_bld("add to free: PEB %d, EC %d", pnum, ec);
|
||||||
else if (list == &si->erase)
|
else if (list == &si->erase)
|
||||||
dbg_bld("add to erase: PEB %d, EC %d", pnum, ec);
|
dbg_bld("add to erase: PEB %d, EC %d", pnum, ec);
|
||||||
else if (list == &si->corr)
|
else if (list == &si->corr) {
|
||||||
dbg_bld("add to corrupted: PEB %d, EC %d", pnum, ec);
|
dbg_bld("add to corrupted: PEB %d, EC %d", pnum, ec);
|
||||||
else if (list == &si->alien)
|
si->corr_count += 1;
|
||||||
|
} else if (list == &si->alien)
|
||||||
dbg_bld("add to alien: PEB %d, EC %d", pnum, ec);
|
dbg_bld("add to alien: PEB %d, EC %d", pnum, ec);
|
||||||
else
|
else
|
||||||
BUG();
|
BUG();
|
||||||
|
@ -864,7 +865,9 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Both UBI headers seem to be fine */
|
if (ec_corr)
|
||||||
|
ubi_warn("valid VID header but corrupted EC header at PEB %d",
|
||||||
|
pnum);
|
||||||
err = ubi_scan_add_used(ubi, si, pnum, ec, vidh, bitflips);
|
err = ubi_scan_add_used(ubi, si, pnum, ec, vidh, bitflips);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
@ -935,6 +938,19 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
|
||||||
if (si->is_empty)
|
if (si->is_empty)
|
||||||
ubi_msg("empty MTD device detected");
|
ubi_msg("empty MTD device detected");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Few corrupted PEBs are not a problem and may be just a result of
|
||||||
|
* unclean reboots. However, many of them may indicate some problems
|
||||||
|
* with the flash HW or driver. Print a warning in this case.
|
||||||
|
*/
|
||||||
|
if (si->corr_count >= 8 || si->corr_count >= ubi->peb_count / 4) {
|
||||||
|
ubi_warn("%d PEBs are corrupted", si->corr_count);
|
||||||
|
printk(KERN_WARNING "corrupted PEBs are:");
|
||||||
|
list_for_each_entry(seb, &si->corr, u.list)
|
||||||
|
printk(KERN_CONT " %d", seb->pnum);
|
||||||
|
printk(KERN_CONT "\n");
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In case of unknown erase counter we use the mean erase counter
|
* In case of unknown erase counter we use the mean erase counter
|
||||||
* value.
|
* value.
|
||||||
|
|
|
@ -102,6 +102,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
|
||||||
|
* @corr_count: count of corrupted PEBs
|
||||||
* @image_seq_set: indicates @ubi->image_seq is known
|
* @image_seq_set: indicates @ubi->image_seq is known
|
||||||
*
|
*
|
||||||
* 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
|
||||||
|
@ -125,6 +126,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;
|
||||||
|
int corr_count;
|
||||||
int image_seq_set;
|
int image_seq_set;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -579,7 +579,8 @@ void ubi_do_get_volume_info(struct ubi_device *ubi, struct ubi_volume *vol,
|
||||||
for (rb = rb_first(root), \
|
for (rb = rb_first(root), \
|
||||||
pos = (rb ? container_of(rb, typeof(*pos), member) : NULL); \
|
pos = (rb ? container_of(rb, typeof(*pos), member) : NULL); \
|
||||||
rb; \
|
rb; \
|
||||||
rb = rb_next(rb), pos = container_of(rb, typeof(*pos), member))
|
rb = rb_next(rb), \
|
||||||
|
pos = (rb ? container_of(rb, typeof(*pos), member) : NULL))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ubi_zalloc_vid_hdr - allocate a volume identifier header object.
|
* ubi_zalloc_vid_hdr - allocate a volume identifier header object.
|
||||||
|
|
Loading…
Reference in New Issue