crypto: api - Move alg destroy work from instance to template
authorHerbert Xu <herbert@gondor.apana.org.au>
Mon, 17 Mar 2025 08:33:54 +0000 (16:33 +0800)
committerHerbert Xu <herbert@gondor.apana.org.au>
Mon, 7 Apr 2025 05:22:25 +0000 (13:22 +0800)
Commit 9ae4577bc077 ("crypto: api - Use work queue in
crypto_destroy_instance") introduced a work struct to free an
instance after the last user goes away.

Move the delayed work from the instance into its template so that
when the template is unregistered it can ensure that all its
instances have been freed before returning.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
crypto/algapi.c
include/crypto/algapi.h

index ea9ed9580aa82935b7815106470d48ad32bbd25e..22bf80aad82b6fb825e87d17e8e79cff88893ffb 100644 (file)
@@ -71,12 +71,23 @@ static void crypto_free_instance(struct crypto_instance *inst)
 
 static void crypto_destroy_instance_workfn(struct work_struct *w)
 {
-       struct crypto_instance *inst = container_of(w, struct crypto_instance,
+       struct crypto_template *tmpl = container_of(w, struct crypto_template,
                                                    free_work);
-       struct crypto_template *tmpl = inst->tmpl;
+       struct crypto_instance *inst;
+       struct hlist_node *n;
+       HLIST_HEAD(list);
 
-       crypto_free_instance(inst);
-       crypto_tmpl_put(tmpl);
+       down_write(&crypto_alg_sem);
+       hlist_for_each_entry_safe(inst, n, &tmpl->dead, list) {
+               if (refcount_read(&inst->alg.cra_refcnt) != -1)
+                       continue;
+               hlist_del(&inst->list);
+               hlist_add_head(&inst->list, &list);
+       }
+       up_write(&crypto_alg_sem);
+
+       hlist_for_each_entry_safe(inst, n, &list, list)
+               crypto_free_instance(inst);
 }
 
 static void crypto_destroy_instance(struct crypto_alg *alg)
@@ -84,9 +95,10 @@ static void crypto_destroy_instance(struct crypto_alg *alg)
        struct crypto_instance *inst = container_of(alg,
                                                    struct crypto_instance,
                                                    alg);
+       struct crypto_template *tmpl = inst->tmpl;
 
-       INIT_WORK(&inst->free_work, crypto_destroy_instance_workfn);
-       schedule_work(&inst->free_work);
+       refcount_set(&alg->cra_refcnt, -1);
+       schedule_work(&tmpl->free_work);
 }
 
 /*
@@ -132,14 +144,17 @@ static void crypto_remove_instance(struct crypto_instance *inst,
 
        inst->alg.cra_flags |= CRYPTO_ALG_DEAD;
 
-       if (!tmpl || !crypto_tmpl_get(tmpl))
+       if (!tmpl)
                return;
 
-       list_move(&inst->alg.cra_list, list);
+       list_del_init(&inst->alg.cra_list);
        hlist_del(&inst->list);
+       hlist_add_head(&inst->list, &tmpl->dead);
        inst->alg.cra_destroy = crypto_destroy_instance;
 
        BUG_ON(!list_empty(&inst->alg.cra_users));
+
+       crypto_alg_put(&inst->alg);
 }
 
 /*
@@ -504,6 +519,8 @@ int crypto_register_template(struct crypto_template *tmpl)
        struct crypto_template *q;
        int err = -EEXIST;
 
+       INIT_WORK(&tmpl->free_work, crypto_destroy_instance_workfn);
+
        down_write(&crypto_alg_sem);
 
        crypto_check_module_sig(tmpl->module);
@@ -565,6 +582,8 @@ void crypto_unregister_template(struct crypto_template *tmpl)
                crypto_free_instance(inst);
        }
        crypto_remove_final(&users);
+
+       flush_work(&tmpl->free_work);
 }
 EXPORT_SYMBOL_GPL(crypto_unregister_template);
 
index 6e07bbc040895bf967ba41645d8532f0e0bb204d..03b7eca8af9a0c7e9aefc99fdca546ca1e02affb 100644 (file)
@@ -68,16 +68,17 @@ struct crypto_instance {
                struct crypto_spawn *spawns;
        };
 
-       struct work_struct free_work;
-
        void *__ctx[] CRYPTO_MINALIGN_ATTR;
 };
 
 struct crypto_template {
        struct list_head list;
        struct hlist_head instances;
+       struct hlist_head dead;
        struct module *module;
 
+       struct work_struct free_work;
+
        int (*create)(struct crypto_template *tmpl, struct rtattr **tb);
 
        char name[CRYPTO_MAX_ALG_NAME];