blkdebug.c 25.7 KB
Newer Older
K
Kevin Wolf 已提交
1 2 3
/*
 * Block protocol for I/O error injection
 *
4
 * Copyright (C) 2016-2017 Red Hat, Inc.
K
Kevin Wolf 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 * Copyright (c) 2010 Kevin Wolf <kwolf@redhat.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

P
Peter Maydell 已提交
26
#include "qemu/osdep.h"
27
#include "qapi/error.h"
28
#include "qemu/cutils.h"
29
#include "qemu/config-file.h"
30
#include "block/block_int.h"
31
#include "qemu/module.h"
32 33 34 35
#include "qapi/qmp/qbool.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qint.h"
#include "qapi/qmp/qstring.h"
36
#include "sysemu/qtest.h"
K
Kevin Wolf 已提交
37 38

typedef struct BDRVBlkdebugState {
39
    int state;
40
    int new_state;
E
Eric Blake 已提交
41
    uint64_t align;
42 43 44 45 46
    uint64_t max_transfer;
    uint64_t opt_write_zero;
    uint64_t max_write_zero;
    uint64_t opt_discard;
    uint64_t max_discard;
47

48 49 50
    /* For blkdebug_refresh_filename() */
    char *config_file;

51
    QLIST_HEAD(, BlkdebugRule) rules[BLKDBG__MAX];
52
    QSIMPLEQ_HEAD(, BlkdebugRule) active_rules;
53
    QLIST_HEAD(, BlkdebugSuspendedReq) suspended_reqs;
K
Kevin Wolf 已提交
54 55
} BDRVBlkdebugState;

K
Kevin Wolf 已提交
56
typedef struct BlkdebugAIOCB {
57
    BlockAIOCB common;
K
Kevin Wolf 已提交
58 59 60
    int ret;
} BlkdebugAIOCB;

61 62 63 64 65 66
typedef struct BlkdebugSuspendedReq {
    Coroutine *co;
    char *tag;
    QLIST_ENTRY(BlkdebugSuspendedReq) next;
} BlkdebugSuspendedReq;

K
Kevin Wolf 已提交
67 68 69
enum {
    ACTION_INJECT_ERROR,
    ACTION_SET_STATE,
70
    ACTION_SUSPEND,
K
Kevin Wolf 已提交
71 72 73
};

typedef struct BlkdebugRule {
74
    BlkdebugEvent event;
K
Kevin Wolf 已提交
75 76 77 78 79 80 81
    int action;
    int state;
    union {
        struct {
            int error;
            int immediately;
            int once;
82
            int64_t offset;
K
Kevin Wolf 已提交
83 84 85 86
        } inject;
        struct {
            int new_state;
        } set_state;
87 88 89
        struct {
            char *tag;
        } suspend;
K
Kevin Wolf 已提交
90 91
    } options;
    QLIST_ENTRY(BlkdebugRule) next;
92
    QSIMPLEQ_ENTRY(BlkdebugRule) active_next;
K
Kevin Wolf 已提交
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
} BlkdebugRule;

static QemuOptsList inject_error_opts = {
    .name = "inject-error",
    .head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head),
    .desc = {
        {
            .name = "event",
            .type = QEMU_OPT_STRING,
        },
        {
            .name = "state",
            .type = QEMU_OPT_NUMBER,
        },
        {
            .name = "errno",
            .type = QEMU_OPT_NUMBER,
        },
111 112 113 114
        {
            .name = "sector",
            .type = QEMU_OPT_NUMBER,
        },
K
Kevin Wolf 已提交
115 116 117 118 119 120 121 122 123 124 125 126 127 128
        {
            .name = "once",
            .type = QEMU_OPT_BOOL,
        },
        {
            .name = "immediately",
            .type = QEMU_OPT_BOOL,
        },
        { /* end of list */ }
    },
};

static QemuOptsList set_state_opts = {
    .name = "set-state",
129
    .head = QTAILQ_HEAD_INITIALIZER(set_state_opts.head),
K
Kevin Wolf 已提交
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
    .desc = {
        {
            .name = "event",
            .type = QEMU_OPT_STRING,
        },
        {
            .name = "state",
            .type = QEMU_OPT_NUMBER,
        },
        {
            .name = "new_state",
            .type = QEMU_OPT_NUMBER,
        },
        { /* end of list */ }
    },
};

