diff options
Diffstat (limited to 'fs/verity/verify.c')
| -rw-r--r-- | fs/verity/verify.c | 76 |
1 files changed, 50 insertions, 26 deletions
diff --git a/fs/verity/verify.c b/fs/verity/verify.c index 86067c8b40cf..81e4c6012eb5 100644 --- a/fs/verity/verify.c +++ b/fs/verity/verify.c @@ -21,7 +21,6 @@ struct fsverity_pending_block { struct fsverity_verification_context { struct inode *inode; struct fsverity_info *vi; - unsigned long max_ra_pages; /* * This is the queue of data blocks that are pending verification. When @@ -37,6 +36,50 @@ struct fsverity_verification_context { static struct workqueue_struct *fsverity_read_workqueue; +/** + * fsverity_readahead() - kick off readahead on fsverity hashes + * @inode: inode that is being read + * @index: first file data page index that is being read + * @nr_pages: number of file data pages to be read + * + * Start readahead on the fsverity hashes that are needed to verify the file + * data in the range from @index to @index + @nr_pages (exclusive upper bound). + * + * To be called from the file systems' ->read_folio and ->readahead methods to + * ensure that the hashes are already cached on completion of the file data + * read if possible. + */ +void fsverity_readahead(struct inode *inode, pgoff_t index, + unsigned long nr_pages) +{ + const struct fsverity_info *vi = *fsverity_info_addr(inode); + const struct merkle_tree_params *params = &vi->tree_params; + u64 start_hidx = (u64)index << params->log_blocks_per_page; + u64 end_hidx = + (((u64)index + nr_pages) << params->log_blocks_per_page) - 1; + int level; + + if (!inode->i_sb->s_vop->readahead_merkle_tree) + return; + + for (level = 0; level < params->num_levels; level++) { + unsigned long level_start = params->level_start[level]; + unsigned long next_start_hidx = start_hidx >> params->log_arity; + unsigned long next_end_hidx = end_hidx >> params->log_arity; + pgoff_t start_idx = (level_start + next_start_hidx) >> + params->log_blocks_per_page; + pgoff_t end_idx = (level_start + next_end_hidx) >> + params->log_blocks_per_page; + + inode->i_sb->s_vop->readahead_merkle_tree( + inode, start_idx, end_idx - start_idx + 1); + + start_hidx = next_start_hidx; + end_hidx = next_end_hidx; + } +} +EXPORT_SYMBOL_GPL(fsverity_readahead); + /* * Returns true if the hash block with index @hblock_idx in the tree, located in * @hpage, has already been verified. @@ -114,8 +157,7 @@ static bool is_hash_block_verified(struct fsverity_info *vi, struct page *hpage, * Return: %true if the data block is valid, else %false. */ static bool verify_data_block(struct inode *inode, struct fsverity_info *vi, - const struct fsverity_pending_block *dblock, - unsigned long max_ra_pages) + const struct fsverity_pending_block *dblock) { const u64 data_pos = dblock->pos; const struct merkle_tree_params *params = &vi->tree_params; @@ -200,8 +242,7 @@ static bool verify_data_block(struct inode *inode, struct fsverity_info *vi, (params->block_size - 1); hpage = inode->i_sb->s_vop->read_merkle_tree_page(inode, - hpage_idx, level == 0 ? min(max_ra_pages, - params->tree_pages - hpage_idx) : 0); + hpage_idx); if (IS_ERR(hpage)) { fsverity_err(inode, "Error %ld reading Merkle tree page %lu", @@ -272,14 +313,12 @@ error: static void fsverity_init_verification_context(struct fsverity_verification_context *ctx, - struct inode *inode, - unsigned long max_ra_pages) + struct inode *inode) { struct fsverity_info *vi = *fsverity_info_addr(inode); ctx->inode = inode; ctx->vi = vi; - ctx->max_ra_pages = max_ra_pages; ctx->num_pending = 0; if (vi->tree_params.hash_alg->algo_id == HASH_ALGO_SHA256 && sha256_finup_2x_is_optimized()) @@ -322,8 +361,7 @@ fsverity_verify_pending_blocks(struct fsverity_verification_context *ctx) } for (i = 0; i < ctx->num_pending; i++) { - if (!verify_data_block(ctx->inode, vi, &ctx->pending_blocks[i], - ctx->max_ra_pages)) + if (!verify_data_block(ctx->inode, vi, &ctx->pending_blocks[i])) return false; } fsverity_clear_pending_blocks(ctx); @@ -373,7 +411,7 @@ bool fsverity_verify_blocks(struct folio *folio, size_t len, size_t offset) { struct fsverity_verification_context ctx; - fsverity_init_verification_context(&ctx, folio->mapping->host, 0); + fsverity_init_verification_context(&ctx, folio->mapping->host); if (fsverity_add_data_blocks(&ctx, folio, len, offset) && fsverity_verify_pending_blocks(&ctx)) @@ -403,22 +441,8 @@ void fsverity_verify_bio(struct bio *bio) struct inode *inode = bio_first_folio_all(bio)->mapping->host; struct fsverity_verification_context ctx; struct folio_iter fi; - unsigned long max_ra_pages = 0; - - if (bio->bi_opf & REQ_RAHEAD) { - /* - * If this bio is for data readahead, then we also do readahead - * of the first (largest) level of the Merkle tree. Namely, - * when a Merkle tree page is read, we also try to piggy-back on - * some additional pages -- up to 1/4 the number of data pages. - * - * This improves sequential read performance, as it greatly - * reduces the number of I/O requests made to the Merkle tree. - */ - max_ra_pages = bio->bi_iter.bi_size >> (PAGE_SHIFT + 2); - } - fsverity_init_verification_context(&ctx, inode, max_ra_pages); + fsverity_init_verification_context(&ctx, inode); bio_for_each_folio_all(fi, bio) { if (!fsverity_add_data_blocks(&ctx, fi.folio, fi.length, |
