Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f6bccf69 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6:
  crypto: skcipher - Use RNG interface instead of get_random_bytes
  crypto: rng - RNG interface and implementation
  crypto: api - Add fips_enable flag
  crypto: skcipher - Move IV generators into their own modules
  crypto: cryptomgr - Test ciphers using ECB
  crypto: api - Use test infrastructure
  crypto: cryptomgr - Add test infrastructure
  crypto: tcrypt - Add alg_test interface
  crypto: tcrypt - Abort and only log if there is an error
  crypto: crc32c - Use Intel CRC32 instruction
  crypto: tcrypt - Avoid using contiguous pages
  crypto: api - Display larval objects properly
  crypto: api - Export crypto_alg_lookup instead of __crypto_alg_lookup
  crypto: Kconfig - Replace leading spaces with tabs
parents 3af73d39 a0f000ec
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -10,6 +10,8 @@ obj-$(CONFIG_CRYPTO_AES_X86_64) += aes-x86_64.o
obj-$(CONFIG_CRYPTO_TWOFISH_X86_64) += twofish-x86_64.o
obj-$(CONFIG_CRYPTO_TWOFISH_X86_64) += twofish-x86_64.o
obj-$(CONFIG_CRYPTO_SALSA20_X86_64) += salsa20-x86_64.o
obj-$(CONFIG_CRYPTO_SALSA20_X86_64) += salsa20-x86_64.o


obj-$(CONFIG_CRYPTO_CRC32C_INTEL) += crc32c-intel.o

aes-i586-y := aes-i586-asm_32.o aes_glue.o
aes-i586-y := aes-i586-asm_32.o aes_glue.o
twofish-i586-y := twofish-i586-asm_32.o twofish_glue.o
twofish-i586-y := twofish-i586-asm_32.o twofish_glue.o
salsa20-i586-y := salsa20-i586-asm_32.o salsa20_glue.o
salsa20-i586-y := salsa20-i586-asm_32.o salsa20_glue.o
+197 −0
Original line number Original line Diff line number Diff line
/*
 * Using hardware provided CRC32 instruction to accelerate the CRC32 disposal.
 * CRC32C polynomial:0x1EDC6F41(BE)/0x82F63B78(LE)
 * CRC32 is a new instruction in Intel SSE4.2, the reference can be found at:
 * http://www.intel.com/products/processor/manuals/
 * Intel(R) 64 and IA-32 Architectures Software Developer's Manual
 * Volume 2A: Instruction Set Reference, A-M
 *
 * Copyright (c) 2008 Austin Zhang <austin_zhang@linux.intel.com>
 * Copyright (c) 2008 Kent Liu <kent.liu@intel.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <crypto/internal/hash.h>

#include <asm/cpufeature.h>

#define CHKSUM_BLOCK_SIZE	1
#define CHKSUM_DIGEST_SIZE	4

#define SCALE_F	sizeof(unsigned long)

#ifdef CONFIG_X86_64
#define REX_PRE "0x48, "
#else
#define REX_PRE
#endif

static u32 crc32c_intel_le_hw_byte(u32 crc, unsigned char const *data, size_t length)
{
	while (length--) {
		__asm__ __volatile__(
			".byte 0xf2, 0xf, 0x38, 0xf0, 0xf1"
			:"=S"(crc)
			:"0"(crc), "c"(*data)
		);
		data++;
	}

	return crc;
}

static u32 __pure crc32c_intel_le_hw(u32 crc, unsigned char const *p, size_t len)
{
	unsigned int iquotient = len / SCALE_F;
	unsigned int iremainder = len % SCALE_F;
	unsigned long *ptmp = (unsigned long *)p;

	while (iquotient--) {
		__asm__ __volatile__(
			".byte 0xf2, " REX_PRE "0xf, 0x38, 0xf1, 0xf1;"
			:"=S"(crc)
			:"0"(crc), "c"(*ptmp)
		);
		ptmp++;
	}

	if (iremainder)
		crc = crc32c_intel_le_hw_byte(crc, (unsigned char *)ptmp,
				 iremainder);

	return crc;
}

/*
 * Setting the seed allows arbitrary accumulators and flexible XOR policy
 * If your algorithm starts with ~0, then XOR with ~0 before you set
 * the seed.
 */