static QemuOptsList *config_groups[] = {
    &inject_error_opts,
    &set_state_opts,
    NULL
};

153
static int get_event_by_name(const char *name, BlkdebugEvent *event)
K
Kevin Wolf 已提交
154 155 156
{
    int i;

157
    for (i = 0; i < BLKDBG__MAX; i++) {
158
        if (!strcmp(BlkdebugEvent_lookup[i], name)) {
K
Kevin Wolf 已提交
159 160 161 162 163 164 165 166 167 168 169 170 171
            *event = i;
            return 0;
        }
    }

    return -1;
}

struct add_rule_data {
    BDRVBlkdebugState *s;
    int action;
};

172
static int add_rule(void *opaque, QemuOpts *opts, Error **errp)
K
Kevin Wolf 已提交
173 174 175 176
{
    struct add_rule_data *d = opaque;
    BDRVBlkdebugState *s = d->s;
    const char* event_name;
177
    BlkdebugEvent event;
K
Kevin Wolf 已提交
178
    struct BlkdebugRule *rule;
179
    int64_t sector;
K
Kevin Wolf 已提交
180 181 182

    /* Find the right event for the rule */
    event_name = qemu_opt_get(opts, "event");
183
    if (!event_name) {
184
        error_setg(errp, "Missing event name for rule");
185 186
        return -1;
    } else if (get_event_by_name(event_name, &event) < 0) {
187
        error_setg(errp, "Invalid event name \"%s\"", event_name);
K
Kevin Wolf 已提交
188 189 190 191
        return -1;
    }

    /* Set attributes common for all actions */
192
    rule = g_malloc0(sizeof(*rule));
K
Kevin Wolf 已提交
193 194 195 196 197 198 199 200 201 202 203 204 205
    *rule = (struct BlkdebugRule) {
        .event  = event,
        .action = d->action,
        .state  = qemu_opt_get_number(opts, "state", 0),
    };

    /* Parse action-specific options */
    switch (d->action) {
    case ACTION_INJECT_ERROR:
        rule->options.inject.error = qemu_opt_get_number(opts, "errno", EIO);
        rule->options.inject.once  = qemu_opt_get_bool(opts, "once", 0);
        rule->options.inject.immediately =
            qemu_opt_get_bool(opts, "immediately", 0);
206 207 208
        sector = qemu_opt_get_number(opts, "sector", -1);
        rule->options.inject.offset =
            sector == -1 ? -1 : sector * BDRV_SECTOR_SIZE;
K
Kevin Wolf 已提交
209 210 211 212 213 214
        break;

    case ACTION_SET_STATE:
        rule->options.set_state.new_state =
            qemu_opt_get_number(opts, "new_state", 0);
        break;
215 216 217 218 219

    case ACTION_SUSPEND:
        rule->options.suspend.tag =
            g_strdup(qemu_opt_get(opts, "tag"));
        break;
K
Kevin Wolf 已提交
220 221 222 223 224 225 226 227
    };

    /* Add the rule */
    QLIST_INSERT_HEAD(&s->rules[event], rule, next);

    return 0;
}

K
Kevin Wolf 已提交
228 229 230 231 232 233
static void remove_rule(BlkdebugRule *rule)
{
    switch (rule->action) {
    case ACTION_INJECT_ERROR:
    case ACTION_SET_STATE:
        break;
234 235 236
    case ACTION_SUSPEND:
        g_free(rule->options.suspend.tag);
        break;
K
Kevin Wolf 已提交
237 238 239 240 241 242
    }

    QLIST_REMOVE(rule, next);
    g_free(rule);
}

243 244
static int read_config(BDRVBlkdebugState *s, const char *filename,
                       QDict *options, Error **errp)
