> Patch attached.
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -85,6 +85,11 @@ struct crypt_config {
struct crypto_tfm *tfm;
unsigned int key_size;
u8 key[0];
+
+#if defined CONFIG_ACRYPTO || defined CONFIG_ACRYPTO_MODULE
+ wait_queue_head_t dm_async_queue;
+ int dm_async_pending;
+#endif
};
#define MIN_IOS 256
@@ -230,6 +235,186 @@ static struct crypt_iv_operations crypt_
.generator = crypt_iv_essiv_gen
};
+#if defined CONFIG_ACRYPTO || defined CONFIG_ACRYPTO_MODULE
+
+#include <linux/acrypto.h>
+#include <linux/crypto_def.h>
+
+struct dm_async_private
+{
+ void *sg;
+ struct crypt_config *cc;
+};
+
+static inline u16 crypto_tfm_get_type(struct crypto_tfm *tfm)
+{
+ u16 type;
+ char *name;
+
+ name = (char *)crypto_tfm_alg_name(tfm);
+
+ if (!strncmp(name, "aes", 3)) {
+ switch (crypto_tfm_alg_blocksize(tfm) << 3) {
+ case 128:
+ type = CRYPTO_TYPE_AES_128;
+ break;
+ case 192:
+ type = CRYPTO_TYPE_AES_192;
+ break;
+ case 256:
+ type = CRYPTO_TYPE_AES_256;
+ break;
+ default:
+ type = 0xffff;
+ break;
+ }
+ } else if (!strncmp(name, "des3_ede", 3))
+ type = CRYPTO_TYPE_3DES;
+ else
+ type = 0xffff;
+
+ return type;
+}
+
+static inline u16 crypto_tfm_get_mode(struct crypto_tfm *tfm)
+{
+ u16 mode = tfm->crt_cipher.cit_mode & CRYPTO_TFM_MODE_MASK;
+
+ switch (mode) {
+ case CRYPTO_TFM_MODE_ECB:
+ mode = CRYPTO_MODE_ECB;
+ break;
+ case CRYPTO_TFM_MODE_CBC:
+ mode = CRYPTO_MODE_CBC;
+ break;
+ case CRYPTO_TFM_MODE_CFB:
+ mode = CRYPTO_MODE_CFB;
+ break;
+ case CRYPTO_TFM_MODE_CTR:
+ mode = CRYPTO_MODE_CTR;
+ break;
+ default:
+ mode = 0xffff;
+ break;
+ }
+
+ return mode;
+}
+
+static void dm_callback(struct crypto_session_initializer *ci, struct
crypto_data *data)
+{
+ struct dm_async_private *priv = data->priv;
+
+ priv->cc->dm_async_pending--;
+ wake_up(&priv->cc->dm_async_queue);
+
+ kfree(priv->sg);
+}
+
+static inline int acrypto_process(struct crypt_config *cc, struct scatterlist
*out,
+ struct scatterlist *in, unsigned int len, u8 *iv, int iv_size,
int write)
+{
+ struct crypto_session *s;
+ struct crypto_session_initializer ci;
+ struct crypto_data data;
+ struct scatterlist *sg;
+ int sg_size, err = 0;
+ u8 *local_key;
+ struct dm_async_private *priv;
+
+ memset(&ci, 0, sizeof(ci));
+ memset(&data, 0, sizeof(data));
+
+ ci.operation = (write)?CRYPTO_OP_ENCRYPT:CRYPTO_OP_DECRYPT;
+ ci.priority = 0;
+ ci.callback = &dm_callback;
+ ci.type = crypto_tfm_get_type(cc->tfm);
+ ci.mode = crypto_tfm_get_mode(cc->tfm);
+
+ if (ci.type == 0xffff || ci.mode == 0xffff) {
+ err = -EINVAL;
+ goto err_out_exit;
+ }
+
+ data.sg_src_num = data.sg_dst_num = data.sg_key_num = 1;
+ data.sg_iv_num = (iv)?1:0;
+
+ sg_size = sizeof(*sg) * (data.sg_src_num +
+ data.sg_dst_num + data.sg_iv_num +
+ data.sg_key_num + iv_size + cc->key_size +
+ sizeof(struct dm_async_private));
+ priv = (struct dm_async_private *)kmalloc(sg_size, GFP_KERNEL);
+ if (!priv) {
+ err = -ENOMEM;
+ goto err_out_exit;
+ }
+
+ memset(priv, 0, sg_size);
+#if 0
+ printk("%s: key_size=%u, iv=%p, iv_size=%d, write=%d, priv=%p.\n",
+ __func__, cc->key_size, iv, iv_size, write, sg);
+#endif
+ data.priv = priv;
+ priv->cc = cc;
+ priv->sg = priv;
+
+ sg = (struct scatterlist *)(priv + 1);
+
+ data.sg_src = &sg[0];
+ data.sg_dst = &sg[1];
+
+ data.sg_src[0].page = in->page;
+ data.sg_src[0].offset = in->offset;
+ data.sg_src[0].length = in->length;
+
+ data.sg_dst[0].page = out->page;
+ data.sg_dst[0].offset = out->offset;
+ data.sg_dst[0].length = out->length;
+
+ data.sg_key = &sg[2];
+ local_key = (u8 *)&sg[3];
+
+ memcpy(local_key, cc->key, cc->key_size);
+
+ data.sg_key[0].page = virt_to_page(local_key);
+ data.sg_key[0].offset = offset_in_page(local_key);
+ data.sg_key[0].length = cc->key_size;
+
+ if (iv) {
+ u8 *local_iv;
+
+ data.sg_iv = (struct scatterlist *)(local_key + cc->key_size);
+ local_iv = (u8 *)(local_key + cc->key_size + sizeof(*sg));
+
+ data.sg_iv[0].page = virt_to_page(local_iv);
+ data.sg_iv[0].offset = offset_in_page(local_iv);
+ data.sg_iv[0].length = iv_size;
+
+ memcpy(local_iv, iv, iv_size);
+ }
+
+ s = crypto_session_alloc(&ci, &data);
+ if (!s) {
+ err = -ENOMEM;
+ goto err_out_free;
+ }
+
+ return 0;
+
+err_out_free:
+ kfree(sg);
+err_out_exit:
+ cc->dm_async_pending--;
+
+ return err;
+}
+#else
+static inline int acrypto_process(struct crypt_config *cc, struct scatterlist
*out,
+ struct scatterlist *in, unsigned int len, u8 *iv, int iv_size,
int write)
+{
+ return 0;
+}
+#endif
static inline int
crypt_convert_scatterlist(struct crypt_config *cc, struct scatterlist *out,
@@ -244,11 +429,19 @@ crypt_convert_scatterlist(struct crypt_c
if (r < 0)
return r;
+ r = acrypto_process(cc, out, in, length, iv, cc->iv_size,
write);
+ if (r == 0)
+ return r;
+
if (write)
r = crypto_cipher_encrypt_iv(cc->tfm, out, in, length,
iv);
else
r = crypto_cipher_decrypt_iv(cc->tfm, out, in, length,
iv);
} else {
+ r = acrypto_process(cc, out, in, length, NULL, 0, write);
+ if (r == 0)
+ return r;
+
if (write)
r = crypto_cipher_encrypt(cc->tfm, out, in, length);
else
@@ -281,6 +474,42 @@ static int crypt_convert(struct crypt_co
{
int r = 0;
+#if defined CONFIG_ACRYPTO || defined CONFIG_ACRYPTO_MODULE
+ {
+ unsigned int idx_in, idx_out, offset_in, offset_out;
+ int num = 0;
+
+ idx_in = ctx->idx_in;
+ idx_out = ctx->idx_out;
+ offset_in = ctx->offset_in;
+ offset_out = ctx->offset_out;
+
+ while(idx_in < ctx->bio_in->bi_vcnt &&
+ idx_out < ctx->bio_out->bi_vcnt) {
+
+ struct bio_vec *bv_in = bio_iovec_idx(ctx->bio_in,
idx_in);
+ struct bio_vec *bv_out = bio_iovec_idx(ctx->bio_out,
idx_out);
+
+ offset_in += 1 << SECTOR_SHIFT;
+ offset_out += 1 << SECTOR_SHIFT;
+
+ if (offset_in >= bv_in->bv_len) {
+ offset_in = 0;
+ idx_in++;
+ }
+
+ if (offset_out >= bv_out->bv_len) {
+ offset_out = 0;
+ idx_out++;
+ }
+
+ num++;
+ }
+
+ cc->dm_async_pending = num;
+ }
+#endif
+
while(ctx->idx_in < ctx->bio_in->bi_vcnt &&
ctx->idx_out < ctx->bio_out->bi_vcnt) {
struct bio_vec *bv_in = bio_iovec_idx(ctx->bio_in, ctx->idx_in);
@@ -316,6 +545,18 @@ static int crypt_convert(struct crypt_co
ctx->sector++;
}
+#if defined CONFIG_ACRYPTO || defined CONFIG_ACRYPTO_MODULE
+ {
+ long timeout = 1000;
+ long tm;
+
+ tm = wait_event_timeout(cc->dm_async_queue,
cc->dm_async_pending == 0, msecs_to_jiffies(timeout));
+ if (!tm)
+ printk("%s: bug: work was not finished in %ld msecs, %d
users remains.\n",
+ __func__, timeout,
cc->dm_async_pending);
+ }
+#endif
+
return r;
}
@@ -680,6 +921,11 @@ static int crypt_ctr(struct dm_target *t
} else
cc->iv_mode = NULL;
+#if defined CONFIG_ACRYPTO || defined CONFIG_ACRYPTO_MODULE
+ init_waitqueue_head(&cc->dm_async_queue);
+ cc->dm_async_pending = 0;
+#endif
+
ti->private = cc;
return 0;
--
Evgeniy Polyakov
-
To unsubscribe from this list: send the line "unsubscribe linux-crypto" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html