From: zhouminqiang <zhouminqiang2@huawei.com>
To: <dwmw2@infradead.org>, <richard@nod.at>
Cc: <linux-mtd@lists.infradead.org>, <linux-kernel@vger.kernel.org>,
<chengzhihao1@huawei.com>, <yangerkun@huawei.com>,
<yi.zhang@huawei.com>
Subject: [PATCH 3/6] jffs2: add write verification to direct page writes in flash_writev
Date: Thu, 20 Aug 2026 18:49:59 +0800 [thread overview]
Message-ID: <20260820105003.2525647-4-zhouminqiang2@huawei.com> (raw)
In-Reply-To: <20260820105003.2525647-1-zhouminqiang2@huawei.com>
jffs2_flash_writev() performs writes in three phases: phase 1 fills
the write buffer and flushes it when full, phase 2 writes full pages
directly via mtd_write() bypassing the buffer, and phase 3 fills the
remaining data into the write buffer.
Phases 1 and 3 both invoke __jffs2_flush_wbuf() when the buffer is
full, which includes write-back verification when
CONFIG_JFFS2_FS_WBUF_VERIFY is enabled. However phase 2, which
handles the bulk of the write data, calls mtd_write() directly
without any verification.
Phase 2 direct writes may span multiple wbuf_pagesize pages. Extend
jffs2_verify_write() with a len parameter to specify the data length
to verify, and add the verification call after the phase 2
mtd_write() to cover this gap.
Signed-off-by: zhouminqiang <zhouminqiang2@huawei.com>
---
fs/jffs2/wbuf.c | 33 ++++++++++++++++++++-------------
1 file changed, 20 insertions(+), 13 deletions(-)
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c
index da6da813a4ef..3e99587f40e4 100644
--- a/fs/jffs2/wbuf.c
+++ b/fs/jffs2/wbuf.c
@@ -229,33 +229,33 @@ static struct jffs2_raw_node_ref **jffs2_incore_replace_raw(struct jffs2_sb_info
#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
static int jffs2_verify_write(struct jffs2_sb_info *c, unsigned char *buf,
- uint32_t ofs)
+ uint32_t ofs, size_t len)
{
int ret = 0;
size_t retlen, i;
char *eccstr;
void *verify_buf;
- verify_buf = __vmalloc(c->wbuf_pagesize, GFP_NOFS);
+ verify_buf = __vmalloc(len, GFP_NOFS);
if (!verify_buf) {
pr_warn("%s(): verify buffer allocation failed, skipping verification\n",
__func__);
return 0;
}
- ret = mtd_read(c->mtd, ofs, c->wbuf_pagesize, &retlen, verify_buf);
+ ret = mtd_read(c->mtd, ofs, len, &retlen, verify_buf);
if (ret && ret != -EUCLEAN && ret != -EBADMSG) {
pr_warn("%s(): Read back of page at %08x failed: %d\n",
__func__, ofs, ret);
goto out_free;
- } else if (retlen != c->wbuf_pagesize) {
- pr_warn("%s(): Read back of page at %08x gave short read: %zu not %d\n",
- __func__, ofs, retlen, c->wbuf_pagesize);
+ } else if (retlen != len) {
+ pr_warn("%s(): Read back of page at %08x gave short read: %zu not %zu\n",
+ __func__, ofs, retlen, len);
ret = -EIO;
goto out_free;
}
- for (i = 0; i < c->wbuf_pagesize; i++) {
+ for (i = 0; i < len; i++) {
uint8_t c1 = ((uint8_t *)buf)[i];
uint8_t c2 = ((uint8_t *)verify_buf)[i];
int dump_len;
@@ -270,9 +270,9 @@ static int jffs2_verify_write(struct jffs2_sb_info *c, unsigned char *buf,
else
eccstr = "OK or unused";
- 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);
+ dump_len = min_t(int, 128, len - i);
+ pr_warn("Write verify error (ECC %s) at %08x (+%zu/%zu). Wrote:\n",
+ eccstr, ofs, i, len);
print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1,
buf + i, dump_len, 0);
@@ -292,7 +292,7 @@ static int jffs2_verify_write(struct jffs2_sb_info *c, unsigned char *buf,
return ret;
}
#else
-#define jffs2_verify_write(c,b,o) (0)
+#define jffs2_verify_write(c,b,o,l) (0)
#endif
/* Recover from failure to write wbuf. Recover the nodes up to the
@@ -455,7 +455,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
ret = mtd_write(c->mtd, ofs, towrite, &retlen,
rewrite_buf);
- if (ret || retlen != towrite || jffs2_verify_write(c, rewrite_buf, ofs)) {
+ if (ret || retlen != towrite || jffs2_verify_write(c, rewrite_buf, ofs, towrite)) {
/* Argh. We tried. Really we did. */
pr_crit("Recovery of wbuf failed due to a second write error\n");
kfree(buf);
@@ -672,7 +672,10 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
retlen, c->wbuf_pagesize);
ret = -EIO;
goto wfail;
- } else if ((ret = jffs2_verify_write(c, c->wbuf, c->wbuf_ofs))) {
+ }
+
+ ret = jffs2_verify_write(c, c->wbuf, c->wbuf_ofs, c->wbuf_pagesize);
+ if (ret) {
wfail:
jffs2_wbuf_recover(c);
@@ -904,6 +907,10 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs,
if (ret < 0 || wbuf_retlen != PAGE_DIV(vlen))
goto outfile;
+ ret = jffs2_verify_write(c, v, outvec_to, PAGE_DIV(vlen));
+ if (ret)
+ goto outfile;
+
vlen -= wbuf_retlen;
outvec_to += wbuf_retlen;
c->wbuf_ofs = outvec_to;
--
2.52.0
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
WARNING: multiple messages have this Message-ID (diff)
From: zhouminqiang <zhouminqiang2@huawei.com>
To: <dwmw2@infradead.org>, <richard@nod.at>
Cc: <linux-mtd@lists.infradead.org>, <linux-kernel@vger.kernel.org>,
<chengzhihao1@huawei.com>, <yangerkun@huawei.com>,
<yi.zhang@huawei.com>
Subject: [PATCH 3/6] jffs2: add write verification to direct page writes in flash_writev
Date: Thu, 20 Aug 2026 18:49:59 +0800 [thread overview]
Message-ID: <20260820105003.2525647-4-zhouminqiang2@huawei.com> (raw)
In-Reply-To: <20260820105003.2525647-1-zhouminqiang2@huawei.com>
jffs2_flash_writev() performs writes in three phases: phase 1 fills
the write buffer and flushes it when full, phase 2 writes full pages
directly via mtd_write() bypassing the buffer, and phase 3 fills the
remaining data into the write buffer.
Phases 1 and 3 both invoke __jffs2_flush_wbuf() when the buffer is
full, which includes write-back verification when
CONFIG_JFFS2_FS_WBUF_VERIFY is enabled. However phase 2, which
handles the bulk of the write data, calls mtd_write() directly
without any verification.
Phase 2 direct writes may span multiple wbuf_pagesize pages. Extend
jffs2_verify_write() with a len parameter to specify the data length
to verify, and add the verification call after the phase 2
mtd_write() to cover this gap.
Signed-off-by: zhouminqiang <zhouminqiang2@huawei.com>
---
fs/jffs2/wbuf.c | 33 ++++++++++++++++++++-------------
1 file changed, 20 insertions(+), 13 deletions(-)
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c
index da6da813a4ef..3e99587f40e4 100644
--- a/fs/jffs2/wbuf.c
+++ b/fs/jffs2/wbuf.c
@@ -229,33 +229,33 @@ static struct jffs2_raw_node_ref **jffs2_incore_replace_raw(struct jffs2_sb_info
#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
static int jffs2_verify_write(struct jffs2_sb_info *c, unsigned char *buf,
- uint32_t ofs)
+ uint32_t ofs, size_t len)
{
int ret = 0;
size_t retlen, i;
char *eccstr;
void *verify_buf;
- verify_buf = __vmalloc(c->wbuf_pagesize, GFP_NOFS);
+ verify_buf = __vmalloc(len, GFP_NOFS);
if (!verify_buf) {
pr_warn("%s(): verify buffer allocation failed, skipping verification\n",
__func__);
return 0;
}
- ret = mtd_read(c->mtd, ofs, c->wbuf_pagesize, &retlen, verify_buf);
+ ret = mtd_read(c->mtd, ofs, len, &retlen, verify_buf);
if (ret && ret != -EUCLEAN && ret != -EBADMSG) {
pr_warn("%s(): Read back of page at %08x failed: %d\n",
__func__, ofs, ret);
goto out_free;
- } else if (retlen != c->wbuf_pagesize) {
- pr_warn("%s(): Read back of page at %08x gave short read: %zu not %d\n",
- __func__, ofs, retlen, c->wbuf_pagesize);
+ } else if (retlen != len) {
+ pr_warn("%s(): Read back of page at %08x gave short read: %zu not %zu\n",
+ __func__, ofs, retlen, len);
ret = -EIO;
goto out_free;
}
- for (i = 0; i < c->wbuf_pagesize; i++) {
+ for (i = 0; i < len; i++) {
uint8_t c1 = ((uint8_t *)buf)[i];
uint8_t c2 = ((uint8_t *)verify_buf)[i];
int dump_len;
@@ -270,9 +270,9 @@ static int jffs2_verify_write(struct jffs2_sb_info *c, unsigned char *buf,
else
eccstr = "OK or unused";
- 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);
+ dump_len = min_t(int, 128, len - i);
+ pr_warn("Write verify error (ECC %s) at %08x (+%zu/%zu). Wrote:\n",
+ eccstr, ofs, i, len);
print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1,
buf + i, dump_len, 0);
@@ -292,7 +292,7 @@ static int jffs2_verify_write(struct jffs2_sb_info *c, unsigned char *buf,
return ret;
}
#else
-#define jffs2_verify_write(c,b,o) (0)
+#define jffs2_verify_write(c,b,o,l) (0)
#endif
/* Recover from failure to write wbuf. Recover the nodes up to the
@@ -455,7 +455,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
ret = mtd_write(c->mtd, ofs, towrite, &retlen,
rewrite_buf);
- if (ret || retlen != towrite || jffs2_verify_write(c, rewrite_buf, ofs)) {
+ if (ret || retlen != towrite || jffs2_verify_write(c, rewrite_buf, ofs, towrite)) {
/* Argh. We tried. Really we did. */
pr_crit("Recovery of wbuf failed due to a second write error\n");
kfree(buf);
@@ -672,7 +672,10 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
retlen, c->wbuf_pagesize);
ret = -EIO;
goto wfail;
- } else if ((ret = jffs2_verify_write(c, c->wbuf, c->wbuf_ofs))) {
+ }
+
+ ret = jffs2_verify_write(c, c->wbuf, c->wbuf_ofs, c->wbuf_pagesize);
+ if (ret) {
wfail:
jffs2_wbuf_recover(c);
@@ -904,6 +907,10 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs,
if (ret < 0 || wbuf_retlen != PAGE_DIV(vlen))
goto outfile;
+ ret = jffs2_verify_write(c, v, outvec_to, PAGE_DIV(vlen));
+ if (ret)
+ goto outfile;
+
vlen -= wbuf_retlen;
outvec_to += wbuf_retlen;
c->wbuf_ofs = outvec_to;
--
2.52.0
next prev parent reply other threads:[~2026-08-20 10:57 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-20 10:49 [PATCH 0/6] jffs2: extend write verification to all write paths zhouminqiang
2026-08-20 10:49 ` zhouminqiang
2026-08-20 10:49 ` [PATCH 1/6] jffs2: replace per-superblock verify buffer with per-write buffer zhouminqiang
2026-08-20 10:49 ` zhouminqiang
2026-08-20 10:49 ` [PATCH 2/6] jffs2: write verify: replace memcmp with byte-by-byte comparison zhouminqiang
2026-08-20 10:49 ` zhouminqiang
2026-08-20 10:49 ` zhouminqiang [this message]
2026-08-20 10:49 ` [PATCH 3/6] jffs2: add write verification to direct page writes in flash_writev zhouminqiang
2026-08-20 10:50 ` [PATCH 4/6] jffs2: add write verification to NOR direct write paths zhouminqiang
2026-08-20 10:50 ` zhouminqiang
2026-08-20 10:50 ` [PATCH 5/6] jffs2: rename CONFIG_JFFS2_FS_WBUF_VERIFY to CONFIG_JFFS2_FS_WRITE_VERIFY zhouminqiang
2026-08-20 10:50 ` zhouminqiang
2026-08-20 10:50 ` [PATCH 6/6] jffs2: add runtime toggle for write verification zhouminqiang
2026-08-20 10:50 ` zhouminqiang
2026-08-20 18:58 ` [PATCH 0/6] jffs2: extend write verification to all write paths Richard Weinberger
2026-08-20 18:58 ` Richard Weinberger
2026-08-20 20:46 ` David Woodhouse
2026-08-20 20:46 ` David Woodhouse
2026-08-21 3:37 ` zhouminqiang
2026-08-21 3:37 ` zhouminqiang
2026-08-21 6:31 ` Richard Weinberger
2026-08-21 6:31 ` Richard Weinberger
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260820105003.2525647-4-zhouminqiang2@huawei.com \
--to=zhouminqiang2@huawei.com \
--cc=chengzhihao1@huawei.com \
--cc=dwmw2@infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mtd@lists.infradead.org \
--cc=richard@nod.at \
--cc=yangerkun@huawei.com \
--cc=yi.zhang@huawei.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.