Re: [PATCH 1/1] ubifs: Try to recover from missing znode

From: Zhihao Cheng
Date: Tue Oct 08 2024 - 22:23:25 EST


在 2024/10/8 21:33, Benedikt Spranger 写道:
After powercut on a system using ubifs mounting failed:

2024-09-30T12:38:26.880487+02:00 sonja kernel: UBIFS error (ubi0:0 pid 2178): ubifs_read_node [ubifs]: bad node type (255 but expected 9)
2024-09-30T12:38:26.880506+02:00 sonja kernel: UBIFS error (ubi0:0 pid 2178): ubifs_read_node [ubifs]: bad node at LEB 103:46920, LEB mapping status 0
2024-09-30T12:38:26.880509+02:00 sonja kernel: Not a node, first 24 bytes:
2024-09-30T12:38:26.880510+02:00 sonja kernel: 00000000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ........................

While traversing over zbranches during the journal replay one zbranch
points to a znode, which was not written to the flash and therefore the
flash is empty.

UBIFS guarantees two things for znodes:
1) all index nodes(in commit seq N) are written on flash before master nodes(for commit seq N) are written.
2) all index nodes(in commit seq N) won't be erased from flash before master nodes(for commit seq N+1) are written.
So, I don't understand that why znodes not exist during journal replaying?

Try to recover from that by inserting an empty znode instead of failing.

Signed-off-by: Benedikt Spranger <b.spranger@xxxxxxxxxxxxx>
Reviewed-by: John Ogness <john.ogness@xxxxxxxxxxxxx>
---
fs/ubifs/io.c | 16 ++++++++++++++++
fs/ubifs/tnc_misc.c | 6 +++++-
2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/fs/ubifs/io.c b/fs/ubifs/io.c
index 01d8eb170382..0bbb426f9006 100644
--- a/fs/ubifs/io.c
+++ b/fs/ubifs/io.c
@@ -1110,6 +1110,22 @@ int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len,
return err;
if (type != ch->node_type) {
+ /*
+ * While recovering, we may face lost data i.e. empty flash.
+ * Give callsites a hint by returning -ENODATA.
+ */
+ if (c->replaying) {
+ u8 *b = buf;
+
+ for (l = 0; l < len; l++) {
+ if (b[l] != 0xff)
+ break;
+ }
+ if (l == len) {
+ ubifs_errc(c, "no node, but empty flash");
+ return -ENODATA;
+ }
+ }
ubifs_errc(c, "bad node type (%d but expected %d)",
ch->node_type, type);
goto out;
diff --git a/fs/ubifs/tnc_misc.c b/fs/ubifs/tnc_misc.c
index d3f8a6aa1f49..4d085fc1300f 100644
--- a/fs/ubifs/tnc_misc.c
+++ b/fs/ubifs/tnc_misc.c
@@ -300,7 +300,11 @@ static int read_znode(struct ubifs_info *c, struct ubifs_zbranch *zzbr,
err = ubifs_read_node(c, idx, UBIFS_IDX_NODE, len, lnum, offs);
if (err < 0) {
kfree(idx);
- return err;
+ /*
+ * While recovering we may face a non written znode.
+ * Inject an empty znode in this case.
+ */
+ return (err == -ENODATA) ? 0 : err;
}
err = ubifs_node_check_hash(c, idx, zzbr->hash);