static int crc32c_intel_setkey(struct crypto_ahash *hash, const u8 *key,
			unsigned int keylen)
{
	u32 *mctx = crypto_ahash_ctx(hash);

	if (keylen != sizeof(u32)) {
		crypto_ahash_set_flags(hash, CRYPTO_TFM_RES_BAD_KEY_LEN);
		return -EINVAL;
	}
	*mctx = le32_to_cpup((__le32 *)key);
	return 0;
}

static int crc32c_intel_init(struct ahash_request *req)
{
	u32 *mctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req));
	u32 *crcp = ahash_request_ctx(req);

	*crcp = *mctx;

	return 0;
}

static int crc32c_intel_update(struct ahash_request *req)
{
	struct crypto_hash_walk walk;
	u32 *crcp = ahash_request_ctx(req);
	u32 crc = *crcp;
	int nbytes;

	for (nbytes = crypto_hash_walk_first(req, &walk); nbytes;
	   nbytes = crypto_hash_walk_done(&walk, 0))
	crc = crc32c_intel_le_hw(crc, walk.data, nbytes);

	*crcp = crc;
	return 0;
}

static int crc32c_intel_final(struct ahash_request *req)
{
	u32 *crcp = ahash_request_ctx(req);

	*(__le32 *)req->result = ~cpu_to_le32p(crcp);
	return 0;
}

static int crc32c_intel_digest(struct ahash_request *req)
{
	struct crypto_hash_walk walk;
	u32 *mctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req));
	u32 crc = *mctx;
	int nbytes;

	for (nbytes = crypto_hash_walk_first(req, &walk); nbytes;
	   nbytes = crypto_hash_walk_done(&walk, 0))
		crc = crc32c_intel_le_hw(crc, walk.data, nbytes);

	*(__le32 *)req->result = ~cpu_to_le32(crc);
	return 0;
}

static int crc32c_intel_cra_init(struct crypto_tfm *tfm)
{
	u32 *key = crypto_tfm_ctx(tfm);

	*key = ~0;

	tfm->crt_ahash.reqsize = sizeof(u32);

	return 0;
}

static struct crypto_alg alg = {
	.cra_name               =       "crc32c",
	.cra_driver_name        =       "crc32c-intel",
	.cra_priority           =       200,
	.cra_flags              =       CRYPTO_ALG_TYPE_AHASH,
	.cra_blocksize          =       CHKSUM_BLOCK_SIZE,
	.cra_alignmask          =       3,
	.cra_ctxsize            =       sizeof(u32),
	.cra_module             =       THIS_MODULE,
	.cra_list               =       LIST_HEAD_INIT(alg.cra_list),
	.cra_init               =       crc32c_intel_cra_init,
	.cra_type               =       &crypto_ahash_type,
	.cra_u                  =       {
		.ahash = {
			.digestsize    =       CHKSUM_DIGEST_SIZE,
			.setkey        =       crc32c_intel_setkey,
			.init          =       crc32c_intel_init,
			.update        =       crc32c_intel_update,
			.final         =       crc32c_intel_final,
			.digest        =       crc32c_intel_digest,
		}
	}
};


static int __init crc32c_intel_mod_init(void)
{
	if (cpu_has_xmm4_2)
		return crypto_register_alg(&alg);
	else
		return -ENODEV;
}

static void __exit crc32c_intel_mod_fini(void)
{
	crypto_unregister_alg(&alg);
}

module_init(crc32c_intel_mod_init);
module_exit(crc32c_intel_mod_fini);

MODULE_AUTHOR("Austin Zhang <austin.zhang@intel.com>, Kent Liu <kent.liu@intel.com>");
MODULE_DESCRIPTION("CRC32c (Castagnoli) optimization using Intel Hardware.");
MODULE_LICENSE("GPL");

MODULE_ALIAS("crc32c");
MODULE_ALIAS("crc32c-intel");
+84 −43
Original line number Original line Diff line number Diff line
@@ -21,6 +21,14 @@ if CRYPTO


comment "Crypto core or helper"
comment "Crypto core or helper"


config CRYPTO_FIPS
	bool "FIPS 200 compliance"
	help
	  This options enables the fips boot option which is
	  required if you want to system to operate in a FIPS 200
	  certification.  You should say no unless you know what
	  this is.

config CRYPTO_ALGAPI
config CRYPTO_ALGAPI
	tristate
	tristate
	help
	help
@@ -33,14 +41,21 @@ config CRYPTO_AEAD
config CRYPTO_BLKCIPHER
config CRYPTO_BLKCIPHER
	tristate
	tristate
	select CRYPTO_ALGAPI
	select CRYPTO_ALGAPI
	select CRYPTO_RNG


