root / block / blkdebug.c @ 5d259fc7
History | View | Annotate | Download (19.9 kB)
1 | 6a143727 | Kevin Wolf | /*
|
---|---|---|---|
2 | 6a143727 | Kevin Wolf | * Block protocol for I/O error injection
|
3 | 6a143727 | Kevin Wolf | *
|
4 | 6a143727 | Kevin Wolf | * Copyright (c) 2010 Kevin Wolf <kwolf@redhat.com>
|
5 | 6a143727 | Kevin Wolf | *
|
6 | 6a143727 | Kevin Wolf | * Permission is hereby granted, free of charge, to any person obtaining a copy
|
7 | 6a143727 | Kevin Wolf | * of this software and associated documentation files (the "Software"), to deal
|
8 | 6a143727 | Kevin Wolf | * in the Software without restriction, including without limitation the rights
|
9 | 6a143727 | Kevin Wolf | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10 | 6a143727 | Kevin Wolf | * copies of the Software, and to permit persons to whom the Software is
|
11 | 6a143727 | Kevin Wolf | * furnished to do so, subject to the following conditions:
|
12 | 6a143727 | Kevin Wolf | *
|
13 | 6a143727 | Kevin Wolf | * The above copyright notice and this permission notice shall be included in
|
14 | 6a143727 | Kevin Wolf | * all copies or substantial portions of the Software.
|
15 | 6a143727 | Kevin Wolf | *
|
16 | 6a143727 | Kevin Wolf | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17 | 6a143727 | Kevin Wolf | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18 | 6a143727 | Kevin Wolf | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
19 | 6a143727 | Kevin Wolf | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20 | 6a143727 | Kevin Wolf | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21 | 6a143727 | Kevin Wolf | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22 | 6a143727 | Kevin Wolf | * THE SOFTWARE.
|
23 | 6a143727 | Kevin Wolf | */
|
24 | 6a143727 | Kevin Wolf | |
25 | 6a143727 | Kevin Wolf | #include "qemu-common.h" |
26 | 1de7afc9 | Paolo Bonzini | #include "qemu/config-file.h" |
27 | 737e150e | Paolo Bonzini | #include "block/block_int.h" |
28 | 1de7afc9 | Paolo Bonzini | #include "qemu/module.h" |
29 | 6a143727 | Kevin Wolf | |
30 | 6a143727 | Kevin Wolf | typedef struct BDRVBlkdebugState { |
31 | 571cd43e | Paolo Bonzini | int state;
|
32 | 8f96b5be | Paolo Bonzini | int new_state;
|
33 | 3c90c65d | Kevin Wolf | |
34 | 571cd43e | Paolo Bonzini | QLIST_HEAD(, BlkdebugRule) rules[BLKDBG_EVENT_MAX]; |
35 | 571cd43e | Paolo Bonzini | QSIMPLEQ_HEAD(, BlkdebugRule) active_rules; |
36 | 3c90c65d | Kevin Wolf | QLIST_HEAD(, BlkdebugSuspendedReq) suspended_reqs; |
37 | 6a143727 | Kevin Wolf | } BDRVBlkdebugState; |
38 | 6a143727 | Kevin Wolf | |
39 | b9f66d96 | Kevin Wolf | typedef struct BlkdebugAIOCB { |
40 | b9f66d96 | Kevin Wolf | BlockDriverAIOCB common; |
41 | b9f66d96 | Kevin Wolf | QEMUBH *bh; |
42 | b9f66d96 | Kevin Wolf | int ret;
|
43 | b9f66d96 | Kevin Wolf | } BlkdebugAIOCB; |
44 | b9f66d96 | Kevin Wolf | |
45 | 3c90c65d | Kevin Wolf | typedef struct BlkdebugSuspendedReq { |
46 | 3c90c65d | Kevin Wolf | Coroutine *co; |
47 | 3c90c65d | Kevin Wolf | char *tag;
|
48 | 3c90c65d | Kevin Wolf | QLIST_ENTRY(BlkdebugSuspendedReq) next; |
49 | 3c90c65d | Kevin Wolf | } BlkdebugSuspendedReq; |
50 | 3c90c65d | Kevin Wolf | |
51 | b9f66d96 | Kevin Wolf | static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb); |
52 | b9f66d96 | Kevin Wolf | |
53 | d7331bed | Stefan Hajnoczi | static const AIOCBInfo blkdebug_aiocb_info = { |
54 | b9f66d96 | Kevin Wolf | .aiocb_size = sizeof(BlkdebugAIOCB),
|
55 | b9f66d96 | Kevin Wolf | .cancel = blkdebug_aio_cancel, |
56 | b9f66d96 | Kevin Wolf | }; |
57 | b9f66d96 | Kevin Wolf | |
58 | 8b9b0cc2 | Kevin Wolf | enum {
|
59 | 8b9b0cc2 | Kevin Wolf | ACTION_INJECT_ERROR, |
60 | 8b9b0cc2 | Kevin Wolf | ACTION_SET_STATE, |
61 | 3c90c65d | Kevin Wolf | ACTION_SUSPEND, |
62 | 8b9b0cc2 | Kevin Wolf | }; |
63 | 8b9b0cc2 | Kevin Wolf | |
64 | 8b9b0cc2 | Kevin Wolf | typedef struct BlkdebugRule { |
65 | 8b9b0cc2 | Kevin Wolf | BlkDebugEvent event; |
66 | 8b9b0cc2 | Kevin Wolf | int action;
|
67 | 8b9b0cc2 | Kevin Wolf | int state;
|
68 | 8b9b0cc2 | Kevin Wolf | union {
|
69 | 8b9b0cc2 | Kevin Wolf | struct {
|
70 | 8b9b0cc2 | Kevin Wolf | int error;
|
71 | 8b9b0cc2 | Kevin Wolf | int immediately;
|
72 | 8b9b0cc2 | Kevin Wolf | int once;
|
73 | e4780db4 | Paolo Bonzini | int64_t sector; |
74 | 8b9b0cc2 | Kevin Wolf | } inject; |
75 | 8b9b0cc2 | Kevin Wolf | struct {
|
76 | 8b9b0cc2 | Kevin Wolf | int new_state;
|
77 | 8b9b0cc2 | Kevin Wolf | } set_state; |
78 | 3c90c65d | Kevin Wolf | struct {
|
79 | 3c90c65d | Kevin Wolf | char *tag;
|
80 | 3c90c65d | Kevin Wolf | } suspend; |
81 | 8b9b0cc2 | Kevin Wolf | } options; |
82 | 8b9b0cc2 | Kevin Wolf | QLIST_ENTRY(BlkdebugRule) next; |
83 | 571cd43e | Paolo Bonzini | QSIMPLEQ_ENTRY(BlkdebugRule) active_next; |
84 | 8b9b0cc2 | Kevin Wolf | } BlkdebugRule; |
85 | 8b9b0cc2 | Kevin Wolf | |
86 | 8b9b0cc2 | Kevin Wolf | static QemuOptsList inject_error_opts = {
|
87 | 8b9b0cc2 | Kevin Wolf | .name = "inject-error",
|
88 | 8b9b0cc2 | Kevin Wolf | .head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head), |
89 | 8b9b0cc2 | Kevin Wolf | .desc = { |
90 | 8b9b0cc2 | Kevin Wolf | { |
91 | 8b9b0cc2 | Kevin Wolf | .name = "event",
|
92 | 8b9b0cc2 | Kevin Wolf | .type = QEMU_OPT_STRING, |
93 | 8b9b0cc2 | Kevin Wolf | }, |
94 | 8b9b0cc2 | Kevin Wolf | { |
95 | 8b9b0cc2 | Kevin Wolf | .name = "state",
|
96 | 8b9b0cc2 | Kevin Wolf | .type = QEMU_OPT_NUMBER, |
97 | 8b9b0cc2 | Kevin Wolf | }, |
98 | 8b9b0cc2 | Kevin Wolf | { |
99 | 8b9b0cc2 | Kevin Wolf | .name = "errno",
|
100 | 8b9b0cc2 | Kevin Wolf | .type = QEMU_OPT_NUMBER, |
101 | 8b9b0cc2 | Kevin Wolf | }, |
102 | 8b9b0cc2 | Kevin Wolf | { |
103 | e4780db4 | Paolo Bonzini | .name = "sector",
|
104 | e4780db4 | Paolo Bonzini | .type = QEMU_OPT_NUMBER, |
105 | e4780db4 | Paolo Bonzini | }, |
106 | e4780db4 | Paolo Bonzini | { |
107 | 8b9b0cc2 | Kevin Wolf | .name = "once",
|
108 | 8b9b0cc2 | Kevin Wolf | .type = QEMU_OPT_BOOL, |
109 | 8b9b0cc2 | Kevin Wolf | }, |
110 | 8b9b0cc2 | Kevin Wolf | { |
111 | 8b9b0cc2 | Kevin Wolf | .name = "immediately",
|
112 | 8b9b0cc2 | Kevin Wolf | .type = QEMU_OPT_BOOL, |
113 | 8b9b0cc2 | Kevin Wolf | }, |
114 | 8b9b0cc2 | Kevin Wolf | { /* end of list */ }
|
115 | 8b9b0cc2 | Kevin Wolf | }, |
116 | 8b9b0cc2 | Kevin Wolf | }; |
117 | 8b9b0cc2 | Kevin Wolf | |
118 | 8b9b0cc2 | Kevin Wolf | static QemuOptsList set_state_opts = {
|
119 | 8b9b0cc2 | Kevin Wolf | .name = "set-state",
|
120 | 327cdad4 | Kevin Wolf | .head = QTAILQ_HEAD_INITIALIZER(set_state_opts.head), |
121 | 8b9b0cc2 | Kevin Wolf | .desc = { |
122 | 8b9b0cc2 | Kevin Wolf | { |
123 | 8b9b0cc2 | Kevin Wolf | .name = "event",
|
124 | 8b9b0cc2 | Kevin Wolf | .type = QEMU_OPT_STRING, |
125 | 8b9b0cc2 | Kevin Wolf | }, |
126 | 8b9b0cc2 | Kevin Wolf | { |
127 | 8b9b0cc2 | Kevin Wolf | .name = "state",
|
128 | 8b9b0cc2 | Kevin Wolf | .type = QEMU_OPT_NUMBER, |
129 | 8b9b0cc2 | Kevin Wolf | }, |
130 | 8b9b0cc2 | Kevin Wolf | { |
131 | 8b9b0cc2 | Kevin Wolf | .name = "new_state",
|
132 | 8b9b0cc2 | Kevin Wolf | .type = QEMU_OPT_NUMBER, |
133 | 8b9b0cc2 | Kevin Wolf | }, |
134 | 8b9b0cc2 | Kevin Wolf | { /* end of list */ }
|
135 | 8b9b0cc2 | Kevin Wolf | }, |
136 | 8b9b0cc2 | Kevin Wolf | }; |
137 | 8b9b0cc2 | Kevin Wolf | |
138 | 8b9b0cc2 | Kevin Wolf | static QemuOptsList *config_groups[] = {
|
139 | 8b9b0cc2 | Kevin Wolf | &inject_error_opts, |
140 | 8b9b0cc2 | Kevin Wolf | &set_state_opts, |
141 | 8b9b0cc2 | Kevin Wolf | NULL
|
142 | 8b9b0cc2 | Kevin Wolf | }; |
143 | 8b9b0cc2 | Kevin Wolf | |
144 | 8b9b0cc2 | Kevin Wolf | static const char *event_names[BLKDBG_EVENT_MAX] = { |
145 | 8252278a | Kevin Wolf | [BLKDBG_L1_UPDATE] = "l1_update",
|
146 | 8252278a | Kevin Wolf | [BLKDBG_L1_GROW_ALLOC_TABLE] = "l1_grow.alloc_table",
|
147 | 8252278a | Kevin Wolf | [BLKDBG_L1_GROW_WRITE_TABLE] = "l1_grow.write_table",
|
148 | 8252278a | Kevin Wolf | [BLKDBG_L1_GROW_ACTIVATE_TABLE] = "l1_grow.activate_table",
|
149 | 8252278a | Kevin Wolf | |
150 | 8252278a | Kevin Wolf | [BLKDBG_L2_LOAD] = "l2_load",
|
151 | 8252278a | Kevin Wolf | [BLKDBG_L2_UPDATE] = "l2_update",
|
152 | 8252278a | Kevin Wolf | [BLKDBG_L2_UPDATE_COMPRESSED] = "l2_update_compressed",
|
153 | 8252278a | Kevin Wolf | [BLKDBG_L2_ALLOC_COW_READ] = "l2_alloc.cow_read",
|
154 | 8252278a | Kevin Wolf | [BLKDBG_L2_ALLOC_WRITE] = "l2_alloc.write",
|
155 | 8252278a | Kevin Wolf | |
156 | 8252278a | Kevin Wolf | [BLKDBG_READ_AIO] = "read_aio",
|
157 | 8252278a | Kevin Wolf | [BLKDBG_READ_BACKING_AIO] = "read_backing_aio",
|
158 | 8252278a | Kevin Wolf | [BLKDBG_READ_COMPRESSED] = "read_compressed",
|
159 | 8252278a | Kevin Wolf | |
160 | 8252278a | Kevin Wolf | [BLKDBG_WRITE_AIO] = "write_aio",
|
161 | 8252278a | Kevin Wolf | [BLKDBG_WRITE_COMPRESSED] = "write_compressed",
|
162 | 8252278a | Kevin Wolf | |
163 | 8252278a | Kevin Wolf | [BLKDBG_VMSTATE_LOAD] = "vmstate_load",
|
164 | 8252278a | Kevin Wolf | [BLKDBG_VMSTATE_SAVE] = "vmstate_save",
|
165 | 8252278a | Kevin Wolf | |
166 | 8252278a | Kevin Wolf | [BLKDBG_COW_READ] = "cow_read",
|
167 | 8252278a | Kevin Wolf | [BLKDBG_COW_WRITE] = "cow_write",
|
168 | 8252278a | Kevin Wolf | |
169 | 8252278a | Kevin Wolf | [BLKDBG_REFTABLE_LOAD] = "reftable_load",
|
170 | 8252278a | Kevin Wolf | [BLKDBG_REFTABLE_GROW] = "reftable_grow",
|
171 | afa50193 | Max Reitz | [BLKDBG_REFTABLE_UPDATE] = "reftable_update",
|
172 | 8252278a | Kevin Wolf | |
173 | 8252278a | Kevin Wolf | [BLKDBG_REFBLOCK_LOAD] = "refblock_load",
|
174 | 8252278a | Kevin Wolf | [BLKDBG_REFBLOCK_UPDATE] = "refblock_update",
|
175 | 8252278a | Kevin Wolf | [BLKDBG_REFBLOCK_UPDATE_PART] = "refblock_update_part",
|
176 | 8252278a | Kevin Wolf | [BLKDBG_REFBLOCK_ALLOC] = "refblock_alloc",
|
177 | 8252278a | Kevin Wolf | [BLKDBG_REFBLOCK_ALLOC_HOOKUP] = "refblock_alloc.hookup",
|
178 | 8252278a | Kevin Wolf | [BLKDBG_REFBLOCK_ALLOC_WRITE] = "refblock_alloc.write",
|
179 | 8252278a | Kevin Wolf | [BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS] = "refblock_alloc.write_blocks",
|
180 | 8252278a | Kevin Wolf | [BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE] = "refblock_alloc.write_table",
|
181 | 8252278a | Kevin Wolf | [BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE] = "refblock_alloc.switch_table",
|
182 | 8252278a | Kevin Wolf | |
183 | 8252278a | Kevin Wolf | [BLKDBG_CLUSTER_ALLOC] = "cluster_alloc",
|
184 | 8252278a | Kevin Wolf | [BLKDBG_CLUSTER_ALLOC_BYTES] = "cluster_alloc_bytes",
|
185 | 8252278a | Kevin Wolf | [BLKDBG_CLUSTER_FREE] = "cluster_free",
|
186 | bf736fe3 | Kevin Wolf | |
187 | bf736fe3 | Kevin Wolf | [BLKDBG_FLUSH_TO_OS] = "flush_to_os",
|
188 | bf736fe3 | Kevin Wolf | [BLKDBG_FLUSH_TO_DISK] = "flush_to_disk",
|
189 | 9e1cb96d | Kevin Wolf | |
190 | 9e1cb96d | Kevin Wolf | [BLKDBG_PWRITEV_RMW_HEAD] = "pwritev_rmw.head",
|
191 | 9e1cb96d | Kevin Wolf | [BLKDBG_PWRITEV_RMW_AFTER_HEAD] = "pwritev_rmw.after_head",
|
192 | 9e1cb96d | Kevin Wolf | [BLKDBG_PWRITEV_RMW_TAIL] = "pwritev_rmw.tail",
|
193 | 9e1cb96d | Kevin Wolf | [BLKDBG_PWRITEV_RMW_AFTER_TAIL] = "pwritev_rmw.after_tail",
|
194 | 9e1cb96d | Kevin Wolf | [BLKDBG_PWRITEV] = "pwritev",
|
195 | 9e1cb96d | Kevin Wolf | [BLKDBG_PWRITEV_ZERO] = "pwritev_zero",
|
196 | 9e1cb96d | Kevin Wolf | [BLKDBG_PWRITEV_DONE] = "pwritev_done",
|
197 | 8b9b0cc2 | Kevin Wolf | }; |
198 | 8b9b0cc2 | Kevin Wolf | |
199 | 8b9b0cc2 | Kevin Wolf | static int get_event_by_name(const char *name, BlkDebugEvent *event) |
200 | 8b9b0cc2 | Kevin Wolf | { |
201 | 8b9b0cc2 | Kevin Wolf | int i;
|
202 | 8b9b0cc2 | Kevin Wolf | |
203 | 8b9b0cc2 | Kevin Wolf | for (i = 0; i < BLKDBG_EVENT_MAX; i++) { |
204 | 8b9b0cc2 | Kevin Wolf | if (!strcmp(event_names[i], name)) {
|
205 | 8b9b0cc2 | Kevin Wolf | *event = i; |
206 | 8b9b0cc2 | Kevin Wolf | return 0; |
207 | 8b9b0cc2 | Kevin Wolf | } |
208 | 8b9b0cc2 | Kevin Wolf | } |
209 | 8b9b0cc2 | Kevin Wolf | |
210 | 8b9b0cc2 | Kevin Wolf | return -1; |
211 | 8b9b0cc2 | Kevin Wolf | } |
212 | 8b9b0cc2 | Kevin Wolf | |
213 | 8b9b0cc2 | Kevin Wolf | struct add_rule_data {
|
214 | 8b9b0cc2 | Kevin Wolf | BDRVBlkdebugState *s; |
215 | 8b9b0cc2 | Kevin Wolf | int action;
|
216 | 8b9b0cc2 | Kevin Wolf | }; |
217 | 8b9b0cc2 | Kevin Wolf | |
218 | 8b9b0cc2 | Kevin Wolf | static int add_rule(QemuOpts *opts, void *opaque) |
219 | 8b9b0cc2 | Kevin Wolf | { |
220 | 8b9b0cc2 | Kevin Wolf | struct add_rule_data *d = opaque;
|
221 | 8b9b0cc2 | Kevin Wolf | BDRVBlkdebugState *s = d->s; |
222 | 8b9b0cc2 | Kevin Wolf | const char* event_name; |
223 | 8b9b0cc2 | Kevin Wolf | BlkDebugEvent event; |
224 | 8b9b0cc2 | Kevin Wolf | struct BlkdebugRule *rule;
|
225 | 8b9b0cc2 | Kevin Wolf | |
226 | 8b9b0cc2 | Kevin Wolf | /* Find the right event for the rule */
|
227 | 8b9b0cc2 | Kevin Wolf | event_name = qemu_opt_get(opts, "event");
|
228 | 8b9b0cc2 | Kevin Wolf | if (!event_name || get_event_by_name(event_name, &event) < 0) { |
229 | 8b9b0cc2 | Kevin Wolf | return -1; |
230 | 8b9b0cc2 | Kevin Wolf | } |
231 | 8b9b0cc2 | Kevin Wolf | |
232 | 8b9b0cc2 | Kevin Wolf | /* Set attributes common for all actions */
|
233 | 7267c094 | Anthony Liguori | rule = g_malloc0(sizeof(*rule));
|
234 | 8b9b0cc2 | Kevin Wolf | *rule = (struct BlkdebugRule) {
|
235 | 8b9b0cc2 | Kevin Wolf | .event = event, |
236 | 8b9b0cc2 | Kevin Wolf | .action = d->action, |
237 | 8b9b0cc2 | Kevin Wolf | .state = qemu_opt_get_number(opts, "state", 0), |
238 | 8b9b0cc2 | Kevin Wolf | }; |
239 | 8b9b0cc2 | Kevin Wolf | |
240 | 8b9b0cc2 | Kevin Wolf | /* Parse action-specific options */
|
241 | 8b9b0cc2 | Kevin Wolf | switch (d->action) {
|
242 | 8b9b0cc2 | Kevin Wolf | case ACTION_INJECT_ERROR:
|
243 | 8b9b0cc2 | Kevin Wolf | rule->options.inject.error = qemu_opt_get_number(opts, "errno", EIO);
|
244 | 8b9b0cc2 | Kevin Wolf | rule->options.inject.once = qemu_opt_get_bool(opts, "once", 0); |
245 | 8b9b0cc2 | Kevin Wolf | rule->options.inject.immediately = |
246 | 8b9b0cc2 | Kevin Wolf | qemu_opt_get_bool(opts, "immediately", 0); |
247 | e4780db4 | Paolo Bonzini | rule->options.inject.sector = qemu_opt_get_number(opts, "sector", -1); |
248 | 8b9b0cc2 | Kevin Wolf | break;
|
249 | 8b9b0cc2 | Kevin Wolf | |
250 | 8b9b0cc2 | Kevin Wolf | case ACTION_SET_STATE:
|
251 | 8b9b0cc2 | Kevin Wolf | rule->options.set_state.new_state = |
252 | 8b9b0cc2 | Kevin Wolf | qemu_opt_get_number(opts, "new_state", 0); |
253 | 8b9b0cc2 | Kevin Wolf | break;
|
254 | 3c90c65d | Kevin Wolf | |
255 | 3c90c65d | Kevin Wolf | case ACTION_SUSPEND:
|
256 | 3c90c65d | Kevin Wolf | rule->options.suspend.tag = |
257 | 3c90c65d | Kevin Wolf | g_strdup(qemu_opt_get(opts, "tag"));
|
258 | 3c90c65d | Kevin Wolf | break;
|
259 | 8b9b0cc2 | Kevin Wolf | }; |
260 | 8b9b0cc2 | Kevin Wolf | |
261 | 8b9b0cc2 | Kevin Wolf | /* Add the rule */
|
262 | 8b9b0cc2 | Kevin Wolf | QLIST_INSERT_HEAD(&s->rules[event], rule, next); |
263 | 8b9b0cc2 | Kevin Wolf | |
264 | 8b9b0cc2 | Kevin Wolf | return 0; |
265 | 8b9b0cc2 | Kevin Wolf | } |
266 | 8b9b0cc2 | Kevin Wolf | |
267 | 9e35542b | Kevin Wolf | static void remove_rule(BlkdebugRule *rule) |
268 | 9e35542b | Kevin Wolf | { |
269 | 9e35542b | Kevin Wolf | switch (rule->action) {
|
270 | 9e35542b | Kevin Wolf | case ACTION_INJECT_ERROR:
|
271 | 9e35542b | Kevin Wolf | case ACTION_SET_STATE:
|
272 | 9e35542b | Kevin Wolf | break;
|
273 | 3c90c65d | Kevin Wolf | case ACTION_SUSPEND:
|
274 | 3c90c65d | Kevin Wolf | g_free(rule->options.suspend.tag); |
275 | 3c90c65d | Kevin Wolf | break;
|
276 | 9e35542b | Kevin Wolf | } |
277 | 9e35542b | Kevin Wolf | |
278 | 9e35542b | Kevin Wolf | QLIST_REMOVE(rule, next); |
279 | 9e35542b | Kevin Wolf | g_free(rule); |
280 | 9e35542b | Kevin Wolf | } |
281 | 9e35542b | Kevin Wolf | |
282 | 89f2b21e | Max Reitz | static int read_config(BDRVBlkdebugState *s, const char *filename, |
283 | 89f2b21e | Max Reitz | QDict *options, Error **errp) |
284 | 8b9b0cc2 | Kevin Wolf | { |
285 | 85a040e5 | Max Reitz | FILE *f = NULL;
|
286 | 8b9b0cc2 | Kevin Wolf | int ret;
|
287 | 8b9b0cc2 | Kevin Wolf | struct add_rule_data d;
|
288 | 89f2b21e | Max Reitz | Error *local_err = NULL;
|
289 | 8b9b0cc2 | Kevin Wolf | |
290 | 85a040e5 | Max Reitz | if (filename) {
|
291 | 85a040e5 | Max Reitz | f = fopen(filename, "r");
|
292 | 85a040e5 | Max Reitz | if (f == NULL) { |
293 | 85a040e5 | Max Reitz | error_setg_errno(errp, errno, "Could not read blkdebug config file");
|
294 | 85a040e5 | Max Reitz | return -errno;
|
295 | 85a040e5 | Max Reitz | } |
296 | 8b9b0cc2 | Kevin Wolf | |
297 | 85a040e5 | Max Reitz | ret = qemu_config_parse(f, config_groups, filename); |
298 | 85a040e5 | Max Reitz | if (ret < 0) { |
299 | 85a040e5 | Max Reitz | error_setg(errp, "Could not parse blkdebug config file");
|
300 | 85a040e5 | Max Reitz | ret = -EINVAL; |
301 | 85a040e5 | Max Reitz | goto fail;
|
302 | 85a040e5 | Max Reitz | } |
303 | 8b9b0cc2 | Kevin Wolf | } |
304 | 8b9b0cc2 | Kevin Wolf | |
305 | 89f2b21e | Max Reitz | qemu_config_parse_qdict(options, config_groups, &local_err); |
306 | 89f2b21e | Max Reitz | if (error_is_set(&local_err)) {
|
307 | 89f2b21e | Max Reitz | error_propagate(errp, local_err); |
308 | 89f2b21e | Max Reitz | ret = -EINVAL; |
309 | 89f2b21e | Max Reitz | goto fail;
|
310 | 89f2b21e | Max Reitz | } |
311 | 89f2b21e | Max Reitz | |
312 | 8b9b0cc2 | Kevin Wolf | d.s = s; |
313 | 8b9b0cc2 | Kevin Wolf | d.action = ACTION_INJECT_ERROR; |
314 | 8b9b0cc2 | Kevin Wolf | qemu_opts_foreach(&inject_error_opts, add_rule, &d, 0);
|
315 | 8b9b0cc2 | Kevin Wolf | |
316 | 8b9b0cc2 | Kevin Wolf | d.action = ACTION_SET_STATE; |
317 | 8b9b0cc2 | Kevin Wolf | qemu_opts_foreach(&set_state_opts, add_rule, &d, 0);
|
318 | 8b9b0cc2 | Kevin Wolf | |
319 | 8b9b0cc2 | Kevin Wolf | ret = 0;
|
320 | 8b9b0cc2 | Kevin Wolf | fail:
|
321 | 698f0d52 | Kevin Wolf | qemu_opts_reset(&inject_error_opts); |
322 | 698f0d52 | Kevin Wolf | qemu_opts_reset(&set_state_opts); |
323 | 85a040e5 | Max Reitz | if (f) {
|
324 | 85a040e5 | Max Reitz | fclose(f); |
325 | 85a040e5 | Max Reitz | } |
326 | 8b9b0cc2 | Kevin Wolf | return ret;
|
327 | 8b9b0cc2 | Kevin Wolf | } |
328 | 8b9b0cc2 | Kevin Wolf | |
329 | 8b9b0cc2 | Kevin Wolf | /* Valid blkdebug filenames look like blkdebug:path/to/config:path/to/image */
|
330 | f4681212 | Kevin Wolf | static void blkdebug_parse_filename(const char *filename, QDict *options, |
331 | f4681212 | Kevin Wolf | Error **errp) |
332 | 6a143727 | Kevin Wolf | { |
333 | f4681212 | Kevin Wolf | const char *c; |
334 | 6a143727 | Kevin Wolf | |
335 | 8b9b0cc2 | Kevin Wolf | /* Parse the blkdebug: prefix */
|
336 | f4681212 | Kevin Wolf | if (!strstart(filename, "blkdebug:", &filename)) { |
337 | d4881b9b | Max Reitz | /* There was no prefix; therefore, all options have to be already
|
338 | d4881b9b | Max Reitz | present in the QDict (except for the filename) */
|
339 | d4881b9b | Max Reitz | qdict_put(options, "x-image", qstring_from_str(filename));
|
340 | f4681212 | Kevin Wolf | return;
|
341 | 6a143727 | Kevin Wolf | } |
342 | 6a143727 | Kevin Wolf | |
343 | f4681212 | Kevin Wolf | /* Parse config file path */
|
344 | 8b9b0cc2 | Kevin Wolf | c = strchr(filename, ':');
|
345 | 8b9b0cc2 | Kevin Wolf | if (c == NULL) { |
346 | f4681212 | Kevin Wolf | error_setg(errp, "blkdebug requires both config file and image path");
|
347 | f4681212 | Kevin Wolf | return;
|
348 | 8b9b0cc2 | Kevin Wolf | } |
349 | 8b9b0cc2 | Kevin Wolf | |
350 | f4681212 | Kevin Wolf | if (c != filename) {
|
351 | f4681212 | Kevin Wolf | QString *config_path; |
352 | f4681212 | Kevin Wolf | config_path = qstring_from_substr(filename, 0, c - filename - 1); |
353 | f4681212 | Kevin Wolf | qdict_put(options, "config", config_path);
|
354 | 8b9b0cc2 | Kevin Wolf | } |
355 | f4681212 | Kevin Wolf | |
356 | f4681212 | Kevin Wolf | /* TODO Allow multi-level nesting and set file.filename here */
|
357 | 8b9b0cc2 | Kevin Wolf | filename = c + 1;
|
358 | f4681212 | Kevin Wolf | qdict_put(options, "x-image", qstring_from_str(filename));
|
359 | f4681212 | Kevin Wolf | } |
360 | f4681212 | Kevin Wolf | |
361 | f4681212 | Kevin Wolf | static QemuOptsList runtime_opts = {
|
362 | f4681212 | Kevin Wolf | .name = "blkdebug",
|
363 | f4681212 | Kevin Wolf | .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head), |
364 | f4681212 | Kevin Wolf | .desc = { |
365 | f4681212 | Kevin Wolf | { |
366 | f4681212 | Kevin Wolf | .name = "config",
|
367 | f4681212 | Kevin Wolf | .type = QEMU_OPT_STRING, |
368 | f4681212 | Kevin Wolf | .help = "Path to the configuration file",
|
369 | f4681212 | Kevin Wolf | }, |
370 | f4681212 | Kevin Wolf | { |
371 | f4681212 | Kevin Wolf | .name = "x-image",
|
372 | f4681212 | Kevin Wolf | .type = QEMU_OPT_STRING, |
373 | f4681212 | Kevin Wolf | .help = "[internal use only, will be removed]",
|
374 | f4681212 | Kevin Wolf | }, |
375 | b35ee7fb | Kevin Wolf | { |
376 | b35ee7fb | Kevin Wolf | .name = "align",
|
377 | b35ee7fb | Kevin Wolf | .type = QEMU_OPT_SIZE, |
378 | b35ee7fb | Kevin Wolf | .help = "Required alignment in bytes",
|
379 | b35ee7fb | Kevin Wolf | }, |
380 | f4681212 | Kevin Wolf | { /* end of list */ }
|
381 | f4681212 | Kevin Wolf | }, |
382 | f4681212 | Kevin Wolf | }; |
383 | f4681212 | Kevin Wolf | |
384 | 015a1036 | Max Reitz | static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags, |
385 | 015a1036 | Max Reitz | Error **errp) |
386 | f4681212 | Kevin Wolf | { |
387 | f4681212 | Kevin Wolf | BDRVBlkdebugState *s = bs->opaque; |
388 | f4681212 | Kevin Wolf | QemuOpts *opts; |
389 | f4681212 | Kevin Wolf | Error *local_err = NULL;
|
390 | 4373593d | Max Reitz | const char *config; |
391 | b35ee7fb | Kevin Wolf | uint64_t align; |
392 | f4681212 | Kevin Wolf | int ret;
|
393 | f4681212 | Kevin Wolf | |
394 | 87ea75d5 | Peter Crosthwaite | opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); |
395 | f4681212 | Kevin Wolf | qemu_opts_absorb_qdict(opts, options, &local_err); |
396 | f4681212 | Kevin Wolf | if (error_is_set(&local_err)) {
|
397 | 10ffa72f | Max Reitz | error_propagate(errp, local_err); |
398 | f4681212 | Kevin Wolf | ret = -EINVAL; |
399 | f4681212 | Kevin Wolf | goto fail;
|
400 | f4681212 | Kevin Wolf | } |
401 | f4681212 | Kevin Wolf | |
402 | 89f2b21e | Max Reitz | /* Read rules from config file or command line options */
|
403 | f4681212 | Kevin Wolf | config = qemu_opt_get(opts, "config");
|
404 | 89f2b21e | Max Reitz | ret = read_config(s, config, options, errp); |
405 | 85a040e5 | Max Reitz | if (ret) {
|
406 | 85a040e5 | Max Reitz | goto fail;
|
407 | f4681212 | Kevin Wolf | } |
408 | 8b9b0cc2 | Kevin Wolf | |
409 | 8db520ce | Kevin Wolf | /* Set initial state */
|
410 | 571cd43e | Paolo Bonzini | s->state = 1;
|
411 | 8db520ce | Kevin Wolf | |
412 | 8b9b0cc2 | Kevin Wolf | /* Open the backing file */
|
413 | 4373593d | Max Reitz | ret = bdrv_open_image(&bs->file, qemu_opt_get(opts, "x-image"), options, "image", |
414 | 4373593d | Max Reitz | flags, true, false, &local_err); |
415 | 8b9b0cc2 | Kevin Wolf | if (ret < 0) { |
416 | 10ffa72f | Max Reitz | error_propagate(errp, local_err); |
417 | f4681212 | Kevin Wolf | goto fail;
|
418 | 8b9b0cc2 | Kevin Wolf | } |
419 | 8b9b0cc2 | Kevin Wolf | |
420 | b35ee7fb | Kevin Wolf | /* Set request alignment */
|
421 | b35ee7fb | Kevin Wolf | align = qemu_opt_get_size(opts, "align", bs->request_alignment);
|
422 | b35ee7fb | Kevin Wolf | if (align > 0 && align < INT_MAX && !(align & (align - 1))) { |
423 | b35ee7fb | Kevin Wolf | bs->request_alignment = align; |
424 | b35ee7fb | Kevin Wolf | } else {
|
425 | b35ee7fb | Kevin Wolf | error_setg(errp, "Invalid alignment");
|
426 | b35ee7fb | Kevin Wolf | ret = -EINVAL; |
427 | b35ee7fb | Kevin Wolf | goto fail;
|
428 | b35ee7fb | Kevin Wolf | } |
429 | b35ee7fb | Kevin Wolf | |
430 | f4681212 | Kevin Wolf | ret = 0;
|
431 | f4681212 | Kevin Wolf | fail:
|
432 | f4681212 | Kevin Wolf | qemu_opts_del(opts); |
433 | f4681212 | Kevin Wolf | return ret;
|
434 | 6a143727 | Kevin Wolf | } |
435 | 6a143727 | Kevin Wolf | |
436 | b9f66d96 | Kevin Wolf | static void error_callback_bh(void *opaque) |
437 | b9f66d96 | Kevin Wolf | { |
438 | b9f66d96 | Kevin Wolf | struct BlkdebugAIOCB *acb = opaque;
|
439 | b9f66d96 | Kevin Wolf | qemu_bh_delete(acb->bh); |
440 | b9f66d96 | Kevin Wolf | acb->common.cb(acb->common.opaque, acb->ret); |
441 | b9f66d96 | Kevin Wolf | qemu_aio_release(acb); |
442 | b9f66d96 | Kevin Wolf | } |
443 | b9f66d96 | Kevin Wolf | |
444 | b9f66d96 | Kevin Wolf | static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb) |
445 | b9f66d96 | Kevin Wolf | { |
446 | b666d239 | Kevin Wolf | BlkdebugAIOCB *acb = container_of(blockacb, BlkdebugAIOCB, common); |
447 | b9f66d96 | Kevin Wolf | qemu_aio_release(acb); |
448 | b9f66d96 | Kevin Wolf | } |
449 | b9f66d96 | Kevin Wolf | |
450 | b9f66d96 | Kevin Wolf | static BlockDriverAIOCB *inject_error(BlockDriverState *bs,
|
451 | 571cd43e | Paolo Bonzini | BlockDriverCompletionFunc *cb, void *opaque, BlkdebugRule *rule)
|
452 | b9f66d96 | Kevin Wolf | { |
453 | b9f66d96 | Kevin Wolf | BDRVBlkdebugState *s = bs->opaque; |
454 | 571cd43e | Paolo Bonzini | int error = rule->options.inject.error;
|
455 | b9f66d96 | Kevin Wolf | struct BlkdebugAIOCB *acb;
|
456 | b9f66d96 | Kevin Wolf | QEMUBH *bh; |
457 | b9f66d96 | Kevin Wolf | |
458 | 571cd43e | Paolo Bonzini | if (rule->options.inject.once) {
|
459 | 571cd43e | Paolo Bonzini | QSIMPLEQ_INIT(&s->active_rules); |
460 | b9f66d96 | Kevin Wolf | } |
461 | b9f66d96 | Kevin Wolf | |
462 | 571cd43e | Paolo Bonzini | if (rule->options.inject.immediately) {
|
463 | b9f66d96 | Kevin Wolf | return NULL; |
464 | b9f66d96 | Kevin Wolf | } |
465 | b9f66d96 | Kevin Wolf | |
466 | d7331bed | Stefan Hajnoczi | acb = qemu_aio_get(&blkdebug_aiocb_info, bs, cb, opaque); |
467 | b9f66d96 | Kevin Wolf | acb->ret = -error; |
468 | b9f66d96 | Kevin Wolf | |
469 | b9f66d96 | Kevin Wolf | bh = qemu_bh_new(error_callback_bh, acb); |
470 | b9f66d96 | Kevin Wolf | acb->bh = bh; |
471 | b9f66d96 | Kevin Wolf | qemu_bh_schedule(bh); |
472 | b9f66d96 | Kevin Wolf | |
473 | b666d239 | Kevin Wolf | return &acb->common;
|
474 | b9f66d96 | Kevin Wolf | } |
475 | b9f66d96 | Kevin Wolf | |
476 | 6a143727 | Kevin Wolf | static BlockDriverAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
|
477 | 6a143727 | Kevin Wolf | int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
478 | 6a143727 | Kevin Wolf | BlockDriverCompletionFunc *cb, void *opaque)
|
479 | 6a143727 | Kevin Wolf | { |
480 | 6a143727 | Kevin Wolf | BDRVBlkdebugState *s = bs->opaque; |
481 | e4780db4 | Paolo Bonzini | BlkdebugRule *rule = NULL;
|
482 | e4780db4 | Paolo Bonzini | |
483 | e4780db4 | Paolo Bonzini | QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) { |
484 | e4780db4 | Paolo Bonzini | if (rule->options.inject.sector == -1 || |
485 | e4780db4 | Paolo Bonzini | (rule->options.inject.sector >= sector_num && |
486 | e4780db4 | Paolo Bonzini | rule->options.inject.sector < sector_num + nb_sectors)) { |
487 | e4780db4 | Paolo Bonzini | break;
|
488 | e4780db4 | Paolo Bonzini | } |
489 | e4780db4 | Paolo Bonzini | } |
490 | b9f66d96 | Kevin Wolf | |
491 | 571cd43e | Paolo Bonzini | if (rule && rule->options.inject.error) {
|
492 | 571cd43e | Paolo Bonzini | return inject_error(bs, cb, opaque, rule);
|
493 | b9f66d96 | Kevin Wolf | } |
494 | b9f66d96 | Kevin Wolf | |
495 | 368e8dd1 | Paolo Bonzini | return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
|
496 | 6a143727 | Kevin Wolf | } |
497 | 6a143727 | Kevin Wolf | |
498 | 6a143727 | Kevin Wolf | static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
|
499 | 6a143727 | Kevin Wolf | int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
500 | 6a143727 | Kevin Wolf | BlockDriverCompletionFunc *cb, void *opaque)
|
501 | 6a143727 | Kevin Wolf | { |
502 | 6a143727 | Kevin Wolf | BDRVBlkdebugState *s = bs->opaque; |
503 | e4780db4 | Paolo Bonzini | BlkdebugRule *rule = NULL;
|
504 | e4780db4 | Paolo Bonzini | |
505 | e4780db4 | Paolo Bonzini | QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) { |
506 | e4780db4 | Paolo Bonzini | if (rule->options.inject.sector == -1 || |
507 | e4780db4 | Paolo Bonzini | (rule->options.inject.sector >= sector_num && |
508 | e4780db4 | Paolo Bonzini | rule->options.inject.sector < sector_num + nb_sectors)) { |
509 | e4780db4 | Paolo Bonzini | break;
|
510 | e4780db4 | Paolo Bonzini | } |
511 | e4780db4 | Paolo Bonzini | } |
512 | b9f66d96 | Kevin Wolf | |
513 | 571cd43e | Paolo Bonzini | if (rule && rule->options.inject.error) {
|
514 | 571cd43e | Paolo Bonzini | return inject_error(bs, cb, opaque, rule);
|
515 | b9f66d96 | Kevin Wolf | } |
516 | b9f66d96 | Kevin Wolf | |
517 | 368e8dd1 | Paolo Bonzini | return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
|
518 | 6a143727 | Kevin Wolf | } |
519 | 6a143727 | Kevin Wolf | |
520 | 3c90c65d | Kevin Wolf | |
521 | 6a143727 | Kevin Wolf | static void blkdebug_close(BlockDriverState *bs) |
522 | 6a143727 | Kevin Wolf | { |
523 | 6a143727 | Kevin Wolf | BDRVBlkdebugState *s = bs->opaque; |
524 | 8b9b0cc2 | Kevin Wolf | BlkdebugRule *rule, *next; |
525 | 8b9b0cc2 | Kevin Wolf | int i;
|
526 | 8b9b0cc2 | Kevin Wolf | |
527 | 8b9b0cc2 | Kevin Wolf | for (i = 0; i < BLKDBG_EVENT_MAX; i++) { |
528 | 8b9b0cc2 | Kevin Wolf | QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) { |
529 | 9e35542b | Kevin Wolf | remove_rule(rule); |
530 | 8b9b0cc2 | Kevin Wolf | } |
531 | 8b9b0cc2 | Kevin Wolf | } |
532 | 6a143727 | Kevin Wolf | } |
533 | 6a143727 | Kevin Wolf | |
534 | 3c90c65d | Kevin Wolf | static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule) |
535 | 3c90c65d | Kevin Wolf | { |
536 | 3c90c65d | Kevin Wolf | BDRVBlkdebugState *s = bs->opaque; |
537 | 3c90c65d | Kevin Wolf | BlkdebugSuspendedReq r; |
538 | 3c90c65d | Kevin Wolf | |
539 | 3c90c65d | Kevin Wolf | r = (BlkdebugSuspendedReq) { |
540 | 3c90c65d | Kevin Wolf | .co = qemu_coroutine_self(), |
541 | 3c90c65d | Kevin Wolf | .tag = g_strdup(rule->options.suspend.tag), |
542 | 3c90c65d | Kevin Wolf | }; |
543 | 3c90c65d | Kevin Wolf | |
544 | 3c90c65d | Kevin Wolf | remove_rule(rule); |
545 | 3c90c65d | Kevin Wolf | QLIST_INSERT_HEAD(&s->suspended_reqs, &r, next); |
546 | 3c90c65d | Kevin Wolf | |
547 | 3c90c65d | Kevin Wolf | printf("blkdebug: Suspended request '%s'\n", r.tag);
|
548 | 3c90c65d | Kevin Wolf | qemu_coroutine_yield(); |
549 | 3c90c65d | Kevin Wolf | printf("blkdebug: Resuming request '%s'\n", r.tag);
|
550 | 3c90c65d | Kevin Wolf | |
551 | 3c90c65d | Kevin Wolf | QLIST_REMOVE(&r, next); |
552 | 3c90c65d | Kevin Wolf | g_free(r.tag); |
553 | 3c90c65d | Kevin Wolf | } |
554 | 3c90c65d | Kevin Wolf | |
555 | 571cd43e | Paolo Bonzini | static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule, |
556 | 8f96b5be | Paolo Bonzini | bool injected)
|
557 | 8b9b0cc2 | Kevin Wolf | { |
558 | 8b9b0cc2 | Kevin Wolf | BDRVBlkdebugState *s = bs->opaque; |
559 | 8b9b0cc2 | Kevin Wolf | |
560 | 8b9b0cc2 | Kevin Wolf | /* Only process rules for the current state */
|
561 | 8f96b5be | Paolo Bonzini | if (rule->state && rule->state != s->state) {
|
562 | 571cd43e | Paolo Bonzini | return injected;
|
563 | 8b9b0cc2 | Kevin Wolf | } |
564 | 8b9b0cc2 | Kevin Wolf | |
565 | 8b9b0cc2 | Kevin Wolf | /* Take the action */
|
566 | 8b9b0cc2 | Kevin Wolf | switch (rule->action) {
|
567 | 8b9b0cc2 | Kevin Wolf | case ACTION_INJECT_ERROR:
|
568 | 571cd43e | Paolo Bonzini | if (!injected) {
|
569 | 571cd43e | Paolo Bonzini | QSIMPLEQ_INIT(&s->active_rules); |
570 | 571cd43e | Paolo Bonzini | injected = true;
|
571 | 571cd43e | Paolo Bonzini | } |
572 | 571cd43e | Paolo Bonzini | QSIMPLEQ_INSERT_HEAD(&s->active_rules, rule, active_next); |
573 | 8b9b0cc2 | Kevin Wolf | break;
|
574 | 8b9b0cc2 | Kevin Wolf | |
575 | 8b9b0cc2 | Kevin Wolf | case ACTION_SET_STATE:
|
576 | 8f96b5be | Paolo Bonzini | s->new_state = rule->options.set_state.new_state; |
577 | 8b9b0cc2 | Kevin Wolf | break;
|
578 | 3c90c65d | Kevin Wolf | |
579 | 3c90c65d | Kevin Wolf | case ACTION_SUSPEND:
|
580 | 3c90c65d | Kevin Wolf | suspend_request(bs, rule); |
581 | 3c90c65d | Kevin Wolf | break;
|
582 | 8b9b0cc2 | Kevin Wolf | } |
583 | 571cd43e | Paolo Bonzini | return injected;
|
584 | 8b9b0cc2 | Kevin Wolf | } |
585 | 8b9b0cc2 | Kevin Wolf | |
586 | 8b9b0cc2 | Kevin Wolf | static void blkdebug_debug_event(BlockDriverState *bs, BlkDebugEvent event) |
587 | 8b9b0cc2 | Kevin Wolf | { |
588 | 8b9b0cc2 | Kevin Wolf | BDRVBlkdebugState *s = bs->opaque; |
589 | 3c90c65d | Kevin Wolf | struct BlkdebugRule *rule, *next;
|
590 | 571cd43e | Paolo Bonzini | bool injected;
|
591 | 8b9b0cc2 | Kevin Wolf | |
592 | 95ee3914 | Blue Swirl | assert((int)event >= 0 && event < BLKDBG_EVENT_MAX); |
593 | 8b9b0cc2 | Kevin Wolf | |
594 | 571cd43e | Paolo Bonzini | injected = false;
|
595 | 8f96b5be | Paolo Bonzini | s->new_state = s->state; |
596 | 3c90c65d | Kevin Wolf | QLIST_FOREACH_SAFE(rule, &s->rules[event], next, next) { |
597 | 8f96b5be | Paolo Bonzini | injected = process_rule(bs, rule, injected); |
598 | 8b9b0cc2 | Kevin Wolf | } |
599 | 8f96b5be | Paolo Bonzini | s->state = s->new_state; |
600 | 8b9b0cc2 | Kevin Wolf | } |
601 | 8b9b0cc2 | Kevin Wolf | |
602 | 3c90c65d | Kevin Wolf | static int blkdebug_debug_breakpoint(BlockDriverState *bs, const char *event, |
603 | 3c90c65d | Kevin Wolf | const char *tag) |
604 | 3c90c65d | Kevin Wolf | { |
605 | 3c90c65d | Kevin Wolf | BDRVBlkdebugState *s = bs->opaque; |
606 | 3c90c65d | Kevin Wolf | struct BlkdebugRule *rule;
|
607 | 3c90c65d | Kevin Wolf | BlkDebugEvent blkdebug_event; |
608 | 3c90c65d | Kevin Wolf | |
609 | 3c90c65d | Kevin Wolf | if (get_event_by_name(event, &blkdebug_event) < 0) { |
610 | 3c90c65d | Kevin Wolf | return -ENOENT;
|
611 | 3c90c65d | Kevin Wolf | } |
612 | 3c90c65d | Kevin Wolf | |
613 | 3c90c65d | Kevin Wolf | |
614 | 3c90c65d | Kevin Wolf | rule = g_malloc(sizeof(*rule));
|
615 | 3c90c65d | Kevin Wolf | *rule = (struct BlkdebugRule) {
|
616 | 3c90c65d | Kevin Wolf | .event = blkdebug_event, |
617 | 3c90c65d | Kevin Wolf | .action = ACTION_SUSPEND, |
618 | 3c90c65d | Kevin Wolf | .state = 0,
|
619 | 3c90c65d | Kevin Wolf | .options.suspend.tag = g_strdup(tag), |
620 | 3c90c65d | Kevin Wolf | }; |
621 | 3c90c65d | Kevin Wolf | |
622 | 3c90c65d | Kevin Wolf | QLIST_INSERT_HEAD(&s->rules[blkdebug_event], rule, next); |
623 | 3c90c65d | Kevin Wolf | |
624 | 3c90c65d | Kevin Wolf | return 0; |
625 | 3c90c65d | Kevin Wolf | } |
626 | 3c90c65d | Kevin Wolf | |
627 | 3c90c65d | Kevin Wolf | static int blkdebug_debug_resume(BlockDriverState *bs, const char *tag) |
628 | 3c90c65d | Kevin Wolf | { |
629 | 3c90c65d | Kevin Wolf | BDRVBlkdebugState *s = bs->opaque; |
630 | c547e564 | Fam Zheng | BlkdebugSuspendedReq *r, *next; |
631 | 3c90c65d | Kevin Wolf | |
632 | c547e564 | Fam Zheng | QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, next) { |
633 | 3c90c65d | Kevin Wolf | if (!strcmp(r->tag, tag)) {
|
634 | 3c90c65d | Kevin Wolf | qemu_coroutine_enter(r->co, NULL);
|
635 | 3c90c65d | Kevin Wolf | return 0; |
636 | 3c90c65d | Kevin Wolf | } |
637 | 3c90c65d | Kevin Wolf | } |
638 | 3c90c65d | Kevin Wolf | return -ENOENT;
|
639 | 3c90c65d | Kevin Wolf | } |
640 | 3c90c65d | Kevin Wolf | |
641 | 4cc70e93 | Fam Zheng | static int blkdebug_debug_remove_breakpoint(BlockDriverState *bs, |
642 | 4cc70e93 | Fam Zheng | const char *tag) |
643 | 4cc70e93 | Fam Zheng | { |
644 | 4cc70e93 | Fam Zheng | BDRVBlkdebugState *s = bs->opaque; |
645 | c547e564 | Fam Zheng | BlkdebugSuspendedReq *r, *r_next; |
646 | 4cc70e93 | Fam Zheng | BlkdebugRule *rule, *next; |
647 | 4cc70e93 | Fam Zheng | int i, ret = -ENOENT;
|
648 | 4cc70e93 | Fam Zheng | |
649 | 4cc70e93 | Fam Zheng | for (i = 0; i < BLKDBG_EVENT_MAX; i++) { |
650 | 4cc70e93 | Fam Zheng | QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) { |
651 | 4cc70e93 | Fam Zheng | if (rule->action == ACTION_SUSPEND &&
|
652 | 4cc70e93 | Fam Zheng | !strcmp(rule->options.suspend.tag, tag)) { |
653 | 4cc70e93 | Fam Zheng | remove_rule(rule); |
654 | 4cc70e93 | Fam Zheng | ret = 0;
|
655 | 4cc70e93 | Fam Zheng | } |
656 | 4cc70e93 | Fam Zheng | } |
657 | 4cc70e93 | Fam Zheng | } |
658 | c547e564 | Fam Zheng | QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, r_next) { |
659 | 4cc70e93 | Fam Zheng | if (!strcmp(r->tag, tag)) {
|
660 | 4cc70e93 | Fam Zheng | qemu_coroutine_enter(r->co, NULL);
|
661 | 4cc70e93 | Fam Zheng | ret = 0;
|
662 | 4cc70e93 | Fam Zheng | } |
663 | 4cc70e93 | Fam Zheng | } |
664 | 4cc70e93 | Fam Zheng | return ret;
|
665 | 4cc70e93 | Fam Zheng | } |
666 | 3c90c65d | Kevin Wolf | |
667 | 3c90c65d | Kevin Wolf | static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag) |
668 | 3c90c65d | Kevin Wolf | { |
669 | 3c90c65d | Kevin Wolf | BDRVBlkdebugState *s = bs->opaque; |
670 | 3c90c65d | Kevin Wolf | BlkdebugSuspendedReq *r; |
671 | 3c90c65d | Kevin Wolf | |
672 | 3c90c65d | Kevin Wolf | QLIST_FOREACH(r, &s->suspended_reqs, next) { |
673 | 3c90c65d | Kevin Wolf | if (!strcmp(r->tag, tag)) {
|
674 | 3c90c65d | Kevin Wolf | return true; |
675 | 3c90c65d | Kevin Wolf | } |
676 | 3c90c65d | Kevin Wolf | } |
677 | 3c90c65d | Kevin Wolf | return false; |
678 | 3c90c65d | Kevin Wolf | } |
679 | 3c90c65d | Kevin Wolf | |
680 | e1302255 | Paolo Bonzini | static int64_t blkdebug_getlength(BlockDriverState *bs)
|
681 | e1302255 | Paolo Bonzini | { |
682 | e1302255 | Paolo Bonzini | return bdrv_getlength(bs->file);
|
683 | e1302255 | Paolo Bonzini | } |
684 | e1302255 | Paolo Bonzini | |
685 | 6a143727 | Kevin Wolf | static BlockDriver bdrv_blkdebug = {
|
686 | f4681212 | Kevin Wolf | .format_name = "blkdebug",
|
687 | f4681212 | Kevin Wolf | .protocol_name = "blkdebug",
|
688 | f4681212 | Kevin Wolf | .instance_size = sizeof(BDRVBlkdebugState),
|
689 | 6a143727 | Kevin Wolf | |
690 | f4681212 | Kevin Wolf | .bdrv_parse_filename = blkdebug_parse_filename, |
691 | f4681212 | Kevin Wolf | .bdrv_file_open = blkdebug_open, |
692 | f4681212 | Kevin Wolf | .bdrv_close = blkdebug_close, |
693 | f4681212 | Kevin Wolf | .bdrv_getlength = blkdebug_getlength, |
694 | 6a143727 | Kevin Wolf | |
695 | f4681212 | Kevin Wolf | .bdrv_aio_readv = blkdebug_aio_readv, |
696 | f4681212 | Kevin Wolf | .bdrv_aio_writev = blkdebug_aio_writev, |
697 | 8b9b0cc2 | Kevin Wolf | |
698 | 3c90c65d | Kevin Wolf | .bdrv_debug_event = blkdebug_debug_event, |
699 | 3c90c65d | Kevin Wolf | .bdrv_debug_breakpoint = blkdebug_debug_breakpoint, |
700 | 4cc70e93 | Fam Zheng | .bdrv_debug_remove_breakpoint |
701 | 4cc70e93 | Fam Zheng | = blkdebug_debug_remove_breakpoint, |
702 | 3c90c65d | Kevin Wolf | .bdrv_debug_resume = blkdebug_debug_resume, |
703 | 3c90c65d | Kevin Wolf | .bdrv_debug_is_suspended = blkdebug_debug_is_suspended, |
704 | 6a143727 | Kevin Wolf | }; |
705 | 6a143727 | Kevin Wolf | |
706 | 6a143727 | Kevin Wolf | static void bdrv_blkdebug_init(void) |
707 | 6a143727 | Kevin Wolf | { |
708 | 6a143727 | Kevin Wolf | bdrv_register(&bdrv_blkdebug); |
709 | 6a143727 | Kevin Wolf | } |
710 | 6a143727 | Kevin Wolf | |
711 | 6a143727 | Kevin Wolf | block_init(bdrv_blkdebug_init); |