From 171f71f40253a34ed32483a271e9355ce36f5c7b Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Thu, 14 May 2015 17:22:04 -0400 Subject: [PATCH] Update crypto changes --- clean-up-superblock-encryption-mode-fields | 110 ++++++++++++++++ crypto-get-rid-of-ci_mode | 107 ++++++++++++++++ crypto-shrink-ext4_crypto_ctx | 171 +++++++++++++++++++++++++ crypto-use-slab-caches | 198 +++++++++++++++++++++++++++++ reorganize-fname-crypto | 37 ++++-- require-ctr-mode | 23 ++++ series | 5 + 7 files changed, 638 insertions(+), 13 deletions(-) create mode 100644 clean-up-superblock-encryption-mode-fields create mode 100644 crypto-get-rid-of-ci_mode create mode 100644 crypto-shrink-ext4_crypto_ctx create mode 100644 crypto-use-slab-caches create mode 100644 require-ctr-mode diff --git a/clean-up-superblock-encryption-mode-fields b/clean-up-superblock-encryption-mode-fields new file mode 100644 index 00000000..2071b44b --- /dev/null +++ b/clean-up-superblock-encryption-mode-fields @@ -0,0 +1,110 @@ +ext4: clean up superblock encryption mode fields + +The superblock fields s_file_encryption_mode and s_dir_encryption_mode +are vestigal, so remove them as a cleanup. While we're at it, allow +file systems with both encryption and inline_data enabled at the same +time to work correctly. We can't have encrypted inodes with inline +data, but there's no reason to prohibit unencrypted inodes from using +the inline data feature. + +Signed-off-by: Theodore Ts'o +--- + fs/ext4/crypto_policy.c | 9 +++++++-- + fs/ext4/ext4.h | 6 ------ + fs/ext4/ialloc.c | 19 ------------------- + fs/ext4/super.c | 5 ----- + 4 files changed, 7 insertions(+), 32 deletions(-) + +diff --git a/fs/ext4/crypto_policy.c b/fs/ext4/crypto_policy.c +index 370d3aa..683391f 100644 +--- a/fs/ext4/crypto_policy.c ++++ b/fs/ext4/crypto_policy.c +@@ -51,6 +51,10 @@ static int ext4_create_encryption_context_from_policy( + struct ext4_encryption_context ctx; + int res = 0; + ++ res = ext4_convert_inline_data(inode); ++ if (res) ++ return res; ++ + ctx.format = EXT4_ENCRYPTION_CONTEXT_FORMAT_V1; + memcpy(ctx.master_key_descriptor, policy->master_key_descriptor, + EXT4_KEY_DESCRIPTOR_SIZE); +@@ -199,8 +203,9 @@ int ext4_inherit_context(struct inode *parent, struct inode *child) + res = ext4_xattr_set(child, EXT4_XATTR_INDEX_ENCRYPTION, + EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, &ctx, + sizeof(ctx), 0); +- if (!res) ++ if (!res) { + ext4_set_inode_flag(child, EXT4_INODE_ENCRYPT); ++ ext4_clear_inode_state(child, EXT4_STATE_MAY_INLINE_DATA); ++ } + return res; +- + } +diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h +index 6dd3f51..4b589fe 100644 +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -1374,12 +1374,6 @@ struct ext4_sb_info { + struct ratelimit_state s_err_ratelimit_state; + struct ratelimit_state s_warning_ratelimit_state; + struct ratelimit_state s_msg_ratelimit_state; +- +-#ifdef CONFIG_EXT4_FS_ENCRYPTION +- /* Encryption */ +- uint32_t s_file_encryption_mode; +- uint32_t s_dir_encryption_mode; +-#endif + }; + + static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb) +diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c +index 2cf18a2..8fa00d3 100644 +--- a/fs/ext4/ialloc.c ++++ b/fs/ext4/ialloc.c +@@ -1034,28 +1034,9 @@ got: + ext4_set_inode_state(inode, EXT4_STATE_NEW); + + ei->i_extra_isize = EXT4_SB(sb)->s_want_extra_isize; +-#ifdef CONFIG_EXT4_FS_ENCRYPTION +- if ((sbi->s_file_encryption_mode == EXT4_ENCRYPTION_MODE_INVALID) && +- (sbi->s_dir_encryption_mode == EXT4_ENCRYPTION_MODE_INVALID)) { +- ei->i_inline_off = 0; +- if (EXT4_HAS_INCOMPAT_FEATURE(sb, +- EXT4_FEATURE_INCOMPAT_INLINE_DATA)) +- ext4_set_inode_state(inode, +- EXT4_STATE_MAY_INLINE_DATA); +- } else { +- /* Inline data and encryption are incompatible +- * We turn off inline data since encryption is enabled */ +- ei->i_inline_off = 1; +- if (EXT4_HAS_INCOMPAT_FEATURE(sb, +- EXT4_FEATURE_INCOMPAT_INLINE_DATA)) +- ext4_clear_inode_state(inode, +- EXT4_STATE_MAY_INLINE_DATA); +- } +-#else + ei->i_inline_off = 0; + if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_INLINE_DATA)) + ext4_set_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); +-#endif + ret = inode; + err = dquot_alloc_inode(inode); + if (err) +diff --git a/fs/ext4/super.c b/fs/ext4/super.c +index c0df4f7..4ac5df5 100644 +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -3450,11 +3450,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) + if (sb->s_bdev->bd_part) + sbi->s_sectors_written_start = + part_stat_read(sb->s_bdev->bd_part, sectors[1]); +-#ifdef CONFIG_EXT4_FS_ENCRYPTION +- /* Modes of operations for file and directory encryption. */ +- sbi->s_file_encryption_mode = EXT4_ENCRYPTION_MODE_AES_256_XTS; +- sbi->s_dir_encryption_mode = EXT4_ENCRYPTION_MODE_INVALID; +-#endif + + /* Cleanup superblock name */ + for (cp = sb->s_id; (cp = strchr(cp, '/'));) diff --git a/crypto-get-rid-of-ci_mode b/crypto-get-rid-of-ci_mode new file mode 100644 index 00000000..d744898d --- /dev/null +++ b/crypto-get-rid-of-ci_mode @@ -0,0 +1,107 @@ +ext4 crypto: get rid of ci_mode from struct ext4_crypt_info + +The ci_mode field was superfluous, and getting rid of it gets rid of +an unused hole in the structure. + +Signed-off-by: Theodore Ts'o +--- + fs/ext4/crypto.c | 11 +++++------ + fs/ext4/crypto_fname.c | 4 ++-- + fs/ext4/crypto_key.c | 11 +++++------ + fs/ext4/ext4_crypto.h | 1 - + 4 files changed, 12 insertions(+), 15 deletions(-) + +diff --git a/fs/ext4/crypto.c b/fs/ext4/crypto.c +index 1c34f0e..9969d05 100644 +--- a/fs/ext4/crypto.c ++++ b/fs/ext4/crypto.c +@@ -137,14 +137,13 @@ struct ext4_crypto_ctx *ext4_get_crypto_ctx(struct inode *inode) + + /* Allocate a new Crypto API context if we don't already have + * one or if it isn't the right mode. */ +- BUG_ON(ci->ci_mode == EXT4_ENCRYPTION_MODE_INVALID); +- if (ctx->tfm && (ctx->mode != ci->ci_mode)) { ++ if (ctx->tfm && (ctx->mode != ci->ci_data_mode)) { + crypto_free_tfm(ctx->tfm); + ctx->tfm = NULL; + ctx->mode = EXT4_ENCRYPTION_MODE_INVALID; + } + if (!ctx->tfm) { +- switch (ci->ci_mode) { ++ switch (ci->ci_data_mode) { + case EXT4_ENCRYPTION_MODE_AES_256_XTS: + ctx->tfm = crypto_ablkcipher_tfm( + crypto_alloc_ablkcipher("xts(aes)", 0, 0)); +@@ -162,9 +161,9 @@ struct ext4_crypto_ctx *ext4_get_crypto_ctx(struct inode *inode) + ctx->tfm = NULL; + goto out; + } +- ctx->mode = ci->ci_mode; ++ ctx->mode = ci->ci_data_mode; + } +- BUG_ON(ci->ci_size != ext4_encryption_key_size(ci->ci_mode)); ++ BUG_ON(ci->ci_size != ext4_encryption_key_size(ci->ci_data_mode)); + + /* There shouldn't be a bounce page attached to the crypto + * context at this point. */ +@@ -321,7 +320,7 @@ static int ext4_page_crypto(struct ext4_crypto_ctx *ctx, + int res = 0; + + BUG_ON(!ctx->tfm); +- BUG_ON(ctx->mode != ei->i_crypt_info->ci_mode); ++ BUG_ON(ctx->mode != ei->i_crypt_info->ci_data_mode); + + if (ctx->mode != EXT4_ENCRYPTION_MODE_AES_256_XTS) { + printk_ratelimited(KERN_ERR +diff --git a/fs/ext4/crypto_fname.c b/fs/ext4/crypto_fname.c +index 374d0e7..e63dd29 100644 +--- a/fs/ext4/crypto_fname.c ++++ b/fs/ext4/crypto_fname.c +@@ -272,9 +272,9 @@ int ext4_setup_fname_crypto(struct inode *inode) + if (!ci || ci->ci_ctfm) + return 0; + +- if (ci->ci_mode != EXT4_ENCRYPTION_MODE_AES_256_CTS) { ++ if (ci->ci_filename_mode != EXT4_ENCRYPTION_MODE_AES_256_CTS) { + printk_once(KERN_WARNING "ext4: unsupported key mode %d\n", +- ci->ci_mode); ++ ci->ci_filename_mode); + return -ENOKEY; + } + +diff --git a/fs/ext4/crypto_key.c b/fs/ext4/crypto_key.c +index d6abe46..858d7d6 100644 +--- a/fs/ext4/crypto_key.c ++++ b/fs/ext4/crypto_key.c +@@ -152,14 +152,13 @@ int _ext4_get_encryption_info(struct inode *inode) + memcpy(crypt_info->ci_master_key, ctx.master_key_descriptor, + sizeof(crypt_info->ci_master_key)); + if (S_ISREG(inode->i_mode)) +- crypt_info->ci_mode = ctx.contents_encryption_mode; ++ crypt_info->ci_size = ++ ext4_encryption_key_size(crypt_info->ci_data_mode); + else if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) +- crypt_info->ci_mode = ctx.filenames_encryption_mode; +- else { +- printk(KERN_ERR "ext4 crypto: Unsupported inode type.\n"); ++ crypt_info->ci_size = ++ ext4_encryption_key_size(crypt_info->ci_filename_mode); ++ else + BUG(); +- } +- crypt_info->ci_size = ext4_encryption_key_size(crypt_info->ci_mode); + BUG_ON(!crypt_info->ci_size); + if (DUMMY_ENCRYPTION_ENABLED(sbi)) { + memset(crypt_info->ci_raw, 0x42, EXT4_AES_256_XTS_KEY_SIZE); +diff --git a/fs/ext4/ext4_crypto.h b/fs/ext4/ext4_crypto.h +index d29687c..69faf0e 100644 +--- a/fs/ext4/ext4_crypto.h ++++ b/fs/ext4/ext4_crypto.h +@@ -74,7 +74,6 @@ struct ext4_encryption_key { + } __attribute__((__packed__)); + + struct ext4_crypt_info { +- unsigned char ci_mode; + unsigned char ci_size; + char ci_data_mode; + char ci_filename_mode; diff --git a/crypto-shrink-ext4_crypto_ctx b/crypto-shrink-ext4_crypto_ctx new file mode 100644 index 00000000..2fcb8514 --- /dev/null +++ b/crypto-shrink-ext4_crypto_ctx @@ -0,0 +1,171 @@ +ext4 crypto: shrink size of the ext4_crypto_ctx structure + +Some fields are only used when the crypto_ctx is being used on the +read path, some are only used on the write path, and some are only +used when the structure is on free list. Optimize memory use by using +a union. + +Signed-off-by: Theodore Ts'o +--- + fs/ext4/crypto.c | 28 +++++++++++++--------------- + fs/ext4/ext4_crypto.h | 21 ++++++++++++++------- + fs/ext4/page-io.c | 2 +- + fs/ext4/readpage.c | 10 +++++----- + 4 files changed, 33 insertions(+), 28 deletions(-) + +diff --git a/fs/ext4/crypto.c b/fs/ext4/crypto.c +index 9969d05..1484b58 100644 +--- a/fs/ext4/crypto.c ++++ b/fs/ext4/crypto.c +@@ -71,14 +71,14 @@ void ext4_release_crypto_ctx(struct ext4_crypto_ctx *ctx) + { + unsigned long flags; + +- if (ctx->bounce_page) { ++ if (ctx->flags & EXT4_WRITE_PATH_FL && ctx->w.bounce_page) { + if (ctx->flags & EXT4_BOUNCE_PAGE_REQUIRES_FREE_ENCRYPT_FL) +- __free_page(ctx->bounce_page); ++ __free_page(ctx->w.bounce_page); + else +- mempool_free(ctx->bounce_page, ext4_bounce_page_pool); +- ctx->bounce_page = NULL; ++ mempool_free(ctx->w.bounce_page, ext4_bounce_page_pool); ++ ctx->w.bounce_page = NULL; + } +- ctx->control_page = NULL; ++ ctx->w.control_page = NULL; + if (ctx->flags & EXT4_CTX_REQUIRES_FREE_ENCRYPT_FL) { + if (ctx->tfm) + crypto_free_tfm(ctx->tfm); +@@ -134,6 +134,7 @@ struct ext4_crypto_ctx *ext4_get_crypto_ctx(struct inode *inode) + } else { + ctx->flags &= ~EXT4_CTX_REQUIRES_FREE_ENCRYPT_FL; + } ++ ctx->flags &= ~EXT4_WRITE_PATH_FL; + + /* Allocate a new Crypto API context if we don't already have + * one or if it isn't the right mode. */ +@@ -165,10 +166,6 @@ struct ext4_crypto_ctx *ext4_get_crypto_ctx(struct inode *inode) + } + BUG_ON(ci->ci_size != ext4_encryption_key_size(ci->ci_data_mode)); + +- /* There shouldn't be a bounce page attached to the crypto +- * context at this point. */ +- BUG_ON(ctx->bounce_page); +- + out: + if (res) { + if (!IS_ERR_OR_NULL(ctx)) +@@ -189,12 +186,12 @@ void ext4_exit_crypto(void) + struct ext4_crypto_ctx *pos, *n; + + list_for_each_entry_safe(pos, n, &ext4_free_crypto_ctxs, free_list) { +- if (pos->bounce_page) { ++ if (pos->w.bounce_page) { + if (pos->flags & + EXT4_BOUNCE_PAGE_REQUIRES_FREE_ENCRYPT_FL) { +- __free_page(pos->bounce_page); ++ __free_page(pos->w.bounce_page); + } else { +- mempool_free(pos->bounce_page, ++ mempool_free(pos->w.bounce_page, + ext4_bounce_page_pool); + } + } +@@ -425,8 +422,9 @@ struct page *ext4_encrypt(struct inode *inode, + } else { + ctx->flags |= EXT4_BOUNCE_PAGE_REQUIRES_FREE_ENCRYPT_FL; + } +- ctx->bounce_page = ciphertext_page; +- ctx->control_page = plaintext_page; ++ ctx->flags |= EXT4_WRITE_PATH_FL; ++ ctx->w.bounce_page = ciphertext_page; ++ ctx->w.control_page = plaintext_page; + err = ext4_page_crypto(ctx, inode, EXT4_ENCRYPT, plaintext_page->index, + plaintext_page, ciphertext_page); + if (err) { +@@ -505,7 +503,7 @@ int ext4_encrypted_zeroout(struct inode *inode, struct ext4_extent *ex) + } else { + ctx->flags |= EXT4_BOUNCE_PAGE_REQUIRES_FREE_ENCRYPT_FL; + } +- ctx->bounce_page = ciphertext_page; ++ ctx->w.bounce_page = ciphertext_page; + + while (len--) { + err = ext4_page_crypto(ctx, inode, EXT4_ENCRYPT, lblk, +diff --git a/fs/ext4/ext4_crypto.h b/fs/ext4/ext4_crypto.h +index 69faf0e..c5258f2 100644 +--- a/fs/ext4/ext4_crypto.h ++++ b/fs/ext4/ext4_crypto.h +@@ -86,16 +86,23 @@ struct ext4_crypt_info { + + #define EXT4_CTX_REQUIRES_FREE_ENCRYPT_FL 0x00000001 + #define EXT4_BOUNCE_PAGE_REQUIRES_FREE_ENCRYPT_FL 0x00000002 ++#define EXT4_WRITE_PATH_FL 0x00000004 + + struct ext4_crypto_ctx { + struct crypto_tfm *tfm; /* Crypto API context */ +- struct page *bounce_page; /* Ciphertext page on write path */ +- struct page *control_page; /* Original page on write path */ +- struct bio *bio; /* The bio for this context */ +- struct work_struct work; /* Work queue for read complete path */ +- struct list_head free_list; /* Free list */ +- int flags; /* Flags */ +- int mode; /* Encryption mode for tfm */ ++ union { ++ struct { ++ struct page *bounce_page; /* Ciphertext page */ ++ struct page *control_page; /* Original page */ ++ } w; ++ struct { ++ struct bio *bio; ++ struct work_struct work; ++ } r; ++ struct list_head free_list; /* Free list */ ++ }; ++ char flags; /* Flags */ ++ char mode; /* Encryption mode for tfm */ + }; + + struct ext4_completion_result { +diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c +index 51a5f12..4457a3c 100644 +--- a/fs/ext4/page-io.c ++++ b/fs/ext4/page-io.c +@@ -85,7 +85,7 @@ static void ext4_finish_bio(struct bio *bio) + /* The bounce data pages are unmapped. */ + data_page = page; + ctx = (struct ext4_crypto_ctx *)page_private(data_page); +- page = ctx->control_page; ++ page = ctx->w.control_page; + } + #endif + +diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c +index 171b9ac..ec3ef93 100644 +--- a/fs/ext4/readpage.c ++++ b/fs/ext4/readpage.c +@@ -54,8 +54,8 @@ static void completion_pages(struct work_struct *work) + { + #ifdef CONFIG_EXT4_FS_ENCRYPTION + struct ext4_crypto_ctx *ctx = +- container_of(work, struct ext4_crypto_ctx, work); +- struct bio *bio = ctx->bio; ++ container_of(work, struct ext4_crypto_ctx, r.work); ++ struct bio *bio = ctx->r.bio; + struct bio_vec *bv; + int i; + +@@ -109,9 +109,9 @@ static void mpage_end_io(struct bio *bio, int err) + if (err) { + ext4_release_crypto_ctx(ctx); + } else { +- INIT_WORK(&ctx->work, completion_pages); +- ctx->bio = bio; +- queue_work(ext4_read_workqueue, &ctx->work); ++ INIT_WORK(&ctx->r.work, completion_pages); ++ ctx->r.bio = bio; ++ queue_work(ext4_read_workqueue, &ctx->r.work); + return; + } + } diff --git a/crypto-use-slab-caches b/crypto-use-slab-caches new file mode 100644 index 00000000..75f354f0 --- /dev/null +++ b/crypto-use-slab-caches @@ -0,0 +1,198 @@ +ext4 crypto: use slab caches + +Use slab caches the ext4_crypto_ctx and ext4_crypt_info structures for +slighly better memory efficiency and debuggability. + +Signed-off-by: Theodore Ts'o +--- + fs/ext4/crypto.c | 60 +++++++++++++++++++++++++++++------------------------------- + fs/ext4/crypto_key.c | 12 +++++++++--- + fs/ext4/ext4.h | 1 + + 3 files changed, 39 insertions(+), 34 deletions(-) + +diff --git a/fs/ext4/crypto.c b/fs/ext4/crypto.c +index 3a25aa4..1c34f0e 100644 +--- a/fs/ext4/crypto.c ++++ b/fs/ext4/crypto.c +@@ -55,6 +55,9 @@ static mempool_t *ext4_bounce_page_pool; + static LIST_HEAD(ext4_free_crypto_ctxs); + static DEFINE_SPINLOCK(ext4_crypto_ctx_lock); + ++static struct kmem_cache *ext4_crypto_ctx_cachep; ++struct kmem_cache *ext4_crypt_info_cachep; ++ + /** + * ext4_release_crypto_ctx() - Releases an encryption context + * @ctx: The encryption context to release. +@@ -79,7 +82,7 @@ void ext4_release_crypto_ctx(struct ext4_crypto_ctx *ctx) + if (ctx->flags & EXT4_CTX_REQUIRES_FREE_ENCRYPT_FL) { + if (ctx->tfm) + crypto_free_tfm(ctx->tfm); +- kfree(ctx); ++ kmem_cache_free(ext4_crypto_ctx_cachep, ctx); + } else { + spin_lock_irqsave(&ext4_crypto_ctx_lock, flags); + list_add(&ctx->free_list, &ext4_free_crypto_ctxs); +@@ -88,23 +91,6 @@ void ext4_release_crypto_ctx(struct ext4_crypto_ctx *ctx) + } + + /** +- * ext4_alloc_and_init_crypto_ctx() - Allocates and inits an encryption context +- * @mask: The allocation mask. +- * +- * Return: An allocated and initialized encryption context on success. An error +- * value or NULL otherwise. +- */ +-static struct ext4_crypto_ctx *ext4_alloc_and_init_crypto_ctx(gfp_t mask) +-{ +- struct ext4_crypto_ctx *ctx = kzalloc(sizeof(struct ext4_crypto_ctx), +- mask); +- +- if (!ctx) +- return ERR_PTR(-ENOMEM); +- return ctx; +-} +- +-/** + * ext4_get_crypto_ctx() - Gets an encryption context + * @inode: The inode for which we are doing the crypto + * +@@ -121,8 +107,6 @@ struct ext4_crypto_ctx *ext4_get_crypto_ctx(struct inode *inode) + struct ext4_crypt_info *ci = EXT4_I(inode)->i_crypt_info; + + BUG_ON(ci == NULL); +- if (!ext4_read_workqueue) +- ext4_init_crypto(); + + /* + * We first try getting the ctx from a free list because in +@@ -141,9 +125,9 @@ struct ext4_crypto_ctx *ext4_get_crypto_ctx(struct inode *inode) + list_del(&ctx->free_list); + spin_unlock_irqrestore(&ext4_crypto_ctx_lock, flags); + if (!ctx) { +- ctx = ext4_alloc_and_init_crypto_ctx(GFP_NOFS); +- if (IS_ERR(ctx)) { +- res = PTR_ERR(ctx); ++ ctx = kmem_cache_zalloc(ext4_crypto_ctx_cachep, GFP_NOFS); ++ if (!ctx) { ++ res = -ENOMEM; + goto out; + } + ctx->flags |= EXT4_CTX_REQUIRES_FREE_ENCRYPT_FL; +@@ -217,7 +201,7 @@ void ext4_exit_crypto(void) + } + if (pos->tfm) + crypto_free_tfm(pos->tfm); +- kfree(pos); ++ kmem_cache_free(ext4_crypto_ctx_cachep, pos); + } + INIT_LIST_HEAD(&ext4_free_crypto_ctxs); + if (ext4_bounce_page_pool) +@@ -226,6 +210,12 @@ void ext4_exit_crypto(void) + if (ext4_read_workqueue) + destroy_workqueue(ext4_read_workqueue); + ext4_read_workqueue = NULL; ++ if (ext4_crypto_ctx_cachep) ++ kmem_cache_destroy(ext4_crypto_ctx_cachep); ++ ext4_crypto_ctx_cachep = NULL; ++ if (ext4_crypt_info_cachep) ++ kmem_cache_destroy(ext4_crypt_info_cachep); ++ ext4_crypt_info_cachep = NULL; + } + + /** +@@ -238,23 +228,31 @@ void ext4_exit_crypto(void) + */ + int ext4_init_crypto(void) + { +- int i, res; ++ int i, res = -ENOMEM; + + mutex_lock(&crypto_init); + if (ext4_read_workqueue) + goto already_initialized; + ext4_read_workqueue = alloc_workqueue("ext4_crypto", WQ_HIGHPRI, 0); +- if (!ext4_read_workqueue) { +- res = -ENOMEM; ++ if (!ext4_read_workqueue) ++ goto fail; ++ ++ ext4_crypto_ctx_cachep = KMEM_CACHE(ext4_crypto_ctx, ++ SLAB_RECLAIM_ACCOUNT); ++ if (!ext4_crypto_ctx_cachep) ++ goto fail; ++ ++ ext4_crypt_info_cachep = KMEM_CACHE(ext4_crypt_info, ++ SLAB_RECLAIM_ACCOUNT); ++ if (!ext4_crypt_info_cachep) + goto fail; +- } + + for (i = 0; i < num_prealloc_crypto_ctxs; i++) { + struct ext4_crypto_ctx *ctx; + +- ctx = ext4_alloc_and_init_crypto_ctx(GFP_KERNEL); +- if (IS_ERR(ctx)) { +- res = PTR_ERR(ctx); ++ ctx = kmem_cache_zalloc(ext4_crypto_ctx_cachep, GFP_NOFS); ++ if (!ctx) { ++ res = -ENOMEM; + goto fail; + } + list_add(&ctx->free_list, &ext4_free_crypto_ctxs); +diff --git a/fs/ext4/crypto_key.c b/fs/ext4/crypto_key.c +index 0075e43..d6abe46 100644 +--- a/fs/ext4/crypto_key.c ++++ b/fs/ext4/crypto_key.c +@@ -96,7 +96,7 @@ void ext4_free_encryption_info(struct inode *inode) + key_put(ci->ci_keyring_key); + crypto_free_ablkcipher(ci->ci_ctfm); + memzero_explicit(&ci->ci_raw, sizeof(ci->ci_raw)); +- kfree(ci); ++ kmem_cache_free(ext4_crypt_info_cachep, ci); + ei->i_crypt_info = NULL; + } + +@@ -113,6 +113,12 @@ int _ext4_get_encryption_info(struct inode *inode) + struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); + int res; + ++ if (!ext4_read_workqueue) { ++ res = ext4_init_crypto(); ++ if (res) ++ return res; ++ } ++ + if (ei->i_crypt_info) { + if (!ei->i_crypt_info->ci_keyring_key || + key_validate(ei->i_crypt_info->ci_keyring_key) == 0) +@@ -134,7 +140,7 @@ int _ext4_get_encryption_info(struct inode *inode) + return -EINVAL; + res = 0; + +- crypt_info = kmalloc(sizeof(struct ext4_crypt_info), GFP_KERNEL); ++ crypt_info = kmem_cache_alloc(ext4_crypt_info_cachep, GFP_KERNEL); + if (!crypt_info) + return -ENOMEM; + +@@ -188,7 +194,7 @@ out: + if (res < 0) { + if (res == -ENOKEY) + res = 0; +- kfree(crypt_info); ++ kmem_cache_free(ext4_crypt_info_cachep, crypt_info); + } else { + ei->i_crypt_info = crypt_info; + crypt_info->ci_keyring_key = keyring_key; +diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h +index 4b589fe..9c2b48cd 100644 +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -2059,6 +2059,7 @@ int ext4_get_policy(struct inode *inode, + struct ext4_encryption_policy *policy); + + /* crypto.c */ ++extern struct kmem_cache *ext4_crypt_info_cachep; + bool ext4_valid_contents_enc_mode(uint32_t mode); + uint32_t ext4_validate_encryption_key_size(uint32_t mode, uint32_t size); + extern struct workqueue_struct *ext4_read_workqueue; diff --git a/reorganize-fname-crypto b/reorganize-fname-crypto index 999e33df..f76e770f 100644 --- a/reorganize-fname-crypto +++ b/reorganize-fname-crypto @@ -36,18 +36,18 @@ This is a pretty massive patch which does a number of different things: Signed-off-by: Theodore Ts'o --- - fs/ext4/crypto.c | 9 ++- - fs/ext4/crypto_fname.c | 284 +++++++++++++++++++---------------------------------------------------- - fs/ext4/crypto_key.c | 74 ++++++++++++++----- - fs/ext4/crypto_policy.c | 76 ++++++++++--------- - fs/ext4/dir.c | 21 ++---- - fs/ext4/ext4.h | 40 ++++++---- - fs/ext4/ext4_crypto.h | 16 ++-- + fs/ext4/crypto.c | 9 +-- + fs/ext4/crypto_fname.c | 284 ++++++++++++++++++++------------------------------------------------------ + fs/ext4/crypto_key.c | 74 +++++++++++++++----- + fs/ext4/crypto_policy.c | 76 +++++++++++--------- + fs/ext4/dir.c | 21 +++--- + fs/ext4/ext4.h | 44 +++++++----- + fs/ext4/ext4_crypto.h | 16 ++--- fs/ext4/file.c | 4 +- fs/ext4/namei.c | 42 ++++------- - fs/ext4/super.c | 5 +- + fs/ext4/super.c | 7 +- fs/ext4/symlink.c | 15 ++-- - 11 files changed, 240 insertions(+), 346 deletions(-) + 11 files changed, 246 insertions(+), 346 deletions(-) diff --git a/fs/ext4/crypto.c b/fs/ext4/crypto.c index 918200e..3a25aa4 100644 @@ -824,7 +824,7 @@ index d799d5d..28cb94f 100644 #endif brelse(bh); diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h -index e3671c2..4ffaa02 100644 +index e3671c2..1db3bfa 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -955,7 +955,7 @@ struct ext4_inode_info { @@ -881,7 +881,7 @@ index e3671c2..4ffaa02 100644 } static inline void ext4_fname_crypto_free_buffer(struct ext4_str *p) { } static inline int ext4_fname_setup_filename(struct inode *dir, -@@ -2143,10 +2136,25 @@ static inline void ext4_fname_free_filename(struct ext4_filename *fname) { } +@@ -2143,15 +2136,34 @@ static inline void ext4_fname_free_filename(struct ext4_filename *fname) { } /* crypto_key.c */ @@ -908,6 +908,15 @@ index e3671c2..4ffaa02 100644 #else static inline int ext4_has_encryption_key(struct inode *inode) { + return 0; + } ++static inline int ext4_get_encryption_info(struct inode *inode) ++{ ++ return 0; ++} + #endif + + diff --git a/fs/ext4/ext4_crypto.h b/fs/ext4/ext4_crypto.h index deecbe8..d29687c 100644 --- a/fs/ext4/ext4_crypto.h @@ -1096,7 +1105,7 @@ index b340643..9bed99f 100644 goto err_drop_inode; sd->len = cpu_to_le16(ostr.len); diff --git a/fs/ext4/super.c b/fs/ext4/super.c -index a9ebe3d..1850553 100644 +index a9ebe3d..ef19bda 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -877,9 +877,8 @@ static struct inode *ext4_alloc_inode(struct super_block *sb) @@ -1110,12 +1119,14 @@ index a9ebe3d..1850553 100644 return &ei->vfs_inode; } -@@ -956,6 +955,8 @@ void ext4_clear_inode(struct inode *inode) +@@ -956,6 +955,10 @@ void ext4_clear_inode(struct inode *inode) jbd2_free_inode(EXT4_I(inode)->jinode); EXT4_I(inode)->jinode = NULL; } ++#ifdef CONFIG_EXT4_FS_ENCRYPTION + if (EXT4_I(inode)->i_crypt_info) + ext4_free_encryption_info(inode); ++#endif } static struct inode *ext4_nfs_get_inode(struct super_block *sb, diff --git a/require-ctr-mode b/require-ctr-mode new file mode 100644 index 00000000..b9766d29 --- /dev/null +++ b/require-ctr-mode @@ -0,0 +1,23 @@ +ext4 crypto: require CONFIG_CRYPTO_CTR if ext4 encryption is enabled + +On arm64 this is apparently needed for CTS mode to function correctly. +Otherwise attempts to use CTS return ENOENT. + +Change-Id: I732ea9a5157acc76de5b89edec195d0365f4ca63 +Signed-off-by: Theodore Ts'o +--- + fs/ext4/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/ext4/Kconfig b/fs/ext4/Kconfig +index 024f228..bf8bc8a 100644 +--- a/fs/ext4/Kconfig ++++ b/fs/ext4/Kconfig +@@ -72,6 +72,7 @@ config EXT4_ENCRYPTION + select CRYPTO_ECB + select CRYPTO_XTS + select CRYPTO_CTS ++ select CRYPTO_CTR + select CRYPTO_SHA256 + select KEYS + select ENCRYPTED_KEYS diff --git a/series b/series index c7e950b3..742905a3 100644 --- a/series +++ b/series @@ -5,6 +5,11 @@ optimize-ext4-encryption stop-allocating-pages separate-kernel-and-user-structure-for-encryption-key reorganize-fname-crypto +clean-up-superblock-encryption-mode-fields +crypto-use-slab-caches +crypto-get-rid-of-ci_mode +crypto-shrink-ext4_crypto_ctx +require-ctr-mode ########################################## # unstable patches -- 2.11.4.GIT