fs/verity/verify.c

Source file repositories/reference/linux-study-clean/fs/verity/verify.c

File Facts

System
Linux kernel
Corpus path
fs/verity/verify.c
Extension
.c
Size
16306 bytes
Lines
500
Domain
Core OS
Bucket
VFS And Filesystem Core
Inferred role
Core OS: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

struct fsverity_pending_block {
	const void *data;
	u64 pos;
	u8 real_hash[FS_VERITY_MAX_DIGEST_SIZE];
};

struct fsverity_verification_context {
	struct fsverity_info *vi;

	/*
	 * This is the queue of data blocks that are pending verification.  When
	 * the crypto layer supports interleaved hashing, we allow multiple
	 * blocks to be queued up in order to utilize it.  This can improve
	 * performance significantly vs. sequential hashing of each block.
	 */
	int num_pending;
	int max_pending;
	struct fsverity_pending_block
		pending_blocks[FS_VERITY_MAX_PENDING_BLOCKS];
};

static struct workqueue_struct *fsverity_read_workqueue;

/**
 * fsverity_readahead() - kick off readahead on fsverity hashes
 * @vi:			fsverity_info for the inode to be 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 fsverity_info *vi, pgoff_t index,
			unsigned long nr_pages)
{
	struct inode *inode = vi->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.
 */
static bool is_hash_block_verified(struct fsverity_info *vi, struct page *hpage,
				   unsigned long hblock_idx)
{
	unsigned int blocks_per_page;
	unsigned int i;

	/*
	 * When the Merkle tree block size and page size are the same, then the
	 * ->hash_block_verified bitmap isn't allocated, and we use PG_checked
	 * to directly indicate whether the page's block has been verified.
	 *
	 * Using PG_checked also guarantees that we re-verify hash pages that
	 * get evicted and re-instantiated from the backing storage, as new
	 * pages always start out with PG_checked cleared.
	 */
	if (!vi->hash_block_verified)
		return PageChecked(hpage);

	/*

Annotation

Implementation Notes