]> git.proxmox.com Git - mirror_qemu.git/blob - block/blkdebug.c
blkdebug: store list of active rules
[mirror_qemu.git] / block / blkdebug.c
1 /*
2 * Block protocol for I/O error injection
3 *
4 * Copyright (c) 2010 Kevin Wolf <kwolf@redhat.com>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
25 #include "qemu-common.h"
26 #include "block_int.h"
27 #include "module.h"
28
29 typedef struct BDRVBlkdebugState {
30 int state;
31 QLIST_HEAD(, BlkdebugRule) rules[BLKDBG_EVENT_MAX];
32 QSIMPLEQ_HEAD(, BlkdebugRule) active_rules;
33 } BDRVBlkdebugState;
34
35 typedef struct BlkdebugAIOCB {
36 BlockDriverAIOCB common;
37 QEMUBH *bh;
38 int ret;
39 } BlkdebugAIOCB;
40
41 static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb);
42
43 static AIOPool blkdebug_aio_pool = {
44 .aiocb_size = sizeof(BlkdebugAIOCB),
45 .cancel = blkdebug_aio_cancel,
46 };
47
48 enum {
49 ACTION_INJECT_ERROR,
50 ACTION_SET_STATE,
51 };
52
53 typedef struct BlkdebugRule {
54 BlkDebugEvent event;
55 int action;
56 int state;
57 union {
58 struct {
59 int error;
60 int immediately;
61 int once;
62 } inject;
63 struct {
64 int new_state;
65 } set_state;
66 } options;
67 QLIST_ENTRY(BlkdebugRule) next;
68 QSIMPLEQ_ENTRY(BlkdebugRule) active_next;
69 } BlkdebugRule;
70
71 static QemuOptsList inject_error_opts = {
72 .name = "inject-error",
73 .head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head),
74 .desc = {
75 {
76 .name = "event",
77 .type = QEMU_OPT_STRING,
78 },
79 {
80 .name = "state",
81 .type = QEMU_OPT_NUMBER,
82 },
83 {
84 .name = "errno",
85 .type = QEMU_OPT_NUMBER,
86 },
87 {
88 .name = "once",
89 .type = QEMU_OPT_BOOL,
90 },
91 {
92 .name = "immediately",
93 .type = QEMU_OPT_BOOL,
94 },
95 { /* end of list */ }
96 },
97 };
98
99 static QemuOptsList set_state_opts = {
100 .name = "set-state",
101 .head = QTAILQ_HEAD_INITIALIZER(set_state_opts.head),
102 .desc = {
103 {
104 .name = "event",
105 .type = QEMU_OPT_STRING,
106 },
107 {
108 .name = "state",
109 .type = QEMU_OPT_NUMBER,
110 },
111 {
112 .name = "new_state",
113 .type = QEMU_OPT_NUMBER,
114 },
115 { /* end of list */ }
116 },
117 };
118
119 static QemuOptsList *config_groups[] = {
120 &inject_error_opts,
121 &set_state_opts,
122 NULL
123 };
124
125 static const char *event_names[BLKDBG_EVENT_MAX] = {
126 [BLKDBG_L1_UPDATE] = "l1_update",
127 [BLKDBG_L1_GROW_ALLOC_TABLE] = "l1_grow.alloc_table",
128 [BLKDBG_L1_GROW_WRITE_TABLE] = "l1_grow.write_table",
129 [BLKDBG_L1_GROW_ACTIVATE_TABLE] = "l1_grow.activate_table",
130
131 [BLKDBG_L2_LOAD] = "l2_load",
132 [BLKDBG_L2_UPDATE] = "l2_update",
133 [BLKDBG_L2_UPDATE_COMPRESSED] = "l2_update_compressed",
134 [BLKDBG_L2_ALLOC_COW_READ] = "l2_alloc.cow_read",
135 [BLKDBG_L2_ALLOC_WRITE] = "l2_alloc.write",
136
137 [BLKDBG_READ_AIO] = "read_aio",
138 [BLKDBG_READ_BACKING_AIO] = "read_backing_aio",
139 [BLKDBG_READ_COMPRESSED] = "read_compressed",
140
141 [BLKDBG_WRITE_AIO] = "write_aio",
142 [BLKDBG_WRITE_COMPRESSED] = "write_compressed",
143
144 [BLKDBG_VMSTATE_LOAD] = "vmstate_load",
145 [BLKDBG_VMSTATE_SAVE] = "vmstate_save",
146
147 [BLKDBG_COW_READ] = "cow_read",
148 [BLKDBG_COW_WRITE] = "cow_write",
149
150 [BLKDBG_REFTABLE_LOAD] = "reftable_load",
151 [BLKDBG_REFTABLE_GROW] = "reftable_grow",
152
153 [BLKDBG_REFBLOCK_LOAD] = "refblock_load",
154 [BLKDBG_REFBLOCK_UPDATE] = "refblock_update",
155 [BLKDBG_REFBLOCK_UPDATE_PART] = "refblock_update_part",
156 [BLKDBG_REFBLOCK_ALLOC] = "refblock_alloc",
157 [BLKDBG_REFBLOCK_ALLOC_HOOKUP] = "refblock_alloc.hookup",
158 [BLKDBG_REFBLOCK_ALLOC_WRITE] = "refblock_alloc.write",
159 [BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS] = "refblock_alloc.write_blocks",
160 [BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE] = "refblock_alloc.write_table",
161 [BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE] = "refblock_alloc.switch_table",
162
163 [BLKDBG_CLUSTER_ALLOC] = "cluster_alloc",
164 [BLKDBG_CLUSTER_ALLOC_BYTES] = "cluster_alloc_bytes",
165 [BLKDBG_CLUSTER_FREE] = "cluster_free",
166 };
167
168 static int get_event_by_name(const char *name, BlkDebugEvent *event)
169 {
170 int i;
171
172 for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
173 if (!strcmp(event_names[i], name)) {
174 *event = i;
175 return 0;
176 }
177 }
178
179 return -1;
180 }
181
182 struct add_rule_data {
183 BDRVBlkdebugState *s;
184 int action;
185 };
186
187 static int add_rule(QemuOpts *opts, void *opaque)
188 {
189 struct add_rule_data *d = opaque;
190 BDRVBlkdebugState *s = d->s;
191 const char* event_name;
192 BlkDebugEvent event;
193 struct BlkdebugRule *rule;
194
195 /* Find the right event for the rule */
196 event_name = qemu_opt_get(opts, "event");
197 if (!event_name || get_event_by_name(event_name, &event) < 0) {
198 return -1;
199 }
200
201 /* Set attributes common for all actions */
202 rule = g_malloc0(sizeof(*rule));
203 *rule = (struct BlkdebugRule) {
204 .event = event,
205 .action = d->action,
206 .state = qemu_opt_get_number(opts, "state", 0),
207 };
208
209 /* Parse action-specific options */
210 switch (d->action) {
211 case ACTION_INJECT_ERROR:
212 rule->options.inject.error = qemu_opt_get_number(opts, "errno", EIO);
213 rule->options.inject.once = qemu_opt_get_bool(opts, "once", 0);
214 rule->options.inject.immediately =
215 qemu_opt_get_bool(opts, "immediately", 0);
216 break;
217
218 case ACTION_SET_STATE:
219 rule->options.set_state.new_state =
220 qemu_opt_get_number(opts, "new_state", 0);
221 break;
222 };
223
224 /* Add the rule */
225 QLIST_INSERT_HEAD(&s->rules[event], rule, next);
226
227 return 0;
228 }
229
230 static int read_config(BDRVBlkdebugState *s, const char *filename)
231 {
232 FILE *f;
233 int ret;
234 struct add_rule_data d;
235
236 f = fopen(filename, "r");
237 if (f == NULL) {
238 return -errno;
239 }
240
241 ret = qemu_config_parse(f, config_groups, filename);
242 if (ret < 0) {
243 goto fail;
244 }
245
246 d.s = s;
247 d.action = ACTION_INJECT_ERROR;
248 qemu_opts_foreach(&inject_error_opts, add_rule, &d, 0);
249
250 d.action = ACTION_SET_STATE;
251 qemu_opts_foreach(&set_state_opts, add_rule, &d, 0);
252
253 ret = 0;
254 fail:
255 qemu_opts_reset(&inject_error_opts);
256 qemu_opts_reset(&set_state_opts);
257 fclose(f);
258 return ret;
259 }
260
261 /* Valid blkdebug filenames look like blkdebug:path/to/config:path/to/image */
262 static int blkdebug_open(BlockDriverState *bs, const char *filename, int flags)
263 {
264 BDRVBlkdebugState *s = bs->opaque;
265 int ret;
266 char *config, *c;
267
268 /* Parse the blkdebug: prefix */
269 if (strncmp(filename, "blkdebug:", strlen("blkdebug:"))) {
270 return -EINVAL;
271 }
272 filename += strlen("blkdebug:");
273
274 /* Read rules from config file */
275 c = strchr(filename, ':');
276 if (c == NULL) {
277 return -EINVAL;
278 }
279
280 config = g_strdup(filename);
281 config[c - filename] = '\0';
282 ret = read_config(s, config);
283 g_free(config);
284 if (ret < 0) {
285 return ret;
286 }
287 filename = c + 1;
288
289 /* Set initial state */
290 s->state = 1;
291
292 /* Open the backing file */
293 ret = bdrv_file_open(&bs->file, filename, flags);
294 if (ret < 0) {
295 return ret;
296 }
297
298 return 0;
299 }
300
301 static void error_callback_bh(void *opaque)
302 {
303 struct BlkdebugAIOCB *acb = opaque;
304 qemu_bh_delete(acb->bh);
305 acb->common.cb(acb->common.opaque, acb->ret);
306 qemu_aio_release(acb);
307 }
308
309 static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb)
310 {
311 BlkdebugAIOCB *acb = container_of(blockacb, BlkdebugAIOCB, common);
312 qemu_aio_release(acb);
313 }
314
315 static BlockDriverAIOCB *inject_error(BlockDriverState *bs,
316 BlockDriverCompletionFunc *cb, void *opaque, BlkdebugRule *rule)
317 {
318 BDRVBlkdebugState *s = bs->opaque;
319 int error = rule->options.inject.error;
320 struct BlkdebugAIOCB *acb;
321 QEMUBH *bh;
322
323 if (rule->options.inject.once) {
324 QSIMPLEQ_INIT(&s->active_rules);
325 }
326
327 if (rule->options.inject.immediately) {
328 return NULL;
329 }
330
331 acb = qemu_aio_get(&blkdebug_aio_pool, bs, cb, opaque);
332 acb->ret = -error;
333
334 bh = qemu_bh_new(error_callback_bh, acb);
335 acb->bh = bh;
336 qemu_bh_schedule(bh);
337
338 return &acb->common;
339 }
340
341 static BlockDriverAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
342 int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
343 BlockDriverCompletionFunc *cb, void *opaque)
344 {
345 BDRVBlkdebugState *s = bs->opaque;
346 BlkdebugRule *rule = QSIMPLEQ_FIRST(&s->active_rules);
347
348 if (rule && rule->options.inject.error) {
349 return inject_error(bs, cb, opaque, rule);
350 }
351
352 return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
353 }
354
355 static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
356 int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
357 BlockDriverCompletionFunc *cb, void *opaque)
358 {
359 BDRVBlkdebugState *s = bs->opaque;
360 BlkdebugRule *rule = QSIMPLEQ_FIRST(&s->active_rules);
361
362 if (rule && rule->options.inject.error) {
363 return inject_error(bs, cb, opaque, rule);
364 }
365
366 return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
367 }
368
369 static void blkdebug_close(BlockDriverState *bs)
370 {
371 BDRVBlkdebugState *s = bs->opaque;
372 BlkdebugRule *rule, *next;
373 int i;
374
375 for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
376 QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
377 QLIST_REMOVE(rule, next);
378 g_free(rule);
379 }
380 }
381 }
382
383 static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
384 int old_state, bool injected)
385 {
386 BDRVBlkdebugState *s = bs->opaque;
387
388 /* Only process rules for the current state */
389 if (rule->state && rule->state != old_state) {
390 return injected;
391 }
392
393 /* Take the action */
394 switch (rule->action) {
395 case ACTION_INJECT_ERROR:
396 if (!injected) {
397 QSIMPLEQ_INIT(&s->active_rules);
398 injected = true;
399 }
400 QSIMPLEQ_INSERT_HEAD(&s->active_rules, rule, active_next);
401 break;
402
403 case ACTION_SET_STATE:
404 s->state = rule->options.set_state.new_state;
405 break;
406 }
407 return injected;
408 }
409
410 static void blkdebug_debug_event(BlockDriverState *bs, BlkDebugEvent event)
411 {
412 BDRVBlkdebugState *s = bs->opaque;
413 struct BlkdebugRule *rule;
414 int old_state = s->state;
415 bool injected;
416
417 assert((int)event >= 0 && event < BLKDBG_EVENT_MAX);
418
419 injected = false;
420 QLIST_FOREACH(rule, &s->rules[event], next) {
421 injected = process_rule(bs, rule, old_state, injected);
422 }
423 }
424
425 static int64_t blkdebug_getlength(BlockDriverState *bs)
426 {
427 return bdrv_getlength(bs->file);
428 }
429
430 static BlockDriver bdrv_blkdebug = {
431 .format_name = "blkdebug",
432 .protocol_name = "blkdebug",
433
434 .instance_size = sizeof(BDRVBlkdebugState),
435
436 .bdrv_file_open = blkdebug_open,
437 .bdrv_close = blkdebug_close,
438 .bdrv_getlength = blkdebug_getlength,
439
440 .bdrv_aio_readv = blkdebug_aio_readv,
441 .bdrv_aio_writev = blkdebug_aio_writev,
442
443 .bdrv_debug_event = blkdebug_debug_event,
444 };
445
446 static void bdrv_blkdebug_init(void)
447 {
448 bdrv_register(&bdrv_blkdebug);
449 }
450
451 block_init(bdrv_blkdebug_init);