crypto.c 19.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * QEMU block full disk encryption
 *
 * Copyright (c) 2015-2016 Red Hat, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "qemu/osdep.h"

#include "block/block_int.h"
24
#include "block/qdict.h"
25 26 27
#include "sysemu/block-backend.h"
#include "crypto/block.h"
#include "qapi/opts-visitor.h"
28
#include "qapi/qapi-visit-crypto.h"
29
#include "qapi/qobject-input-visitor.h"
30
#include "qapi/error.h"
31
#include "qemu/module.h"
32
#include "qemu/option.h"
33
#include "crypto.h"
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58

typedef struct BlockCrypto BlockCrypto;

struct BlockCrypto {
    QCryptoBlock *block;
};


static int block_crypto_probe_generic(QCryptoBlockFormat format,
                                      const uint8_t *buf,
                                      int buf_size,
                                      const char *filename)
{
    if (qcrypto_block_has_format(format, buf, buf_size)) {
        return 100;
    } else {
        return 0;
    }
}


static ssize_t block_crypto_read_func(QCryptoBlock *block,
                                      size_t offset,
                                      uint8_t *buf,
                                      size_t buflen,
59
                                      void *opaque,
60
                                      Error **errp)
61 62 63 64
{
    BlockDriverState *bs = opaque;
    ssize_t ret;

65
    ret = bdrv_pread(bs->file, offset, buf, buflen);
66 67 68 69 70 71 72 73 74 75 76
    if (ret < 0) {
        error_setg_errno(errp, -ret, "Could not read encryption header");
        return ret;
    }
    return ret;
}


struct BlockCryptoCreateData {
    BlockBackend *blk;
    uint64_t size;
M
Maxim Levitsky 已提交
77
    PreallocMode prealloc;
78 79 80 81 82 83 84
};


static ssize_t block_crypto_write_func(QCryptoBlock *block,
                                       size_t offset,
                                       const uint8_t *buf,
                                       size_t buflen,
85
                                       void *opaque,
86
                                       Error **errp)
87 88 89 90
{
    struct BlockCryptoCreateData *data = opaque;
    ssize_t ret;

91
    ret = blk_pwrite(data->blk, offset, buf, buflen, 0);
92 93 94 95 96 97 98 99 100 101
    if (ret < 0) {
        error_setg_errno(errp, -ret, "Could not write encryption header");
        return ret;
    }
    return ret;
}


static ssize_t block_crypto_init_func(QCryptoBlock *block,
                                      size_t headerlen,
102
                                      void *opaque,
103
                                      Error **errp)
104 105 106
{
    struct BlockCryptoCreateData *data = opaque;

107 108 109 110 111
    if (data->size > INT64_MAX || headerlen > INT64_MAX - data->size) {
        error_setg(errp, "The requested file size is too large");
        return -EFBIG;
    }

112 113 114 115
    /* User provided size should reflect amount of space made
     * available to the guest, so we must take account of that
     * which will be used by the crypto header
     */
116 117
    return blk_truncate(data->blk, data->size + headerlen, false,
                        data->prealloc, errp);
118 119 120 121 122 123 124
}


static QemuOptsList block_crypto_runtime_opts_luks = {
    .name = "crypto",
    .head = QTAILQ_HEAD_INITIALIZER(block_crypto_runtime_opts_luks.head),
    .desc = {
125
        BLOCK_CRYPTO_OPT_DEF_LUKS_KEY_SECRET(""),
126 127 128 129 130 131 132 133 134 135 136 137 138 139
        { /* end of list */ }
    },
};


static QemuOptsList block_crypto_create_opts_luks = {
    .name = "crypto",
    .head = QTAILQ_HEAD_INITIALIZER(block_crypto_create_opts_luks.head),
    .desc = {
        {
            .name = BLOCK_OPT_SIZE,
            .type = QEMU_OPT_SIZE,
            .help = "Virtual disk size"
        },
140 141 142 143 144 145 146
        BLOCK_CRYPTO_OPT_DEF_LUKS_KEY_SECRET(""),
        BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_ALG(""),
        BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_MODE(""),
        BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_ALG(""),
        BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_HASH_ALG(""),
        BLOCK_CRYPTO_OPT_DEF_LUKS_HASH_ALG(""),
        BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME(""),
147 148 149 150 151
        { /* end of list */ }
    },
};