config CRYPTO_HASH
config CRYPTO_HASH
	tristate
	tristate
	select CRYPTO_ALGAPI
	select CRYPTO_ALGAPI


config CRYPTO_RNG
	tristate
	select CRYPTO_ALGAPI

config CRYPTO_MANAGER
config CRYPTO_MANAGER
	tristate "Cryptographic algorithm manager"
	tristate "Cryptographic algorithm manager"
	select CRYPTO_ALGAPI
	select CRYPTO_AEAD
	select CRYPTO_HASH
	select CRYPTO_BLKCIPHER
	help
	help
	  Create default cryptographic template instantiations such as
	  Create default cryptographic template instantiations such as
	  cbc(aes).
	  cbc(aes).
@@ -85,9 +100,7 @@ config CRYPTO_AUTHENC
config CRYPTO_TEST
config CRYPTO_TEST
	tristate "Testing module"
	tristate "Testing module"
	depends on m
	depends on m
	select CRYPTO_ALGAPI
	select CRYPTO_MANAGER
	select CRYPTO_AEAD
	select CRYPTO_BLKCIPHER
	help
	help
	  Quick & dirty crypto test module.
	  Quick & dirty crypto test module.


@@ -113,6 +126,7 @@ config CRYPTO_SEQIV
	tristate "Sequence Number IV Generator"
	tristate "Sequence Number IV Generator"
	select CRYPTO_AEAD
	select CRYPTO_AEAD
	select CRYPTO_BLKCIPHER
	select CRYPTO_BLKCIPHER
	select CRYPTO_RNG
	help
	help
	  This IV generator generates an IV based on a sequence number by
	  This IV generator generates an IV based on a sequence number by
	  xoring it with a salt.  This algorithm is mainly useful for CTR
	  xoring it with a salt.  This algorithm is mainly useful for CTR
@@ -221,6 +235,18 @@ config CRYPTO_CRC32C
	  See Castagnoli93.  This implementation uses lib/libcrc32c.
	  See Castagnoli93.  This implementation uses lib/libcrc32c.
	  Module will be crc32c.
	  Module will be crc32c.


config CRYPTO_CRC32C_INTEL
	tristate "CRC32c INTEL hardware acceleration"
	depends on X86
	select CRYPTO_HASH
	help
	  In Intel processor with SSE4.2 supported, the processor will
	  support CRC32C implementation using hardware accelerated CRC32
	  instruction. This option will create 'crc32c-intel' module,
	  which will enable any routine to use the CRC32 instruction to
	  gain performance compared with software implementation.
	  Module will be crc32c-intel.

config CRYPTO_MD4
config CRYPTO_MD4
	tristate "MD4 digest algorithm"
	tristate "MD4 digest algorithm"
	select CRYPTO_ALGAPI
	select CRYPTO_ALGAPI
@@ -263,10 +289,11 @@ config CRYPTO_RMD160


	  RIPEMD-160 is a 160-bit cryptographic hash function. It is intended
	  RIPEMD-160 is a 160-bit cryptographic hash function. It is intended
	  to be used as a secure replacement for the 128-bit hash functions
	  to be used as a secure replacement for the 128-bit hash functions
    MD4, MD5 and it's predecessor RIPEMD (not to be confused with RIPEMD-128).
	  MD4, MD5 and it's predecessor RIPEMD
	  (not to be confused with RIPEMD-128).


    It's speed is comparable to SHA1 and there are no known attacks against
	  It's speed is comparable to SHA1 and there are no known attacks
    RIPEMD-160.
	  against RIPEMD-160.


	  Developed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel.
	  Developed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel.
	  See <http://home.esat.kuleuven.be/~bosselae/ripemd160.html>
	  See <http://home.esat.kuleuven.be/~bosselae/ripemd160.html>
@@ -275,9 +302,10 @@ config CRYPTO_RMD256
	tristate "RIPEMD-256 digest algorithm"
	tristate "RIPEMD-256 digest algorithm"
	select CRYPTO_ALGAPI
	select CRYPTO_ALGAPI
	help
	help
    RIPEMD-256 is an optional extension of RIPEMD-128 with a 256 bit hash.
	  RIPEMD-256 is an optional extension of RIPEMD-128 with a
    It is intended for applications that require longer hash-results, without
	  256 bit hash. It is intended for applications that require
    needing a larger security level (than RIPEMD-128).
	  longer hash-results, without needing a larger security level
	  (than RIPEMD-128).


	  Developed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel.
	  Developed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel.
	  See <http://home.esat.kuleuven.be/~bosselae/ripemd160.html>
	  See <http://home.esat.kuleuven.be/~bosselae/ripemd160.html>
