aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/Kconfig8
-rw-r--r--fs/jffs2/jffs2_fs_sb.h3
-rw-r--r--fs/jffs2/wbuf.c73
3 files changed, 74 insertions, 10 deletions
diff --git a/fs/Kconfig b/fs/Kconfig
index e9c5b81dd665..e19423a2aa7d 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -1228,6 +1228,14 @@ config JFFS2_FS_WRITEBUFFER
1228 - NOR flash with transparent ECC 1228 - NOR flash with transparent ECC
1229 - DataFlash 1229 - DataFlash
1230 1230
1231config JFFS2_FS_WBUF_VERIFY
1232 bool "Verify JFFS2 write-buffer reads"
1233 depends on JFFS2_FS_WRITEBUFFER
1234 default n
1235 help
1236 This causes JFFS2 to read back every page written through the
1237 write-buffer, and check for errors.
1238
1231config JFFS2_SUMMARY 1239config JFFS2_SUMMARY
1232 bool "JFFS2 summary support (EXPERIMENTAL)" 1240 bool "JFFS2 summary support (EXPERIMENTAL)"
1233 depends on JFFS2_FS && EXPERIMENTAL 1241 depends on JFFS2_FS && EXPERIMENTAL
diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h
index b13298a824ed..ae99cd7fd43b 100644
--- a/fs/jffs2/jffs2_fs_sb.h
+++ b/fs/jffs2/jffs2_fs_sb.h
@@ -106,6 +106,9 @@ struct jffs2_sb_info {
106 106
107 uint32_t wbuf_pagesize; /* 0 for NOR and other flashes with no wbuf */ 107 uint32_t wbuf_pagesize; /* 0 for NOR and other flashes with no wbuf */
108 108
109#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
110 unsigned char *wbuf_verify; /* read-back buffer for verification */
111#endif
109#ifdef CONFIG_JFFS2_FS_WRITEBUFFER 112#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
110 unsigned char *wbuf; /* Write-behind buffer for NAND flash */ 113 unsigned char *wbuf; /* Write-behind buffer for NAND flash */
111 uint32_t wbuf_ofs; 114 uint32_t wbuf_ofs;
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c
index 64f8d7add7e8..ec99c8ec83ae 100644
--- a/fs/jffs2/wbuf.c
+++ b/fs/jffs2/wbuf.c
@@ -220,6 +220,47 @@ static struct jffs2_raw_node_ref **jffs2_incore_replace_raw(struct jffs2_sb_info
220 return NULL; 220 return NULL;
221} 221}
222 222
223#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
224static int jffs2_verify_write(struct jffs2_sb_info *c, unsigned char *buf,
225 uint32_t ofs)
226{
227 int ret;
228 size_t retlen;
229 char *eccstr;
230
231 ret = c->mtd->read(c->mtd, ofs, c->wbuf_pagesize, &retlen, c->wbuf_verify);
232 if (ret && ret != -EUCLEAN && ret != -EBADMSG) {
233 printk(KERN_WARNING "jffs2_verify_write(): Read back of page at %08x failed: %d\n", c->wbuf_ofs, ret);
234 return ret;
235 } else if (retlen != c->wbuf_pagesize) {
236 printk(KERN_WARNING "jffs2_verify_write(): Read back of page at %08x gave short read: %zd not %d.\n", ofs, retlen, c->wbuf_pagesize);
237 return -EIO;
238 }
239 if (!memcmp(buf, c->wbuf_verify, c->wbuf_pagesize))
240 return 0;
241
242 if (ret == -EUCLEAN)
243 eccstr = "corrected";
244 else if (ret == -EBADMSG)
245 eccstr = "correction failed";
246 else
247 eccstr = "OK or unused";
248
249 printk(KERN_WARNING "Write verify error (ECC %s) at %08x. Wrote:\n",
250 eccstr, c->wbuf_ofs);
251 print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1,
252 c->wbuf, c->wbuf_pagesize, 0);
253
254 printk(KERN_WARNING "Read back:\n");
255 print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1,
256 c->wbuf_verify, c->wbuf_pagesize, 0);
257
258 return -EIO;
259}
260#else
261#define jffs2_verify_write(c,b,o) (0)
262#endif
263
223/* Recover from failure to write wbuf. Recover the nodes up to the 264/* Recover from failure to write wbuf. Recover the nodes up to the
224 * wbuf, not the one which we were starting to try to write. */ 265 * wbuf, not the one which we were starting to try to write. */
225 266
@@ -380,7 +421,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
380 ret = c->mtd->write(c->mtd, ofs, towrite, &retlen, 421 ret = c->mtd->write(c->mtd, ofs, towrite, &retlen,
381 rewrite_buf); 422 rewrite_buf);
382 423
383 if (ret || retlen != towrite) { 424 if (ret || retlen != towrite || jffs2_verify_write(c, rewrite_buf, ofs)) {
384 /* Argh. We tried. Really we did. */ 425 /* Argh. We tried. Really we did. */
385 printk(KERN_CRIT "Recovery of wbuf failed due to a second write error\n"); 426 printk(KERN_CRIT "Recovery of wbuf failed due to a second write error\n");
386 kfree(buf); 427 kfree(buf);
@@ -587,15 +628,16 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
587 628
588 ret = c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf); 629 ret = c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf);
589 630
590 if (ret || retlen != c->wbuf_pagesize) { 631 if (ret) {
591 if (ret) 632 printk(KERN_WARNING "jffs2_flush_wbuf(): Write failed with %d\n", ret);
592 printk(KERN_WARNING "jffs2_flush_wbuf(): Write failed with %d\n",ret); 633 goto wfail;
593 else { 634 } else if (retlen != c->wbuf_pagesize) {
594 printk(KERN_WARNING "jffs2_flush_wbuf(): Write was short: %zd instead of %d\n", 635 printk(KERN_WARNING "jffs2_flush_wbuf(): Write was short: %zd instead of %d\n",
595 retlen, c->wbuf_pagesize); 636 retlen, c->wbuf_pagesize);
596 ret = -EIO; 637 ret = -EIO;
597 } 638 goto wfail;
598 639 } else if ((ret = jffs2_verify_write(c, c->wbuf, c->wbuf_ofs))) {
640 wfail:
599 jffs2_wbuf_recover(c); 641 jffs2_wbuf_recover(c);
600 642
601 return ret; 643 return ret;
@@ -1138,11 +1180,22 @@ int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
1138 return -ENOMEM; 1180 return -ENOMEM;
1139 } 1181 }
1140 1182
1183#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
1184 c->wbuf_verify = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
1185 if (!c->wbuf_verify) {
1186 kfree(c->oobbuf);
1187 kfree(c->wbuf);
1188 return -ENOMEM;
1189 }
1190#endif
1141 return 0; 1191 return 0;
1142} 1192}
1143 1193
1144void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c) 1194void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c)
1145{ 1195{
1196#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
1197 kfree(c->wbuf_verify);
1198#endif
1146 kfree(c->wbuf); 1199 kfree(c->wbuf);
1147 kfree(c->oobbuf); 1200 kfree(c->oobbuf);
1148} 1201}