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