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