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:
committed by
Blagovest Kolenichev
parent
9e7d58e0a8
commit
5409507f89
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user