Merge tag 'libnvdimm-for-5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdim...
[linux-2.6-microblaze.git] / crypto / algapi.c
index 43f999d..d379fd9 100644 (file)
@@ -216,6 +216,32 @@ void crypto_remove_spawns(struct crypto_alg *alg, struct list_head *list,
 }
 EXPORT_SYMBOL_GPL(crypto_remove_spawns);
 
+static struct crypto_larval *crypto_alloc_test_larval(struct crypto_alg *alg)
+{
+       struct crypto_larval *larval;
+
+       if (!IS_ENABLED(CONFIG_CRYPTO_MANAGER))
+               return NULL;
+
+       larval = crypto_larval_alloc(alg->cra_name,
+                                    alg->cra_flags | CRYPTO_ALG_TESTED, 0);
+       if (IS_ERR(larval))
+               return larval;
+
+       larval->adult = crypto_mod_get(alg);
+       if (!larval->adult) {
+               kfree(larval);
+               return ERR_PTR(-ENOENT);
+       }
+
+       refcount_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;
+
+       return larval;
+}
+
 static struct crypto_larval *__crypto_register_alg(struct crypto_alg *alg)
 {
        struct crypto_alg *q;
@@ -250,31 +276,20 @@ static struct crypto_larval *__crypto_register_alg(struct crypto_alg *alg)
                        goto err;
        }
 
-       larval = crypto_larval_alloc(alg->cra_name,
-                                    alg->cra_flags | CRYPTO_ALG_TESTED, 0);
+       larval = crypto_alloc_test_larval(alg);
        if (IS_ERR(larval))
                goto out;
 
-       ret = -ENOENT;
-       larval->adult = crypto_mod_get(alg);
-       if (!larval->adult)
-               goto free_larval;
-
-       refcount_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);
+
+       if (larval)
+               list_add(&larval->alg.cra_list, &crypto_alg_list);
 
        crypto_stats_init(alg);
 
 out:
        return larval;
 
-free_larval:
-       kfree(larval);
 err:
        larval = ERR_PTR(ret);
        goto out;
@@ -389,29 +404,10 @@ void crypto_remove_final(struct list_head *list)
 }
 EXPORT_SYMBOL_GPL(crypto_remove_final);
 
-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_killable(&larval->completion);
-       WARN_ON(err);
-       if (!err)
-               crypto_notify(CRYPTO_MSG_ALG_LOADED, larval);
-
-out:
-       crypto_larval_kill(&larval->alg);
-}
-
 int crypto_register_alg(struct crypto_alg *alg)
 {
        struct crypto_larval *larval;
+       bool test_started;
        int err;
 
        alg->cra_flags &= ~CRYPTO_ALG_DEAD;
@@ -421,12 +417,16 @@ int crypto_register_alg(struct crypto_alg *alg)
 
        down_write(&crypto_alg_sem);
        larval = __crypto_register_alg(alg);
+       test_started = static_key_enabled(&crypto_boot_test_finished);
+       if (!IS_ERR_OR_NULL(larval))
+               larval->test_started = test_started;
        up_write(&crypto_alg_sem);
 
-       if (IS_ERR(larval))
+       if (IS_ERR_OR_NULL(larval))
                return PTR_ERR(larval);
 
-       crypto_wait_for_test(larval);
+       if (test_started)
+               crypto_wait_for_test(larval);
        return 0;
 }
 EXPORT_SYMBOL_GPL(crypto_register_alg);
@@ -632,6 +632,8 @@ int crypto_register_instance(struct crypto_template *tmpl,
        larval = __crypto_register_alg(&inst->alg);
        if (IS_ERR(larval))
                goto unlock;
+       else if (larval)
+               larval->test_started = true;
 
        hlist_add_head(&inst->list, &tmpl->instances);
        inst->tmpl = tmpl;
@@ -640,7 +642,7 @@ unlock:
        up_write(&crypto_alg_sem);
 
        err = PTR_ERR(larval);
-       if (IS_ERR(larval))
+       if (IS_ERR_OR_NULL(larval))
                goto err;
 
        crypto_wait_for_test(larval);
@@ -1261,9 +1263,48 @@ void crypto_stats_skcipher_decrypt(unsigned int cryptlen, int ret,
 EXPORT_SYMBOL_GPL(crypto_stats_skcipher_decrypt);
 #endif
 
+static void __init crypto_start_tests(void)
+{
+       for (;;) {
+               struct crypto_larval *larval = NULL;
+               struct crypto_alg *q;
+
+               down_write(&crypto_alg_sem);
+
+               list_for_each_entry(q, &crypto_alg_list, cra_list) {
+                       struct crypto_larval *l;
+
+                       if (!crypto_is_larval(q))
+                               continue;
+
+                       l = (void *)q;
+
+                       if (!crypto_is_test_larval(l))
+                               continue;
+
+                       if (l->test_started)
+                               continue;
+
+                       l->test_started = true;
+                       larval = l;
+                       break;
+               }
+
+               up_write(&crypto_alg_sem);
+
+               if (!larval)
+                       break;
+
+               crypto_wait_for_test(larval);
+       }
+
+       static_branch_enable(&crypto_boot_test_finished);
+}
+
 static int __init crypto_algapi_init(void)
 {
        crypto_init_proc();
+       crypto_start_tests();
        return 0;
 }
 
@@ -1272,7 +1313,11 @@ static void __exit crypto_algapi_exit(void)
        crypto_exit_proc();
 }
 
-module_init(crypto_algapi_init);
+/*
+ * We run this at late_initcall so that all the built-in algorithms
+ * have had a chance to register themselves first.
+ */
+late_initcall(crypto_algapi_init);
 module_exit(crypto_algapi_exit);
 
 MODULE_LICENSE("GPL");