dm-crypt: use __bio_add_page to add single page to clone bio
[linux-block.git] / fs / ksmbd / crypto_ctx.c
CommitLineData
e2f34481
NJ
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>
e2f34481
NJ
12
13#include "glob.h"
14#include "crypto_ctx.h"
e2f34481
NJ
15
16struct 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
23static struct crypto_ctx_list ctx_list;
24
25static inline void free_aead(struct crypto_aead *aead)
26{
27 if (aead)
28 crypto_free_aead(aead);
29}
30
31static void free_shash(struct shash_desc *shash)
32{
33 if (shash) {
34 crypto_free_shash(shash->tfm);
35 kfree(shash);
36 }
37}
38
39static struct crypto_aead *alloc_aead(int id)
40{
41 struct crypto_aead *tfm = NULL;
42
43 switch (id) {
5a0ca770 44 case CRYPTO_AEAD_AES_GCM:
e2f34481
NJ
45 tfm = crypto_alloc_aead("gcm(aes)", 0, 0);
46 break;
5a0ca770 47 case CRYPTO_AEAD_AES_CCM:
e2f34481
NJ
48 tfm = crypto_alloc_aead("ccm(aes)", 0, 0);
49 break;
50 default:
bde1694a 51 pr_err("Does not support encrypt ahead(id : %d)\n", id);
e2f34481
NJ
52 return NULL;
53 }
54
55 if (IS_ERR(tfm)) {
bde1694a 56 pr_err("Failed to alloc encrypt aead : %ld\n", PTR_ERR(tfm));
e2f34481
NJ
57 return NULL;
58 }
59
60 return tfm;
61}
62
63static 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;
533a45da
NJ
84 default:
85 return NULL;
e2f34481
NJ
86 }
87
88 if (IS_ERR(tfm))
89 return NULL;
90
91 shash = kzalloc(sizeof(*shash) + crypto_shash_descsize(tfm),
92 GFP_KERNEL);
93 if (!shash)
94 crypto_free_shash(tfm);
95 else
96 shash->tfm = tfm;
97 return shash;
98}
99
e2f34481
NJ
100static void ctx_free(struct ksmbd_crypto_ctx *ctx)
101{
102 int i;
103
104 for (i = 0; i < CRYPTO_SHASH_MAX; i++)
105 free_shash(ctx->desc[i]);
106 for (i = 0; i < CRYPTO_AEAD_MAX; i++)
107 free_aead(ctx->ccmaes[i]);
79f6b11a 108 kfree(ctx);
e2f34481
NJ
109}
110
111static struct ksmbd_crypto_ctx *ksmbd_find_crypto_ctx(void)
112{
113 struct ksmbd_crypto_ctx *ctx;
114
115 while (1) {
116 spin_lock(&ctx_list.ctx_lock);
117 if (!list_empty(&ctx_list.idle_ctx)) {
118 ctx = list_entry(ctx_list.idle_ctx.next,
070fb21e
NJ
119 struct ksmbd_crypto_ctx,
120 list);
e2f34481
NJ
121 list_del(&ctx->list);
122 spin_unlock(&ctx_list.ctx_lock);
123 return ctx;
124 }
125
126 if (ctx_list.avail_ctx > num_online_cpus()) {
127 spin_unlock(&ctx_list.ctx_lock);
128 wait_event(ctx_list.ctx_wait,
129 !list_empty(&ctx_list.idle_ctx));
130 continue;
131 }
132
133 ctx_list.avail_ctx++;
134 spin_unlock(&ctx_list.ctx_lock);
135
12fc7044 136 ctx = kzalloc(sizeof(struct ksmbd_crypto_ctx), GFP_KERNEL);
e2f34481
NJ
137 if (!ctx) {
138 spin_lock(&ctx_list.ctx_lock);
139 ctx_list.avail_ctx--;
140 spin_unlock(&ctx_list.ctx_lock);
141 wait_event(ctx_list.ctx_wait,
142 !list_empty(&ctx_list.idle_ctx));
143 continue;
144 }
145 break;
146 }
147 return ctx;
148}
149
150void ksmbd_release_crypto_ctx(struct ksmbd_crypto_ctx *ctx)
151{
152 if (!ctx)
153 return;
154
155 spin_lock(&ctx_list.ctx_lock);
156 if (ctx_list.avail_ctx <= num_online_cpus()) {
157 list_add(&ctx->list, &ctx_list.idle_ctx);
158 spin_unlock(&ctx_list.ctx_lock);
159 wake_up(&ctx_list.ctx_wait);
160 return;
161 }
162
163 ctx_list.avail_ctx--;
164 spin_unlock(&ctx_list.ctx_lock);
165 ctx_free(ctx);
166}
167
168static struct ksmbd_crypto_ctx *____crypto_shash_ctx_find(int id)
169{
170 struct ksmbd_crypto_ctx *ctx;
171
172 if (id >= CRYPTO_SHASH_MAX)
173 return NULL;
174
175 ctx = ksmbd_find_crypto_ctx();
176 if (ctx->desc[id])
177 return ctx;
178
179 ctx->desc[id] = alloc_shash_desc(id);
180 if (ctx->desc[id])
181 return ctx;
182 ksmbd_release_crypto_ctx(ctx);
183 return NULL;
184}
185
186struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_hmacmd5(void)
187{
188 return ____crypto_shash_ctx_find(CRYPTO_SHASH_HMACMD5);
189}
190
191struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_hmacsha256(void)
192{
193 return ____crypto_shash_ctx_find(CRYPTO_SHASH_HMACSHA256);
194}
195
196struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_cmacaes(void)
197{
198 return ____crypto_shash_ctx_find(CRYPTO_SHASH_CMACAES);
199}
200
201struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_sha256(void)
202{
203 return ____crypto_shash_ctx_find(CRYPTO_SHASH_SHA256);
204}
205
206struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_sha512(void)
207{
208 return ____crypto_shash_ctx_find(CRYPTO_SHASH_SHA512);
209}
210
e2f34481
NJ
211static struct ksmbd_crypto_ctx *____crypto_aead_ctx_find(int id)
212{
213 struct ksmbd_crypto_ctx *ctx;
214
215 if (id >= CRYPTO_AEAD_MAX)
216 return NULL;
217
218 ctx = ksmbd_find_crypto_ctx();
219 if (ctx->ccmaes[id])
220 return ctx;
221
222 ctx->ccmaes[id] = alloc_aead(id);
223 if (ctx->ccmaes[id])
224 return ctx;
225 ksmbd_release_crypto_ctx(ctx);
226 return NULL;
227}
228
229struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_gcm(void)
230{
5a0ca770 231 return ____crypto_aead_ctx_find(CRYPTO_AEAD_AES_GCM);
e2f34481
NJ
232}
233
234struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_ccm(void)
235{
5a0ca770 236 return ____crypto_aead_ctx_find(CRYPTO_AEAD_AES_CCM);
e2f34481
NJ
237}
238
239void ksmbd_crypto_destroy(void)
240{
241 struct ksmbd_crypto_ctx *ctx;
242
243 while (!list_empty(&ctx_list.idle_ctx)) {
244 ctx = list_entry(ctx_list.idle_ctx.next,
245 struct ksmbd_crypto_ctx,
246 list);
247 list_del(&ctx->list);
248 ctx_free(ctx);
249 }
250}
251
252int ksmbd_crypto_create(void)
253{
254 struct ksmbd_crypto_ctx *ctx;
255
256 spin_lock_init(&ctx_list.ctx_lock);
257 INIT_LIST_HEAD(&ctx_list.idle_ctx);
258 init_waitqueue_head(&ctx_list.ctx_wait);
259 ctx_list.avail_ctx = 1;
260
12fc7044 261 ctx = kzalloc(sizeof(struct ksmbd_crypto_ctx), GFP_KERNEL);
e2f34481
NJ
262 if (!ctx)
263 return -ENOMEM;
264 list_add(&ctx->list, &ctx_list.idle_ctx);
265 return 0;
266}