[RAMEN9610-8702][COMMON] diskcipher: support f2fs
[GitHub/LineageOS/android_kernel_motorola_exynos9610.git] / fs / f2fs / data.c
index da7b00e6559b247427426d7218e2faf54dfc5670..513e24024a75b58b5dfad85335c4b5bd2f2cf7ff 100644 (file)
@@ -19,8 +19,6 @@
 #include <linux/bio.h>
 #include <linux/prefetch.h>
 #include <linux/uio.h>
-#include <linux/mm.h>
-#include <linux/memcontrol.h>
 #include <linux/cleancache.h>
 #include <linux/sched/signal.h>
 
 #include <trace/events/f2fs.h>
 #include <trace/events/android_fs.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;
@@ -51,11 +54,126 @@ static bool __is_cp_guaranteed(struct page *page)
        return false;
 }
 
-static void f2fs_read_end_io(struct bio *bio)
+/* postprocessing steps for read bios */
+enum bio_post_read_step {
+       STEP_INITIAL = 0,
+       STEP_DECRYPT,
+};
+
+struct bio_post_read_ctx {
+       struct bio *bio;
+       struct work_struct work;
+       unsigned int cur_step;
+       unsigned int enabled_steps;
+};
+
+/* device unit number for iv sector */
+#define PG_DUN(i,p)                                            \
+       ((((i)->i_ino & 0xffffffff) << 32) | ((p)->index & 0xffffffff))
+
+static inline bool f2fs_may_encrypt_bio(struct inode *inode,
+               struct f2fs_io_info *fio)
 {
-       struct bio_vec *bvec;
+#ifdef CONFIG_CRYPTO_DISKCIPHER
+       if (fio && (fio->type != DATA || fio->encrypted_page))
+               return false;
+
+       return (f2fs_encrypted_file(inode) &&
+                       fscrypt_disk_encrypted(inode));
+#else
+       return false;
+#endif
+}
+
+static inline bool f2fs_bio_disk_encrypted(unsigned int bi_opf)
+{
+       if (bi_opf & REQ_CRYPT)
+               return true;
+       else
+               return false;
+}
+
+static bool f2fs_mergeable_bio(struct bio *bio, u64 dun, void *ci, bool bio_encrypted)
+{
+#ifdef CONFIG_CRYPTO_DISKCIPHER
+       if (!bio)
+               return true;
+
+       /* if both of them are not encrypted, no further check is needed */
+       if (!f2fs_bio_disk_encrypted(bio->bi_opf) && !bio_encrypted)
+               return true;
+
+#ifdef CONFIG_CRYPTO_DISKCIPHER_DUN
+       if (bio->bi_aux_private == ci)
+               return bio_end_dun(bio) == dun;
+       else
+               return false;
+#else
+       return bio->bi_aux_private == ci;
+#endif
+#else
+       return true;
+#endif
+}
+
+static void __read_end_io(struct bio *bio)
+{
+       struct page *page;
+       struct bio_vec *bv;
        int i;
 
+       bio_for_each_segment_all(bv, bio, i) {
+               page = bv->bv_page;
+
+               /* PG_error was set if any post_read step failed */
+               if (bio->bi_status || PageError(page)) {
+                       ClearPageUptodate(page);
+                       SetPageError(page);
+               } else {
+                       SetPageUptodate(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);
+}
+
+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);
+       }
+}
+
+static bool f2fs_bio_post_read_required(struct bio *bio)
+{
+       return bio->bi_private && !bio->bi_status;
+}
+
+static void f2fs_read_end_io(struct bio *bio)
+{
 #ifdef CONFIG_F2FS_FAULT_INJECTION
        if (time_to_inject(F2FS_P_SB(bio->bi_io_vec->bv_page), FAULT_IO)) {
                f2fs_show_injection_info(FAULT_IO);
@@ -63,28 +181,19 @@ static void f2fs_read_end_io(struct bio *bio)
        }
 #endif
 
-       if (f2fs_bio_encrypted(bio)) {
-               if (bio->bi_status) {
-                       fscrypt_release_ctx(bio->bi_private);
-               } else {
-                       fscrypt_decrypt_bio_pages(bio->bi_private, bio);
-                       return;
-               }
-       }
+       if(f2fs_bio_disk_encrypted(bio->bi_opf))
+               goto end_io;
 
-       bio_for_each_segment_all(bvec, bio, i) {
-               struct page *page = bvec->bv_page;
+       if (f2fs_bio_post_read_required(bio)) {
+               struct bio_post_read_ctx *ctx = bio->bi_private;
 
-               if (!bio->bi_status) {
-                       if (!PageUptodate(page))
-                               SetPageUptodate(page);
-               } else {
-                       ClearPageUptodate(page);
-                       SetPageError(page);
-               }
-               unlock_page(page);
+               ctx->cur_step = STEP_INITIAL;
+               bio_post_read_processing(ctx);
+               return;
        }
-       bio_put(bio);
+
+end_io:
+       __read_end_io(bio);
 }
 
 static void f2fs_write_end_io(struct bio *bio)
@@ -176,15 +285,22 @@ static bool __same_bdev(struct f2fs_sb_info *sbi,
  */
 static struct bio *__bio_alloc(struct f2fs_sb_info *sbi, block_t blk_addr,
                                struct writeback_control *wbc,
-                               int npages, bool is_read)
+                               int npages, bool is_read,
+                               enum page_type type, enum temp_type temp)
 {
        struct bio *bio;
 
        bio = f2fs_bio_alloc(sbi, npages, true);
 
        f2fs_target_device(sbi, blk_addr, bio);
-       bio->bi_end_io = is_read ? f2fs_read_end_io : f2fs_write_end_io;
-       bio->bi_private = is_read ? NULL : sbi;
+       if (is_read) {
+               bio->bi_end_io = f2fs_read_end_io;
+               bio->bi_private = NULL;
+       } else {
+               bio->bi_end_io = f2fs_write_end_io;
+               bio->bi_private = sbi;
+               bio->bi_write_hint = io_type_to_rw_hint(sbi, type, temp);
+       }
        if (wbc)
                wbc_init_bio(wbc, bio);
 
@@ -197,13 +313,12 @@ static inline void __submit_bio(struct f2fs_sb_info *sbi,
        if (!is_read_io(bio_op(bio))) {
                unsigned int start;
 
-               if (f2fs_sb_mounted_blkzoned(sbi->sb) &&
-                       current->plug && (type == DATA || type == NODE))
-                       blk_finish_plug(current->plug);
-
                if (type != DATA && type != NODE)
                        goto submit_io;
 
+               if (f2fs_sb_has_blkzoned(sbi->sb) && current->plug)
+                       blk_finish_plug(current->plug);
+
                start = bio->bi_iter.bi_size >> F2FS_BLKSIZE_BITS;
                start %= F2FS_IO_SIZE(sbi);
 
@@ -245,7 +360,10 @@ static void __submit_merged_bio(struct f2fs_bio_info *io)
        if (!io->bio)
                return;
 
-       bio_set_op_attrs(io->bio, fio->op, fio->op_flags);
+       if (f2fs_bio_disk_encrypted(io->bio->bi_opf))
+               bio_set_op_attrs(io->bio, fio->op, fio->op_flags | REQ_CRYPT);
+       else
+               bio_set_op_attrs(io->bio, fio->op, fio->op_flags);
 
        if (is_read_io(fio->op))
                trace_f2fs_prepare_read_bio(io->sbi->sb, fio->type, io->bio);
@@ -377,20 +495,26 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)
        struct bio *bio;
        struct page *page = fio->encrypted_page ?
                        fio->encrypted_page : fio->page;
+       struct inode *inode = fio->page->mapping->host;
 
+       verify_block_addr(fio, fio->new_blkaddr);
        trace_f2fs_submit_page_bio(page, fio);
        f2fs_trace_ios(fio, 0);
 
        /* Allocate a new bio */
        bio = __bio_alloc(fio->sbi, fio->new_blkaddr, fio->io_wbc,
-                               1, is_read_io(fio->op));
+                               1, is_read_io(fio->op), fio->type, fio->temp);
 
        if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) {
                bio_put(bio);
                return -EFAULT;
        }
+       fio->op_flags |= fio->encrypted_page ? REQ_NOENCRYPT : 0;
        bio_set_op_attrs(bio, fio->op, fio->op_flags);
 
+       if (f2fs_may_encrypt_bio(inode, fio))
+               fscrypt_set_bio(inode, bio, PG_DUN(inode, fio->page));
+
        __submit_bio(fio->sbi, bio, fio->type);
 
        if (!is_read_io(fio->op))
@@ -405,6 +529,9 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio)
        struct f2fs_bio_info *io = sbi->write_io[btype] + fio->temp;
        struct page *bio_page;
        int err = 0;
