root/fs/verity/pagecache.c
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright 2019 Google LLC
 */
#include "fsverity_private.h"

#include <linux/export.h>
#include <linux/fsverity.h>
#include <linux/pagemap.h>

/**
 * 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);