@@ -30,6 +30,10 @@
#include <linux/backing-dev.h>
#include <linux/pagevec.h>
#include <linux/cleancache.h>
+#include <linux/fsverity.h>
+#if defined(CONFIG_FS_ENCRYPTION) || defined(CONFIG_FS_VERITY)
+#include <linux/read_callbacks.h>
+#endif
#include "internal.h"
/*
@@ -50,6 +54,20 @@ static void mpage_end_io(struct bio *bio)
int i;
struct bvec_iter_all iter_all;
+#if defined(CONFIG_FS_ENCRYPTION) || defined(CONFIG_FS_VERITY)
+ if (!bio->bi_status && bio->bi_private) {
+ struct read_callbacks_ctx *ctx;
+
+ ctx = bio->bi_private;
+
+ read_callbacks(ctx);
+ return;
+ }
+
+ if (bio->bi_private)
+ put_read_callbacks_ctx((struct read_callbacks_ctx *)(bio->bi_private));
+#endif
+
bio_for_each_segment_all(bv, bio, i, iter_all) {
struct page *page = bv->bv_page;
page_endio(page, bio_op(bio),
@@ -189,7 +207,13 @@ static struct bio *do_mpage_readpage(struct mpage_readpage_args *args)
block_in_file = (sector_t)page->index << (PAGE_SHIFT - blkbits);
last_block = block_in_file + args->nr_pages * blocks_per_page;
- last_block_in_file = (i_size_read(inode) + blocksize - 1) >> blkbits;
+#ifdef CONFIG_FS_VERITY
+ if (IS_VERITY(inode) && inode->i_sb->s_vop->readpage_limit)
+ last_block_in_file = inode->i_sb->s_vop->readpage_limit(inode);
+ else
+#endif
+ last_block_in_file = (i_size_read(inode) + blocksize - 1)
+ >> blkbits;
if (last_block > last_block_in_file)
last_block = last_block_in_file;
page_block = 0;
@@ -277,6 +301,14 @@ static struct bio *do_mpage_readpage(struct mpage_readpage_args *args)
if (first_hole != blocks_per_page) {
zero_user_segment(page, first_hole << blkbits, PAGE_SIZE);
if (first_hole == 0) {
+#ifdef CONFIG_FS_VERITY
+ if (IS_VERITY(inode)) {
+ if (!fsverity_check_hole(inode, page)) {
+ SetPageError(page);
+ goto confused;
+ }
+ }
+#endif
SetPageUptodate(page);
unlock_page(page);
goto out;
@@ -299,7 +331,11 @@ static struct bio *do_mpage_readpage(struct mpage_readpage_args *args)
alloc_new:
if (args->bio == NULL) {
- if (first_hole == blocks_per_page) {
+#if defined(CONFIG_FS_ENCRYPTION) || defined(CONFIG_FS_VERITY)
+ struct read_callbacks_ctx *ctx;
+#endif
+ if (first_hole == blocks_per_page
+ && !(IS_ENCRYPTED(inode) || IS_VERITY(inode))) {
if (!bdev_read_page(bdev, blocks[0] << (blkbits - 9),
page))
goto out;
@@ -310,6 +346,15 @@ static struct bio *do_mpage_readpage(struct mpage_readpage_args *args)
gfp);
if (args->bio == NULL)
goto confused;
+
+#if defined(CONFIG_FS_ENCRYPTION) || defined(CONFIG_FS_VERITY)
+ ctx = get_read_callbacks_ctx(inode, args->bio, page->index);
+ if (IS_ERR(ctx)) {
+ bio_put(args->bio);
+ args->bio = NULL;
+ goto confused;
+ }
+#endif
}
length = first_hole << blkbits;
@@ -331,7 +376,7 @@ static struct bio *do_mpage_readpage(struct mpage_readpage_args *args)
confused:
if (args->bio)
args->bio = mpage_bio_submit(REQ_OP_READ, op_flags, args->bio);
- if (!PageUptodate(page))
+ if (!PageUptodate(page) && !PageError(page))
block_read_full_page(page, args->get_block);
else
unlock_page(page);
This commit adds code to make do_mpage_readpage() to be "read callbacks" aware i.e. for files requiring decryption/verification, do_mpage_readpage() now allocates a context structure and assigns the corresponding pointer to bio->bi_private. At endio time, a non-zero bio->bi_private indicates that after the read operation is performed, the bio's payload needs to be processed further before handing over the data to user space. The context structure is used for tracking the state machine associated with post read processing. Signed-off-by: Chandan Rajendra <chandan@linux.ibm.com> --- fs/mpage.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 3 deletions(-)