jffs2_verify_write() uses memcmp() to compare the write buffer
against data read back from flash. On mismatch, the current code
dumps the entire source and read-back data, which will become
impractical once the verify path is extended to NOR flash where
a single write can span PAGE_SIZE.

Add a byte-by-byte comparison after the memcmp() mismatch path
to locate the exact mismatch offset, reporting the first
differing offset and dumping up to 128 bytes of both the source
and read-back data. memcmp() remains on the hotpath for
successful writes, and the byte-by-byte loop only runs when an
error is actually detected.

Signed-off-by: zhouminqiang <[email protected]>
---
 fs/jffs2/wbuf.c | 46 ++++++++++++++++++++++++++++------------------
 1 file changed, 28 insertions(+), 18 deletions(-)

diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c
index f10be57c5543..74e169dedab7 100644
--- a/fs/jffs2/wbuf.c
+++ b/fs/jffs2/wbuf.c
@@ -231,7 +231,7 @@ static int jffs2_verify_write(struct jffs2_sb_info *c, 
unsigned char *buf,
                              uint32_t ofs)
 {
        int ret;
-       size_t retlen;
+       size_t retlen, i;
        char *eccstr;
        void *verify_buf;
 
@@ -246,10 +246,10 @@ static int jffs2_verify_write(struct jffs2_sb_info *c, 
unsigned char *buf,
 
        if (ret && ret != -EUCLEAN && ret != -EBADMSG) {
                pr_warn("%s(): Read back of page at %08x failed: %d\n",
-                       __func__, c->wbuf_ofs, ret);
+                       __func__, ofs, ret);
                goto out_free;
        } else if (retlen != c->wbuf_pagesize) {
-               pr_warn("%s(): Read back of page at %08x gave short read: %zd 
not %d\n",
+               pr_warn("%s(): Read back of page at %08x gave short read: %zu 
not %d\n",
                        __func__, ofs, retlen, c->wbuf_pagesize);
                ret = -EIO;
                goto out_free;
@@ -259,24 +259,34 @@ static int jffs2_verify_write(struct jffs2_sb_info *c, 
unsigned char *buf,
                goto out_free;
        }
 
-       if (ret == -EUCLEAN)
-               eccstr = "corrected";
-       else if (ret == -EBADMSG)
-               eccstr = "correction failed";
-       else
-               eccstr = "OK or unused";
+       for (i = 0; i < c->wbuf_pagesize; i++) {
+               uint8_t c1 = ((uint8_t *)buf)[i];
+               uint8_t c2 = ((uint8_t *)verify_buf)[i];
+               int dump_len;
 
-       pr_warn("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);
+               if (c1 == c2)
+                       continue;
 
-       pr_warn("Read back:\n");
-       print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1,
-                      verify_buf, c->wbuf_pagesize, 0);
+               if (ret == -EUCLEAN)
+                       eccstr = "corrected";
+               else if (ret == -EBADMSG)
+                       eccstr = "correction failed";
+               else
+                       eccstr = "OK or unused";
 
-       kfree(verify_buf);
-       return -EIO;
+               dump_len = min_t(int, 128, c->wbuf_pagesize - i);
+               pr_warn("Write verify error (ECC %s) at %08x (+%zu/%d). 
Wrote:\n",
+                       eccstr, ofs, i, c->wbuf_pagesize);
+               print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1,
+                              buf + i, dump_len, 0);
+
+               pr_warn("Read back:\n");
+               print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1,
+                              verify_buf + i, dump_len, 0);
+
+               ret = -EIO;
+               goto out_free;
+       }
 
 out_free:
        kfree(verify_buf);
-- 
2.52.0


Reply via email to