123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- /*
- * Block protocol for record/replay
- *
- * Copyright (c) 2010-2016 Institute for System Programming
- * of the Russian Academy of Sciences.
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
- #include "qemu/osdep.h"
- #include "qemu/module.h"
- #include "block/block-io.h"
- #include "block/block_int.h"
- #include "system/replay.h"
- #include "qapi/error.h"
- typedef struct Request {
- Coroutine *co;
- QEMUBH *bh;
- } Request;
- static int blkreplay_open(BlockDriverState *bs, QDict *options, int flags,
- Error **errp)
- {
- int ret;
- /* Open the image file */
- ret = bdrv_open_file_child(NULL, options, "image", bs, errp);
- if (ret < 0) {
- goto fail;
- }
- bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED;
- bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED;
- ret = 0;
- fail:
- return ret;
- }
- static int64_t coroutine_fn GRAPH_RDLOCK
- blkreplay_co_getlength(BlockDriverState *bs)
- {
- return bdrv_co_getlength(bs->file->bs);
- }
- /* This bh is used for synchronization of return from coroutines.
- It continues yielded coroutine which then finishes its execution.
- BH is called adjusted to some replay checkpoint, therefore
- record and replay will always finish coroutines deterministically.
- */
- static void blkreplay_bh_cb(void *opaque)
- {
- Request *req = opaque;
- aio_co_wake(req->co);
- qemu_bh_delete(req->bh);
- g_free(req);
- }
- static void block_request_create(uint64_t reqid, BlockDriverState *bs,
- Coroutine *co)
- {
- Request *req = g_new(Request, 1);
- *req = (Request) {
- .co = co,
- .bh = aio_bh_new(bdrv_get_aio_context(bs), blkreplay_bh_cb, req),
- };
- replay_block_event(req->bh, reqid);
- }
- static int coroutine_fn GRAPH_RDLOCK
- blkreplay_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
- QEMUIOVector *qiov, BdrvRequestFlags flags)
- {
- uint64_t reqid = blkreplay_next_id();
- int ret = bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
- block_request_create(reqid, bs, qemu_coroutine_self());
- qemu_coroutine_yield();
- return ret;
- }
- static int coroutine_fn GRAPH_RDLOCK
- blkreplay_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
- QEMUIOVector *qiov, BdrvRequestFlags flags)
- {
- uint64_t reqid = blkreplay_next_id();
- int ret = bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
- block_request_create(reqid, bs, qemu_coroutine_self());
- qemu_coroutine_yield();
- return ret;
- }
- static int coroutine_fn GRAPH_RDLOCK
- blkreplay_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes,
- BdrvRequestFlags flags)
- {
- uint64_t reqid = blkreplay_next_id();
- int ret = bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
- block_request_create(reqid, bs, qemu_coroutine_self());
- qemu_coroutine_yield();
- return ret;
- }
- static int coroutine_fn GRAPH_RDLOCK
- blkreplay_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
- {
- uint64_t reqid = blkreplay_next_id();
- int ret = bdrv_co_pdiscard(bs->file, offset, bytes);
- block_request_create(reqid, bs, qemu_coroutine_self());
- qemu_coroutine_yield();
- return ret;
- }
- static int coroutine_fn GRAPH_RDLOCK blkreplay_co_flush(BlockDriverState *bs)
- {
- uint64_t reqid = blkreplay_next_id();
- int ret = bdrv_co_flush(bs->file->bs);
- block_request_create(reqid, bs, qemu_coroutine_self());
- qemu_coroutine_yield();
- return ret;
- }
- static int blkreplay_snapshot_goto(BlockDriverState *bs,
- const char *snapshot_id)
- {
- BlockDriverState *file_bs;
- bdrv_graph_rdlock_main_loop();
- file_bs = bs->file->bs;
- bdrv_graph_rdunlock_main_loop();
- return bdrv_snapshot_goto(file_bs, snapshot_id, NULL);
- }
- static BlockDriver bdrv_blkreplay = {
- .format_name = "blkreplay",
- .instance_size = 0,
- .is_filter = true,
- .bdrv_open = blkreplay_open,
- .bdrv_child_perm = bdrv_default_perms,
- .bdrv_co_getlength = blkreplay_co_getlength,
- .bdrv_co_preadv = blkreplay_co_preadv,
- .bdrv_co_pwritev = blkreplay_co_pwritev,
- .bdrv_co_pwrite_zeroes = blkreplay_co_pwrite_zeroes,
- .bdrv_co_pdiscard = blkreplay_co_pdiscard,
- .bdrv_co_flush = blkreplay_co_flush,
- .bdrv_snapshot_goto = blkreplay_snapshot_goto,
- };
- static void bdrv_blkreplay_init(void)
- {
- bdrv_register(&bdrv_blkreplay);
- }
- block_init(bdrv_blkreplay_init);
|