1
2
3
4
5
6
7
8
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 Error *local_err = NULL;
27 int ret;
28
29
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 bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED;
39 bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED;
40
41 ret = 0;
42fail:
43 return ret;
44}
45
46static int64_t blkreplay_getlength(BlockDriverState *bs)
47{
48 return bdrv_getlength(bs->file->bs);
49}
50
51
52
53
54
55
56static void blkreplay_bh_cb(void *opaque)
57{
58 Request *req = opaque;
59 aio_co_wake(req->co);
60 qemu_bh_delete(req->bh);
61 g_free(req);
62}
63
64static void block_request_create(uint64_t reqid, BlockDriverState *bs,
65 Coroutine *co)
66{
67 Request *req = g_new(Request, 1);
68 *req = (Request) {
69 .co = co,
70 .bh = aio_bh_new(bdrv_get_aio_context(bs), blkreplay_bh_cb, req),
71 };
72 replay_block_event(req->bh, reqid);
73}
74
75static int coroutine_fn blkreplay_co_preadv(BlockDriverState *bs,
76 uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags)
77{
78 uint64_t reqid = blkreplay_next_id();
79 int ret = bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
80 block_request_create(reqid, bs, qemu_coroutine_self());
81 qemu_coroutine_yield();
82
83 return ret;
84}
85
86static int coroutine_fn blkreplay_co_pwritev(BlockDriverState *bs,
87 uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags)
88{
89 uint64_t reqid = blkreplay_next_id();
90 int ret = bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
91 block_request_create(reqid, bs, qemu_coroutine_self());
92 qemu_coroutine_yield();
93
94 return ret;
95}
96
97static int coroutine_fn blkreplay_co_pwrite_zeroes(BlockDriverState *bs,
98 int64_t offset, int bytes, BdrvRequestFlags flags)
99{
100 uint64_t reqid = blkreplay_next_id();
101 int ret = bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
102 block_request_create(reqid, bs, qemu_coroutine_self());
103 qemu_coroutine_yield();
104
105 return ret;
106}
107
108static int coroutine_fn blkreplay_co_pdiscard(BlockDriverState *bs,
109 int64_t offset, int bytes)
110{
111 uint64_t reqid = blkreplay_next_id();
112 int ret = bdrv_co_pdiscard(bs->file, offset, bytes);
113 block_request_create(reqid, bs, qemu_coroutine_self());
114 qemu_coroutine_yield();
115
116 return ret;
117}
118
119static int coroutine_fn blkreplay_co_flush(BlockDriverState *bs)
120{
121 uint64_t reqid = blkreplay_next_id();
122 int ret = bdrv_co_flush(bs->file->bs);
123 block_request_create(reqid, bs, qemu_coroutine_self());
124 qemu_coroutine_yield();
125
126 return ret;
127}
128
129static BlockDriver bdrv_blkreplay = {
130 .format_name = "blkreplay",
131 .instance_size = 0,
132
133 .bdrv_open = blkreplay_open,
134 .bdrv_child_perm = bdrv_filter_default_perms,
135 .bdrv_getlength = blkreplay_getlength,
136
137 .bdrv_co_preadv = blkreplay_co_preadv,
138 .bdrv_co_pwritev = blkreplay_co_pwritev,
139
140 .bdrv_co_pwrite_zeroes = blkreplay_co_pwrite_zeroes,
141 .bdrv_co_pdiscard = blkreplay_co_pdiscard,
142 .bdrv_co_flush = blkreplay_co_flush,
143};
144
145static void bdrv_blkreplay_init(void)
146{
147 bdrv_register(&bdrv_blkreplay);
148}
149
150block_init(bdrv_blkreplay_init);
151