]> git.proxmox.com Git - mirror_qemu.git/blame - block/blkreplay.c
MAINTAINERS: Change my email address
[mirror_qemu.git] / block / blkreplay.c
CommitLineData
63785678
PD
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"
0b8fa32f 13#include "qemu/module.h"
63785678
PD
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
63785678
PD
23static int blkreplay_open(BlockDriverState *bs, QDict *options, int flags,
24 Error **errp)
25{
63785678
PD
26 int ret;
27
28 /* Open the image file */
b3af2af4
HR
29 bs->file = bdrv_open_child(NULL, options, "image", bs, &child_of_bds,
30 BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
bc520249
VSO
31 false, errp);
32 if (!bs->file) {
63785678 33 ret = -EINVAL;
63785678
PD
34 goto fail;
35 }
36
228345bf
HR
37 bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED;
38 bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED;
39
63785678
PD
40 ret = 0;
41fail:
63785678
PD
42 return ret;
43}
44
63785678
PD
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;
1919631e 58 aio_co_wake(req->co);
63785678
PD
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
e858a970 74static int coroutine_fn blkreplay_co_preadv(BlockDriverState *bs,
f7ef38dd 75 int64_t offset, int64_t bytes, QEMUIOVector *qiov, BdrvRequestFlags flags)
63785678 76{
6d0ceb80 77 uint64_t reqid = blkreplay_next_id();
a03ef88f 78 int ret = bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
63785678
PD
79 block_request_create(reqid, bs, qemu_coroutine_self());
80 qemu_coroutine_yield();
81
82 return ret;
83}
84
e858a970 85static int coroutine_fn blkreplay_co_pwritev(BlockDriverState *bs,
e75abeda 86 int64_t offset, int64_t bytes, QEMUIOVector *qiov, BdrvRequestFlags flags)
63785678 87{
6d0ceb80 88 uint64_t reqid = blkreplay_next_id();
a03ef88f 89 int ret = bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
63785678
PD
90 block_request_create(reqid, bs, qemu_coroutine_self());
91 qemu_coroutine_yield();
92
93 return ret;
94}
95
9c21a422 96static int coroutine_fn blkreplay_co_pwrite_zeroes(BlockDriverState *bs,
f34b2bcf 97 int64_t offset, int64_t bytes, BdrvRequestFlags flags)
63785678 98{
6d0ceb80 99 uint64_t reqid = blkreplay_next_id();
f5a5ca79 100 int ret = bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
63785678
PD
101 block_request_create(reqid, bs, qemu_coroutine_self());
102 qemu_coroutine_yield();
103
104 return ret;
105}
106
aba76e2f 107static int coroutine_fn blkreplay_co_pdiscard(BlockDriverState *bs,
0c802287 108 int64_t offset, int64_t bytes)
63785678 109{
6d0ceb80 110 uint64_t reqid = blkreplay_next_id();
0b9fd3f4 111 int ret = bdrv_co_pdiscard(bs->file, offset, bytes);
63785678
PD
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{
6d0ceb80 120 uint64_t reqid = blkreplay_next_id();
63785678
PD
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
3c6c4348
PD
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
63785678
PD
134static BlockDriver bdrv_blkreplay = {
135 .format_name = "blkreplay",
63785678 136 .instance_size = 0,
6540fd15 137 .is_filter = true,
63785678 138
8140e786 139 .bdrv_open = blkreplay_open,
69dca43d 140 .bdrv_child_perm = bdrv_default_perms,
63785678
PD
141 .bdrv_getlength = blkreplay_getlength,
142
e858a970
KW
143 .bdrv_co_preadv = blkreplay_co_preadv,
144 .bdrv_co_pwritev = blkreplay_co_pwritev,
63785678 145
9c21a422 146 .bdrv_co_pwrite_zeroes = blkreplay_co_pwrite_zeroes,
aba76e2f 147 .bdrv_co_pdiscard = blkreplay_co_pdiscard,
63785678 148 .bdrv_co_flush = blkreplay_co_flush,
3c6c4348
PD
149
150 .bdrv_snapshot_goto = blkreplay_snapshot_goto,
63785678
PD
151};
152
153static void bdrv_blkreplay_init(void)
154{
155 bdrv_register(&bdrv_blkreplay);
156}
157
158block_init(bdrv_blkreplay_init);