]> Git Repo - qemu.git/blob - block/blkdebug.c
Merge remote branch 'kwolf/for-anthony' into staging
[qemu.git] / block / blkdebug.c
1 /*
2  * Block protocol for I/O error injection
3  *
4  * Copyright (c) 2010 Kevin Wolf <[email protected]>
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 BlkdebugVars {
30     int state;
31
32     /* If inject_errno != 0, an error is injected for requests */
33     int inject_errno;
34
35     /* Decides if all future requests fail (false) or only the next one and
36      * after the next request inject_errno is reset to 0 (true) */
37     bool inject_once;
38
39     /* Decides if aio_readv/writev fails right away (true) or returns an error
40      * return value only in the callback (false) */
41     bool inject_immediately;
42 } BlkdebugVars;
43
44 typedef struct BDRVBlkdebugState {
45     BlkdebugVars vars;
46     QLIST_HEAD(list, BlkdebugRule) rules[BLKDBG_EVENT_MAX];
47 } BDRVBlkdebugState;
48
49 typedef struct BlkdebugAIOCB {
50     BlockDriverAIOCB common;
51     QEMUBH *bh;
52     int ret;
53 } BlkdebugAIOCB;
54
55 static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb);
56
57 static AIOPool blkdebug_aio_pool = {
58     .aiocb_size = sizeof(BlkdebugAIOCB),
59     .cancel     = blkdebug_aio_cancel,
60 };
61
62 enum {
63     ACTION_INJECT_ERROR,
64     ACTION_SET_STATE,
65 };
66
67 typedef struct BlkdebugRule {
68     BlkDebugEvent event;
69     int action;
70     int state;
71     union {
72         struct {
73             int error;
74             int immediately;
75             int once;
76         } inject;
77         struct {
78             int new_state;
79         } set_state;
80     } options;
81     QLIST_ENTRY(BlkdebugRule) next;
82 } BlkdebugRule;
83
84 static QemuOptsList inject_error_opts = {
85     .name = "inject-error",
86     .head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head),
87     .desc = {
88         {
89             .name = "event",
90             .type = QEMU_OPT_STRING,
91         },
92         {
93             .name = "state",
94             .type = QEMU_OPT_NUMBER,
95         },
96         {
97             .name = "errno",
98             .type = QEMU_OPT_NUMBER,
99         },
100         {
101             .name = "once",
102             .type = QEMU_OPT_BOOL,
103         },
104         {
105             .name = "immediately",
106             .type = QEMU_OPT_BOOL,
107         },
108         { /* end of list */ }
109     },
110 };
111
112 static QemuOptsList set_state_opts = {
113     .name = "set-state",
114     .head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head),
115     .desc = {
116         {
117             .name = "event",
118             .type = QEMU_OPT_STRING,
119         },
120         {
121             .name = "state",
122             .type = QEMU_OPT_NUMBER,
123         },
124         {
125             .name = "new_state",
126             .type = QEMU_OPT_NUMBER,
127         },
128         { /* end of list */ }
129     },
130 };
131
132 static QemuOptsList *config_groups[] = {
133     &inject_error_opts,
134     &set_state_opts,
135     NULL
136 };
137
138 static const char *event_names[BLKDBG_EVENT_MAX] = {
139     [BLKDBG_L1_UPDATE]                      = "l1_update",
140     [BLKDBG_L1_GROW_ALLOC_TABLE]            = "l1_grow.alloc_table",
141     [BLKDBG_L1_GROW_WRITE_TABLE]            = "l1_grow.write_table",
142     [BLKDBG_L1_GROW_ACTIVATE_TABLE]         = "l1_grow.activate_table",
143
144     [BLKDBG_L2_LOAD]                        = "l2_load",
145     [BLKDBG_L2_UPDATE]                      = "l2_update",
146     [BLKDBG_L2_UPDATE_COMPRESSED]           = "l2_update_compressed",
147     [BLKDBG_L2_ALLOC_COW_READ]              = "l2_alloc.cow_read",
148     [BLKDBG_L2_ALLOC_WRITE]                 = "l2_alloc.write",
149
150     [BLKDBG_READ]                           = "read",
151     [BLKDBG_READ_AIO]                       = "read_aio",
152     [BLKDBG_READ_BACKING]                   = "read_backing",
153     [BLKDBG_READ_BACKING_AIO]               = "read_backing_aio",
154     [BLKDBG_READ_COMPRESSED]                = "read_compressed",
155
156     [BLKDBG_WRITE_AIO]                      = "write_aio",
157     [BLKDBG_WRITE_COMPRESSED]               = "write_compressed",
158
159     [BLKDBG_VMSTATE_LOAD]                   = "vmstate_load",
160     [BLKDBG_VMSTATE_SAVE]                   = "vmstate_save",
161
162     [BLKDBG_COW_READ]                       = "cow_read",
163     [BLKDBG_COW_WRITE]                      = "cow_write",
164
165     [BLKDBG_REFTABLE_LOAD]                  = "reftable_load",
166     [BLKDBG_REFTABLE_GROW]                  = "reftable_grow",
167
168     [BLKDBG_REFBLOCK_LOAD]                  = "refblock_load",
169     [BLKDBG_REFBLOCK_UPDATE]                = "refblock_update",
170     [BLKDBG_REFBLOCK_UPDATE_PART]           = "refblock_update_part",
171     [BLKDBG_REFBLOCK_ALLOC]                 = "refblock_alloc",
172     [BLKDBG_REFBLOCK_ALLOC_HOOKUP]          = "refblock_alloc.hookup",
173     [BLKDBG_REFBLOCK_ALLOC_WRITE]           = "refblock_alloc.write",
174     [BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS]    = "refblock_alloc.write_blocks",
175     [BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE]     = "refblock_alloc.write_table",
176     [BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE]    = "refblock_alloc.switch_table",
177
178     [BLKDBG_CLUSTER_ALLOC]                  = "cluster_alloc",
179     [BLKDBG_CLUSTER_ALLOC_BYTES]            = "cluster_alloc_bytes",
180     [BLKDBG_CLUSTER_FREE]                   = "cluster_free",
181 };
182
183 static int get_event_by_name(const char *name, BlkDebugEvent *event)
184 {
185     int i;
186
187     for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
188         if (!strcmp(event_names[i], name)) {
189             *event = i;
190             return 0;
191         }
192     }
193
194     return -1;
195 }
196
197 struct add_rule_data {
198     BDRVBlkdebugState *s;
199     int action;
200 };
201
202 static int add_rule(QemuOpts *opts, void *opaque)
203 {
204     struct add_rule_data *d = opaque;
205     BDRVBlkdebugState *s = d->s;
206     const char* event_name;
207     BlkDebugEvent event;
208     struct BlkdebugRule *rule;
209
210     /* Find the right event for the rule */
211     event_name = qemu_opt_get(opts, "event");
212     if (!event_name || get_event_by_name(event_name, &event) < 0) {
213         return -1;
214     }
215
216     /* Set attributes common for all actions */
217     rule = qemu_mallocz(sizeof(*rule));
218     *rule = (struct BlkdebugRule) {
219         .event  = event,
220         .action = d->action,
221         .state  = qemu_opt_get_number(opts, "state", 0),
222     };
223
224     /* Parse action-specific options */
225     switch (d->action) {
226     case ACTION_INJECT_ERROR:
227         rule->options.inject.error = qemu_opt_get_number(opts, "errno", EIO);
228         rule->options.inject.once  = qemu_opt_get_bool(opts, "once", 0);
229         rule->options.inject.immediately =
230             qemu_opt_get_bool(opts, "immediately", 0);
231         break;
232
233     case ACTION_SET_STATE:
234         rule->options.set_state.new_state =
235             qemu_opt_get_number(opts, "new_state", 0);
236         break;
237     };
238
239     /* Add the rule */
240     QLIST_INSERT_HEAD(&s->rules[event], rule, next);
241
242     return 0;
243 }
244
245 static int read_config(BDRVBlkdebugState *s, const char *filename)
246 {
247     FILE *f;
248     int ret;
249     struct add_rule_data d;
250
251     f = fopen(filename, "r");
252     if (f == NULL) {
253         return -errno;
254     }
255
256     ret = qemu_config_parse(f, config_groups, filename);
257     if (ret < 0) {
258         goto fail;
259     }
260
261     d.s = s;
262     d.action = ACTION_INJECT_ERROR;
263     qemu_opts_foreach(&inject_error_opts, add_rule, &d, 0);
264
265     d.action = ACTION_SET_STATE;
266     qemu_opts_foreach(&set_state_opts, add_rule, &d, 0);
267
268     ret = 0;
269 fail:
270     fclose(f);
271     return ret;
272 }
273
274 /* Valid blkdebug filenames look like blkdebug:path/to/config:path/to/image */
275 static int blkdebug_open(BlockDriverState *bs, const char *filename, int flags)
276 {
277     BDRVBlkdebugState *s = bs->opaque;
278     int ret;
279     char *config, *c;
280
281     /* Parse the blkdebug: prefix */
282     if (strncmp(filename, "blkdebug:", strlen("blkdebug:"))) {
283         return -EINVAL;
284     }
285     filename += strlen("blkdebug:");
286
287     /* Read rules from config file */
288     c = strchr(filename, ':');
289     if (c == NULL) {
290         return -EINVAL;
291     }
292
293     config = strdup(filename);
294     config[c - filename] = '\0';
295     ret = read_config(s, config);
296     free(config);
297     if (ret < 0) {
298         return ret;
299     }
300     filename = c + 1;
301
302     /* Open the backing file */
303     ret = bdrv_file_open(&bs->file, filename, flags);
304     if (ret < 0) {
305         return ret;
306     }
307
308     return 0;
309 }
310
311 static void error_callback_bh(void *opaque)
312 {
313     struct BlkdebugAIOCB *acb = opaque;
314     qemu_bh_delete(acb->bh);
315     acb->common.cb(acb->common.opaque, acb->ret);
316     qemu_aio_release(acb);
317 }
318
319 static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb)
320 {
321     BlkdebugAIOCB *acb = container_of(blockacb, BlkdebugAIOCB, common);
322     qemu_aio_release(acb);
323 }
324
325 static BlockDriverAIOCB *inject_error(BlockDriverState *bs,
326     BlockDriverCompletionFunc *cb, void *opaque)
327 {
328     BDRVBlkdebugState *s = bs->opaque;
329     int error = s->vars.inject_errno;
330     struct BlkdebugAIOCB *acb;
331     QEMUBH *bh;
332
333     if (s->vars.inject_once) {
334         s->vars.inject_errno = 0;
335     }
336
337     if (s->vars.inject_immediately) {
338         return NULL;
339     }
340
341     acb = qemu_aio_get(&blkdebug_aio_pool, bs, cb, opaque);
342     acb->ret = -error;
343
344     bh = qemu_bh_new(error_callback_bh, acb);
345     acb->bh = bh;
346     qemu_bh_schedule(bh);
347
348     return &acb->common;
349 }
350
351 static BlockDriverAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
352     int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
353     BlockDriverCompletionFunc *cb, void *opaque)
354 {
355     BDRVBlkdebugState *s = bs->opaque;
356
357     if (s->vars.inject_errno) {
358         return inject_error(bs, cb, opaque);
359     }
360
361     BlockDriverAIOCB *acb =
362         bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
363     return acb;
364 }
365
366 static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
367     int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
368     BlockDriverCompletionFunc *cb, void *opaque)
369 {
370     BDRVBlkdebugState *s = bs->opaque;
371
372     if (s->vars.inject_errno) {
373         return inject_error(bs, cb, opaque);
374     }
375
376     BlockDriverAIOCB *acb =
377         bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
378     return acb;
379 }
380
381 static void blkdebug_close(BlockDriverState *bs)
382 {
383     BDRVBlkdebugState *s = bs->opaque;
384     BlkdebugRule *rule, *next;
385     int i;
386
387     for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
388         QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
389             QLIST_REMOVE(rule, next);
390             qemu_free(rule);
391         }
392     }
393 }
394
395 static void blkdebug_flush(BlockDriverState *bs)
396 {
397     bdrv_flush(bs->file);
398 }
399
400 static BlockDriverAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
401     BlockDriverCompletionFunc *cb, void *opaque)
402 {
403     return bdrv_aio_flush(bs->file, cb, opaque);
404 }
405
406 static void process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
407     BlkdebugVars *old_vars)
408 {
409     BDRVBlkdebugState *s = bs->opaque;
410     BlkdebugVars *vars = &s->vars;
411
412     /* Only process rules for the current state */
413     if (rule->state && rule->state != old_vars->state) {
414         return;
415     }
416
417     /* Take the action */
418     switch (rule->action) {
419     case ACTION_INJECT_ERROR:
420         vars->inject_errno       = rule->options.inject.error;
421         vars->inject_once        = rule->options.inject.once;
422         vars->inject_immediately = rule->options.inject.immediately;
423         break;
424
425     case ACTION_SET_STATE:
426         vars->state              = rule->options.set_state.new_state;
427         break;
428     }
429 }
430
431 static void blkdebug_debug_event(BlockDriverState *bs, BlkDebugEvent event)
432 {
433     BDRVBlkdebugState *s = bs->opaque;
434     struct BlkdebugRule *rule;
435     BlkdebugVars old_vars = s->vars;
436
437     if (event < 0 || event >= BLKDBG_EVENT_MAX) {
438         return;
439     }
440
441     QLIST_FOREACH(rule, &s->rules[event], next) {
442         process_rule(bs, rule, &old_vars);
443     }
444 }
445
446 static BlockDriver bdrv_blkdebug = {
447     .format_name        = "blkdebug",
448     .protocol_name      = "blkdebug",
449
450     .instance_size      = sizeof(BDRVBlkdebugState),
451
452     .bdrv_file_open     = blkdebug_open,
453     .bdrv_close         = blkdebug_close,
454     .bdrv_flush         = blkdebug_flush,
455
456     .bdrv_aio_readv     = blkdebug_aio_readv,
457     .bdrv_aio_writev    = blkdebug_aio_writev,
458     .bdrv_aio_flush     = blkdebug_aio_flush,
459
460     .bdrv_debug_event   = blkdebug_debug_event,
461 };
462
463 static void bdrv_blkdebug_init(void)
464 {
465     bdrv_register(&bdrv_blkdebug);
466 }
467
468 block_init(bdrv_blkdebug_init);
This page took 0.051001 seconds and 4 git commands to generate.