[RAMEN9610-8702][COMMON] diskcipher: support f2fs
[GitHub/LineageOS/android_kernel_motorola_exynos9610.git] / fs / f2fs / data.c
index 96ebf8da4a228e110b7091e837ec793aceb1c014..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>
 
@@ -69,6 +67,55 @@ struct bio_post_read_ctx {
        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)
+{
+#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;
@@ -134,6 +181,9 @@ static void f2fs_read_end_io(struct bio *bio)
        }
 #endif
 
+       if(f2fs_bio_disk_encrypted(bio->bi_opf))
+               goto end_io;
+
        if (f2fs_bio_post_read_required(bio)) {
                struct bio_post_read_ctx *ctx = bio->bi_private;
 
@@ -142,6 +192,7 @@ static void f2fs_read_end_io(struct bio *bio)
                return;
        }
 
+end_io:
        __read_end_io(bio);
 }
 
@@ -309,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);
@@ -441,6 +495,7 @@ 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);
@@ -454,8 +509,12 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)
                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))
@@ -470,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));
 
@@ -492,6 +554,10 @@ next:
        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;
@@ -502,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) &&
@@ -513,6 +583,9 @@ alloc_new:
                io->bio = __bio_alloc(sbi, fio->new_blkaddr, fio->io_wbc,
                                                BIO_MAX_PAGES, false,
                                                fio->type, fio->temp);
+               if (bio_encrypted)
+                       fscrypt_set_bio(inode, io->bio, dun);
+
                io->fio = *fio;
        }
 
@@ -551,7 +624,7 @@ 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, 0);
 
-       if (f2fs_encrypted_file(inode))
+       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);
@@ -562,6 +635,10 @@ static struct bio *f2fs_grab_read_bio(struct inode *inode, block_t blkaddr,
                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);
@@ -583,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;
 }
@@ -1438,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;
@@ -1515,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)
@@ -1592,6 +1685,9 @@ static int encrypt_one_page(struct f2fs_io_info *fio)
        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))
@@ -1907,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;
@@ -2516,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;
@@ -2568,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;
        }