+       struct inode *inode;
+       bool bio_encrypted;
+       u64 dun;
 
        f2fs_bug_on(sbi, is_read_io(fio->op));
 
@@ -423,10 +550,14 @@ next:
        }
 
        if (fio->old_blkaddr != NEW_ADDR)
-               verify_block_addr(sbi, fio->old_blkaddr);
-       verify_block_addr(sbi, fio->new_blkaddr);
+               verify_block_addr(fio, fio->old_blkaddr);
+       verify_block_addr(fio, fio->new_blkaddr);
 
        bio_page = fio->encrypted_page ? fio->encrypted_page : fio->page;
+       inode = fio->page->mapping->host;
+       dun = PG_DUN(inode, fio->page);
+       bio_encrypted = f2fs_may_encrypt_bio(inode, fio);
+       fio->op_flags |= fio->encrypted_page ? REQ_NOENCRYPT : 0;
 
        /* set submitted = true as a return value */
        fio->submitted = true;
@@ -437,6 +568,10 @@ next:
            (io->fio.op != fio->op || io->fio.op_flags != fio->op_flags) ||
                        !__same_bdev(sbi, fio->new_blkaddr, io->bio)))
                __submit_merged_bio(io);
+
+       if (!f2fs_mergeable_bio(io->bio, dun, fscrypt_get_diskcipher(inode), bio_encrypted))
+               __submit_merged_bio(io);
+
 alloc_new:
        if (io->bio == NULL) {
                if ((fio->type == DATA || fio->type == NODE) &&
@@ -446,7 +581,11 @@ alloc_new:
                        goto out_fail;
                }
                io->bio = __bio_alloc(sbi, fio->new_blkaddr, fio->io_wbc,
-                                               BIO_MAX_PAGES, false);
+                                               BIO_MAX_PAGES, false,
+                                               fio->type, fio->temp);
+               if (bio_encrypted)
+                       fscrypt_set_bio(inode, io->bio, dun);
+
                io->fio = *fio;
        }
 