@@ -286,9 +314,10 @@ config CRYPTO_RMD320
	tristate "RIPEMD-320 digest algorithm"
	tristate "RIPEMD-320 digest algorithm"
	select CRYPTO_ALGAPI
	select CRYPTO_ALGAPI
	help
	help
    RIPEMD-320 is an optional extension of RIPEMD-160 with a 320 bit hash.
	  RIPEMD-320 is an optional extension of RIPEMD-160 with a
    It is intended for applications that require longer hash-results, without
	  320 bit hash. It is intended for applications that require
    needing a larger security level (than RIPEMD-160).
	  longer hash-results, without needing a larger security level
	  (than RIPEMD-160).


	  Developed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel.
	  Developed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel.
	  See <http://home.esat.kuleuven.be/~bosselae/ripemd160.html>
	  See <http://home.esat.kuleuven.be/~bosselae/ripemd160.html>
@@ -666,6 +695,18 @@ config CRYPTO_LZO
	help
	help
	  This is the LZO algorithm.
	  This is the LZO algorithm.


comment "Random Number Generation"

config CRYPTO_ANSI_CPRNG
	tristate "Pseudo Random Number Generation for Cryptographic modules"
	select CRYPTO_AES
	select CRYPTO_RNG
	select CRYPTO_FIPS
	help
	  This option enables the generic pseudo random number generator
	  for cryptographic modules.  Uses the Algorithm specified in
	  ANSI X9.31 A.2.4

source "drivers/crypto/Kconfig"
source "drivers/crypto/Kconfig"


endif	# if CRYPTO
endif	# if CRYPTO
+9 −3
Original line number Original line Diff line number Diff line
@@ -5,6 +5,8 @@
obj-$(CONFIG_CRYPTO) += crypto.o
obj-$(CONFIG_CRYPTO) += crypto.o
crypto-objs := api.o cipher.o digest.o compress.o
crypto-objs := api.o cipher.o digest.o compress.o


obj-$(CONFIG_CRYPTO_FIPS) += fips.o

crypto_algapi-$(CONFIG_PROC_FS) += proc.o
crypto_algapi-$(CONFIG_PROC_FS) += proc.o
crypto_algapi-objs := algapi.o scatterwalk.o $(crypto_algapi-y)
crypto_algapi-objs := algapi.o scatterwalk.o $(crypto_algapi-y)
obj-$(CONFIG_CRYPTO_ALGAPI) += crypto_algapi.o
obj-$(CONFIG_CRYPTO_ALGAPI) += crypto_algapi.o
@@ -13,15 +15,17 @@ obj-$(CONFIG_CRYPTO_AEAD) += aead.o


crypto_blkcipher-objs := ablkcipher.o
crypto_blkcipher-objs := ablkcipher.o
crypto_blkcipher-objs += blkcipher.o
crypto_blkcipher-objs += blkcipher.o
crypto_blkcipher-objs += chainiv.o
crypto_blkcipher-objs += eseqiv.o
obj-$(CONFIG_CRYPTO_BLKCIPHER) += crypto_blkcipher.o
obj-$(CONFIG_CRYPTO_BLKCIPHER) += crypto_blkcipher.o
obj-$(CONFIG_CRYPTO_BLKCIPHER) += chainiv.o
obj-$(CONFIG_CRYPTO_BLKCIPHER) += eseqiv.o
obj-$(CONFIG_CRYPTO_SEQIV) += seqiv.o
obj-$(CONFIG_CRYPTO_SEQIV) += seqiv.o


crypto_hash-objs := hash.o
crypto_hash-objs := hash.o
crypto_hash-objs += ahash.o
crypto_hash-objs += ahash.o
obj-$(CONFIG_CRYPTO_HASH) += crypto_hash.o
obj-$(CONFIG_CRYPTO_HASH) += crypto_hash.o


cryptomgr-objs := algboss.o testmgr.o

obj-$(CONFIG_CRYPTO_MANAGER) += cryptomgr.o
obj-$(CONFIG_CRYPTO_MANAGER) += cryptomgr.o
obj-$(CONFIG_CRYPTO_HMAC) += hmac.o
obj-$(CONFIG_CRYPTO_HMAC) += hmac.o
obj-$(CONFIG_CRYPTO_XCBC) += xcbc.o
obj-$(CONFIG_CRYPTO_XCBC) += xcbc.o
@@ -69,7 +73,9 @@ obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o
obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o
obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o
obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o
obj-$(CONFIG_CRYPTO_LZO) += lzo.o
obj-$(CONFIG_CRYPTO_LZO) += lzo.o

