xref: /linux/fs/verity/pagecache.c (revision bb29b957eaaa15be33243550d9ee576c2d601669)
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