K
Kevin Wolf 已提交
245
{
M
Max Reitz 已提交
246
    FILE *f = NULL;
K
Kevin Wolf 已提交
247 248
    int ret;
    struct add_rule_data d;
249
    Error *local_err = NULL;
K
Kevin Wolf 已提交
250

M
Max Reitz 已提交
251 252 253 254 255 256
    if (filename) {
        f = fopen(filename, "r");
        if (f == NULL) {
            error_setg_errno(errp, errno, "Could not read blkdebug config file");
            return -errno;
        }
K
Kevin Wolf 已提交
257

M
Max Reitz 已提交
258 259 260 261 262 263
        ret = qemu_config_parse(f, config_groups, filename);
        if (ret < 0) {
            error_setg(errp, "Could not parse blkdebug config file");
            ret = -EINVAL;
            goto fail;
        }
K
Kevin Wolf 已提交
264 265
    }

266
    qemu_config_parse_qdict(options, config_groups, &local_err);
267
    if (local_err) {
268 269 270 271 272
        error_propagate(errp, local_err);
        ret = -EINVAL;
        goto fail;
    }

K
Kevin Wolf 已提交
273 274
    d.s = s;
    d.action = ACTION_INJECT_ERROR;
275
    qemu_opts_foreach(&inject_error_opts, add_rule, &d, &local_err);
276 277 278 279 280
    if (local_err) {
        error_propagate(errp, local_err);
        ret = -EINVAL;
        goto fail;
    }
K
Kevin Wolf 已提交
281 282

    d.action = ACTION_SET_STATE;
283
    qemu_opts_foreach(&set_state_opts, add_rule, &d, &local_err);
284 285 286 287 288
    if (local_err) {
        error_propagate(errp, local_err);
        ret = -EINVAL;
        goto fail;
    }
K
Kevin Wolf 已提交
289 290 291

    ret = 0;
fail:
292 293
    qemu_opts_reset(&inject_error_opts);
    qemu_opts_reset(&set_state_opts);
M
Max Reitz 已提交
294 295 296
    if (f) {
        fclose(f);
    }
K
Kevin Wolf 已提交
297 298 299 300
    return ret;
}

/* Valid blkdebug filenames look like blkdebug:path/to/config:path/to/image */
301 302
static void blkdebug_parse_filename(const char *filename, QDict *options,
                                    Error **errp)
K
Kevin Wolf 已提交
303
{
304
    const char *c;
K
Kevin Wolf 已提交
305

K
Kevin Wolf 已提交
306
    /* Parse the blkdebug: prefix */
307
    if (!strstart(filename, "blkdebug:", &filename)) {
308 309
        /* There was no prefix; therefore, all options have to be already
           present in the QDict (except for the filename) */
310
        qdict_put_str(options, "x-image", filename);
311
        return;
K
Kevin Wolf 已提交
312 313
    }

314
    /* Parse config file path */
K
Kevin Wolf 已提交
315 316
    c = strchr(filename, ':');
    if (c == NULL) {
317 318
        error_setg(errp, "blkdebug requires both config file and image path");
        return;
K
Kevin Wolf 已提交
319 320
    }

321 322 323 324
    if (c != filename) {
        QString *config_path;
        config_path = qstring_from_substr(filename, 0, c - filename - 1);
        qdict_put(options, "config", config_path);
K
Kevin Wolf 已提交
325
    }
326 327

    /* TODO Allow multi-level nesting and set file.filename here */
K
Kevin Wolf 已提交
328
    filename = c + 1;
329
    qdict_put_str(options, "x-image", filename);
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
}

static QemuOptsList runtime_opts = {
    .name = "blkdebug",
    .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
    .desc = {
        {
            .name = "config",
            .type = QEMU_OPT_STRING,
            .help = "Path to the configuration file",
        },
        {
            .name = "x-image",
            .type = QEMU_OPT_STRING,
            .help = "[internal use only, will be removed]",
        },
346 347 348 349 350
        {
            .name = "align",
            .type = QEMU_OPT_SIZE,
            .help = "Required alignment in bytes",
        },
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
        {
            .name = "max-transfer",
            .type = QEMU_OPT_SIZE,
            .help = "Maximum transfer size in bytes",
        },
        {
            .name = "opt-write-zero",
            .type = QEMU_OPT_SIZE,
            .help = "Optimum write zero alignment in bytes",
        },
        {
            .name = "max-write-zero",
            .type = QEMU_OPT_SIZE,
            .help = "Maximum write zero size in bytes",
        },
        {
            .name = "opt-discard",
            .type = QEMU_OPT_SIZE,
            .help = "Optimum discard alignment in bytes",
        },
        {
            .name = "max-discard",
            .type = QEMU_OPT_SIZE,
            .help = "Maximum discard size in bytes",
        },
376 377 378 379
        { /* end of list */ }
    },
};

M
Max Reitz 已提交
380 381
static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
                         Error **errp)