152
QCryptoBlockOpenOptions *
153
block_crypto_open_opts_init(QDict *opts, Error **errp)
154
{
155
    Visitor *v;
156
    QCryptoBlockOpenOptions *ret;
157

158
    v = qobject_input_visitor_new_flat_confused(opts, errp);
159
    if (!v) {
160
        return NULL;
161
    }
162

163
    visit_type_QCryptoBlockOpenOptions(v, NULL, &ret, errp);
164

165
    visit_free(v);
166 167 168 169
    return ret;
}


170
QCryptoBlockCreateOptions *
171
block_crypto_create_opts_init(QDict *opts, Error **errp)
172
{
173
    Visitor *v;
174
    QCryptoBlockCreateOptions *ret;
175

176
    v = qobject_input_visitor_new_flat_confused(opts, errp);
177
    if (!v) {
178
        return NULL;
179
    }
180

181
    visit_type_QCryptoBlockCreateOptions(v, NULL, &ret, errp);
182

183
    visit_free(v);
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
    return ret;
}


static int block_crypto_open_generic(QCryptoBlockFormat format,
                                     QemuOptsList *opts_spec,
                                     BlockDriverState *bs,
                                     QDict *options,
                                     int flags,
                                     Error **errp)
{
    BlockCrypto *crypto = bs->opaque;
    QemuOpts *opts = NULL;
    Error *local_err = NULL;
    int ret = -EINVAL;
    QCryptoBlockOpenOptions *open_opts = NULL;
    unsigned int cflags = 0;
201
    QDict *cryptoopts = NULL;
202

203 204 205 206 207 208
    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
                               false, errp);
    if (!bs->file) {
        return -EINVAL;
    }

209 210 211
    bs->supported_write_flags = BDRV_REQ_FUA &
        bs->file->bs->supported_write_flags;

212 213 214 215 216 217 218
    opts = qemu_opts_create(opts_spec, NULL, 0, &error_abort);
    qemu_opts_absorb_qdict(opts, options, &local_err);
    if (local_err) {
        error_propagate(errp, local_err);
        goto cleanup;
    }

219
    cryptoopts = qemu_opts_to_qdict(opts, NULL);
220
    qdict_put_str(cryptoopts, "format", QCryptoBlockFormat_str(format));
221

222
    open_opts = block_crypto_open_opts_init(cryptoopts, errp);
223 224 225 226 227 228 229
    if (!open_opts) {
        goto cleanup;
    }

    if (flags & BDRV_O_NO_IO) {
        cflags |= QCRYPTO_BLOCK_OPEN_NO_IO;
    }
230
    crypto->block = qcrypto_block_open(open_opts, NULL,
231 232 233
                                       block_crypto_read_func,
                                       bs,
                                       cflags,
234
                                       1,
235 236 237 238 239 240 241
                                       errp);

    if (!crypto->block) {
        ret = -EIO;
        goto cleanup;
    }

242
    bs->encrypted = true;
243 244 245

    ret = 0;
 cleanup:
246
    qobject_unref(cryptoopts);
247 248 249 250 251
    qapi_free_QCryptoBlockOpenOptions(open_opts);
    return ret;
}


252 253 254
static int block_crypto_co_create_generic(BlockDriverState *bs,
                                          int64_t size,
                                          QCryptoBlockCreateOptions *opts,
M
Maxim Levitsky 已提交
255
                                          PreallocMode prealloc,
256
                                          Error **errp)
