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: Paul Lawrence <paullawrence@google.com>
Change-Id: I980a700d65eb4f4a77434715d61dda4b8e80658c
Git-commit: e2ca3e718475d1c9f5f33bfe00b85c85d92a141b
Git-repo: https://android.googlesource.com/kernel/common/
Signed-off-by: Sayali Lokhande <sayalil@codeaurora.org>
This commit is contained in:
Paul Lawrence
2020-05-27 14:00:12 -07:00
committed by Blagovest Kolenichev
parent 9e7d58e0a8
commit 5409507f89

View File

@@ -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;
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 (aligned) {
page = read_mapping_page(
bf->f_inode->i_mapping,
hash_block_off / INCFS_DATA_FILE_BLOCK_SIZE,
NULL);
if (read_res < 0)
return read_res;
if (read_res != INCFS_DATA_FILE_BLOCK_SIZE)
return -EIO;
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);
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;
}