Skip to content

Commit

Permalink
Merge tag 'ecryptfs-3.10-rc1-ablkcipher' of git://git.kernel.org/pub/…
Browse files Browse the repository at this point in the history
…scm/linux/kernel/git/tyhicks/ecryptfs

Pull eCryptfs update from Tyler Hicks:
 "Improve performance when AES-NI (and most likely other crypto
  accelerators) is available by moving to the ablkcipher crypto API.
  The improvement is more apparent on faster storage devices.

  There's no noticeable change when hardware crypto is not available"

* tag 'ecryptfs-3.10-rc1-ablkcipher' of git://git.kernel.org/pub/scm/linux/kernel/git/tyhicks/ecryptfs:
  eCryptfs: Use the ablkcipher crypto API
  • Loading branch information
Linus Torvalds committed May 10, 2013
2 parents f741df1 + 4dfea4f commit 6fad8d0
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 41 deletions.
141 changes: 101 additions & 40 deletions fs/ecryptfs/crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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.
Expand All @@ -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
Expand All @@ -349,24 +362,47 @@ 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;

wait_for_completion(&ecr->completion);
rc = ecr->rc;
INIT_COMPLETION(ecr->completion);
}
out:
ablkcipher_request_free(req);
return rc;
}

Expand Down Expand Up @@ -624,35 +660,61 @@ 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;

wait_for_completion(&ecr->completion);
rc = ecr->rc;
INIT_COMPLETION(ecr->completion);
}
rc = size;
out:
ablkcipher_request_free(req);
return rc;

}

/**
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion fs/ecryptfs/ecryptfs_kernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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];
Expand Down

0 comments on commit 6fad8d0

Please sign in to comment.