382 383 384 385 386
{
    BDRVBlkdebugState *s = bs->opaque;
    QemuOpts *opts;
    Error *local_err = NULL;
    int ret;
387
    uint64_t align;
388

389
    opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
390
    qemu_opts_absorb_qdict(opts, options, &local_err);
391
    if (local_err) {
M
Max Reitz 已提交
392
        error_propagate(errp, local_err);
393
        ret = -EINVAL;
394
        goto out;
395 396
    }

397
    /* Read rules from config file or command line options */
398 399
    s->config_file = g_strdup(qemu_opt_get(opts, "config"));
    ret = read_config(s, s->config_file, options, errp);
M
Max Reitz 已提交
400
    if (ret) {
401
        goto out;
402
    }
K
Kevin Wolf 已提交
403

K
Kevin Wolf 已提交
404
    /* Set initial state */
405
    s->state = 1;
K
Kevin Wolf 已提交
406

407
    /* Open the image file */
K
Kevin Wolf 已提交
408 409 410 411
    bs->file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, "image",
                               bs, &child_file, false, &local_err);
    if (local_err) {
        ret = -EINVAL;
M
Max Reitz 已提交
412
        error_propagate(errp, local_err);
413
        goto out;
K
Kevin Wolf 已提交
414 415
    }

416 417 418 419
    bs->supported_write_flags = BDRV_REQ_FUA &
        bs->file->bs->supported_write_flags;
    bs->supported_zero_flags = (BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP) &
        bs->file->bs->supported_zero_flags;
E
Eric Blake 已提交
420
    ret = -EINVAL;
421

422
    /* Set alignment overrides */
E
Eric Blake 已提交
423 424 425 426
    s->align = qemu_opt_get_size(opts, "align", 0);
    if (s->align && (s->align >= INT_MAX || !is_power_of_2(s->align))) {
        error_setg(errp, "Cannot meet constraints with align %" PRIu64,
                   s->align);
427
        goto out;
428
    }
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476
    align = MAX(s->align, bs->file->bs->bl.request_alignment);

    s->max_transfer = qemu_opt_get_size(opts, "max-transfer", 0);
    if (s->max_transfer &&
        (s->max_transfer >= INT_MAX ||
         !QEMU_IS_ALIGNED(s->max_transfer, align))) {
        error_setg(errp, "Cannot meet constraints with max-transfer %" PRIu64,
                   s->max_transfer);
        goto out;
    }

    s->opt_write_zero = qemu_opt_get_size(opts, "opt-write-zero", 0);
    if (s->opt_write_zero &&
        (s->opt_write_zero >= INT_MAX ||
         !QEMU_IS_ALIGNED(s->opt_write_zero, align))) {
        error_setg(errp, "Cannot meet constraints with opt-write-zero %" PRIu64,
                   s->opt_write_zero);
        goto out;
    }

    s->max_write_zero = qemu_opt_get_size(opts, "max-write-zero", 0);
    if (s->max_write_zero &&
        (s->max_write_zero >= INT_MAX ||
         !QEMU_IS_ALIGNED(s->max_write_zero,
                          MAX(s->opt_write_zero, align)))) {
        error_setg(errp, "Cannot meet constraints with max-write-zero %" PRIu64,
                   s->max_write_zero);
        goto out;
    }

    s->opt_discard = qemu_opt_get_size(opts, "opt-discard", 0);
    if (s->opt_discard &&
        (s->opt_discard >= INT_MAX ||
         !QEMU_IS_ALIGNED(s->opt_discard, align))) {
        error_setg(errp, "Cannot meet constraints with opt-discard %" PRIu64,
                   s->opt_discard);
        goto out;
    }

    s->max_discard = qemu_opt_get_size(opts, "max-discard", 0);
    if (s->max_discard &&
        (s->max_discard >= INT_MAX ||
         !QEMU_IS_ALIGNED(s->max_discard,
                          MAX(s->opt_discard, align)))) {
        error_setg(errp, "Cannot meet constraints with max-discard %" PRIu64,
                   s->max_discard);
        goto out;
    }
477

478
    ret = 0;
479
out:
480 481 482
    if (ret < 0) {
        g_free(s->config_file);
    }
483 484
    qemu_opts_del(opts);
    return ret;
K
Kevin Wolf 已提交
485 486
}

