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