Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dee1afdd authored by Paul Lawrence's avatar Paul Lawrence
Browse files

Revert "ANDROID: Incremental fs: Avoid continually recalculating hashes"



This reverts commit ab185e45f637ba0b0239268f1130890c8837981d.

This change used the PageChecked flag to mark the Merkle tree as
checked. However, f2fs uses this internally. This caused file system
hangs on devices after installs.

Test: incfs_test passes, installs no longer hang
Bug: 157589629
Signed-off-by: default avatarPaul Lawrence <paullawrence@google.com>
Change-Id: I980a700d65eb4f4a77434715d61dda4b8e80658c
parent a4834780
Loading
Loading
Loading
Loading
+10 −70
Original line number Diff line number Diff line
@@ -9,7 +9,6 @@
#include <linux/ktime.h>
#include <linux/mm.h>
#include <linux/workqueue.h>
#include <linux/pagemap.h>
#include <linux/lz4.h>
#include <linux/crc32.h>

@@ -388,8 +387,7 @@ static void log_block_read(struct mount_info *mi, incfs_uuid_t *id,
}

static int validate_hash_tree(struct file *bf, struct data_file *df,
			      int block_index, struct mem_range data,
			      u8 *tmp_buf)
			      int block_index, struct mem_range data, u8 *buf)
{
	u8 digest[INCFS_MAX_HASH_SIZE] = {};
	struct mtree *tree = NULL;
@@ -402,7 +400,6 @@ static int validate_hash_tree(struct file *bf, struct data_file *df,
	int hash_per_block;
	int lvl = 0;
	int res;
	struct page *saved_page = NULL;

	tree = df->df_hash_tree;
	sig = df->df_signature;
@@ -424,39 +421,17 @@ static int validate_hash_tree(struct file *bf, struct data_file *df,
				INCFS_DATA_FILE_BLOCK_SIZE);
		size_t hash_off_in_block = hash_block_index * digest_size
			% INCFS_DATA_FILE_BLOCK_SIZE;
		struct mem_range buf_range;
		struct page *page = NULL;
		bool aligned = (hash_block_off &
				(INCFS_DATA_FILE_BLOCK_SIZE - 1)) == 0;
		u8 *actual_buf;

		if (aligned) {
			page = read_mapping_page(
				bf->f_inode->i_mapping,
				hash_block_off / INCFS_DATA_FILE_BLOCK_SIZE,
				NULL);

			if (IS_ERR(page))
				return PTR_ERR(page);

			actual_buf = page_address(page);
		} else {
			size_t read_res =
				incfs_kread(bf, tmp_buf,
					    INCFS_DATA_FILE_BLOCK_SIZE,
					    hash_block_off);
		struct mem_range buf_range = range(buf,
					INCFS_DATA_FILE_BLOCK_SIZE);
		ssize_t read_res = incfs_kread(bf, buf,
				INCFS_DATA_FILE_BLOCK_SIZE, hash_block_off);

		if (read_res < 0)
			return read_res;
		if (read_res != INCFS_DATA_FILE_BLOCK_SIZE)
			return -EIO;

			actual_buf = tmp_buf;
		}

		buf_range = range(actual_buf, INCFS_DATA_FILE_BLOCK_SIZE);
		saved_digest_rng =
			range(actual_buf + hash_off_in_block, digest_size);
		saved_digest_rng = range(buf + hash_off_in_block, digest_size);
		if (!incfs_equal_ranges(calc_digest_rng, saved_digest_rng)) {
			int i;
			bool zero = true;
@@ -471,37 +446,9 @@ static int validate_hash_tree(struct file *bf, struct data_file *df,

			if (zero)
				pr_debug("incfs: Note saved_digest all zero - did you forget to load the hashes?\n");

			if (saved_page)
				put_page(saved_page);
			if (page)
				put_page(page);
			return -EBADMSG;
		}

		if (saved_page) {
			/*
			 * This is something of a kludge. The PageChecked flag
			 * is reserved for the file system, but we are setting
			 * this on the pages belonging to the underlying file
			 * system. incfs is only going to be used on f2fs and
			 * ext4 which only use this flag when fs-verity is being
			 * used, so this is safe for now, however a better
			 * mechanism needs to be found.
			 */
			SetPageChecked(saved_page);
			put_page(saved_page);
			saved_page = NULL;
		}

		if (page && PageChecked(page)) {
			put_page(page);
			return 0;
		}

		saved_page = page;
		page = NULL;

		res = incfs_calc_digest(tree->alg, buf_range, calc_digest_rng);
		if (res)
			return res;
@@ -511,15 +458,8 @@ static int validate_hash_tree(struct file *bf, struct data_file *df,
	root_hash_rng = range(tree->root_hash, digest_size);
	if (!incfs_equal_ranges(calc_digest_rng, root_hash_rng)) {
		pr_debug("incfs: Root hash mismatch blk:%d\n", block_index);
		if (saved_page)
			put_page(saved_page);
		return -EBADMSG;
	}

	if (saved_page) {
		SetPageChecked(saved_page);
		put_page(saved_page);
	}
	return 0;
}