projects/linux·blob master · refs

113 lines · 3.3 KiB

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 */
20struct 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}
29EXPORT_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 */
42void 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}
59EXPORT_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 */
68void 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}
80EXPORT_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 */
92int 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}
113EXPORT_SYMBOL_GPL(fsverity_pagecache_read);