@@ -474,29 +613,37 @@ static struct bio *f2fs_grab_read_bio(struct inode *inode, block_t blkaddr,
                                                         unsigned nr_pages)
 {
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
-       struct fscrypt_ctx *ctx = NULL;
        struct bio *bio;
-
-       if (f2fs_encrypted_file(inode)) {
-               ctx = fscrypt_get_ctx(inode, GFP_NOFS);
-               if (IS_ERR(ctx))
-                       return ERR_CAST(ctx);
-
-               /* wait the page to be moved by cleaning */
-               f2fs_wait_on_block_writeback(sbi, blkaddr);
-       }
+       struct bio_post_read_ctx *ctx;
+       unsigned int post_read_steps = 0;
 
        bio = f2fs_bio_alloc(sbi, min_t(int, nr_pages, BIO_MAX_PAGES), false);
-       if (!bio) {
-               if (ctx)
-                       fscrypt_release_ctx(ctx);
+       if (!bio)
                return ERR_PTR(-ENOMEM);
-       }
        f2fs_target_device(sbi, blkaddr, bio);
        bio->bi_end_io = f2fs_read_end_io;
-       bio->bi_private = ctx;
        bio_set_op_attrs(bio, REQ_OP_READ, 0);
 
+       if (f2fs_encrypted_file(inode) && !fscrypt_disk_encrypted(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;
+               bio_set_op_attrs(bio, REQ_OP_READ,
+                       (f2fs_encrypted_inode(inode) ?
+                        REQ_NOENCRYPT :
+                        0));
+
+               /* wait the page to be moved by cleaning */
+               f2fs_wait_on_block_writeback(sbi, blkaddr);
+       }
+
        return bio;
 }
 
@@ -513,6 +660,10 @@ static int f2fs_submit_page_read(struct inode *inode, struct page *page,
                bio_put(bio);
                return -EFAULT;
        }
+
+       if (f2fs_may_encrypt_bio(inode, NULL))
+               fscrypt_set_bio(inode, bio, PG_DUN(inode, page));
+
        __submit_bio(F2FS_I_SB(inode), bio, DATA);
        return 0;
 }
@@ -833,13 +984,6 @@ alloc:
        return 0;
 }
 
-static inline bool __force_buffered_io(struct inode *inode, int rw)
-{
-       return (f2fs_encrypted_file(inode) ||
-                       (rw == WRITE && test_opt(F2FS_I_SB(inode), LFS)) ||
-                       F2FS_I_SB(inode)->s_ndevs);
-}
-
 int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from)
 {
        struct inode *inode = file_inode(iocb->ki_filp);
@@ -871,7 +1015,7 @@ int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from)
 
        if (direct_io) {
                map.m_seg_type = rw_hint_to_seg_type(iocb->ki_hint);
-               flag = __force_buffered_io(inode, WRITE) ?
+               flag = f2fs_force_buffered_io(inode, WRITE) ?
                                        F2FS_GET_BLOCK_PRE_AIO :
                                        F2FS_GET_BLOCK_PRE_DIO;
                goto map_blocks;
@@ -1115,6 +1259,31 @@ out:
        return err;
 }
 
