diff options
| author | Zhihao Cheng <chengzhihao1@huawei.com> | 2024-11-11 16:37:02 +0800 | 
|---|---|---|
| committer | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2024-11-11 10:32:45 +0100 | 
| commit | f3dc08f6d88e89262433f0582a7750f6ff6791ae (patch) | |
| tree | d88638e383bb5bd7f3ca2ae6f82e0ea2da357096 /ubifs-utils | |
| parent | 711dcc3da36538c0d9d8a75eb33205b6d2708175 (diff) | |
ubifs-utils: Adapt recovery subsystem in libubifs
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>
Diffstat (limited to 'ubifs-utils')
| -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; | 
