diff options
Diffstat (limited to 'ubifs-utils/libubifs')
-rw-r--r-- | ubifs-utils/libubifs/recovery.c | 236 | ||||
-rw-r--r-- | ubifs-utils/libubifs/replay.c | 90 |
2 files changed, 35 insertions, 291 deletions
diff --git a/ubifs-utils/libubifs/recovery.c b/ubifs-utils/libubifs/recovery.c index f0d51dd..910414c 100644 --- a/ubifs-utils/libubifs/recovery.c +++ b/ubifs-utils/libubifs/recovery.c @@ -35,9 +35,17 @@ * refuses to mount. */ -#include <linux/crc32.h> -#include <linux/slab.h> +#include <sys/types.h> + +#include "linux_err.h" +#include "bitops.h" +#include "kmem.h" +#include "crc32.h" #include "ubifs.h" +#include "defs.h" +#include "debug.h" +#include "key.h" +#include "misc.h" /** * is_empty - determine whether a buffer is empty (contains all 0xff). @@ -364,31 +372,6 @@ out_free: } /** - * ubifs_write_rcvrd_mst_node - write the recovered master node. - * @c: UBIFS file-system description object - * - * This function writes the master node that was recovered during mounting in - * read-only mode and must now be written because we are remounting rw. - * - * This function returns %0 on success and a negative error code on failure. - */ -int ubifs_write_rcvrd_mst_node(struct ubifs_info *c) -{ - int err; - - if (!c->rcvrd_mst_node) - return 0; - c->rcvrd_mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY); - c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY); - err = write_rcvrd_mst_node(c, c->rcvrd_mst_node); - if (err) - return err; - kfree(c->rcvrd_mst_node); - c->rcvrd_mst_node = NULL; - return 0; -} - -/** * is_last_write - determine if an offset was in the last write to a LEB. * @c: UBIFS file-system description object * @buf: buffer to check @@ -530,7 +513,7 @@ static int fix_unclean_leb(struct ubifs_info *c, struct ubifs_scan_leb *sleb, if (start) { err = ubifs_leb_read(c, lnum, sleb->buf, 0, start, 1); - if (err) + if (err && err != -EBADMSG) return err; } /* Pad to min_io_size */ @@ -926,7 +909,7 @@ static int recover_head(struct ubifs_info *c, int lnum, int offs, void *sbuf) if (offs == 0) return ubifs_leb_unmap(c, lnum); err = ubifs_leb_read(c, lnum, sbuf, 0, offs, 1); - if (err) + if (err && err != -EBADMSG) return err; return ubifs_leb_change(c, lnum, sbuf, offs); } @@ -968,129 +951,6 @@ int ubifs_recover_inl_heads(struct ubifs_info *c, void *sbuf) } /** - * clean_an_unclean_leb - read and write a LEB to remove corruption. - * @c: UBIFS file-system description object - * @ucleb: unclean LEB information - * @sbuf: LEB-sized buffer to use - * - * This function reads a LEB up to a point pre-determined by the mount recovery, - * checks the nodes, and writes the result back to the flash, thereby cleaning - * off any following corruption, or non-fatal ECC errors. - * - * This function returns %0 on success and a negative error code on failure. - */ -static int clean_an_unclean_leb(struct ubifs_info *c, - struct ubifs_unclean_leb *ucleb, void *sbuf) -{ - int err, lnum = ucleb->lnum, offs = 0, len = ucleb->endpt, quiet = 1; - void *buf = sbuf; - - dbg_rcvry("LEB %d len %d", lnum, len); - - if (len == 0) { - /* Nothing to read, just unmap it */ - return ubifs_leb_unmap(c, lnum); - } - - err = ubifs_leb_read(c, lnum, buf, offs, len, 0); - if (err && err != -EBADMSG) - return err; - - while (len >= 8) { - int ret; - - cond_resched(); - - /* Scan quietly until there is an error */ - ret = ubifs_scan_a_node(c, buf, len, lnum, offs, quiet); - - if (ret == SCANNED_A_NODE) { - /* A valid node, and not a padding node */ - struct ubifs_ch *ch = buf; - int node_len; - - node_len = ALIGN(le32_to_cpu(ch->len), 8); - offs += node_len; - buf += node_len; - len -= node_len; - continue; - } - - if (ret > 0) { - /* Padding bytes or a valid padding node */ - offs += ret; - buf += ret; - len -= ret; - continue; - } - - if (ret == SCANNED_EMPTY_SPACE) { - ubifs_err(c, "unexpected empty space at %d:%d", - lnum, offs); - return -EUCLEAN; - } - - if (quiet) { - /* Redo the last scan but noisily */ - quiet = 0; - continue; - } - - ubifs_scanned_corruption(c, lnum, offs, buf); - return -EUCLEAN; - } - - /* Pad to min_io_size */ - len = ALIGN(ucleb->endpt, c->min_io_size); - if (len > ucleb->endpt) { - int pad_len = len - ALIGN(ucleb->endpt, 8); - - if (pad_len > 0) { - buf = c->sbuf + len - pad_len; - ubifs_pad(c, buf, pad_len); - } - } - - /* Write back the LEB atomically */ - err = ubifs_leb_change(c, lnum, sbuf, len); - if (err) - return err; - - dbg_rcvry("cleaned LEB %d", lnum); - - return 0; -} - -/** - * ubifs_clean_lebs - clean LEBs recovered during read-only mount. - * @c: UBIFS file-system description object - * @sbuf: LEB-sized buffer to use - * - * This function cleans a LEB identified during recovery that needs to be - * written but was not because UBIFS was mounted read-only. This happens when - * remounting to read-write mode. - * - * This function returns %0 on success and a negative error code on failure. - */ -int ubifs_clean_lebs(struct ubifs_info *c, void *sbuf) -{ - dbg_rcvry("recovery"); - while (!list_empty(&c->unclean_leb_list)) { - struct ubifs_unclean_leb *ucleb; - int err; - - ucleb = list_entry(c->unclean_leb_list.next, - struct ubifs_unclean_leb, list); - err = clean_an_unclean_leb(c, ucleb, sbuf); - if (err) - return err; - list_del(&ucleb->list); - kfree(ucleb); - } - return 0; -} - -/** * grab_empty_leb - grab an empty LEB to use as GC LEB and run commit. * @c: UBIFS file-system description object * @@ -1224,7 +1084,6 @@ int ubifs_rcvry_gc_commit(struct ubifs_info *c) * @i_size: size on inode * @d_size: maximum size based on data nodes * @exists: indicates whether the inode exists - * @inode: inode if pinned in memory awaiting rw mode to fix it */ struct size_entry { struct rb_node rb; @@ -1232,7 +1091,6 @@ struct size_entry { loff_t i_size; loff_t d_size; int exists; - struct inode *inode; }; /** @@ -1319,7 +1177,6 @@ void ubifs_destroy_size_tree(struct ubifs_info *c) struct size_entry *e, *n; rbtree_postorder_for_each_entry_safe(e, n, &c->size_tree, rb) { - iput(e->inode); kfree(e); } @@ -1422,7 +1279,7 @@ static int fix_size_in_place(struct ubifs_info *c, struct size_entry *e) return 0; /* Read the LEB */ err = ubifs_leb_read(c, lnum, c->sbuf, 0, c->leb_size, 1); - if (err) + if (err && err != -EBADMSG) goto out; /* Change the size field and recalculate the CRC */ ino = c->sbuf + offs; @@ -1441,12 +1298,14 @@ static int fix_size_in_place(struct ubifs_info *c, struct size_entry *e) if (err) goto out; dbg_rcvry("inode %lu at %d:%d size %lld -> %lld", - (unsigned long)e->inum, lnum, offs, i_size, e->d_size); + (unsigned long)e->inum, lnum, offs, (long long)i_size, + (long long)e->d_size); return 0; out: ubifs_warn(c, "inode %lu failed to fix size %lld -> %lld error %d", - (unsigned long)e->inum, e->i_size, e->d_size, err); + (unsigned long)e->inum, (long long)e->i_size, + (long long)e->d_size, err); return err; } @@ -1455,64 +1314,12 @@ out: * @c: UBIFS file-system description object * @e: inode size information for recovery */ -static int inode_fix_size(struct ubifs_info *c, struct size_entry *e) +static int inode_fix_size(struct ubifs_info *c, __unused struct size_entry *e) { - struct inode *inode; - struct ubifs_inode *ui; - int err; - - if (c->ro_mount) - ubifs_assert(c, !e->inode); - - if (e->inode) { - /* Remounting rw, pick up inode we stored earlier */ - inode = e->inode; - } else { - inode = ubifs_iget(c->vfs_sb, e->inum); - if (IS_ERR(inode)) - return PTR_ERR(inode); - - if (inode->i_size >= e->d_size) { - /* - * The original inode in the index already has a size - * big enough, nothing to do - */ - iput(inode); - return 0; - } - - dbg_rcvry("ino %lu size %lld -> %lld", - (unsigned long)e->inum, - inode->i_size, e->d_size); - - ui = ubifs_inode(inode); - - inode->i_size = e->d_size; - ui->ui_size = e->d_size; - ui->synced_i_size = e->d_size; + ubifs_assert(c, 0); - e->inode = inode; - } - - /* - * In readonly mode just keep the inode pinned in memory until we go - * readwrite. In readwrite mode write the inode to the journal with the - * fixed size. - */ - if (c->ro_mount) - return 0; - - err = ubifs_jnl_write_inode(c, inode); - - iput(inode); - - if (err) - return err; - - rb_erase(&e->rb, &c->size_tree); - kfree(e); - - return 0; + // To be implemented + return -EINVAL; } /** @@ -1571,7 +1378,6 @@ int ubifs_recover_size(struct ubifs_info *c, bool in_place) err = fix_size_in_place(c, e); if (err) return err; - iput(e->inode); } else { err = inode_fix_size(c, e); if (err) diff --git a/ubifs-utils/libubifs/replay.c b/ubifs-utils/libubifs/replay.c index c59d47f..b1d0164 100644 --- a/ubifs-utils/libubifs/replay.c +++ b/ubifs-utils/libubifs/replay.c @@ -20,9 +20,14 @@ * larger is the journal, the more memory its index may consume. */ +#include "linux_err.h" +#include "bitops.h" +#include "kmem.h" #include "ubifs.h" -#include <linux/list_sort.h> -#include <crypto/hash.h> +#include "defs.h" +#include "debug.h" +#include "key.h" +#include "misc.h" /** * struct replay_entry - replay list entry. @@ -485,7 +490,8 @@ int ubifs_validate_entry(struct ubifs_info *c, if (le32_to_cpu(dent->ch.len) != nlen + UBIFS_DENT_NODE_SZ + 1 || dent->type >= UBIFS_ITYPES_CNT || nlen > UBIFS_MAX_NLEN || dent->name[nlen] != 0 || - (key_type == UBIFS_XENT_KEY && strnlen(dent->name, nlen) != nlen) || + (key_type == UBIFS_XENT_KEY && + strnlen((const char *)dent->name, nlen) != nlen) || le64_to_cpu(dent->inum) > MAX_INUM) { ubifs_err(c, "bad %s node", key_type == UBIFS_DENT_KEY ? "directory entry" : "extended attribute entry"); @@ -558,19 +564,6 @@ static int is_last_bud(struct ubifs_info *c, struct ubifs_bud *bud) return data == 0xFFFFFFFF; } -/* authenticate_sleb_hash is split out for stack usage */ -static int noinline_for_stack -authenticate_sleb_hash(struct ubifs_info *c, - struct shash_desc *log_hash, u8 *hash) -{ - SHASH_DESC_ON_STACK(hash_desc, c->hash_tfm); - - hash_desc->tfm = c->hash_tfm; - - ubifs_shash_copy_state(c, log_hash, hash_desc); - return crypto_shash_final(hash_desc, hash); -} - /** * authenticate_sleb - authenticate one scan LEB * @c: UBIFS file-system description object @@ -588,69 +581,14 @@ authenticate_sleb_hash(struct ubifs_info *c, * that could be authenticated or a negative error code. */ static int authenticate_sleb(struct ubifs_info *c, struct ubifs_scan_leb *sleb, - struct shash_desc *log_hash, int is_last) + __unused struct shash_desc *log_hash, + __unused int is_last) { - int n_not_auth = 0; - struct ubifs_scan_node *snod; - int n_nodes = 0; - int err; - u8 hash[UBIFS_HASH_ARR_SZ]; - u8 hmac[UBIFS_HMAC_ARR_SZ]; - if (!ubifs_authenticated(c)) return sleb->nodes_cnt; - list_for_each_entry(snod, &sleb->nodes, list) { - - n_nodes++; - - if (snod->type == UBIFS_AUTH_NODE) { - struct ubifs_auth_node *auth = snod->node; - - err = authenticate_sleb_hash(c, log_hash, hash); - if (err) - goto out; - - err = crypto_shash_tfm_digest(c->hmac_tfm, hash, - c->hash_len, hmac); - if (err) - goto out; - - err = ubifs_check_hmac(c, auth->hmac, hmac); - if (err) { - err = -EPERM; - goto out; - } - n_not_auth = 0; - } else { - err = crypto_shash_update(log_hash, snod->node, - snod->len); - if (err) - goto out; - n_not_auth++; - } - } - - /* - * A powercut can happen when some nodes were written, but not yet - * the corresponding authentication node. This may only happen on - * the last bud though. - */ - if (n_not_auth) { - if (is_last) { - dbg_mnt("%d unauthenticated nodes found on LEB %d, Ignoring them", - n_not_auth, sleb->lnum); - err = 0; - } else { - dbg_mnt("%d unauthenticated nodes found on non-last LEB %d", - n_not_auth, sleb->lnum); - err = -EPERM; - } - } else { - err = 0; - } -out: - return err ? err : n_nodes - n_not_auth; + // To be implemented + return -EINVAL; } /** @@ -768,7 +706,7 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b) goto out_dump; err = insert_dent(c, lnum, snod->offs, snod->len, hash, - &snod->key, dent->name, + &snod->key, (const char *)dent->name, le16_to_cpu(dent->nlen), snod->sqnum, !le64_to_cpu(dent->inum), &used); break; |