257
{
258 259
    int ret;
    BlockBackend *blk;
260
    QCryptoBlock *crypto = NULL;
261
    struct BlockCryptoCreateData data;
262

K
Kevin Wolf 已提交
263 264
    blk = blk_new(bdrv_get_aio_context(bs),
                  BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
265

266
    ret = blk_insert_bs(blk, bs, errp);
267
    if (ret < 0) {
268
        goto cleanup;
269 270
    }

M
Maxim Levitsky 已提交
271 272 273 274
    if (prealloc == PREALLOC_MODE_METADATA) {
        prealloc = PREALLOC_MODE_OFF;
    }

275 276 277
    data = (struct BlockCryptoCreateData) {
        .blk = blk,
        .size = size,
M
Maxim Levitsky 已提交
278
        .prealloc = prealloc,
279
    };
280

281
    crypto = qcrypto_block_create(opts, NULL,
282 283 284 285 286 287 288 289 290 291 292 293 294
                                  block_crypto_init_func,
                                  block_crypto_write_func,
                                  &data,
                                  errp);

    if (!crypto) {
        ret = -EIO;
        goto cleanup;
    }

    ret = 0;
 cleanup:
    qcrypto_block_free(crypto);
295
    blk_unref(blk);
296 297 298
    return ret;
}

299
static int coroutine_fn
300
block_crypto_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
301
                         PreallocMode prealloc, Error **errp)
302 303
{
    BlockCrypto *crypto = bs->opaque;
304
    uint64_t payload_offset =
305
        qcrypto_block_get_payload_offset(crypto->block);
306 307 308 309 310

    if (payload_offset > INT64_MAX - offset) {
        error_setg(errp, "The requested file size is too large");
        return -EFBIG;
    }
311 312 313

    offset += payload_offset;

M
Max Reitz 已提交
314
    return bdrv_co_truncate(bs->file, offset, exact, prealloc, errp);
315 316 317 318 319 320 321 322
}

static void block_crypto_close(BlockDriverState *bs)
{
    BlockCrypto *crypto = bs->opaque;
    qcrypto_block_free(crypto->block);
}

323 324 325 326 327 328
static int block_crypto_reopen_prepare(BDRVReopenState *state,
                                       BlockReopenQueue *queue, Error **errp)
{
    /* nothing needs checking */
    return 0;
}
329

330 331 332 333 334
/*
 * 1 MB bounce buffer gives good performance / memory tradeoff
 * when using cache=none|directsync.
 */
#define BLOCK_CRYPTO_MAX_IO_SIZE (1024 * 1024)
335 336

static coroutine_fn int
337 338
block_crypto_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
                       QEMUIOVector *qiov, int flags)
339 340
{
    BlockCrypto *crypto = bs->opaque;
341
    uint64_t cur_bytes; /* number of bytes in current iteration */
342 343 344 345
    uint64_t bytes_done = 0;
    uint8_t *cipher_data = NULL;
    QEMUIOVector hd_qiov;
    int ret = 0;
346 347 348 349 350 351 352
    uint64_t sector_size = qcrypto_block_get_sector_size(crypto->block);
    uint64_t payload_offset = qcrypto_block_get_payload_offset(crypto->block);

    assert(!flags);
    assert(payload_offset < INT64_MAX);
    assert(QEMU_IS_ALIGNED(offset, sector_size));
    assert(QEMU_IS_ALIGNED(bytes, sector_size));
353 354 355

    qemu_iovec_init(&hd_qiov, qiov->niov);

356 357
    /* Bounce buffer because we don't wish to expose cipher text
     * in qiov which points to guest memory.
358 359
     */
    cipher_data =
360
        qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_IO_SIZE,
361 362 363 364 365 366
                                              qiov->size));
    if (cipher_data == NULL) {
        ret = -ENOMEM;
        goto cleanup;
    }

