summaryrefslogtreecommitdiffstats
path: root/crypto/algapi.c
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2007-04-08 13:31:36 +0200
committerHerbert Xu <herbert@gondor.apana.org.au>2007-05-02 06:38:32 +0200
commita73e69965fa2647faa36caf40f4132b9c99d61fd (patch)
tree8c138eaeb2daeb58d5634961607d37d258729349 /crypto/algapi.c
parent[CRYPTO] cryptomgr: Fix parsing of nested templates (diff)
downloadlinux-a73e69965fa2647faa36caf40f4132b9c99d61fd.tar.xz
linux-a73e69965fa2647faa36caf40f4132b9c99d61fd.zip
[CRYPTO] api: Do not remove users unless new algorithm matches
As it is whenever a new algorithm with the same name is registered users of the old algorithm will be removed so that they can take advantage of the new algorithm. This presents a problem when the new algorithm is not equivalent to the old algorithm. In particular, the new algorithm might only function on top of the existing one. Hence we should not remove users unless they can make use of the new algorithm. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto/algapi.c')
-rw-r--r--crypto/algapi.c65
1 files changed, 39 insertions, 26 deletions
diff --git a/crypto/algapi.c b/crypto/algapi.c
index 1c2185b5b005..f137a432061f 100644
--- a/crypto/algapi.c
+++ b/crypto/algapi.c
@@ -84,36 +84,47 @@ static void crypto_destroy_instance(struct crypto_alg *alg)
crypto_tmpl_put(tmpl);
}
-static void crypto_remove_spawns(struct list_head *spawns,
- struct list_head *list)
+static void crypto_remove_spawn(struct crypto_spawn *spawn,
+ struct list_head *list,
+ struct list_head *secondary_spawns)
{
- struct crypto_spawn *spawn, *n;
+ struct crypto_instance *inst = spawn->inst;
+ struct crypto_template *tmpl = inst->tmpl;
- list_for_each_entry_safe(spawn, n, spawns, list) {
- struct crypto_instance *inst = spawn->inst;
- struct crypto_template *tmpl = inst->tmpl;
+ list_del_init(&spawn->list);
+ spawn->alg = NULL;
- list_del_init(&spawn->list);
- spawn->alg = NULL;
+ if (crypto_is_dead(&inst->alg))
+ return;
- if (crypto_is_dead(&inst->alg))
- continue;
+ inst->alg.cra_flags |= CRYPTO_ALG_DEAD;
+ if (!tmpl || !crypto_tmpl_get(tmpl))
+ return;
+
+ crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, &inst->alg);
+ list_move(&inst->alg.cra_list, list);
+ hlist_del(&inst->list);
+ inst->alg.cra_destroy = crypto_destroy_instance;
+
+ list_splice(&inst->alg.cra_users, secondary_spawns);
+}
+
+static void crypto_remove_spawns(struct list_head *spawns,
+ struct list_head *list, u32 new_type)
+{
+ struct crypto_spawn *spawn, *n;
+ LIST_HEAD(secondary_spawns);
- inst->alg.cra_flags |= CRYPTO_ALG_DEAD;
- if (!tmpl || !crypto_tmpl_get(tmpl))
+ list_for_each_entry_safe(spawn, n, spawns, list) {
+ if ((spawn->alg->cra_flags ^ new_type) & spawn->mask)
continue;
- crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, &inst->alg);
- list_move(&inst->alg.cra_list, list);
- hlist_del(&inst->list);
- inst->alg.cra_destroy = crypto_destroy_instance;
+ crypto_remove_spawn(spawn, list, &secondary_spawns);
+ }
- if (!list_empty(&inst->alg.cra_users)) {
- if (&n->list == spawns)
- n = list_entry(inst->alg.cra_users.next,
- typeof(*n), list);
- __list_splice(&inst->alg.cra_users, spawns->prev);
- }
+ while (!list_empty(&secondary_spawns)) {
+ list_for_each_entry_safe(spawn, n, &secondary_spawns, list)
+ crypto_remove_spawn(spawn, list, &secondary_spawns);
}
}
@@ -164,7 +175,7 @@ static int __crypto_register_alg(struct crypto_alg *alg,
q->cra_priority > alg->cra_priority)
continue;
- crypto_remove_spawns(&q->cra_users, list);
+ crypto_remove_spawns(&q->cra_users, list, alg->cra_flags);
}
list_add(&alg->cra_list, &crypto_alg_list);
@@ -214,7 +225,7 @@ static int crypto_remove_alg(struct crypto_alg *alg, struct list_head *list)
crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, alg);
list_del_init(&alg->cra_list);
- crypto_remove_spawns(&alg->cra_users, list);
+ crypto_remove_spawns(&alg->cra_users, list, alg->cra_flags);
return 0;
}
@@ -351,11 +362,12 @@ err:
EXPORT_SYMBOL_GPL(crypto_register_instance);
int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg,
- struct crypto_instance *inst)
+ struct crypto_instance *inst, u32 mask)
{
int err = -EAGAIN;
spawn->inst = inst;
+ spawn->mask = mask;
down_write(&crypto_alg_sem);
if (!crypto_is_moribund(alg)) {
@@ -494,7 +506,8 @@ struct crypto_instance *crypto_alloc_instance(const char *name,
goto err_free_inst;
spawn = crypto_instance_ctx(inst);
- err = crypto_init_spawn(spawn, alg, inst);
+ err = crypto_init_spawn(spawn, alg, inst,
+ CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
if (err)
goto err_free_inst;