Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/geert/linux...
[linux-btrfs-devel.git] / drivers / staging / pohmelfs / crypto.c
blobad92771dce5713ee6958876bd460ce554e689c95
1 /*
2 * 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
3 * All rights reserved.
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.
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.
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>
23 #include "netfs.h"
25 static struct crypto_hash *pohmelfs_init_hash(struct pohmelfs_sb *psb)
27 int err;
28 struct crypto_hash *hash;
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;
38 psb->crypto_attached_size = crypto_hash_digestsize(hash);
40 if (!psb->hash_keysize)
41 return hash;
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;
50 return hash;
52 err_out_free:
53 crypto_free_hash(hash);
54 err_out_exit:
55 return ERR_PTR(err);
58 static struct crypto_ablkcipher *pohmelfs_init_cipher(struct pohmelfs_sb *psb)
60 int err = -EINVAL;
61 struct crypto_ablkcipher *cipher;
63 if (!psb->cipher_keysize)
64 goto err_out_exit;
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;
74 crypto_ablkcipher_clear_flags(cipher, ~0);
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;
83 return cipher;
85 err_out_free:
86 crypto_free_ablkcipher(cipher);
87 err_out_exit:
88 return ERR_PTR(err);
91 int pohmelfs_crypto_engine_init(struct pohmelfs_crypto_engine *e, struct pohmelfs_sb *psb)
93 int err;
95 e->page_num = 0;
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;
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;
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;
122 return 0;
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;
132 void pohmelfs_crypto_engine_exit(struct pohmelfs_crypto_engine *e)
134 crypto_free_hash(e->hash);
135 crypto_free_ablkcipher(e->cipher);
136 kfree(e->data);
139 static void pohmelfs_crypto_complete(struct crypto_async_request *req, int err)
141 struct pohmelfs_crypto_completion *c = req->data;
143 if (err == -EINPROGRESS)
144 return;
146 dprintk("%s: req: %p, err: %d.\n", __func__, req, err);
147 c->error = err;
148 complete(&c->complete);
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)
155 struct pohmelfs_crypto_completion complete;
156 int err;
158 init_completion(&complete.complete);
159 complete.error = -EINPROGRESS;
161 ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
162 pohmelfs_crypto_complete, &complete);
164 ablkcipher_request_set_crypt(req, sg_src, sg_dst, sg_src->length, iv);
166 if (enc)
167 err = crypto_ablkcipher_encrypt(req);
168 else
169 err = crypto_ablkcipher_decrypt(req);
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;
185 return err;
188 int pohmelfs_crypto_process_input_data(struct pohmelfs_crypto_engine *e, u64 cmd_iv,
189 void *data, struct page *page, unsigned int size)
191 int err;
192 struct scatterlist sg;
194 if (!e->cipher && !e->hash)
195 return 0;
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);
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);
207 if (e->cipher) {
208 struct ablkcipher_request *req = e->data + crypto_hash_digestsize(e->hash);
209 u8 iv[32];
211 memset(iv, 0, sizeof(iv));
212 memcpy(iv, &cmd_iv, sizeof(cmd_iv));
214 ablkcipher_request_set_tfm(req, e->cipher);
216 err = pohmelfs_crypto_process(req, &sg, &sg, iv, 0, e->timeout);
217 if (err)
218 goto err_out_exit;
221 if (e->hash) {
222 struct hash_desc desc;
223 void *dst = e->data + e->size/2;
225 desc.tfm = e->hash;
226 desc.flags = 0;
228 err = crypto_hash_init(&desc);
229 if (err)
230 goto err_out_exit;
232 err = crypto_hash_update(&desc, &sg, size);
233 if (err)
234 goto err_out_exit;
236 err = crypto_hash_final(&desc, dst);
237 if (err)
238 goto err_out_exit;
240 err = !!memcmp(dst, e->data, crypto_hash_digestsize(e->hash));
242 if (err) {
243 #ifdef CONFIG_POHMELFS_DEBUG
244 unsigned int i;
245 unsigned char *recv = e->data, *calc = dst;
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;
256 #else
257 dprintka("%02x/%02x ", recv[i], calc[i]);
258 #endif
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);
269 dprintk("%s: eng: %p, size: %u, hash: %p, cipher: %p: completed.\n",
270 __func__, e, e->size, e->hash, e->cipher);
272 return 0;
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;
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))
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;
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);
298 if (cmd_cmd == NETFS_READ_PAGES || cmd_cmd == NETFS_READ_PAGE)
299 csize = __be16_to_cpu(cmd->ext);
301 sz = csize + __be16_to_cpu(cmd->cpad) + sizeof(struct netfs_cmd);
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));
306 data += sz;
307 size -= sz;
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));
312 err = iterator(e, &sg_dst, &sg_src);
313 if (err)
314 return err;
317 if (!pages)
318 return 0;
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];
325 if (!page)
326 continue;
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);
333 err = iterator(e, &sg_dst, &sg_src);
334 if (err)
335 return err;
337 pages--;
338 if (!pages)
339 break;
340 dpage_idx++;
343 return 0;
346 static int pohmelfs_encrypt_iterator(struct pohmelfs_crypto_engine *e,
347 struct scatterlist *sg_dst, struct scatterlist *sg_src)
349 struct ablkcipher_request *req = e->data;
350 u8 iv[32];
352 memset(iv, 0, sizeof(iv));
354 memcpy(iv, &e->iv, sizeof(e->iv));
356 return pohmelfs_crypto_process(req, sg_dst, sg_src, iv, 1, e->timeout);
359 static int pohmelfs_encrypt(struct pohmelfs_crypto_thread *tc)
361 struct netfs_trans *t = tc->trans;
362 struct pohmelfs_crypto_engine *e = &tc->eng;
363 struct ablkcipher_request *req = e->data;
365 memset(req, 0, sizeof(struct ablkcipher_request));
366 ablkcipher_request_set_tfm(req, e->cipher);
368 e->iv = pohmelfs_gen_iv(t);
370 return pohmelfs_trans_iter(t, e, pohmelfs_encrypt_iterator);
373 static int pohmelfs_hash_iterator(struct pohmelfs_crypto_engine *e,
374 struct scatterlist *sg_dst, struct scatterlist *sg_src)
376 return crypto_hash_update(e->data, sg_src, sg_src->length);
379 static int pohmelfs_hash(struct pohmelfs_crypto_thread *tc)
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;
386 desc->tfm = e->hash;
387 desc->flags = 0;
389 err = crypto_hash_init(desc);
390 if (err)
391 return err;
393 err = pohmelfs_trans_iter(tc->trans, e, pohmelfs_hash_iterator);
394 if (err)
395 return err;
397 err = crypto_hash_final(desc, dst);
398 if (err)
399 return err;
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");
409 return 0;
412 static void pohmelfs_crypto_pages_free(struct pohmelfs_crypto_engine *e)
414 unsigned int i;
416 for (i = 0; i < e->page_num; ++i)
417 __free_page(e->pages[i]);
418 kfree(e->pages);
421 static int pohmelfs_crypto_pages_alloc(struct pohmelfs_crypto_engine *e, struct pohmelfs_sb *psb)
423 unsigned int i;
425 e->pages = kmalloc(psb->trans_max_pages * sizeof(struct page *), GFP_KERNEL);
426 if (!e->pages)
427 return -ENOMEM;
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;
435 e->page_num = i;
436 if (!e->page_num)
437 goto err_out_free;
439 return 0;
441 err_out_free:
442 kfree(e->pages);
443 return -ENOMEM;
446 static void pohmelfs_sys_crypto_exit_one(struct pohmelfs_crypto_thread *t)
448 struct pohmelfs_sb *psb = t->psb;
450 if (t->thread)
451 kthread_stop(t->thread);
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);
458 pohmelfs_crypto_engine_exit(&t->eng);
459 pohmelfs_crypto_pages_free(&t->eng);
460 kfree(t);
463 static int pohmelfs_crypto_finish(struct netfs_trans *t, struct pohmelfs_sb *psb, int err)
465 struct netfs_cmd *cmd = t->iovec.iov_base;
466 netfs_convert_cmd(cmd);
468 if (likely(!err))
469 err = netfs_trans_finish_send(t, psb);
471 t->result = err;
472 netfs_trans_put(t);
474 return err;
477 void pohmelfs_crypto_thread_make_ready(struct pohmelfs_crypto_thread *th)
479 struct pohmelfs_sb *psb = th->psb;
481 th->page = NULL;
482 th->trans = NULL;
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);
490 static int pohmelfs_crypto_thread_trans(struct pohmelfs_crypto_thread *t)
492 struct netfs_trans *trans;
493 int err = 0;
495 trans = t->trans;
496 trans->eng = NULL;
498 if (t->eng.hash) {
499 err = pohmelfs_hash(t);
500 if (err)
501 goto out_complete;
504 if (t->eng.cipher) {
505 err = pohmelfs_encrypt(t);
506 if (err)
507 goto out_complete;
508 trans->eng = &t->eng;
511 out_complete:
512 t->page = NULL;
513 t->trans = NULL;
515 if (!trans->eng)
516 pohmelfs_crypto_thread_make_ready(t);
518 pohmelfs_crypto_finish(trans, t->psb, err);
519 return err;
522 static int pohmelfs_crypto_thread_page(struct pohmelfs_crypto_thread *t)
524 struct pohmelfs_crypto_engine *e = &t->eng;
525 struct page *page = t->page;
526 int err;
528 WARN_ON(!PageChecked(page));
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);
538 pohmelfs_crypto_thread_make_ready(t);
540 return err;
543 static int pohmelfs_crypto_thread_func(void *data)
545 struct pohmelfs_crypto_thread *t = data;
547 while (!kthread_should_stop()) {
548 wait_event_interruptible(t->wait, kthread_should_stop() ||
549 t->trans || t->page);
551 if (kthread_should_stop())
552 break;
554 if (!t->trans && !t->page)
555 continue;
557 dprintk("%s: thread: %p, trans: %p, page: %p.\n",
558 __func__, t, t->trans, t->page);
560 if (t->trans)
561 pohmelfs_crypto_thread_trans(t);
562 else if (t->page)
563 pohmelfs_crypto_thread_page(t);
566 return 0;
569 static void pohmelfs_crypto_flush(struct pohmelfs_sb *psb, struct list_head *head)
571 while (!list_empty(head)) {
572 struct pohmelfs_crypto_thread *t = NULL;
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);
579 mutex_unlock(&psb->crypto_thread_lock);
581 if (t)
582 pohmelfs_sys_crypto_exit_one(t);
586 static void pohmelfs_sys_crypto_exit(struct pohmelfs_sb *psb)
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);
595 static int pohmelfs_sys_crypto_init(struct pohmelfs_sb *psb)
597 unsigned int i;
598 struct pohmelfs_crypto_thread *t;
599 struct pohmelfs_config *c;
600 struct netfs_state *st;
601 int err;
603 list_for_each_entry(c, &psb->state_list, config_entry) {
604 st = &c->state;
606 err = pohmelfs_crypto_engine_init(&st->eng, psb);
607 if (err)
608 goto err_out_exit;
610 dprintk("%s: st: %p, eng: %p, hash: %p, cipher: %p.\n",
611 __func__, st, &st->eng, &st->eng.hash, &st->eng.cipher);
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;
620 init_waitqueue_head(&t->wait);
622 t->psb = psb;
623 t->trans = NULL;
624 t->eng.thread = t;
626 err = pohmelfs_crypto_engine_init(&t->eng, psb);
627 if (err)
628 goto err_out_free_state_engines;
630 err = pohmelfs_crypto_pages_alloc(&t->eng, psb);
631 if (err)
632 goto err_out_free;
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;
642 if (t->eng.cipher)
643 psb->crypto_align_size = crypto_ablkcipher_blocksize(t->eng.cipher);
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);
650 psb->crypto_thread_num = i;
651 return 0;
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);
660 err_out_exit:
661 pohmelfs_sys_crypto_exit(psb);
662 return err;
665 void pohmelfs_crypto_exit(struct pohmelfs_sb *psb)
667 pohmelfs_sys_crypto_exit(psb);
669 kfree(psb->hash_string);
670 kfree(psb->cipher_string);
673 static int pohmelfs_crypt_init_complete(struct page **pages, unsigned int page_num,
674 void *private, int err)
676 struct pohmelfs_sb *psb = private;
678 psb->flags = -err;
679 dprintk("%s: err: %d.\n", __func__, err);
681 wake_up(&psb->wait);
683 return err;
686 static int pohmelfs_crypto_init_handshake(struct pohmelfs_sb *psb)
688 struct netfs_trans *t;
689 struct netfs_crypto_capabilities *cap;
690 struct netfs_cmd *cmd;
691 char *str;
692 int err = -ENOMEM, size;
694 size = sizeof(struct netfs_crypto_capabilities) +
695 psb->cipher_strlen + psb->hash_strlen + 2; /* 0 bytes */
697 t = netfs_trans_alloc(psb, size, 0, 0);
698 if (!t)
699 goto err_out_exit;
701 t->complete = pohmelfs_crypt_init_complete;
702 t->private = psb;
704 cmd = netfs_trans_current(t);
705 cap = (struct netfs_crypto_capabilities *)(cmd + 1);
706 str = (char *)(cap + 1);
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;
715 netfs_convert_cmd(cmd);
716 netfs_trans_update(cmd, t, size);
718 cap->hash_strlen = psb->hash_strlen;
719 if (cap->hash_strlen) {
720 sprintf(str, "%s", psb->hash_string);
721 str += cap->hash_strlen;
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);
729 netfs_convert_crypto_capabilities(cap);
731 psb->flags = ~0;
732 err = netfs_trans_finish(t, psb);
733 if (err)
734 goto err_out_exit;
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;
743 if (!err)
744 psb->perform_crypto = 1;
745 psb->flags = 0;
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.
754 if (err)
755 goto err_out_exit;
757 return 0;
759 err_out_exit:
760 return err;
763 int pohmelfs_crypto_init(struct pohmelfs_sb *psb)
765 int err;
767 if (!psb->cipher_string && !psb->hash_string)
768 return 0;
770 err = pohmelfs_crypto_init_handshake(psb);
771 if (err)
772 return err;
774 err = pohmelfs_sys_crypto_init(psb);
775 if (err)
776 return err;
778 return 0;
781 static int pohmelfs_crypto_thread_get(struct pohmelfs_sb *psb,
782 int (*action)(struct pohmelfs_crypto_thread *t, void *data), void *data)
784 struct pohmelfs_crypto_thread *t = NULL;
785 int err;
787 while (!t) {
788 err = wait_event_interruptible_timeout(psb->wait,
789 !list_empty(&psb->crypto_ready_list),
790 psb->wait_on_page_timeout);
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);
800 list_move_tail(&t->thread_entry,
801 &psb->crypto_active_list);
803 action(t, data);
804 wake_up(&t->wait);
807 mutex_unlock(&psb->crypto_thread_lock);
810 return err;
813 static int pohmelfs_trans_crypt_action(struct pohmelfs_crypto_thread *t, void *data)
815 struct netfs_trans *trans = data;
817 netfs_trans_get(trans);
818 t->trans = trans;
820 dprintk("%s: t: %p, gen: %u, thread: %p.\n", __func__, trans, trans->gen, t);
821 return 0;
824 int pohmelfs_trans_crypt(struct netfs_trans *trans, struct pohmelfs_sb *psb)
826 if ((!psb->hash_string && !psb->cipher_string) || !psb->perform_crypto) {
827 netfs_trans_get(trans);
828 return pohmelfs_crypto_finish(trans, psb, 0);
831 return pohmelfs_crypto_thread_get(psb, pohmelfs_trans_crypt_action, trans);
834 struct pohmelfs_crypto_input_action_data {
835 struct page *page;
836 struct pohmelfs_crypto_engine *e;
837 u64 iv;
838 unsigned int size;
841 static int pohmelfs_crypt_input_page_action(struct pohmelfs_crypto_thread *t, void *data)
843 struct pohmelfs_crypto_input_action_data *act = data;
845 memcpy(t->eng.data, act->e->data, t->psb->crypto_attached_size);
847 t->size = act->size;
848 t->eng.iv = act->iv;
850 t->page = act->page;
851 return 0;
854 int pohmelfs_crypto_process_input_page(struct pohmelfs_crypto_engine *e,
855 struct page *page, unsigned int size, u64 iv)
857 struct inode *inode = page->mapping->host;
858 struct pohmelfs_crypto_input_action_data act;
859 int err = -ENOENT;
861 act.page = page;
862 act.e = e;
863 act.size = size;
864 act.iv = iv;
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;
871 return 0;
873 err_out_exit:
874 SetPageUptodate(page);
875 page_cache_release(page);
877 return err;