Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.37 879 lines 20 kB view raw
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#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 if (err > 0) 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 835struct pohmelfs_crypto_input_action_data { 836 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}