Fix common misspellings
[linux-2.6-block.git] / drivers / staging / pohmelfs / crypto.c
CommitLineData
e2396ae5
EP
1/*
2 * 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
3 * All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <linux/crypto.h>
17#include <linux/highmem.h>
18#include <linux/kthread.h>
19#include <linux/pagemap.h>
20#include <linux/slab.h>
21
22#include "netfs.h"
23
24static struct crypto_hash *pohmelfs_init_hash(struct pohmelfs_sb *psb)
25{
26 int err;
27 struct crypto_hash *hash;
28
29 hash = crypto_alloc_hash(psb->hash_string, 0, CRYPTO_ALG_ASYNC);
30 if (IS_ERR(hash)) {
31 err = PTR_ERR(hash);
32 dprintk("%s: idx: %u: failed to allocate hash '%s', err: %d.\n",
33 __func__, psb->idx, psb->hash_string, err);
34 goto err_out_exit;
35 }
36
37 psb->crypto_attached_size = crypto_hash_digestsize(hash);
38
39 if (!psb->hash_keysize)
40 return hash;
41
42 err = crypto_hash_setkey(hash, psb->hash_key, psb->hash_keysize);
43 if (err) {
44 dprintk("%s: idx: %u: failed to set key for hash '%s', err: %d.\n",
45 __func__, psb->idx, psb->hash_string, err);
46 goto err_out_free;
47 }
48
49 return hash;
50
51err_out_free:
52 crypto_free_hash(hash);
53err_out_exit:
54 return ERR_PTR(err);
55}
56
57static struct crypto_ablkcipher *pohmelfs_init_cipher(struct pohmelfs_sb *psb)
58{
59 int err = -EINVAL;
60 struct crypto_ablkcipher *cipher;
61
62 if (!psb->cipher_keysize)
63 goto err_out_exit;
64
65 cipher = crypto_alloc_ablkcipher(psb->cipher_string, 0, 0);
66 if (IS_ERR(cipher)) {
67 err = PTR_ERR(cipher);
68 dprintk("%s: idx: %u: failed to allocate cipher '%s', err: %d.\n",
69 __func__, psb->idx, psb->cipher_string, err);
70 goto err_out_exit;
71 }
72
73 crypto_ablkcipher_clear_flags(cipher, ~0);
74
75 err = crypto_ablkcipher_setkey(cipher, psb->cipher_key, psb->cipher_keysize);
76 if (err) {
77 dprintk("%s: idx: %u: failed to set key for cipher '%s', err: %d.\n",
78 __func__, psb->idx, psb->cipher_string, err);
79 goto err_out_free;
80 }
81
82 return cipher;
83
84err_out_free:
85 crypto_free_ablkcipher(cipher);
86err_out_exit:
87 return ERR_PTR(err);
88}
89
90int pohmelfs_crypto_engine_init(struct pohmelfs_crypto_engine *e, struct pohmelfs_sb *psb)
91{
92 int err;
93
94 e->page_num = 0;
95
96 e->size = PAGE_SIZE;
97 e->data = kmalloc(e->size, GFP_KERNEL);
98 if (!e->data) {
99 err = -ENOMEM;
100 goto err_out_exit;
101 }
102
103 if (psb->hash_string) {
104 e->hash = pohmelfs_init_hash(psb);
105 if (IS_ERR(e->hash)) {
106 err = PTR_ERR(e->hash);
107 e->hash = NULL;
108 goto err_out_free;
109 }
110 }
111
112 if (psb->cipher_string) {
113 e->cipher = pohmelfs_init_cipher(psb);
114 if (IS_ERR(e->cipher)) {
115 err = PTR_ERR(e->cipher);
116 e->cipher = NULL;
117 goto err_out_free_hash;
118 }
119 }
120
121 return 0;
122
123err_out_free_hash:
124 crypto_free_hash(e->hash);
125err_out_free:
126 kfree(e->data);
127err_out_exit:
128 return err;
129}
130
131void pohmelfs_crypto_engine_exit(struct pohmelfs_crypto_engine *e)
132{
391a169e
JJ
133 crypto_free_hash(e->hash);
134 crypto_free_ablkcipher(e->cipher);
e2396ae5
EP
135 kfree(e->data);
136}
137
138static void pohmelfs_crypto_complete(struct crypto_async_request *req, int err)
139{
140 struct pohmelfs_crypto_completion *c = req->data;
141
142 if (err == -EINPROGRESS)
143 return;
144
145 dprintk("%s: req: %p, err: %d.\n", __func__, req, err);
146 c->error = err;
147 complete(&c->complete);
148}
149
150static int pohmelfs_crypto_process(struct ablkcipher_request *req,
151 struct scatterlist *sg_dst, struct scatterlist *sg_src,
152 void *iv, int enc, unsigned long timeout)
153{
154 struct pohmelfs_crypto_completion complete;
155 int err;
156
157 init_completion(&complete.complete);
158 complete.error = -EINPROGRESS;
159
160 ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
161 pohmelfs_crypto_complete, &complete);
162
163 ablkcipher_request_set_crypt(req, sg_src, sg_dst, sg_src->length, iv);
164
165 if (enc)
166 err = crypto_ablkcipher_encrypt(req);
167 else
168 err = crypto_ablkcipher_decrypt(req);
169
170 switch (err) {
e3f052f2
RP
171 case -EINPROGRESS:
172 case -EBUSY:
173 err = wait_for_completion_interruptible_timeout(&complete.complete,
e2396ae5 174 timeout);
e3f052f2
RP
175 if (!err)
176 err = -ETIMEDOUT;
177 else if (err > 0)
178 err = complete.error;
179 break;
180 default:
181 break;
e2396ae5
EP
182 }
183
184 return err;
185}
186
187int pohmelfs_crypto_process_input_data(struct pohmelfs_crypto_engine *e, u64 cmd_iv,
188 void *data, struct page *page, unsigned int size)
189{
190 int err;
191 struct scatterlist sg;
192
193 if (!e->cipher && !e->hash)
194 return 0;
195
196 dprintk("%s: eng: %p, iv: %llx, data: %p, page: %p/%lu, size: %u.\n",
e3f052f2 197 __func__, e, cmd_iv, data, page, (page) ? page->index : 0, size);
e2396ae5
EP
198
199 if (data) {
200 sg_init_one(&sg, data, size);
201 } else {
202 sg_init_table(&sg, 1);
203 sg_set_page(&sg, page, size, 0);
204 }
205
206 if (e->cipher) {
207 struct ablkcipher_request *req = e->data + crypto_hash_digestsize(e->hash);
208 u8 iv[32];
209
210 memset(iv, 0, sizeof(iv));
211 memcpy(iv, &cmd_iv, sizeof(cmd_iv));
212
213 ablkcipher_request_set_tfm(req, e->cipher);
214
215 err = pohmelfs_crypto_process(req, &sg, &sg, iv, 0, e->timeout);
216 if (err)
217 goto err_out_exit;
218 }
219
220 if (e->hash) {
221 struct hash_desc desc;
222 void *dst = e->data + e->size/2;
223
224 desc.tfm = e->hash;
225 desc.flags = 0;
226
227 err = crypto_hash_init(&desc);
228 if (err)
229 goto err_out_exit;
230
231 err = crypto_hash_update(&desc, &sg, size);
232 if (err)
233 goto err_out_exit;
234
235 err = crypto_hash_final(&desc, dst);
236 if (err)
237 goto err_out_exit;
238
239 err = !!memcmp(dst, e->data, crypto_hash_digestsize(e->hash));
240
241 if (err) {
242#ifdef CONFIG_POHMELFS_DEBUG
243 unsigned int i;
244 unsigned char *recv = e->data, *calc = dst;
245
246 dprintk("%s: eng: %p, hash: %p, cipher: %p: iv : %llx, hash mismatch (recv/calc): ",
247 __func__, e, e->hash, e->cipher, cmd_iv);
e3f052f2 248 for (i = 0; i < crypto_hash_digestsize(e->hash); ++i) {
e2396ae5
EP
249#if 0
250 dprintka("%02x ", recv[i]);
251 if (recv[i] != calc[i]) {
252 dprintka("| calc byte: %02x.\n", calc[i]);
253 break;
254 }
255#else
256 dprintka("%02x/%02x ", recv[i], calc[i]);
257#endif
258 }
259 dprintk("\n");
260#endif
261 goto err_out_exit;
262 } else {
263 dprintk("%s: eng: %p, hash: %p, cipher: %p: hashes matched.\n",
264 __func__, e, e->hash, e->cipher);
265 }
266 }
267
268 dprintk("%s: eng: %p, size: %u, hash: %p, cipher: %p: completed.\n",
269 __func__, e, e->size, e->hash, e->cipher);
270
271 return 0;
272
273err_out_exit:
274 dprintk("%s: eng: %p, hash: %p, cipher: %p: err: %d.\n",
275 __func__, e, e->hash, e->cipher, err);
276 return err;
277}
278
279static int pohmelfs_trans_iter(struct netfs_trans *t, struct pohmelfs_crypto_engine *e,
e3f052f2 280 int (*iterator) (struct pohmelfs_crypto_engine *e,
e2396ae5
EP
281 struct scatterlist *dst,
282 struct scatterlist *src))
283{
284 void *data = t->iovec.iov_base + sizeof(struct netfs_cmd) + t->psb->crypto_attached_size;
285 unsigned int size = t->iovec.iov_len - sizeof(struct netfs_cmd) - t->psb->crypto_attached_size;
286 struct netfs_cmd *cmd = data;
287 unsigned int sz, pages = t->attached_pages, i, csize, cmd_cmd, dpage_idx;
288 struct scatterlist sg_src, sg_dst;
289 int err;
290
291 while (size) {
292 cmd = data;
293 cmd_cmd = __be16_to_cpu(cmd->cmd);
294 csize = __be32_to_cpu(cmd->size);
295 cmd->iv = __cpu_to_be64(e->iv);
296
297 if (cmd_cmd == NETFS_READ_PAGES || cmd_cmd == NETFS_READ_PAGE)
298 csize = __be16_to_cpu(cmd->ext);
299
300 sz = csize + __be16_to_cpu(cmd->cpad) + sizeof(struct netfs_cmd);
301
302 dprintk("%s: size: %u, sz: %u, cmd_size: %u, cmd_cpad: %u.\n",
303 __func__, size, sz, __be32_to_cpu(cmd->size), __be16_to_cpu(cmd->cpad));
304
305 data += sz;
306 size -= sz;
307
308 sg_init_one(&sg_src, cmd->data, sz - sizeof(struct netfs_cmd));
309 sg_init_one(&sg_dst, cmd->data, sz - sizeof(struct netfs_cmd));
310
311 err = iterator(e, &sg_dst, &sg_src);
312 if (err)
313 return err;
314 }
315
316 if (!pages)
317 return 0;
318
319 dpage_idx = 0;
e3f052f2 320 for (i = 0; i < t->page_num; ++i) {
e2396ae5
EP
321 struct page *page = t->pages[i];
322 struct page *dpage = e->pages[dpage_idx];
323
324 if (!page)
325 continue;
326
327 sg_init_table(&sg_src, 1);
328 sg_init_table(&sg_dst, 1);
329 sg_set_page(&sg_src, page, page_private(page), 0);
330 sg_set_page(&sg_dst, dpage, page_private(page), 0);
331
332 err = iterator(e, &sg_dst, &sg_src);
333 if (err)
334 return err;
335
336 pages--;
337 if (!pages)
338 break;
339 dpage_idx++;
340 }
341
342 return 0;
343}
344
345static int pohmelfs_encrypt_iterator(struct pohmelfs_crypto_engine *e,
346 struct scatterlist *sg_dst, struct scatterlist *sg_src)
347{
348 struct ablkcipher_request *req = e->data;
349 u8 iv[32];
350
351 memset(iv, 0, sizeof(iv));
352
353 memcpy(iv, &e->iv, sizeof(e->iv));
354
355 return pohmelfs_crypto_process(req, sg_dst, sg_src, iv, 1, e->timeout);
356}
357
358static int pohmelfs_encrypt(struct pohmelfs_crypto_thread *tc)
359{
360 struct netfs_trans *t = tc->trans;
361 struct pohmelfs_crypto_engine *e = &tc->eng;
362 struct ablkcipher_request *req = e->data;
363
364 memset(req, 0, sizeof(struct ablkcipher_request));
365 ablkcipher_request_set_tfm(req, e->cipher);
366
367 e->iv = pohmelfs_gen_iv(t);
368
369 return pohmelfs_trans_iter(t, e, pohmelfs_encrypt_iterator);
370}
371
372static int pohmelfs_hash_iterator(struct pohmelfs_crypto_engine *e,
373 struct scatterlist *sg_dst, struct scatterlist *sg_src)
374{
375 return crypto_hash_update(e->data, sg_src, sg_src->length);
376}
377
378static int pohmelfs_hash(struct pohmelfs_crypto_thread *tc)
379{
380 struct pohmelfs_crypto_engine *e = &tc->eng;
381 struct hash_desc *desc = e->data;
382 unsigned char *dst = tc->trans->iovec.iov_base + sizeof(struct netfs_cmd);
383 int err;
384
385 desc->tfm = e->hash;
386 desc->flags = 0;
387
388 err = crypto_hash_init(desc);
389 if (err)
390 return err;
391
392 err = pohmelfs_trans_iter(tc->trans, e, pohmelfs_hash_iterator);
393 if (err)
394 return err;
395
396 err = crypto_hash_final(desc, dst);
397 if (err)
398 return err;
399
400 {
401 unsigned int i;
402 dprintk("%s: ", __func__);
e3f052f2 403 for (i = 0; i < tc->psb->crypto_attached_size; ++i)
e2396ae5
EP
404 dprintka("%02x ", dst[i]);
405 dprintka("\n");
406 }
407
408 return 0;
409}
410
411static void pohmelfs_crypto_pages_free(struct pohmelfs_crypto_engine *e)
412{
413 unsigned int i;
414
e3f052f2 415 for (i = 0; i < e->page_num; ++i)
e2396ae5
EP
416 __free_page(e->pages[i]);
417 kfree(e->pages);
418}
419
420static int pohmelfs_crypto_pages_alloc(struct pohmelfs_crypto_engine *e, struct pohmelfs_sb *psb)
421{
422 unsigned int i;
423
424 e->pages = kmalloc(psb->trans_max_pages * sizeof(struct page *), GFP_KERNEL);
425 if (!e->pages)
426 return -ENOMEM;
427
e3f052f2 428 for (i = 0; i < psb->trans_max_pages; ++i) {
e2396ae5
EP
429 e->pages[i] = alloc_page(GFP_KERNEL);
430 if (!e->pages[i])
431 break;
432 }
433
434 e->page_num = i;
435 if (!e->page_num)
436 goto err_out_free;
437
438 return 0;
439
440err_out_free:
441 kfree(e->pages);
442 return -ENOMEM;
443}
444
445static void pohmelfs_sys_crypto_exit_one(struct pohmelfs_crypto_thread *t)
446{
447 struct pohmelfs_sb *psb = t->psb;
448
449 if (t->thread)
450 kthread_stop(t->thread);
451
452 mutex_lock(&psb->crypto_thread_lock);
453 list_del(&t->thread_entry);
454 psb->crypto_thread_num--;
455 mutex_unlock(&psb->crypto_thread_lock);
456
457 pohmelfs_crypto_engine_exit(&t->eng);
458 pohmelfs_crypto_pages_free(&t->eng);
459 kfree(t);
460}
461
462static int pohmelfs_crypto_finish(struct netfs_trans *t, struct pohmelfs_sb *psb, int err)
463{
464 struct netfs_cmd *cmd = t->iovec.iov_base;
465 netfs_convert_cmd(cmd);
466
467 if (likely(!err))
468 err = netfs_trans_finish_send(t, psb);
469
470 t->result = err;
471 netfs_trans_put(t);
472
473 return err;
474}
475
476void pohmelfs_crypto_thread_make_ready(struct pohmelfs_crypto_thread *th)
477{
478 struct pohmelfs_sb *psb = th->psb;
479
480 th->page = NULL;
481 th->trans = NULL;
482
483 mutex_lock(&psb->crypto_thread_lock);
484 list_move_tail(&th->thread_entry, &psb->crypto_ready_list);
485 mutex_unlock(&psb->crypto_thread_lock);
486 wake_up(&psb->wait);
487}
488
489static int pohmelfs_crypto_thread_trans(struct pohmelfs_crypto_thread *t)
490{
491 struct netfs_trans *trans;
492 int err = 0;
493
494 trans = t->trans;
495 trans->eng = NULL;
496
497 if (t->eng.hash) {
498 err = pohmelfs_hash(t);
499 if (err)
500 goto out_complete;
501 }
502
503 if (t->eng.cipher) {
504 err = pohmelfs_encrypt(t);
505 if (err)
506 goto out_complete;
507 trans->eng = &t->eng;
508 }
509
510out_complete:
511 t->page = NULL;
512 t->trans = NULL;
513
514 if (!trans->eng)
515 pohmelfs_crypto_thread_make_ready(t);
516
517 pohmelfs_crypto_finish(trans, t->psb, err);
518 return err;
519}
520
521static int pohmelfs_crypto_thread_page(struct pohmelfs_crypto_thread *t)
522{
523 struct pohmelfs_crypto_engine *e = &t->eng;
524 struct page *page = t->page;
525 int err;
526
527 WARN_ON(!PageChecked(page));
528
529 err = pohmelfs_crypto_process_input_data(e, e->iv, NULL, page, t->size);
530 if (!err)
531 SetPageUptodate(page);
532 else
533 SetPageError(page);
534 unlock_page(page);
535 page_cache_release(page);
536
537 pohmelfs_crypto_thread_make_ready(t);
538
539 return err;
540}
541
542static int pohmelfs_crypto_thread_func(void *data)
543{
544 struct pohmelfs_crypto_thread *t = data;
545
546 while (!kthread_should_stop()) {
547 wait_event_interruptible(t->wait, kthread_should_stop() ||
548 t->trans || t->page);
549
550 if (kthread_should_stop())
551 break;
552
553 if (!t->trans && !t->page)
554 continue;
555
556 dprintk("%s: thread: %p, trans: %p, page: %p.\n",
557 __func__, t, t->trans, t->page);
558
559 if (t->trans)
560 pohmelfs_crypto_thread_trans(t);
561 else if (t->page)
562 pohmelfs_crypto_thread_page(t);
563 }
564
565 return 0;
566}
567
568static void pohmelfs_crypto_flush(struct pohmelfs_sb *psb, struct list_head *head)
569{
570 while (!list_empty(head)) {
571 struct pohmelfs_crypto_thread *t = NULL;
572
573 mutex_lock(&psb->crypto_thread_lock);
574 if (!list_empty(head)) {
575 t = list_first_entry(head, struct pohmelfs_crypto_thread, thread_entry);
576 list_del_init(&t->thread_entry);
577 }
578 mutex_unlock(&psb->crypto_thread_lock);
579
580 if (t)
581 pohmelfs_sys_crypto_exit_one(t);
582 }
583}
584
585static void pohmelfs_sys_crypto_exit(struct pohmelfs_sb *psb)
586{
587 while (!list_empty(&psb->crypto_active_list) || !list_empty(&psb->crypto_ready_list)) {
588 dprintk("%s: crypto_thread_num: %u.\n", __func__, psb->crypto_thread_num);
589 pohmelfs_crypto_flush(psb, &psb->crypto_active_list);
590 pohmelfs_crypto_flush(psb, &psb->crypto_ready_list);
591 }
592}
593
594static int pohmelfs_sys_crypto_init(struct pohmelfs_sb *psb)
595{
596 unsigned int i;
597 struct pohmelfs_crypto_thread *t;
598 struct pohmelfs_config *c;
599 struct netfs_state *st;
600 int err;
601
602 list_for_each_entry(c, &psb->state_list, config_entry) {
603 st = &c->state;
604
605 err = pohmelfs_crypto_engine_init(&st->eng, psb);
606 if (err)
607 goto err_out_exit;
608
609 dprintk("%s: st: %p, eng: %p, hash: %p, cipher: %p.\n",
610 __func__, st, &st->eng, &st->eng.hash, &st->eng.cipher);
611 }
612
e3f052f2 613 for (i = 0; i < psb->crypto_thread_num; ++i) {
e2396ae5
EP
614 err = -ENOMEM;
615 t = kzalloc(sizeof(struct pohmelfs_crypto_thread), GFP_KERNEL);
616 if (!t)
617 goto err_out_free_state_engines;
618
619 init_waitqueue_head(&t->wait);
620
621 t->psb = psb;
622 t->trans = NULL;
623 t->eng.thread = t;
624
625 err = pohmelfs_crypto_engine_init(&t->eng, psb);
626 if (err)
627 goto err_out_free_state_engines;
628
629 err = pohmelfs_crypto_pages_alloc(&t->eng, psb);
630 if (err)
631 goto err_out_free;
632
633 t->thread = kthread_run(pohmelfs_crypto_thread_func, t,
634 "pohmelfs-crypto-%d-%d", psb->idx, i);
635 if (IS_ERR(t->thread)) {
636 err = PTR_ERR(t->thread);
637 t->thread = NULL;
638 goto err_out_free;
639 }
640
641 if (t->eng.cipher)
642 psb->crypto_align_size = crypto_ablkcipher_blocksize(t->eng.cipher);
643
644 mutex_lock(&psb->crypto_thread_lock);
645 list_add_tail(&t->thread_entry, &psb->crypto_ready_list);
646 mutex_unlock(&psb->crypto_thread_lock);
647 }
648
649 psb->crypto_thread_num = i;
650 return 0;
651
652err_out_free:
653 pohmelfs_sys_crypto_exit_one(t);
654err_out_free_state_engines:
655 list_for_each_entry(c, &psb->state_list, config_entry) {
656 st = &c->state;
657 pohmelfs_crypto_engine_exit(&st->eng);
658 }
659err_out_exit:
660 pohmelfs_sys_crypto_exit(psb);
661 return err;
662}
663
664void pohmelfs_crypto_exit(struct pohmelfs_sb *psb)
665{
666 pohmelfs_sys_crypto_exit(psb);
667
668 kfree(psb->hash_string);
669 kfree(psb->cipher_string);
670}
671
672static int pohmelfs_crypt_init_complete(struct page **pages, unsigned int page_num,
673 void *private, int err)
674{
675 struct pohmelfs_sb *psb = private;
676
677 psb->flags = -err;
678 dprintk("%s: err: %d.\n", __func__, err);
679
680 wake_up(&psb->wait);
681
682 return err;
683}
684
685static int pohmelfs_crypto_init_handshake(struct pohmelfs_sb *psb)
686{
687 struct netfs_trans *t;
688 struct netfs_crypto_capabilities *cap;
689 struct netfs_cmd *cmd;
690 char *str;
691 int err = -ENOMEM, size;
692
693 size = sizeof(struct netfs_crypto_capabilities) +
694 psb->cipher_strlen + psb->hash_strlen + 2; /* 0 bytes */
695
696 t = netfs_trans_alloc(psb, size, 0, 0);
697 if (!t)
698 goto err_out_exit;
699
700 t->complete = pohmelfs_crypt_init_complete;
701 t->private = psb;
702
703 cmd = netfs_trans_current(t);
704 cap = (struct netfs_crypto_capabilities *)(cmd + 1);
705 str = (char *)(cap + 1);
706
707 cmd->cmd = NETFS_CAPABILITIES;
708 cmd->id = POHMELFS_CRYPTO_CAPABILITIES;
709 cmd->size = size;
710 cmd->start = 0;
711 cmd->ext = 0;
712 cmd->csize = 0;
713
714 netfs_convert_cmd(cmd);
715 netfs_trans_update(cmd, t, size);
716
717 cap->hash_strlen = psb->hash_strlen;
718 if (cap->hash_strlen) {
719 sprintf(str, "%s", psb->hash_string);
720 str += cap->hash_strlen;
721 }
722
723 cap->cipher_strlen = psb->cipher_strlen;
724 cap->cipher_keysize = psb->cipher_keysize;
725 if (cap->cipher_strlen)
726 sprintf(str, "%s", psb->cipher_string);
727
728 netfs_convert_crypto_capabilities(cap);
729
730 psb->flags = ~0;
731 err = netfs_trans_finish(t, psb);
732 if (err)
733 goto err_out_exit;
734
735 err = wait_event_interruptible_timeout(psb->wait, (psb->flags != ~0),
736 psb->wait_on_page_timeout);
737 if (!err)
738 err = -ETIMEDOUT;
2d7cf8ef 739 else if (err > 0)
e2396ae5
EP
740 err = -psb->flags;
741
742 if (!err)
743 psb->perform_crypto = 1;
744 psb->flags = 0;
745
746 /*
747 * At this point NETFS_CAPABILITIES response command
25985edc 748 * should setup superblock in a way, which is acceptable
e2396ae5
EP
749 * for both client and server, so if server refuses connection,
750 * it will send error in transaction response.
751 */
752
753 if (err)
754 goto err_out_exit;
755
756 return 0;
757
758err_out_exit:
759 return err;
760}
761
762int pohmelfs_crypto_init(struct pohmelfs_sb *psb)
763{
764 int err;
765
766 if (!psb->cipher_string && !psb->hash_string)
767 return 0;
768
769 err = pohmelfs_crypto_init_handshake(psb);
770 if (err)
771 return err;
772
773 err = pohmelfs_sys_crypto_init(psb);
774 if (err)
775 return err;
776
777 return 0;
778}
779
780static int pohmelfs_crypto_thread_get(struct pohmelfs_sb *psb,
e3f052f2 781 int (*action)(struct pohmelfs_crypto_thread *t, void *data), void *data)
e2396ae5
EP
782{
783 struct pohmelfs_crypto_thread *t = NULL;
784 int err;
785
786 while (!t) {
787 err = wait_event_interruptible_timeout(psb->wait,
788 !list_empty(&psb->crypto_ready_list),
789 psb->wait_on_page_timeout);
790
791 t = NULL;
792 err = 0;
793 mutex_lock(&psb->crypto_thread_lock);
794 if (!list_empty(&psb->crypto_ready_list)) {
795 t = list_entry(psb->crypto_ready_list.prev,
796 struct pohmelfs_crypto_thread,
797 thread_entry);
798
799 list_move_tail(&t->thread_entry,
800 &psb->crypto_active_list);
801
802 action(t, data);
803 wake_up(&t->wait);
804
805 }
806 mutex_unlock(&psb->crypto_thread_lock);
807 }
808
809 return err;
810}
811
812static int pohmelfs_trans_crypt_action(struct pohmelfs_crypto_thread *t, void *data)
813{
814 struct netfs_trans *trans = data;
815
816 netfs_trans_get(trans);
817 t->trans = trans;
818
819 dprintk("%s: t: %p, gen: %u, thread: %p.\n", __func__, trans, trans->gen, t);
820 return 0;
821}
822
823int pohmelfs_trans_crypt(struct netfs_trans *trans, struct pohmelfs_sb *psb)
824{
825 if ((!psb->hash_string && !psb->cipher_string) || !psb->perform_crypto) {
826 netfs_trans_get(trans);
827 return pohmelfs_crypto_finish(trans, psb, 0);
828 }
829
830 return pohmelfs_crypto_thread_get(psb, pohmelfs_trans_crypt_action, trans);
831}
832
385e3f1a 833struct pohmelfs_crypto_input_action_data {
e2396ae5
EP
834 struct page *page;
835 struct pohmelfs_crypto_engine *e;
836 u64 iv;
837 unsigned int size;
838};
839
840static int pohmelfs_crypt_input_page_action(struct pohmelfs_crypto_thread *t, void *data)
841{
842 struct pohmelfs_crypto_input_action_data *act = data;
843
844 memcpy(t->eng.data, act->e->data, t->psb->crypto_attached_size);
845
846 t->size = act->size;
847 t->eng.iv = act->iv;
848
849 t->page = act->page;
850 return 0;
851}
852
853int pohmelfs_crypto_process_input_page(struct pohmelfs_crypto_engine *e,
854 struct page *page, unsigned int size, u64 iv)
855{
856 struct inode *inode = page->mapping->host;
857 struct pohmelfs_crypto_input_action_data act;
858 int err = -ENOENT;
859
860 act.page = page;
861 act.e = e;
862 act.size = size;
863 act.iv = iv;
864
865 err = pohmelfs_crypto_thread_get(POHMELFS_SB(inode->i_sb),
866 pohmelfs_crypt_input_page_action, &act);
867 if (err)
868 goto err_out_exit;
869
870 return 0;
871
872err_out_exit:
873 SetPageUptodate(page);
874 page_cache_release(page);
875
876 return err;
877}