367 368
    while (bytes) {
        cur_bytes = MIN(bytes, BLOCK_CRYPTO_MAX_IO_SIZE);
369 370

        qemu_iovec_reset(&hd_qiov);
371
        qemu_iovec_add(&hd_qiov, cipher_data, cur_bytes);
372

373 374
        ret = bdrv_co_preadv(bs->file, payload_offset + offset + bytes_done,
                             cur_bytes, &hd_qiov, 0);
375 376 377 378
        if (ret < 0) {
            goto cleanup;
        }

379 380
        if (qcrypto_block_decrypt(crypto->block, offset + bytes_done,
                                  cipher_data, cur_bytes, NULL) < 0) {
381 382 383 384
            ret = -EIO;
            goto cleanup;
        }

385
        qemu_iovec_from_buf(qiov, bytes_done, cipher_data, cur_bytes);
386

387 388
        bytes -= cur_bytes;
        bytes_done += cur_bytes;
389 390 391 392 393 394 395 396 397 398 399
    }

 cleanup:
    qemu_iovec_destroy(&hd_qiov);
    qemu_vfree(cipher_data);

    return ret;
}


static coroutine_fn int
400 401
block_crypto_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
                        QEMUIOVector *qiov, int flags)
402 403
{
    BlockCrypto *crypto = bs->opaque;
404
    uint64_t cur_bytes; /* number of bytes in current iteration */
405 406 407 408
    uint64_t bytes_done = 0;
    uint8_t *cipher_data = NULL;
    QEMUIOVector hd_qiov;
    int ret = 0;
409 410 411
    uint64_t sector_size = qcrypto_block_get_sector_size(crypto->block);
    uint64_t payload_offset = qcrypto_block_get_payload_offset(crypto->block);

412
    assert(!(flags & ~BDRV_REQ_FUA));
413 414 415
    assert(payload_offset < INT64_MAX);
    assert(QEMU_IS_ALIGNED(offset, sector_size));
    assert(QEMU_IS_ALIGNED(bytes, sector_size));
416 417 418

    qemu_iovec_init(&hd_qiov, qiov->niov);

419 420
    /* Bounce buffer because we're not permitted to touch
     * contents of qiov - it points to guest memory.
421 422
     */
    cipher_data =
423
        qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_IO_SIZE,
424 425 426 427 428 429
                                              qiov->size));
    if (cipher_data == NULL) {
        ret = -ENOMEM;
        goto cleanup;
    }

430 431
    while (bytes) {
        cur_bytes = MIN(bytes, BLOCK_CRYPTO_MAX_IO_SIZE);
432

433
        qemu_iovec_to_buf(qiov, bytes_done, cipher_data, cur_bytes);
434

435 436
        if (qcrypto_block_encrypt(crypto->block, offset + bytes_done,
                                  cipher_data, cur_bytes, NULL) < 0) {
437 438 439 440 441
            ret = -EIO;
            goto cleanup;
        }

        qemu_iovec_reset(&hd_qiov);
442
        qemu_iovec_add(&hd_qiov, cipher_data, cur_bytes);
443

444
        ret = bdrv_co_pwritev(bs->file, payload_offset + offset + bytes_done,
445
                              cur_bytes, &hd_qiov, flags);
446 447 448 449
        if (ret < 0) {
            goto cleanup;
        }

450 451
        bytes -= cur_bytes;
        bytes_done += cur_bytes;
452 453 454 455 456 457 458 459 460
    }

 cleanup:
    qemu_iovec_destroy(&hd_qiov);
    qemu_vfree(cipher_data);

    return ret;
}

461 462 463 464 465 466 467
static void block_crypto_refresh_limits(BlockDriverState *bs, Error **errp)
{
    BlockCrypto *crypto = bs->opaque;
    uint64_t sector_size = qcrypto_block_get_sector_size(crypto->block);
    bs->bl.request_alignment = sector_size; /* No sub-sector I/O */
}

468 469 470 471 472 473

static int64_t block_crypto_getlength(BlockDriverState *bs)
{
    BlockCrypto *crypto = bs->opaque;
    int64_t len = bdrv_getlength(bs->file->bs);

474 475
    uint64_t offset = qcrypto_block_get_payload_offset(crypto->block);
    assert(offset < INT64_MAX);
476 477 478 479

    if (offset > len) {
        return -EIO;
    }
480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503

    len -= offset;

    return len;
}


