]> www.infradead.org Git - mtd-utils.git/commitdiff
ubifs-utils: Adapt recovery subsystem in libubifs
authorZhihao Cheng <chengzhihao1@huawei.com>
Mon, 11 Nov 2024 08:37:02 +0000 (16:37 +0800)
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>
Mon, 11 Nov 2024 09:32:45 +0000 (10:32 +0100)
Adapt recovery subsystem(replay.c, recovery.c) in libubifs, compared with
linux kernel implementations:
 1. Remove authentication related implementations
    (eg. authenticate_sleb_hash), authentication is not supported in fsck
    for now.
 2. Add explicit type conversions(const char *) to avoid compiling
    warnings.
 3. Replace implementations of inode_fix_size() with ubifs_assert(0),
    authentication is not supported in fsck, so this function won't
    be invoked.
 4. Remove unused ubifs_clean_lebs() and ubifs_write_rcvrd_mst_node().
 5. Adapt fix_unclean_leb/recover_head/fix_size_in_place to ignore
    %-EBADMSG, subsequent steps will check nodes in lpt/main area
    carefully.

Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com>
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
ubifs-utils/libubifs/recovery.c
ubifs-utils/libubifs/replay.c

index f0d51dd21c9e13d5ba13e29f3caa703bc84e8b61..910414cb0ce44bb59aed0b312999b75c4e382fa0 100644 (file)
  * 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).
@@ -363,31 +371,6 @@ out_free:
        return err;
 }
 
-/**
- * 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
@@ -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);
        }
@@ -967,129 +950,6 @@ int ubifs_recover_inl_heads(struct ubifs_info *c, void *sbuf)
        return recover_head(c, c->nhead_lnum, c->nhead_offs, 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)
index c59d47fe79396f6f20d120516e7187b92f12196f..b1d0164823f00000da4e834275ce35859b3e123f 100644 (file)
  * 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;