mirror of
https://github.com/tbsdtv/linux_media.git
synced 2025-07-23 12:43:29 +02:00
crypto: api - Fix built-in testing dependency failures
When complex algorithms that depend on other algorithms are built into the kernel, the order of registration must be done such that the underlying algorithms are ready before the ones on top are registered. As otherwise they would fail during the self-test which is required during registration. In the past we have used subsystem initialisation ordering to guarantee this. The number of such precedence levels are limited and they may cause ripple effects in other subsystems. This patch solves this problem by delaying all self-tests during boot-up for built-in algorithms. They will be tested either when something else in the kernel requests for them, or when we have finished registering all built-in algorithms, whichever comes earlier. Reported-by: Vladis Dronov <vdronov@redhat.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
This commit is contained in:
52
crypto/api.c
52
crypto/api.c
@@ -12,6 +12,7 @@
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/jump_label.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kmod.h>
|
||||
#include <linux/module.h>
|
||||
@@ -30,6 +31,8 @@ EXPORT_SYMBOL_GPL(crypto_alg_sem);
|
||||
BLOCKING_NOTIFIER_HEAD(crypto_chain);
|
||||
EXPORT_SYMBOL_GPL(crypto_chain);
|
||||
|
||||
DEFINE_STATIC_KEY_FALSE(crypto_boot_test_finished);
|
||||
|
||||
static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg);
|
||||
|
||||
struct crypto_alg *crypto_mod_get(struct crypto_alg *alg)
|
||||
@@ -47,11 +50,6 @@ void crypto_mod_put(struct crypto_alg *alg)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_mod_put);
|
||||
|
||||
static inline int crypto_is_test_larval(struct crypto_larval *larval)
|
||||
{
|
||||
return larval->alg.cra_driver_name[0];
|
||||
}
|
||||
|
||||
static struct crypto_alg *__crypto_alg_lookup(const char *name, u32 type,
|
||||
u32 mask)
|
||||
{
|
||||
@@ -163,11 +161,55 @@ void crypto_larval_kill(struct crypto_alg *alg)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_larval_kill);
|
||||
|
||||
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_killable(&larval->completion);
|
||||
WARN_ON(err);
|
||||
if (!err)
|
||||
crypto_notify(CRYPTO_MSG_ALG_LOADED, larval);
|
||||
|
||||
out:
|
||||
crypto_larval_kill(&larval->alg);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_wait_for_test);
|
||||
|
||||
static void crypto_start_test(struct crypto_larval *larval)
|
||||
{
|
||||
if (!crypto_is_test_larval(larval))
|
||||
return;
|
||||
|
||||
if (larval->test_started)
|
||||
return;
|
||||
|
||||
down_write(&crypto_alg_sem);
|
||||
if (larval->test_started) {
|
||||
up_write(&crypto_alg_sem);
|
||||
return;
|
||||
}
|
||||
|
||||
larval->test_started = true;
|
||||
up_write(&crypto_alg_sem);
|
||||
|
||||
crypto_wait_for_test(larval);
|
||||
}
|
||||
|
||||
static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg)
|
||||
{
|
||||
struct crypto_larval *larval = (void *)alg;
|
||||
long timeout;
|
||||
|
||||
if (!static_branch_likely(&crypto_boot_test_finished))
|
||||
crypto_start_test(larval);
|
||||
|
||||
timeout = wait_for_completion_killable_timeout(
|
||||
&larval->completion, 60 * HZ);
|
||||
|
||||
|
Reference in New Issue
Block a user