io_uring: fix ltimeout unprep
[platform/kernel/linux-starfive.git] / fs / ksmbd / crypto_ctx.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *   Copyright (C) 2019 Samsung Electronics Co., Ltd.
4  */
5
6 #include <linux/kernel.h>
7 #include <linux/string.h>
8 #include <linux/err.h>
9 #include <linux/slab.h>
10 #include <linux/wait.h>
11 #include <linux/sched.h>
12
13 #include "glob.h"
14 #include "crypto_ctx.h"
15
16 struct crypto_ctx_list {
17         spinlock_t              ctx_lock;
18         int                     avail_ctx;
19         struct list_head        idle_ctx;
20         wait_queue_head_t       ctx_wait;
21 };
22
23 static struct crypto_ctx_list ctx_list;
24
25 static inline void free_aead(struct crypto_aead *aead)
26 {
27         if (aead)
28                 crypto_free_aead(aead);
29 }
30
31 static void free_shash(struct shash_desc *shash)
32 {
33         if (shash) {
34                 crypto_free_shash(shash->tfm);
35                 kfree(shash);
36         }
37 }
38
39 static struct crypto_aead *alloc_aead(int id)
40 {
41         struct crypto_aead *tfm = NULL;
42
43         switch (id) {
44         case CRYPTO_AEAD_AES_GCM:
45                 tfm = crypto_alloc_aead("gcm(aes)", 0, 0);
46                 break;
47         case CRYPTO_AEAD_AES_CCM:
48                 tfm = crypto_alloc_aead("ccm(aes)", 0, 0);
49                 break;
50         default:
51                 pr_err("Does not support encrypt ahead(id : %d)\n", id);
52                 return NULL;
53         }
54
55         if (IS_ERR(tfm)) {
56                 pr_err("Failed to alloc encrypt aead : %ld\n", PTR_ERR(tfm));
57                 return NULL;
58         }
59
60         return tfm;
61 }
62
63 static struct shash_desc *alloc_shash_desc(int id)
64 {
65         struct crypto_shash *tfm = NULL;
66         struct shash_desc *shash;
67
68         switch (id) {
69         case CRYPTO_SHASH_HMACMD5:
70                 tfm = crypto_alloc_shash("hmac(md5)", 0, 0);
71                 break;
72         case CRYPTO_SHASH_HMACSHA256:
73                 tfm = crypto_alloc_shash("hmac(sha256)", 0, 0);
74                 break;
75         case CRYPTO_SHASH_CMACAES:
76                 tfm = crypto_alloc_shash("cmac(aes)", 0, 0);
77                 break;
78         case CRYPTO_SHASH_SHA256:
79                 tfm = crypto_alloc_shash("sha256", 0, 0);
80                 break;
81         case CRYPTO_SHASH_SHA512:
82                 tfm = crypto_alloc_shash("sha512", 0, 0);
83                 break;
84         case CRYPTO_SHASH_MD4:
85                 tfm = crypto_alloc_shash("md4", 0, 0);
86                 break;
87         case CRYPTO_SHASH_MD5:
88                 tfm = crypto_alloc_shash("md5", 0, 0);
89                 break;
90         default:
91                 return NULL;
92         }
93
94         if (IS_ERR(tfm))
95                 return NULL;
96
97         shash = kzalloc(sizeof(*shash) + crypto_shash_descsize(tfm),
98                         GFP_KERNEL);
99         if (!shash)
100                 crypto_free_shash(tfm);
101         else
102                 shash->tfm = tfm;
103         return shash;
104 }
105
106 static void ctx_free(struct ksmbd_crypto_ctx *ctx)
107 {
108         int i;
109
110         for (i = 0; i < CRYPTO_SHASH_MAX; i++)
111                 free_shash(ctx->desc[i]);
112         for (i = 0; i < CRYPTO_AEAD_MAX; i++)
113                 free_aead(ctx->ccmaes[i]);
114         kfree(ctx);
115 }
116
117 static struct ksmbd_crypto_ctx *ksmbd_find_crypto_ctx(void)
118 {
119         struct ksmbd_crypto_ctx *ctx;
120
121         while (1) {
122                 spin_lock(&ctx_list.ctx_lock);
123                 if (!list_empty(&ctx_list.idle_ctx)) {
124                         ctx = list_entry(ctx_list.idle_ctx.next,
125                                          struct ksmbd_crypto_ctx,
126                                          list);
127                         list_del(&ctx->list);
128                         spin_unlock(&ctx_list.ctx_lock);
129                         return ctx;
130                 }
131
132                 if (ctx_list.avail_ctx > num_online_cpus()) {
133                         spin_unlock(&ctx_list.ctx_lock);
134                         wait_event(ctx_list.ctx_wait,
135                                    !list_empty(&ctx_list.idle_ctx));
136                         continue;
137                 }
138
139                 ctx_list.avail_ctx++;
140                 spin_unlock(&ctx_list.ctx_lock);
141
142                 ctx = kzalloc(sizeof(struct ksmbd_crypto_ctx), GFP_KERNEL);
143                 if (!ctx) {
144                         spin_lock(&ctx_list.ctx_lock);
145                         ctx_list.avail_ctx--;
146                         spin_unlock(&ctx_list.ctx_lock);
147                         wait_event(ctx_list.ctx_wait,
148                                    !list_empty(&ctx_list.idle_ctx));
149                         continue;
150                 }
151                 break;
152         }
153         return ctx;
154 }
155
156 void ksmbd_release_crypto_ctx(struct ksmbd_crypto_ctx *ctx)
157 {
158         if (!ctx)
159                 return;
160
161         spin_lock(&ctx_list.ctx_lock);
162         if (ctx_list.avail_ctx <= num_online_cpus()) {
163                 list_add(&ctx->list, &ctx_list.idle_ctx);
164                 spin_unlock(&ctx_list.ctx_lock);
165                 wake_up(&ctx_list.ctx_wait);
166                 return;
167         }
168
169         ctx_list.avail_ctx--;
170         spin_unlock(&ctx_list.ctx_lock);
171         ctx_free(ctx);
172 }
173
174 static struct ksmbd_crypto_ctx *____crypto_shash_ctx_find(int id)
175 {
176         struct ksmbd_crypto_ctx *ctx;
177
178         if (id >= CRYPTO_SHASH_MAX)
179                 return NULL;
180
181         ctx = ksmbd_find_crypto_ctx();
182         if (ctx->desc[id])
183                 return ctx;
184
185         ctx->desc[id] = alloc_shash_desc(id);
186         if (ctx->desc[id])
187                 return ctx;
188         ksmbd_release_crypto_ctx(ctx);
189         return NULL;
190 }
191
192 struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_hmacmd5(void)
193 {
194         return ____crypto_shash_ctx_find(CRYPTO_SHASH_HMACMD5);
195 }
196
197 struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_hmacsha256(void)
198 {
199         return ____crypto_shash_ctx_find(CRYPTO_SHASH_HMACSHA256);
200 }
201
202 struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_cmacaes(void)
203 {
204         return ____crypto_shash_ctx_find(CRYPTO_SHASH_CMACAES);
205 }
206
207 struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_sha256(void)
208 {
209         return ____crypto_shash_ctx_find(CRYPTO_SHASH_SHA256);
210 }
211
212 struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_sha512(void)
213 {
214         return ____crypto_shash_ctx_find(CRYPTO_SHASH_SHA512);
215 }
216
217 struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_md4(void)
218 {
219         return ____crypto_shash_ctx_find(CRYPTO_SHASH_MD4);
220 }
221
222 struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_md5(void)
223 {
224         return ____crypto_shash_ctx_find(CRYPTO_SHASH_MD5);
225 }
226
227 static struct ksmbd_crypto_ctx *____crypto_aead_ctx_find(int id)
228 {
229         struct ksmbd_crypto_ctx *ctx;
230
231         if (id >= CRYPTO_AEAD_MAX)
232                 return NULL;
233
234         ctx = ksmbd_find_crypto_ctx();
235         if (ctx->ccmaes[id])
236                 return ctx;
237
238         ctx->ccmaes[id] = alloc_aead(id);
239         if (ctx->ccmaes[id])
240                 return ctx;
241         ksmbd_release_crypto_ctx(ctx);
242         return NULL;
243 }
244
245 struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_gcm(void)
246 {
247         return ____crypto_aead_ctx_find(CRYPTO_AEAD_AES_GCM);
248 }
249
250 struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_ccm(void)
251 {
252         return ____crypto_aead_ctx_find(CRYPTO_AEAD_AES_CCM);
253 }
254
255 void ksmbd_crypto_destroy(void)
256 {
257         struct ksmbd_crypto_ctx *ctx;
258
259         while (!list_empty(&ctx_list.idle_ctx)) {
260                 ctx = list_entry(ctx_list.idle_ctx.next,
261                                  struct ksmbd_crypto_ctx,
262                                  list);
263                 list_del(&ctx->list);
264                 ctx_free(ctx);
265         }
266 }
267
268 int ksmbd_crypto_create(void)
269 {
270         struct ksmbd_crypto_ctx *ctx;
271
272         spin_lock_init(&ctx_list.ctx_lock);
273         INIT_LIST_HEAD(&ctx_list.idle_ctx);
274         init_waitqueue_head(&ctx_list.ctx_wait);
275         ctx_list.avail_ctx = 1;
276
277         ctx = kzalloc(sizeof(struct ksmbd_crypto_ctx), GFP_KERNEL);
278         if (!ctx)
279                 return -ENOMEM;
280         list_add(&ctx->list, &ctx_list.idle_ctx);
281         return 0;
282 }