162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Data verification functions, i.e. hooks for ->readahead() 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2019 Google LLC 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "fsverity_private.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <crypto/hash.h> 1162306a36Sopenharmony_ci#include <linux/bio.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_cistatic struct workqueue_struct *fsverity_read_workqueue; 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci/* 1662306a36Sopenharmony_ci * Returns true if the hash block with index @hblock_idx in the tree, located in 1762306a36Sopenharmony_ci * @hpage, has already been verified. 1862306a36Sopenharmony_ci */ 1962306a36Sopenharmony_cistatic bool is_hash_block_verified(struct fsverity_info *vi, struct page *hpage, 2062306a36Sopenharmony_ci unsigned long hblock_idx) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci bool verified; 2362306a36Sopenharmony_ci unsigned int blocks_per_page; 2462306a36Sopenharmony_ci unsigned int i; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci /* 2762306a36Sopenharmony_ci * When the Merkle tree block size and page size are the same, then the 2862306a36Sopenharmony_ci * ->hash_block_verified bitmap isn't allocated, and we use PG_checked 2962306a36Sopenharmony_ci * to directly indicate whether the page's block has been verified. 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci * Using PG_checked also guarantees that we re-verify hash pages that 3262306a36Sopenharmony_ci * get evicted and re-instantiated from the backing storage, as new 3362306a36Sopenharmony_ci * pages always start out with PG_checked cleared. 3462306a36Sopenharmony_ci */ 3562306a36Sopenharmony_ci if (!vi->hash_block_verified) 3662306a36Sopenharmony_ci return PageChecked(hpage); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci /* 3962306a36Sopenharmony_ci * When the Merkle tree block size and page size differ, we use a bitmap 4062306a36Sopenharmony_ci * to indicate whether each hash block has been verified. 4162306a36Sopenharmony_ci * 4262306a36Sopenharmony_ci * However, we still need to ensure that hash pages that get evicted and 4362306a36Sopenharmony_ci * re-instantiated from the backing storage are re-verified. To do 4462306a36Sopenharmony_ci * this, we use PG_checked again, but now it doesn't really mean 4562306a36Sopenharmony_ci * "checked". Instead, now it just serves as an indicator for whether 4662306a36Sopenharmony_ci * the hash page is newly instantiated or not. 4762306a36Sopenharmony_ci * 4862306a36Sopenharmony_ci * The first thread that sees PG_checked=0 must clear the corresponding 4962306a36Sopenharmony_ci * bitmap bits, then set PG_checked=1. This requires a spinlock. To 5062306a36Sopenharmony_ci * avoid having to take this spinlock in the common case of 5162306a36Sopenharmony_ci * PG_checked=1, we start with an opportunistic lockless read. 5262306a36Sopenharmony_ci */ 5362306a36Sopenharmony_ci if (PageChecked(hpage)) { 5462306a36Sopenharmony_ci /* 5562306a36Sopenharmony_ci * A read memory barrier is needed here to give ACQUIRE 5662306a36Sopenharmony_ci * semantics to the above PageChecked() test. 5762306a36Sopenharmony_ci */ 5862306a36Sopenharmony_ci smp_rmb(); 5962306a36Sopenharmony_ci return test_bit(hblock_idx, vi->hash_block_verified); 6062306a36Sopenharmony_ci } 6162306a36Sopenharmony_ci spin_lock(&vi->hash_page_init_lock); 6262306a36Sopenharmony_ci if (PageChecked(hpage)) { 6362306a36Sopenharmony_ci verified = test_bit(hblock_idx, vi->hash_block_verified); 6462306a36Sopenharmony_ci } else { 6562306a36Sopenharmony_ci blocks_per_page = vi->tree_params.blocks_per_page; 6662306a36Sopenharmony_ci hblock_idx = round_down(hblock_idx, blocks_per_page); 6762306a36Sopenharmony_ci for (i = 0; i < blocks_per_page; i++) 6862306a36Sopenharmony_ci clear_bit(hblock_idx + i, vi->hash_block_verified); 6962306a36Sopenharmony_ci /* 7062306a36Sopenharmony_ci * A write memory barrier is needed here to give RELEASE 7162306a36Sopenharmony_ci * semantics to the below SetPageChecked() operation. 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_ci smp_wmb(); 7462306a36Sopenharmony_ci SetPageChecked(hpage); 7562306a36Sopenharmony_ci verified = false; 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci spin_unlock(&vi->hash_page_init_lock); 7862306a36Sopenharmony_ci return verified; 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/* 8262306a36Sopenharmony_ci * Verify a single data block against the file's Merkle tree. 8362306a36Sopenharmony_ci * 8462306a36Sopenharmony_ci * In principle, we need to verify the entire path to the root node. However, 8562306a36Sopenharmony_ci * for efficiency the filesystem may cache the hash blocks. Therefore we need 8662306a36Sopenharmony_ci * only ascend the tree until an already-verified hash block is seen, and then 8762306a36Sopenharmony_ci * verify the path to that block. 8862306a36Sopenharmony_ci * 8962306a36Sopenharmony_ci * Return: %true if the data block is valid, else %false. 9062306a36Sopenharmony_ci */ 9162306a36Sopenharmony_cistatic bool 9262306a36Sopenharmony_civerify_data_block(struct inode *inode, struct fsverity_info *vi, 9362306a36Sopenharmony_ci const void *data, u64 data_pos, unsigned long max_ra_pages) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci const struct merkle_tree_params *params = &vi->tree_params; 9662306a36Sopenharmony_ci const unsigned int hsize = params->digest_size; 9762306a36Sopenharmony_ci int level; 9862306a36Sopenharmony_ci u8 _want_hash[FS_VERITY_MAX_DIGEST_SIZE]; 9962306a36Sopenharmony_ci const u8 *want_hash; 10062306a36Sopenharmony_ci u8 real_hash[FS_VERITY_MAX_DIGEST_SIZE]; 10162306a36Sopenharmony_ci /* The hash blocks that are traversed, indexed by level */ 10262306a36Sopenharmony_ci struct { 10362306a36Sopenharmony_ci /* Page containing the hash block */ 10462306a36Sopenharmony_ci struct page *page; 10562306a36Sopenharmony_ci /* Mapped address of the hash block (will be within @page) */ 10662306a36Sopenharmony_ci const void *addr; 10762306a36Sopenharmony_ci /* Index of the hash block in the tree overall */ 10862306a36Sopenharmony_ci unsigned long index; 10962306a36Sopenharmony_ci /* Byte offset of the wanted hash relative to @addr */ 11062306a36Sopenharmony_ci unsigned int hoffset; 11162306a36Sopenharmony_ci } hblocks[FS_VERITY_MAX_LEVELS]; 11262306a36Sopenharmony_ci /* 11362306a36Sopenharmony_ci * The index of the previous level's block within that level; also the 11462306a36Sopenharmony_ci * index of that block's hash within the current level. 11562306a36Sopenharmony_ci */ 11662306a36Sopenharmony_ci u64 hidx = data_pos >> params->log_blocksize; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci /* Up to 1 + FS_VERITY_MAX_LEVELS pages may be mapped at once */ 11962306a36Sopenharmony_ci BUILD_BUG_ON(1 + FS_VERITY_MAX_LEVELS > KM_MAX_IDX); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci if (unlikely(data_pos >= inode->i_size)) { 12262306a36Sopenharmony_ci /* 12362306a36Sopenharmony_ci * This can happen in the data page spanning EOF when the Merkle 12462306a36Sopenharmony_ci * tree block size is less than the page size. The Merkle tree 12562306a36Sopenharmony_ci * doesn't cover data blocks fully past EOF. But the entire 12662306a36Sopenharmony_ci * page spanning EOF can be visible to userspace via a mmap, and 12762306a36Sopenharmony_ci * any part past EOF should be all zeroes. Therefore, we need 12862306a36Sopenharmony_ci * to verify that any data blocks fully past EOF are all zeroes. 12962306a36Sopenharmony_ci */ 13062306a36Sopenharmony_ci if (memchr_inv(data, 0, params->block_size)) { 13162306a36Sopenharmony_ci fsverity_err(inode, 13262306a36Sopenharmony_ci "FILE CORRUPTED! Data past EOF is not zeroed"); 13362306a36Sopenharmony_ci return false; 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci return true; 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci#ifdef CONFIG_SECURITY_CODE_SIGN 13962306a36Sopenharmony_ci if (data_pos >= vi->verified_data_size) { 14062306a36Sopenharmony_ci pr_debug_ratelimited("Data[%lu] out of verity range %lu\n", 14162306a36Sopenharmony_ci data_pos, vi->verified_data_size); 14262306a36Sopenharmony_ci return true; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci#endif 14562306a36Sopenharmony_ci /* 14662306a36Sopenharmony_ci * Starting at the leaf level, ascend the tree saving hash blocks along 14762306a36Sopenharmony_ci * the way until we find a hash block that has already been verified, or 14862306a36Sopenharmony_ci * until we reach the root. 14962306a36Sopenharmony_ci */ 15062306a36Sopenharmony_ci for (level = 0; level < params->num_levels; level++) { 15162306a36Sopenharmony_ci unsigned long next_hidx; 15262306a36Sopenharmony_ci unsigned long hblock_idx; 15362306a36Sopenharmony_ci pgoff_t hpage_idx; 15462306a36Sopenharmony_ci unsigned int hblock_offset_in_page; 15562306a36Sopenharmony_ci unsigned int hoffset; 15662306a36Sopenharmony_ci struct page *hpage; 15762306a36Sopenharmony_ci const void *haddr; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci /* 16062306a36Sopenharmony_ci * The index of the block in the current level; also the index 16162306a36Sopenharmony_ci * of that block's hash within the next level. 16262306a36Sopenharmony_ci */ 16362306a36Sopenharmony_ci next_hidx = hidx >> params->log_arity; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci /* Index of the hash block in the tree overall */ 16662306a36Sopenharmony_ci hblock_idx = params->level_start[level] + next_hidx; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci /* Index of the hash page in the tree overall */ 16962306a36Sopenharmony_ci hpage_idx = hblock_idx >> params->log_blocks_per_page; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci /* Byte offset of the hash block within the page */ 17262306a36Sopenharmony_ci hblock_offset_in_page = 17362306a36Sopenharmony_ci (hblock_idx << params->log_blocksize) & ~PAGE_MASK; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci /* Byte offset of the hash within the block */ 17662306a36Sopenharmony_ci hoffset = (hidx << params->log_digestsize) & 17762306a36Sopenharmony_ci (params->block_size - 1); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci hpage = inode->i_sb->s_vop->read_merkle_tree_page(inode, 18062306a36Sopenharmony_ci hpage_idx, level == 0 ? min(max_ra_pages, 18162306a36Sopenharmony_ci params->tree_pages - hpage_idx) : 0); 18262306a36Sopenharmony_ci if (IS_ERR(hpage)) { 18362306a36Sopenharmony_ci fsverity_err(inode, 18462306a36Sopenharmony_ci "Error %ld reading Merkle tree page %lu", 18562306a36Sopenharmony_ci PTR_ERR(hpage), hpage_idx); 18662306a36Sopenharmony_ci goto error; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci haddr = kmap_local_page(hpage) + hblock_offset_in_page; 18962306a36Sopenharmony_ci if (is_hash_block_verified(vi, hpage, hblock_idx)) { 19062306a36Sopenharmony_ci memcpy(_want_hash, haddr + hoffset, hsize); 19162306a36Sopenharmony_ci want_hash = _want_hash; 19262306a36Sopenharmony_ci kunmap_local(haddr); 19362306a36Sopenharmony_ci put_page(hpage); 19462306a36Sopenharmony_ci goto descend; 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci hblocks[level].page = hpage; 19762306a36Sopenharmony_ci hblocks[level].addr = haddr; 19862306a36Sopenharmony_ci hblocks[level].index = hblock_idx; 19962306a36Sopenharmony_ci hblocks[level].hoffset = hoffset; 20062306a36Sopenharmony_ci hidx = next_hidx; 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci want_hash = vi->root_hash; 20462306a36Sopenharmony_cidescend: 20562306a36Sopenharmony_ci /* Descend the tree verifying hash blocks. */ 20662306a36Sopenharmony_ci for (; level > 0; level--) { 20762306a36Sopenharmony_ci struct page *hpage = hblocks[level - 1].page; 20862306a36Sopenharmony_ci const void *haddr = hblocks[level - 1].addr; 20962306a36Sopenharmony_ci unsigned long hblock_idx = hblocks[level - 1].index; 21062306a36Sopenharmony_ci unsigned int hoffset = hblocks[level - 1].hoffset; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if (fsverity_hash_block(params, inode, haddr, real_hash) != 0) 21362306a36Sopenharmony_ci goto error; 21462306a36Sopenharmony_ci if (memcmp(want_hash, real_hash, hsize) != 0) 21562306a36Sopenharmony_ci goto corrupted; 21662306a36Sopenharmony_ci /* 21762306a36Sopenharmony_ci * Mark the hash block as verified. This must be atomic and 21862306a36Sopenharmony_ci * idempotent, as the same hash block might be verified by 21962306a36Sopenharmony_ci * multiple threads concurrently. 22062306a36Sopenharmony_ci */ 22162306a36Sopenharmony_ci if (vi->hash_block_verified) 22262306a36Sopenharmony_ci set_bit(hblock_idx, vi->hash_block_verified); 22362306a36Sopenharmony_ci else 22462306a36Sopenharmony_ci SetPageChecked(hpage); 22562306a36Sopenharmony_ci memcpy(_want_hash, haddr + hoffset, hsize); 22662306a36Sopenharmony_ci want_hash = _want_hash; 22762306a36Sopenharmony_ci kunmap_local(haddr); 22862306a36Sopenharmony_ci put_page(hpage); 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci /* Finally, verify the data block. */ 23262306a36Sopenharmony_ci if (fsverity_hash_block(params, inode, data, real_hash) != 0) 23362306a36Sopenharmony_ci goto error; 23462306a36Sopenharmony_ci if (memcmp(want_hash, real_hash, hsize) != 0) 23562306a36Sopenharmony_ci goto corrupted; 23662306a36Sopenharmony_ci return true; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cicorrupted: 23962306a36Sopenharmony_ci fsverity_err(inode, 24062306a36Sopenharmony_ci "FILE CORRUPTED! pos=%llu, level=%d, want_hash=%s:%*phN, real_hash=%s:%*phN", 24162306a36Sopenharmony_ci data_pos, level - 1, 24262306a36Sopenharmony_ci params->hash_alg->name, hsize, want_hash, 24362306a36Sopenharmony_ci params->hash_alg->name, hsize, real_hash); 24462306a36Sopenharmony_cierror: 24562306a36Sopenharmony_ci for (; level > 0; level--) { 24662306a36Sopenharmony_ci kunmap_local(hblocks[level - 1].addr); 24762306a36Sopenharmony_ci put_page(hblocks[level - 1].page); 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci return false; 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_cistatic bool 25362306a36Sopenharmony_civerify_data_blocks(struct folio *data_folio, size_t len, size_t offset, 25462306a36Sopenharmony_ci unsigned long max_ra_pages) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci struct inode *inode = data_folio->mapping->host; 25762306a36Sopenharmony_ci struct fsverity_info *vi = inode->i_verity_info; 25862306a36Sopenharmony_ci const unsigned int block_size = vi->tree_params.block_size; 25962306a36Sopenharmony_ci u64 pos = (u64)data_folio->index << PAGE_SHIFT; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci if (WARN_ON_ONCE(len <= 0 || !IS_ALIGNED(len | offset, block_size))) 26262306a36Sopenharmony_ci return false; 26362306a36Sopenharmony_ci if (WARN_ON_ONCE(!folio_test_locked(data_folio) || 26462306a36Sopenharmony_ci folio_test_uptodate(data_folio))) 26562306a36Sopenharmony_ci return false; 26662306a36Sopenharmony_ci do { 26762306a36Sopenharmony_ci void *data; 26862306a36Sopenharmony_ci bool valid; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci data = kmap_local_folio(data_folio, offset); 27162306a36Sopenharmony_ci valid = verify_data_block(inode, vi, data, pos + offset, 27262306a36Sopenharmony_ci max_ra_pages); 27362306a36Sopenharmony_ci kunmap_local(data); 27462306a36Sopenharmony_ci if (!valid) 27562306a36Sopenharmony_ci return false; 27662306a36Sopenharmony_ci offset += block_size; 27762306a36Sopenharmony_ci len -= block_size; 27862306a36Sopenharmony_ci } while (len); 27962306a36Sopenharmony_ci return true; 28062306a36Sopenharmony_ci} 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci/** 28362306a36Sopenharmony_ci * fsverity_verify_blocks() - verify data in a folio 28462306a36Sopenharmony_ci * @folio: the folio containing the data to verify 28562306a36Sopenharmony_ci * @len: the length of the data to verify in the folio 28662306a36Sopenharmony_ci * @offset: the offset of the data to verify in the folio 28762306a36Sopenharmony_ci * 28862306a36Sopenharmony_ci * Verify data that has just been read from a verity file. The data must be 28962306a36Sopenharmony_ci * located in a pagecache folio that is still locked and not yet uptodate. The 29062306a36Sopenharmony_ci * length and offset of the data must be Merkle tree block size aligned. 29162306a36Sopenharmony_ci * 29262306a36Sopenharmony_ci * Return: %true if the data is valid, else %false. 29362306a36Sopenharmony_ci */ 29462306a36Sopenharmony_cibool fsverity_verify_blocks(struct folio *folio, size_t len, size_t offset) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci return verify_data_blocks(folio, len, offset, 0); 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(fsverity_verify_blocks); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci#ifdef CONFIG_BLOCK 30162306a36Sopenharmony_ci/** 30262306a36Sopenharmony_ci * fsverity_verify_bio() - verify a 'read' bio that has just completed 30362306a36Sopenharmony_ci * @bio: the bio to verify 30462306a36Sopenharmony_ci * 30562306a36Sopenharmony_ci * Verify the bio's data against the file's Merkle tree. All bio data segments 30662306a36Sopenharmony_ci * must be aligned to the file's Merkle tree block size. If any data fails 30762306a36Sopenharmony_ci * verification, then bio->bi_status is set to an error status. 30862306a36Sopenharmony_ci * 30962306a36Sopenharmony_ci * This is a helper function for use by the ->readahead() method of filesystems 31062306a36Sopenharmony_ci * that issue bios to read data directly into the page cache. Filesystems that 31162306a36Sopenharmony_ci * populate the page cache without issuing bios (e.g. non block-based 31262306a36Sopenharmony_ci * filesystems) must instead call fsverity_verify_page() directly on each page. 31362306a36Sopenharmony_ci * All filesystems must also call fsverity_verify_page() on holes. 31462306a36Sopenharmony_ci */ 31562306a36Sopenharmony_civoid fsverity_verify_bio(struct bio *bio) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci struct folio_iter fi; 31862306a36Sopenharmony_ci unsigned long max_ra_pages = 0; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci if (bio->bi_opf & REQ_RAHEAD) { 32162306a36Sopenharmony_ci /* 32262306a36Sopenharmony_ci * If this bio is for data readahead, then we also do readahead 32362306a36Sopenharmony_ci * of the first (largest) level of the Merkle tree. Namely, 32462306a36Sopenharmony_ci * when a Merkle tree page is read, we also try to piggy-back on 32562306a36Sopenharmony_ci * some additional pages -- up to 1/4 the number of data pages. 32662306a36Sopenharmony_ci * 32762306a36Sopenharmony_ci * This improves sequential read performance, as it greatly 32862306a36Sopenharmony_ci * reduces the number of I/O requests made to the Merkle tree. 32962306a36Sopenharmony_ci */ 33062306a36Sopenharmony_ci max_ra_pages = bio->bi_iter.bi_size >> (PAGE_SHIFT + 2); 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci bio_for_each_folio_all(fi, bio) { 33462306a36Sopenharmony_ci if (!verify_data_blocks(fi.folio, fi.length, fi.offset, 33562306a36Sopenharmony_ci max_ra_pages)) { 33662306a36Sopenharmony_ci bio->bi_status = BLK_STS_IOERR; 33762306a36Sopenharmony_ci break; 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(fsverity_verify_bio); 34262306a36Sopenharmony_ci#endif /* CONFIG_BLOCK */ 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci/** 34562306a36Sopenharmony_ci * fsverity_get_verified_data_size() - get verified data size of a verity file 34662306a36Sopenharmony_ci * @inode: the file's inode 34762306a36Sopenharmony_ci * 34862306a36Sopenharmony_ci * Return: verified data size 34962306a36Sopenharmony_ci */ 35062306a36Sopenharmony_ciu64 fsverity_get_verified_data_size(const struct inode *inode) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci#ifdef CONFIG_SECURITY_CODE_SIGN 35362306a36Sopenharmony_ci return fsverity_get_info(inode)->verified_data_size; 35462306a36Sopenharmony_ci#else 35562306a36Sopenharmony_ci return inode->i_size; 35662306a36Sopenharmony_ci#endif 35762306a36Sopenharmony_ci} 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci/** 36062306a36Sopenharmony_ci * fsverity_enqueue_verify_work() - enqueue work on the fs-verity workqueue 36162306a36Sopenharmony_ci * @work: the work to enqueue 36262306a36Sopenharmony_ci * 36362306a36Sopenharmony_ci * Enqueue verification work for asynchronous processing. 36462306a36Sopenharmony_ci */ 36562306a36Sopenharmony_civoid fsverity_enqueue_verify_work(struct work_struct *work) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci queue_work(fsverity_read_workqueue, work); 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(fsverity_enqueue_verify_work); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_civoid __init fsverity_init_workqueue(void) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci /* 37462306a36Sopenharmony_ci * Use a high-priority workqueue to prioritize verification work, which 37562306a36Sopenharmony_ci * blocks reads from completing, over regular application tasks. 37662306a36Sopenharmony_ci * 37762306a36Sopenharmony_ci * For performance reasons, don't use an unbound workqueue. Using an 37862306a36Sopenharmony_ci * unbound workqueue for crypto operations causes excessive scheduler 37962306a36Sopenharmony_ci * latency on ARM64. 38062306a36Sopenharmony_ci */ 38162306a36Sopenharmony_ci fsverity_read_workqueue = alloc_workqueue("fsverity_read_queue", 38262306a36Sopenharmony_ci WQ_HIGHPRI, 38362306a36Sopenharmony_ci num_online_cpus()); 38462306a36Sopenharmony_ci if (!fsverity_read_workqueue) 38562306a36Sopenharmony_ci panic("failed to allocate fsverity_read_queue"); 38662306a36Sopenharmony_ci} 387