From bb32a122d059150ec5b92f01d53fef6ff4e5f740 Mon Sep 17 00:00:00 2001 From: Boojin Kim Date: Wed, 16 May 2018 00:09:30 +0900 Subject: [PATCH] [COMMON] fs: add diskcipher free_req and debug Change-Id: Ib5cfb98ed1b0ac43eff6ec3d9cbe3507a191b7b5 Signed-off-by: Boojin Kim --- fs/buffer.c | 2 ++ fs/crypto/bio.c | 25 ++++++++++++++++------- fs/crypto/crypto.c | 16 +++++++++------ fs/crypto/fscrypt_private.h | 3 +-- fs/crypto/keyinfo.c | 6 +++--- fs/direct-io.c | 4 +++- fs/ext4/inode.c | 35 ++++++++++++++++++++++----------- fs/ext4/page-io.c | 14 ++++++------- fs/ext4/readpage.c | 7 +++---- include/linux/fscrypt.h | 1 + include/linux/fscrypt_notsupp.h | 10 ++++++++++ include/linux/fscrypt_supp.h | 3 +++ 12 files changed, 84 insertions(+), 42 deletions(-) diff --git a/fs/buffer.c b/fs/buffer.c index 81434292082e..fd41645f26eb 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -46,6 +46,7 @@ #include #include #include +#include /* for CONFIG_CRYPTO_DISKCIPHER_DEBUG */ static int fsync_buffers_list(spinlock_t *lock, struct list_head *list); static int submit_bh_wbc(int op, int op_flags, struct buffer_head *bh, @@ -3141,6 +3142,7 @@ static int submit_bh_wbc(int op, int op_flags, struct buffer_head *bh, op_flags |= REQ_PRIO; bio_set_op_attrs(bio, op, op_flags); + crypto_diskcipher_debug(BLK_BH, op_flags); if (bio->bi_opf & REQ_AUX_PRIV) bio->bi_aux_private = bh->b_private; submit_bio(bio); diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c index b182c1afd080..0968c4f1d20e 100644 --- a/fs/crypto/bio.c +++ b/fs/crypto/bio.c @@ -94,7 +94,7 @@ int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk, BUG_ON(inode->i_sb->s_blocksize != PAGE_SIZE); - if (fscrypt_disk_encrypted(inode)) { + 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); @@ -142,10 +142,8 @@ int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk, err = -EIO; goto errout; } -#ifdef CONFIG_CRYPTO_DISKCIPHER - if (fscrypt_has_encryption_key(inode)) - fscrypt_set_bio(inode, bio); -#endif + fscrypt_set_bio(inode, bio); + crypto_diskcipher_debug(FS_ZEROPAGE, bio->bi_opf); err = submit_bio_wait(bio); if (err == 0 && bio->bi_status) err = -EIO; @@ -165,12 +163,25 @@ errout: } 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) { #ifdef CONFIG_CRYPTO_DISKCIPHER - if (inode->i_crypt_info->ci_dtfm) + if (__fscrypt_disk_encrypted(inode)) crypto_diskcipher_set(bio, inode->i_crypt_info->ci_dtfm); -#else +#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; } diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index f65237d137f9..f5ee6141a028 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -97,7 +97,7 @@ struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *inode, gfp_t gfp_flags) if (ci == NULL) return ERR_PTR(-ENOKEY); - if (fscrypt_disk_encrypted(inode)) + if (__fscrypt_disk_encrypted(inode)) return NULL; /* @@ -251,10 +251,12 @@ struct page *fscrypt_encrypt_page(const struct inode *inode, struct page *ciphertext_page = page; int err; - BUG_ON(len % FS_CRYPTO_BLOCK_SIZE != 0); +#ifdef CONFIG_CRYPTO_DISKCIPHER_DEBUG + if (__fscrypt_disk_encrypted(inode)) + crypto_diskcipher_debug(FS_ENC_WARN, 0); +#endif - if (fscrypt_disk_encrypted(inode)) - return NULL; + BUG_ON(len % FS_CRYPTO_BLOCK_SIZE != 0); if (inode->i_sb->s_cop->flags & FS_CFLG_OWN_PAGES) { /* with inplace-encryption we just encrypt the page */ @@ -315,11 +317,13 @@ 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) { +#ifdef CONFIG_CRYPTO_DISKCIPHER_DEBUG + if (__fscrypt_disk_encrypted(inode)) + crypto_diskcipher_debug(FS_DEC_WARN, 0); +#endif if (!(inode->i_sb->s_cop->flags & FS_CFLG_OWN_PAGES)) BUG_ON(!PageLocked(page)); - if (fscrypt_disk_encrypted(page->mapping->host)) - return 0; return fscrypt_do_page_crypto(inode, FS_DECRYPT, lblk_num, page, page, len, offs, GFP_NOFS); } diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index 06e0f4766050..bd53a2a624b2 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -15,7 +15,6 @@ #define __FS_HAS_ENCRYPTION 1 #include #include -#include /* Encryption parameters */ #define FS_IV_SIZE 16 @@ -91,7 +90,7 @@ extern void fscrypt_free_bounce_page(void *pool); /* keyinfo.c */ extern void __exit fscrypt_essiv_cleanup(void); -static inline int fscrypt_disk_encrypted(const struct inode *inode) +static inline int __fscrypt_disk_encrypted(const struct inode *inode) { #if IS_ENABLED(CONFIG_FS_ENCRYPTION) #if IS_ENABLED(CONFIG_CRYPTO_DISKCIPHER) diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c index 628b22030503..08269e3c8d41 100644 --- a/fs/crypto/keyinfo.c +++ b/fs/crypto/keyinfo.c @@ -170,7 +170,7 @@ static void put_crypt_info(struct fscrypt_info *ci) #if defined(CONFIG_CRYPTO_DISKCIPHER) if (ci->ci_dtfm) - crypto_free_diskcipher(ci->ci_dtfm); + crypto_free_req_diskcipher(ci->ci_dtfm); #endif crypto_free_skcipher(ci->ci_ctfm); crypto_free_cipher(ci->ci_essiv_tfm); @@ -333,8 +333,8 @@ int fscrypt_get_encryption_info(struct inode *inode) if (!res) { if (cmpxchg(&inode->i_crypt_info, NULL, crypt_info) == NULL) crypt_info = NULL; - pr_debug("%s: (inode %lu) uses diskcipher tfm\n", - __func__, inode->i_ino); + pr_debug("%s: (inode %p:%lu, fscrypt:%p) uses diskcipher tfm\n", + __func__, inode, inode->i_ino, inode->i_crypt_info); goto out; } else { pr_warn("%s: error %d fails to set diskciher key\n", diff --git a/fs/direct-io.c b/fs/direct-io.c index 4aa11cdbfe2c..4b5610f88024 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -450,8 +450,10 @@ static inline void dio_bio_submit(struct dio *dio, struct dio_submit *sdio) spin_unlock_irqrestore(&dio->bio_lock, flags); #if defined(CONFIG_EXT4_FS_ENCRYPTION) && defined(CONFIG_CRYPTO_DISKCIPHER) - if (dio->inode && fscrypt_has_encryption_key(dio->inode)) + if (dio->inode && fscrypt_has_encryption_key(dio->inode)) { fscrypt_set_bio(dio->inode, bio); + crypto_diskcipher_debug(FS_DIO, bio->bi_opf); + } #endif if (dio->is_async && dio->op == REQ_OP_READ && dio->should_dirty) bio_set_pages_dirty(bio); diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 51b70932d045..e947526ac964 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -1215,10 +1215,19 @@ static int ext4_block_write_begin(struct page *page, loff_t pos, unsigned len, if (!buffer_uptodate(bh) && !buffer_delay(bh) && !buffer_unwritten(bh) && (block_start < from || block_end > to)) { - ll_rw_block(REQ_OP_READ, 0, 1, &bh); + int bi_opf = 0; + + if (S_ISREG(inode->i_mode) && ext4_encrypted_inode(inode) + && fscrypt_has_encryption_key(inode)) { + bh->b_private = fscrypt_get_diskcipher(inode); + if (bh->b_private) + bi_opf = REQ_CRYPT | REQ_AUX_PRIV; + } + ll_rw_block(REQ_OP_READ, bi_opf, 1, &bh); + crypto_diskcipher_debug(FS_BLOCK_WRITE, bi_opf); *wait_bh++ = bh; decrypt = ext4_encrypted_inode(inode) && - S_ISREG(inode->i_mode); + S_ISREG(inode->i_mode) && !bh->b_private; } } /* @@ -3823,14 +3832,9 @@ static ssize_t ext4_direct_IO(struct kiocb *iocb, struct iov_iter *iter) ssize_t ret; int rw = iov_iter_rw(iter); -#if defined(CONFIG_EXT4_FS_ENCRYPTION) && !defined(CONFIG_CRYPTO_DISKCIPHER) - if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode)) + if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode) + && !fscrypt_disk_encrypted(inode)) return 0; -#elif defined(CONFIG_CRYPTO_DISKCIPHER) - if (ext4_encrypted_inode(inode) && !fscrypt_has_encryption_key(inode)) - return 0; -#endif - /* * If we are doing data journalling we don't support O_DIRECT */ @@ -4030,7 +4034,14 @@ static int __ext4_block_zero_page_range(handle_t *handle, if (!buffer_uptodate(bh)) { err = -EIO; - ll_rw_block(REQ_OP_READ, 0, 1, &bh); + if (S_ISREG(inode->i_mode) && ext4_encrypted_inode(inode) + && fscrypt_has_encryption_key(inode)) + bh->b_private = fscrypt_get_diskcipher(inode); + if (bh->b_private) + ll_rw_block(REQ_OP_READ, REQ_CRYPT, 1, &bh); + else + ll_rw_block(REQ_OP_READ, 0, 1, &bh); + wait_on_buffer(bh); /* Uhhuh. Read error. Complain and punt. */ if (!buffer_uptodate(bh)) @@ -4040,7 +4051,9 @@ static int __ext4_block_zero_page_range(handle_t *handle, /* We expect the key to be set. */ BUG_ON(!fscrypt_has_encryption_key(inode)); BUG_ON(blocksize != PAGE_SIZE); - WARN_ON_ONCE(fscrypt_decrypt_page(page->mapping->host, + + if (!bh->b_private) + WARN_ON_ONCE(fscrypt_decrypt_page(page->mapping->host, page, PAGE_SIZE, 0, page->index)); } } diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index b769a6e8b80b..f3f96aacae0d 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c @@ -352,9 +352,12 @@ void ext4_io_submit(struct ext4_io_submit *io) int io_op_flags = io->io_wbc->sync_mode == WB_SYNC_ALL ? REQ_SYNC : 0; io->io_bio->bi_write_hint = io->io_end->inode->i_write_hint; - if (bio->bi_opf & REQ_CRYPT) - io_op_flags |= (REQ_CRYPT | REQ_AUX_PRIV); bio_set_op_attrs(io->io_bio, REQ_OP_WRITE, io_op_flags); + if (ext4_encrypted_inode(io->io_end->inode) && + S_ISREG(io->io_end->inode->i_mode)) { + fscrypt_set_bio(io->io_end->inode, io->io_bio); + crypto_diskcipher_debug(FS_PAGEIO, io->io_bio->bi_opf); + } submit_bio(io->io_bio); } io->io_bio = NULL; @@ -401,11 +404,6 @@ submit_and_retry: ret = io_submit_init_bio(io, bh); if (ret) return ret; -#if defined(CONFIG_EXT4_FS_ENCRYPTION) && defined(CONFIG_CRYPTO_DISKCIPHER) - if (ext4_encrypted_inode(inode) && - S_ISREG(inode->i_mode) && fscrypt_has_encryption_key(inode)) - fscrypt_set_bio(inode, io->io_bio); -#endif io->io_bio->bi_write_hint = inode->i_write_hint; } ret = bio_add_page(io->io_bio, page, bh->b_size, bh_offset(bh)); @@ -485,7 +483,7 @@ int ext4_bio_write_page(struct ext4_io_submit *io, bh = head = page_buffers(page); if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode) && - nr_to_submit) { + nr_to_submit && !fscrypt_disk_encrypted(inode)) { gfp_t gfp_flags = GFP_NOFS; retry_encrypt: diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c index 25797025c1b3..55ae5362880b 100644 --- a/fs/ext4/readpage.c +++ b/fs/ext4/readpage.c @@ -303,11 +303,10 @@ int ext4_mpage_readpages(struct address_space *mapping, bio->bi_end_io = mpage_end_io; bio->bi_private = ctx; bio_set_op_attrs(bio, REQ_OP_READ, 0); -#if defined(CONFIG_EXT4_FS_ENCRYPTION) && defined(CONFIG_CRYPTO_DISKCIPHER) - if (ext4_encrypted_inode(inode) && - S_ISREG(inode->i_mode) && fscrypt_has_encryption_key(inode)) + if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode)) { fscrypt_set_bio(inode, bio); -#endif + crypto_diskcipher_debug(FS_READP, bio->bi_opf); + } } length = first_hole << blkbits; diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h index 5257e495bf3b..6f6da7a28416 100644 --- a/include/linux/fscrypt.h +++ b/include/linux/fscrypt.h @@ -21,6 +21,7 @@ #include #include #include +#include #define FS_CRYPTO_BLOCK_SIZE 16 diff --git a/include/linux/fscrypt_notsupp.h b/include/linux/fscrypt_notsupp.h index 9ea9625f0f7b..47b03b3deaf3 100644 --- a/include/linux/fscrypt_notsupp.h +++ b/include/linux/fscrypt_notsupp.h @@ -208,8 +208,18 @@ static inline int __fscrypt_prepare_lookup(struct inode *dir, return -EOPNOTSUPP; } +static inline int fscrypt_disk_encrypted(const struct inode *inode) +{ + return; +} + static inline void fscrypt_set_bio(const struct inode *inode, struct bio *bio) { return; } + +static inline void *fscrypt_get_diskcipher(const struct inode *inode) +{ + return NULL; +} #endif /* _LINUX_FSCRYPT_NOTSUPP_H */ diff --git a/include/linux/fscrypt_supp.h b/include/linux/fscrypt_supp.h index 79c6a02a0558..5e004ff66e47 100644 --- a/include/linux/fscrypt_supp.h +++ b/include/linux/fscrypt_supp.h @@ -144,6 +144,9 @@ extern void fscrypt_pullback_bio_page(struct page **, bool); extern int fscrypt_zeroout_range(const struct inode *, pgoff_t, sector_t, unsigned int); void fscrypt_set_bio(const struct inode *inode, struct bio *bio); +void *fscrypt_get_diskcipher(const struct inode *inode); +int fscrypt_disk_encrypted(const struct inode *inode); + /* hooks.c */ extern int fscrypt_file_open(struct inode *inode, struct file *filp); extern int __fscrypt_prepare_link(struct inode *inode, struct inode *dir); -- 2.20.1