aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2006-09-20 21:39:29 -0400
committerHerbert Xu <herbert@gondor.apana.org.au>2006-09-20 21:39:29 -0400
commit6bfd48096ff8ecabf955958b51ddfa7988eb0a14 (patch)
tree813799f00d8402348ba6817953b1c631541be66c
parent492e2b63eb10c28f4f0b694264d74a8755cd1be0 (diff)
[CRYPTO] api: Added spawns
Spawns lock a specific crypto algorithm in place. They can then be used with crypto_spawn_tfm to allocate a tfm for that algorithm. When the base algorithm of a spawn is deregistered, all its spawns will be automatically removed. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--crypto/algapi.c185
-rw-r--r--crypto/api.c95
-rw-r--r--crypto/cryptomgr.c19
-rw-r--r--crypto/internal.h19
-rw-r--r--include/crypto/algapi.h11
-rw-r--r--include/linux/crypto.h4
6 files changed, 280 insertions, 53 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);
diff --git a/crypto/api.c b/crypto/api.c
index ddf6a767acdd..7e5522cf856e 100644
--- a/crypto/api.c
+++ b/crypto/api.c
@@ -15,11 +15,13 @@
15 * 15 *
16 */ 16 */
17 17
18#include <linux/err.h>
18#include <linux/errno.h> 19#include <linux/errno.h>
19#include <linux/kernel.h> 20#include <linux/kernel.h>
20#include <linux/kmod.h> 21#include <linux/kmod.h>
21#include <linux/module.h> 22#include <linux/module.h>
22#include <linux/param.h> 23#include <linux/param.h>
24#include <linux/sched.h>
23#include <linux/slab.h> 25#include <linux/slab.h>
24#include <linux/string.h> 26#include <linux/string.h>
25#include "internal.h" 27#include "internal.h"
@@ -38,12 +40,6 @@ static inline struct crypto_alg *crypto_alg_get(struct crypto_alg *alg)
38 return alg; 40 return alg;
39} 41}
40 42
41static inline void crypto_alg_put(struct crypto_alg *alg)
42{
43 if (atomic_dec_and_test(&alg->cra_refcnt) && alg->cra_destroy)
44 alg->cra_destroy(alg);
45}
46
47struct crypto_alg *crypto_mod_get(struct crypto_alg *alg) 43struct crypto_alg *crypto_mod_get(struct crypto_alg *alg)
48{ 44{
49 return try_module_get(alg->cra_module) ? crypto_alg_get(alg) : NULL; 45 return try_module_get(alg->cra_module) ? crypto_alg_get(alg) : NULL;
@@ -65,6 +61,9 @@ struct crypto_alg *__crypto_alg_lookup(const char *name, u32 type, u32 mask)
65 list_for_each_entry(q, &crypto_alg_list, cra_list) { 61 list_for_each_entry(q, &crypto_alg_list, cra_list) {
66 int exact, fuzzy; 62 int exact, fuzzy;
67 63
64 if (crypto_is_moribund(q))
65 continue;
66
68 if ((q->cra_flags ^ type) & mask) 67 if ((q->cra_flags ^ type) & mask)
69 continue; 68 continue;
70 69
@@ -111,7 +110,7 @@ static struct crypto_alg *crypto_larval_alloc(const char *name, u32 type,
111 110
112 larval = kzalloc(sizeof(*larval), GFP_KERNEL); 111 larval = kzalloc(sizeof(*larval), GFP_KERNEL);
113 if (!larval) 112 if (!larval)
114 return NULL; 113 return ERR_PTR(-ENOMEM);
115 114
116 larval->mask = mask; 115 larval->mask = mask;
117 larval->alg.cra_flags = CRYPTO_ALG_LARVAL | type; 116 larval->alg.cra_flags = CRYPTO_ALG_LARVAL | type;
@@ -153,8 +152,11 @@ static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg)
153 152
154 wait_for_completion_interruptible_timeout(&larval->completion, 60 * HZ); 153 wait_for_completion_interruptible_timeout(&larval->completion, 60 * HZ);
155 alg = larval->adult; 154 alg = larval->adult;
156 if (alg && !crypto_mod_get(alg)) 155 if (alg) {
157 alg = NULL; 156 if (!crypto_mod_get(alg))
157 alg = ERR_PTR(-EAGAIN);
158 } else
159 alg = ERR_PTR(-ENOENT);
158 crypto_mod_put(&larval->alg); 160 crypto_mod_put(&larval->alg);
159 161
160 return alg; 162 return alg;
@@ -165,9 +167,6 @@ static struct crypto_alg *crypto_alg_lookup(const char *name, u32 type,
165{ 167{
166 struct crypto_alg *alg; 168 struct crypto_alg *alg;
167 169
168 if (!name)
169 return NULL;
170
171 down_read(&crypto_alg_sem); 170 down_read(&crypto_alg_sem);
172 alg = __crypto_alg_lookup(name, type, mask); 171 alg = __crypto_alg_lookup(name, type, mask);
173 up_read(&crypto_alg_sem); 172 up_read(&crypto_alg_sem);
@@ -181,7 +180,10 @@ struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask)
181 struct crypto_alg *larval; 180 struct crypto_alg *larval;
182 int ok; 181 int ok;
183 182
184 mask &= ~CRYPTO_ALG_LARVAL; 183 if (!name)
184 return ERR_PTR(-ENOENT);
185
186 mask &= ~(CRYPTO_ALG_LARVAL | CRYPTO_ALG_DEAD);
185 type &= mask; 187 type &= mask;
186 188
187 alg = try_then_request_module(crypto_alg_lookup(name, type, mask), 189 alg = try_then_request_module(crypto_alg_lookup(name, type, mask),
@@ -190,7 +192,7 @@ struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask)
190 return crypto_is_larval(alg) ? crypto_larval_wait(alg) : alg; 192 return crypto_is_larval(alg) ? crypto_larval_wait(alg) : alg;
191 193
192 larval = crypto_larval_alloc(name, type, mask); 194 larval = crypto_larval_alloc(name, type, mask);
193 if (!larval || !crypto_is_larval(larval)) 195 if (IS_ERR(larval) || !crypto_is_larval(larval))
194 return larval; 196 return larval;
195 197
196 ok = crypto_notify(CRYPTO_MSG_ALG_REQUEST, larval); 198 ok = crypto_notify(CRYPTO_MSG_ALG_REQUEST, larval);
@@ -203,7 +205,7 @@ struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask)
203 alg = crypto_larval_wait(larval); 205 alg = crypto_larval_wait(larval);
204 else { 206 else {
205 crypto_mod_put(larval); 207 crypto_mod_put(larval);
206 alg = NULL; 208 alg = ERR_PTR(-ENOENT);
207 } 209 }
208 crypto_larval_kill(larval); 210 crypto_larval_kill(larval);
209 return alg; 211 return alg;
@@ -298,31 +300,40 @@ static unsigned int crypto_ctxsize(struct crypto_alg *alg, int flags)
298 return len + (alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1)); 300 return len + (alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1));
299} 301}
300 302
301struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags) 303void crypto_shoot_alg(struct crypto_alg *alg)
304{
305 down_write(&crypto_alg_sem);
306 alg->cra_flags |= CRYPTO_ALG_DYING;
307 up_write(&crypto_alg_sem);
308}
309EXPORT_SYMBOL_GPL(crypto_shoot_alg);
310
311struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 flags)
302{ 312{
303 struct crypto_tfm *tfm = NULL; 313 struct crypto_tfm *tfm = NULL;
304 struct crypto_alg *alg;
305 unsigned int tfm_size; 314 unsigned int tfm_size;
306 315 int err = -ENOMEM;
307 alg = crypto_alg_mod_lookup(name, 0, 0);
308 if (alg == NULL)
309 goto out;
310 316
311 tfm_size = sizeof(*tfm) + crypto_ctxsize(alg, flags); 317 tfm_size = sizeof(*tfm) + crypto_ctxsize(alg, flags);
312 tfm = kzalloc(tfm_size, GFP_KERNEL); 318 tfm = kzalloc(tfm_size, GFP_KERNEL);
313 if (tfm == NULL) 319 if (tfm == NULL)
314 goto out_put; 320 goto out;
315 321
316 tfm->__crt_alg = alg; 322 tfm->__crt_alg = alg;
317 323
318 if (crypto_init_flags(tfm, flags)) 324 err = crypto_init_flags(tfm, flags);
325 if (err)
319 goto out_free_tfm; 326 goto out_free_tfm;
320 327
321 if (crypto_init_ops(tfm)) 328 err = crypto_init_ops(tfm);
329 if (err)
322 goto out_free_tfm; 330 goto out_free_tfm;
323 331
324 if (alg->cra_init && alg->cra_init(tfm)) 332 if (alg->cra_init && (err = alg->cra_init(tfm))) {
333 if (err == -EAGAIN)
334 crypto_shoot_alg(alg);
325 goto cra_init_failed; 335 goto cra_init_failed;
336 }
326 337
327 goto out; 338 goto out;
328 339
@@ -330,12 +341,36 @@ cra_init_failed:
330 crypto_exit_ops(tfm); 341 crypto_exit_ops(tfm);
331out_free_tfm: 342out_free_tfm:
332 kfree(tfm); 343 kfree(tfm);
333 tfm = NULL; 344 tfm = ERR_PTR(err);
334out_put:
335 crypto_mod_put(alg);
336out: 345out:
337 return tfm; 346 return tfm;
338} 347}
348EXPORT_SYMBOL_GPL(__crypto_alloc_tfm);
349
350struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags)
351{
352 struct crypto_tfm *tfm = NULL;
353 int err;
354
355 do {
356 struct crypto_alg *alg;
357
358 alg = crypto_alg_mod_lookup(name, 0, 0);
359 err = PTR_ERR(alg);
360 if (IS_ERR(alg))
361 continue;
362
363 tfm = __crypto_alloc_tfm(alg, flags);
364 err = 0;
365 if (IS_ERR(tfm)) {
366 crypto_mod_put(alg);
367 err = PTR_ERR(tfm);
368 tfm = NULL;
369 }
370 } while (err == -EAGAIN && !signal_pending(current));
371
372 return tfm;
373}
339 374
340void crypto_free_tfm(struct crypto_tfm *tfm) 375void crypto_free_tfm(struct crypto_tfm *tfm)
341{ 376{
@@ -361,7 +396,7 @@ int crypto_alg_available(const char *name, u32 flags)
361 int ret = 0; 396 int ret = 0;
362 struct crypto_alg *alg = crypto_alg_mod_lookup(name, 0, 0); 397 struct crypto_alg *alg = crypto_alg_mod_lookup(name, 0, 0);
363 398
364 if (alg) { 399 if (!IS_ERR(alg)) {
365 crypto_mod_put(alg); 400 crypto_mod_put(alg);
366 ret = 1; 401 ret = 1;
367 } 402 }
diff --git a/crypto/cryptomgr.c b/crypto/cryptomgr.c
index ae54942e3b31..9b5b15601068 100644
--- a/crypto/cryptomgr.c
+++ b/crypto/cryptomgr.c
@@ -17,6 +17,7 @@
17#include <linux/module.h> 17#include <linux/module.h>
18#include <linux/notifier.h> 18#include <linux/notifier.h>
19#include <linux/rtnetlink.h> 19#include <linux/rtnetlink.h>
20#include <linux/sched.h>
20#include <linux/string.h> 21#include <linux/string.h>
21#include <linux/workqueue.h> 22#include <linux/workqueue.h>
22 23
@@ -44,21 +45,25 @@ static void cryptomgr_probe(void *data)
44 struct cryptomgr_param *param = data; 45 struct cryptomgr_param *param = data;
45 struct crypto_template *tmpl; 46 struct crypto_template *tmpl;
46 struct crypto_instance *inst; 47 struct crypto_instance *inst;
48 int err;
47 49
48 tmpl = crypto_lookup_template(param->template); 50 tmpl = crypto_lookup_template(param->template);
49 if (!tmpl) 51 if (!tmpl)
50 goto err; 52 goto err;
51 53
52 inst = tmpl->alloc(&param->alg, sizeof(param->alg)); 54 do {
53 if (IS_ERR(inst)) 55 inst = tmpl->alloc(&param->alg, sizeof(param->alg));
54 goto err; 56 if (IS_ERR(inst))
55 else if ((err = crypto_register_instance(tmpl, inst))) { 57 err = PTR_ERR(inst);
56 tmpl->free(inst); 58 else if ((err = crypto_register_instance(tmpl, inst)))
57 goto err; 59 tmpl->free(inst);
58 } 60 } while (err == -EAGAIN && !signal_pending(current));
59 61
60 crypto_tmpl_put(tmpl); 62 crypto_tmpl_put(tmpl);
61 63
64 if (err)
65 goto err;
66
62out: 67out:
63 kfree(param); 68 kfree(param);
64 return; 69 return;
diff --git a/crypto/internal.h b/crypto/internal.h
index c08d93bdadc4..03c00b0e6b60 100644
--- a/crypto/internal.h
+++ b/crypto/internal.h
@@ -142,12 +142,21 @@ void crypto_exit_compress_ops(struct crypto_tfm *tfm);
142 142
143void crypto_larval_error(const char *name, u32 type, u32 mask); 143void crypto_larval_error(const char *name, u32 type, u32 mask);
144 144
145void crypto_shoot_alg(struct crypto_alg *alg);
146struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 flags);
147
145int crypto_register_instance(struct crypto_template *tmpl, 148int crypto_register_instance(struct crypto_template *tmpl,
146 struct crypto_instance *inst); 149 struct crypto_instance *inst);
147 150
148int crypto_register_notifier(struct notifier_block *nb); 151int crypto_register_notifier(struct notifier_block *nb);
149int crypto_unregister_notifier(struct notifier_block *nb); 152int crypto_unregister_notifier(struct notifier_block *nb);
150 153
154static inline void crypto_alg_put(struct crypto_alg *alg)
155{
156 if (atomic_dec_and_test(&alg->cra_refcnt) && alg->cra_destroy)
157 alg->cra_destroy(alg);
158}
159
151static inline int crypto_tmpl_get(struct crypto_template *tmpl) 160static inline int crypto_tmpl_get(struct crypto_template *tmpl)
152{ 161{
153 return try_module_get(tmpl->module); 162 return try_module_get(tmpl->module);
@@ -163,6 +172,16 @@ static inline int crypto_is_larval(struct crypto_alg *alg)
163 return alg->cra_flags & CRYPTO_ALG_LARVAL; 172 return alg->cra_flags & CRYPTO_ALG_LARVAL;
164} 173}
165 174
175static inline int crypto_is_dead(struct crypto_alg *alg)
176{
177 return alg->cra_flags & CRYPTO_ALG_DEAD;
178}
179
180static inline int crypto_is_moribund(struct crypto_alg *alg)
181{
182 return alg->cra_flags & (CRYPTO_ALG_DEAD | CRYPTO_ALG_DYING);
183}
184
166static inline int crypto_notify(unsigned long val, void *v) 185static inline int crypto_notify(unsigned long val, void *v)
167{ 186{
168 return blocking_notifier_call_chain(&crypto_chain, val, v); 187 return blocking_notifier_call_chain(&crypto_chain, val, v);
diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h
index ffec530d52fb..b20f4bdb23ba 100644
--- a/include/crypto/algapi.h
+++ b/include/crypto/algapi.h
@@ -36,10 +36,21 @@ struct crypto_template {
36 char name[CRYPTO_MAX_ALG_NAME]; 36 char name[CRYPTO_MAX_ALG_NAME];
37}; 37};
38 38
39struct crypto_spawn {
40 struct list_head list;
41 struct crypto_alg *alg;
42 struct crypto_instance *inst;
43};
44
39int crypto_register_template(struct crypto_template *tmpl); 45int crypto_register_template(struct crypto_template *tmpl);
40void crypto_unregister_template(struct crypto_template *tmpl); 46void crypto_unregister_template(struct crypto_template *tmpl);
41struct crypto_template *crypto_lookup_template(const char *name); 47struct crypto_template *crypto_lookup_template(const char *name);
42 48
49int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg,
50 struct crypto_instance *inst);
51void crypto_drop_spawn(struct crypto_spawn *spawn);
52struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn);
53
43static inline void *crypto_instance_ctx(struct crypto_instance *inst) 54static inline void *crypto_instance_ctx(struct crypto_instance *inst)
44{ 55{
45 return inst->__ctx; 56 return inst->__ctx;
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index 85f73c381913..40a6330abc8d 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -35,6 +35,8 @@
35#define CRYPTO_ALG_TYPE_COMPRESS 0x00000004 35#define CRYPTO_ALG_TYPE_COMPRESS 0x00000004
36 36
37#define CRYPTO_ALG_LARVAL 0x00000010 37#define CRYPTO_ALG_LARVAL 0x00000010
38#define CRYPTO_ALG_DEAD 0x00000020
39#define CRYPTO_ALG_DYING 0x00000040
38 40
39/* 41/*
40 * Transform masks and values (for crt_flags). 42 * Transform masks and values (for crt_flags).
@@ -145,6 +147,8 @@ struct compress_alg {
145 147
146struct crypto_alg { 148struct crypto_alg {
147 struct list_head cra_list; 149 struct list_head cra_list;
150 struct list_head cra_users;
151
148 u32 cra_flags; 152 u32 cra_flags;
149 unsigned int cra_blocksize; 153 unsigned int cra_blocksize;
150 unsigned int cra_ctxsize; 154 unsigned int cra_ctxsize;