struct ubifs_mst_node *mst)
{
int err = 0, lnum = UBIFS_MST_LNUM, sz = c->mst_node_alsz;
- uint32_t save_flags;
+ __le32 save_flags;
dbg_rcvry("recovery");
save_flags = mst->flags;
- mst->flags = cpu_to_le32(le32_to_cpu(mst->flags) | UBIFS_MST_RCVRY);
+ mst->flags |= cpu_to_le32(UBIFS_MST_RCVRY);
ubifs_prepare_node(c, mst, UBIFS_MST_NODE_SZ, 1);
err = ubi_leb_change(c->ubi, lnum, mst, sz, UBI_SHORTTERM);
* @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;
}
/**
err = ubi_leb_change(c->ubi, lnum, c->sbuf, len, UBI_UNKNOWN);
if (err)
goto out;
- dbg_rcvry("inode %lu at %d:%d size %lld -> %lld ", e->inum, lnum, offs,
- i_size, e->d_size);
+ dbg_rcvry("inode %lu at %d:%d size %lld -> %lld ",
+ (unsigned long)e->inum, lnum, offs, i_size, e->d_size);
return 0;
out:
ubifs_warn("inode %lu failed to fix size %lld -> %lld error %d",
- e->inum, e->i_size, e->d_size, err);
+ (unsigned long)e->inum, e->i_size, e->d_size, err);
return err;
}
return err;
if (err == -ENOENT) {
/* Remove data nodes that have no inode */
- dbg_rcvry("removing ino %lu", e->inum);
+ dbg_rcvry("removing ino %lu",
+ (unsigned long)e->inum);
err = ubifs_tnc_remove_ino(c, e->inum);
if (err)
return err;
return PTR_ERR(inode);
if (inode->i_size < e->d_size) {
dbg_rcvry("ino %lu size %lld -> %lld",
- e->inum, e->d_size,
- inode->i_size);
+ (unsigned long)e->inum,
+ e->d_size, inode->i_size);
inode->i_size = e->d_size;
ubifs_inode(inode)->ui_size = e->d_size;
e->inode = inode;