mirror of
https://github.com/adulau/aha.git
synced 2024-12-29 04:06:22 +00:00
UBIFS: fix recovery bug
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@nokia.com>
This commit is contained in:
parent
963f0cf6d1
commit
de0975781a
1 changed files with 23 additions and 47 deletions
|
@ -425,59 +425,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
|
* @lnum: LEB number of the LEB from which @buf was read
|
||||||
* @offs: offset 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
|
* This function ensures that the corrupted node at @offs is the last thing
|
||||||
* %1 if no more nodes are found.
|
* 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,
|
static int no_more_nodes(const struct ubifs_info *c, void *buf, int len,
|
||||||
int lnum, int offs)
|
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) {
|
/* Check for empty space after the corrupt node's common header */
|
||||||
struct ubifs_ch *ch = buf;
|
skip = ALIGN(offs + UBIFS_CH_SZ, c->min_io_size) - offs;
|
||||||
int dlen = le32_to_cpu(ch->len);
|
if (is_empty(buf + skip, len - skip))
|
||||||
|
return 1;
|
||||||
if (ch->node_type == UBIFS_DATA_NODE && dlen >= UBIFS_CH_SZ &&
|
/*
|
||||||
dlen <= UBIFS_MAX_DATA_NODE_SZ)
|
* The area after the common header size is not empty, so the common
|
||||||
/* The corrupt node looks like a data node */
|
* header must be intact. Check it.
|
||||||
next_offs = ALIGN(offs + dlen, 8);
|
*/
|
||||||
|
if (ubifs_check_node(c, buf, lnum, offs, 1, 0) != -EUCLEAN) {
|
||||||
|
dbg_rcvry("unexpected bad common header at %d:%d", lnum, offs);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
/* Now we know the corrupt node's length we can skip over it */
|
||||||
if (c->min_io_size == 1)
|
skip = ALIGN(offs + dlen, c->min_io_size) - offs;
|
||||||
skip = 8;
|
/* After which there should be empty space */
|
||||||
else
|
if (is_empty(buf + skip, len - skip))
|
||||||
skip = ALIGN(offs + 1, c->min_io_size) - offs;
|
return 1;
|
||||||
|
dbg_rcvry("unexpected data at %d:%d", lnum, offs + skip);
|
||||||
offs += skip;
|
return 0;
|
||||||
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;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue