[RFC PATCH mtd-utils 040/110] ubifs-utils: Adapt recovery subsystem in libubifs

Zhihao Cheng chengzhihao1 at huawei.com
Thu Jun 6 21:25:05 PDT 2024


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 at huawei.com>
---
 ubifs-utils/libubifs/recovery.c | 236 ++++------------------------------------
 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 f0d51dd2..910414cb 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 c59d47fe..ff9efaac 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;
-- 
2.13.6




More information about the linux-mtd mailing list