* [RFC 0/1] eCryptfs: Use the ablkcipher crypto API @ 2013-04-05 23:42 Tyler Hicks 2013-04-05 23:42 ` [RFC 1/1] " Tyler Hicks 0 siblings, 1 reply; 8+ messages in thread From: Tyler Hicks @ 2013-04-05 23:42 UTC (permalink / raw) To: ecryptfs Cc: Colin King, Dustin Kirkland, Tim Chen, Ying Huang, Thieu Le, Li Wang, Zeev Zilberman, Jarkko Sakkinen I've written an alternative patch to address the AES-NI performance issues discussed at various times on this list. I'll refer to this new patch as the "ablkcipher patch" because it is the most simple way that we could move to the ablkcipher interface. The older patches, written by Thieue (ecryptfs: Migrate to ablkcipher API) and Zeev (eCryptfs: ablkcipher support - add workqueue) are nicely designed but much more complex. I'll refer to those two patches as the "async patches". My intent was to come up with a patch that has the same performance benefits as those patches but with a more straightforward implementation. The async patches offload the write-to-lower-filesystem work to the crypto API callback function which then offloads it to a workqueue. The async patches also include multiple completion functions for page crypto operations and extent crypto operations. The async patches are well designed but, IMO, a bit more complex than what is needed. They end up modifying most of the eCryptfs I/O paths. I've never been comfortable merging them and feeling certain that all the bugs would be caught by the time the next kernel was released. So after looking at the performance results of the async patches, some analysis of the crypto API using the tcrypt module, and some numbers from Colin, it hit me that I could probably get similar numbers to the async patches by simply using the ablkcipher interface and then waiting for the results. All of those changes could be contained inside of crypto.c and the higher level page I/O functions don't even have to know about the changes to how we're using the crypto API. I've done some testing on my laptop and it looks like my hunch may be correct. If I had to give a quick summary of the ablkcipher patch vs the async patches, I'd say that the ablkcipher patch accentuates the performance changes found in the async patches. If the async patches improved throughput for a certain workload, the ablkcipher patch improves it a little more. If the async patches decrease performance in a certain case, the ablkcipher patch decrease performance a little more for that case. As far as the complexity of changes involved, the ablkcipher patch is much more simple. The ablkcipher patch diffstat: crypto.c | 141 ++++++++++++++++++++++++++++++++++++---------------- ecryptfs_kernel.h | 3 - 2 files changed, 102 insertions(+), 42 deletions(-) The async patches diffstat: crypto.c | 722 ++++++++++++++++++++++++++++++++++++++++------------ ecryptfs_kernel.h | 39 ++ main.c | 10 mmap.c | 88 +++++- 4 files changed, 683 insertions(+), 176 deletions(-) I also plan on collapsing the encrypt_scatterlist() and decrypt_scatterlist() functions into a single function since the only difference is whether crypto_ablkcipher_encrypt() or crypto_ablkcipher_decrypt() is called. Alright, enough about the async patches and ablkcipher patch comparisons. In comparison to the unpatched kernel, on AES-NI hardware, the ablkcipher patch shows considerable performance improvements, along with a some important performance decreases. I did the testing on my Thinkpad X220, with an i5-2520M, which has AES-NI support. I tested on the spinning disk (HITACHI HTS723232A7A364), a slow mSATA SSD (INTEL SSDMAEMC080G2), and eCryptfs mounted on top of tmpfs, using tiobench. The situations where performance drops are noticeable are while doing single and dual threaded sequential reads and writes on slower spinning media (laptop hard drive). I measure these decreases to be between 8% and 20%. Four and eight threaded tests start to see increases, especially eight thread sequential reads and writes (30% to 35%). When using a SSD, all tests show improvements in performance. The improvements are much more apparent in single and dual thread tests but not as apparent in four and eight thread tests. The biggest improvement, a 139% increase, happens in single-threaded random writes. In other single and dual thread SSD tests, 15% to 55% improvements can be seen, except for sequential reads which show minimal improvements. When mounting eCryptfs on top of tmpfs, improvements over 100% are seen across the board but tiobench prints ###### on some of the read tests when testing with this patch because the results are too large, I believe. So what's missing? I'd like to see some numbers on a faster SSD than what I have, numbers on non-AES-NI hardware, and maybe some numbers when using another cipher such as 3DES. I can do the 3DES testing, but I could use some help with the first two. Also, I'd appreciate opinions on the bad performance of single and dual threaded sequential reads and writes on an HDD (maybe other folks' testing will show better results?). I'd say that we're still potentially on track for the 3.10 merge window, but I don't expect anyone to have much time to devote to this between now and then so we'll have to see. Tyler ^ permalink raw reply [flat|nested] 8+ messages in thread
* [RFC 1/1] eCryptfs: Use the ablkcipher crypto API 2013-04-05 23:42 [RFC 0/1] eCryptfs: Use the ablkcipher crypto API Tyler Hicks @ 2013-04-05 23:42 ` Tyler Hicks 2013-04-09 4:30 ` Tyler Hicks 0 siblings, 1 reply; 8+ messages in thread From: Tyler Hicks @ 2013-04-05 23:42 UTC (permalink / raw) To: ecryptfs Cc: Colin King, Dustin Kirkland, Tim Chen, Ying Huang, Thieu Le, Li Wang, Zeev Zilberman, Jarkko Sakkinen Make the switch from the blkcipher kernel crypto interface to the ablkcipher interface. encrypt_scatterlist() and decrypt_scatterlist() now use the ablkcipher interface but, from the eCryptfs standpoint, still treat the crypto operation as a synchronous operation. They submit the async request and then wait until the operation is finished before they return. Most of the changes are contained inside those two functions. Despite waiting for the completion of the crypto operation, the ablkcipher interface provides performance increases in most cases when used on AES-NI capable hardware. However, sequential I/O with one or two threads on slow storage media does exhibit a sizeable decrease in performance. Signed-off-by: Tyler Hicks <tyhicks@canonical.com> Cc: Colin King <colin.king@canonical.com> Cc: Dustin Kirkland <dustin.kirkland@gazzang.com> Cc: Tim Chen <tim.c.chen@intel.com> Cc: Ying Huang <ying.huang@intel.com> Cc: Thieu Le <thieule@google.com> Cc: Li Wang <dragonylffly@163.com> Cc: Zeev Zilberman <zeev@annapurnaLabs.com> Cc: Jarkko Sakkinen <jarkko.sakkinen@iki.fi> --- fs/ecryptfs/crypto.c | 141 ++++++++++++++++++++++++++++++------------ fs/ecryptfs/ecryptfs_kernel.h | 3 +- 2 files changed, 102 insertions(+), 42 deletions(-) diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index d5c25db..1aa8a96 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -243,7 +243,7 @@ void ecryptfs_destroy_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat) struct ecryptfs_key_sig *key_sig, *key_sig_tmp; if (crypt_stat->tfm) - crypto_free_blkcipher(crypt_stat->tfm); + crypto_free_ablkcipher(crypt_stat->tfm); if (crypt_stat->hash_tfm) crypto_free_hash(crypt_stat->hash_tfm); list_for_each_entry_safe(key_sig, key_sig_tmp, @@ -319,6 +319,22 @@ int virt_to_scatterlist(const void *addr, int size, struct scatterlist *sg, return i; } +struct extent_crypt_result { + struct completion completion; + int rc; +}; + +static void extent_crypt_complete(struct crypto_async_request *req, int rc) +{ + struct extent_crypt_result *ecr = req->data; + + if (rc == -EINPROGRESS) + return; + + ecr->rc = rc; + complete(&ecr->completion); +} + /** * encrypt_scatterlist * @crypt_stat: Pointer to the crypt_stat struct to initialize. @@ -334,11 +350,8 @@ static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat, struct scatterlist *src_sg, int size, unsigned char *iv) { - struct blkcipher_desc desc = { - .tfm = crypt_stat->tfm, - .info = iv, - .flags = CRYPTO_TFM_REQ_MAY_SLEEP - }; + struct ablkcipher_request *req = NULL; + struct extent_crypt_result ecr; int rc = 0; BUG_ON(!crypt_stat || !crypt_stat->tfm @@ -349,24 +362,46 @@ static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat, ecryptfs_dump_hex(crypt_stat->key, crypt_stat->key_size); } - /* Consider doing this once, when the file is opened */ + + init_completion(&ecr.completion); + mutex_lock(&crypt_stat->cs_tfm_mutex); + req = ablkcipher_request_alloc(crypt_stat->tfm, GFP_NOFS); + if (!req) { + rc = -ENOMEM; + goto out; + } + + ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, + extent_crypt_complete, &ecr); + /* Consider doing this once, when the file is opened */ if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) { - rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key, - crypt_stat->key_size); + rc = crypto_ablkcipher_setkey(crypt_stat->tfm, crypt_stat->key, + crypt_stat->key_size); + if (rc) { + ecryptfs_printk(KERN_ERR, + "Error setting key; rc = [%d]\n", + rc); + mutex_unlock(&crypt_stat->cs_tfm_mutex); + rc = -EINVAL; + goto out; + } crypt_stat->flags |= ECRYPTFS_KEY_SET; } - if (rc) { - ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n", - rc); - mutex_unlock(&crypt_stat->cs_tfm_mutex); - rc = -EINVAL; - goto out; - } - ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes.\n", size); - crypto_blkcipher_encrypt_iv(&desc, dest_sg, src_sg, size); mutex_unlock(&crypt_stat->cs_tfm_mutex); + ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes.\n", size); + ablkcipher_request_set_crypt(req, src_sg, dest_sg, size, iv); + rc = crypto_ablkcipher_encrypt(req); + if (rc == -EINPROGRESS || rc == -EBUSY) { + struct extent_crypt_result *ecr = req->base.data; + + rc = wait_for_completion_interruptible(&ecr->completion); + if (!rc) + rc = ecr->rc; + INIT_COMPLETION(ecr->completion); + } out: + ablkcipher_request_free(req); return rc; } @@ -624,35 +659,60 @@ static int decrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat, struct scatterlist *src_sg, int size, unsigned char *iv) { - struct blkcipher_desc desc = { - .tfm = crypt_stat->tfm, - .info = iv, - .flags = CRYPTO_TFM_REQ_MAY_SLEEP - }; + struct ablkcipher_request *req = NULL; + struct extent_crypt_result ecr; int rc = 0; - /* Consider doing this once, when the file is opened */ + BUG_ON(!crypt_stat || !crypt_stat->tfm + || !(crypt_stat->flags & ECRYPTFS_STRUCT_INITIALIZED)); + if (unlikely(ecryptfs_verbosity > 0)) { + ecryptfs_printk(KERN_DEBUG, "Key size [%zd]; key:\n", + crypt_stat->key_size); + ecryptfs_dump_hex(crypt_stat->key, + crypt_stat->key_size); + } + + init_completion(&ecr.completion); + mutex_lock(&crypt_stat->cs_tfm_mutex); - rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key, - crypt_stat->key_size); - if (rc) { - ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n", - rc); - mutex_unlock(&crypt_stat->cs_tfm_mutex); - rc = -EINVAL; + req = ablkcipher_request_alloc(crypt_stat->tfm, GFP_NOFS); + if (!req) { + rc = -ENOMEM; goto out; } - ecryptfs_printk(KERN_DEBUG, "Decrypting [%d] bytes.\n", size); - rc = crypto_blkcipher_decrypt_iv(&desc, dest_sg, src_sg, size); + + ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, + extent_crypt_complete, &ecr); + /* Consider doing this once, when the file is opened */ + if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) { + rc = crypto_ablkcipher_setkey(crypt_stat->tfm, crypt_stat->key, + crypt_stat->key_size); + if (rc) { + ecryptfs_printk(KERN_ERR, + "Error setting key; rc = [%d]\n", + rc); + mutex_unlock(&crypt_stat->cs_tfm_mutex); + rc = -EINVAL; + goto out; + } + crypt_stat->flags |= ECRYPTFS_KEY_SET; + } mutex_unlock(&crypt_stat->cs_tfm_mutex); - if (rc) { - ecryptfs_printk(KERN_ERR, "Error decrypting; rc = [%d]\n", - rc); - goto out; + ecryptfs_printk(KERN_DEBUG, "Decrypting [%d] bytes.\n", size); + ablkcipher_request_set_crypt(req, src_sg, dest_sg, size, iv); + rc = crypto_ablkcipher_decrypt(req); + if (rc == -EINPROGRESS || rc == -EBUSY) { + struct extent_crypt_result *ecr = req->base.data; + + rc = wait_for_completion_interruptible(&ecr->completion); + if (!rc) + rc = ecr->rc; + INIT_COMPLETION(ecr->completion); } - rc = size; out: + ablkcipher_request_free(req); return rc; + } /** @@ -746,8 +806,7 @@ int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat) crypt_stat->cipher, "cbc"); if (rc) goto out_unlock; - crypt_stat->tfm = crypto_alloc_blkcipher(full_alg_name, 0, - CRYPTO_ALG_ASYNC); + crypt_stat->tfm = crypto_alloc_ablkcipher(full_alg_name, 0, 0); kfree(full_alg_name); if (IS_ERR(crypt_stat->tfm)) { rc = PTR_ERR(crypt_stat->tfm); @@ -757,7 +816,7 @@ int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat) crypt_stat->cipher); goto out_unlock; } - crypto_blkcipher_set_flags(crypt_stat->tfm, CRYPTO_TFM_REQ_WEAK_KEY); + crypto_ablkcipher_set_flags(crypt_stat->tfm, CRYPTO_TFM_REQ_WEAK_KEY); rc = 0; out_unlock: mutex_unlock(&crypt_stat->cs_tfm_mutex); diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h index dd299b3..f622a73 100644 --- a/fs/ecryptfs/ecryptfs_kernel.h +++ b/fs/ecryptfs/ecryptfs_kernel.h @@ -38,6 +38,7 @@ #include <linux/nsproxy.h> #include <linux/backing-dev.h> #include <linux/ecryptfs.h> +#include <linux/crypto.h> #define ECRYPTFS_DEFAULT_IV_BYTES 16 #define ECRYPTFS_DEFAULT_EXTENT_SIZE 4096 @@ -233,7 +234,7 @@ struct ecryptfs_crypt_stat { size_t extent_shift; unsigned int extent_mask; struct ecryptfs_mount_crypt_stat *mount_crypt_stat; - struct crypto_blkcipher *tfm; + struct crypto_ablkcipher *tfm; struct crypto_hash *hash_tfm; /* Crypto context for generating * the initialization vectors */ unsigned char cipher[ECRYPTFS_MAX_CIPHER_NAME_SIZE]; -- 1.8.1.2 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [RFC 1/1] eCryptfs: Use the ablkcipher crypto API 2013-04-05 23:42 ` [RFC 1/1] " Tyler Hicks @ 2013-04-09 4:30 ` Tyler Hicks 2013-04-09 4:39 ` [RFC v2 " Tyler Hicks 0 siblings, 1 reply; 8+ messages in thread From: Tyler Hicks @ 2013-04-09 4:30 UTC (permalink / raw) To: ecryptfs Cc: Colin King, Dustin Kirkland, Tim Chen, Ying Huang, Thieu Le, Li Wang, Zeev Zilberman, Jarkko Sakkinen [-- Attachment #1: Type: text/plain, Size: 9948 bytes --] On 2013-04-05 16:42:55, Tyler Hicks wrote: > Make the switch from the blkcipher kernel crypto interface to the > ablkcipher interface. > > encrypt_scatterlist() and decrypt_scatterlist() now use the ablkcipher > interface but, from the eCryptfs standpoint, still treat the crypto > operation as a synchronous operation. They submit the async request and > then wait until the operation is finished before they return. Most of > the changes are contained inside those two functions. > > Despite waiting for the completion of the crypto operation, the > ablkcipher interface provides performance increases in most cases when > used on AES-NI capable hardware. However, sequential I/O with one or two > threads on slow storage media does exhibit a sizeable decrease in > performance. > > Signed-off-by: Tyler Hicks <tyhicks@canonical.com> > Cc: Colin King <colin.king@canonical.com> > Cc: Dustin Kirkland <dustin.kirkland@gazzang.com> > Cc: Tim Chen <tim.c.chen@intel.com> > Cc: Ying Huang <ying.huang@intel.com> > Cc: Thieu Le <thieule@google.com> > Cc: Li Wang <dragonylffly@163.com> > Cc: Zeev Zilberman <zeev@annapurnaLabs.com> > Cc: Jarkko Sakkinen <jarkko.sakkinen@iki.fi> > --- I noticed two changes that need to be made to this patch. See the inline comments for details. I'll respond to this email with a v2 of the patch. I'll run tiobench overnight and share the new results in the morning. > fs/ecryptfs/crypto.c | 141 ++++++++++++++++++++++++++++++------------ > fs/ecryptfs/ecryptfs_kernel.h | 3 +- > 2 files changed, 102 insertions(+), 42 deletions(-) > > diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c > index d5c25db..1aa8a96 100644 > --- a/fs/ecryptfs/crypto.c > +++ b/fs/ecryptfs/crypto.c > @@ -243,7 +243,7 @@ void ecryptfs_destroy_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat) > struct ecryptfs_key_sig *key_sig, *key_sig_tmp; > > if (crypt_stat->tfm) > - crypto_free_blkcipher(crypt_stat->tfm); > + crypto_free_ablkcipher(crypt_stat->tfm); > if (crypt_stat->hash_tfm) > crypto_free_hash(crypt_stat->hash_tfm); > list_for_each_entry_safe(key_sig, key_sig_tmp, > @@ -319,6 +319,22 @@ int virt_to_scatterlist(const void *addr, int size, struct scatterlist *sg, > return i; > } > > +struct extent_crypt_result { > + struct completion completion; > + int rc; > +}; > + > +static void extent_crypt_complete(struct crypto_async_request *req, int rc) > +{ > + struct extent_crypt_result *ecr = req->data; > + > + if (rc == -EINPROGRESS) > + return; > + > + ecr->rc = rc; > + complete(&ecr->completion); > +} > + > /** > * encrypt_scatterlist > * @crypt_stat: Pointer to the crypt_stat struct to initialize. > @@ -334,11 +350,8 @@ static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat, > struct scatterlist *src_sg, int size, > unsigned char *iv) > { > - struct blkcipher_desc desc = { > - .tfm = crypt_stat->tfm, > - .info = iv, > - .flags = CRYPTO_TFM_REQ_MAY_SLEEP > - }; > + struct ablkcipher_request *req = NULL; > + struct extent_crypt_result ecr; > int rc = 0; > > BUG_ON(!crypt_stat || !crypt_stat->tfm > @@ -349,24 +362,46 @@ static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat, > ecryptfs_dump_hex(crypt_stat->key, > crypt_stat->key_size); > } > - /* Consider doing this once, when the file is opened */ > + > + init_completion(&ecr.completion); > + > mutex_lock(&crypt_stat->cs_tfm_mutex); > + req = ablkcipher_request_alloc(crypt_stat->tfm, GFP_NOFS); > + if (!req) { > + rc = -ENOMEM; > + goto out; cs_tfm_mutex needs to be unlocked in this error path. > + } > + > + ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, I think that we should set the CRYPTO_TFM_REQ_MAY_SLEEP flag here. Tyler > + extent_crypt_complete, &ecr); > + /* Consider doing this once, when the file is opened */ > if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) { > - rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key, > - crypt_stat->key_size); > + rc = crypto_ablkcipher_setkey(crypt_stat->tfm, crypt_stat->key, > + crypt_stat->key_size); > + if (rc) { > + ecryptfs_printk(KERN_ERR, > + "Error setting key; rc = [%d]\n", > + rc); > + mutex_unlock(&crypt_stat->cs_tfm_mutex); > + rc = -EINVAL; > + goto out; > + } > crypt_stat->flags |= ECRYPTFS_KEY_SET; > } > - if (rc) { > - ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n", > - rc); > - mutex_unlock(&crypt_stat->cs_tfm_mutex); > - rc = -EINVAL; > - goto out; > - } > - ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes.\n", size); > - crypto_blkcipher_encrypt_iv(&desc, dest_sg, src_sg, size); > mutex_unlock(&crypt_stat->cs_tfm_mutex); > + ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes.\n", size); > + ablkcipher_request_set_crypt(req, src_sg, dest_sg, size, iv); > + rc = crypto_ablkcipher_encrypt(req); > + if (rc == -EINPROGRESS || rc == -EBUSY) { > + struct extent_crypt_result *ecr = req->base.data; > + > + rc = wait_for_completion_interruptible(&ecr->completion); > + if (!rc) > + rc = ecr->rc; > + INIT_COMPLETION(ecr->completion); > + } > out: > + ablkcipher_request_free(req); > return rc; > } > > @@ -624,35 +659,60 @@ static int decrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat, > struct scatterlist *src_sg, int size, > unsigned char *iv) > { > - struct blkcipher_desc desc = { > - .tfm = crypt_stat->tfm, > - .info = iv, > - .flags = CRYPTO_TFM_REQ_MAY_SLEEP > - }; > + struct ablkcipher_request *req = NULL; > + struct extent_crypt_result ecr; > int rc = 0; > > - /* Consider doing this once, when the file is opened */ > + BUG_ON(!crypt_stat || !crypt_stat->tfm > + || !(crypt_stat->flags & ECRYPTFS_STRUCT_INITIALIZED)); > + if (unlikely(ecryptfs_verbosity > 0)) { > + ecryptfs_printk(KERN_DEBUG, "Key size [%zd]; key:\n", > + crypt_stat->key_size); > + ecryptfs_dump_hex(crypt_stat->key, > + crypt_stat->key_size); > + } > + > + init_completion(&ecr.completion); > + > mutex_lock(&crypt_stat->cs_tfm_mutex); > - rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key, > - crypt_stat->key_size); > - if (rc) { > - ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n", > - rc); > - mutex_unlock(&crypt_stat->cs_tfm_mutex); > - rc = -EINVAL; > + req = ablkcipher_request_alloc(crypt_stat->tfm, GFP_NOFS); > + if (!req) { > + rc = -ENOMEM; > goto out; > } > - ecryptfs_printk(KERN_DEBUG, "Decrypting [%d] bytes.\n", size); > - rc = crypto_blkcipher_decrypt_iv(&desc, dest_sg, src_sg, size); > + > + ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, > + extent_crypt_complete, &ecr); > + /* Consider doing this once, when the file is opened */ > + if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) { > + rc = crypto_ablkcipher_setkey(crypt_stat->tfm, crypt_stat->key, > + crypt_stat->key_size); > + if (rc) { > + ecryptfs_printk(KERN_ERR, > + "Error setting key; rc = [%d]\n", > + rc); > + mutex_unlock(&crypt_stat->cs_tfm_mutex); > + rc = -EINVAL; > + goto out; > + } > + crypt_stat->flags |= ECRYPTFS_KEY_SET; > + } > mutex_unlock(&crypt_stat->cs_tfm_mutex); > - if (rc) { > - ecryptfs_printk(KERN_ERR, "Error decrypting; rc = [%d]\n", > - rc); > - goto out; > + ecryptfs_printk(KERN_DEBUG, "Decrypting [%d] bytes.\n", size); > + ablkcipher_request_set_crypt(req, src_sg, dest_sg, size, iv); > + rc = crypto_ablkcipher_decrypt(req); > + if (rc == -EINPROGRESS || rc == -EBUSY) { > + struct extent_crypt_result *ecr = req->base.data; > + > + rc = wait_for_completion_interruptible(&ecr->completion); > + if (!rc) > + rc = ecr->rc; > + INIT_COMPLETION(ecr->completion); > } > - rc = size; > out: > + ablkcipher_request_free(req); > return rc; > + > } > > /** > @@ -746,8 +806,7 @@ int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat) > crypt_stat->cipher, "cbc"); > if (rc) > goto out_unlock; > - crypt_stat->tfm = crypto_alloc_blkcipher(full_alg_name, 0, > - CRYPTO_ALG_ASYNC); > + crypt_stat->tfm = crypto_alloc_ablkcipher(full_alg_name, 0, 0); > kfree(full_alg_name); > if (IS_ERR(crypt_stat->tfm)) { > rc = PTR_ERR(crypt_stat->tfm); > @@ -757,7 +816,7 @@ int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat) > crypt_stat->cipher); > goto out_unlock; > } > - crypto_blkcipher_set_flags(crypt_stat->tfm, CRYPTO_TFM_REQ_WEAK_KEY); > + crypto_ablkcipher_set_flags(crypt_stat->tfm, CRYPTO_TFM_REQ_WEAK_KEY); > rc = 0; > out_unlock: > mutex_unlock(&crypt_stat->cs_tfm_mutex); > diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h > index dd299b3..f622a73 100644 > --- a/fs/ecryptfs/ecryptfs_kernel.h > +++ b/fs/ecryptfs/ecryptfs_kernel.h > @@ -38,6 +38,7 @@ > #include <linux/nsproxy.h> > #include <linux/backing-dev.h> > #include <linux/ecryptfs.h> > +#include <linux/crypto.h> > > #define ECRYPTFS_DEFAULT_IV_BYTES 16 > #define ECRYPTFS_DEFAULT_EXTENT_SIZE 4096 > @@ -233,7 +234,7 @@ struct ecryptfs_crypt_stat { > size_t extent_shift; > unsigned int extent_mask; > struct ecryptfs_mount_crypt_stat *mount_crypt_stat; > - struct crypto_blkcipher *tfm; > + struct crypto_ablkcipher *tfm; > struct crypto_hash *hash_tfm; /* Crypto context for generating > * the initialization vectors */ > unsigned char cipher[ECRYPTFS_MAX_CIPHER_NAME_SIZE]; > -- > 1.8.1.2 > > -- > To unsubscribe from this list: send the line "unsubscribe ecryptfs" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html [-- Attachment #2: Digital signature --] [-- Type: application/pgp-signature, Size: 836 bytes --] ^ permalink raw reply [flat|nested] 8+ messages in thread
* [RFC v2 1/1] eCryptfs: Use the ablkcipher crypto API 2013-04-09 4:30 ` Tyler Hicks @ 2013-04-09 4:39 ` Tyler Hicks 2013-04-09 19:07 ` [RFC v3 " Tyler Hicks 0 siblings, 1 reply; 8+ messages in thread From: Tyler Hicks @ 2013-04-09 4:39 UTC (permalink / raw) To: ecryptfs Cc: Colin King, Dustin Kirkland, Tim Chen, Ying Huang, Thieu Le, Li Wang, Zeev Zilberman, Jarkko Sakkinen Make the switch from the blkcipher kernel crypto interface to the ablkcipher interface. encrypt_scatterlist() and decrypt_scatterlist() now use the ablkcipher interface but, from the eCryptfs standpoint, still treat the crypto operation as a synchronous operation. They submit the async request and then wait until the operation is finished before they return. Most of the changes are contained inside those two functions. Despite waiting for the completion of the crypto operation, the ablkcipher interface provides performance increases in most cases when used on AES-NI capable hardware. However, sequential I/O with one or two threads on slow storage media does exhibit a sizeable decrease in performance. Signed-off-by: Tyler Hicks <tyhicks@canonical.com> Cc: Colin King <colin.king@canonical.com> Cc: Dustin Kirkland <dustin.kirkland@gazzang.com> Cc: Tim Chen <tim.c.chen@intel.com> Cc: Ying Huang <ying.huang@intel.com> Cc: Thieu Le <thieule@google.com> Cc: Li Wang <dragonylffly@163.com> Cc: Zeev Zilberman <zeev@annapurnaLabs.com> Cc: Jarkko Sakkinen <jarkko.sakkinen@iki.fi> --- * Changes from v1: - Unlock cs_tfm_mutex if ablkcipher_request_alloc() fails - Add CRYPTO_TFM_REQ_MAY_SLEEP flag to the ablkcipher_request_set_callback() parameters fs/ecryptfs/crypto.c | 143 ++++++++++++++++++++++++++++++------------ fs/ecryptfs/ecryptfs_kernel.h | 3 +- 2 files changed, 104 insertions(+), 42 deletions(-) diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index d5c25db..76808e7 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -243,7 +243,7 @@ void ecryptfs_destroy_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat) struct ecryptfs_key_sig *key_sig, *key_sig_tmp; if (crypt_stat->tfm) - crypto_free_blkcipher(crypt_stat->tfm); + crypto_free_ablkcipher(crypt_stat->tfm); if (crypt_stat->hash_tfm) crypto_free_hash(crypt_stat->hash_tfm); list_for_each_entry_safe(key_sig, key_sig_tmp, @@ -319,6 +319,22 @@ int virt_to_scatterlist(const void *addr, int size, struct scatterlist *sg, return i; } +struct extent_crypt_result { + struct completion completion; + int rc; +}; + +static void extent_crypt_complete(struct crypto_async_request *req, int rc) +{ + struct extent_crypt_result *ecr = req->data; + + if (rc == -EINPROGRESS) + return; + + ecr->rc = rc; + complete(&ecr->completion); +} + /** * encrypt_scatterlist * @crypt_stat: Pointer to the crypt_stat struct to initialize. @@ -334,11 +350,8 @@ static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat, struct scatterlist *src_sg, int size, unsigned char *iv) { - struct blkcipher_desc desc = { - .tfm = crypt_stat->tfm, - .info = iv, - .flags = CRYPTO_TFM_REQ_MAY_SLEEP - }; + struct ablkcipher_request *req = NULL; + struct extent_crypt_result ecr; int rc = 0; BUG_ON(!crypt_stat || !crypt_stat->tfm @@ -349,24 +362,48 @@ static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat, ecryptfs_dump_hex(crypt_stat->key, crypt_stat->key_size); } - /* Consider doing this once, when the file is opened */ + + init_completion(&ecr.completion); + mutex_lock(&crypt_stat->cs_tfm_mutex); - if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) { - rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key, - crypt_stat->key_size); - crypt_stat->flags |= ECRYPTFS_KEY_SET; - } - if (rc) { - ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n", - rc); + req = ablkcipher_request_alloc(crypt_stat->tfm, GFP_NOFS); + if (!req) { mutex_unlock(&crypt_stat->cs_tfm_mutex); - rc = -EINVAL; + rc = -ENOMEM; goto out; } - ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes.\n", size); - crypto_blkcipher_encrypt_iv(&desc, dest_sg, src_sg, size); + + ablkcipher_request_set_callback(req, + CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, + extent_crypt_complete, &ecr); + /* Consider doing this once, when the file is opened */ + if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) { + rc = crypto_ablkcipher_setkey(crypt_stat->tfm, crypt_stat->key, + crypt_stat->key_size); + if (rc) { + ecryptfs_printk(KERN_ERR, + "Error setting key; rc = [%d]\n", + rc); + mutex_unlock(&crypt_stat->cs_tfm_mutex); + rc = -EINVAL; + goto out; + } + crypt_stat->flags |= ECRYPTFS_KEY_SET; + } mutex_unlock(&crypt_stat->cs_tfm_mutex); + ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes.\n", size); + ablkcipher_request_set_crypt(req, src_sg, dest_sg, size, iv); + rc = crypto_ablkcipher_encrypt(req); + if (rc == -EINPROGRESS || rc == -EBUSY) { + struct extent_crypt_result *ecr = req->base.data; + + rc = wait_for_completion_interruptible(&ecr->completion); + if (!rc) + rc = ecr->rc; + INIT_COMPLETION(ecr->completion); + } out: + ablkcipher_request_free(req); return rc; } @@ -624,35 +661,60 @@ static int decrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat, struct scatterlist *src_sg, int size, unsigned char *iv) { - struct blkcipher_desc desc = { - .tfm = crypt_stat->tfm, - .info = iv, - .flags = CRYPTO_TFM_REQ_MAY_SLEEP - }; + struct ablkcipher_request *req = NULL; + struct extent_crypt_result ecr; int rc = 0; - /* Consider doing this once, when the file is opened */ + BUG_ON(!crypt_stat || !crypt_stat->tfm + || !(crypt_stat->flags & ECRYPTFS_STRUCT_INITIALIZED)); + if (unlikely(ecryptfs_verbosity > 0)) { + ecryptfs_printk(KERN_DEBUG, "Key size [%zd]; key:\n", + crypt_stat->key_size); + ecryptfs_dump_hex(crypt_stat->key, + crypt_stat->key_size); + } + + init_completion(&ecr.completion); + mutex_lock(&crypt_stat->cs_tfm_mutex); - rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key, - crypt_stat->key_size); - if (rc) { - ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n", - rc); - mutex_unlock(&crypt_stat->cs_tfm_mutex); - rc = -EINVAL; + req = ablkcipher_request_alloc(crypt_stat->tfm, GFP_NOFS); + if (!req) { + rc = -ENOMEM; goto out; } - ecryptfs_printk(KERN_DEBUG, "Decrypting [%d] bytes.\n", size); - rc = crypto_blkcipher_decrypt_iv(&desc, dest_sg, src_sg, size); + + ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, + extent_crypt_complete, &ecr); + /* Consider doing this once, when the file is opened */ + if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) { + rc = crypto_ablkcipher_setkey(crypt_stat->tfm, crypt_stat->key, + crypt_stat->key_size); + if (rc) { + ecryptfs_printk(KERN_ERR, + "Error setting key; rc = [%d]\n", + rc); + mutex_unlock(&crypt_stat->cs_tfm_mutex); + rc = -EINVAL; + goto out; + } + crypt_stat->flags |= ECRYPTFS_KEY_SET; + } mutex_unlock(&crypt_stat->cs_tfm_mutex); - if (rc) { - ecryptfs_printk(KERN_ERR, "Error decrypting; rc = [%d]\n", - rc); - goto out; + ecryptfs_printk(KERN_DEBUG, "Decrypting [%d] bytes.\n", size); + ablkcipher_request_set_crypt(req, src_sg, dest_sg, size, iv); + rc = crypto_ablkcipher_decrypt(req); + if (rc == -EINPROGRESS || rc == -EBUSY) { + struct extent_crypt_result *ecr = req->base.data; + + rc = wait_for_completion_interruptible(&ecr->completion); + if (!rc) + rc = ecr->rc; + INIT_COMPLETION(ecr->completion); } - rc = size; out: + ablkcipher_request_free(req); return rc; + } /** @@ -746,8 +808,7 @@ int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat) crypt_stat->cipher, "cbc"); if (rc) goto out_unlock; - crypt_stat->tfm = crypto_alloc_blkcipher(full_alg_name, 0, - CRYPTO_ALG_ASYNC); + crypt_stat->tfm = crypto_alloc_ablkcipher(full_alg_name, 0, 0); kfree(full_alg_name); if (IS_ERR(crypt_stat->tfm)) { rc = PTR_ERR(crypt_stat->tfm); @@ -757,7 +818,7 @@ int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat) crypt_stat->cipher); goto out_unlock; } - crypto_blkcipher_set_flags(crypt_stat->tfm, CRYPTO_TFM_REQ_WEAK_KEY); + crypto_ablkcipher_set_flags(crypt_stat->tfm, CRYPTO_TFM_REQ_WEAK_KEY); rc = 0; out_unlock: mutex_unlock(&crypt_stat->cs_tfm_mutex); diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h index dd299b3..f622a73 100644 --- a/fs/ecryptfs/ecryptfs_kernel.h +++ b/fs/ecryptfs/ecryptfs_kernel.h @@ -38,6 +38,7 @@ #include <linux/nsproxy.h> #include <linux/backing-dev.h> #include <linux/ecryptfs.h> +#include <linux/crypto.h> #define ECRYPTFS_DEFAULT_IV_BYTES 16 #define ECRYPTFS_DEFAULT_EXTENT_SIZE 4096 @@ -233,7 +234,7 @@ struct ecryptfs_crypt_stat { size_t extent_shift; unsigned int extent_mask; struct ecryptfs_mount_crypt_stat *mount_crypt_stat; - struct crypto_blkcipher *tfm; + struct crypto_ablkcipher *tfm; struct crypto_hash *hash_tfm; /* Crypto context for generating * the initialization vectors */ unsigned char cipher[ECRYPTFS_MAX_CIPHER_NAME_SIZE]; -- 1.8.1.2 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [RFC v3 1/1] eCryptfs: Use the ablkcipher crypto API 2013-04-09 4:39 ` [RFC v2 " Tyler Hicks @ 2013-04-09 19:07 ` Tyler Hicks 2013-04-10 17:08 ` Tyler Hicks ` (2 more replies) 0 siblings, 3 replies; 8+ messages in thread From: Tyler Hicks @ 2013-04-09 19:07 UTC (permalink / raw) To: ecryptfs Cc: Colin King, Dustin Kirkland, Tim Chen, Ying Huang, Thieu Le, Li Wang, Zeev Zilberman, Jarkko Sakkinen Make the switch from the blkcipher kernel crypto interface to the ablkcipher interface. encrypt_scatterlist() and decrypt_scatterlist() now use the ablkcipher interface but, from the eCryptfs standpoint, still treat the crypto operation as a synchronous operation. They submit the async request and then wait until the operation is finished before they return. Most of the changes are contained inside those two functions. Despite waiting for the completion of the crypto operation, the ablkcipher interface provides performance increases in most cases when used on AES-NI capable hardware. However, sequential I/O with one or two threads on slow storage media does exhibit a sizeable decrease in performance. Signed-off-by: Tyler Hicks <tyhicks@canonical.com> Cc: Colin King <colin.king@canonical.com> Cc: Dustin Kirkland <dustin.kirkland@gazzang.com> Cc: Tim Chen <tim.c.chen@intel.com> Cc: Ying Huang <ying.huang@intel.com> Cc: Thieu Le <thieule@google.com> Cc: Li Wang <dragonylffly@163.com> Cc: Zeev Zilberman <zeev@annapurnaLabs.com> Cc: Jarkko Sakkinen <jarkko.sakkinen@iki.fi> --- * I only made the changes mentioned in RFC v2 to encrypt_scatterlist(). This patch also makes those same changes to decrypt_scatterlist(): - Unlock cs_tfm_mutex if ablkcipher_request_alloc() fails - Add CRYPTO_TFM_REQ_MAY_SLEEP flag to the ablkcipher_request_set_callback() parameters I won't have a chance to gather new performance numbers until later tonight or tomorrow morning. fs/ecryptfs/crypto.c | 143 ++++++++++++++++++++++++++++++------------ fs/ecryptfs/ecryptfs_kernel.h | 3 +- 2 files changed, 105 insertions(+), 41 deletions(-) diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index d5c25db..eb50bce 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -243,7 +243,7 @@ void ecryptfs_destroy_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat) struct ecryptfs_key_sig *key_sig, *key_sig_tmp; if (crypt_stat->tfm) - crypto_free_blkcipher(crypt_stat->tfm); + crypto_free_ablkcipher(crypt_stat->tfm); if (crypt_stat->hash_tfm) crypto_free_hash(crypt_stat->hash_tfm); list_for_each_entry_safe(key_sig, key_sig_tmp, @@ -319,6 +319,22 @@ int virt_to_scatterlist(const void *addr, int size, struct scatterlist *sg, return i; } +struct extent_crypt_result { + struct completion completion; + int rc; +}; + +static void extent_crypt_complete(struct crypto_async_request *req, int rc) +{ + struct extent_crypt_result *ecr = req->data; + + if (rc == -EINPROGRESS) + return; + + ecr->rc = rc; + complete(&ecr->completion); +} + /** * encrypt_scatterlist * @crypt_stat: Pointer to the crypt_stat struct to initialize. @@ -334,11 +350,8 @@ static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat, struct scatterlist *src_sg, int size, unsigned char *iv) { - struct blkcipher_desc desc = { - .tfm = crypt_stat->tfm, - .info = iv, - .flags = CRYPTO_TFM_REQ_MAY_SLEEP - }; + struct ablkcipher_request *req = NULL; + struct extent_crypt_result ecr; int rc = 0; BUG_ON(!crypt_stat || !crypt_stat->tfm @@ -349,24 +362,48 @@ static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat, ecryptfs_dump_hex(crypt_stat->key, crypt_stat->key_size); } - /* Consider doing this once, when the file is opened */ + + init_completion(&ecr.completion); + mutex_lock(&crypt_stat->cs_tfm_mutex); - if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) { - rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key, - crypt_stat->key_size); - crypt_stat->flags |= ECRYPTFS_KEY_SET; - } - if (rc) { - ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n", - rc); + req = ablkcipher_request_alloc(crypt_stat->tfm, GFP_NOFS); + if (!req) { mutex_unlock(&crypt_stat->cs_tfm_mutex); - rc = -EINVAL; + rc = -ENOMEM; goto out; } - ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes.\n", size); - crypto_blkcipher_encrypt_iv(&desc, dest_sg, src_sg, size); + + ablkcipher_request_set_callback(req, + CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, + extent_crypt_complete, &ecr); + /* Consider doing this once, when the file is opened */ + if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) { + rc = crypto_ablkcipher_setkey(crypt_stat->tfm, crypt_stat->key, + crypt_stat->key_size); + if (rc) { + ecryptfs_printk(KERN_ERR, + "Error setting key; rc = [%d]\n", + rc); + mutex_unlock(&crypt_stat->cs_tfm_mutex); + rc = -EINVAL; + goto out; + } + crypt_stat->flags |= ECRYPTFS_KEY_SET; + } mutex_unlock(&crypt_stat->cs_tfm_mutex); + ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes.\n", size); + ablkcipher_request_set_crypt(req, src_sg, dest_sg, size, iv); + rc = crypto_ablkcipher_encrypt(req); + if (rc == -EINPROGRESS || rc == -EBUSY) { + struct extent_crypt_result *ecr = req->base.data; + + rc = wait_for_completion_interruptible(&ecr->completion); + if (!rc) + rc = ecr->rc; + INIT_COMPLETION(ecr->completion); + } out: + ablkcipher_request_free(req); return rc; } @@ -624,35 +661,62 @@ static int decrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat, struct scatterlist *src_sg, int size, unsigned char *iv) { - struct blkcipher_desc desc = { - .tfm = crypt_stat->tfm, - .info = iv, - .flags = CRYPTO_TFM_REQ_MAY_SLEEP - }; + struct ablkcipher_request *req = NULL; + struct extent_crypt_result ecr; int rc = 0; - /* Consider doing this once, when the file is opened */ + BUG_ON(!crypt_stat || !crypt_stat->tfm + || !(crypt_stat->flags & ECRYPTFS_STRUCT_INITIALIZED)); + if (unlikely(ecryptfs_verbosity > 0)) { + ecryptfs_printk(KERN_DEBUG, "Key size [%zd]; key:\n", + crypt_stat->key_size); + ecryptfs_dump_hex(crypt_stat->key, + crypt_stat->key_size); + } + + init_completion(&ecr.completion); + mutex_lock(&crypt_stat->cs_tfm_mutex); - rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key, - crypt_stat->key_size); - if (rc) { - ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n", - rc); + req = ablkcipher_request_alloc(crypt_stat->tfm, GFP_NOFS); + if (!req) { mutex_unlock(&crypt_stat->cs_tfm_mutex); - rc = -EINVAL; + rc = -ENOMEM; goto out; } - ecryptfs_printk(KERN_DEBUG, "Decrypting [%d] bytes.\n", size); - rc = crypto_blkcipher_decrypt_iv(&desc, dest_sg, src_sg, size); + + ablkcipher_request_set_callback(req, + CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, + extent_crypt_complete, &ecr); + /* Consider doing this once, when the file is opened */ + if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) { + rc = crypto_ablkcipher_setkey(crypt_stat->tfm, crypt_stat->key, + crypt_stat->key_size); + if (rc) { + ecryptfs_printk(KERN_ERR, + "Error setting key; rc = [%d]\n", + rc); + mutex_unlock(&crypt_stat->cs_tfm_mutex); + rc = -EINVAL; + goto out; + } + crypt_stat->flags |= ECRYPTFS_KEY_SET; + } mutex_unlock(&crypt_stat->cs_tfm_mutex); - if (rc) { - ecryptfs_printk(KERN_ERR, "Error decrypting; rc = [%d]\n", - rc); - goto out; + ecryptfs_printk(KERN_DEBUG, "Decrypting [%d] bytes.\n", size); + ablkcipher_request_set_crypt(req, src_sg, dest_sg, size, iv); + rc = crypto_ablkcipher_decrypt(req); + if (rc == -EINPROGRESS || rc == -EBUSY) { + struct extent_crypt_result *ecr = req->base.data; + + rc = wait_for_completion_interruptible(&ecr->completion); + if (!rc) + rc = ecr->rc; + INIT_COMPLETION(ecr->completion); } - rc = size; out: + ablkcipher_request_free(req); return rc; + } /** @@ -746,8 +810,7 @@ int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat) crypt_stat->cipher, "cbc"); if (rc) goto out_unlock; - crypt_stat->tfm = crypto_alloc_blkcipher(full_alg_name, 0, - CRYPTO_ALG_ASYNC); + crypt_stat->tfm = crypto_alloc_ablkcipher(full_alg_name, 0, 0); kfree(full_alg_name); if (IS_ERR(crypt_stat->tfm)) { rc = PTR_ERR(crypt_stat->tfm); @@ -757,7 +820,7 @@ int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat) crypt_stat->cipher); goto out_unlock; } - crypto_blkcipher_set_flags(crypt_stat->tfm, CRYPTO_TFM_REQ_WEAK_KEY); + crypto_ablkcipher_set_flags(crypt_stat->tfm, CRYPTO_TFM_REQ_WEAK_KEY); rc = 0; out_unlock: mutex_unlock(&crypt_stat->cs_tfm_mutex); diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h index dd299b3..f622a73 100644 --- a/fs/ecryptfs/ecryptfs_kernel.h +++ b/fs/ecryptfs/ecryptfs_kernel.h @@ -38,6 +38,7 @@ #include <linux/nsproxy.h> #include <linux/backing-dev.h> #include <linux/ecryptfs.h> +#include <linux/crypto.h> #define ECRYPTFS_DEFAULT_IV_BYTES 16 #define ECRYPTFS_DEFAULT_EXTENT_SIZE 4096 @@ -233,7 +234,7 @@ struct ecryptfs_crypt_stat { size_t extent_shift; unsigned int extent_mask; struct ecryptfs_mount_crypt_stat *mount_crypt_stat; - struct crypto_blkcipher *tfm; + struct crypto_ablkcipher *tfm; struct crypto_hash *hash_tfm; /* Crypto context for generating * the initialization vectors */ unsigned char cipher[ECRYPTFS_MAX_CIPHER_NAME_SIZE]; -- 1.8.1.2 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [RFC v3 1/1] eCryptfs: Use the ablkcipher crypto API 2013-04-09 19:07 ` [RFC v3 " Tyler Hicks @ 2013-04-10 17:08 ` Tyler Hicks 2013-04-10 17:26 ` Colin Ian King 2013-04-28 7:37 ` Zeev Zilberman 2 siblings, 0 replies; 8+ messages in thread From: Tyler Hicks @ 2013-04-10 17:08 UTC (permalink / raw) To: ecryptfs Cc: Colin King, Dustin Kirkland, Tim Chen, Ying Huang, Thieu Le, Li Wang, Zeev Zilberman, Jarkko Sakkinen [-- Attachment #1.1: Type: text/plain, Size: 11039 bytes --] On 2013-04-09 12:07:59, Tyler Hicks wrote: > Make the switch from the blkcipher kernel crypto interface to the > ablkcipher interface. > > encrypt_scatterlist() and decrypt_scatterlist() now use the ablkcipher > interface but, from the eCryptfs standpoint, still treat the crypto > operation as a synchronous operation. They submit the async request and > then wait until the operation is finished before they return. Most of > the changes are contained inside those two functions. > > Despite waiting for the completion of the crypto operation, the > ablkcipher interface provides performance increases in most cases when > used on AES-NI capable hardware. However, sequential I/O with one or two > threads on slow storage media does exhibit a sizeable decrease in > performance. > > Signed-off-by: Tyler Hicks <tyhicks@canonical.com> > Cc: Colin King <colin.king@canonical.com> > Cc: Dustin Kirkland <dustin.kirkland@gazzang.com> > Cc: Tim Chen <tim.c.chen@intel.com> > Cc: Ying Huang <ying.huang@intel.com> > Cc: Thieu Le <thieule@google.com> > Cc: Li Wang <dragonylffly@163.com> > Cc: Zeev Zilberman <zeev@annapurnaLabs.com> > Cc: Jarkko Sakkinen <jarkko.sakkinen@iki.fi> > --- > > * I only made the changes mentioned in RFC v2 to encrypt_scatterlist(). This > patch also makes those same changes to decrypt_scatterlist(): > - Unlock cs_tfm_mutex if ablkcipher_request_alloc() fails > - Add CRYPTO_TFM_REQ_MAY_SLEEP flag to the ablkcipher_request_set_callback() > parameters > > I won't have a chance to gather new performance numbers until later tonight or > tomorrow morning. I've attached a PDF of the tiobench results using vanilla 3.9-rc5, 3.9-rc5 plus the async patches, and 3.9-rc5 plus the ablkcipher patch. After looking a bunch of these test results, I've noticed some variations in the results. For example, the attached numbers show the ablkcipher patch causing a slow down on the SSD when doing single-threaded sequential writes. But, I've seen another set of results that had a similar slow down with the async patches but not the ablkcipher patch. So, my take away is that the ablkcipher patch and async patches perform the same. The ablkcipher patch does not have any effect when using AES or 3DES when hardware acceleration is not available. I plan on queuing up the ablkcipher patch for the 3.10 merge window unless anyone speaks up between now and then. It is simple and performs the same as the async patches. Tyler > > fs/ecryptfs/crypto.c | 143 ++++++++++++++++++++++++++++++------------ > fs/ecryptfs/ecryptfs_kernel.h | 3 +- > 2 files changed, 105 insertions(+), 41 deletions(-) > > diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c > index d5c25db..eb50bce 100644 > --- a/fs/ecryptfs/crypto.c > +++ b/fs/ecryptfs/crypto.c > @@ -243,7 +243,7 @@ void ecryptfs_destroy_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat) > struct ecryptfs_key_sig *key_sig, *key_sig_tmp; > > if (crypt_stat->tfm) > - crypto_free_blkcipher(crypt_stat->tfm); > + crypto_free_ablkcipher(crypt_stat->tfm); > if (crypt_stat->hash_tfm) > crypto_free_hash(crypt_stat->hash_tfm); > list_for_each_entry_safe(key_sig, key_sig_tmp, > @@ -319,6 +319,22 @@ int virt_to_scatterlist(const void *addr, int size, struct scatterlist *sg, > return i; > } > > +struct extent_crypt_result { > + struct completion completion; > + int rc; > +}; > + > +static void extent_crypt_complete(struct crypto_async_request *req, int rc) > +{ > + struct extent_crypt_result *ecr = req->data; > + > + if (rc == -EINPROGRESS) > + return; > + > + ecr->rc = rc; > + complete(&ecr->completion); > +} > + > /** > * encrypt_scatterlist > * @crypt_stat: Pointer to the crypt_stat struct to initialize. > @@ -334,11 +350,8 @@ static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat, > struct scatterlist *src_sg, int size, > unsigned char *iv) > { > - struct blkcipher_desc desc = { > - .tfm = crypt_stat->tfm, > - .info = iv, > - .flags = CRYPTO_TFM_REQ_MAY_SLEEP > - }; > + struct ablkcipher_request *req = NULL; > + struct extent_crypt_result ecr; > int rc = 0; > > BUG_ON(!crypt_stat || !crypt_stat->tfm > @@ -349,24 +362,48 @@ static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat, > ecryptfs_dump_hex(crypt_stat->key, > crypt_stat->key_size); > } > - /* Consider doing this once, when the file is opened */ > + > + init_completion(&ecr.completion); > + > mutex_lock(&crypt_stat->cs_tfm_mutex); > - if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) { > - rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key, > - crypt_stat->key_size); > - crypt_stat->flags |= ECRYPTFS_KEY_SET; > - } > - if (rc) { > - ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n", > - rc); > + req = ablkcipher_request_alloc(crypt_stat->tfm, GFP_NOFS); > + if (!req) { > mutex_unlock(&crypt_stat->cs_tfm_mutex); > - rc = -EINVAL; > + rc = -ENOMEM; > goto out; > } > - ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes.\n", size); > - crypto_blkcipher_encrypt_iv(&desc, dest_sg, src_sg, size); > + > + ablkcipher_request_set_callback(req, > + CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, > + extent_crypt_complete, &ecr); > + /* Consider doing this once, when the file is opened */ > + if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) { > + rc = crypto_ablkcipher_setkey(crypt_stat->tfm, crypt_stat->key, > + crypt_stat->key_size); > + if (rc) { > + ecryptfs_printk(KERN_ERR, > + "Error setting key; rc = [%d]\n", > + rc); > + mutex_unlock(&crypt_stat->cs_tfm_mutex); > + rc = -EINVAL; > + goto out; > + } > + crypt_stat->flags |= ECRYPTFS_KEY_SET; > + } > mutex_unlock(&crypt_stat->cs_tfm_mutex); > + ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes.\n", size); > + ablkcipher_request_set_crypt(req, src_sg, dest_sg, size, iv); > + rc = crypto_ablkcipher_encrypt(req); > + if (rc == -EINPROGRESS || rc == -EBUSY) { > + struct extent_crypt_result *ecr = req->base.data; > + > + rc = wait_for_completion_interruptible(&ecr->completion); > + if (!rc) > + rc = ecr->rc; > + INIT_COMPLETION(ecr->completion); > + } > out: > + ablkcipher_request_free(req); > return rc; > } > > @@ -624,35 +661,62 @@ static int decrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat, > struct scatterlist *src_sg, int size, > unsigned char *iv) > { > - struct blkcipher_desc desc = { > - .tfm = crypt_stat->tfm, > - .info = iv, > - .flags = CRYPTO_TFM_REQ_MAY_SLEEP > - }; > + struct ablkcipher_request *req = NULL; > + struct extent_crypt_result ecr; > int rc = 0; > > - /* Consider doing this once, when the file is opened */ > + BUG_ON(!crypt_stat || !crypt_stat->tfm > + || !(crypt_stat->flags & ECRYPTFS_STRUCT_INITIALIZED)); > + if (unlikely(ecryptfs_verbosity > 0)) { > + ecryptfs_printk(KERN_DEBUG, "Key size [%zd]; key:\n", > + crypt_stat->key_size); > + ecryptfs_dump_hex(crypt_stat->key, > + crypt_stat->key_size); > + } > + > + init_completion(&ecr.completion); > + > mutex_lock(&crypt_stat->cs_tfm_mutex); > - rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key, > - crypt_stat->key_size); > - if (rc) { > - ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n", > - rc); > + req = ablkcipher_request_alloc(crypt_stat->tfm, GFP_NOFS); > + if (!req) { > mutex_unlock(&crypt_stat->cs_tfm_mutex); > - rc = -EINVAL; > + rc = -ENOMEM; > goto out; > } > - ecryptfs_printk(KERN_DEBUG, "Decrypting [%d] bytes.\n", size); > - rc = crypto_blkcipher_decrypt_iv(&desc, dest_sg, src_sg, size); > + > + ablkcipher_request_set_callback(req, > + CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, > + extent_crypt_complete, &ecr); > + /* Consider doing this once, when the file is opened */ > + if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) { > + rc = crypto_ablkcipher_setkey(crypt_stat->tfm, crypt_stat->key, > + crypt_stat->key_size); > + if (rc) { > + ecryptfs_printk(KERN_ERR, > + "Error setting key; rc = [%d]\n", > + rc); > + mutex_unlock(&crypt_stat->cs_tfm_mutex); > + rc = -EINVAL; > + goto out; > + } > + crypt_stat->flags |= ECRYPTFS_KEY_SET; > + } > mutex_unlock(&crypt_stat->cs_tfm_mutex); > - if (rc) { > - ecryptfs_printk(KERN_ERR, "Error decrypting; rc = [%d]\n", > - rc); > - goto out; > + ecryptfs_printk(KERN_DEBUG, "Decrypting [%d] bytes.\n", size); > + ablkcipher_request_set_crypt(req, src_sg, dest_sg, size, iv); > + rc = crypto_ablkcipher_decrypt(req); > + if (rc == -EINPROGRESS || rc == -EBUSY) { > + struct extent_crypt_result *ecr = req->base.data; > + > + rc = wait_for_completion_interruptible(&ecr->completion); > + if (!rc) > + rc = ecr->rc; > + INIT_COMPLETION(ecr->completion); > } > - rc = size; > out: > + ablkcipher_request_free(req); > return rc; > + > } > > /** > @@ -746,8 +810,7 @@ int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat) > crypt_stat->cipher, "cbc"); > if (rc) > goto out_unlock; > - crypt_stat->tfm = crypto_alloc_blkcipher(full_alg_name, 0, > - CRYPTO_ALG_ASYNC); > + crypt_stat->tfm = crypto_alloc_ablkcipher(full_alg_name, 0, 0); > kfree(full_alg_name); > if (IS_ERR(crypt_stat->tfm)) { > rc = PTR_ERR(crypt_stat->tfm); > @@ -757,7 +820,7 @@ int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat) > crypt_stat->cipher); > goto out_unlock; > } > - crypto_blkcipher_set_flags(crypt_stat->tfm, CRYPTO_TFM_REQ_WEAK_KEY); > + crypto_ablkcipher_set_flags(crypt_stat->tfm, CRYPTO_TFM_REQ_WEAK_KEY); > rc = 0; > out_unlock: > mutex_unlock(&crypt_stat->cs_tfm_mutex); > diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h > index dd299b3..f622a73 100644 > --- a/fs/ecryptfs/ecryptfs_kernel.h > +++ b/fs/ecryptfs/ecryptfs_kernel.h > @@ -38,6 +38,7 @@ > #include <linux/nsproxy.h> > #include <linux/backing-dev.h> > #include <linux/ecryptfs.h> > +#include <linux/crypto.h> > > #define ECRYPTFS_DEFAULT_IV_BYTES 16 > #define ECRYPTFS_DEFAULT_EXTENT_SIZE 4096 > @@ -233,7 +234,7 @@ struct ecryptfs_crypt_stat { > size_t extent_shift; > unsigned int extent_mask; > struct ecryptfs_mount_crypt_stat *mount_crypt_stat; > - struct crypto_blkcipher *tfm; > + struct crypto_ablkcipher *tfm; > struct crypto_hash *hash_tfm; /* Crypto context for generating > * the initialization vectors */ > unsigned char cipher[ECRYPTFS_MAX_CIPHER_NAME_SIZE]; > -- > 1.8.1.2 > > -- > To unsubscribe from this list: send the line "unsubscribe ecryptfs" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html [-- Attachment #1.2: 3.9-rc5-async-ablkcipher-tiobench.pdf --] [-- Type: application/pdf, Size: 29306 bytes --] [-- Attachment #2: Digital signature --] [-- Type: application/pgp-signature, Size: 836 bytes --] ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [RFC v3 1/1] eCryptfs: Use the ablkcipher crypto API 2013-04-09 19:07 ` [RFC v3 " Tyler Hicks 2013-04-10 17:08 ` Tyler Hicks @ 2013-04-10 17:26 ` Colin Ian King 2013-04-28 7:37 ` Zeev Zilberman 2 siblings, 0 replies; 8+ messages in thread From: Colin Ian King @ 2013-04-10 17:26 UTC (permalink / raw) To: Tyler Hicks Cc: ecryptfs, Dustin Kirkland, Tim Chen, Ying Huang, Thieu Le, Li Wang, Zeev Zilberman, Jarkko Sakkinen On 09/04/13 20:07, Tyler Hicks wrote: > Make the switch from the blkcipher kernel crypto interface to the > ablkcipher interface. > > encrypt_scatterlist() and decrypt_scatterlist() now use the ablkcipher > interface but, from the eCryptfs standpoint, still treat the crypto > operation as a synchronous operation. They submit the async request and > then wait until the operation is finished before they return. Most of > the changes are contained inside those two functions. > > Despite waiting for the completion of the crypto operation, the > ablkcipher interface provides performance increases in most cases when > used on AES-NI capable hardware. However, sequential I/O with one or two > threads on slow storage media does exhibit a sizeable decrease in > performance. > With the testing I've run with the ablkcipher patch I observe a noticeable performance win with fast media such as SSD or tmpfs and a slight improvement with fast 7200 rpm HDDs. With slower HDDs, I don't see any negative performance impact with ablkcipher. Exercised on a recent AES-NI capable Intel 4 core server with 7200 rpm HDD and Intel 330 SSD and also with a Intel i3-2350M Lenovo X220i laptop with a 5400 rpm HDD and Intel 330 SSD. I have also given this patch considerable amount of soak testing overnight with continuous parallel kernel builds while also running the eCryptfs tests without any issues. As it stands, I am happy with v3 of this patch. ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [RFC v3 1/1] eCryptfs: Use the ablkcipher crypto API 2013-04-09 19:07 ` [RFC v3 " Tyler Hicks 2013-04-10 17:08 ` Tyler Hicks 2013-04-10 17:26 ` Colin Ian King @ 2013-04-28 7:37 ` Zeev Zilberman 2 siblings, 0 replies; 8+ messages in thread From: Zeev Zilberman @ 2013-04-28 7:37 UTC (permalink / raw) To: Tyler Hicks, ecryptfs@vger.kernel.org Cc: Colin King, Dustin Kirkland, Tim Chen, Ying Huang, Thieu Le, Li Wang, Jarkko Sakkinen Hi Tyler, The patch works well, except the use of wait_for_completion_interruptible() which can cause crashes. In case a signal is sent, the request is freed before the processing was finished. So, the driver can attempt to access a request that was already freed. I think that regular wait_for_completion() should be used. Zeev On 4/9/13 10:07 PM, "Tyler Hicks" <tyhicks@canonical.com> wrote: >Make the switch from the blkcipher kernel crypto interface to the >ablkcipher interface. > >encrypt_scatterlist() and decrypt_scatterlist() now use the ablkcipher >interface but, from the eCryptfs standpoint, still treat the crypto >operation as a synchronous operation. They submit the async request and >then wait until the operation is finished before they return. Most of >the changes are contained inside those two functions. > >Despite waiting for the completion of the crypto operation, the >ablkcipher interface provides performance increases in most cases when >used on AES-NI capable hardware. However, sequential I/O with one or two >threads on slow storage media does exhibit a sizeable decrease in >performance. > >Signed-off-by: Tyler Hicks <tyhicks@canonical.com> >Cc: Colin King <colin.king@canonical.com> >Cc: Dustin Kirkland <dustin.kirkland@gazzang.com> >Cc: Tim Chen <tim.c.chen@intel.com> >Cc: Ying Huang <ying.huang@intel.com> >Cc: Thieu Le <thieule@google.com> >Cc: Li Wang <dragonylffly@163.com> >Cc: Zeev Zilberman <zeev@annapurnaLabs.com> >Cc: Jarkko Sakkinen <jarkko.sakkinen@iki.fi> >--- > >* I only made the changes mentioned in RFC v2 to encrypt_scatterlist(). >This > patch also makes those same changes to decrypt_scatterlist(): > - Unlock cs_tfm_mutex if ablkcipher_request_alloc() fails > - Add CRYPTO_TFM_REQ_MAY_SLEEP flag to the >ablkcipher_request_set_callback() > parameters > >I won't have a chance to gather new performance numbers until later >tonight or >tomorrow morning. > > fs/ecryptfs/crypto.c | 143 >++++++++++++++++++++++++++++++------------ > fs/ecryptfs/ecryptfs_kernel.h | 3 +- > 2 files changed, 105 insertions(+), 41 deletions(-) > >diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c >index d5c25db..eb50bce 100644 >--- a/fs/ecryptfs/crypto.c >+++ b/fs/ecryptfs/crypto.c >@@ -243,7 +243,7 @@ void ecryptfs_destroy_crypt_stat(struct >ecryptfs_crypt_stat *crypt_stat) > struct ecryptfs_key_sig *key_sig, *key_sig_tmp; > > if (crypt_stat->tfm) >- crypto_free_blkcipher(crypt_stat->tfm); >+ crypto_free_ablkcipher(crypt_stat->tfm); > if (crypt_stat->hash_tfm) > crypto_free_hash(crypt_stat->hash_tfm); > list_for_each_entry_safe(key_sig, key_sig_tmp, >@@ -319,6 +319,22 @@ int virt_to_scatterlist(const void *addr, int size, >struct scatterlist *sg, > return i; > } > >+struct extent_crypt_result { >+ struct completion completion; >+ int rc; >+}; >+ >+static void extent_crypt_complete(struct crypto_async_request *req, int >rc) >+{ >+ struct extent_crypt_result *ecr = req->data; >+ >+ if (rc == -EINPROGRESS) >+ return; >+ >+ ecr->rc = rc; >+ complete(&ecr->completion); >+} >+ > /** > * encrypt_scatterlist > * @crypt_stat: Pointer to the crypt_stat struct to initialize. >@@ -334,11 +350,8 @@ static int encrypt_scatterlist(struct >ecryptfs_crypt_stat *crypt_stat, > struct scatterlist *src_sg, int size, > unsigned char *iv) > { >- struct blkcipher_desc desc = { >- .tfm = crypt_stat->tfm, >- .info = iv, >- .flags = CRYPTO_TFM_REQ_MAY_SLEEP >- }; >+ struct ablkcipher_request *req = NULL; >+ struct extent_crypt_result ecr; > int rc = 0; > > BUG_ON(!crypt_stat || !crypt_stat->tfm >@@ -349,24 +362,48 @@ static int encrypt_scatterlist(struct >ecryptfs_crypt_stat *crypt_stat, > ecryptfs_dump_hex(crypt_stat->key, > crypt_stat->key_size); > } >- /* Consider doing this once, when the file is opened */ >+ >+ init_completion(&ecr.completion); >+ > mutex_lock(&crypt_stat->cs_tfm_mutex); >- if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) { >- rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key, >- crypt_stat->key_size); >- crypt_stat->flags |= ECRYPTFS_KEY_SET; >- } >- if (rc) { >- ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n", >- rc); >+ req = ablkcipher_request_alloc(crypt_stat->tfm, GFP_NOFS); >+ if (!req) { > mutex_unlock(&crypt_stat->cs_tfm_mutex); >- rc = -EINVAL; >+ rc = -ENOMEM; > goto out; > } >- ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes.\n", size); >- crypto_blkcipher_encrypt_iv(&desc, dest_sg, src_sg, size); >+ >+ ablkcipher_request_set_callback(req, >+ CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, >+ extent_crypt_complete, &ecr); >+ /* Consider doing this once, when the file is opened */ >+ if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) { >+ rc = crypto_ablkcipher_setkey(crypt_stat->tfm, crypt_stat->key, >+ crypt_stat->key_size); >+ if (rc) { >+ ecryptfs_printk(KERN_ERR, >+ "Error setting key; rc = [%d]\n", >+ rc); >+ mutex_unlock(&crypt_stat->cs_tfm_mutex); >+ rc = -EINVAL; >+ goto out; >+ } >+ crypt_stat->flags |= ECRYPTFS_KEY_SET; >+ } > mutex_unlock(&crypt_stat->cs_tfm_mutex); >+ ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes.\n", size); >+ ablkcipher_request_set_crypt(req, src_sg, dest_sg, size, iv); >+ rc = crypto_ablkcipher_encrypt(req); >+ if (rc == -EINPROGRESS || rc == -EBUSY) { >+ struct extent_crypt_result *ecr = req->base.data; >+ >+ rc = wait_for_completion_interruptible(&ecr->completion); >+ if (!rc) >+ rc = ecr->rc; >+ INIT_COMPLETION(ecr->completion); >+ } > out: >+ ablkcipher_request_free(req); > return rc; > } > >@@ -624,35 +661,62 @@ static int decrypt_scatterlist(struct >ecryptfs_crypt_stat *crypt_stat, > struct scatterlist *src_sg, int size, > unsigned char *iv) > { >- struct blkcipher_desc desc = { >- .tfm = crypt_stat->tfm, >- .info = iv, >- .flags = CRYPTO_TFM_REQ_MAY_SLEEP >- }; >+ struct ablkcipher_request *req = NULL; >+ struct extent_crypt_result ecr; > int rc = 0; > >- /* Consider doing this once, when the file is opened */ >+ BUG_ON(!crypt_stat || !crypt_stat->tfm >+ || !(crypt_stat->flags & ECRYPTFS_STRUCT_INITIALIZED)); >+ if (unlikely(ecryptfs_verbosity > 0)) { >+ ecryptfs_printk(KERN_DEBUG, "Key size [%zd]; key:\n", >+ crypt_stat->key_size); >+ ecryptfs_dump_hex(crypt_stat->key, >+ crypt_stat->key_size); >+ } >+ >+ init_completion(&ecr.completion); >+ > mutex_lock(&crypt_stat->cs_tfm_mutex); >- rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key, >- crypt_stat->key_size); >- if (rc) { >- ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n", >- rc); >+ req = ablkcipher_request_alloc(crypt_stat->tfm, GFP_NOFS); >+ if (!req) { > mutex_unlock(&crypt_stat->cs_tfm_mutex); >- rc = -EINVAL; >+ rc = -ENOMEM; > goto out; > } >- ecryptfs_printk(KERN_DEBUG, "Decrypting [%d] bytes.\n", size); >- rc = crypto_blkcipher_decrypt_iv(&desc, dest_sg, src_sg, size); >+ >+ ablkcipher_request_set_callback(req, >+ CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, >+ extent_crypt_complete, &ecr); >+ /* Consider doing this once, when the file is opened */ >+ if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) { >+ rc = crypto_ablkcipher_setkey(crypt_stat->tfm, crypt_stat->key, >+ crypt_stat->key_size); >+ if (rc) { >+ ecryptfs_printk(KERN_ERR, >+ "Error setting key; rc = [%d]\n", >+ rc); >+ mutex_unlock(&crypt_stat->cs_tfm_mutex); >+ rc = -EINVAL; >+ goto out; >+ } >+ crypt_stat->flags |= ECRYPTFS_KEY_SET; >+ } > mutex_unlock(&crypt_stat->cs_tfm_mutex); >- if (rc) { >- ecryptfs_printk(KERN_ERR, "Error decrypting; rc = [%d]\n", >- rc); >- goto out; >+ ecryptfs_printk(KERN_DEBUG, "Decrypting [%d] bytes.\n", size); >+ ablkcipher_request_set_crypt(req, src_sg, dest_sg, size, iv); >+ rc = crypto_ablkcipher_decrypt(req); >+ if (rc == -EINPROGRESS || rc == -EBUSY) { >+ struct extent_crypt_result *ecr = req->base.data; >+ >+ rc = wait_for_completion_interruptible(&ecr->completion); >+ if (!rc) >+ rc = ecr->rc; >+ INIT_COMPLETION(ecr->completion); > } >- rc = size; > out: >+ ablkcipher_request_free(req); > return rc; >+ > } > > /** >@@ -746,8 +810,7 @@ int ecryptfs_init_crypt_ctx(struct >ecryptfs_crypt_stat *crypt_stat) > crypt_stat->cipher, "cbc"); > if (rc) > goto out_unlock; >- crypt_stat->tfm = crypto_alloc_blkcipher(full_alg_name, 0, >- CRYPTO_ALG_ASYNC); >+ crypt_stat->tfm = crypto_alloc_ablkcipher(full_alg_name, 0, 0); > kfree(full_alg_name); > if (IS_ERR(crypt_stat->tfm)) { > rc = PTR_ERR(crypt_stat->tfm); >@@ -757,7 +820,7 @@ int ecryptfs_init_crypt_ctx(struct >ecryptfs_crypt_stat *crypt_stat) > crypt_stat->cipher); > goto out_unlock; > } >- crypto_blkcipher_set_flags(crypt_stat->tfm, CRYPTO_TFM_REQ_WEAK_KEY); >+ crypto_ablkcipher_set_flags(crypt_stat->tfm, CRYPTO_TFM_REQ_WEAK_KEY); > rc = 0; > out_unlock: > mutex_unlock(&crypt_stat->cs_tfm_mutex); >diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h >index dd299b3..f622a73 100644 >--- a/fs/ecryptfs/ecryptfs_kernel.h >+++ b/fs/ecryptfs/ecryptfs_kernel.h >@@ -38,6 +38,7 @@ > #include <linux/nsproxy.h> > #include <linux/backing-dev.h> > #include <linux/ecryptfs.h> >+#include <linux/crypto.h> > > #define ECRYPTFS_DEFAULT_IV_BYTES 16 > #define ECRYPTFS_DEFAULT_EXTENT_SIZE 4096 >@@ -233,7 +234,7 @@ struct ecryptfs_crypt_stat { > size_t extent_shift; > unsigned int extent_mask; > struct ecryptfs_mount_crypt_stat *mount_crypt_stat; >- struct crypto_blkcipher *tfm; >+ struct crypto_ablkcipher *tfm; > struct crypto_hash *hash_tfm; /* Crypto context for generating > * the initialization vectors */ > unsigned char cipher[ECRYPTFS_MAX_CIPHER_NAME_SIZE]; >-- >1.8.1.2 > >-- >To unsubscribe from this list: send the line "unsubscribe ecryptfs" in >the body of a message to majordomo@vger.kernel.org >More majordomo info at http://vger.kernel.org/majordomo-info.html > ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2013-04-28 7:37 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2013-04-05 23:42 [RFC 0/1] eCryptfs: Use the ablkcipher crypto API Tyler Hicks 2013-04-05 23:42 ` [RFC 1/1] " Tyler Hicks 2013-04-09 4:30 ` Tyler Hicks 2013-04-09 4:39 ` [RFC v2 " Tyler Hicks 2013-04-09 19:07 ` [RFC v3 " Tyler Hicks 2013-04-10 17:08 ` Tyler Hicks 2013-04-10 17:26 ` Colin Ian King 2013-04-28 7:37 ` Zeev Zilberman
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox