From: zhouminqiang <[email protected]>
In jffs2_wbuf_recover(), when the recovery write to the new erase
block also fails, the code marks the already-written portion as
REF_OBSOLETE via jffs2_add_physical_node_ref(). However, the length
passed is ref_totlen(c, jeb, first_raw), which is the length of a
single node on the old block, rather than the full range of data
that was attempted to be written to the new block.
On the recovery target block the layout is:
ref_totlen(first_raw)
|<------------->|
ofs +---------------+-------+-------+ +--------+
| node 1 |node 2 |node 3 | ... |erased |
+---------------+-------+-------+ +--------+
| OBSOLETE | |
|<-towrite (page-aligned)->| |
|<-------- end - start -------->| |
|<-truly free->|
When the recovery buffer contains multiple nodes, ref_totlen only
accounts for the first node's length, which can be much smaller than
the total range. This under-deducts free_size, so the next write
lands at the start of node 2, which is already programmed on NAND,
and the AND operation corrupts both the old and new data.
With towrite as the OBSOLETE length, the next write lands right
after towrite in truly free space. However, node 3's header has
been written within the towrite region while its data extends beyond
it due to page-alignment truncation. On remount, the scanner finds
node 3's header, validates its CRC, and trusts its totlen -- skipping
PAD(totlen_node3) bytes. This skip extends past towrite into the
area where the subsequent write was placed, creating a shadow zone
that causes the newly written data to be silently lost.
Use end - start as the OBSOLETE length, which covers the full range
of data that was attempted to be written to the new block, so that
neither the NAND AND corruption nor the scanner shadow zone can
occur.
Fixes: b64335f2b740 ("[JFFS2] Add length argument to
jffs2_add_physical_node_ref().")
Signed-off-by: zhouminqiang <[email protected]>
---
fs/jffs2/wbuf.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c
index 61e3dbd4cd7b..ab247117ec77 100644
--- a/fs/jffs2/wbuf.c
+++ b/fs/jffs2/wbuf.c
@@ -437,7 +437,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
kfree(buf);
if (retlen)
- jffs2_add_physical_node_ref(c, ofs |
REF_OBSOLETE, ref_totlen(c, jeb, first_raw), NULL);
+ jffs2_add_physical_node_ref(c, ofs |
REF_OBSOLETE, end-start, NULL);
c->wbuf_len = 0;
return;
--
2.52.0