qemu/block/blkdebug.c
<<
>>
Prefs
   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 "qemu/config-file.h"
  27#include "block/block_int.h"
  28#include "qemu/module.h"
  29#include "qapi/qmp/qbool.h"
  30#include "qapi/qmp/qdict.h"
  31#include "qapi/qmp/qint.h"
  32#include "qapi/qmp/qstring.h"
  33
  34typedef struct BDRVBlkdebugState {
  35    int state;
  36    int new_state;
  37
  38    QLIST_HEAD(, BlkdebugRule) rules[BLKDBG_EVENT_MAX];
  39    QSIMPLEQ_HEAD(, BlkdebugRule) active_rules;
  40    QLIST_HEAD(, BlkdebugSuspendedReq) suspended_reqs;
  41} BDRVBlkdebugState;
  42
  43typedef struct BlkdebugAIOCB {
  44    BlockAIOCB common;
  45    QEMUBH *bh;
  46    int ret;
  47} BlkdebugAIOCB;
  48
  49typedef struct BlkdebugSuspendedReq {
  50    Coroutine *co;
  51    char *tag;
  52    QLIST_ENTRY(BlkdebugSuspendedReq) next;
  53} BlkdebugSuspendedReq;
  54
  55static const AIOCBInfo blkdebug_aiocb_info = {
  56    .aiocb_size    = sizeof(BlkdebugAIOCB),
  57};
  58
  59enum {
  60    ACTION_INJECT_ERROR,
  61    ACTION_SET_STATE,
  62    ACTION_SUSPEND,
  63};
  64
  65typedef struct BlkdebugRule {
  66    BlkDebugEvent event;
  67    int action;
  68    int state;
  69    union {
  70        struct {
  71            int error;
  72            int immediately;
  73            int once;
  74            int64_t sector;
  75        } inject;
  76        struct {
  77            int new_state;
  78        } set_state;
  79        struct {
  80            char *tag;
  81        } suspend;
  82    } options;
  83    QLIST_ENTRY(BlkdebugRule) next;
  84    QSIMPLEQ_ENTRY(BlkdebugRule) active_next;
  85} BlkdebugRule;
  86
  87static QemuOptsList inject_error_opts = {
  88    .name = "inject-error",
  89    .head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head),
  90    .desc = {
  91        {
  92            .name = "event",
  93            .type = QEMU_OPT_STRING,
  94        },
  95        {
  96            .name = "state",
  97            .type = QEMU_OPT_NUMBER,
  98        },
  99        {
 100            .name = "errno",
 101            .type = QEMU_OPT_NUMBER,
 102        },
 103        {
 104            .name = "sector",
 105            .type = QEMU_OPT_NUMBER,
 106        },
 107        {
 108            .name = "once",
 109            .type = QEMU_OPT_BOOL,
 110        },
 111        {
 112            .name = "immediately",
 113            .type = QEMU_OPT_BOOL,
 114        },
 115        { /* end of list */ }
 116    },
 117};
 118
 119static QemuOptsList set_state_opts = {
 120    .name = "set-state",
 121    .head = QTAILQ_HEAD_INITIALIZER(set_state_opts.head),
 122    .desc = {
 123        {
 124            .name = "event",
 125            .type = QEMU_OPT_STRING,
 126        },
 127        {
 128            .name = "state",
 129            .type = QEMU_OPT_NUMBER,
 130        },
 131        {
 132            .name = "new_state",
 133            .type = QEMU_OPT_NUMBER,
 134        },
 135        { /* end of list */ }
 136    },
 137};
 138
 139static QemuOptsList *config_groups[] = {
 140    &inject_error_opts,
 141    &set_state_opts,
 142    NULL
 143};
 144
 145static const char *event_names[BLKDBG_EVENT_MAX] = {
 146    [BLKDBG_L1_UPDATE]                      = "l1_update",
 147    [BLKDBG_L1_GROW_ALLOC_TABLE]            = "l1_grow.alloc_table",
 148    [BLKDBG_L1_GROW_WRITE_TABLE]            = "l1_grow.write_table",
 149    [BLKDBG_L1_GROW_ACTIVATE_TABLE]         = "l1_grow.activate_table",
 150
 151    [BLKDBG_L2_LOAD]                        = "l2_load",
 152    [BLKDBG_L2_UPDATE]                      = "l2_update",
 153    [BLKDBG_L2_UPDATE_COMPRESSED]           = "l2_update_compressed",
 154    [BLKDBG_L2_ALLOC_COW_READ]              = "l2_alloc.cow_read",
 155    [BLKDBG_L2_ALLOC_WRITE]                 = "l2_alloc.write",
 156
 157    [BLKDBG_READ_AIO]                       = "read_aio",
 158    [BLKDBG_READ_BACKING_AIO]               = "read_backing_aio",
 159    [BLKDBG_READ_COMPRESSED]                = "read_compressed",
 160
 161    [BLKDBG_WRITE_AIO]                      = "write_aio",
 162    [BLKDBG_WRITE_COMPRESSED]               = "write_compressed",
 163
 164    [BLKDBG_VMSTATE_LOAD]                   = "vmstate_load",
 165    [BLKDBG_VMSTATE_SAVE]                   = "vmstate_save",
 166
 167    [BLKDBG_COW_READ]                       = "cow_read",
 168    [BLKDBG_COW_WRITE]                      = "cow_write",
 169
 170    [BLKDBG_REFTABLE_LOAD]                  = "reftable_load",
 171    [BLKDBG_REFTABLE_GROW]                  = "reftable_grow",
 172    [BLKDBG_REFTABLE_UPDATE]                = "reftable_update",
 173
 174    [BLKDBG_REFBLOCK_LOAD]                  = "refblock_load",
 175    [BLKDBG_REFBLOCK_UPDATE]                = "refblock_update",
 176    [BLKDBG_REFBLOCK_UPDATE_PART]           = "refblock_update_part",
 177    [BLKDBG_REFBLOCK_ALLOC]                 = "refblock_alloc",
 178    [BLKDBG_REFBLOCK_ALLOC_HOOKUP]          = "refblock_alloc.hookup",
 179    [BLKDBG_REFBLOCK_ALLOC_WRITE]           = "refblock_alloc.write",
 180    [BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS]    = "refblock_alloc.write_blocks",
 181    [BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE]     = "refblock_alloc.write_table",
 182    [BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE]    = "refblock_alloc.switch_table",
 183
 184    [BLKDBG_CLUSTER_ALLOC]                  = "cluster_alloc",
 185    [BLKDBG_CLUSTER_ALLOC_BYTES]            = "cluster_alloc_bytes",
 186    [BLKDBG_CLUSTER_FREE]                   = "cluster_free",
 187
 188    [BLKDBG_FLUSH_TO_OS]                    = "flush_to_os",
 189    [BLKDBG_FLUSH_TO_DISK]                  = "flush_to_disk",
 190
 191    [BLKDBG_PWRITEV_RMW_HEAD]               = "pwritev_rmw.head",
 192    [BLKDBG_PWRITEV_RMW_AFTER_HEAD]         = "pwritev_rmw.after_head",
 193    [BLKDBG_PWRITEV_RMW_TAIL]               = "pwritev_rmw.tail",
 194    [BLKDBG_PWRITEV_RMW_AFTER_TAIL]         = "pwritev_rmw.after_tail",
 195    [BLKDBG_PWRITEV]                        = "pwritev",
 196    [BLKDBG_PWRITEV_ZERO]                   = "pwritev_zero",
 197    [BLKDBG_PWRITEV_DONE]                   = "pwritev_done",
 198
 199    [BLKDBG_EMPTY_IMAGE_PREPARE]            = "empty_image_prepare",
 200};
 201
 202static int get_event_by_name(const char *name, BlkDebugEvent *event)
 203{
 204    int i;
 205
 206    for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
 207        if (!strcmp(event_names[i], name)) {
 208            *event = i;
 209            return 0;
 210        }
 211    }
 212
 213    return -1;
 214}
 215
 216struct add_rule_data {
 217    BDRVBlkdebugState *s;
 218    int action;
 219};
 220
 221static int add_rule(void *opaque, QemuOpts *opts, Error **errp)
 222{
 223    struct add_rule_data *d = opaque;
 224    BDRVBlkdebugState *s = d->s;
 225    const char* event_name;
 226    BlkDebugEvent event;
 227    struct BlkdebugRule *rule;
 228
 229    /* Find the right event for the rule */
 230    event_name = qemu_opt_get(opts, "event");
 231    if (!event_name) {
 232        error_setg(errp, "Missing event name for rule");
 233        return -1;
 234    } else if (get_event_by_name(event_name, &event) < 0) {
 235        error_setg(errp, "Invalid event name \"%s\"", event_name);
 236        return -1;
 237    }
 238
 239    /* Set attributes common for all actions */
 240    rule = g_malloc0(sizeof(*rule));
 241    *rule = (struct BlkdebugRule) {
 242        .event  = event,
 243        .action = d->action,
 244        .state  = qemu_opt_get_number(opts, "state", 0),
 245    };
 246
 247    /* Parse action-specific options */
 248    switch (d->action) {
 249    case ACTION_INJECT_ERROR:
 250        rule->options.inject.error = qemu_opt_get_number(opts, "errno", EIO);
 251        rule->options.inject.once  = qemu_opt_get_bool(opts, "once", 0);
 252        rule->options.inject.immediately =
 253            qemu_opt_get_bool(opts, "immediately", 0);
 254        rule->options.inject.sector = qemu_opt_get_number(opts, "sector", -1);
 255        break;
 256
 257    case ACTION_SET_STATE:
 258        rule->options.set_state.new_state =
 259            qemu_opt_get_number(opts, "new_state", 0);
 260        break;
 261
 262    case ACTION_SUSPEND:
 263        rule->options.suspend.tag =
 264            g_strdup(qemu_opt_get(opts, "tag"));
 265        break;
 266    };
 267
 268    /* Add the rule */
 269    QLIST_INSERT_HEAD(&s->rules[event], rule, next);
 270
 271    return 0;
 272}
 273
 274static void remove_rule(BlkdebugRule *rule)
 275{
 276    switch (rule->action) {
 277    case ACTION_INJECT_ERROR:
 278    case ACTION_SET_STATE:
 279        break;
 280    case ACTION_SUSPEND:
 281        g_free(rule->options.suspend.tag);
 282        break;
 283    }
 284
 285    QLIST_REMOVE(rule, next);
 286    g_free(rule);
 287}
 288
 289static int read_config(BDRVBlkdebugState *s, const char *filename,
 290                       QDict *options, Error **errp)
 291{
 292    FILE *f = NULL;
 293    int ret;
 294    struct add_rule_data d;
 295    Error *local_err = NULL;
 296
 297    if (filename) {
 298        f = fopen(filename, "r");
 299        if (f == NULL) {
 300            error_setg_errno(errp, errno, "Could not read blkdebug config file");
 301            return -errno;
 302        }
 303
 304        ret = qemu_config_parse(f, config_groups, filename);
 305        if (ret < 0) {
 306            error_setg(errp, "Could not parse blkdebug config file");
 307            ret = -EINVAL;
 308            goto fail;
 309        }
 310    }
 311
 312    qemu_config_parse_qdict(options, config_groups, &local_err);
 313    if (local_err) {
 314        error_propagate(errp, local_err);
 315        ret = -EINVAL;
 316        goto fail;
 317    }
 318
 319    d.s = s;
 320    d.action = ACTION_INJECT_ERROR;
 321    qemu_opts_foreach(&inject_error_opts, add_rule, &d, &local_err);
 322    if (local_err) {
 323        error_propagate(errp, local_err);
 324        ret = -EINVAL;
 325        goto fail;
 326    }
 327
 328    d.action = ACTION_SET_STATE;
 329    qemu_opts_foreach(&set_state_opts, add_rule, &d, &local_err);
 330    if (local_err) {
 331        error_propagate(errp, local_err);
 332        ret = -EINVAL;
 333        goto fail;
 334    }
 335
 336    ret = 0;
 337fail:
 338    qemu_opts_reset(&inject_error_opts);
 339    qemu_opts_reset(&set_state_opts);
 340    if (f) {
 341        fclose(f);
 342    }
 343    return ret;
 344}
 345
 346/* Valid blkdebug filenames look like blkdebug:path/to/config:path/to/image */
 347static void blkdebug_parse_filename(const char *filename, QDict *options,
 348                                    Error **errp)
 349{
 350    const char *c;
 351
 352    /* Parse the blkdebug: prefix */
 353    if (!strstart(filename, "blkdebug:", &filename)) {
 354        /* There was no prefix; therefore, all options have to be already
 355           present in the QDict (except for the filename) */
 356        qdict_put(options, "x-image", qstring_from_str(filename));
 357        return;
 358    }
 359
 360    /* Parse config file path */
 361    c = strchr(filename, ':');
 362    if (c == NULL) {
 363        error_setg(errp, "blkdebug requires both config file and image path");
 364        return;
 365    }
 366
 367    if (c != filename) {
 368        QString *config_path;
 369        config_path = qstring_from_substr(filename, 0, c - filename - 1);
 370        qdict_put(options, "config", config_path);
 371    }
 372
 373    /* TODO Allow multi-level nesting and set file.filename here */
 374    filename = c + 1;
 375    qdict_put(options, "x-image", qstring_from_str(filename));
 376}
 377
 378static QemuOptsList runtime_opts = {
 379    .name = "blkdebug",
 380    .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
 381    .desc = {
 382        {
 383            .name = "config",
 384            .type = QEMU_OPT_STRING,
 385            .help = "Path to the configuration file",
 386        },
 387        {
 388            .name = "x-image",
 389            .type = QEMU_OPT_STRING,
 390            .help = "[internal use only, will be removed]",
 391        },
 392        {
 393            .name = "align",
 394            .type = QEMU_OPT_SIZE,
 395            .help = "Required alignment in bytes",
 396        },
 397        { /* end of list */ }
 398    },
 399};
 400
 401static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
 402                         Error **errp)
 403{
 404    BDRVBlkdebugState *s = bs->opaque;
 405    QemuOpts *opts;
 406    Error *local_err = NULL;
 407    const char *config;
 408    uint64_t align;
 409    int ret;
 410
 411    opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
 412    qemu_opts_absorb_qdict(opts, options, &local_err);
 413    if (local_err) {
 414        error_propagate(errp, local_err);
 415        ret = -EINVAL;
 416        goto out;
 417    }
 418
 419    /* Read rules from config file or command line options */
 420    config = qemu_opt_get(opts, "config");
 421    ret = read_config(s, config, options, errp);
 422    if (ret) {
 423        goto out;
 424    }
 425
 426    /* Set initial state */
 427    s->state = 1;
 428
 429    /* Open the backing file */
 430    assert(bs->file == NULL);
 431    ret = bdrv_open_image(&bs->file, qemu_opt_get(opts, "x-image"), options, "image",
 432                          bs, &child_file, false, &local_err);
 433    if (ret < 0) {
 434        error_propagate(errp, local_err);
 435        goto out;
 436    }
 437
 438    /* Set request alignment */
 439    align = qemu_opt_get_size(opts, "align", bs->request_alignment);
 440    if (align > 0 && align < INT_MAX && !(align & (align - 1))) {
 441        bs->request_alignment = align;
 442    } else {
 443        error_setg(errp, "Invalid alignment");
 444        ret = -EINVAL;
 445        goto fail_unref;
 446    }
 447
 448    ret = 0;
 449    goto out;
 450
 451fail_unref:
 452    bdrv_unref(bs->file);
 453out:
 454    qemu_opts_del(opts);
 455    return ret;
 456}
 457
 458static void error_callback_bh(void *opaque)
 459{
 460    struct BlkdebugAIOCB *acb = opaque;
 461    qemu_bh_delete(acb->bh);
 462    acb->common.cb(acb->common.opaque, acb->ret);
 463    qemu_aio_unref(acb);
 464}
 465
 466static BlockAIOCB *inject_error(BlockDriverState *bs,
 467    BlockCompletionFunc *cb, void *opaque, BlkdebugRule *rule)
 468{
 469    BDRVBlkdebugState *s = bs->opaque;
 470    int error = rule->options.inject.error;
 471    struct BlkdebugAIOCB *acb;
 472    QEMUBH *bh;
 473    bool immediately = rule->options.inject.immediately;
 474
 475    if (rule->options.inject.once) {
 476        QSIMPLEQ_REMOVE(&s->active_rules, rule, BlkdebugRule, active_next);
 477        remove_rule(rule);
 478    }
 479
 480    if (immediately) {
 481        return NULL;
 482    }
 483
 484    acb = qemu_aio_get(&blkdebug_aiocb_info, bs, cb, opaque);
 485    acb->ret = -error;
 486
 487    bh = aio_bh_new(bdrv_get_aio_context(bs), error_callback_bh, acb);
 488    acb->bh = bh;
 489    qemu_bh_schedule(bh);
 490
 491    return &acb->common;
 492}
 493
 494static BlockAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
 495    int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
 496    BlockCompletionFunc *cb, void *opaque)
 497{
 498    BDRVBlkdebugState *s = bs->opaque;
 499    BlkdebugRule *rule = NULL;
 500
 501    QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
 502        if (rule->options.inject.sector == -1 ||
 503            (rule->options.inject.sector >= sector_num &&
 504             rule->options.inject.sector < sector_num + nb_sectors)) {
 505            break;
 506        }
 507    }
 508
 509    if (rule && rule->options.inject.error) {
 510        return inject_error(bs, cb, opaque, rule);
 511    }
 512
 513    return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
 514}
 515
 516static BlockAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
 517    int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
 518    BlockCompletionFunc *cb, void *opaque)
 519{
 520    BDRVBlkdebugState *s = bs->opaque;
 521    BlkdebugRule *rule = NULL;
 522
 523    QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
 524        if (rule->options.inject.sector == -1 ||
 525            (rule->options.inject.sector >= sector_num &&
 526             rule->options.inject.sector < sector_num + nb_sectors)) {
 527            break;
 528        }
 529    }
 530
 531    if (rule && rule->options.inject.error) {
 532        return inject_error(bs, cb, opaque, rule);
 533    }
 534
 535    return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
 536}
 537
 538static BlockAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
 539    BlockCompletionFunc *cb, void *opaque)
 540{
 541    BDRVBlkdebugState *s = bs->opaque;
 542    BlkdebugRule *rule = NULL;
 543
 544    QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
 545        if (rule->options.inject.sector == -1) {
 546            break;
 547        }
 548    }
 549
 550    if (rule && rule->options.inject.error) {
 551        return inject_error(bs, cb, opaque, rule);
 552    }
 553
 554    return bdrv_aio_flush(bs->file, cb, opaque);
 555}
 556
 557
 558static void blkdebug_close(BlockDriverState *bs)
 559{
 560    BDRVBlkdebugState *s = bs->opaque;
 561    BlkdebugRule *rule, *next;
 562    int i;
 563
 564    for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
 565        QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
 566            remove_rule(rule);
 567        }
 568    }
 569}
 570
 571static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule)
 572{
 573    BDRVBlkdebugState *s = bs->opaque;
 574    BlkdebugSuspendedReq r;
 575
 576    r = (BlkdebugSuspendedReq) {
 577        .co         = qemu_coroutine_self(),
 578        .tag        = g_strdup(rule->options.suspend.tag),
 579    };
 580
 581    remove_rule(rule);
 582    QLIST_INSERT_HEAD(&s->suspended_reqs, &r, next);
 583
 584    printf("blkdebug: Suspended request '%s'\n", r.tag);
 585    qemu_coroutine_yield();
 586    printf("blkdebug: Resuming request '%s'\n", r.tag);
 587
 588    QLIST_REMOVE(&r, next);
 589    g_free(r.tag);
 590}
 591
 592static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
 593    bool injected)
 594{
 595    BDRVBlkdebugState *s = bs->opaque;
 596
 597    /* Only process rules for the current state */
 598    if (rule->state && rule->state != s->state) {
 599        return injected;
 600    }
 601
 602    /* Take the action */
 603    switch (rule->action) {
 604    case ACTION_INJECT_ERROR:
 605        if (!injected) {
 606            QSIMPLEQ_INIT(&s->active_rules);
 607            injected = true;
 608        }
 609        QSIMPLEQ_INSERT_HEAD(&s->active_rules, rule, active_next);
 610        break;
 611
 612    case ACTION_SET_STATE:
 613        s->new_state = rule->options.set_state.new_state;
 614        break;
 615
 616    case ACTION_SUSPEND:
 617        suspend_request(bs, rule);
 618        break;
 619    }
 620    return injected;
 621}
 622
 623static void blkdebug_debug_event(BlockDriverState *bs, BlkDebugEvent event)
 624{
 625    BDRVBlkdebugState *s = bs->opaque;
 626    struct BlkdebugRule *rule, *next;
 627    bool injected;
 628
 629    assert((int)event >= 0 && event < BLKDBG_EVENT_MAX);
 630
 631    injected = false;
 632    s->new_state = s->state;
 633    QLIST_FOREACH_SAFE(rule, &s->rules[event], next, next) {
 634        injected = process_rule(bs, rule, injected);
 635    }
 636    s->state = s->new_state;
 637}
 638
 639static int blkdebug_debug_breakpoint(BlockDriverState *bs, const char *event,
 640                                     const char *tag)
 641{
 642    BDRVBlkdebugState *s = bs->opaque;
 643    struct BlkdebugRule *rule;
 644    BlkDebugEvent blkdebug_event;
 645
 646    if (get_event_by_name(event, &blkdebug_event) < 0) {
 647        return -ENOENT;
 648    }
 649
 650
 651    rule = g_malloc(sizeof(*rule));
 652    *rule = (struct BlkdebugRule) {
 653        .event  = blkdebug_event,
 654        .action = ACTION_SUSPEND,
 655        .state  = 0,
 656        .options.suspend.tag = g_strdup(tag),
 657    };
 658
 659    QLIST_INSERT_HEAD(&s->rules[blkdebug_event], rule, next);
 660
 661    return 0;
 662}
 663
 664static int blkdebug_debug_resume(BlockDriverState *bs, const char *tag)
 665{
 666    BDRVBlkdebugState *s = bs->opaque;
 667    BlkdebugSuspendedReq *r, *next;
 668
 669    QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, next) {
 670        if (!strcmp(r->tag, tag)) {
 671            qemu_coroutine_enter(r->co, NULL);
 672            return 0;
 673        }
 674    }
 675    return -ENOENT;
 676}
 677
 678static int blkdebug_debug_remove_breakpoint(BlockDriverState *bs,
 679                                            const char *tag)
 680{
 681    BDRVBlkdebugState *s = bs->opaque;
 682    BlkdebugSuspendedReq *r, *r_next;
 683    BlkdebugRule *rule, *next;
 684    int i, ret = -ENOENT;
 685
 686    for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
 687        QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
 688            if (rule->action == ACTION_SUSPEND &&
 689                !strcmp(rule->options.suspend.tag, tag)) {
 690                remove_rule(rule);
 691                ret = 0;
 692            }
 693        }
 694    }
 695    QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, r_next) {
 696        if (!strcmp(r->tag, tag)) {
 697            qemu_coroutine_enter(r->co, NULL);
 698            ret = 0;
 699        }
 700    }
 701    return ret;
 702}
 703
 704static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag)
 705{
 706    BDRVBlkdebugState *s = bs->opaque;
 707    BlkdebugSuspendedReq *r;
 708
 709    QLIST_FOREACH(r, &s->suspended_reqs, next) {
 710        if (!strcmp(r->tag, tag)) {
 711            return true;
 712        }
 713    }
 714    return false;
 715}
 716
 717static int64_t blkdebug_getlength(BlockDriverState *bs)
 718{
 719    return bdrv_getlength(bs->file);
 720}
 721
 722static int blkdebug_truncate(BlockDriverState *bs, int64_t offset)
 723{
 724    return bdrv_truncate(bs->file, offset);
 725}
 726
 727static void blkdebug_refresh_filename(BlockDriverState *bs)
 728{
 729    QDict *opts;
 730    const QDictEntry *e;
 731    bool force_json = false;
 732
 733    for (e = qdict_first(bs->options); e; e = qdict_next(bs->options, e)) {
 734        if (strcmp(qdict_entry_key(e), "config") &&
 735            strcmp(qdict_entry_key(e), "x-image") &&
 736            strcmp(qdict_entry_key(e), "image") &&
 737            strncmp(qdict_entry_key(e), "image.", strlen("image.")))
 738        {
 739            force_json = true;
 740            break;
 741        }
 742    }
 743
 744    if (force_json && !bs->file->full_open_options) {
 745        /* The config file cannot be recreated, so creating a plain filename
 746         * is impossible */
 747        return;
 748    }
 749
 750    if (!force_json && bs->file->exact_filename[0]) {
 751        snprintf(bs->exact_filename, sizeof(bs->exact_filename),
 752                 "blkdebug:%s:%s",
 753                 qdict_get_try_str(bs->options, "config") ?: "",
 754                 bs->file->exact_filename);
 755    }
 756
 757    opts = qdict_new();
 758    qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("blkdebug")));
 759
 760    QINCREF(bs->file->full_open_options);
 761    qdict_put_obj(opts, "image", QOBJECT(bs->file->full_open_options));
 762
 763    for (e = qdict_first(bs->options); e; e = qdict_next(bs->options, e)) {
 764        if (strcmp(qdict_entry_key(e), "x-image") &&
 765            strcmp(qdict_entry_key(e), "image") &&
 766            strncmp(qdict_entry_key(e), "image.", strlen("image.")))
 767        {
 768            qobject_incref(qdict_entry_value(e));
 769            qdict_put_obj(opts, qdict_entry_key(e), qdict_entry_value(e));
 770        }
 771    }
 772
 773    bs->full_open_options = opts;
 774}
 775
 776static BlockDriver bdrv_blkdebug = {
 777    .format_name            = "blkdebug",
 778    .protocol_name          = "blkdebug",
 779    .instance_size          = sizeof(BDRVBlkdebugState),
 780
 781    .bdrv_parse_filename    = blkdebug_parse_filename,
 782    .bdrv_file_open         = blkdebug_open,
 783    .bdrv_close             = blkdebug_close,
 784    .bdrv_getlength         = blkdebug_getlength,
 785    .bdrv_truncate          = blkdebug_truncate,
 786    .bdrv_refresh_filename  = blkdebug_refresh_filename,
 787
 788    .bdrv_aio_readv         = blkdebug_aio_readv,
 789    .bdrv_aio_writev        = blkdebug_aio_writev,
 790    .bdrv_aio_flush         = blkdebug_aio_flush,
 791
 792    .bdrv_debug_event           = blkdebug_debug_event,
 793    .bdrv_debug_breakpoint      = blkdebug_debug_breakpoint,
 794    .bdrv_debug_remove_breakpoint
 795                                = blkdebug_debug_remove_breakpoint,
 796    .bdrv_debug_resume          = blkdebug_debug_resume,
 797    .bdrv_debug_is_suspended    = blkdebug_debug_is_suspended,
 798};
 799
 800static void bdrv_blkdebug_init(void)
 801{
 802    bdrv_register(&bdrv_blkdebug);
 803}
 804
 805block_init(bdrv_blkdebug_init);
 806