|
@@ -220,6 +220,47 @@ static struct jffs2_raw_node_ref **jffs2_incore_replace_raw(struct jffs2_sb_info
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
+#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
|
|
|
+static int jffs2_verify_write(struct jffs2_sb_info *c, unsigned char *buf,
|
|
|
+ uint32_t ofs)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+ size_t retlen;
|
|
|
+ char *eccstr;
|
|
|
+
|
|
|
+ ret = c->mtd->read(c->mtd, ofs, c->wbuf_pagesize, &retlen, c->wbuf_verify);
|
|
|
+ if (ret && ret != -EUCLEAN && ret != -EBADMSG) {
|
|
|
+ printk(KERN_WARNING "jffs2_verify_write(): Read back of page at %08x failed: %d\n", c->wbuf_ofs, ret);
|
|
|
+ return ret;
|
|
|
+ } else if (retlen != c->wbuf_pagesize) {
|
|
|
+ printk(KERN_WARNING "jffs2_verify_write(): Read back of page at %08x gave short read: %zd not %d.\n", ofs, retlen, c->wbuf_pagesize);
|
|
|
+ return -EIO;
|
|
|
+ }
|
|
|
+ if (!memcmp(buf, c->wbuf_verify, c->wbuf_pagesize))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if (ret == -EUCLEAN)
|
|
|
+ eccstr = "corrected";
|
|
|
+ else if (ret == -EBADMSG)
|
|
|
+ eccstr = "correction failed";
|
|
|
+ else
|
|
|
+ eccstr = "OK or unused";
|
|
|
+
|
|
|
+ printk(KERN_WARNING "Write verify error (ECC %s) at %08x. Wrote:\n",
|
|
|
+ eccstr, c->wbuf_ofs);
|
|
|
+ print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1,
|
|
|
+ c->wbuf, c->wbuf_pagesize, 0);
|
|
|
+
|
|
|
+ printk(KERN_WARNING "Read back:\n");
|
|
|
+ print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1,
|
|
|
+ c->wbuf_verify, c->wbuf_pagesize, 0);
|
|
|
+
|
|
|
+ return -EIO;
|
|
|
+}
|
|
|
+#else
|
|
|
+#define jffs2_verify_write(c,b,o) (0)
|
|
|
+#endif
|
|
|
+
|
|
|
/* Recover from failure to write wbuf. Recover the nodes up to the
|
|
|
* wbuf, not the one which we were starting to try to write. */
|
|
|
|
|
@@ -380,7 +421,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
|
|
|
ret = c->mtd->write(c->mtd, ofs, towrite, &retlen,
|
|
|
rewrite_buf);
|
|
|
|
|
|
- if (ret || retlen != towrite) {
|
|
|
+ if (ret || retlen != towrite || jffs2_verify_write(c, rewrite_buf, ofs)) {
|
|
|
/* Argh. We tried. Really we did. */
|
|
|
printk(KERN_CRIT "Recovery of wbuf failed due to a second write error\n");
|
|
|
kfree(buf);
|
|
@@ -587,15 +628,16 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
|
|
|
|
|
|
ret = c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf);
|
|
|
|
|
|
- if (ret || retlen != c->wbuf_pagesize) {
|
|
|
- if (ret)
|
|
|
- printk(KERN_WARNING "jffs2_flush_wbuf(): Write failed with %d\n",ret);
|
|
|
- else {
|
|
|
- printk(KERN_WARNING "jffs2_flush_wbuf(): Write was short: %zd instead of %d\n",
|
|
|
- retlen, c->wbuf_pagesize);
|
|
|
- ret = -EIO;
|
|
|
- }
|
|
|
-
|
|
|
+ if (ret) {
|
|
|
+ printk(KERN_WARNING "jffs2_flush_wbuf(): Write failed with %d\n", ret);
|
|
|
+ goto wfail;
|
|
|
+ } else if (retlen != c->wbuf_pagesize) {
|
|
|
+ printk(KERN_WARNING "jffs2_flush_wbuf(): Write was short: %zd instead of %d\n",
|
|
|
+ retlen, c->wbuf_pagesize);
|
|
|
+ ret = -EIO;
|
|
|
+ goto wfail;
|
|
|
+ } else if ((ret = jffs2_verify_write(c, c->wbuf, c->wbuf_ofs))) {
|
|
|
+ wfail:
|
|
|
jffs2_wbuf_recover(c);
|
|
|
|
|
|
return ret;
|
|
@@ -1138,11 +1180,22 @@ int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
|
|
|
return -ENOMEM;
|
|
|
}
|
|
|
|
|
|
+#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
|
|
|
+ c->wbuf_verify = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
|
|
|
+ if (!c->wbuf_verify) {
|
|
|
+ kfree(c->oobbuf);
|
|
|
+ kfree(c->wbuf);
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+#endif
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c)
|
|
|
{
|
|
|
+#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
|
|
|
+ kfree(c->wbuf_verify);
|
|
|
+#endif
|
|
|
kfree(c->wbuf);
|
|
|
kfree(c->oobbuf);
|
|
|
}
|