E
Eric Blake 已提交
487
static int rule_check(BlockDriverState *bs, uint64_t offset, uint64_t bytes)
K
Kevin Wolf 已提交
488 489
{
    BDRVBlkdebugState *s = bs->opaque;
E
Eric Blake 已提交
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510
    BlkdebugRule *rule = NULL;
    int error;
    bool immediately;

    QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
        uint64_t inject_offset = rule->options.inject.offset;

        if (inject_offset == -1 ||
            (bytes && inject_offset >= offset &&
             inject_offset < offset + bytes))
        {
            break;
        }
    }

    if (!rule || !rule->options.inject.error) {
        return 0;
    }

    immediately = rule->options.inject.immediately;
    error = rule->options.inject.error;
K
Kevin Wolf 已提交
511

512
    if (rule->options.inject.once) {
J
John Snow 已提交
513 514
        QSIMPLEQ_REMOVE(&s->active_rules, rule, BlkdebugRule, active_next);
        remove_rule(rule);
K
Kevin Wolf 已提交
515 516
    }

517
    if (!immediately) {
518
        aio_co_schedule(qemu_get_current_aio_context(), qemu_coroutine_self());
519
        qemu_coroutine_yield();
K
Kevin Wolf 已提交
520 521
    }

522
    return -error;
K
Kevin Wolf 已提交
523 524
}

525 526 527
static int coroutine_fn
blkdebug_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
                   QEMUIOVector *qiov, int flags)
K
Kevin Wolf 已提交
528
{
E
Eric Blake 已提交
529
    int err;
530

531 532 533 534 535 536 537
    /* Sanity check block layer guarantees */
    assert(QEMU_IS_ALIGNED(offset, bs->bl.request_alignment));
    assert(QEMU_IS_ALIGNED(bytes, bs->bl.request_alignment));
    if (bs->bl.max_transfer) {
        assert(bytes <= bs->bl.max_transfer);
    }

E
Eric Blake 已提交
538 539 540
    err = rule_check(bs, offset, bytes);
    if (err) {
        return err;
K
Kevin Wolf 已提交
541 542
    }

543
    return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
K
Kevin Wolf 已提交
544 545
}

546 547 548
static int coroutine_fn
blkdebug_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
                    QEMUIOVector *qiov, int flags)
K
Kevin Wolf 已提交
549
{
E
Eric Blake 已提交
550
    int err;
551

552 553 554 555 556 557 558
    /* Sanity check block layer guarantees */
    assert(QEMU_IS_ALIGNED(offset, bs->bl.request_alignment));
    assert(QEMU_IS_ALIGNED(bytes, bs->bl.request_alignment));
    if (bs->bl.max_transfer) {
        assert(bytes <= bs->bl.max_transfer);
    }

E
Eric Blake 已提交
559 560 561
    err = rule_check(bs, offset, bytes);
    if (err) {
        return err;
K
Kevin Wolf 已提交
562 563
    }

564
    return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
K
Kevin Wolf 已提交
565 566
}

567
static int blkdebug_co_flush(BlockDriverState *bs)
568
{
E
Eric Blake 已提交
569
    int err = rule_check(bs, 0, 0);
570

E
Eric Blake 已提交
571 572
    if (err) {
        return err;
573 574
    }

575
    return bdrv_co_flush(bs->file->bs);
576 577
}

578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643
static int coroutine_fn blkdebug_co_pwrite_zeroes(BlockDriverState *bs,
                                                  int64_t offset, int count,
                                                  BdrvRequestFlags flags)
{
    uint32_t align = MAX(bs->bl.request_alignment,
                         bs->bl.pwrite_zeroes_alignment);
    int err;

    /* Only pass through requests that are larger than requested
     * preferred alignment (so that we test the fallback to writes on
     * unaligned portions), and check that the block layer never hands
     * us anything unaligned that crosses an alignment boundary.  */
    if (count < align) {
        assert(QEMU_IS_ALIGNED(offset, align) ||
               QEMU_IS_ALIGNED(offset + count, align) ||
               DIV_ROUND_UP(offset, align) ==
               DIV_ROUND_UP(offset + count, align));
        return -ENOTSUP;
    }
    assert(QEMU_IS_ALIGNED(offset, align));
    assert(QEMU_IS_ALIGNED(count, align));
    if (bs->bl.max_pwrite_zeroes) {
        assert(count <= bs->bl.max_pwrite_zeroes);
    }

    err = rule_check(bs, offset, count);
    if (err) {
        return err;
    }

    return bdrv_co_pwrite_zeroes(bs->file, offset, count, flags);
}

