aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorTyler Hicks <tyhicks@canonical.com>2013-05-09 19:55:07 -0400
committerTyler Hicks <tyhicks@canonical.com>2013-05-09 19:55:07 -0400
commit4dfea4f0d7f13309d2ee112a2584210cae4320c6 (patch)
tree53af474217e7072070f260f4284d988b75456332 /fs
parentc1be5a5b1b355d40e6cf79cc979eb66dafa24ad1 (diff)
eCryptfs: Use the ablkcipher crypto API
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. Signed-off-by: Tyler Hicks <tyhicks@canonical.com> Acked-by: Colin King <colin.king@canonical.com> Reviewed-by: Zeev Zilberman <zeev@annapurnaLabs.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: Jarkko Sakkinen <jarkko.sakkinen@iki.fi>
Diffstat (limited to 'fs')
-rw-r--r--fs/ecryptfs/crypto.c141
-rw-r--r--fs/ecryptfs/ecryptfs_kernel.h3
2 files changed, 103 insertions, 41 deletions
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index d5c25db4398f..f71ec125290d 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)
243 struct ecryptfs_key_sig *key_sig, *key_sig_tmp; 243 struct ecryptfs_key_sig *key_sig, *key_sig_tmp;
244 244
245 if (crypt_stat->tfm) 245 if (crypt_stat->tfm)
246 crypto_free_blkcipher(crypt_stat->tfm); 246 crypto_free_ablkcipher(crypt_stat->tfm);
247 if (crypt_stat->hash_tfm) 247 if (crypt_stat->hash_tfm)
248 crypto_free_hash(crypt_stat->hash_tfm); 248 crypto_free_hash(crypt_stat->hash_tfm);
249 list_for_each_entry_safe(key_sig, key_sig_tmp, 249 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,
319 return i; 319 return i;
320} 320}
321 321
322struct extent_crypt_result {
323 struct completion completion;
324 int rc;
325};
326
327static void extent_crypt_complete(struct crypto_async_request *req, int rc)
328{
329 struct extent_crypt_result *ecr = req->data;
330
331 if (rc == -EINPROGRESS)
332 return;
333
334 ecr->rc = rc;
335 complete(&ecr->completion);
336}
337
322/** 338/**
323 * encrypt_scatterlist 339 * encrypt_scatterlist
324 * @crypt_stat: Pointer to the crypt_stat struct to initialize. 340 * @crypt_stat: Pointer to the crypt_stat struct to initialize.
@@ -334,11 +350,8 @@ static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,
334 struct scatterlist *src_sg, int size, 350 struct scatterlist *src_sg, int size,
335 unsigned char *iv) 351 unsigned char *iv)
336{ 352{
337 struct blkcipher_desc desc = { 353 struct ablkcipher_request *req = NULL;
338 .tfm = crypt_stat->tfm, 354 struct extent_crypt_result ecr;
339 .info = iv,
340 .flags = CRYPTO_TFM_REQ_MAY_SLEEP
341 };
342 int rc = 0; 355 int rc = 0;
343 356
344 BUG_ON(!crypt_stat || !crypt_stat->tfm 357 BUG_ON(!crypt_stat || !crypt_stat->tfm
@@ -349,24 +362,47 @@ static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,
349 ecryptfs_dump_hex(crypt_stat->key, 362 ecryptfs_dump_hex(crypt_stat->key,
350 crypt_stat->key_size); 363 crypt_stat->key_size);
351 } 364 }
352 /* Consider doing this once, when the file is opened */ 365
366 init_completion(&ecr.completion);
367
353 mutex_lock(&crypt_stat->cs_tfm_mutex); 368 mutex_lock(&crypt_stat->cs_tfm_mutex);
354 if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) { 369 req = ablkcipher_request_alloc(crypt_stat->tfm, GFP_NOFS);
355 rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key, 370 if (!req) {
356 crypt_stat->key_size);
357 crypt_stat->flags |= ECRYPTFS_KEY_SET;
358 }
359 if (rc) {
360 ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n",
361 rc);
362 mutex_unlock(&crypt_stat->cs_tfm_mutex); 371 mutex_unlock(&crypt_stat->cs_tfm_mutex);
363 rc = -EINVAL; 372 rc = -ENOMEM;
364 goto out; 373 goto out;
365 } 374 }
366 ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes.\n", size); 375
367 crypto_blkcipher_encrypt_iv(&desc, dest_sg, src_sg, size); 376 ablkcipher_request_set_callback(req,
377 CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
378 extent_crypt_complete, &ecr);
379 /* Consider doing this once, when the file is opened */
380 if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) {
381 rc = crypto_ablkcipher_setkey(crypt_stat->tfm, crypt_stat->key,
382 crypt_stat->key_size);
383 if (rc) {
384 ecryptfs_printk(KERN_ERR,
385 "Error setting key; rc = [%d]\n",
386 rc);
387 mutex_unlock(&crypt_stat->cs_tfm_mutex);
388 rc = -EINVAL;
389 goto out;
390 }
391 crypt_stat->flags |= ECRYPTFS_KEY_SET;
392 }
368 mutex_unlock(&crypt_stat->cs_tfm_mutex); 393 mutex_unlock(&crypt_stat->cs_tfm_mutex);
394 ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes.\n", size);
395 ablkcipher_request_set_crypt(req, src_sg, dest_sg, size, iv);
396 rc = crypto_ablkcipher_encrypt(req);
397 if (rc == -EINPROGRESS || rc == -EBUSY) {
398 struct extent_crypt_result *ecr = req->base.data;
399
400 wait_for_completion(&ecr->completion);
401 rc = ecr->rc;
402 INIT_COMPLETION(ecr->completion);
403 }
369out: 404out:
405 ablkcipher_request_free(req);
370 return rc; 406 return rc;
371} 407}
372 408
@@ -624,35 +660,61 @@ static int decrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,
624 struct scatterlist *src_sg, int size, 660 struct scatterlist *src_sg, int size,
625 unsigned char *iv) 661 unsigned char *iv)
626{ 662{
627 struct blkcipher_desc desc = { 663 struct ablkcipher_request *req = NULL;
628 .tfm = crypt_stat->tfm, 664 struct extent_crypt_result ecr;
629 .info = iv,
630 .flags = CRYPTO_TFM_REQ_MAY_SLEEP
631 };
632 int rc = 0; 665 int rc = 0;
633 666
634 /* Consider doing this once, when the file is opened */ 667 BUG_ON(!crypt_stat || !crypt_stat->tfm
668 || !(crypt_stat->flags & ECRYPTFS_STRUCT_INITIALIZED));
669 if (unlikely(ecryptfs_verbosity > 0)) {
670 ecryptfs_printk(KERN_DEBUG, "Key size [%zd]; key:\n",
671 crypt_stat->key_size);
672 ecryptfs_dump_hex(crypt_stat->key,
673 crypt_stat->key_size);
674 }
675
676 init_completion(&ecr.completion);
677
635 mutex_lock(&crypt_stat->cs_tfm_mutex); 678 mutex_lock(&crypt_stat->cs_tfm_mutex);
636 rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key, 679 req = ablkcipher_request_alloc(crypt_stat->tfm, GFP_NOFS);
637 crypt_stat->key_size); 680 if (!req) {
638 if (rc) {
639 ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n",
640 rc);
641 mutex_unlock(&crypt_stat->cs_tfm_mutex); 681 mutex_unlock(&crypt_stat->cs_tfm_mutex);
642 rc = -EINVAL; 682 rc = -ENOMEM;
643 goto out; 683 goto out;
644 } 684 }
645 ecryptfs_printk(KERN_DEBUG, "Decrypting [%d] bytes.\n", size); 685
646 rc = crypto_blkcipher_decrypt_iv(&desc, dest_sg, src_sg, size); 686 ablkcipher_request_set_callback(req,
687 CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
688 extent_crypt_complete, &ecr);
689 /* Consider doing this once, when the file is opened */
690 if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) {
691 rc = crypto_ablkcipher_setkey(crypt_stat->tfm, crypt_stat->key,
692 crypt_stat->key_size);
693 if (rc) {
694 ecryptfs_printk(KERN_ERR,
695 "Error setting key; rc = [%d]\n",
696 rc);
697 mutex_unlock(&crypt_stat->cs_tfm_mutex);
698 rc = -EINVAL;
699 goto out;
700 }
701 crypt_stat->flags |= ECRYPTFS_KEY_SET;
702 }
647 mutex_unlock(&crypt_stat->cs_tfm_mutex); 703 mutex_unlock(&crypt_stat->cs_tfm_mutex);
648 if (rc) { 704 ecryptfs_printk(KERN_DEBUG, "Decrypting [%d] bytes.\n", size);
649 ecryptfs_printk(KERN_ERR, "Error decrypting; rc = [%d]\n", 705 ablkcipher_request_set_crypt(req, src_sg, dest_sg, size, iv);
650 rc); 706 rc = crypto_ablkcipher_decrypt(req);
651 goto out; 707 if (rc == -EINPROGRESS || rc == -EBUSY) {
708 struct extent_crypt_result *ecr = req->base.data;
709
710 wait_for_completion(&ecr->completion);
711 rc = ecr->rc;
712 INIT_COMPLETION(ecr->completion);
652 } 713 }
653 rc = size;
654out: 714out:
715 ablkcipher_request_free(req);
655 return rc; 716 return rc;
717
656} 718}
657 719
658/** 720/**
@@ -746,8 +808,7 @@ int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat)
746 crypt_stat->cipher, "cbc"); 808 crypt_stat->cipher, "cbc");
747 if (rc) 809 if (rc)
748 goto out_unlock; 810 goto out_unlock;
749 crypt_stat->tfm = crypto_alloc_blkcipher(full_alg_name, 0, 811 crypt_stat->tfm = crypto_alloc_ablkcipher(full_alg_name, 0, 0);
750 CRYPTO_ALG_ASYNC);
751 kfree(full_alg_name); 812 kfree(full_alg_name);
752 if (IS_ERR(crypt_stat->tfm)) { 813 if (IS_ERR(crypt_stat->tfm)) {
753 rc = PTR_ERR(crypt_stat->tfm); 814 rc = PTR_ERR(crypt_stat->tfm);
@@ -757,7 +818,7 @@ int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat)
757 crypt_stat->cipher); 818 crypt_stat->cipher);
758 goto out_unlock; 819 goto out_unlock;
759 } 820 }
760 crypto_blkcipher_set_flags(crypt_stat->tfm, CRYPTO_TFM_REQ_WEAK_KEY); 821 crypto_ablkcipher_set_flags(crypt_stat->tfm, CRYPTO_TFM_REQ_WEAK_KEY);
761 rc = 0; 822 rc = 0;
762out_unlock: 823out_unlock:
763 mutex_unlock(&crypt_stat->cs_tfm_mutex); 824 mutex_unlock(&crypt_stat->cs_tfm_mutex);
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index dd299b389d4e..f622a733f7ad 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -38,6 +38,7 @@
38#include <linux/nsproxy.h> 38#include <linux/nsproxy.h>
39#include <linux/backing-dev.h> 39#include <linux/backing-dev.h>
40#include <linux/ecryptfs.h> 40#include <linux/ecryptfs.h>
41#include <linux/crypto.h>
41 42
42#define ECRYPTFS_DEFAULT_IV_BYTES 16 43#define ECRYPTFS_DEFAULT_IV_BYTES 16
43#define ECRYPTFS_DEFAULT_EXTENT_SIZE 4096 44#define ECRYPTFS_DEFAULT_EXTENT_SIZE 4096
@@ -233,7 +234,7 @@ struct ecryptfs_crypt_stat {
233 size_t extent_shift; 234 size_t extent_shift;
234 unsigned int extent_mask; 235 unsigned int extent_mask;
235 struct ecryptfs_mount_crypt_stat *mount_crypt_stat; 236 struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
236 struct crypto_blkcipher *tfm; 237 struct crypto_ablkcipher *tfm;
237 struct crypto_hash *hash_tfm; /* Crypto context for generating 238 struct crypto_hash *hash_tfm; /* Crypto context for generating
238 * the initialization vectors */ 239 * the initialization vectors */
239 unsigned char cipher[ECRYPTFS_MAX_CIPHER_NAME_SIZE]; 240 unsigned char cipher[ECRYPTFS_MAX_CIPHER_NAME_SIZE];