Commit | Line | Data |
---|---|---|
2ad5939e BK |
1 | /* |
2 | * Copyright (C) 2017 Samsung Electronics Co., Ltd. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License as published by | |
6 | * the Free Software Foundation; either version 2 of the License, or | |
7 | * (at your option) any later version. | |
8 | */ | |
9 | ||
10 | #include <linux/kernel.h> | |
11 | #include <linux/blkdev.h> | |
12 | #include <linux/errno.h> | |
13 | #include <linux/module.h> | |
14 | #include <linux/seq_file.h> | |
15 | #include <linux/string.h> | |
16 | #include <linux/crypto.h> | |
17 | #include <crypto/algapi.h> | |
18 | #include <crypto/diskcipher.h> | |
37cd97e0 | 19 | #include <linux/delay.h> |
2ad5939e BK |
20 | |
21 | #include "internal.h" | |
22 | ||
37cd97e0 | 23 | #ifdef CONFIG_CRYPTO_DISKCIPHER_DEBUG |
2ad5939e BK |
24 | #include <crypto/fmp.h> |
25 | #include <linux/mm_types.h> | |
37cd97e0 BK |
26 | #include <linux/fs.h> |
27 | #include <linux/fscrypt.h> | |
2ad5939e BK |
28 | |
29 | #define DUMP_MAX 20 | |
30 | ||
2ad5939e BK |
31 | struct dump_err { |
32 | struct page *page; | |
33 | struct bio bio; | |
34 | struct fmp_crypto_info ci; | |
37cd97e0 | 35 | enum diskcipher_dbg api; |
2ad5939e BK |
36 | }; |
37 | ||
38 | struct diskc_debug_info { | |
39 | struct dump_err dump[DUMP_MAX]; | |
40 | int err; | |
37cd97e0 | 41 | int cnt[DISKC_USER_MAX][2]; |
2ad5939e BK |
42 | }; |
43 | ||
44 | static struct diskc_debug_info diskc_dbg; | |
45 | ||
37cd97e0 BK |
46 | void crypto_diskcipher_debug(enum diskcipher_dbg api, int bi_opf) |
47 | { | |
48 | int idx = 0; | |
49 | struct diskc_debug_info *dbg = &diskc_dbg; | |
50 | ||
51 | if (api <= DISKC_API_MAX) | |
52 | dbg->cnt[api][bi_opf]++; | |
53 | else { | |
49e3bbe3 | 54 | if (bi_opf) |
37cd97e0 BK |
55 | idx = 1; |
56 | dbg->cnt[api][idx]++; | |
57 | } | |
58 | } | |
59 | ||
2ad5939e BK |
60 | static void print_err(void) |
61 | { | |
62 | int i, j; | |
63 | struct bio_vec *bv; /* bio page list */ | |
64 | struct bio *bio; | |
65 | struct fmp_crypto_info *ci; | |
66 | struct diskc_debug_info *dbg = &diskc_dbg; | |
67 | ||
68 | for (j = 0; j < dbg->err; j++) { | |
69 | bio = &dbg->dump[j].bio; | |
70 | ci = &dbg->dump[j].ci; | |
71 | ||
72 | if (bio) { | |
73 | pr_info | |
74 | ("%s(%d/%d): bio:%p ci:%p page:%p flag:%x, opf:%x, crypt:%p\n", | |
75 | __func__, j, dbg->err, bio, ci, &dbg->dump[j].page, | |
76 | bio->bi_flags, bio->bi_opf, bio->bi_aux_private); | |
77 | print_hex_dump(KERN_CONT, "bio:", DUMP_PREFIX_OFFSET, | |
78 | 16, 1, bio, sizeof(struct bio), false); | |
79 | for (i = 0; i < bio->bi_max_vecs; i++) { | |
80 | bv = &bio->bi_io_vec[i]; | |
81 | pr_info("bv[%d] page:%p len:%d offset:%d\n", | |
82 | i, bv->bv_page, bv->bv_len, bv->bv_offset); | |
83 | } | |
84 | } | |
85 | ||
86 | if (ci) { | |
87 | pr_info("[ci] key_size:%d algo_mode:%d\n", | |
88 | ci->key_size, ci->algo_mode); | |
89 | print_hex_dump(KERN_CONT, "key:", DUMP_PREFIX_OFFSET, | |
90 | 16, 1, ci->key, sizeof(ci->key), false); | |
91 | } | |
92 | } | |
93 | } | |
94 | ||
37cd97e0 | 95 | static void dump_err(struct crypto_diskcipher *ci, enum diskcipher_dbg api, |
2ad5939e BK |
96 | struct bio *bio, struct page *page) |
97 | { | |
98 | struct diskc_debug_info *dbg = &diskc_dbg; | |
99 | ||
100 | if ((dbg->err < DUMP_MAX) && ci) { | |
101 | struct crypto_tfm *tfm = crypto_diskcipher_tfm(ci); | |
102 | ||
103 | dbg->dump[dbg->err].api = api; | |
104 | memcpy(&dbg->dump[dbg->err].ci, crypto_tfm_ctx(tfm), | |
105 | sizeof(struct fmp_crypto_info)); | |
106 | ||
107 | if (page) | |
108 | dbg->dump[dbg->err].page = page; | |
109 | if (bio) | |
110 | memcpy(&dbg->dump[dbg->err].bio, bio, | |
111 | sizeof(struct bio)); | |
112 | } | |
113 | dbg->err++; | |
114 | } | |
115 | ||
2ad5939e BK |
116 | static void disckipher_log_show(struct seq_file *m) |
117 | { | |
118 | int i; | |
2ad5939e | 119 | struct diskc_debug_info *dbg = &diskc_dbg; |
49e3bbe3 BK |
120 | char name[DISKC_USER_MAX][32] = { |
121 | "ALLOC", "FREE", "FREEREQ", "SETKEY", "SET", "GET", "CRYPT", "CLEAR", | |
122 | "DISKC_API_MAX", "FS_PAGEIO", "FS_READP", "FS_DIO", "FS_BLOCK_WRITE", | |
123 | "FS_ZEROPAGE", "BLK_BH", "DMCRYPT", "DISKC_MERGE", "DISKC_MERGE_ERR_INODE", "DISKC_MERGE_ERR_DISK", | |
124 | "FS_DEC_WARN", "FS_ENC_WARN", "DISKC_MERGE_DIO", "DISKC_FREE_REQ_WARN", | |
125 | "DISKC_FREE_WQ_WARN", "DISKC_CRYPT_WARN", | |
126 | "DM_CRYPT_NONENCRYPT", "DM_CRYPT_CTR", "DM_CRYPT_DTR", "DM_CRYPT_OVER", | |
127 | "F2FS_gc", "F2FS_gc_data_page", "F2FS_gc_data_page_no_key", "F2FS_gc_data_page_no_key_FC", | |
128 | "F2FS_gc_data_page_FC", "F2FS_gc_data_block", "F2FS_gc_data_block_key", | |
129 | "F2FS_gc_data_block_err1", "F2FS_gc_data_block_err2", "F2FS_gc_data_block_err3", "F2FS_gc_skip", | |
130 | "DISKC_ERR", "DISKC_NO_KEY_ERR", "DISKC_NO_SYNC_ERR", "DISKC_NO_CRYPT_ERR", "DISKC_NO_DISKC_ERR"}; | |
37cd97e0 BK |
131 | |
132 | for (i = 0; i < DISKC_USER_MAX; i++) | |
133 | if (dbg->cnt[i][0] || dbg->cnt[i][1]) | |
134 | seq_printf(m, "%s\t: %6u(err:%u)\n", | |
135 | name[i], dbg->cnt[i][0], dbg->cnt[i][1]); | |
2ad5939e BK |
136 | |
137 | if (dbg->err) | |
138 | print_err(); | |
139 | } | |
140 | ||
141 | /* check diskcipher for FBE */ | |
37cd97e0 | 142 | #define DISKC_FS_ENCRYPT_DEBUG |
37cd97e0 | 143 | #ifdef DISKC_FS_ENCRYPT_DEBUG |
49e3bbe3 BK |
144 | static bool crypto_diskcipher_check(struct bio *bio) |
145 | { | |
2ad5939e BK |
146 | int ret = 0; |
147 | struct crypto_diskcipher *ci = NULL; | |
37cd97e0 | 148 | struct inode *inode = NULL; |
c99b5690 | 149 | struct page *page = NULL; |
2ad5939e | 150 | |
c99b5690 | 151 | if (!bio) { |
152 | pr_err("%s: doesn't exist bio\n", __func__); | |
153 | goto out; | |
154 | } | |
155 | ||
156 | page = bio->bi_io_vec[0].bv_page; | |
2ad5939e BK |
157 | if (page && !PageAnon(page) && bio) |
158 | if (page->mapping) | |
49e3bbe3 | 159 | if (page->mapping->host) { |
2ad5939e | 160 | if (page->mapping->host->i_crypt_info) { |
37cd97e0 | 161 | inode = page->mapping->host; |
49e3bbe3 | 162 | ci = fscrypt_get_diskcipher(inode); |
2ad5939e BK |
163 | if (ci && (bio->bi_aux_private != ci) |
164 | && (!(bio->bi_flags & REQ_OP_DISCARD))) { | |
49e3bbe3 | 165 | pr_err("%s: no sync err\n", __func__); |
2ad5939e | 166 | dump_err(ci, DISKC_API_GET, bio, page); |
49e3bbe3 BK |
167 | crypto_diskcipher_debug(DISKC_NO_SYNC_ERR, 0); |
168 | ret = -EINVAL; | |
37cd97e0 | 169 | } |
49e3bbe3 BK |
170 | if (!ci) { |
171 | crypto_diskcipher_debug(DISKC_NO_DISKC_ERR, 1); | |
172 | pr_err("%s: no crypt err\n", __func__); | |
173 | ret = -EINVAL; | |
2ad5939e | 174 | } |
49e3bbe3 BK |
175 | } else { |
176 | crypto_diskcipher_debug(DISKC_NO_KEY_ERR, 1); | |
177 | ret = -EINVAL; | |
2ad5939e | 178 | } |
49e3bbe3 | 179 | } |
c99b5690 | 180 | out: |
37cd97e0 | 181 | crypto_diskcipher_debug(DISKC_API_GET, ret); |
49e3bbe3 | 182 | return ret; |
2ad5939e BK |
183 | } |
184 | #else | |
49e3bbe3 BK |
185 | #define crypto_diskcipher_check(a) ((void)0) |
186 | #endif | |
187 | #else | |
188 | #define crypto_diskcipher_check(a) (0) | |
2ad5939e | 189 | #define disckipher_log_show(a) do { } while (0) |
2ad5939e BK |
190 | #endif |
191 | ||
2ad5939e BK |
192 | struct crypto_diskcipher *crypto_diskcipher_get(struct bio *bio) |
193 | { | |
194 | if (!bio || !virt_addr_valid(bio)) { | |
195 | pr_err("%s: Invalid bio:%p\n", __func__, bio); | |
196 | return NULL; | |
197 | } | |
49e3bbe3 BK |
198 | |
199 | if (bio->bi_opf & REQ_CRYPT) { | |
200 | if (bio->bi_aux_private) { | |
201 | if (!crypto_diskcipher_check(bio)) | |
202 | return bio->bi_aux_private; | |
203 | else | |
204 | return ERR_PTR(-EINVAL); | |
205 | } else { | |
206 | crypto_diskcipher_debug(DISKC_NO_CRYPT_ERR, 0); | |
207 | return ERR_PTR(-EINVAL); | |
208 | } | |
209 | } | |
210 | ||
211 | return NULL; | |
212 | } | |
213 | ||
214 | struct inode *crypto_diskcipher_get_inode(struct bio *bio) | |
215 | { | |
216 | struct crypto_diskcipher *tfm; | |
217 | ||
218 | if (bio->bi_opf & REQ_CRYPT) { | |
219 | tfm = bio->bi_aux_private; | |
220 | return tfm->inode; | |
221 | } else { | |
2ad5939e | 222 | return NULL; |
49e3bbe3 | 223 | } |
2ad5939e BK |
224 | } |
225 | ||
49e3bbe3 BK |
226 | void crypto_diskcipher_set(struct bio *bio, struct crypto_diskcipher *tfm, |
227 | const struct inode *inode, u64 dun) | |
2ad5939e | 228 | { |
37cd97e0 | 229 | if (bio && tfm) { |
e4bdfe04 | 230 | bio->bi_opf |= REQ_CRYPT; |
37cd97e0 | 231 | bio->bi_aux_private = tfm; |
49e3bbe3 BK |
232 | tfm->inode = (struct inode *)inode; |
233 | #ifdef CONFIG_CRYPTO_DISKCIPHER_DUN | |
234 | if (dun) | |
235 | bio->bi_iter.bi_dun = dun; | |
236 | #endif | |
2ad5939e | 237 | } |
37cd97e0 | 238 | crypto_diskcipher_debug(DISKC_API_SET, 0); |
2ad5939e BK |
239 | } |
240 | ||
37cd97e0 BK |
241 | /* debug freerq */ |
242 | enum diskc_status { | |
243 | DISKC_ST_INIT, | |
244 | DISKC_ST_FREE_REQ, | |
245 | DISKC_ST_FREE, | |
246 | }; | |
49e3bbe3 | 247 | |
2ad5939e BK |
248 | int crypto_diskcipher_setkey(struct crypto_diskcipher *tfm, const char *in_key, |
249 | unsigned int key_len, bool persistent) | |
250 | { | |
251 | struct crypto_tfm *base = crypto_diskcipher_tfm(tfm); | |
252 | struct diskcipher_alg *cra = crypto_diskcipher_alg(base->__crt_alg); | |
253 | ||
254 | if (!cra) { | |
c99b5690 | 255 | pr_err("%s: doesn't exist cra. base:%p", __func__, base); |
2ad5939e BK |
256 | return -EINVAL; |
257 | } | |
37cd97e0 BK |
258 | |
259 | crypto_diskcipher_debug(DISKC_API_SETKEY, 0); | |
2ad5939e BK |
260 | return cra->setkey(base, in_key, key_len, persistent); |
261 | } | |
262 | ||
263 | int crypto_diskcipher_clearkey(struct crypto_diskcipher *tfm) | |
264 | { | |
265 | struct crypto_tfm *base = crypto_diskcipher_tfm(tfm); | |
266 | struct diskcipher_alg *cra = crypto_diskcipher_alg(base->__crt_alg); | |
267 | ||
268 | if (!cra) { | |
c99b5690 | 269 | pr_err("%s: doesn't exist cra. base:%p", __func__, base); |
2ad5939e BK |
270 | return -EINVAL; |
271 | } | |
272 | return cra->clearkey(base); | |
273 | } | |
274 | ||
275 | int crypto_diskcipher_set_crypt(struct crypto_diskcipher *tfm, void *req) | |
276 | { | |
277 | int ret = 0; | |
278 | struct crypto_tfm *base = crypto_diskcipher_tfm(tfm); | |
c99b5690 | 279 | struct diskcipher_alg *cra = NULL; |
280 | ||
a87c4fbf BK |
281 | if (!base || (base && !virt_addr_valid(base))) { |
282 | pr_err("%s: doesn't exist base, tfm:%p, base:%p(vaild:%d)\n", | |
283 | __func__, tfm, base, virt_addr_valid(base)); | |
c99b5690 | 284 | ret = -EINVAL; |
285 | goto out; | |
286 | } | |
287 | ||
288 | cra = crypto_diskcipher_alg(base->__crt_alg); | |
2ad5939e | 289 | if (!cra) { |
a87c4fbf | 290 | pr_err("%s: doesn't exist cra:%p base:%p\n",__func__, cra, base); |
c99b5690 | 291 | ret = -EINVAL; |
2ad5939e BK |
292 | goto out; |
293 | } | |
294 | ||
37cd97e0 BK |
295 | if (atomic_read(&tfm->status) == DISKC_ST_FREE) { |
296 | pr_err("%s: tfm is free\n", __func__); | |
297 | crypto_diskcipher_debug(DISKC_CRYPT_WARN, 0); | |
298 | return -EINVAL; | |
299 | } | |
300 | ||
2ad5939e | 301 | ret = cra->crypt(base, req); |
91b23ddd BK |
302 | #ifdef USE_FREE_REQ |
303 | if (!list_empty(&cra->freectrl.freelist)) { | |
304 | if (!atomic_read(&cra->freectrl.freewq_active)) { | |
305 | atomic_set(&cra->freectrl.freewq_active, 1); | |
306 | schedule_delayed_work(&cra->freectrl.freewq, 0); | |
37cd97e0 BK |
307 | } |
308 | } | |
91b23ddd | 309 | #endif |
2ad5939e BK |
310 | out: |
311 | if (ret) | |
312 | pr_err("%s fails ret:%d, cra:%p\n", __func__, ret, cra); | |
37cd97e0 | 313 | crypto_diskcipher_debug(DISKC_API_CRYPT, ret); |
2ad5939e BK |
314 | return ret; |
315 | } | |
316 | ||
317 | int crypto_diskcipher_clear_crypt(struct crypto_diskcipher *tfm, void *req) | |
318 | { | |
319 | int ret = 0; | |
320 | struct crypto_tfm *base = crypto_diskcipher_tfm(tfm); | |
c99b5690 | 321 | struct diskcipher_alg *cra = NULL; |
322 | ||
a87c4fbf BK |
323 | if (!base || (base && !virt_addr_valid(base))) { |
324 | pr_err("%s: doesn't exist base, tfm:%p, base:%p(vaild:%d)\n", | |
325 | __func__, tfm, base, virt_addr_valid(base)); | |
c99b5690 | 326 | ret = -EINVAL; |
327 | goto out; | |
328 | } | |
329 | ||
330 | cra = crypto_diskcipher_alg(base->__crt_alg); | |
2ad5939e | 331 | if (!cra) { |
a87c4fbf | 332 | pr_err("%s: doesn't exist cra:%p base:%p\n",__func__, cra, base); |
c99b5690 | 333 | ret = -EINVAL; |
2ad5939e BK |
334 | goto out; |
335 | } | |
336 | ||
c99b5690 | 337 | if (atomic_read(&tfm->status) == DISKC_ST_FREE) { |
338 | pr_warn("%s: tfm is free\n", __func__); | |
339 | return -EINVAL; | |
340 | } | |
341 | ||
2ad5939e BK |
342 | ret = cra->clear(base, req); |
343 | if (ret) | |
344 | pr_err("%s fails", __func__); | |
345 | ||
346 | out: | |
37cd97e0 | 347 | crypto_diskcipher_debug(DISKC_API_CLEAR, ret); |
2ad5939e BK |
348 | return ret; |
349 | } | |
350 | ||
351 | #ifndef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS | |
352 | int diskcipher_do_crypt(struct crypto_diskcipher *tfm, | |
353 | struct diskcipher_test_request *req) | |
354 | { | |
355 | int ret; | |
356 | struct crypto_tfm *base = crypto_diskcipher_tfm(tfm); | |
357 | struct diskcipher_alg *cra = crypto_diskcipher_alg(base->__crt_alg); | |
358 | ||
359 | if (!cra) { | |
c99b5690 | 360 | pr_err("%s: doesn't exist cra. base:%p\n", __func__, base); |
361 | ret = -EINVAL; | |
2ad5939e BK |
362 | goto out; |
363 | } | |
364 | ||
365 | if (cra->do_crypt) | |
366 | ret = cra->do_crypt(base, req); | |
367 | else | |
368 | ret = -EINVAL; | |
369 | if (ret) | |
370 | pr_err("%s fails ret:%d", __func__, ret); | |
371 | ||
372 | out: | |
2ad5939e BK |
373 | return ret; |
374 | } | |
375 | #endif | |
376 | ||
37cd97e0 | 377 | static int crypto_diskcipher_init_tfm(struct crypto_tfm *base) |
2ad5939e | 378 | { |
37cd97e0 BK |
379 | struct crypto_diskcipher *tfm = __crypto_diskcipher_cast(base); |
380 | ||
37cd97e0 | 381 | atomic_set(&tfm->status, DISKC_ST_INIT); |
2ad5939e BK |
382 | return 0; |
383 | } | |
384 | ||
91b23ddd | 385 | #ifdef USE_FREE_REQ |
37cd97e0 BK |
386 | static void free_workq_func(struct work_struct *work) |
387 | { | |
388 | struct diskcipher_alg *cra = | |
389 | container_of(work, struct diskcipher_alg, freectrl.freewq.work); | |
390 | struct diskcipher_freectrl *fctrl = &cra->freectrl; | |
391 | struct crypto_diskcipher *_tfm, *tmp; | |
392 | unsigned long cur_jiffies = jiffies; | |
393 | struct list_head poss_free_list; | |
394 | unsigned long flags; | |
395 | ||
396 | INIT_LIST_HEAD(&poss_free_list); | |
397 | ||
398 | /* pickup freelist */ | |
399 | spin_lock_irqsave(&fctrl->freelist_lock, flags); | |
400 | list_for_each_entry_safe(_tfm, tmp, &fctrl->freelist, node) { | |
401 | if (jiffies_to_msecs(cur_jiffies - _tfm->req_jiffies) > fctrl->max_io_ms) | |
402 | list_move_tail(&_tfm->node, &poss_free_list); | |
403 | } | |
404 | spin_unlock_irqrestore(&fctrl->freelist_lock, flags); | |
405 | ||
406 | list_for_each_entry_safe(_tfm, tmp, &poss_free_list, node) { | |
407 | if (atomic_read (&_tfm->status) != DISKC_ST_FREE_REQ) | |
408 | crypto_diskcipher_debug(DISKC_FREE_WQ_WARN, 0); | |
409 | crypto_free_diskcipher(_tfm); | |
410 | } | |
411 | ||
412 | if (!list_empty(&fctrl->freelist)) | |
413 | schedule_delayed_work(&fctrl->freewq, msecs_to_jiffies(fctrl->max_io_ms)); | |
414 | else | |
415 | atomic_set(&fctrl->freewq_active, 0); | |
416 | } | |
91b23ddd | 417 | #endif |
37cd97e0 BK |
418 | |
419 | void crypto_free_req_diskcipher(struct crypto_diskcipher *tfm) | |
420 | { | |
91b23ddd | 421 | #ifdef USE_FREE_REQ |
37cd97e0 BK |
422 | struct crypto_tfm *base = crypto_diskcipher_tfm(tfm); |
423 | struct diskcipher_alg *cra = crypto_diskcipher_alg(base->__crt_alg); | |
424 | struct diskcipher_freectrl *fctrl = &cra->freectrl; | |
425 | unsigned long flags; | |
426 | ||
427 | if (atomic_read(&tfm->status) != DISKC_ST_INIT) { | |
428 | crypto_diskcipher_debug(DISKC_FREE_REQ_WARN, 0); | |
429 | pr_warn("%s: already submit status:%d\n", __func__, atomic_read(&tfm->status)); | |
430 | return; | |
431 | } | |
432 | ||
433 | atomic_set(&tfm->status, DISKC_ST_FREE_REQ); | |
434 | INIT_LIST_HEAD(&tfm->node); | |
435 | tfm->req_jiffies = jiffies; | |
436 | spin_lock_irqsave(&fctrl->freelist_lock, flags); | |
437 | list_move_tail(&tfm->node, &fctrl->freelist); | |
438 | spin_unlock_irqrestore(&fctrl->freelist_lock, flags); | |
439 | crypto_diskcipher_debug(DISKC_API_FREEREQ, 0); | |
91b23ddd BK |
440 | #else |
441 | crypto_free_diskcipher(tfm); | |
442 | #endif | |
37cd97e0 BK |
443 | } |
444 | ||
2ad5939e BK |
445 | unsigned int crypto_diskcipher_extsize(struct crypto_alg *alg) |
446 | { | |
447 | return alg->cra_ctxsize + | |
448 | (alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1)); | |
449 | } | |
450 | ||
451 | static void crypto_diskcipher_show(struct seq_file *m, struct crypto_alg *alg) | |
452 | { | |
453 | seq_printf(m, "type : diskcipher\n"); | |
454 | disckipher_log_show(m); | |
455 | } | |
456 | ||
457 | static const struct crypto_type crypto_diskcipher_type = { | |
458 | .extsize = crypto_diskcipher_extsize, | |
459 | .init_tfm = crypto_diskcipher_init_tfm, | |
460 | #ifdef CONFIG_PROC_FS | |
461 | .show = crypto_diskcipher_show, | |
462 | #endif | |
463 | .maskclear = ~CRYPTO_ALG_TYPE_MASK, | |
464 | .maskset = CRYPTO_ALG_TYPE_MASK, | |
465 | .type = CRYPTO_ALG_TYPE_DISKCIPHER, | |
466 | .tfmsize = offsetof(struct crypto_diskcipher, base), | |
467 | }; | |
468 | ||
37cd97e0 BK |
469 | #define DISKC_NAME "-disk" |
470 | #define DISKC_NAME_SIZE (5) | |
471 | #define DISKCIPHER_MAX_IO_MS (1000) | |
2ad5939e BK |
472 | struct crypto_diskcipher *crypto_alloc_diskcipher(const char *alg_name, |
473 | u32 type, u32 mask, bool force) | |
474 | { | |
37cd97e0 | 475 | crypto_diskcipher_debug(DISKC_API_ALLOC, 0); |
2ad5939e BK |
476 | if (force) { |
477 | if (strlen(alg_name) + DISKC_NAME_SIZE < CRYPTO_MAX_ALG_NAME) { | |
478 | char diskc_name[CRYPTO_MAX_ALG_NAME]; | |
479 | ||
480 | strcpy(diskc_name, alg_name); | |
481 | strcat(diskc_name, DISKC_NAME); | |
482 | return crypto_alloc_tfm(diskc_name, | |
483 | &crypto_diskcipher_type, type, mask); | |
484 | } | |
485 | } else { | |
486 | return crypto_alloc_tfm(alg_name, &crypto_diskcipher_type, type, mask); | |
487 | } | |
2ad5939e BK |
488 | return NULL; |
489 | } | |
490 | ||
491 | void crypto_free_diskcipher(struct crypto_diskcipher *tfm) | |
492 | { | |
37cd97e0 BK |
493 | crypto_diskcipher_debug(DISKC_API_FREE, 0); |
494 | atomic_set(&tfm->status, DISKC_ST_FREE); | |
a87c4fbf BK |
495 | if (tfm && virt_addr_valid(tfm)) |
496 | crypto_destroy_tfm(tfm, crypto_diskcipher_tfm(tfm)); | |
497 | else | |
498 | pr_warn("%s: invalid tfm:%p(valid:%d)\n", __func__, tfm, virt_addr_valid(tfm)); | |
2ad5939e BK |
499 | } |
500 | ||
501 | int crypto_register_diskcipher(struct diskcipher_alg *alg) | |
502 | { | |
503 | struct crypto_alg *base = &alg->base; | |
91b23ddd BK |
504 | |
505 | #ifdef USE_FREE_REQ | |
37cd97e0 | 506 | struct diskcipher_freectrl *fctrl = &alg->freectrl; |
2ad5939e | 507 | |
37cd97e0 BK |
508 | INIT_LIST_HEAD(&fctrl->freelist); |
509 | INIT_DELAYED_WORK(&fctrl->freewq, free_workq_func); | |
510 | spin_lock_init(&fctrl->freelist_lock); | |
511 | if (!fctrl->max_io_ms) | |
512 | fctrl->max_io_ms = DISKCIPHER_MAX_IO_MS; | |
91b23ddd | 513 | #endif |
2ad5939e BK |
514 | base->cra_type = &crypto_diskcipher_type; |
515 | base->cra_flags = CRYPTO_ALG_TYPE_DISKCIPHER; | |
516 | return crypto_register_alg(base); | |
517 | } | |
518 | ||
519 | void crypto_unregister_diskcipher(struct diskcipher_alg *alg) | |
520 | { | |
521 | crypto_unregister_alg(&alg->base); | |
522 | } | |
523 | ||
524 | int crypto_register_diskciphers(struct diskcipher_alg *algs, int count) | |
525 | { | |
526 | int i, ret; | |
527 | ||
528 | for (i = 0; i < count; i++) { | |
529 | ret = crypto_register_diskcipher(algs + i); | |
530 | if (ret) | |
531 | goto err; | |
532 | } | |
533 | return 0; | |
534 | ||
535 | err: | |
536 | for (--i; i >= 0; --i) | |
537 | crypto_unregister_diskcipher(algs + i); | |
538 | return ret; | |
539 | } | |
540 | ||
541 | void crypto_unregister_diskciphers(struct diskcipher_alg *algs, int count) | |
542 | { | |
543 | int i; | |
544 | ||
545 | for (i = count - 1; i >= 0; --i) | |
546 | crypto_unregister_diskcipher(algs + i); | |
547 | } |