static int coroutine_fn blkdebug_co_pdiscard(BlockDriverState *bs,
                                             int64_t offset, int count)
{
    uint32_t align = bs->bl.pdiscard_alignment;
    int err;

    /* Only pass through requests that are larger than requested
     * minimum alignment, and ensure that unaligned requests do not
     * cross optimum discard boundaries. */
    if (count < bs->bl.request_alignment) {
        assert(QEMU_IS_ALIGNED(offset, align) ||
               QEMU_IS_ALIGNED(offset + count, align) ||
               DIV_ROUND_UP(offset, align) ==
               DIV_ROUND_UP(offset + count, align));
        return -ENOTSUP;
    }
    assert(QEMU_IS_ALIGNED(offset, bs->bl.request_alignment));
    assert(QEMU_IS_ALIGNED(count, bs->bl.request_alignment));
    if (align && count >= align) {
        assert(QEMU_IS_ALIGNED(offset, align));
        assert(QEMU_IS_ALIGNED(count, align));
    }
    if (bs->bl.max_pdiscard) {
        assert(count <= bs->bl.max_pdiscard);
    }

    err = rule_check(bs, offset, count);
    if (err) {
        return err;
    }

    return bdrv_co_pdiscard(bs->file->bs, offset, count);
}
644

K
Kevin Wolf 已提交
645 646 647
static void blkdebug_close(BlockDriverState *bs)
{
    BDRVBlkdebugState *s = bs->opaque;
K
Kevin Wolf 已提交
648 649 650
    BlkdebugRule *rule, *next;
    int i;

651
    for (i = 0; i < BLKDBG__MAX; i++) {
K
Kevin Wolf 已提交
652
        QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
K
Kevin Wolf 已提交
653
            remove_rule(rule);
K
Kevin Wolf 已提交
654 655
        }
    }
656 657

    g_free(s->config_file);
K
Kevin Wolf 已提交
658 659
}

660 661 662 663 664 665 666 667 668 669 670 671 672
static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule)
{
    BDRVBlkdebugState *s = bs->opaque;
    BlkdebugSuspendedReq r;

    r = (BlkdebugSuspendedReq) {
        .co         = qemu_coroutine_self(),
        .tag        = g_strdup(rule->options.suspend.tag),
    };

    remove_rule(rule);
    QLIST_INSERT_HEAD(&s->suspended_reqs, &r, next);

673 674 675
    if (!qtest_enabled()) {
        printf("blkdebug: Suspended request '%s'\n", r.tag);
    }
676
    qemu_coroutine_yield();
677 678 679
    if (!qtest_enabled()) {
        printf("blkdebug: Resuming request '%s'\n", r.tag);
    }
680 681 682 683 684

    QLIST_REMOVE(&r, next);
    g_free(r.tag);
}

685
static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
686
    bool injected)
K
Kevin Wolf 已提交
687 688 689 690
{
    BDRVBlkdebugState *s = bs->opaque;

    /* Only process rules for the current state */
691
    if (rule->state && rule->state != s->state) {
692
        return injected;
K
Kevin Wolf 已提交
693 694 695 696 697
    }

    /* Take the action */
    switch (rule->action) {
    case ACTION_INJECT_ERROR:
698 699 700 701 702
        if (!injected) {
            QSIMPLEQ_INIT(&s->active_rules);
            injected = true;
        }
        QSIMPLEQ_INSERT_HEAD(&s->active_rules, rule, active_next);
K
Kevin Wolf 已提交
703 704 705
        break;

    case ACTION_SET_STATE:
706
        s->new_state = rule->options.set_state.new_state;
K
Kevin Wolf 已提交
707
        break;
708 709 710 711

    case ACTION_SUSPEND:
        suspend_request(bs, rule);
        break;
K
Kevin Wolf 已提交
712
    }
713
    return injected;
K
Kevin Wolf 已提交
714 715
}

716
static void blkdebug_debug_event(BlockDriverState *bs, BlkdebugEvent event)
K
Kevin Wolf 已提交
717 718
{
    BDRVBlkdebugState *s = bs->opaque;
719
    struct BlkdebugRule *rule, *next;
720
    bool injected;
K
Kevin Wolf 已提交
721

722
    assert((int)event >= 0 && event < BLKDBG__MAX);
K
Kevin Wolf 已提交
723

724
    injected = false;
725
    s->new_state = s->state;
726
    QLIST_FOREACH_SAFE(rule, &s->rules[event], next, next) {
727
        injected = process_rule(bs, rule, injected);
K
Kevin Wolf 已提交
728
    }
729
    s->state = s->new_state;
K
Kevin Wolf 已提交
730 731
}

