From: Chandan Rajendra <chandan@linux.ibm.com>
To: linux-fsdevel@vger.kernel.org, linux-ext4@vger.kernel.org,
linux-f2fs-devel@lists.sourceforge.net,
linux-fscrypt@vger.kernel.org
Cc: Chandan Rajendra <chandan@linux.ibm.com>,
tytso@mit.edu, adilger.kernel@dilger.ca, ebiggers@kernel.org,
jaegeuk@kernel.org, yuchao0@huawei.com, hch@infradead.org
Subject: [PATCH V2 07/13] Add decryption support for sub-pagesized blocks
Date: Sun, 28 Apr 2019 10:01:15 +0530 [thread overview]
Message-ID: <20190428043121.30925-8-chandan@linux.ibm.com> (raw)
In-Reply-To: <20190428043121.30925-1-chandan@linux.ibm.com>
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. In the corresponding endio, loop across all the blocks mapped by the
page, decrypting each block in turn.
Signed-off-by: Chandan Rajendra <chandan@linux.ibm.com>
---
fs/buffer.c | 83 +++++++++++++++++++++++++---------
fs/crypto/bio.c | 50 +++++++++++++-------
fs/crypto/crypto.c | 19 +++++++-
fs/f2fs/data.c | 2 +-
fs/mpage.c | 2 +-
fs/read_callbacks.c | 53 ++++++++++++++--------
include/linux/buffer_head.h | 1 +
include/linux/read_callbacks.h | 5 +-
8 files changed, 154 insertions(+), 61 deletions(-)
diff --git a/fs/buffer.c b/fs/buffer.c
index ce357602f471..f324727e24bb 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -45,6 +45,7 @@
#include <linux/bit_spinlock.h>
#include <linux/pagevec.h>
#include <linux/sched/mm.h>
+#include <linux/read_callbacks.h>
#include <trace/events/block.h>
static int fsync_buffers_list(spinlock_t *lock, struct list_head *list);
@@ -245,11 +246,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_page_read(struct buffer_head *bh)
{
unsigned long flags;
struct buffer_head *first;
@@ -257,17 +254,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
@@ -305,6 +292,44 @@ static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
local_irq_restore(flags);
return;
}
+EXPORT_SYMBOL(end_buffer_page_read);
+
+/*
+ * 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)
+{
+ struct page *page;
+
+ BUG_ON(!buffer_async_read(bh));
+
+#if defined(CONFIG_FS_ENCRYPTION) || defined(CONFIG_FS_VERITY)
+ if (uptodate && bh->b_private) {
+ struct read_callbacks_ctx *ctx = bh->b_private;
+
+ read_callbacks(ctx);
+ return;
+ }
+
+ if (bh->b_private) {
+ struct read_callbacks_ctx *ctx = bh->b_private;
+
+ WARN_ON(uptodate);
+ put_read_callbacks_ctx(ctx);
+ }
+#endif
+ 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_page_read(bh);
+}
/*
* Completion handler for block_write_full_page() - pages which are unlocked
@@ -2220,7 +2245,11 @@ int block_read_full_page(struct page *page, get_block_t *get_block)
{
struct inode *inode = page->mapping->host;
sector_t iblock, lblock;
- struct buffer_head *bh, *head, *arr[MAX_BUF_PER_PAGE];
+ struct buffer_head *bh, *head;
+ struct {
+ sector_t blk_nr;
+ struct buffer_head *bh;
+ } arr[MAX_BUF_PER_PAGE];
unsigned int blocksize, bbits;
int nr, i;
int fully_mapped = 1;
@@ -2262,7 +2291,9 @@ int block_read_full_page(struct page *page, get_block_t *get_block)
if (buffer_uptodate(bh))
continue;
}
- arr[nr++] = bh;
+ arr[nr].blk_nr = iblock;
+ arr[nr].bh = bh;
+ ++nr;
} while (i++, iblock++, (bh = bh->b_this_page) != head);
if (fully_mapped)
@@ -2281,7 +2312,7 @@ int block_read_full_page(struct page *page, get_block_t *get_block)
/* Stage two: lock the buffers */
for (i = 0; i < nr; i++) {
- bh = arr[i];
+ bh = arr[i].bh;
lock_buffer(bh);
mark_buffer_async_read(bh);
}
@@ -2292,11 +2323,21 @@ int block_read_full_page(struct page *page, get_block_t *get_block)
* the underlying blockdev brought it uptodate (the sct fix).
*/
for (i = 0; i < nr; i++) {
- bh = arr[i];
- if (buffer_uptodate(bh))
+ bh = arr[i].bh;
+ if (buffer_uptodate(bh)) {
end_buffer_async_read(bh, 1);
- else
+ } else {
+#if defined(CONFIG_FS_ENCRYPTION) || defined(CONFIG_FS_VERITY)
+ struct read_callbacks_ctx *ctx;
+
+ ctx = get_read_callbacks_ctx(inode, NULL, bh, arr[i].blk_nr);
+ if (WARN_ON(IS_ERR(ctx))) {
+ end_buffer_async_read(bh, 0);
+ continue;
+ }
+#endif
submit_bh(REQ_OP_READ, 0, bh);
+ }
}
return 0;
}
diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c
index 27f5618174f2..856f4694902d 100644
--- a/fs/crypto/bio.c
+++ b/fs/crypto/bio.c
@@ -24,44 +24,62 @@
#include <linux/module.h>
#include <linux/bio.h>
#include <linux/namei.h>
+#include <linux/buffer_head.h>
#include <linux/read_callbacks.h>
#include "fscrypt_private.h"
-static void __fscrypt_decrypt_bio(struct bio *bio, bool done)
+static void fscrypt_decrypt(struct bio *bio, struct buffer_head *bh)
{
+ struct inode *inode;
+ struct page *page;
struct bio_vec *bv;
+ sector_t blk_nr;
+ int ret;
int i;
struct bvec_iter_all iter_all;
- bio_for_each_segment_all(bv, bio, i, iter_all) {
- struct page *page = bv->bv_page;
- int ret = fscrypt_decrypt_page(page->mapping->host, page,
- PAGE_SIZE, 0, page->index);
+ WARN_ON(!bh && !bio);
+ if (bh) {
+ page = bh->b_page;
+ inode = page->mapping->host;
+
+ blk_nr = page->index << (PAGE_SHIFT - inode->i_blkbits);
+ blk_nr += (bh_offset(bh) >> inode->i_blkbits);
+
+ ret = fscrypt_decrypt_page(inode, page, i_blocksize(inode),
+ bh_offset(bh), blk_nr);
if (ret) {
WARN_ON_ONCE(1);
SetPageError(page);
- } else if (done) {
- SetPageUptodate(page);
}
- if (done)
- unlock_page(page);
+ } else if (bio) {
+ bio_for_each_segment_all(bv, bio, i, iter_all) {
+ unsigned int blkbits;
+
+ page = bv->bv_page;
+ inode = page->mapping->host;
+ blkbits = inode->i_blkbits;
+ blk_nr = page->index << (PAGE_SHIFT - blkbits);
+ blk_nr += (bv->bv_offset >> blkbits);
+ ret = fscrypt_decrypt_page(page->mapping->host,
+ page, bv->bv_len,
+ bv->bv_offset, blk_nr);
+ if (ret) {
+ WARN_ON_ONCE(1);
+ SetPageError(page);
+ }
+ }
}
}
-void fscrypt_decrypt_bio(struct bio *bio)
-{
- __fscrypt_decrypt_bio(bio, false);
-}
-EXPORT_SYMBOL(fscrypt_decrypt_bio);
-
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);
+ fscrypt_decrypt(ctx->bio, ctx->bh);
read_callbacks(ctx);
}
diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c
index ffa9302a7351..4f0d832cae71 100644
--- a/fs/crypto/crypto.c
+++ b/fs/crypto/crypto.c
@@ -305,11 +305,26 @@ EXPORT_SYMBOL(fscrypt_encrypt_page);
int fscrypt_decrypt_page(const struct inode *inode, struct page *page,
unsigned int len, unsigned int offs, u64 lblk_num)
{
+ int i, page_nr_blks;
+ int err = 0;
+
if (!(inode->i_sb->s_cop->flags & FS_CFLG_OWN_PAGES))
BUG_ON(!PageLocked(page));
- return fscrypt_do_page_crypto(inode, FS_DECRYPT, lblk_num, page, page,
- len, offs, GFP_NOFS);
+ page_nr_blks = len >> inode->i_blkbits;
+
+ for (i = 0; i < page_nr_blks; i++) {
+ err = fscrypt_do_page_crypto(inode, FS_DECRYPT, lblk_num,
+ page, page, i_blocksize(inode), offs,
+ GFP_NOFS);
+ if (err)
+ break;
+
+ ++lblk_num;
+ offs += i_blocksize(inode);
+ }
+
+ return err;
}
EXPORT_SYMBOL(fscrypt_decrypt_page);
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 05430d3650ab..ba437a2085e7 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -527,7 +527,7 @@ static struct bio *f2fs_grab_read_bio(struct inode *inode, block_t blkaddr,
bio_set_op_attrs(bio, REQ_OP_READ, op_flag);
#if defined(CONFIG_FS_ENCRYPTION) || defined(CONFIG_FS_VERITY)
- ctx = get_read_callbacks_ctx(inode, bio, first_idx);
+ ctx = get_read_callbacks_ctx(inode, bio, NULL, first_idx);
if (IS_ERR(ctx)) {
bio_put(bio);
return (struct bio *)ctx;
diff --git a/fs/mpage.c b/fs/mpage.c
index e342b859ee44..0557479fdca4 100644
--- a/fs/mpage.c
+++ b/fs/mpage.c
@@ -348,7 +348,7 @@ static struct bio *do_mpage_readpage(struct mpage_readpage_args *args)
goto confused;
#if defined(CONFIG_FS_ENCRYPTION) || defined(CONFIG_FS_VERITY)
- ctx = get_read_callbacks_ctx(inode, args->bio, page->index);
+ ctx = get_read_callbacks_ctx(inode, args->bio, NULL, page->index);
if (IS_ERR(ctx)) {
bio_put(args->bio);
args->bio = NULL;
diff --git a/fs/read_callbacks.c b/fs/read_callbacks.c
index 6dea54b0baa9..b3881c525720 100644
--- a/fs/read_callbacks.c
+++ b/fs/read_callbacks.c
@@ -8,6 +8,7 @@
#include <linux/mm.h>
#include <linux/pagemap.h>
#include <linux/bio.h>
+#include <linux/buffer_head.h>
#include <linux/fscrypt.h>
#include <linux/fsverity.h>
#include <linux/read_callbacks.h>
@@ -24,26 +25,41 @@ enum read_callbacks_step {
STEP_VERITY,
};
-void end_read_callbacks(struct bio *bio)
+void end_read_callbacks(struct bio *bio, struct buffer_head *bh)
{
+ struct read_callbacks_ctx *ctx;
struct page *page;
struct bio_vec *bv;
int i;
struct bvec_iter_all iter_all;
- bio_for_each_segment_all(bv, bio, i, iter_all) {
- page = bv->bv_page;
+ if (bh) {
+ if (!PageError(bh->b_page))
+ set_buffer_uptodate(bh);
- BUG_ON(bio->bi_status);
+ ctx = bh->b_private;
- if (!PageError(page))
- SetPageUptodate(page);
+ end_buffer_page_read(bh);
- unlock_page(page);
+ put_read_callbacks_ctx(ctx);
+ } else if (bio) {
+ bio_for_each_segment_all(bv, bio, i, iter_all) {
+ page = bv->bv_page;
+
+ WARN_ON(bio->bi_status);
+
+ if (!PageError(page))
+ SetPageUptodate(page);
+
+ unlock_page(page);
+ }
+ WARN_ON(!bio->bi_private);
+
+ ctx = bio->bi_private;
+ put_read_callbacks_ctx(ctx);
+
+ bio_put(bio);
}
- if (bio->bi_private)
- put_read_callbacks_ctx(bio->bi_private);
- bio_put(bio);
}
EXPORT_SYMBOL(end_read_callbacks);
@@ -70,18 +86,21 @@ void read_callbacks(struct read_callbacks_ctx *ctx)
ctx->cur_step++;
/* fall-through */
default:
- end_read_callbacks(ctx->bio);
+ end_read_callbacks(ctx->bio, ctx->bh);
}
}
EXPORT_SYMBOL(read_callbacks);
struct read_callbacks_ctx *get_read_callbacks_ctx(struct inode *inode,
struct bio *bio,
+ struct buffer_head *bh,
pgoff_t index)
{
unsigned int read_callbacks_steps = 0;
struct read_callbacks_ctx *ctx = NULL;
+ WARN_ON(!bh && !bio);
+
if (IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode))
read_callbacks_steps |= 1 << STEP_DECRYPT;
#ifdef CONFIG_FS_VERITY
@@ -95,11 +114,15 @@ struct read_callbacks_ctx *get_read_callbacks_ctx(struct inode *inode,
ctx = mempool_alloc(read_callbacks_ctx_pool, GFP_NOFS);
if (!ctx)
return ERR_PTR(-ENOMEM);
+ ctx->bh = bh;
ctx->bio = bio;
ctx->inode = inode;
ctx->enabled_steps = read_callbacks_steps;
ctx->cur_step = STEP_INITIAL;
- bio->bi_private = ctx;
+ if (bio)
+ bio->bi_private = ctx;
+ else if (bh)
+ bh->b_private = ctx;
}
return ctx;
}
@@ -111,12 +134,6 @@ void put_read_callbacks_ctx(struct read_callbacks_ctx *ctx)
}
EXPORT_SYMBOL(put_read_callbacks_ctx);
-bool read_callbacks_required(struct bio *bio)
-{
- return bio->bi_private && !bio->bi_status;
-}
-EXPORT_SYMBOL(read_callbacks_required);
-
static int __init init_read_callbacks(void)
{
read_callbacks_ctx_cache = KMEM_CACHE(read_callbacks_ctx, 0);
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
index 7b73ef7f902d..782ed6350dfc 100644
--- a/include/linux/buffer_head.h
+++ b/include/linux/buffer_head.h
@@ -165,6 +165,7 @@ void create_empty_buffers(struct page *, unsigned long,
void end_buffer_read_sync(struct buffer_head *bh, int uptodate);
void end_buffer_write_sync(struct buffer_head *bh, int uptodate);
void end_buffer_async_write(struct buffer_head *bh, int uptodate);
+void end_buffer_page_read(struct buffer_head *bh);
/* Things to do with buffers at mapping->private_list */
void mark_buffer_dirty_inode(struct buffer_head *bh, struct inode *inode);
diff --git a/include/linux/read_callbacks.h b/include/linux/read_callbacks.h
index c501cdf83a5b..ae32dc4efa6d 100644
--- a/include/linux/read_callbacks.h
+++ b/include/linux/read_callbacks.h
@@ -3,6 +3,7 @@
#define _READ_CALLBACKS_H
struct read_callbacks_ctx {
+ struct buffer_head *bh;
struct bio *bio;
struct inode *inode;
struct work_struct work;
@@ -10,12 +11,12 @@ struct read_callbacks_ctx {
unsigned int enabled_steps;
};
-void end_read_callbacks(struct bio *bio);
+void end_read_callbacks(struct bio *bio, struct buffer_head *bh);
void read_callbacks(struct read_callbacks_ctx *ctx);
struct read_callbacks_ctx *get_read_callbacks_ctx(struct inode *inode,
struct bio *bio,
+ struct buffer_head *bh,
pgoff_t index);
void put_read_callbacks_ctx(struct read_callbacks_ctx *ctx);
-bool read_callbacks_required(struct bio *bio);
#endif /* _READ_CALLBACKS_H */
--
2.19.1
WARNING: multiple messages have this Message-ID (diff)
From: Chandan Rajendra <chandan@linux.ibm.com>
To: linux-fsdevel@vger.kernel.org, linux-ext4@vger.kernel.org,
linux-f2fs-devel@lists.sourceforge.net,
linux-fscrypt@vger.kernel.org
Cc: hch@infradead.org, tytso@mit.edu, ebiggers@kernel.org,
Chandan Rajendra <chandan@linux.ibm.com>,
adilger.kernel@dilger.ca, jaegeuk@kernel.org
Subject: [PATCH V2 07/13] Add decryption support for sub-pagesized blocks
Date: Sun, 28 Apr 2019 10:01:15 +0530 [thread overview]
Message-ID: <20190428043121.30925-8-chandan@linux.ibm.com> (raw)
In-Reply-To: <20190428043121.30925-1-chandan@linux.ibm.com>
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. In the corresponding endio, loop across all the blocks mapped by the
page, decrypting each block in turn.
Signed-off-by: Chandan Rajendra <chandan@linux.ibm.com>
---
fs/buffer.c | 83 +++++++++++++++++++++++++---------
fs/crypto/bio.c | 50 +++++++++++++-------
fs/crypto/crypto.c | 19 +++++++-
fs/f2fs/data.c | 2 +-
fs/mpage.c | 2 +-
fs/read_callbacks.c | 53 ++++++++++++++--------
include/linux/buffer_head.h | 1 +
include/linux/read_callbacks.h | 5 +-
8 files changed, 154 insertions(+), 61 deletions(-)
diff --git a/fs/buffer.c b/fs/buffer.c
index ce357602f471..f324727e24bb 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -45,6 +45,7 @@
#include <linux/bit_spinlock.h>
#include <linux/pagevec.h>
#include <linux/sched/mm.h>
+#include <linux/read_callbacks.h>
#include <trace/events/block.h>
static int fsync_buffers_list(spinlock_t *lock, struct list_head *list);
@@ -245,11 +246,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_page_read(struct buffer_head *bh)
{
unsigned long flags;
struct buffer_head *first;
@@ -257,17 +254,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
@@ -305,6 +292,44 @@ static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
local_irq_restore(flags);
return;
}
+EXPORT_SYMBOL(end_buffer_page_read);
+
+/*
+ * 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)
+{
+ struct page *page;
+
+ BUG_ON(!buffer_async_read(bh));
+
+#if defined(CONFIG_FS_ENCRYPTION) || defined(CONFIG_FS_VERITY)
+ if (uptodate && bh->b_private) {
+ struct read_callbacks_ctx *ctx = bh->b_private;
+
+ read_callbacks(ctx);
+ return;
+ }
+
+ if (bh->b_private) {
+ struct read_callbacks_ctx *ctx = bh->b_private;
+
+ WARN_ON(uptodate);
+ put_read_callbacks_ctx(ctx);
+ }
+#endif
+ 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_page_read(bh);
+}
/*
* Completion handler for block_write_full_page() - pages which are unlocked
@@ -2220,7 +2245,11 @@ int block_read_full_page(struct page *page, get_block_t *get_block)
{
struct inode *inode = page->mapping->host;
sector_t iblock, lblock;
- struct buffer_head *bh, *head, *arr[MAX_BUF_PER_PAGE];
+ struct buffer_head *bh, *head;
+ struct {
+ sector_t blk_nr;
+ struct buffer_head *bh;
+ } arr[MAX_BUF_PER_PAGE];
unsigned int blocksize, bbits;
int nr, i;
int fully_mapped = 1;
@@ -2262,7 +2291,9 @@ int block_read_full_page(struct page *page, get_block_t *get_block)
if (buffer_uptodate(bh))
continue;
}
- arr[nr++] = bh;
+ arr[nr].blk_nr = iblock;
+ arr[nr].bh = bh;
+ ++nr;
} while (i++, iblock++, (bh = bh->b_this_page) != head);
if (fully_mapped)
@@ -2281,7 +2312,7 @@ int block_read_full_page(struct page *page, get_block_t *get_block)
/* Stage two: lock the buffers */
for (i = 0; i < nr; i++) {
- bh = arr[i];
+ bh = arr[i].bh;
lock_buffer(bh);
mark_buffer_async_read(bh);
}
@@ -2292,11 +2323,21 @@ int block_read_full_page(struct page *page, get_block_t *get_block)
* the underlying blockdev brought it uptodate (the sct fix).
*/
for (i = 0; i < nr; i++) {
- bh = arr[i];
- if (buffer_uptodate(bh))
+ bh = arr[i].bh;
+ if (buffer_uptodate(bh)) {
end_buffer_async_read(bh, 1);
- else
+ } else {
+#if defined(CONFIG_FS_ENCRYPTION) || defined(CONFIG_FS_VERITY)
+ struct read_callbacks_ctx *ctx;
+
+ ctx = get_read_callbacks_ctx(inode, NULL, bh, arr[i].blk_nr);
+ if (WARN_ON(IS_ERR(ctx))) {
+ end_buffer_async_read(bh, 0);
+ continue;
+ }
+#endif
submit_bh(REQ_OP_READ, 0, bh);
+ }
}
return 0;
}
diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c
index 27f5618174f2..856f4694902d 100644
--- a/fs/crypto/bio.c
+++ b/fs/crypto/bio.c
@@ -24,44 +24,62 @@
#include <linux/module.h>
#include <linux/bio.h>
#include <linux/namei.h>
+#include <linux/buffer_head.h>
#include <linux/read_callbacks.h>
#include "fscrypt_private.h"
-static void __fscrypt_decrypt_bio(struct bio *bio, bool done)
+static void fscrypt_decrypt(struct bio *bio, struct buffer_head *bh)
{
+ struct inode *inode;
+ struct page *page;
struct bio_vec *bv;
+ sector_t blk_nr;
+ int ret;
int i;
struct bvec_iter_all iter_all;
- bio_for_each_segment_all(bv, bio, i, iter_all) {
- struct page *page = bv->bv_page;
- int ret = fscrypt_decrypt_page(page->mapping->host, page,
- PAGE_SIZE, 0, page->index);
+ WARN_ON(!bh && !bio);
+ if (bh) {
+ page = bh->b_page;
+ inode = page->mapping->host;
+
+ blk_nr = page->index << (PAGE_SHIFT - inode->i_blkbits);
+ blk_nr += (bh_offset(bh) >> inode->i_blkbits);
+
+ ret = fscrypt_decrypt_page(inode, page, i_blocksize(inode),
+ bh_offset(bh), blk_nr);
if (ret) {
WARN_ON_ONCE(1);
SetPageError(page);
- } else if (done) {
- SetPageUptodate(page);
}
- if (done)
- unlock_page(page);
+ } else if (bio) {
+ bio_for_each_segment_all(bv, bio, i, iter_all) {
+ unsigned int blkbits;
+
+ page = bv->bv_page;
+ inode = page->mapping->host;
+ blkbits = inode->i_blkbits;
+ blk_nr = page->index << (PAGE_SHIFT - blkbits);
+ blk_nr += (bv->bv_offset >> blkbits);
+ ret = fscrypt_decrypt_page(page->mapping->host,
+ page, bv->bv_len,
+ bv->bv_offset, blk_nr);
+ if (ret) {
+ WARN_ON_ONCE(1);
+ SetPageError(page);
+ }
+ }
}
}
-void fscrypt_decrypt_bio(struct bio *bio)
-{
- __fscrypt_decrypt_bio(bio, false);
-}
-EXPORT_SYMBOL(fscrypt_decrypt_bio);
-
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);
+ fscrypt_decrypt(ctx->bio, ctx->bh);
read_callbacks(ctx);
}
diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c
index ffa9302a7351..4f0d832cae71 100644
--- a/fs/crypto/crypto.c
+++ b/fs/crypto/crypto.c
@@ -305,11 +305,26 @@ EXPORT_SYMBOL(fscrypt_encrypt_page);
int fscrypt_decrypt_page(const struct inode *inode, struct page *page,
unsigned int len, unsigned int offs, u64 lblk_num)
{
+ int i, page_nr_blks;
+ int err = 0;
+
if (!(inode->i_sb->s_cop->flags & FS_CFLG_OWN_PAGES))
BUG_ON(!PageLocked(page));
- return fscrypt_do_page_crypto(inode, FS_DECRYPT, lblk_num, page, page,
- len, offs, GFP_NOFS);
+ page_nr_blks = len >> inode->i_blkbits;
+
+ for (i = 0; i < page_nr_blks; i++) {
+ err = fscrypt_do_page_crypto(inode, FS_DECRYPT, lblk_num,
+ page, page, i_blocksize(inode), offs,
+ GFP_NOFS);
+ if (err)
+ break;
+
+ ++lblk_num;
+ offs += i_blocksize(inode);
+ }
+
+ return err;
}
EXPORT_SYMBOL(fscrypt_decrypt_page);
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 05430d3650ab..ba437a2085e7 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -527,7 +527,7 @@ static struct bio *f2fs_grab_read_bio(struct inode *inode, block_t blkaddr,
bio_set_op_attrs(bio, REQ_OP_READ, op_flag);
#if defined(CONFIG_FS_ENCRYPTION) || defined(CONFIG_FS_VERITY)
- ctx = get_read_callbacks_ctx(inode, bio, first_idx);
+ ctx = get_read_callbacks_ctx(inode, bio, NULL, first_idx);
if (IS_ERR(ctx)) {
bio_put(bio);
return (struct bio *)ctx;
diff --git a/fs/mpage.c b/fs/mpage.c
index e342b859ee44..0557479fdca4 100644
--- a/fs/mpage.c
+++ b/fs/mpage.c
@@ -348,7 +348,7 @@ static struct bio *do_mpage_readpage(struct mpage_readpage_args *args)
goto confused;
#if defined(CONFIG_FS_ENCRYPTION) || defined(CONFIG_FS_VERITY)
- ctx = get_read_callbacks_ctx(inode, args->bio, page->index);
+ ctx = get_read_callbacks_ctx(inode, args->bio, NULL, page->index);
if (IS_ERR(ctx)) {
bio_put(args->bio);
args->bio = NULL;
diff --git a/fs/read_callbacks.c b/fs/read_callbacks.c
index 6dea54b0baa9..b3881c525720 100644
--- a/fs/read_callbacks.c
+++ b/fs/read_callbacks.c
@@ -8,6 +8,7 @@
#include <linux/mm.h>
#include <linux/pagemap.h>
#include <linux/bio.h>
+#include <linux/buffer_head.h>
#include <linux/fscrypt.h>
#include <linux/fsverity.h>
#include <linux/read_callbacks.h>
@@ -24,26 +25,41 @@ enum read_callbacks_step {
STEP_VERITY,
};
-void end_read_callbacks(struct bio *bio)
+void end_read_callbacks(struct bio *bio, struct buffer_head *bh)
{
+ struct read_callbacks_ctx *ctx;
struct page *page;
struct bio_vec *bv;
int i;
struct bvec_iter_all iter_all;
- bio_for_each_segment_all(bv, bio, i, iter_all) {
- page = bv->bv_page;
+ if (bh) {
+ if (!PageError(bh->b_page))
+ set_buffer_uptodate(bh);
- BUG_ON(bio->bi_status);
+ ctx = bh->b_private;
- if (!PageError(page))
- SetPageUptodate(page);
+ end_buffer_page_read(bh);
- unlock_page(page);
+ put_read_callbacks_ctx(ctx);
+ } else if (bio) {
+ bio_for_each_segment_all(bv, bio, i, iter_all) {
+ page = bv->bv_page;
+
+ WARN_ON(bio->bi_status);
+
+ if (!PageError(page))
+ SetPageUptodate(page);
+
+ unlock_page(page);
+ }
+ WARN_ON(!bio->bi_private);
+
+ ctx = bio->bi_private;
+ put_read_callbacks_ctx(ctx);
+
+ bio_put(bio);
}
- if (bio->bi_private)
- put_read_callbacks_ctx(bio->bi_private);
- bio_put(bio);
}
EXPORT_SYMBOL(end_read_callbacks);
@@ -70,18 +86,21 @@ void read_callbacks(struct read_callbacks_ctx *ctx)
ctx->cur_step++;
/* fall-through */
default:
- end_read_callbacks(ctx->bio);
+ end_read_callbacks(ctx->bio, ctx->bh);
}
}
EXPORT_SYMBOL(read_callbacks);
struct read_callbacks_ctx *get_read_callbacks_ctx(struct inode *inode,
struct bio *bio,
+ struct buffer_head *bh,
pgoff_t index)
{
unsigned int read_callbacks_steps = 0;
struct read_callbacks_ctx *ctx = NULL;
+ WARN_ON(!bh && !bio);
+
if (IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode))
read_callbacks_steps |= 1 << STEP_DECRYPT;
#ifdef CONFIG_FS_VERITY
@@ -95,11 +114,15 @@ struct read_callbacks_ctx *get_read_callbacks_ctx(struct inode *inode,
ctx = mempool_alloc(read_callbacks_ctx_pool, GFP_NOFS);
if (!ctx)
return ERR_PTR(-ENOMEM);
+ ctx->bh = bh;
ctx->bio = bio;
ctx->inode = inode;
ctx->enabled_steps = read_callbacks_steps;
ctx->cur_step = STEP_INITIAL;
- bio->bi_private = ctx;
+ if (bio)
+ bio->bi_private = ctx;
+ else if (bh)
+ bh->b_private = ctx;
}
return ctx;
}
@@ -111,12 +134,6 @@ void put_read_callbacks_ctx(struct read_callbacks_ctx *ctx)
}
EXPORT_SYMBOL(put_read_callbacks_ctx);
-bool read_callbacks_required(struct bio *bio)
-{
- return bio->bi_private && !bio->bi_status;
-}
-EXPORT_SYMBOL(read_callbacks_required);
-
static int __init init_read_callbacks(void)
{
read_callbacks_ctx_cache = KMEM_CACHE(read_callbacks_ctx, 0);
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
index 7b73ef7f902d..782ed6350dfc 100644
--- a/include/linux/buffer_head.h
+++ b/include/linux/buffer_head.h
@@ -165,6 +165,7 @@ void create_empty_buffers(struct page *, unsigned long,
void end_buffer_read_sync(struct buffer_head *bh, int uptodate);
void end_buffer_write_sync(struct buffer_head *bh, int uptodate);
void end_buffer_async_write(struct buffer_head *bh, int uptodate);
+void end_buffer_page_read(struct buffer_head *bh);
/* Things to do with buffers at mapping->private_list */
void mark_buffer_dirty_inode(struct buffer_head *bh, struct inode *inode);
diff --git a/include/linux/read_callbacks.h b/include/linux/read_callbacks.h
index c501cdf83a5b..ae32dc4efa6d 100644
--- a/include/linux/read_callbacks.h
+++ b/include/linux/read_callbacks.h
@@ -3,6 +3,7 @@
#define _READ_CALLBACKS_H
struct read_callbacks_ctx {
+ struct buffer_head *bh;
struct bio *bio;
struct inode *inode;
struct work_struct work;
@@ -10,12 +11,12 @@ struct read_callbacks_ctx {
unsigned int enabled_steps;
};
-void end_read_callbacks(struct bio *bio);
+void end_read_callbacks(struct bio *bio, struct buffer_head *bh);
void read_callbacks(struct read_callbacks_ctx *ctx);
struct read_callbacks_ctx *get_read_callbacks_ctx(struct inode *inode,
struct bio *bio,
+ struct buffer_head *bh,
pgoff_t index);
void put_read_callbacks_ctx(struct read_callbacks_ctx *ctx);
-bool read_callbacks_required(struct bio *bio);
#endif /* _READ_CALLBACKS_H */
--
2.19.1
next prev parent reply other threads:[~2019-04-28 4:32 UTC|newest]
Thread overview: 74+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-04-28 4:31 [PATCH V2 00/13] Consolidate FS read I/O callbacks code Chandan Rajendra
2019-04-28 4:31 ` Chandan Rajendra
2019-04-28 4:31 ` [PATCH V2 01/13] ext4: Clear BH_Uptodate flag on decryption error Chandan Rajendra
2019-04-28 4:31 ` Chandan Rajendra
2019-04-28 4:31 ` [PATCH V2 02/13] Consolidate "read callbacks" into a new file Chandan Rajendra
2019-04-28 4:31 ` Chandan Rajendra
2019-04-30 0:00 ` Eric Biggers
2019-04-30 0:00 ` [f2fs-dev] " Eric Biggers
2019-04-30 0:00 ` Eric Biggers
2019-05-01 12:30 ` Chandan Rajendra
2019-05-01 12:30 ` Chandan Rajendra
2019-04-30 1:37 ` Chao Yu
2019-04-30 1:37 ` Chao Yu
2019-04-30 1:37 ` Chao Yu
2019-05-01 12:31 ` Chandan Rajendra
2019-05-01 12:31 ` Chandan Rajendra
2019-04-30 18:05 ` Eric Biggers
2019-04-30 18:05 ` [f2fs-dev] " Eric Biggers
2019-04-30 18:05 ` Eric Biggers
2019-05-01 12:32 ` Chandan Rajendra
2019-05-01 12:32 ` Chandan Rajendra
2019-04-28 4:31 ` [PATCH V2 03/13] fsverity: Add call back to decide if verity check has to be performed Chandan Rajendra
2019-04-28 4:31 ` Chandan Rajendra
2019-04-30 21:10 ` Jeremy Sowden
2019-05-01 12:33 ` Chandan Rajendra
2019-05-01 12:33 ` Chandan Rajendra
2019-04-28 4:31 ` [PATCH V2 04/13] fsverity: Add call back to determine readpage limit Chandan Rajendra
2019-04-28 4:31 ` Chandan Rajendra
2019-04-28 4:31 ` [PATCH V2 05/13] fs/mpage.c: Integrate read callbacks Chandan Rajendra
2019-04-28 4:31 ` Chandan Rajendra
2019-04-28 4:31 ` [PATCH V2 06/13] ext4: Wire up ext4_readpage[s] to use mpage_readpage[s] Chandan Rajendra
2019-04-28 4:31 ` Chandan Rajendra
2019-04-28 4:31 ` Chandan Rajendra [this message]
2019-04-28 4:31 ` [PATCH V2 07/13] Add decryption support for sub-pagesized blocks Chandan Rajendra
2019-04-30 0:38 ` Eric Biggers
2019-04-30 0:38 ` [f2fs-dev] " Eric Biggers
2019-04-30 0:38 ` Eric Biggers
2019-05-01 13:40 ` Chandan Rajendra
2019-05-01 13:40 ` Chandan Rajendra
2019-04-28 4:31 ` [PATCH V2 08/13] ext4: Decrypt all boundary blocks when doing buffered write Chandan Rajendra
2019-04-28 4:31 ` Chandan Rajendra
2019-04-28 4:31 ` [PATCH V2 09/13] ext4: Decrypt the block that needs to be partially zeroed Chandan Rajendra
2019-04-28 4:31 ` Chandan Rajendra
2019-04-28 4:31 ` [PATCH V2 10/13] fscrypt_encrypt_page: Loop across all blocks mapped by a page range Chandan Rajendra
2019-04-28 4:31 ` Chandan Rajendra
2019-04-30 17:11 ` Eric Biggers
2019-04-30 17:11 ` [f2fs-dev] " Eric Biggers
2019-04-30 17:11 ` Eric Biggers
2019-04-30 23:08 ` [f2fs-dev] " Eric Biggers
2019-04-30 23:08 ` Eric Biggers
2019-05-01 14:49 ` [f2fs-dev] " Chandan Rajendra
2019-05-01 14:49 ` Chandan Rajendra
2019-05-01 22:29 ` [f2fs-dev] " Eric Biggers
2019-05-01 22:29 ` Eric Biggers
2019-05-02 5:52 ` [f2fs-dev] " Chandan Rajendra
2019-05-02 5:52 ` Chandan Rajendra
2019-05-02 18:16 ` [f2fs-dev] " Eric Biggers
2019-05-02 18:16 ` Eric Biggers
2019-04-28 4:31 ` [PATCH V2 11/13] ext4: Compute logical block and the page range to be encrypted Chandan Rajendra
2019-04-28 4:31 ` Chandan Rajendra
2019-04-30 17:01 ` Eric Biggers
2019-04-30 17:01 ` Eric Biggers
2019-05-01 14:11 ` Chandan Rajendra
2019-05-01 14:11 ` Chandan Rajendra
2019-04-28 4:31 ` [PATCH V2 12/13] fscrypt_zeroout_range: Encrypt all zeroed out blocks of a page Chandan Rajendra
2019-04-28 4:31 ` Chandan Rajendra
2019-04-30 16:51 ` Eric Biggers
2019-04-30 16:51 ` Eric Biggers
2019-05-01 14:22 ` Chandan Rajendra
2019-05-01 14:22 ` Chandan Rajendra
2019-04-28 4:31 ` [PATCH V2 13/13] ext4: Enable encryption for subpage-sized blocks Chandan Rajendra
2019-04-28 4:31 ` Chandan Rajendra
2019-04-30 0:27 ` [PATCH V2 00/13] Consolidate FS read I/O callbacks code Matthew Wilcox
2019-04-30 0:27 ` Matthew Wilcox
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190428043121.30925-8-chandan@linux.ibm.com \
--to=chandan@linux.ibm.com \
--cc=adilger.kernel@dilger.ca \
--cc=ebiggers@kernel.org \
--cc=hch@infradead.org \
--cc=jaegeuk@kernel.org \
--cc=linux-ext4@vger.kernel.org \
--cc=linux-f2fs-devel@lists.sourceforge.net \
--cc=linux-fscrypt@vger.kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=tytso@mit.edu \
--cc=yuchao0@huawei.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.