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