@@ -167,14 +167,15 @@ static inline bool fsverity_caches_blocks(const struct inode *inode)
static inline bool fsverity_uses_bitmap(const struct fsverity_info *vi,
const struct inode *inode)
{
+ if (fsverity_caches_blocks(inode))
+ return false;
+
/*
* If fs uses block-based Merkle tree caching, then fs-verity must use
* hash_block_verified bitmap as there's no page to mark it with
* PG_checked.
*/
- if (vi->tree_params.block_size != PAGE_SIZE)
- return true;
- return fsverity_caches_blocks(inode);
+ return vi->tree_params.block_size != PAGE_SIZE;
}
int fsverity_read_merkle_tree_block(struct inode *inode,
@@ -26,12 +26,11 @@ static bool is_hash_block_verified(struct inode *inode,
struct page *hpage;
/*
- * If the filesystem uses block-based caching, then
- * ->hash_block_verified is always used and the filesystem pushes
- * invalidations to it as needed.
+ * If the filesystem uses block-based caching, then rely on the
+ * implementation to retain verified status.
*/
if (fsverity_caches_blocks(inode))
- return test_bit(hblock_idx, vi->hash_block_verified);
+ return block->verified;
/* Otherwise, the filesystem uses page-based caching. */
hpage = (struct page *)block->context;
@@ -224,7 +223,9 @@ verify_data_block(struct inode *inode, struct fsverity_info *vi,
* idempotent, as the same hash block might be verified by
* multiple threads concurrently.
*/
- if (fsverity_uses_bitmap(vi, inode))
+ if (fsverity_caches_blocks(inode))
+ block->verified = true;
+ else if (fsverity_uses_bitmap(vi, inode))
set_bit(hblock_idx, vi->hash_block_verified);
else
SetPageChecked((struct page *)block->context);
@@ -375,33 +376,6 @@ void __init fsverity_init_workqueue(void)
panic("failed to allocate fsverity_read_queue");
}
-/**
- * fsverity_invalidate_block() - invalidate Merkle tree block
- * @inode: inode to which this Merkle tree blocks belong
- * @block: block to be invalidated
- *
- * This function invalidates/clears "verified" state of Merkle tree block
- * in the fs-verity bitmap. The block needs to have ->offset set.
- */
-void fsverity_invalidate_block(struct inode *inode,
- struct fsverity_blockbuf *block)
-{
- struct fsverity_info *vi = inode->i_verity_info;
- const unsigned int log_blocksize = vi->tree_params.log_blocksize;
-
- trace_fsverity_invalidate_block(inode, block);
-
- if (block->offset >= vi->tree_params.tree_size) {
- fsverity_err(inode,
-"Trying to invalidate beyond Merkle tree (tree %lld, offset %lld)",
- vi->tree_params.tree_size, block->offset);
- return;
- }
-
- clear_bit(block->offset >> log_blocksize, vi->hash_block_verified);
-}
-EXPORT_SYMBOL_GPL(fsverity_invalidate_block);
-
/**
* fsverity_read_merkle_tree_block() - read Merkle tree block
* @inode: inode to which this Merkle tree blocks belong
@@ -436,6 +410,7 @@ int fsverity_read_merkle_tree_block(struct inode *inode,
.log_blocksize = params->log_blocksize,
.ra_bytes = ra_bytes,
};
+ block->verified = false;
return vops->read_merkle_tree_block(&req, block);
}
@@ -32,6 +32,7 @@
* @offset: block's offset into Merkle tree
* @size: the Merkle tree block size
* @context: filesystem private context
+ * @verified: has this buffer been validated?
*
* Buffer containing single Merkle Tree block. These buffers are passed
* - to filesystem, when fs-verity is building merkel tree,
@@ -49,6 +50,7 @@
struct fsverity_blockbuf {
void *kaddr;
u64 offset;
+ unsigned int verified:1;
unsigned int size;
void *context;
};
@@ -168,9 +170,9 @@ struct fsverity_operations {
* This can be called at any time on an open verity file. It may be
* called by multiple processes concurrently.
*
- * In case that block was evicted from the memory filesystem has to use
- * fsverity_invalidate_block() to let fsverity know that block's
- * verification state is not valid anymore.
+ * Implementations may cache the @block->verified state in
+ * ->drop_merkle_tree_block. They must clear the @block->verified
+ * flag for a cache miss.
*
* If this function is implemented, ->drop_merkle_tree_block must also
* be implemented.
@@ -204,6 +206,9 @@ struct fsverity_operations {
* This is called when fs-verity is done with a block obtained with
* ->read_merkle_tree_block().
*
+ * Implementations should cache a @block->verified==1 state to avoid
+ * unnecessary revalidations during later accesses.
+ *
* If this function is implemented, ->read_merkle_tree_block must also
* be implemented.
*/
@@ -264,8 +269,6 @@ int fsverity_ioctl_read_metadata(struct file *filp, const void __user *uarg);
bool fsverity_verify_blocks(struct folio *folio, size_t len, size_t offset);
void fsverity_verify_bio(struct bio *bio);
void fsverity_enqueue_verify_work(struct work_struct *work);
-void fsverity_invalidate_block(struct inode *inode,
- struct fsverity_blockbuf *block);
static inline int fsverity_set_ops(struct super_block *sb,
const struct fsverity_operations *ops)
@@ -109,25 +109,6 @@ TRACE_EVENT(fsverity_merkle_tree_block_verified,
__entry->direction == 0 ? "ascend" : "descend")
);
-TRACE_EVENT(fsverity_invalidate_block,
- TP_PROTO(struct inode *inode, struct fsverity_blockbuf *block),
- TP_ARGS(inode, block),
- TP_STRUCT__entry(
- __field(ino_t, ino)
- __field(u64, offset)
- __field(unsigned int, block_size)
- ),
- TP_fast_assign(
- __entry->ino = inode->i_ino;
- __entry->offset = block->offset;
- __entry->block_size = block->size;
- ),
- TP_printk("ino %lu block position %llu block size %u",
- (unsigned long) __entry->ino,
- __entry->offset,
- __entry->block_size)
-);
-
TRACE_EVENT(fsverity_read_merkle_tree_block,
TP_PROTO(struct inode *inode, u64 offset, unsigned int log_blocksize),
TP_ARGS(inode, offset, log_blocksize),