+bool f2fs_overwrite_io(struct inode *inode, loff_t pos, size_t len)
+{
+       struct f2fs_map_blocks map;
+       block_t last_lblk;
+       int err;
+
+       if (pos + len > i_size_read(inode))
+               return false;
+
+       map.m_lblk = F2FS_BYTES_TO_BLK(pos);
+       map.m_next_pgofs = NULL;
+       map.m_next_extent = NULL;
+       map.m_seg_type = NO_CHECK_TYPE;
+       last_lblk = F2FS_BLK_ALIGN(pos + len);
+
+       while (map.m_lblk < last_lblk) {
+               map.m_len = last_lblk - map.m_lblk;
+               err = f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_DEFAULT);
+               if (err || map.m_len == 0)
+                       return false;
+               map.m_lblk += map.m_len;
+       }
+       return true;
+}
+
 static int __get_data_block(struct inode *inode, sector_t iblock,
                        struct buffer_head *bh, int create, int flag,
                        pgoff_t *next_pgofs, int seg_type)
@@ -1350,6 +1519,8 @@ static int f2fs_mpage_readpages(struct address_space *mapping,
        sector_t last_block_in_file;
        sector_t block_nr;
        struct f2fs_map_blocks map;
+       bool bio_encrypted;
+       u64 dun;
 
        map.m_pblk = 0;
        map.m_lblk = 0;
@@ -1427,12 +1598,22 @@ submit_and_realloc:
                        __submit_bio(F2FS_I_SB(inode), bio, DATA);
                        bio = NULL;
                }
+
+               dun = PG_DUN(inode, page);
+               bio_encrypted = f2fs_may_encrypt_bio(inode, NULL);
+               if (!f2fs_mergeable_bio(bio, dun, fscrypt_get_diskcipher(inode), bio_encrypted)) {
+                       __submit_bio(F2FS_I_SB(inode), bio, DATA);
+                       bio = NULL;
+               }
+
                if (bio == NULL) {
                        bio = f2fs_grab_read_bio(inode, block_nr, nr_pages);
                        if (IS_ERR(bio)) {
                                bio = NULL;
                                goto set_error_page;
                        }
+                       if (f2fs_may_encrypt_bio(inode, NULL))
+                               fscrypt_set_bio(inode, bio, dun);
                }
 
                if (bio_add_page(bio, page, blocksize, 0) < blocksize)
@@ -1500,10 +1681,13 @@ static int encrypt_one_page(struct f2fs_io_info *fio)
        if (!f2fs_encrypted_file(inode))
                return 0;
 
-       /* wait for GCed encrypted page writeback */
+       /* wait for GCed page writeback via META_MAPPING */
        f2fs_wait_on_block_writeback(fio->sbi, fio->old_blkaddr);
 
 retry_encrypt:
+       if (fscrypt_disk_encrypted(inode))
+               return 0;
+
        fio->encrypted_page = fscrypt_encrypt_page(inode, fio->page,
                        PAGE_SIZE, 0, fio->page->index, gfp_flags);
        if (!IS_ERR(fio->encrypted_page))
@@ -1650,6 +1834,7 @@ got_it:
                        goto out_writepage;
 
                set_page_writeback(page);
+               ClearPageError(page);
                f2fs_put_dnode(&dn);
                if (fio->need_lock == LOCK_REQ)
                        f2fs_unlock_op(fio->sbi);
@@ -1672,6 +1857,7 @@ got_it:
                goto out_writepage;
 
        set_page_writeback(page);
+       ClearPageError(page);
 
        /* LFS mode write path */
        write_data_page(&dn, fio);
@@ -1817,7 +2003,13 @@ out:
 
 redirty_out:
        redirty_page_for_writepage(wbc, page);
-       if (!err)
+       /*
+        * pageout() in MM traslates EAGAIN, so calls handle_write_error()
+        * -> mapping_set_error() -> set_bit(AS_EIO, ...).
+        * file_write_and_wait_range() will see EIO error, which is critical
+        * to return value of fsync() followed by atomic_write failure to user.
+        */
+       if (!err || wbc->for_reclaim)
                return AOP_WRITEPAGE_ACTIVATE;
        unlock_page(page);
        return err;