static int block_crypto_probe_luks(const uint8_t *buf,
                                   int buf_size,
                                   const char *filename) {
    return block_crypto_probe_generic(Q_CRYPTO_BLOCK_FORMAT_LUKS,
                                      buf, buf_size, filename);
}

static int block_crypto_open_luks(BlockDriverState *bs,
                                  QDict *options,
                                  int flags,
                                  Error **errp)
{
    return block_crypto_open_generic(Q_CRYPTO_BLOCK_FORMAT_LUKS,
                                     &block_crypto_runtime_opts_luks,
                                     bs, options, flags, errp);
}

K
Kevin Wolf 已提交
504 505 506 507 508 509
static int coroutine_fn
block_crypto_co_create_luks(BlockdevCreateOptions *create_options, Error **errp)
{
    BlockdevCreateOptionsLUKS *luks_opts;
    BlockDriverState *bs = NULL;
    QCryptoBlockCreateOptions create_opts;
M
Maxim Levitsky 已提交
510
    PreallocMode preallocation = PREALLOC_MODE_OFF;
K
Kevin Wolf 已提交
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525
    int ret;

    assert(create_options->driver == BLOCKDEV_DRIVER_LUKS);
    luks_opts = &create_options->u.luks;

    bs = bdrv_open_blockdev_ref(luks_opts->file, errp);
    if (bs == NULL) {
        return -EIO;
    }

    create_opts = (QCryptoBlockCreateOptions) {
        .format = Q_CRYPTO_BLOCK_FORMAT_LUKS,
        .u.luks = *qapi_BlockdevCreateOptionsLUKS_base(luks_opts),
    };

M
Maxim Levitsky 已提交
526 527 528 529
    if (luks_opts->has_preallocation) {
        preallocation = luks_opts->preallocation;
    }

K
Kevin Wolf 已提交
530
    ret = block_crypto_co_create_generic(bs, luks_opts->size, &create_opts,
M
Maxim Levitsky 已提交
531
                                         preallocation, errp);
K
Kevin Wolf 已提交
532 533 534 535 536 537 538 539 540 541
    if (ret < 0) {
        goto fail;
    }

    ret = 0;
fail:
    bdrv_unref(bs);
    return ret;
}

542 543 544
static int coroutine_fn block_crypto_co_create_opts_luks(const char *filename,
                                                         QemuOpts *opts,
                                                         Error **errp)
545
{
546 547 548
    QCryptoBlockCreateOptions *create_opts = NULL;
    BlockDriverState *bs = NULL;
    QDict *cryptoopts;
M
Maxim Levitsky 已提交
549 550
    PreallocMode prealloc;
    char *buf = NULL;
551 552
    int64_t size;
    int ret;
M
Maxim Levitsky 已提交
553
    Error *local_err = NULL;
554 555 556 557

    /* Parse options */
    size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);

M
Maxim Levitsky 已提交
558 559 560 561 562 563 564 565 566
    buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
    prealloc = qapi_enum_parse(&PreallocMode_lookup, buf,
                               PREALLOC_MODE_OFF, &local_err);
    g_free(buf);
    if (local_err) {
        error_propagate(errp, local_err);
        return -EINVAL;
    }

567 568 569 570
    cryptoopts = qemu_opts_to_qdict_filtered(opts, NULL,
                                             &block_crypto_create_opts_luks,
                                             true);

571 572
    qdict_put_str(cryptoopts, "format", "luks");
    create_opts = block_crypto_create_opts_init(cryptoopts, errp);
