aboutsummaryrefslogtreecommitdiffstats
path: root/crypto/algapi.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/algapi.c')
-rw-r--r--crypto/algapi.c185
1 files changed, 169 insertions, 16 deletions
diff --git a/crypto/algapi.c b/crypto/algapi.c
index acea250677c0..36c4f1bdb521 100644
--- a/crypto/algapi.c
+++ b/crypto/algapi.c
@@ -10,6 +10,7 @@
10 * 10 *
11 */ 11 */
12 12
13#include <linux/err.h>
13#include <linux/errno.h> 14#include <linux/errno.h>
14#include <linux/init.h> 15#include <linux/init.h>
15#include <linux/kernel.h> 16#include <linux/kernel.h>
@@ -73,27 +74,96 @@ static int crypto_check_alg(struct crypto_alg *alg)
73 return crypto_set_driver_name(alg); 74 return crypto_set_driver_name(alg);
74} 75}
75 76
76static int __crypto_register_alg(struct crypto_alg *alg) 77static void crypto_destroy_instance(struct crypto_alg *alg)
78{
79 struct crypto_instance *inst = (void *)alg;
80 struct crypto_template *tmpl = inst->tmpl;
81
82 tmpl->free(inst);
83 crypto_tmpl_put(tmpl);
84}
85
86static void crypto_remove_spawns(struct list_head *spawns,
87 struct list_head *list)
88{
89 struct crypto_spawn *spawn, *n;
90
91 list_for_each_entry_safe(spawn, n, spawns, list) {
92 struct crypto_instance *inst = spawn->inst;
93 struct crypto_template *tmpl = inst->tmpl;
94
95 list_del_init(&spawn->list);
96 spawn->alg = NULL;
97
98 if (crypto_is_dead(&inst->alg))
99 continue;
100
101 inst->alg.cra_flags |= CRYPTO_ALG_DEAD;
102 if (!tmpl || !crypto_tmpl_get(tmpl))
103 continue;
104
105 crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, &inst->alg);
106 list_move(&inst->alg.cra_list, list);
107 hlist_del(&inst->list);
108 inst->alg.cra_destroy = crypto_destroy_instance;
109
110 if (!list_empty(&inst->alg.cra_users)) {
111 if (&n->list == spawns)
112 n = list_entry(inst->alg.cra_users.next,
113 typeof(*n), list);
114 __list_splice(&inst->alg.cra_users, spawns->prev);
115 }
116 }
117}
118
119static int __crypto_register_alg(struct crypto_alg *alg,
120 struct list_head *list)
77{ 121{
78 struct crypto_alg *q; 122 struct crypto_alg *q;
79 int ret = -EEXIST; 123 int ret = -EAGAIN;
124
125 if (crypto_is_dead(alg))
126 goto out;
127
128 INIT_LIST_HEAD(&alg->cra_users);
129
130 ret = -EEXIST;
80 131
81 atomic_set(&alg->cra_refcnt, 1); 132 atomic_set(&alg->cra_refcnt, 1);
82 list_for_each_entry(q, &crypto_alg_list, cra_list) { 133 list_for_each_entry(q, &crypto_alg_list, cra_list) {
83 if (q == alg) 134 if (q == alg)
84 goto out; 135 goto out;
85 if (crypto_is_larval(q) && 136
86 (!strcmp(alg->cra_name, q->cra_name) || 137 if (crypto_is_moribund(q))
87 !strcmp(alg->cra_driver_name, q->cra_name))) { 138 continue;
139
140 if (crypto_is_larval(q)) {
88 struct crypto_larval *larval = (void *)q; 141 struct crypto_larval *larval = (void *)q;
89 142
143 if (strcmp(alg->cra_name, q->cra_name) &&
144 strcmp(alg->cra_driver_name, q->cra_name))
145 continue;
146
147 if (larval->adult)
148 continue;
90 if ((q->cra_flags ^ alg->cra_flags) & larval->mask) 149 if ((q->cra_flags ^ alg->cra_flags) & larval->mask)
91 continue; 150 continue;
92 if (!crypto_mod_get(alg)) 151 if (!crypto_mod_get(alg))
93 continue; 152 continue;
153
94 larval->adult = alg; 154 larval->adult = alg;
95 complete(&larval->completion); 155 complete(&larval->completion);
156 continue;
96 } 157 }
158
159 if (strcmp(alg->cra_name, q->cra_name))
160 continue;
161
162 if (strcmp(alg->cra_driver_name, q->cra_driver_name) &&
163 q->cra_priority > alg->cra_priority)
164 continue;
165
166 crypto_remove_spawns(&q->cra_users, list);
97 } 167 }
98 168
99 list_add(&alg->cra_list, &crypto_alg_list); 169 list_add(&alg->cra_list, &crypto_alg_list);
@@ -105,8 +175,20 @@ out:
105 return ret; 175 return ret;
106} 176}
107 177
178static void crypto_remove_final(struct list_head *list)
179{
180 struct crypto_alg *alg;
181 struct crypto_alg *n;
182
183 list_for_each_entry_safe(alg, n, list, cra_list) {
184 list_del_init(&alg->cra_list);
185 crypto_alg_put(alg);
186 }
187}
188
108int crypto_register_alg(struct crypto_alg *alg) 189int crypto_register_alg(struct crypto_alg *alg)
109{ 190{
191 LIST_HEAD(list);
110 int err; 192 int err;
111 193
112 err = crypto_check_alg(alg); 194 err = crypto_check_alg(alg);
@@ -114,23 +196,35 @@ int crypto_register_alg(struct crypto_alg *alg)
114 return err; 196 return err;
115 197
116 down_write(&crypto_alg_sem); 198 down_write(&crypto_alg_sem);
117 err = __crypto_register_alg(alg); 199 err = __crypto_register_alg(alg, &list);
118 up_write(&crypto_alg_sem); 200 up_write(&crypto_alg_sem);
119 201
202 crypto_remove_final(&list);
120 return err; 203 return err;
121} 204}
122EXPORT_SYMBOL_GPL(crypto_register_alg); 205EXPORT_SYMBOL_GPL(crypto_register_alg);
123 206
207static int crypto_remove_alg(struct crypto_alg *alg, struct list_head *list)
208{
209 if (unlikely(list_empty(&alg->cra_list)))
210 return -ENOENT;
211
212 alg->cra_flags |= CRYPTO_ALG_DEAD;
213
214 crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, alg);
215 list_del_init(&alg->cra_list);
216 crypto_remove_spawns(&alg->cra_users, list);
217
218 return 0;
219}
220
124int crypto_unregister_alg(struct crypto_alg *alg) 221int crypto_unregister_alg(struct crypto_alg *alg)
125{ 222{
126 int ret = -ENOENT; 223 int ret;
224 LIST_HEAD(list);
127 225
128 down_write(&crypto_alg_sem); 226 down_write(&crypto_alg_sem);
129 if (likely(!list_empty(&alg->cra_list))) { 227 ret = crypto_remove_alg(alg, &list);
130 list_del_init(&alg->cra_list);
131 ret = 0;
132 }
133 crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, alg);
134 up_write(&crypto_alg_sem); 228 up_write(&crypto_alg_sem);
135 229
136 if (ret) 230 if (ret)
@@ -140,6 +234,7 @@ int crypto_unregister_alg(struct crypto_alg *alg)
140 if (alg->cra_destroy) 234 if (alg->cra_destroy)
141 alg->cra_destroy(alg); 235 alg->cra_destroy(alg);
142 236
237 crypto_remove_final(&list);
143 return 0; 238 return 0;
144} 239}
145EXPORT_SYMBOL_GPL(crypto_unregister_alg); 240EXPORT_SYMBOL_GPL(crypto_unregister_alg);
@@ -170,6 +265,7 @@ void crypto_unregister_template(struct crypto_template *tmpl)
170 struct crypto_instance *inst; 265 struct crypto_instance *inst;
171 struct hlist_node *p, *n; 266 struct hlist_node *p, *n;
172 struct hlist_head *list; 267 struct hlist_head *list;
268 LIST_HEAD(users);
173 269
174 down_write(&crypto_alg_sem); 270 down_write(&crypto_alg_sem);
175 271
@@ -178,9 +274,8 @@ void crypto_unregister_template(struct crypto_template *tmpl)
178 274
179 list = &tmpl->instances; 275 list = &tmpl->instances;
180 hlist_for_each_entry(inst, p, list, list) { 276 hlist_for_each_entry(inst, p, list, list) {
181 BUG_ON(list_empty(&inst->alg.cra_list)); 277 int err = crypto_remove_alg(&inst->alg, &users);
182 list_del_init(&inst->alg.cra_list); 278 BUG_ON(err);
183 crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, &inst->alg);
184 } 279 }
185 280
186 crypto_notify(CRYPTO_MSG_TMPL_UNREGISTER, tmpl); 281 crypto_notify(CRYPTO_MSG_TMPL_UNREGISTER, tmpl);
@@ -191,6 +286,7 @@ void crypto_unregister_template(struct crypto_template *tmpl)
191 BUG_ON(atomic_read(&inst->alg.cra_refcnt) != 1); 286 BUG_ON(atomic_read(&inst->alg.cra_refcnt) != 1);
192 tmpl->free(inst); 287 tmpl->free(inst);
193 } 288 }
289 crypto_remove_final(&users);
194} 290}
195EXPORT_SYMBOL_GPL(crypto_unregister_template); 291EXPORT_SYMBOL_GPL(crypto_unregister_template);
196 292
@@ -222,6 +318,7 @@ EXPORT_SYMBOL_GPL(crypto_lookup_template);
222int crypto_register_instance(struct crypto_template *tmpl, 318int crypto_register_instance(struct crypto_template *tmpl,
223 struct crypto_instance *inst) 319 struct crypto_instance *inst)
224{ 320{
321 LIST_HEAD(list);
225 int err = -EINVAL; 322 int err = -EINVAL;
226 323
227 if (inst->alg.cra_destroy) 324 if (inst->alg.cra_destroy)
@@ -235,7 +332,7 @@ int crypto_register_instance(struct crypto_template *tmpl,
235 332
236 down_write(&crypto_alg_sem); 333 down_write(&crypto_alg_sem);
237 334
238 err = __crypto_register_alg(&inst->alg); 335 err = __crypto_register_alg(&inst->alg, &list);
239 if (err) 336 if (err)
240 goto unlock; 337 goto unlock;
241 338
@@ -245,11 +342,67 @@ int crypto_register_instance(struct crypto_template *tmpl,
245unlock: 342unlock:
246 up_write(&crypto_alg_sem); 343 up_write(&crypto_alg_sem);
247 344
345 crypto_remove_final(&list);
346
248err: 347err:
249 return err; 348 return err;
250} 349}
251EXPORT_SYMBOL_GPL(crypto_register_instance); 350EXPORT_SYMBOL_GPL(crypto_register_instance);
252 351
352int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg,
353 struct crypto_instance *inst)
354{
355 int err = -EAGAIN;
356
357 spawn->inst = inst;
358
359 down_write(&crypto_alg_sem);
360 if (!crypto_is_moribund(alg)) {
361 list_add(&spawn->list, &alg->cra_users);
362 spawn->alg = alg;
363 err = 0;
364 }
365 up_write(&crypto_alg_sem);
366
367 return err;
368}
369EXPORT_SYMBOL_GPL(crypto_init_spawn);
370
371void crypto_drop_spawn(struct crypto_spawn *spawn)
372{
373 down_write(&crypto_alg_sem);
374 list_del(&spawn->list);
375 up_write(&crypto_alg_sem);
376}
377EXPORT_SYMBOL_GPL(crypto_drop_spawn);
378
379struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn)
380{
381 struct crypto_alg *alg;
382 struct crypto_alg *alg2;
383 struct crypto_tfm *tfm;
384
385 down_read(&crypto_alg_sem);
386 alg = spawn->alg;
387 alg2 = alg;
388 if (alg2)
389 alg2 = crypto_mod_get(alg2);
390 up_read(&crypto_alg_sem);
391
392 if (!alg2) {
393 if (alg)
394 crypto_shoot_alg(alg);
395 return ERR_PTR(-EAGAIN);
396 }
397
398 tfm = __crypto_alloc_tfm(alg, 0);
399 if (IS_ERR(tfm))
400 crypto_mod_put(alg);
401
402 return tfm;
403}
404EXPORT_SYMBOL_GPL(crypto_spawn_tfm);
405
253int crypto_register_notifier(struct notifier_block *nb) 406int crypto_register_notifier(struct notifier_block *nb)
254{ 407{
255 return blocking_notifier_chain_register(&crypto_chain, nb); 408 return blocking_notifier_chain_register(&crypto_chain, nb);