732 733 734 735 736
static int blkdebug_debug_breakpoint(BlockDriverState *bs, const char *event,
                                     const char *tag)
{
    BDRVBlkdebugState *s = bs->opaque;
    struct BlkdebugRule *rule;
737
    BlkdebugEvent blkdebug_event;
738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759

    if (get_event_by_name(event, &blkdebug_event) < 0) {
        return -ENOENT;
    }


    rule = g_malloc(sizeof(*rule));
    *rule = (struct BlkdebugRule) {
        .event  = blkdebug_event,
        .action = ACTION_SUSPEND,
        .state  = 0,
        .options.suspend.tag = g_strdup(tag),
    };

    QLIST_INSERT_HEAD(&s->rules[blkdebug_event], rule, next);

    return 0;
}

static int blkdebug_debug_resume(BlockDriverState *bs, const char *tag)
{
    BDRVBlkdebugState *s = bs->opaque;
760
    BlkdebugSuspendedReq *r, *next;
761

762
    QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, next) {
763
        if (!strcmp(r->tag, tag)) {
764
            qemu_coroutine_enter(r->co);
765 766 767 768 769 770
            return 0;
        }
    }
    return -ENOENT;
}

F
Fam Zheng 已提交
771 772 773 774
static int blkdebug_debug_remove_breakpoint(BlockDriverState *bs,
                                            const char *tag)
{
    BDRVBlkdebugState *s = bs->opaque;
775
    BlkdebugSuspendedReq *r, *r_next;
F
Fam Zheng 已提交
776 777 778
    BlkdebugRule *rule, *next;
    int i, ret = -ENOENT;

779
    for (i = 0; i < BLKDBG__MAX; i++) {
F
Fam Zheng 已提交
780 781 782 783 784 785 786 787
        QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
            if (rule->action == ACTION_SUSPEND &&
                !strcmp(rule->options.suspend.tag, tag)) {
                remove_rule(rule);
                ret = 0;
            }
        }
    }
788
    QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, r_next) {
F
Fam Zheng 已提交
789
        if (!strcmp(r->tag, tag)) {
790
            qemu_coroutine_enter(r->co);
F
Fam Zheng 已提交
791 792 793 794 795
            ret = 0;
        }
    }
    return ret;
}
796 797 798 799 800 801 802 803 804 805 806 807 808 809

static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag)
{
    BDRVBlkdebugState *s = bs->opaque;
    BlkdebugSuspendedReq *r;

    QLIST_FOREACH(r, &s->suspended_reqs, next) {
        if (!strcmp(r->tag, tag)) {
            return true;
        }
    }
    return false;
}

810 811
static int64_t blkdebug_getlength(BlockDriverState *bs)
{
K
Kevin Wolf 已提交
812
    return bdrv_getlength(bs->file->bs);
813 814
}

K
Kevin Wolf 已提交
815 816
static int blkdebug_truncate(BlockDriverState *bs, int64_t offset)
{
817
    return bdrv_truncate(bs->file, offset, NULL);
K
Kevin Wolf 已提交
818 819
}

