ANDROID: Incremental fs: Avoid continually recalculating hashes
With a verified file (use incfs_perf to create a verified file), throughput
measured using dd after dropping caches increases from 200M/s to 290M/s
Test: incfs_test passes
Bug: 155996534
Signed-off-by: Paul Lawrence <paullawrence@google.com>
Change-Id: I7abb5ad92e4167f82f3452acc9db322fec8307dd
Git-commit: adb33b84e3
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
a025eadde3
commit
c368bec884
@@ -8,6 +8,7 @@
|
|||||||
#include <linux/file.h>
|
#include <linux/file.h>
|
||||||
#include <linux/ktime.h>
|
#include <linux/ktime.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
|
#include <linux/pagemap.h>
|
||||||
#include <linux/lz4.h>
|
#include <linux/lz4.h>
|
||||||
#include <linux/crc32.h>
|
#include <linux/crc32.h>
|
||||||
|
|
||||||
@@ -366,7 +367,8 @@ 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,
|
static int validate_hash_tree(struct file *bf, struct data_file *df,
|
||||||
int block_index, struct mem_range data, u8 *buf)
|
int block_index, struct mem_range data,
|
||||||
|
u8 *tmp_buf)
|
||||||
{
|
{
|
||||||
u8 digest[INCFS_MAX_HASH_SIZE] = {};
|
u8 digest[INCFS_MAX_HASH_SIZE] = {};
|
||||||
struct mtree *tree = NULL;
|
struct mtree *tree = NULL;
|
||||||
@@ -379,6 +381,7 @@ static int validate_hash_tree(struct file *bf, struct data_file *df,
|
|||||||
int hash_per_block;
|
int hash_per_block;
|
||||||
int lvl = 0;
|
int lvl = 0;
|
||||||
int res;
|
int res;
|
||||||
|
struct page *saved_page = NULL;
|
||||||
|
|
||||||
tree = df->df_hash_tree;
|
tree = df->df_hash_tree;
|
||||||
sig = df->df_signature;
|
sig = df->df_signature;
|
||||||
@@ -400,17 +403,39 @@ static int validate_hash_tree(struct file *bf, struct data_file *df,
|
|||||||
INCFS_DATA_FILE_BLOCK_SIZE);
|
INCFS_DATA_FILE_BLOCK_SIZE);
|
||||||
size_t hash_off_in_block = hash_block_index * digest_size
|
size_t hash_off_in_block = hash_block_index * digest_size
|
||||||
% INCFS_DATA_FILE_BLOCK_SIZE;
|
% INCFS_DATA_FILE_BLOCK_SIZE;
|
||||||
struct mem_range buf_range = range(buf,
|
struct mem_range buf_range;
|
||||||
INCFS_DATA_FILE_BLOCK_SIZE);
|
struct page *page = NULL;
|
||||||
ssize_t read_res = incfs_kread(bf, buf,
|
bool aligned = (hash_block_off &
|
||||||
INCFS_DATA_FILE_BLOCK_SIZE, 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);
|
||||||
|
|
||||||
if (read_res < 0)
|
if (read_res < 0)
|
||||||
return read_res;
|
return read_res;
|
||||||
if (read_res != INCFS_DATA_FILE_BLOCK_SIZE)
|
if (read_res != INCFS_DATA_FILE_BLOCK_SIZE)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
saved_digest_rng = range(buf + hash_off_in_block, digest_size);
|
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);
|
||||||
if (!incfs_equal_ranges(calc_digest_rng, saved_digest_rng)) {
|
if (!incfs_equal_ranges(calc_digest_rng, saved_digest_rng)) {
|
||||||
int i;
|
int i;
|
||||||
bool zero = true;
|
bool zero = true;
|
||||||
@@ -425,9 +450,37 @@ static int validate_hash_tree(struct file *bf, struct data_file *df,
|
|||||||
|
|
||||||
if (zero)
|
if (zero)
|
||||||
pr_debug("incfs: Note saved_digest all zero - did you forget to load the hashes?\n");
|
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;
|
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);
|
res = incfs_calc_digest(tree->alg, buf_range, calc_digest_rng);
|
||||||
if (res)
|
if (res)
|
||||||
return res;
|
return res;
|
||||||
@@ -437,8 +490,15 @@ static int validate_hash_tree(struct file *bf, struct data_file *df,
|
|||||||
root_hash_rng = range(tree->root_hash, digest_size);
|
root_hash_rng = range(tree->root_hash, digest_size);
|
||||||
if (!incfs_equal_ranges(calc_digest_rng, root_hash_rng)) {
|
if (!incfs_equal_ranges(calc_digest_rng, root_hash_rng)) {
|
||||||
pr_debug("incfs: Root hash mismatch blk:%d\n", block_index);
|
pr_debug("incfs: Root hash mismatch blk:%d\n", block_index);
|
||||||
|
if (saved_page)
|
||||||
|
put_page(saved_page);
|
||||||
return -EBADMSG;
|
return -EBADMSG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (saved_page) {
|
||||||
|
SetPageChecked(saved_page);
|
||||||
|
put_page(saved_page);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user