This commit gets Ext4 and F2FS to make use of read callbacks API to perform decryption of file data read from the disk. --- fs/crypto/bio.c | 30 +-------- fs/crypto/crypto.c | 1 + fs/crypto/fscrypt_private.h | 3 + fs/ext4/readpage.c | 29 +++------ fs/f2fs/data.c | 124 +++++++----------------------------- fs/f2fs/super.c | 9 +-- fs/read_callbacks.c | 1 - include/linux/fscrypt.h | 18 ------ 8 files changed, 40 insertions(+), 175 deletions(-) diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c index f677ff93d464..4076d704e2e4 100644 --- a/fs/crypto/bio.c +++ b/fs/crypto/bio.c @@ -27,7 +27,7 @@ #include <linux/read_callbacks.h> #include "fscrypt_private.h" -static void __fscrypt_decrypt_bio(struct bio *bio, bool done) +static void fscrypt_decrypt_bio(struct bio *bio) { struct bio_vec *bv; struct bvec_iter_all iter_all; @@ -38,37 +38,9 @@ static void __fscrypt_decrypt_bio(struct bio *bio, bool done) bv->bv_offset); if (ret) SetPageError(page); - else if (done) - SetPageUptodate(page); - if (done) - unlock_page(page); } } -void fscrypt_decrypt_bio(struct bio *bio) -{ - __fscrypt_decrypt_bio(bio, false); -} -EXPORT_SYMBOL(fscrypt_decrypt_bio); - -static void completion_pages(struct work_struct *work) -{ - struct fscrypt_ctx *ctx = container_of(work, struct fscrypt_ctx, work); - struct bio *bio = ctx->bio; - - __fscrypt_decrypt_bio(bio, true); - fscrypt_release_ctx(ctx); - bio_put(bio); -} - -void fscrypt_enqueue_decrypt_bio(struct fscrypt_ctx *ctx, struct bio *bio) -{ - INIT_WORK(&ctx->work, completion_pages); - ctx->bio = bio; - fscrypt_enqueue_decrypt_work(&ctx->work); -} -EXPORT_SYMBOL(fscrypt_enqueue_decrypt_bio); - void fscrypt_decrypt_work(struct work_struct *work) { struct read_callbacks_ctx *ctx = diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index 45c3d0427fb2..e0aa20cfcaa7 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -54,6 +54,7 @@ struct kmem_cache *fscrypt_info_cachep; void fscrypt_enqueue_decrypt_work(struct work_struct *work) { + INIT_WORK(work, fscrypt_decrypt_work); queue_work(fscrypt_read_workqueue, work); } EXPORT_SYMBOL(fscrypt_enqueue_decrypt_work); diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index 8978eec9d766..0bd65921efbf 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -113,6 +113,9 @@ static inline bool fscrypt_valid_enc_modes(u32 contents_mode, return false; } +/* bio.c */ +void fscrypt_decrypt_work(struct work_struct *work); + /* crypto.c */ extern struct kmem_cache *fscrypt_info_cachep; extern int fscrypt_initialize(unsigned int cop_flags); diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c index c916017db334..652796b95545 100644 --- a/fs/ext4/readpage.c +++ b/fs/ext4/readpage.c @@ -44,6 +44,7 @@ #include <linux/backing-dev.h> #include <linux/pagevec.h> #include <linux/cleancache.h> +#include <linux/read_callbacks.h> #include "ext4.h" @@ -73,14 +74,9 @@ static void mpage_end_io(struct bio *bio) struct bio_vec *bv; struct bvec_iter_all iter_all; - if (ext4_bio_encrypted(bio)) { - if (bio->bi_status) { - fscrypt_release_ctx(bio->bi_private); - } else { - fscrypt_enqueue_decrypt_bio(bio->bi_private, bio); - return; - } - } + if (read_callbacks_end_bio(bio)) + return; + bio_for_each_segment_all(bv, bio, iter_all) { struct page *page = bv->bv_page; @@ -241,24 +237,19 @@ int ext4_mpage_readpages(struct address_space *mapping, bio = NULL; } if (bio == NULL) { - struct fscrypt_ctx *ctx = NULL; - - if (IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode)) { - ctx = fscrypt_get_ctx(GFP_NOFS); - if (IS_ERR(ctx)) - goto set_error_page; - } bio = bio_alloc(GFP_KERNEL, min_t(int, nr_pages, BIO_MAX_PAGES)); - if (!bio) { - if (ctx) - fscrypt_release_ctx(ctx); + if (!bio) + goto set_error_page; + + if (read_callbacks_setup(inode, bio, NULL)) { + bio_put(bio); goto set_error_page; } + bio_set_dev(bio, bdev); bio->bi_iter.bi_sector = blocks[0] << (blkbits - 9); bio->bi_end_io = mpage_end_io; - bio->bi_private = ctx; bio_set_op_attrs(bio, REQ_OP_READ, is_readahead ? REQ_RAHEAD : 0); } diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index a546ac8685ea..23b34399d809 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -18,6 +18,7 @@ #include <linux/uio.h> #include <linux/cleancache.h> #include <linux/sched/signal.h> +#include <linux/read_callbacks.h> #include "f2fs.h" #include "node.h" @@ -25,11 +26,6 @@ #include "trace.h" #include <trace/events/f2fs.h> -#define NUM_PREALLOC_POST_READ_CTXS 128 - -static struct kmem_cache *bio_post_read_ctx_cache; -static mempool_t *bio_post_read_ctx_pool; - static bool __is_cp_guaranteed(struct page *page) { struct address_space *mapping = page->mapping; @@ -69,18 +65,19 @@ static enum count_type __read_io_type(struct page *page) return F2FS_RD_DATA; } -/* postprocessing steps for read bios */ -enum bio_post_read_step { - STEP_INITIAL = 0, - STEP_DECRYPT, -}; +static void f2fs_end_page_op(struct bio *bio, struct page *page) +{ + BUG_ON(!PageLocked(page)); -struct bio_post_read_ctx { - struct bio *bio; - struct work_struct work; - unsigned int cur_step; - unsigned int enabled_steps; -}; + /* PG_error was set if any post_read step failed */ + if (bio->bi_status || PageError(page)) { + ClearPageUptodate(page); + /* will re-read again later */ + ClearPageError(page); + } + + dec_page_count(F2FS_P_SB(page), __read_io_type(page)); +} static void __read_end_io(struct bio *bio) { @@ -91,53 +88,15 @@ static void __read_end_io(struct bio *bio) bio_for_each_segment_all(bv, bio, iter_all) { page = bv->bv_page; - /* PG_error was set if any post_read step failed */ - if (bio->bi_status || PageError(page)) { - ClearPageUptodate(page); - /* will re-read again later */ - ClearPageError(page); - } else { + if (!bio->bi_status && !PageError(page)) SetPageUptodate(page); - } - dec_page_count(F2FS_P_SB(page), __read_io_type(page)); - unlock_page(page); - } - if (bio->bi_private) - mempool_free(bio->bi_private, bio_post_read_ctx_pool); - bio_put(bio); -} -static void bio_post_read_processing(struct bio_post_read_ctx *ctx); - -static void decrypt_work(struct work_struct *work) -{ - struct bio_post_read_ctx *ctx = - container_of(work, struct bio_post_read_ctx, work); - - fscrypt_decrypt_bio(ctx->bio); - - bio_post_read_processing(ctx); -} + f2fs_end_page_op(bio, page); -static void bio_post_read_processing(struct bio_post_read_ctx *ctx) -{ - switch (++ctx->cur_step) { - case STEP_DECRYPT: - if (ctx->enabled_steps & (1 << STEP_DECRYPT)) { - INIT_WORK(&ctx->work, decrypt_work); - fscrypt_enqueue_decrypt_work(&ctx->work); - return; - } - ctx->cur_step++; - /* fall-through */ - default: - __read_end_io(ctx->bio); + unlock_page(page); } -} -static bool f2fs_bio_post_read_required(struct bio *bio) -{ - return bio->bi_private && !bio->bi_status; + bio_put(bio); } static void f2fs_read_end_io(struct bio *bio) @@ -148,13 +107,8 @@ static void f2fs_read_end_io(struct bio *bio) bio->bi_status = BLK_STS_IOERR; } - if (f2fs_bio_post_read_required(bio)) { - struct bio_post_read_ctx *ctx = bio->bi_private; - - ctx->cur_step = STEP_INITIAL; - bio_post_read_processing(ctx); + if (read_callbacks_end_bio(bio)) return; - } __read_end_io(bio); } @@ -557,8 +511,7 @@ static struct bio *f2fs_grab_read_bio(struct inode *inode, block_t blkaddr, { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct bio *bio; - struct bio_post_read_ctx *ctx; - unsigned int post_read_steps = 0; + int ret; bio = f2fs_bio_alloc(sbi, min_t(int, nr_pages, BIO_MAX_PAGES), false); if (!bio) @@ -567,17 +520,10 @@ static struct bio *f2fs_grab_read_bio(struct inode *inode, block_t blkaddr, bio->bi_end_io = f2fs_read_end_io; bio_set_op_attrs(bio, REQ_OP_READ, op_flag); - if (f2fs_encrypted_file(inode)) - post_read_steps |= 1 << STEP_DECRYPT; - if (post_read_steps) { - ctx = mempool_alloc(bio_post_read_ctx_pool, GFP_NOFS); - if (!ctx) { - bio_put(bio); - return ERR_PTR(-ENOMEM); - } - ctx->bio = bio; - ctx->enabled_steps = post_read_steps; - bio->bi_private = ctx; + ret = read_callbacks_setup(inode, bio, f2fs_end_page_op); + if (ret) { + bio_put(bio); + return ERR_PTR(ret); } return bio; @@ -2902,27 +2848,3 @@ void f2fs_clear_page_cache_dirty_tag(struct page *page) PAGECACHE_TAG_DIRTY); xa_unlock_irqrestore(&mapping->i_pages, flags); } - -int __init f2fs_init_post_read_processing(void) -{ - bio_post_read_ctx_cache = KMEM_CACHE(bio_post_read_ctx, 0); - if (!bio_post_read_ctx_cache) - goto fail; - bio_post_read_ctx_pool = - mempool_create_slab_pool(NUM_PREALLOC_POST_READ_CTXS, - bio_post_read_ctx_cache); - if (!bio_post_read_ctx_pool) - goto fail_free_cache; - return 0; - -fail_free_cache: - kmem_cache_destroy(bio_post_read_ctx_cache); -fail: - return -ENOMEM; -} - -void __exit f2fs_destroy_post_read_processing(void) -{ - mempool_destroy(bio_post_read_ctx_pool); - kmem_cache_destroy(bio_post_read_ctx_cache); -} diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 6b959bbb336a..e2e6a8c7236c 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -3627,15 +3627,11 @@ static int __init init_f2fs_fs(void) err = register_filesystem(&f2fs_fs_type); if (err) goto free_shrinker; + f2fs_create_root_stats(); - err = f2fs_init_post_read_processing(); - if (err) - goto free_root_stats; + return 0; -free_root_stats: - f2fs_destroy_root_stats(); - unregister_filesystem(&f2fs_fs_type); free_shrinker: unregister_shrinker(&f2fs_shrinker_info); free_sysfs: @@ -3656,7 +3652,6 @@ static int __init init_f2fs_fs(void) static void __exit exit_f2fs_fs(void) { - f2fs_destroy_post_read_processing(); f2fs_destroy_root_stats(); unregister_filesystem(&f2fs_fs_type); unregister_shrinker(&f2fs_shrinker_info); diff --git a/fs/read_callbacks.c b/fs/read_callbacks.c index a4196e3de05f..4b7fc2a349cd 100644 --- a/fs/read_callbacks.c +++ b/fs/read_callbacks.c @@ -76,7 +76,6 @@ void read_callbacks(struct read_callbacks_ctx *ctx) switch (++ctx->cur_step) { case STEP_DECRYPT: if (ctx->enabled_steps & (1 << STEP_DECRYPT)) { - INIT_WORK(&ctx->work, fscrypt_decrypt_work); fscrypt_enqueue_decrypt_work(&ctx->work); return; } diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h index 159b8ddcd670..4ec0bd7cc0ba 100644 --- a/include/linux/fscrypt.h +++ b/include/linux/fscrypt.h @@ -232,10 +232,6 @@ static inline bool fscrypt_match_name(const struct fscrypt_name *fname, } /* bio.c */ -extern void fscrypt_decrypt_bio(struct bio *); -extern void fscrypt_enqueue_decrypt_bio(struct fscrypt_ctx *ctx, - struct bio *bio); -extern void fscrypt_decrypt_work(struct work_struct *work); extern int fscrypt_zeroout_range(const struct inode *, pgoff_t, sector_t, unsigned int); @@ -431,20 +427,6 @@ static inline bool fscrypt_match_name(const struct fscrypt_name *fname, return !memcmp(de_name, fname->disk_name.name, fname->disk_name.len); } -/* bio.c */ -static inline void fscrypt_decrypt_bio(struct bio *bio) -{ -} - -static inline void fscrypt_enqueue_decrypt_bio(struct fscrypt_ctx *ctx, - struct bio *bio) -{ -} - -static inline void fscrypt_decrypt_work(struct work_struct *work) -{ -} - static inline int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk, sector_t pblk, unsigned int len) { -- 2.19.1