820
static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options)
821
{
822
    BDRVBlkdebugState *s = bs->opaque;
823
    QDict *opts;
824 825 826
    const QDictEntry *e;
    bool force_json = false;

827
    for (e = qdict_first(options); e; e = qdict_next(options, e)) {
828
        if (strcmp(qdict_entry_key(e), "config") &&
829
            strcmp(qdict_entry_key(e), "x-image"))
830 831 832 833 834
        {
            force_json = true;
            break;
        }
    }
835

K
Kevin Wolf 已提交
836
    if (force_json && !bs->file->bs->full_open_options) {
837 838 839 840 841
        /* The config file cannot be recreated, so creating a plain filename
         * is impossible */
        return;
    }

K
Kevin Wolf 已提交
842
    if (!force_json && bs->file->bs->exact_filename[0]) {
843 844 845 846 847 848 849
        int ret = snprintf(bs->exact_filename, sizeof(bs->exact_filename),
                           "blkdebug:%s:%s", s->config_file ?: "",
                           bs->file->bs->exact_filename);
        if (ret >= sizeof(bs->exact_filename)) {
            /* An overflow makes the filename unusable, so do not report any */
            bs->exact_filename[0] = 0;
        }
850 851
    }

852
    opts = qdict_new();
853
    qdict_put_str(opts, "driver", "blkdebug");
854

K
Kevin Wolf 已提交
855
    QINCREF(bs->file->bs->full_open_options);
E
Eric Blake 已提交
856
    qdict_put(opts, "image", bs->file->bs->full_open_options);
857

858 859
    for (e = qdict_first(options); e; e = qdict_next(options, e)) {
        if (strcmp(qdict_entry_key(e), "x-image")) {
860 861
            qobject_incref(qdict_entry_value(e));
            qdict_put_obj(opts, qdict_entry_key(e), qdict_entry_value(e));
862 863 864 865 866 867
        }
    }

    bs->full_open_options = opts;
}

868 869 870 871 872
static void blkdebug_refresh_limits(BlockDriverState *bs, Error **errp)
{
    BDRVBlkdebugState *s = bs->opaque;

    if (s->align) {
873
        bs->bl.request_alignment = s->align;
874
    }
875 876 877 878 879 880 881 882 883 884 885 886 887 888 889
    if (s->max_transfer) {
        bs->bl.max_transfer = s->max_transfer;
    }
    if (s->opt_write_zero) {
        bs->bl.pwrite_zeroes_alignment = s->opt_write_zero;
    }
    if (s->max_write_zero) {
        bs->bl.max_pwrite_zeroes = s->max_write_zero;
    }
    if (s->opt_discard) {
        bs->bl.pdiscard_alignment = s->opt_discard;
    }
    if (s->max_discard) {
        bs->bl.max_pdiscard = s->max_discard;
    }
890 891
}

K
Kevin Wolf 已提交
892 893 894 895 896 897
static int blkdebug_reopen_prepare(BDRVReopenState *reopen_state,
                                   BlockReopenQueue *queue, Error **errp)
{
    return 0;
}

K
Kevin Wolf 已提交
898
static BlockDriver bdrv_blkdebug = {
899 900 901
    .format_name            = "blkdebug",
    .protocol_name          = "blkdebug",
    .instance_size          = sizeof(BDRVBlkdebugState),
K
Kevin Wolf 已提交
902

903 904 905
    .bdrv_parse_filename    = blkdebug_parse_filename,
    .bdrv_file_open         = blkdebug_open,
    .bdrv_close             = blkdebug_close,
K
Kevin Wolf 已提交
906
    .bdrv_reopen_prepare    = blkdebug_reopen_prepare,
907 908
    .bdrv_child_perm        = bdrv_filter_default_perms,

909
    .bdrv_getlength         = blkdebug_getlength,
K
Kevin Wolf 已提交
910
    .bdrv_truncate          = blkdebug_truncate,
911
    .bdrv_refresh_filename  = blkdebug_refresh_filename,
912
    .bdrv_refresh_limits    = blkdebug_refresh_limits,
K
Kevin Wolf 已提交
913

914 915 916
    .bdrv_co_preadv         = blkdebug_co_preadv,
    .bdrv_co_pwritev        = blkdebug_co_pwritev,
    .bdrv_co_flush_to_disk  = blkdebug_co_flush,
917 918
    .bdrv_co_pwrite_zeroes  = blkdebug_co_pwrite_zeroes,
    .bdrv_co_pdiscard       = blkdebug_co_pdiscard,
K
Kevin Wolf 已提交
919

920 921
    .bdrv_debug_event           = blkdebug_debug_event,
    .bdrv_debug_breakpoint      = blkdebug_debug_breakpoint,
F
Fam Zheng 已提交
922 923
    .bdrv_debug_remove_breakpoint
                                = blkdebug_debug_remove_breakpoint,
924 925
    .bdrv_debug_resume          = blkdebug_debug_resume,
    .bdrv_debug_is_suspended    = blkdebug_debug_is_suspended,
K
Kevin Wolf 已提交
926 927 928 929 930 931 932 933
};

static void bdrv_blkdebug_init(void)
{
    bdrv_register(&bdrv_blkdebug);
}

block_init(bdrv_blkdebug_init);