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