[U-Boot] [PATCH] UBIFS: fix recovery bug

Stefan Roese sr at denx.de
Tue Apr 14 17:50:38 CEST 2009


From: Adrian Hunter <adrian.hunter at nokia.com>

UBIFS did not recovery in a situation in which it could
have. The relevant function assumed there could not be
more nodes in an eraseblock after a corrupted node, but
in fact the last (NAND) page written might contain anything.
The correct approach is to check for empty space (0xFF bytes)
from then on.

Signed-off-by: Adrian Hunter <adrian.hunter at nokia.com>
Signed-off-by: Stefan Roese <sr at denx.de>
---
 fs/ubifs/recovery.c |   70 ++++++++++++++++----------------------------------
 1 files changed, 23 insertions(+), 47 deletions(-)

diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c
index fe3b364..7444650 100644
--- a/fs/ubifs/recovery.c
+++ b/fs/ubifs/recovery.c
@@ -418,59 +418,35 @@ static void clean_buf(const struct ubifs_info *c, void **buf, int lnum,
  * @lnum: LEB number of the LEB from which @buf was read
  * @offs: offset from which @buf was read
  *
- * This function scans @buf for more nodes and returns %0 is a node is found and
- * %1 if no more nodes are found.
+ * This function ensures that the corrupted node at @offs is the last thing
+ * written to a LEB. This function returns %1 if more data is not found and
+ * %0 if more data is found.
  */
 static int no_more_nodes(const struct ubifs_info *c, void *buf, int len,
 			int lnum, int offs)
 {
-	int skip, next_offs = 0;
+	struct ubifs_ch *ch = buf;
+	int skip, dlen = le32_to_cpu(ch->len);
 
-	if (len > UBIFS_DATA_NODE_SZ) {
-		struct ubifs_ch *ch = buf;
-		int dlen = le32_to_cpu(ch->len);
-
-		if (ch->node_type == UBIFS_DATA_NODE && dlen >= UBIFS_CH_SZ &&
-		    dlen <= UBIFS_MAX_DATA_NODE_SZ)
-			/* The corrupt node looks like a data node */
-			next_offs = ALIGN(offs + dlen, 8);
-	}
-
-	if (c->min_io_size == 1)
-		skip = 8;
-	else
-		skip = ALIGN(offs + 1, c->min_io_size) - offs;
-
-	offs += skip;
-	buf += skip;
-	len -= skip;
-	while (len > 8) {
-		struct ubifs_ch *ch = buf;
-		uint32_t magic = le32_to_cpu(ch->magic);
-		int ret;
-
-		if (magic == UBIFS_NODE_MAGIC) {
-			ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 1);
-			if (ret == SCANNED_A_NODE || ret > 0) {
-				/*
-				 * There is a small chance this is just data in
-				 * a data node, so check that possibility. e.g.
-				 * this is part of a file that itself contains
-				 * a UBIFS image.
-				 */
-				if (next_offs && offs + le32_to_cpu(ch->len) <=
-				    next_offs)
-					continue;
-				dbg_rcvry("unexpected node at %d:%d", lnum,
-					  offs);
-				return 0;
-			}
-		}
-		offs += 8;
-		buf += 8;
-		len -= 8;
+	/* Check for empty space after the corrupt node's common header */
+	skip = ALIGN(offs + UBIFS_CH_SZ, c->min_io_size) - offs;
+	if (is_empty(buf + skip, len - skip))
+		return 1;
+	/*
+	 * The area after the common header size is not empty, so the common
+	 * header must be intact. Check it.
+	 */
+	if (ubifs_check_node(c, buf, lnum, offs, 1, 0) != -EUCLEAN) {
+		dbg_rcvry("unexpected bad common header at %d:%d", lnum, offs);
+		return 0;
 	}
-	return 1;
+	/* Now we know the corrupt node's length we can skip over it */
+	skip = ALIGN(offs + dlen, c->min_io_size) - offs;
+	/* After which there should be empty space */
+	if (is_empty(buf + skip, len - skip))
+		return 1;
+	dbg_rcvry("unexpected data at %d:%d", lnum, offs + skip);
+	return 0;
 }
 
 /**
-- 
1.6.2.3



More information about the U-Boot mailing list