// SPDX-License-Identifier: GPL-2.0 /* * Copyright 2019 Google LLC */ #include "fsverity_private.h" #include #include #include /** * generic_read_merkle_tree_page - generic ->read_merkle_tree_page helper * @inode: inode containing the Merkle tree * @index: 0-based index of the Merkle tree page in the inode * * The caller needs to adjust @index from the Merkle-tree relative index passed * to ->read_merkle_tree_page to the actual index where the Merkle tree is * stored in the page cache for @inode. */ struct page *generic_read_merkle_tree_page(struct inode *inode, pgoff_t index) { struct folio *folio; folio = read_mapping_folio(inode->i_mapping, index, NULL); if (IS_ERR(folio)) return ERR_CAST(folio); return folio_file_page(folio, index); } EXPORT_SYMBOL_GPL(generic_read_merkle_tree_page); /** * generic_readahead_merkle_tree() - generic ->readahead_merkle_tree helper * @inode: inode containing the Merkle tree * @index: 0-based index of the first Merkle tree page to read ahead in the * inode * @nr_pages: the number of Merkle tree pages that should be read ahead * * The caller needs to adjust @index from the Merkle-tree relative index passed * to ->read_merkle_tree_page to the actual index where the Merkle tree is * stored in the page cache for @inode. */ void generic_readahead_merkle_tree(struct inode *inode, pgoff_t index, unsigned long nr_pages) { struct folio *folio; lockdep_assert_held(&inode->i_mapping->invalidate_lock); folio = __filemap_get_folio(inode->i_mapping, index, FGP_ACCESSED, 0); if (folio == ERR_PTR(-ENOENT) || (!IS_ERR(folio) && !folio_test_uptodate(folio))) { DEFINE_READAHEAD(ractl, NULL, NULL, inode->i_mapping, index); page_cache_ra_unbounded(&ractl, nr_pages, 0); } if (!IS_ERR(folio)) folio_put(folio); } EXPORT_SYMBOL_GPL(generic_readahead_merkle_tree); /** * fsverity_fill_zerohash() - fill folio with hashes of zero data block * @folio: folio to fill * @offset: offset in the folio to start * @len: length of the range to fill with hashes * @vi: fsverity info */ void fsverity_fill_zerohash(struct folio *folio, size_t offset, size_t len, struct fsverity_info *vi) { size_t off = offset; WARN_ON_ONCE(!IS_ALIGNED(offset, vi->tree_params.digest_size)); WARN_ON_ONCE(!IS_ALIGNED(len, vi->tree_params.digest_size)); for (; off < (offset + len); off += vi->tree_params.digest_size) memcpy_to_folio(folio, off, vi->tree_params.zero_digest, vi->tree_params.digest_size); } EXPORT_SYMBOL_GPL(fsverity_fill_zerohash); /** * fsverity_pagecache_read() - read verity metadata via the pagecache * @inode: copy from this inode's address space * @buf: buffer to copy to * @count: number of bytes to copy * @pos: byte offset in the file to copy from * * Read some verity metadata from the inode. __vfs_read() can't be used because * we need to read beyond i_size. */ int fsverity_pagecache_read(struct inode *inode, void *buf, size_t count, loff_t pos) { while (count) { struct folio *folio; size_t n; folio = read_mapping_folio(inode->i_mapping, pos >> PAGE_SHIFT, NULL); if (IS_ERR(folio)) return PTR_ERR(folio); n = memcpy_from_file_folio(buf, folio, pos, count); folio_put(folio); buf += n; pos += n; count -= n; } return 0; } EXPORT_SYMBOL_GPL(fsverity_pagecache_read);