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-common.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    Error *local_err = NULL;
  27    int ret;
  28
  29    /* Open the image file */
  30    bs->file = bdrv_open_child(NULL, options, "image",
  31                               bs, &child_file, false, &local_err);
  32    if (local_err) {
  33        ret = -EINVAL;
  34        error_propagate(errp, local_err);
  35        goto fail;
  36    }
  37
  38    ret = 0;
  39fail:
  40    if (ret < 0) {
  41        bdrv_unref_child(bs, bs->file);
  42    }
  43    return ret;
  44}
  45
  46static void blkreplay_close(BlockDriverState *bs)
  47{
  48}
  49
  50static int64_t blkreplay_getlength(BlockDriverState *bs)
  51{
  52    return bdrv_getlength(bs->file->bs);
  53}
  54
  55/* This bh is used for synchronization of return from coroutines.
  56   It continues yielded coroutine which then finishes its execution.
  57   BH is called adjusted to some replay checkpoint, therefore
  58   record and replay will always finish coroutines deterministically.
  59*/
  60static void blkreplay_bh_cb(void *opaque)
  61{
  62    Request *req = opaque;
  63    qemu_coroutine_enter(req->co);
  64    qemu_bh_delete(req->bh);
  65    g_free(req);
  66}
  67
  68static void block_request_create(uint64_t reqid, BlockDriverState *bs,
  69                                 Coroutine *co)
  70{
  71    Request *req = g_new(Request, 1);
  72    *req = (Request) {
  73        .co = co,
  74        .bh = aio_bh_new(bdrv_get_aio_context(bs), blkreplay_bh_cb, req),
  75    };
  76    replay_block_event(req->bh, reqid);
  77}
  78
  79static int coroutine_fn blkreplay_co_preadv(BlockDriverState *bs,
  80    uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags)
  81{
  82    uint64_t reqid = blkreplay_next_id();
  83    int ret = bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
  84    block_request_create(reqid, bs, qemu_coroutine_self());
  85    qemu_coroutine_yield();
  86
  87    return ret;
  88}
  89
  90static int coroutine_fn blkreplay_co_pwritev(BlockDriverState *bs,
  91    uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags)
  92{
  93    uint64_t reqid = blkreplay_next_id();
  94    int ret = bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
  95    block_request_create(reqid, bs, qemu_coroutine_self());
  96    qemu_coroutine_yield();
  97
  98    return ret;
  99}
 100
 101static int coroutine_fn blkreplay_co_pwrite_zeroes(BlockDriverState *bs,
 102    int64_t offset, int count, BdrvRequestFlags flags)
 103{
 104    uint64_t reqid = blkreplay_next_id();
 105    int ret = bdrv_co_pwrite_zeroes(bs->file, offset, count, flags);
 106    block_request_create(reqid, bs, qemu_coroutine_self());
 107    qemu_coroutine_yield();
 108
 109    return ret;
 110}
 111
 112static int coroutine_fn blkreplay_co_pdiscard(BlockDriverState *bs,
 113                                              int64_t offset, int count)
 114{
 115    uint64_t reqid = blkreplay_next_id();
 116    int ret = bdrv_co_pdiscard(bs->file->bs, offset, count);
 117    block_request_create(reqid, bs, qemu_coroutine_self());
 118    qemu_coroutine_yield();
 119
 120    return ret;
 121}
 122
 123static int coroutine_fn blkreplay_co_flush(BlockDriverState *bs)
 124{
 125    uint64_t reqid = blkreplay_next_id();
 126    int ret = bdrv_co_flush(bs->file->bs);
 127    block_request_create(reqid, bs, qemu_coroutine_self());
 128    qemu_coroutine_yield();
 129
 130    return ret;
 131}
 132
 133static BlockDriver bdrv_blkreplay = {
 134    .format_name            = "blkreplay",
 135    .protocol_name          = "blkreplay",
 136    .instance_size          = 0,
 137
 138    .bdrv_file_open         = blkreplay_open,
 139    .bdrv_close             = blkreplay_close,
 140    .bdrv_getlength         = blkreplay_getlength,
 141
 142    .bdrv_co_preadv         = blkreplay_co_preadv,
 143    .bdrv_co_pwritev        = blkreplay_co_pwritev,
 144
 145    .bdrv_co_pwrite_zeroes  = blkreplay_co_pwrite_zeroes,
 146    .bdrv_co_pdiscard       = blkreplay_co_pdiscard,
 147    .bdrv_co_flush          = blkreplay_co_flush,
 148};
 149
 150static void bdrv_blkreplay_init(void)
 151{
 152    bdrv_register(&bdrv_blkreplay);
 153}
 154
 155block_init(bdrv_blkreplay_init);
 156