Commit f3d0bec9 authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/maxreitz/tags/pull-block-2019-06-14' into staging



Block patches:
- Allow blockdev-backup from nodes that are not in qemu's main AIO
  context to newly added nodes
- Add salvaging mode to qemu-img convert
- Minor fixes to tests, documentation, and for less Valgrind annoyance

# gpg: Signature made Fri 14 Jun 2019 14:38:11 BST
# gpg:                using RSA key 91BEB60A30DB3E8857D11829F407DB0061D5CF40
# gpg:                issuer "mreitz@redhat.com"
# gpg: Good signature from "Max Reitz <mreitz@redhat.com>" [full]
# Primary key fingerprint: 91BE B60A 30DB 3E88 57D1  1829 F407 DB00 61D5 CF40

* remotes/maxreitz/tags/pull-block-2019-06-14:
  iotests: Test qemu-img convert -C --salvage
  iotests: Test qemu-img convert --salvage
  blkdebug: Inject errors on .bdrv_co_block_status()
  blkdebug: Add "none" event
  blkdebug: Add @iotype error option
  qemu-img: Add salvaging mode to convert
  qemu-img: Move quiet into ImgConvertState
  blockdev: Overlays are not snapshots
  qapi/block-core: Overlays are not snapshots
  qemu-img: Fix options leakage in img_rebase()
  iotests: restrict 254 to support only qcow2
  hw/block/fdc: floppy command FIFO memory initialization
  iotests: Fix intermittent failure in 219
  iotests: Filter 175's allocation information
  event_match: always match on None value
  iotests: add iotest 256 for testing blockdev-backup across iothread contexts
  iotests.py: rewrite run_job to be pickier
  QEMUMachine: add events_wait method
  iotests.py: do not use infinite waits
  blockdev-backup: don't check aio_context too early

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents 5ec2eca8 21c1ce59
Loading
Loading
Loading
Loading
+51 −9
Original line number Diff line number Diff line
@@ -75,6 +75,7 @@ typedef struct BlkdebugRule {
    int state;
    union {
        struct {
            uint64_t iotype_mask;
            int error;
            int immediately;
            int once;
@@ -91,6 +92,9 @@ typedef struct BlkdebugRule {
    QSIMPLEQ_ENTRY(BlkdebugRule) active_next;
} BlkdebugRule;

QEMU_BUILD_BUG_MSG(BLKDEBUG_IO_TYPE__MAX > 64,
                   "BlkdebugIOType mask does not fit into an uint64_t");

static QemuOptsList inject_error_opts = {
    .name = "inject-error",
    .head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head),
@@ -103,6 +107,10 @@ static QemuOptsList inject_error_opts = {
            .name = "state",
            .type = QEMU_OPT_NUMBER,
        },
        {
            .name = "iotype",
            .type = QEMU_OPT_STRING,
        },
        {
            .name = "errno",
            .type = QEMU_OPT_NUMBER,
@@ -162,6 +170,8 @@ static int add_rule(void *opaque, QemuOpts *opts, Error **errp)
    int event;
    struct BlkdebugRule *rule;
    int64_t sector;
    BlkdebugIOType iotype;
    Error *local_error = NULL;

    /* Find the right event for the rule */
    event_name = qemu_opt_get(opts, "event");
@@ -192,6 +202,26 @@ static int add_rule(void *opaque, QemuOpts *opts, Error **errp)
        sector = qemu_opt_get_number(opts, "sector", -1);
        rule->options.inject.offset =
            sector == -1 ? -1 : sector * BDRV_SECTOR_SIZE;

        iotype = qapi_enum_parse(&BlkdebugIOType_lookup,
                                 qemu_opt_get(opts, "iotype"),
                                 BLKDEBUG_IO_TYPE__MAX, &local_error);
        if (local_error) {
            error_propagate(errp, local_error);
            return -1;
        }
        if (iotype != BLKDEBUG_IO_TYPE__MAX) {
            rule->options.inject.iotype_mask = (1ull << iotype);
        } else {
            /* Apply the default */
            rule->options.inject.iotype_mask =
                (1ull << BLKDEBUG_IO_TYPE_READ)
                | (1ull << BLKDEBUG_IO_TYPE_WRITE)
                | (1ull << BLKDEBUG_IO_TYPE_WRITE_ZEROES)
                | (1ull << BLKDEBUG_IO_TYPE_DISCARD)
                | (1ull << BLKDEBUG_IO_TYPE_FLUSH);
        }

        break;

    case ACTION_SET_STATE:
@@ -461,6 +491,8 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
        goto out;
    }

    bdrv_debug_event(bs, BLKDBG_NONE);

    ret = 0;
out:
    if (ret < 0) {
@@ -470,7 +502,8 @@ out:
    return ret;
}

static int rule_check(BlockDriverState *bs, uint64_t offset, uint64_t bytes)
static int rule_check(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
                      BlkdebugIOType iotype)
{
    BDRVBlkdebugState *s = bs->opaque;
    BlkdebugRule *rule = NULL;
@@ -480,9 +513,10 @@ static int rule_check(BlockDriverState *bs, uint64_t offset, uint64_t bytes)
    QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
        uint64_t inject_offset = rule->options.inject.offset;

        if (inject_offset == -1 ||
        if ((inject_offset == -1 ||
             (bytes && inject_offset >= offset &&
             inject_offset < offset + bytes))
              inject_offset < offset + bytes)) &&
            (rule->options.inject.iotype_mask & (1ull << iotype)))
        {
            break;
        }
@@ -521,7 +555,7 @@ blkdebug_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
        assert(bytes <= bs->bl.max_transfer);
    }

    err = rule_check(bs, offset, bytes);
    err = rule_check(bs, offset, bytes, BLKDEBUG_IO_TYPE_READ);
    if (err) {
        return err;
    }
@@ -542,7 +576,7 @@ blkdebug_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
        assert(bytes <= bs->bl.max_transfer);
    }

    err = rule_check(bs, offset, bytes);
    err = rule_check(bs, offset, bytes, BLKDEBUG_IO_TYPE_WRITE);
    if (err) {
        return err;
    }
@@ -552,7 +586,7 @@ blkdebug_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,

static int blkdebug_co_flush(BlockDriverState *bs)
{
    int err = rule_check(bs, 0, 0);
    int err = rule_check(bs, 0, 0, BLKDEBUG_IO_TYPE_FLUSH);

    if (err) {
        return err;
@@ -586,7 +620,7 @@ static int coroutine_fn blkdebug_co_pwrite_zeroes(BlockDriverState *bs,
        assert(bytes <= bs->bl.max_pwrite_zeroes);
    }

    err = rule_check(bs, offset, bytes);
    err = rule_check(bs, offset, bytes, BLKDEBUG_IO_TYPE_WRITE_ZEROES);
    if (err) {
        return err;
    }
@@ -620,7 +654,7 @@ static int coroutine_fn blkdebug_co_pdiscard(BlockDriverState *bs,
        assert(bytes <= bs->bl.max_pdiscard);
    }

    err = rule_check(bs, offset, bytes);
    err = rule_check(bs, offset, bytes, BLKDEBUG_IO_TYPE_DISCARD);
    if (err) {
        return err;
    }
@@ -636,7 +670,15 @@ static int coroutine_fn blkdebug_co_block_status(BlockDriverState *bs,
                                                 int64_t *map,
                                                 BlockDriverState **file)
{
    int err;

    assert(QEMU_IS_ALIGNED(offset | bytes, bs->bl.request_alignment));

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

    return bdrv_co_block_status_from_file(bs, want_zero, offset, bytes,
                                          pnum, map, file);
}
+5 −9
Original line number Diff line number Diff line
@@ -1608,13 +1608,13 @@ static void external_snapshot_prepare(BlkActionState *common,
            s->has_snapshot_node_name ? s->snapshot_node_name : NULL;

        if (node_name && !snapshot_node_name) {
            error_setg(errp, "New snapshot node name missing");
            error_setg(errp, "New overlay node name missing");
            goto out;
        }

        if (snapshot_node_name &&
            bdrv_lookup_bs(snapshot_node_name, snapshot_node_name, NULL)) {
            error_setg(errp, "New snapshot node name already in use");
            error_setg(errp, "New overlay node name already in use");
            goto out;
        }

@@ -1656,7 +1656,7 @@ static void external_snapshot_prepare(BlkActionState *common,
    }

    if (bdrv_has_blk(state->new_bs)) {
        error_setg(errp, "The snapshot is already in use");
        error_setg(errp, "The overlay is already in use");
        goto out;
    }

@@ -1666,12 +1666,12 @@ static void external_snapshot_prepare(BlkActionState *common,
    }

    if (state->new_bs->backing != NULL) {
        error_setg(errp, "The snapshot already has a backing image");
        error_setg(errp, "The overlay already has a backing image");
        goto out;
    }

    if (!state->new_bs->drv->supports_backing) {
        error_setg(errp, "The snapshot does not support backing images");
        error_setg(errp, "The overlay does not support backing images");
        goto out;
    }

@@ -1876,10 +1876,6 @@ static void blockdev_backup_prepare(BlkActionState *common, Error **errp)
    }

    aio_context = bdrv_get_aio_context(bs);
    if (aio_context != bdrv_get_aio_context(target)) {
        error_setg(errp, "Backup between two IO threads is not implemented");
        return;
    }
    aio_context_acquire(aio_context);
    state->bs = bs;

+1 −0
Original line number Diff line number Diff line
@@ -2648,6 +2648,7 @@ static void fdctrl_realize_common(DeviceState *dev, FDCtrl *fdctrl,

    FLOPPY_DPRINTF("init controller\n");
    fdctrl->fifo = qemu_memalign(512, FD_SECTOR_LEN);
    memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
    fdctrl->fifo_size = 512;
    fdctrl->result_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
                                             fdctrl_result_timer, fdctrl);
+50 −17
Original line number Diff line number Diff line
@@ -402,42 +402,75 @@ class QEMUMachine(object):
        self._qmp.clear_events()
        return events

    def event_wait(self, name, timeout=60.0, match=None):
    @staticmethod
    def event_match(event, match=None):
        """
        Wait for specified timeout on named event in QMP; optionally filter
        results by match.
        Check if an event matches optional match criteria.

        The match criteria takes the form of a matching subdict. The event is
        checked to be a superset of the subdict, recursively, with matching
        values whenever the subdict values are not None.

        This has a limitation that you cannot explicitly check for None values.

        The 'match' is checked to be a recursive subset of the 'event'; skips
        branch processing on match's value None
           {"foo": {"bar": 1}} matches {"foo": None}
           {"foo": {"bar": 1}} does not matches {"foo": {"baz": None}}
        Examples, with the subdict queries on the left:
         - None matches any object.
         - {"foo": None} matches {"foo": {"bar": 1}}
         - {"foo": None} matches {"foo": 5}
         - {"foo": {"abc": None}} does not match {"foo": {"bar": 1}}
         - {"foo": {"rab": 2}} matches {"foo": {"bar": 1, "rab": 2}}
        """
        def event_match(event, match=None):
        if match is None:
            return True

        try:
            for key in match:
                if key in event:
                    if isinstance(event[key], dict):
                        if not event_match(event[key], match[key]):
                            return False
                    elif event[key] != match[key]:
                    if not QEMUMachine.event_match(event[key], match[key]):
                        return False
                else:
                    return False
            return True
        except TypeError:
            # either match or event wasn't iterable (not a dict)
            return match == event

    def event_wait(self, name, timeout=60.0, match=None):
        """
        event_wait waits for and returns a named event from QMP with a timeout.

        name: The event to wait for.
        timeout: QEMUMonitorProtocol.pull_event timeout parameter.
        match: Optional match criteria. See event_match for details.
        """
        return self.events_wait([(name, match)], timeout)

    def events_wait(self, events, timeout=60.0):
        """
        events_wait waits for and returns a named event from QMP with a timeout.

        events: a sequence of (name, match_criteria) tuples.
                The match criteria are optional and may be None.
                See event_match for details.
        timeout: QEMUMonitorProtocol.pull_event timeout parameter.
        """
        def _match(event):
            for name, match in events:
                if (event['event'] == name and
                    self.event_match(event, match)):
                    return True
            return False

        # Search cached events
        for event in self._events:
            if (event['event'] == name) and event_match(event, match):
            if _match(event):
                self._events.remove(event)
                return event

        # Poll for new events
        while True:
            event = self._qmp.pull_event(wait=timeout)
            if (event['event'] == name) and event_match(event, match):
            if _match(event):
                return event
            self._events.append(event)

+42 −11
Original line number Diff line number Diff line
@@ -1279,17 +1279,17 @@
#
# Either @device or @node-name must be set but not both.
#
# @device: the name of the device to generate the snapshot from.
# @device: the name of the device to take a snapshot of.
#
# @node-name: graph node name to generate the snapshot from (Since 2.0)
#
# @snapshot-file: the target of the new image. If the file exists, or
# if it is a device, the snapshot will be created in the existing
# file/device. Otherwise, a new file will be created.
# @snapshot-file: the target of the new overlay image. If the file
# exists, or if it is a device, the overlay will be created in the
# existing file/device. Otherwise, a new file will be created.
#
# @snapshot-node-name: the graph node name of the new image (Since 2.0)
#
# @format: the format of the snapshot image, default is 'qcow2'.
# @format: the format of the overlay image, default is 'qcow2'.
#
# @mode: whether and how QEMU should create a new image, default is
#        'absolute-paths'.
@@ -1302,10 +1302,10 @@
##
# @BlockdevSnapshot:
#
# @node: device or node name that will have a snapshot created.
# @node: device or node name that will have a snapshot taken.
#
# @overlay: reference to the existing block device that will become
#           the overlay of @node, as part of creating the snapshot.
#           the overlay of @node, as part of taking the snapshot.
#           It must not have a current backing file (this can be
#           achieved by passing "backing": null to blockdev-add).
#
@@ -1443,7 +1443,7 @@
##
# @blockdev-snapshot-sync:
#
# Generates a synchronous snapshot of a block device.
# Takes a synchronous snapshot of a block device.
#
# For the arguments, see the documentation of BlockdevSnapshotSync.
#
@@ -1469,9 +1469,9 @@
##
# @blockdev-snapshot:
#
# Generates a snapshot of a block device.
# Takes a snapshot of a block device.
#
# Create a snapshot, by installing 'node' as the backing image of
# Take a snapshot, by installing 'node' as the backing image of
# 'overlay'. Additionally, if 'node' is associated with a block
# device, the block device changes to using 'overlay' as its new active
# image.
@@ -3244,6 +3244,8 @@
#
# @cluster_alloc_space: an allocation of file space for a cluster (since 4.1)
#
# @none: triggers once at creation of the blkdebug node (since 4.1)
#
# Since: 2.9
##
{ 'enum': 'BlkdebugEvent', 'prefix': 'BLKDBG',
@@ -3262,7 +3264,30 @@
            'pwritev_rmw_tail', 'pwritev_rmw_after_tail', 'pwritev',
            'pwritev_zero', 'pwritev_done', 'empty_image_prepare',
            'l1_shrink_write_table', 'l1_shrink_free_l2_clusters',
            'cor_write', 'cluster_alloc_space'] }
            'cor_write', 'cluster_alloc_space', 'none'] }

