[RAMEN9610-8702][COMMON] diskcipher: support f2fs
[GitHub/LineageOS/android_kernel_motorola_exynos9610.git] / fs / crypto / bio.c
index 0d5e6a569d58ae2c775aad617200ca4fd1b88518..853a6f5d7abafb8ba2fe6f34ec17b93de66f7b2b 100644 (file)
 #include <linux/namei.h>
 #include "fscrypt_private.h"
 
-/*
- * Call fscrypt_decrypt_page on every single page, reusing the encryption
- * context.
- */
-static void completion_pages(struct work_struct *work)
+static void __fscrypt_decrypt_bio(struct bio *bio, bool done)
 {
-       struct fscrypt_ctx *ctx =
-               container_of(work, struct fscrypt_ctx, r.work);
-       struct bio *bio = ctx->r.bio;
        struct bio_vec *bv;
        int i;
 
@@ -46,22 +39,38 @@ static void completion_pages(struct work_struct *work)
                if (ret) {
                        WARN_ON_ONCE(1);
                        SetPageError(page);
-               } else {
+               } else if (done) {
                        SetPageUptodate(page);
                }
-               unlock_page(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, r.work);
+       struct bio *bio = ctx->r.bio;
+
+       __fscrypt_decrypt_bio(bio, true);
        fscrypt_release_ctx(ctx);
        bio_put(bio);
 }
 
-void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *ctx, struct bio *bio)
+void fscrypt_enqueue_decrypt_bio(struct fscrypt_ctx *ctx, struct bio *bio)
 {
        INIT_WORK(&ctx->r.work, completion_pages);
        ctx->r.bio = bio;
-       queue_work(fscrypt_read_workqueue, &ctx->r.work);
+       fscrypt_enqueue_decrypt_work(&ctx->r.work);
 }
-EXPORT_SYMBOL(fscrypt_decrypt_bio_pages);
+EXPORT_SYMBOL(fscrypt_enqueue_decrypt_bio);
 
 void fscrypt_pullback_bio_page(struct page **page, bool restore)
 {
@@ -87,29 +96,42 @@ EXPORT_SYMBOL(fscrypt_pullback_bio_page);
 int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk,
                                sector_t pblk, unsigned int len)
 {
-       struct fscrypt_ctx *ctx;
+       struct fscrypt_ctx *ctx = NULL;
        struct page *ciphertext_page = NULL;
        struct bio *bio;
        int ret, err = 0;
 
        BUG_ON(inode->i_sb->s_blocksize != PAGE_SIZE);
 
-       ctx = fscrypt_get_ctx(inode, GFP_NOFS);
-       if (IS_ERR(ctx))
-               return PTR_ERR(ctx);
+       if (__fscrypt_disk_encrypted(inode)) {
+               ciphertext_page = fscrypt_alloc_bounce_page(NULL, GFP_NOWAIT);
+               if (!ciphertext_page || IS_ERR(ciphertext_page)) {
+                       err = PTR_ERR(ciphertext_page);
+                       goto errout;
+               }
+
+               memset(page_address(ciphertext_page), 0, PAGE_SIZE);
+               ciphertext_page->mapping = inode->i_mapping;
+       } else {
+               ctx = fscrypt_get_ctx(inode, GFP_NOFS);
+               if (IS_ERR(ctx))
+                       return PTR_ERR(ctx);
 
-       ciphertext_page = fscrypt_alloc_bounce_page(ctx, GFP_NOWAIT);
-       if (IS_ERR(ciphertext_page)) {
-               err = PTR_ERR(ciphertext_page);
-               goto errout;
+               ciphertext_page = fscrypt_alloc_bounce_page(ctx, GFP_NOWAIT);
+               if (IS_ERR(ciphertext_page)) {
+                       err = PTR_ERR(ciphertext_page);
+                       goto errout;
+               }
        }
 
        while (len--) {
-               err = fscrypt_do_page_crypto(inode, FS_ENCRYPT, lblk,
-                                            ZERO_PAGE(0), ciphertext_page,
-                                            PAGE_SIZE, 0, GFP_NOFS);
-               if (err)
-                       goto errout;
+               if (ctx) {
+                       err = fscrypt_do_page_crypto(inode, FS_ENCRYPT, lblk,
+                                                    ZERO_PAGE(0), ciphertext_page,
+                                                    PAGE_SIZE, 0, GFP_NOFS);
+                       if (err)
+                               goto errout;
+               }
 
                bio = bio_alloc(GFP_NOWAIT, 1);
                if (!bio) {
@@ -119,7 +141,7 @@ int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk,
                bio_set_dev(bio, inode->i_sb->s_bdev);
                bio->bi_iter.bi_sector =
                        pblk << (inode->i_sb->s_blocksize_bits - 9);
-               bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
+               bio_set_op_attrs(bio, REQ_OP_WRITE, REQ_NOENCRYPT);
                ret = bio_add_page(bio, ciphertext_page,
                                        inode->i_sb->s_blocksize, 0);
                if (ret != inode->i_sb->s_blocksize) {
@@ -129,6 +151,8 @@ int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk,
                        err = -EIO;
                        goto errout;
                }
+               fscrypt_set_bio(inode, bio, 0);
+               crypto_diskcipher_debug(FS_ZEROPAGE, bio->bi_opf);
                err = submit_bio_wait(bio);
                if (err == 0 && bio->bi_status)
                        err = -EIO;
@@ -140,7 +164,33 @@ int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk,
        }
        err = 0;
 errout:
-       fscrypt_release_ctx(ctx);
+       if (!ctx && ciphertext_page)
+               fscrypt_free_bounce_page(ciphertext_page);
+       else
+               fscrypt_release_ctx(ctx);
        return err;
 }
 EXPORT_SYMBOL(fscrypt_zeroout_range);
+
+int fscrypt_disk_encrypted(const struct inode *inode)
+{
+       return __fscrypt_disk_encrypted(inode);
+}
+
+void fscrypt_set_bio(const struct inode *inode, struct bio *bio, u64 dun)
+{
+#ifdef CONFIG_CRYPTO_DISKCIPHER
+       if (__fscrypt_disk_encrypted(inode))
+               crypto_diskcipher_set(bio, inode->i_crypt_info->ci_dtfm, inode, dun);
+#endif
+       return;
+}
+
+void *fscrypt_get_diskcipher(const struct inode *inode)
+{
+#ifdef CONFIG_CRYPTO_DISKCIPHER
+       if (fscrypt_has_encryption_key(inode))
+               return inode->i_crypt_info->ci_dtfm;
+#endif
+       return NULL;
+}