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