obj-$(CONFIG_CRYPTO_RNG) += rng.o
obj-$(CONFIG_CRYPTO_RNG) += krng.o
obj-$(CONFIG_CRYPTO_ANSI_CPRNG) += ansi_cprng.o
obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o
obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o


#
#
+124 −23
Original line number Original line Diff line number Diff line
@@ -21,15 +21,15 @@


#include "internal.h"
#include "internal.h"


static void crypto_remove_final(struct list_head *list);

static LIST_HEAD(crypto_template_list);
static LIST_HEAD(crypto_template_list);


void crypto_larval_error(const char *name, u32 type, u32 mask)
void crypto_larval_error(const char *name, u32 type, u32 mask)
{
{
	struct crypto_alg *alg;
	struct crypto_alg *alg;


	down_read(&crypto_alg_sem);
	alg = crypto_alg_lookup(name, type, mask);
	alg = __crypto_alg_lookup(name, type, mask);
	up_read(&crypto_alg_sem);


	if (alg) {
	if (alg) {
		if (crypto_is_larval(alg)) {
		if (crypto_is_larval(alg)) {
@@ -128,24 +128,98 @@ static void crypto_remove_spawns(struct list_head *spawns,
	}
	}
}
}


static int __crypto_register_alg(struct crypto_alg *alg,
static struct crypto_larval *__crypto_register_alg(struct crypto_alg *alg)
				 struct list_head *list)
{
{
	struct crypto_alg *q;
	struct crypto_alg *q;
	struct crypto_larval *larval;
	int ret = -EAGAIN;
	int ret = -EAGAIN;


	if (crypto_is_dead(alg))
	if (crypto_is_dead(alg))
		goto out;
		goto err;


	INIT_LIST_HEAD(&alg->cra_users);
	INIT_LIST_HEAD(&alg->cra_users);


	/* No cheating! */
	alg->cra_flags &= ~CRYPTO_ALG_TESTED;

	ret = -EEXIST;
	ret = -EEXIST;


	atomic_set(&alg->cra_refcnt, 1);
	atomic_set(&alg->cra_refcnt, 1);
	list_for_each_entry(q, &crypto_alg_list, cra_list) {
	list_for_each_entry(q, &crypto_alg_list, cra_list) {
		if (q == alg)
		if (q == alg)
			goto err;

		if (crypto_is_larval(q)) {
			if (!strcmp(alg->cra_driver_name, q->cra_driver_name))
				goto err;
			continue;
		}

		if (!strcmp(q->cra_driver_name, alg->cra_name) ||
		    !strcmp(q->cra_name, alg->cra_driver_name))
			goto err;
	}

	larval = crypto_larval_alloc(alg->cra_name,
				     alg->cra_flags | CRYPTO_ALG_TESTED, 0);
	if (IS_ERR(larval))
		goto out;
		goto out;


	ret = -ENOENT;
	larval->adult = crypto_mod_get(alg);
	if (!larval->adult)
		goto free_larval;

	atomic_set(&larval->alg.cra_refcnt, 1);
	memcpy(larval->alg.cra_driver_name, alg->cra_driver_name,
	       CRYPTO_MAX_ALG_NAME);
	larval->alg.cra_priority = alg->cra_priority;

	list_add(&alg->cra_list, &crypto_alg_list);
	list_add(&larval->alg.cra_list, &crypto_alg_list);

out:	
	return larval;

free_larval:
	kfree(larval);
err:
	larval = ERR_PTR(ret);
	goto out;
}

void crypto_alg_tested(const char *name, int err)
{
	struct crypto_larval *test;
	struct crypto_alg *alg;
	struct crypto_alg *q;
	LIST_HEAD(list);

	down_write(&crypto_alg_sem);
	list_for_each_entry(q, &crypto_alg_list, cra_list) {
		if (!crypto_is_larval(q))
			continue;

		test = (struct crypto_larval *)q;

		if (!strcmp(q->cra_driver_name, name))
			goto found;
	}

	printk(KERN_ERR "alg: Unexpected test result for %s: %d\n", name, err);
	goto unlock;

found:
	alg = test->adult;
	if (err || list_empty(&alg->cra_list))
		goto complete;

	alg->cra_flags |= CRYPTO_ALG_TESTED;

	list_for_each_entry(q, &crypto_alg_list, cra_list) {
		if (q == alg)
			continue;

		if (crypto_is_moribund(q))
		if (crypto_is_moribund(q))
			continue;
			continue;


@@ -180,17 +254,18 @@ static int __crypto_register_alg(struct crypto_alg *alg,
		    q->cra_priority > alg->cra_priority)
		    q->cra_priority > alg->cra_priority)
			continue;
			continue;


		crypto_remove_spawns(&q->cra_users, list, alg->cra_flags);
		crypto_remove_spawns(&q->cra_users, &list, alg->cra_flags);
	}
	}


	list_add(&alg->cra_list, &crypto_alg_list);
complete:
	complete_all(&test->completion);


	crypto_notify(CRYPTO_MSG_ALG_REGISTER, alg);
unlock:
	ret = 0;
	up_write(&crypto_alg_sem);


out:	
	crypto_remove_final(&list);
	return ret;
}
}
EXPORT_SYMBOL_GPL(crypto_alg_tested);


static void crypto_remove_final(struct list_head *list)
static void crypto_remove_final(struct list_head *list)
{
{
@@ -203,9 +278,27 @@ static void crypto_remove_final(struct list_head *list)
	}
	}
}
}


