diff options
| -rw-r--r-- | crypto/algapi.c | 77 |
1 files changed, 63 insertions, 14 deletions
diff --git a/crypto/algapi.c b/crypto/algapi.c index 6a98076d9d2a..feb77e4bbb48 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c | |||
| @@ -81,16 +81,35 @@ static void crypto_destroy_instance(struct crypto_alg *alg) | |||
| 81 | crypto_tmpl_put(tmpl); | 81 | crypto_tmpl_put(tmpl); |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | static struct list_head *crypto_more_spawns(struct crypto_alg *alg, | ||
| 85 | struct list_head *stack, | ||
| 86 | struct list_head *top, | ||
| 87 | struct list_head *secondary_spawns) | ||
| 88 | { | ||
| 89 | struct crypto_spawn *spawn, *n; | ||
| 90 | |||
| 91 | if (list_empty(stack)) | ||
| 92 | return NULL; | ||
| 93 | |||
| 94 | spawn = list_first_entry(stack, struct crypto_spawn, list); | ||
| 95 | n = list_entry(spawn->list.next, struct crypto_spawn, list); | ||
| 96 | |||
| 97 | if (spawn->alg && &n->list != stack && !n->alg) | ||
| 98 | n->alg = (n->list.next == stack) ? alg : | ||
| 99 | &list_entry(n->list.next, struct crypto_spawn, | ||
| 100 | list)->inst->alg; | ||
| 101 | |||
| 102 | list_move(&spawn->list, secondary_spawns); | ||
| 103 | |||
| 104 | return &n->list == stack ? top : &n->inst->alg.cra_users; | ||
| 105 | } | ||
| 106 | |||
| 84 | static void crypto_remove_spawn(struct crypto_spawn *spawn, | 107 | static void crypto_remove_spawn(struct crypto_spawn *spawn, |
| 85 | struct list_head *list, | 108 | struct list_head *list) |
| 86 | struct list_head *secondary_spawns) | ||
| 87 | { | 109 | { |
| 88 | struct crypto_instance *inst = spawn->inst; | 110 | struct crypto_instance *inst = spawn->inst; |
| 89 | struct crypto_template *tmpl = inst->tmpl; | 111 | struct crypto_template *tmpl = inst->tmpl; |
| 90 | 112 | ||
| 91 | list_del_init(&spawn->list); | ||
| 92 | spawn->alg = NULL; | ||
| 93 | |||
| 94 | if (crypto_is_dead(&inst->alg)) | 113 | if (crypto_is_dead(&inst->alg)) |
| 95 | return; | 114 | return; |
| 96 | 115 | ||
| @@ -106,25 +125,55 @@ static void crypto_remove_spawn(struct crypto_spawn *spawn, | |||
| 106 | hlist_del(&inst->list); | 125 | hlist_del(&inst->list); |
| 107 | inst->alg.cra_destroy = crypto_destroy_instance; | 126 | inst->alg.cra_destroy = crypto_destroy_instance; |
| 108 | 127 | ||
| 109 | list_splice(&inst->alg.cra_users, secondary_spawns); | 128 | BUG_ON(!list_empty(&inst->alg.cra_users)); |
| 110 | } | 129 | } |
| 111 | 130 | ||
| 112 | static void crypto_remove_spawns(struct list_head *spawns, | 131 | static void crypto_remove_spawns(struct crypto_alg *alg, |
| 113 | struct list_head *list, u32 new_type) | 132 | struct list_head *list, |
| 133 | struct crypto_alg *nalg) | ||
| 114 | { | 134 | { |
| 135 | u32 new_type = (nalg ?: alg)->cra_flags; | ||
| 115 | struct crypto_spawn *spawn, *n; | 136 | struct crypto_spawn *spawn, *n; |
| 116 | LIST_HEAD(secondary_spawns); | 137 | LIST_HEAD(secondary_spawns); |
| 138 | struct list_head *spawns; | ||
| 139 | LIST_HEAD(stack); | ||
| 140 | LIST_HEAD(top); | ||
| 117 | 141 | ||
| 142 | spawns = &alg->cra_users; | ||
| 118 | list_for_each_entry_safe(spawn, n, spawns, list) { | 143 | list_for_each_entry_safe(spawn, n, spawns, list) { |
| 119 | if ((spawn->alg->cra_flags ^ new_type) & spawn->mask) | 144 | if ((spawn->alg->cra_flags ^ new_type) & spawn->mask) |
| 120 | continue; | 145 | continue; |
| 121 | 146 | ||
| 122 | crypto_remove_spawn(spawn, list, &secondary_spawns); | 147 | list_move(&spawn->list, &top); |
| 123 | } | 148 | } |
| 124 | 149 | ||
| 125 | while (!list_empty(&secondary_spawns)) { | 150 | spawns = ⊤ |
| 126 | list_for_each_entry_safe(spawn, n, &secondary_spawns, list) | 151 | do { |
| 127 | crypto_remove_spawn(spawn, list, &secondary_spawns); | 152 | while (!list_empty(spawns)) { |
| 153 | struct crypto_instance *inst; | ||
| 154 | |||
| 155 | spawn = list_first_entry(spawns, struct crypto_spawn, | ||
| 156 | list); | ||
| 157 | inst = spawn->inst; | ||
| 158 | |||
| 159 | BUG_ON(&inst->alg == alg); | ||
| 160 | |||
| 161 | list_move(&spawn->list, &stack); | ||
| 162 | |||
| 163 | if (&inst->alg == nalg) | ||
| 164 | break; | ||
| 165 | |||
| 166 | spawn->alg = NULL; | ||
| 167 | spawns = &inst->alg.cra_users; | ||
| 168 | } | ||
| 169 | } while ((spawns = crypto_more_spawns(alg, &stack, &top, | ||
| 170 | &secondary_spawns))); | ||
| 171 | |||
| 172 | list_for_each_entry_safe(spawn, n, &secondary_spawns, list) { | ||
| 173 | if (spawn->alg) | ||
| 174 | list_move(&spawn->list, &spawn->alg->cra_users); | ||
| 175 | else | ||
| 176 | crypto_remove_spawn(spawn, list); | ||
| 128 | } | 177 | } |
| 129 | } | 178 | } |
| 130 | 179 | ||
| @@ -258,7 +307,7 @@ found: | |||
| 258 | q->cra_priority > alg->cra_priority) | 307 | q->cra_priority > alg->cra_priority) |
| 259 | continue; | 308 | continue; |
| 260 | 309 | ||
| 261 | crypto_remove_spawns(&q->cra_users, &list, alg->cra_flags); | 310 | crypto_remove_spawns(q, &list, alg); |
| 262 | } | 311 | } |
| 263 | 312 | ||
| 264 | complete: | 313 | complete: |
| @@ -330,7 +379,7 @@ static int crypto_remove_alg(struct crypto_alg *alg, struct list_head *list) | |||
| 330 | 379 | ||
| 331 | crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, alg); | 380 | crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, alg); |
| 332 | list_del_init(&alg->cra_list); | 381 | list_del_init(&alg->cra_list); |
| 333 | crypto_remove_spawns(&alg->cra_users, list, alg->cra_flags); | 382 | crypto_remove_spawns(alg, list, NULL); |
| 334 | 383 | ||
| 335 | return 0; | 384 | return 0; |
| 336 | } | 385 | } |
