Statistics
| Branch: | Revision:

root / block / blkdebug.c @ d7331bed

History | View | Annotate | Download (13 kB)

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);