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        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}
 880