573 574 575 576 577 578 579 580
    if (!create_opts) {
        ret = -EINVAL;
        goto fail;
    }

    /* Create protocol layer */
    ret = bdrv_create_file(filename, opts, errp);
    if (ret < 0) {
581
        goto fail;
582 583 584 585 586 587 588 589 590 591
    }

    bs = bdrv_open(filename, NULL, NULL,
                   BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
    if (!bs) {
        ret = -EINVAL;
        goto fail;
    }

    /* Create format layer */
M
Maxim Levitsky 已提交
592
    ret = block_crypto_co_create_generic(bs, size, create_opts, prealloc, errp);
593 594 595 596 597 598 599 600
    if (ret < 0) {
        goto fail;
    }

    ret = 0;
fail:
    bdrv_unref(bs);
    qapi_free_QCryptoBlockCreateOptions(create_opts);
601
    qobject_unref(cryptoopts);
602
    return ret;
603 604
}

605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622
static int block_crypto_get_info_luks(BlockDriverState *bs,
                                      BlockDriverInfo *bdi)
{
    BlockDriverInfo subbdi;
    int ret;

    ret = bdrv_get_info(bs->file->bs, &subbdi);
    if (ret != 0) {
        return ret;
    }

    bdi->unallocated_blocks_are_zero = false;
    bdi->cluster_size = subbdi.cluster_size;

    return 0;
}

static ImageInfoSpecific *
623
block_crypto_get_specific_info_luks(BlockDriverState *bs, Error **errp)
624 625 626 627 628
{
    BlockCrypto *crypto = bs->opaque;
    ImageInfoSpecific *spec_info;
    QCryptoBlockInfo *info;

629
    info = qcrypto_block_get_info(crypto->block, errp);
630 631 632
    if (!info) {
        return NULL;
    }
633
    assert(info->format == Q_CRYPTO_BLOCK_FORMAT_LUKS);
634 635 636 637 638 639 640 641 642 643 644 645 646 647

    spec_info = g_new(ImageInfoSpecific, 1);
    spec_info->type = IMAGE_INFO_SPECIFIC_KIND_LUKS;
    spec_info->u.luks.data = g_new(QCryptoBlockInfoLUKS, 1);
    *spec_info->u.luks.data = info->u.luks;

    /* Blank out pointers we've just stolen to avoid double free */
    memset(&info->u.luks, 0, sizeof(info->u.luks));

    qapi_free_QCryptoBlockInfo(info);

    return spec_info;
}

648 649 650 651 652 653
static const char *const block_crypto_strong_runtime_opts[] = {
    BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET,

    NULL
};

654
static BlockDriver bdrv_crypto_luks = {
655 656 657 658 659
    .format_name        = "luks",
    .instance_size      = sizeof(BlockCrypto),
    .bdrv_probe         = block_crypto_probe_luks,
    .bdrv_open          = block_crypto_open_luks,
    .bdrv_close         = block_crypto_close,
F
Fam Zheng 已提交
660 661 662
    /* This driver doesn't modify LUKS metadata except when creating image.
     * Allow share-rw=on as a special case. */
    .bdrv_child_perm    = bdrv_filter_default_perms,
K
Kevin Wolf 已提交
663
    .bdrv_co_create     = block_crypto_co_create_luks,
664
    .bdrv_co_create_opts = block_crypto_co_create_opts_luks,
665
    .bdrv_co_truncate   = block_crypto_co_truncate,
666 667
    .create_opts        = &block_crypto_create_opts_luks,

668
    .bdrv_reopen_prepare = block_crypto_reopen_prepare,
669 670 671
    .bdrv_refresh_limits = block_crypto_refresh_limits,
    .bdrv_co_preadv     = block_crypto_co_preadv,
    .bdrv_co_pwritev    = block_crypto_co_pwritev,
672
    .bdrv_getlength     = block_crypto_getlength,
673 674
    .bdrv_get_info      = block_crypto_get_info_luks,
    .bdrv_get_specific_info = block_crypto_get_specific_info_luks,
675 676

    .strong_runtime_opts = block_crypto_strong_runtime_opts,
677 678 679 680 681 682 683 684
};

static void block_crypto_init(void)
{
    bdrv_register(&bdrv_crypto_luks);
}

block_init(block_crypto_init);