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