To support decryption of sub-pagesized blocks this commit adds code to,
1. Track buffer head in "struct read_callbacks_ctx".
2. Pass buffer head argument to all read callbacks.
3. Add new fscrypt helper to decrypt the file data referred to by a
buffer head.
Signed-off-by: Chandan Rajendra
---
fs/buffer.c| 55 +--
fs/crypto/bio.c| 21 +-
fs/f2fs/data.c | 2 +-
fs/mpage.c | 2 +-
fs/read_callbacks.c| 118 +
include/linux/buffer_head.h| 1 +
include/linux/read_callbacks.h | 13 +++-
7 files changed, 158 insertions(+), 54 deletions(-)
diff --git a/fs/buffer.c b/fs/buffer.c
index e450c55f6434..dcb67525dac9 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -46,6 +46,7 @@
#include
#include
#include
+#include
#include
static int fsync_buffers_list(spinlock_t *lock, struct list_head *list);
@@ -246,11 +247,7 @@ __find_get_block_slow(struct block_device *bdev, sector_t
block)
return ret;
}
-/*
- * I/O completion handler for block_read_full_page() - pages
- * which come unlocked at the end of I/O.
- */
-static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
+void end_buffer_async_read(struct buffer_head *bh)
{
unsigned long flags;
struct buffer_head *first;
@@ -258,17 +255,7 @@ static void end_buffer_async_read(struct buffer_head *bh,
int uptodate)
struct page *page;
int page_uptodate = 1;
- BUG_ON(!buffer_async_read(bh));
-
page = bh->b_page;
- if (uptodate) {
- set_buffer_uptodate(bh);
- } else {
- clear_buffer_uptodate(bh);
- buffer_io_error(bh, ", async page read");
- SetPageError(page);
- }
-
/*
* Be _very_ careful from here on. Bad things can happen if
* two buffer heads end IO at almost the same time and both
@@ -307,6 +294,31 @@ static void end_buffer_async_read(struct buffer_head *bh,
int uptodate)
return;
}
+/*
+ * I/O completion handler for block_read_full_page(). Pages are unlocked
+ * after the I/O completes and the read callbacks (if any) have executed.
+ */
+static void __end_buffer_async_read(struct buffer_head *bh, int uptodate)
+{
+ struct page *page;
+
+ BUG_ON(!buffer_async_read(bh));
+
+ if (read_callbacks_end_bh(bh, uptodate))
+ return;
+
+ page = bh->b_page;
+ if (uptodate) {
+ set_buffer_uptodate(bh);
+ } else {
+ clear_buffer_uptodate(bh);
+ buffer_io_error(bh, ", async page read");
+ SetPageError(page);
+ }
+
+ end_buffer_async_read(bh);
+}
+
/*
* Completion handler for block_write_full_page() - pages which are unlocked
* during I/O, and which have PageWriteback cleared upon I/O completion.
@@ -379,7 +391,7 @@ EXPORT_SYMBOL(end_buffer_async_write);
*/
static void mark_buffer_async_read(struct buffer_head *bh)
{
- bh->b_end_io = end_buffer_async_read;
+ bh->b_end_io = __end_buffer_async_read;
set_buffer_async_read(bh);
}
@@ -2294,10 +2306,15 @@ int block_read_full_page(struct page *page, get_block_t
*get_block)
*/
for (i = 0; i < nr; i++) {
bh = arr[i];
- if (buffer_uptodate(bh))
- end_buffer_async_read(bh, 1);
- else
+ if (buffer_uptodate(bh)) {
+ __end_buffer_async_read(bh, 1);
+ } else {
+ if (WARN_ON(read_callbacks_setup(inode, NULL, bh,
NULL))) {
+ __end_buffer_async_read(bh, 0);
+ continue;
+ }
submit_bh(REQ_OP_READ, 0, bh);
+ }
}
return 0;
}
diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c
index 4076d704e2e4..b836d648fd27 100644
--- a/fs/crypto/bio.c
+++ b/fs/crypto/bio.c
@@ -24,6 +24,7 @@
#include
#include
#include
+#include
#include
#include "fscrypt_private.h"
@@ -41,12 +42,30 @@ static void fscrypt_decrypt_bio(struct bio *bio)
}
}
+static void fscrypt_decrypt_bh(struct buffer_head *bh)
+{
+ struct page *page;
+ int ret;
+
+ page = bh->b_page;
+
+ ret = fscrypt_decrypt_pagecache_blocks(page, bh->b_size,
+ bh_offset(bh));
+ if (ret)
+ SetPageError(page);
+}
+
void fscrypt_decrypt_work(struct work_struct *work)
{
struct read_callbacks_ctx *ctx =
container_of(work, struct read_callbacks_ctx, work);
- fscrypt_decrypt_bio(ctx->bio);
+ WARN_ON(!ctx->bh && !ctx->bio);
+
+ if (ctx->bio)
+ fscrypt_decrypt_bio(ctx->bio);
+ else
+ fscrypt_decrypt_bh(ctx->bh);
read_callbacks(ctx);
}
diff --git a/fs/f2fs/data.c