@@ -2212,8 +2404,8 @@ repeat:
 
        f2fs_wait_on_page_writeback(page, DATA, false);
 
-       /* wait for GCed encrypted page writeback */
-       if (f2fs_encrypted_file(inode))
+       /* wait for GCed page writeback via META_MAPPING */
+       if (f2fs_post_read_required(inode))
                f2fs_wait_on_block_writeback(sbi, blkaddr);
 
        if (len == PAGE_SIZE || PageUptodate(page))
@@ -2304,16 +2496,19 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
 {
        struct address_space *mapping = iocb->ki_filp->f_mapping;
        struct inode *inode = mapping->host;
+       struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
        size_t count = iov_iter_count(iter);
        loff_t offset = iocb->ki_pos;
        int rw = iov_iter_rw(iter);
        int err;
+       enum rw_hint hint = iocb->ki_hint;
+       int whint_mode = F2FS_OPTION(sbi).whint_mode;
 
        err = check_direct_IO(inode, iter, offset);
        if (err)
                return err;
 
-       if (__force_buffered_io(inode, rw))
+       if (f2fs_force_buffered_io(inode, rw))
                return 0;
 
        trace_f2fs_direct_IO_enter(inode, offset, count, rw);
@@ -2340,12 +2535,24 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
                                                 current->pid, path,
                                                 current->comm);
        }
+       if (rw == WRITE && whint_mode == WHINT_MODE_OFF)
+               iocb->ki_hint = WRITE_LIFE_NOT_SET;
+
+       if (!down_read_trylock(&F2FS_I(inode)->dio_rwsem[rw])) {
+               if (iocb->ki_flags & IOCB_NOWAIT) {
+                       iocb->ki_hint = hint;
+                       err = -EAGAIN;
+                       goto out;
+               }
+               down_read(&F2FS_I(inode)->dio_rwsem[rw]);
+       }
 
-       down_read(&F2FS_I(inode)->dio_rwsem[rw]);
        err = blockdev_direct_IO(iocb, inode, iter, get_data_block_dio);
        up_read(&F2FS_I(inode)->dio_rwsem[rw]);
 
        if (rw == WRITE) {
+               if (whint_mode == WHINT_MODE_OFF)
+                       iocb->ki_hint = hint;
                if (err > 0) {
                        f2fs_update_iostat(F2FS_I_SB(inode), APP_DIRECT_IO,
                                                                        err);
@@ -2354,7 +2561,7 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
                        f2fs_write_failed(mapping, offset + count);
                }
        }
-
+out:
        if (trace_android_fs_dataread_start_enabled() &&
            (rw == READ))
                trace_android_fs_dataread_end(inode, offset, count);
@@ -2411,35 +2618,6 @@ int f2fs_release_page(struct page *page, gfp_t wait)
        return 1;
 }
 
-/*
- * This was copied from __set_page_dirty_buffers which gives higher performance
- * in very high speed storages. (e.g., pmem)
- */
-void f2fs_set_page_dirty_nobuffers(struct page *page)
-{
-       struct address_space *mapping = page->mapping;
-       unsigned long flags;
-
-       if (unlikely(!mapping))
-               return;
-
-       spin_lock(&mapping->private_lock);
-       lock_page_memcg(page);
-       SetPageDirty(page);
-       spin_unlock(&mapping->private_lock);
-
-       spin_lock_irqsave(&mapping->tree_lock, flags);
-       WARN_ON_ONCE(!PageUptodate(page));
-       account_page_dirtied(page, mapping);
-       radix_tree_tag_set(&mapping->page_tree,
-                       page_index(page), PAGECACHE_TAG_DIRTY);
-       spin_unlock_irqrestore(&mapping->tree_lock, flags);
-       unlock_page_memcg(page);
-
-       __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
-       return;
-}
-
 static int f2fs_set_data_page_dirty(struct page *page)
 {
        struct address_space *mapping = page->mapping;
@@ -2463,7 +2641,7 @@ static int f2fs_set_data_page_dirty(struct page *page)
        }
 
        if (!PageDirty(page)) {
-               f2fs_set_page_dirty_nobuffers(page);
+               __set_page_dirty_nobuffers(page);
                update_dirty_page(inode, page);
                return 1;
        }
@@ -2559,3 +2737,27 @@ const struct address_space_operations f2fs_dblock_aops = {
        .migratepage    = f2fs_migrate_page,
 #endif
 };
+
+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);
+}