|
|
1.1 root 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(set_state_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 */
1.1.1.3 root 217: rule = g_malloc0(sizeof(*rule));
1.1 root 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: qemu_opts_reset(&inject_error_opts);
271: qemu_opts_reset(&set_state_opts);
272: fclose(f);
273: return ret;
274: }
275:
276: /* Valid blkdebug filenames look like blkdebug:path/to/config:path/to/image */
277: static int blkdebug_open(BlockDriverState *bs, const char *filename, int flags)
278: {
279: BDRVBlkdebugState *s = bs->opaque;
280: int ret;
281: char *config, *c;
282:
283: /* Parse the blkdebug: prefix */
284: if (strncmp(filename, "blkdebug:", strlen("blkdebug:"))) {
285: return -EINVAL;
286: }
287: filename += strlen("blkdebug:");
288:
289: /* Read rules from config file */
290: c = strchr(filename, ':');
291: if (c == NULL) {
292: return -EINVAL;
293: }
294:
1.1.1.4 ! root 295: config = g_strdup(filename);
1.1 root 296: config[c - filename] = '\0';
297: ret = read_config(s, config);
1.1.1.4 ! root 298: g_free(config);
1.1 root 299: if (ret < 0) {
300: return ret;
301: }
302: filename = c + 1;
303:
304: /* Set initial state */
305: s->vars.state = 1;
306:
307: /* Open the backing file */
308: ret = bdrv_file_open(&bs->file, filename, flags);
309: if (ret < 0) {
310: return ret;
311: }
312:
313: return 0;
314: }
315:
316: static void error_callback_bh(void *opaque)
317: {
318: struct BlkdebugAIOCB *acb = opaque;
319: qemu_bh_delete(acb->bh);
320: acb->common.cb(acb->common.opaque, acb->ret);
321: qemu_aio_release(acb);
322: }
323:
324: static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb)
325: {
326: BlkdebugAIOCB *acb = container_of(blockacb, BlkdebugAIOCB, common);
327: qemu_aio_release(acb);
328: }
329:
330: static BlockDriverAIOCB *inject_error(BlockDriverState *bs,
331: BlockDriverCompletionFunc *cb, void *opaque)
332: {
333: BDRVBlkdebugState *s = bs->opaque;
334: int error = s->vars.inject_errno;
335: struct BlkdebugAIOCB *acb;
336: QEMUBH *bh;
337:
338: if (s->vars.inject_once) {
339: s->vars.inject_errno = 0;
340: }
341:
342: if (s->vars.inject_immediately) {
343: return NULL;
344: }
345:
346: acb = qemu_aio_get(&blkdebug_aio_pool, bs, cb, opaque);
347: acb->ret = -error;
348:
349: bh = qemu_bh_new(error_callback_bh, acb);
350: acb->bh = bh;
351: qemu_bh_schedule(bh);
352:
353: return &acb->common;
354: }
355:
356: static BlockDriverAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
357: int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
358: BlockDriverCompletionFunc *cb, void *opaque)
359: {
360: BDRVBlkdebugState *s = bs->opaque;
361:
362: if (s->vars.inject_errno) {
363: return inject_error(bs, cb, opaque);
364: }
365:
366: BlockDriverAIOCB *acb =
367: bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
368: return acb;
369: }
370:
371: static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
372: int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
373: BlockDriverCompletionFunc *cb, void *opaque)
374: {
375: BDRVBlkdebugState *s = bs->opaque;
376:
377: if (s->vars.inject_errno) {
378: return inject_error(bs, cb, opaque);
379: }
380:
381: BlockDriverAIOCB *acb =
382: bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
383: return acb;
384: }
385:
386: static void blkdebug_close(BlockDriverState *bs)
387: {
388: BDRVBlkdebugState *s = bs->opaque;
389: BlkdebugRule *rule, *next;
390: int i;
391:
392: for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
393: QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
394: QLIST_REMOVE(rule, next);
1.1.1.3 root 395: g_free(rule);
1.1 root 396: }
397: }
398: }
399:
400: static void process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
401: BlkdebugVars *old_vars)
402: {
403: BDRVBlkdebugState *s = bs->opaque;
404: BlkdebugVars *vars = &s->vars;
405:
406: /* Only process rules for the current state */
407: if (rule->state && rule->state != old_vars->state) {
408: return;
409: }
410:
411: /* Take the action */
412: switch (rule->action) {
413: case ACTION_INJECT_ERROR:
414: vars->inject_errno = rule->options.inject.error;
415: vars->inject_once = rule->options.inject.once;
416: vars->inject_immediately = rule->options.inject.immediately;
417: break;
418:
419: case ACTION_SET_STATE:
420: vars->state = rule->options.set_state.new_state;
421: break;
422: }
423: }
424:
425: static void blkdebug_debug_event(BlockDriverState *bs, BlkDebugEvent event)
426: {
427: BDRVBlkdebugState *s = bs->opaque;
428: struct BlkdebugRule *rule;
429: BlkdebugVars old_vars = s->vars;
430:
1.1.1.2 root 431: assert((int)event >= 0 && event < BLKDBG_EVENT_MAX);
1.1 root 432:
433: QLIST_FOREACH(rule, &s->rules[event], next) {
434: process_rule(bs, rule, &old_vars);
435: }
436: }
437:
438: static BlockDriver bdrv_blkdebug = {
439: .format_name = "blkdebug",
440: .protocol_name = "blkdebug",
441:
442: .instance_size = sizeof(BDRVBlkdebugState),
443:
444: .bdrv_file_open = blkdebug_open,
445: .bdrv_close = blkdebug_close,
446:
447: .bdrv_aio_readv = blkdebug_aio_readv,
448: .bdrv_aio_writev = blkdebug_aio_writev,
449:
450: .bdrv_debug_event = blkdebug_debug_event,
451: };
452:
453: static void bdrv_blkdebug_init(void)
454: {
455: bdrv_register(&bdrv_blkdebug);
456: }
457:
458: block_init(bdrv_blkdebug_init);
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.