qemu/block/blkreplay.c
<<
>>
Prefs
   1/*
   2 * Block protocol for record/replay
   3 *
   4 * Copyright (c) 2010-2016 Institute for System Programming
   5 *                         of the Russian Academy of Sciences.
   6 *
   7 * This work is licensed under the terms of the GNU GPL, version 2 or later.
   8 * See the COPYING file in the top-level directory.
   9 *
  10 */
  11
  12#include "qemu/osdep.h"
  13#include "qemu/module.h"
  14#include "block/block_int.h"
  15#include "sysemu/replay.h"
  16#include "qapi/error.h"
  17
  18typedef struct Request {
  19    Coroutine *co;
  20    QEMUBH *bh;
  21} Request;
  22
  23static int blkreplay_open(BlockDriverState *bs, QDict *options, int flags,
  24                          Error **errp)
  25{
  26    int ret;
  27
  28    /* Open the image file */
  29    bs->file = bdrv_open_child(NULL, options, "image", bs, &child_of_bds,
  30                               BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
  31                               false, errp);
  32    if (!bs->file) {
  33        ret = -EINVAL;
  34        goto fail;
  35    }
  36
  37    bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED;
  38    bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED;
  39
  40    ret = 0;
  41fail:
  42    return ret;
  43}
  44
  45static int64_t blkreplay_getlength(BlockDriverState *bs)
  46{
  47    return bdrv_getlength(bs->file->bs);
  48}
  49
  50/* This bh is used for synchronization of return from coroutines.
  51   It continues yielded coroutine which then finishes its execution.
  52   BH is called adjusted to some replay checkpoint, therefore
  53   record and replay will always finish coroutines deterministically.
  54*/
  55static void blkreplay_bh_cb(void *opaque)
  56{
  57    Request *req = opaque;
  58    aio_co_wake(req->co);
  59    qemu_bh_delete(req->bh);
  60    g_free(req);
  61}
  62
  63static void block_request_create(uint64_t reqid, BlockDriverState *bs,
  64                                 Coroutine *co)
  65{
  66    Request *req = g_new(Request, 1);
  67    *req = (Request) {
  68        .co = co,
  69        .bh = aio_bh_new(bdrv_get_aio_context(bs), blkreplay_bh_cb, req),
  70    };
  71    replay_block_event(req->bh, reqid);
  72}
  73
  74static int coroutine_fn blkreplay_co_preadv(BlockDriverState *bs,
  75    int64_t offset, int64_t bytes, QEMUIOVector *qiov, BdrvRequestFlags flags)
  76{
  77    uint64_t reqid = blkreplay_next_id();
  78    int ret = bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
  79    block_request_create(reqid, bs, qemu_coroutine_self());
  80    qemu_coroutine_yield();
  81
  82    return ret;
  83}
  84
  85static int coroutine_fn blkreplay_co_pwritev(BlockDriverState *bs,
  86    int64_t offset, int64_t bytes, QEMUIOVector *qiov, BdrvRequestFlags flags)
  87{
  88    uint64_t reqid = blkreplay_next_id();
  89    int ret = bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
  90    block_request_create(reqid, bs, qemu_coroutine_self());
  91    qemu_coroutine_yield();
  92
  93    return ret;
  94}
  95
  96static int coroutine_fn blkreplay_co_pwrite_zeroes(BlockDriverState *bs,
  97    int64_t offset, int64_t bytes, BdrvRequestFlags flags)
  98{
  99    uint64_t reqid = blkreplay_next_id();
 100    int ret = bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
 101    block_request_create(reqid, bs, qemu_coroutine_self());
 102    qemu_coroutine_yield();
 103
 104    return ret;
 105}
 106
 107static int coroutine_fn blkreplay_co_pdiscard(BlockDriverState *bs,
 108                                              int64_t offset, int64_t bytes)
 109{
 110    uint64_t reqid = blkreplay_next_id();
 111    int ret = bdrv_co_pdiscard(bs->file, offset, bytes);
 112    block_request_create(reqid, bs, qemu_coroutine_self());
 113    qemu_coroutine_yield();
 114
 115    return ret;
 116}
 117
 118static int coroutine_fn blkreplay_co_flush(BlockDriverState *bs)
 119{
 120    uint64_t reqid = blkreplay_next_id();
 121    int ret = bdrv_co_flush(bs->file->bs);
 122    block_request_create(reqid, bs, qemu_coroutine_self());
 123    qemu_coroutine_yield();
 124
 125    return ret;
 126}
 127
 128static int blkreplay_snapshot_goto(BlockDriverState *bs,
 129                                   const char *snapshot_id)
 130{
 131    return bdrv_snapshot_goto(bs->file->bs, snapshot_id, NULL);
 132}
 133
 134static BlockDriver bdrv_blkreplay = {
 135    .format_name            = "blkreplay",
 136    .instance_size          = 0,
 137    .is_filter              = true,
 138
 139    .bdrv_open              = blkreplay_open,
 140    .bdrv_child_perm        = bdrv_default_perms,
 141    .bdrv_getlength         = blkreplay_getlength,
 142
 143    .bdrv_co_preadv         = blkreplay_co_preadv,
 144    .bdrv_co_pwritev        = blkreplay_co_pwritev,
 145
 146    .bdrv_co_pwrite_zeroes  = blkreplay_co_pwrite_zeroes,
 147    .bdrv_co_pdiscard       = blkreplay_co_pdiscard,
 148    .bdrv_co_flush          = blkreplay_co_flush,
 149
 150    .bdrv_snapshot_goto     = blkreplay_snapshot_goto,
 151};
 152
 153static void bdrv_blkreplay_init(void)
 154{
 155    bdrv_register(&bdrv_blkreplay);
 156}
 157
 158block_init(bdrv_blkreplay_init);
 159