static void crypto_wait_for_test(struct crypto_larval *larval)
{
	int err;

	err = crypto_probing_notify(CRYPTO_MSG_ALG_REGISTER, larval->adult);
	if (err != NOTIFY_STOP) {
		if (WARN_ON(err != NOTIFY_DONE))
			goto out;
		crypto_alg_tested(larval->alg.cra_driver_name, 0);
	}

	err = wait_for_completion_interruptible(&larval->completion);
	WARN_ON(err);

out:
	crypto_larval_kill(&larval->alg);
}

int crypto_register_alg(struct crypto_alg *alg)
int crypto_register_alg(struct crypto_alg *alg)
{
{
	LIST_HEAD(list);
	struct crypto_larval *larval;
	int err;
	int err;


	err = crypto_check_alg(alg);
	err = crypto_check_alg(alg);
@@ -213,11 +306,14 @@ int crypto_register_alg(struct crypto_alg *alg)
		return err;
		return err;


	down_write(&crypto_alg_sem);
	down_write(&crypto_alg_sem);
	err = __crypto_register_alg(alg, &list);
	larval = __crypto_register_alg(alg);
	up_write(&crypto_alg_sem);
	up_write(&crypto_alg_sem);


	crypto_remove_final(&list);
	if (IS_ERR(larval))
	return err;
		return PTR_ERR(larval);

	crypto_wait_for_test(larval);
	return 0;
}
}
EXPORT_SYMBOL_GPL(crypto_register_alg);
EXPORT_SYMBOL_GPL(crypto_register_alg);


@@ -335,8 +431,8 @@ EXPORT_SYMBOL_GPL(crypto_lookup_template);
int crypto_register_instance(struct crypto_template *tmpl,
int crypto_register_instance(struct crypto_template *tmpl,
			     struct crypto_instance *inst)
			     struct crypto_instance *inst)
{
{
	LIST_HEAD(list);
	struct crypto_larval *larval;
	int err = -EINVAL;
	int err;


	err = crypto_check_alg(&inst->alg);
	err = crypto_check_alg(&inst->alg);
	if (err)
	if (err)
@@ -346,8 +442,8 @@ int crypto_register_instance(struct crypto_template *tmpl,


	down_write(&crypto_alg_sem);
	down_write(&crypto_alg_sem);


	err = __crypto_register_alg(&inst->alg, &list);
	larval = __crypto_register_alg(&inst->alg);
	if (err)
	if (IS_ERR(larval))
		goto unlock;
		goto unlock;


	hlist_add_head(&inst->list, &tmpl->instances);
	hlist_add_head(&inst->list, &tmpl->instances);
@@ -356,7 +452,12 @@ int crypto_register_instance(struct crypto_template *tmpl,
unlock:
unlock:
	up_write(&crypto_alg_sem);
	up_write(&crypto_alg_sem);


	crypto_remove_final(&list);
	err = PTR_ERR(larval);
	if (IS_ERR(larval))
		goto err;

	crypto_wait_for_test(larval);
	err = 0;


err:
err:
	return err;
	return err;
Loading