Allow filesystem to make additional processing on verified pages instead of just dropping a reference. This will be used by XFS for internal buffer cache manipulation in further patches. The btrfs, ext4, and f2fs just drop the reference. Signed-off-by: Andrey Albershteyn <aalbersh@xxxxxxxxxx> --- fs/verity/read_metadata.c | 4 ++-- fs/verity/verify.c | 6 +++--- include/linux/fsverity.h | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/fs/verity/read_metadata.c b/fs/verity/read_metadata.c index f58432772d9e..8bd4b29a9a95 100644 --- a/fs/verity/read_metadata.c +++ b/fs/verity/read_metadata.c @@ -56,12 +56,12 @@ static int fsverity_read_merkle_tree(struct inode *inode, virt = kmap_local_page(page); if (copy_to_user(buf, virt + offs_in_page, bytes_to_copy)) { kunmap_local(virt); - put_page(page); + fsverity_drop_page(inode, page); err = -EFAULT; break; } kunmap_local(virt); - put_page(page); + fsverity_drop_page(inode, page); retval += bytes_to_copy; buf += bytes_to_copy; diff --git a/fs/verity/verify.c b/fs/verity/verify.c index 904ccd7e8e16..2fe7bd57b16e 100644 --- a/fs/verity/verify.c +++ b/fs/verity/verify.c @@ -183,7 +183,7 @@ verify_data_block(struct inode *inode, struct fsverity_info *vi, memcpy(_want_hash, haddr + hoffset, hsize); want_hash = _want_hash; kunmap_local(haddr); - put_page(hpage); + fsverity_drop_page(inode, hpage); goto descend; } hblocks[level].page = hpage; @@ -218,7 +218,7 @@ verify_data_block(struct inode *inode, struct fsverity_info *vi, memcpy(_want_hash, haddr + hoffset, hsize); want_hash = _want_hash; kunmap_local(haddr); - put_page(hpage); + fsverity_drop_page(inode, hpage); } /* Finally, verify the data block. */ @@ -237,7 +237,7 @@ verify_data_block(struct inode *inode, struct fsverity_info *vi, error: for (; level > 0; level--) { kunmap_local(hblocks[level - 1].addr); - put_page(hblocks[level - 1].page); + fsverity_drop_page(inode, hblocks[level - 1].page); } return false; } diff --git a/include/linux/fsverity.h b/include/linux/fsverity.h index 1eb7eae580be..6514ed6b09b4 100644 --- a/include/linux/fsverity.h +++ b/include/linux/fsverity.h @@ -120,6 +120,16 @@ struct fsverity_operations { */ int (*write_merkle_tree_block)(struct inode *inode, const void *buf, u64 pos, unsigned int size); + + /** + * Release the reference to a Merkle tree page + * + * @page: the page to release + * + * This is called when fs-verity is done with a page obtained with + * ->read_merkle_tree_page(). + */ + void (*drop_page)(struct page *page); }; #ifdef CONFIG_FS_VERITY @@ -174,6 +184,24 @@ 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); +/** + * fsverity_drop_page() - drop page obtained with ->read_merkle_tree_page() + * @inode: inode in use for verification or metadata reading + * @page: page to be dropped + * + * Generic put_page() method. Calls out back to filesystem if ->drop_page() is + * set, otherwise just drops the reference to a page. + * + */ +static inline void fsverity_drop_page(struct inode *inode, struct page *page) +{ + if (inode->i_sb->s_vop->drop_page) + inode->i_sb->s_vop->drop_page(page); + else + put_page(page); +} + + #else /* !CONFIG_FS_VERITY */ static inline struct fsverity_info *fsverity_get_info(const struct inode *inode) @@ -251,6 +279,11 @@ static inline void fsverity_enqueue_verify_work(struct work_struct *work) WARN_ON_ONCE(1); } +static inline void fsverity_drop_page(struct inode *inode, struct page *page) +{ + WARN_ON_ONCE(1); +} + #endif /* !CONFIG_FS_VERITY */ static inline bool fsverity_verify_folio(struct folio *folio) -- 2.40.1