##
# @BlkdebugIOType:
#
# Kinds of I/O that blkdebug can inject errors in.
#
# @read: .bdrv_co_preadv()
#
# @write: .bdrv_co_pwritev()
#
# @write-zeroes: .bdrv_co_pwrite_zeroes()
#
# @discard: .bdrv_co_pdiscard()
#
# @flush: .bdrv_co_flush_to_disk()
#
# @block-status: .bdrv_co_block_status()
#
# Since: 4.1
##
{ 'enum': 'BlkdebugIOType', 'prefix': 'BLKDEBUG_IO_TYPE',
  'data': [ 'read', 'write', 'write-zeroes', 'discard', 'flush',
            'block-status' ] }

##
# @BlkdebugInjectErrorOptions:
@@ -3274,6 +3299,11 @@
# @state:       the state identifier blkdebug needs to be in to
#               actually trigger the event; defaults to "any"
#
# @iotype:      the type of I/O operations on which this error should
#               be injected; defaults to "all read, write,
#               write-zeroes, discard, and flush operations"
#               (since: 4.1)
#
# @errno:       error identifier (errno) to be returned; defaults to
#               EIO
#
@@ -3291,6 +3321,7 @@
{ 'struct': 'BlkdebugInjectErrorOptions',
  'data': { 'event': 'BlkdebugEvent',
            '*state': 'int',
            '*iotype': 'BlkdebugIOType',
            '*errno': 'int',
            '*sector': 'int',
            '*once': 'bool',
Loading