1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright 2019 Google LLC 4 */ 5 #include "fsverity_private.h" 6 7 #include <linux/export.h> 8 #include <linux/fsverity.h> 9 #include <linux/pagemap.h> 10 11 /** 12 * generic_read_merkle_tree_page - generic ->read_merkle_tree_page helper 13 * @inode: inode containing the Merkle tree 14 * @index: 0-based index of the Merkle tree page in the inode 15 * 16 * The caller needs to adjust @index from the Merkle-tree relative index passed 17 * to ->read_merkle_tree_page to the actual index where the Merkle tree is 18 * stored in the page cache for @inode. 19 */ 20 struct page *generic_read_merkle_tree_page(struct inode *inode, pgoff_t index) 21 { 22 struct folio *folio; 23 24 folio = read_mapping_folio(inode->i_mapping, index, NULL); 25 if (IS_ERR(folio)) 26 return ERR_CAST(folio); 27 return folio_file_page(folio, index); 28 } 29 EXPORT_SYMBOL_GPL(generic_read_merkle_tree_page); 30 31 /** 32 * generic_readahead_merkle_tree() - generic ->readahead_merkle_tree helper 33 * @inode: inode containing the Merkle tree 34 * @index: 0-based index of the first Merkle tree page to read ahead in the 35 * inode 36 * @nr_pages: the number of Merkle tree pages that should be read ahead 37 * 38 * The caller needs to adjust @index from the Merkle-tree relative index passed 39 * to ->read_merkle_tree_page to the actual index where the Merkle tree is 40 * stored in the page cache for @inode. 41 */ 42 void generic_readahead_merkle_tree(struct inode *inode, pgoff_t index, 43 unsigned long nr_pages) 44 { 45 struct folio *folio; 46 47 lockdep_assert_held(&inode->i_mapping->invalidate_lock); 48 49 folio = __filemap_get_folio(inode->i_mapping, index, FGP_ACCESSED, 0); 50 if (folio == ERR_PTR(-ENOENT) || 51 (!IS_ERR(folio) && !folio_test_uptodate(folio))) { 52 DEFINE_READAHEAD(ractl, NULL, NULL, inode->i_mapping, index); 53 54 page_cache_ra_unbounded(&ractl, nr_pages, 0); 55 } 56 if (!IS_ERR(folio)) 57 folio_put(folio); 58 } 59 EXPORT_SYMBOL_GPL(generic_readahead_merkle_tree); 60 61 /** 62 * fsverity_fill_zerohash() - fill folio with hashes of zero data block 63 * @folio: folio to fill 64 * @offset: offset in the folio to start 65 * @len: length of the range to fill with hashes 66 * @vi: fsverity info 67 */ 68 void fsverity_fill_zerohash(struct folio *folio, size_t offset, size_t len, 69 struct fsverity_info *vi) 70 { 71 size_t off = offset; 72 73 WARN_ON_ONCE(!IS_ALIGNED(offset, vi->tree_params.digest_size)); 74 WARN_ON_ONCE(!IS_ALIGNED(len, vi->tree_params.digest_size)); 75 76 for (; off < (offset + len); off += vi->tree_params.digest_size) 77 memcpy_to_folio(folio, off, vi->tree_params.zero_digest, 78 vi->tree_params.digest_size); 79 } 80 EXPORT_SYMBOL_GPL(fsverity_fill_zerohash); 81 82 /** 83 * fsverity_pagecache_read() - read verity metadata via the pagecache 84 * @inode: copy from this inode's address space 85 * @buf: buffer to copy to 86 * @count: number of bytes to copy 87 * @pos: byte offset in the file to copy from 88 * 89 * Read some verity metadata from the inode. __vfs_read() can't be used because 90 * we need to read beyond i_size. 91 */ 92 int fsverity_pagecache_read(struct inode *inode, void *buf, size_t count, 93 loff_t pos) 94 { 95 while (count) { 96 struct folio *folio; 97 size_t n; 98 99 folio = read_mapping_folio(inode->i_mapping, pos >> PAGE_SHIFT, 100 NULL); 101 if (IS_ERR(folio)) 102 return PTR_ERR(folio); 103 104 n = memcpy_from_file_folio(buf, folio, pos, count); 105 folio_put(folio); 106 107 buf += n; 108 pos += n; 109 count -= n; 110 } 111 return 0; 112 } 113 EXPORT_SYMBOL_GPL(fsverity_pagecache_read); 114