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

Merge remote-tracking branch 'remotes/maxreitz/tags/pull-block-for-peter-2016-02-02' into staging



Block patches

# gpg: Signature made Tue 02 Feb 2016 17:23:44 GMT using RSA key ID E838ACAD
# gpg: Good signature from "Max Reitz <mreitz@redhat.com>"

* remotes/maxreitz/tags/pull-block-for-peter-2016-02-02: (50 commits)
  block: qemu-iotests - add test for snapshot, commit, snapshot bug
  block: set device_list.tqe_prev to NULL on BDS removal
  iotests: Add "qemu-img map" test for VMDK extents
  qemu-img: Make MapEntry a QAPI struct
  qemu-img: In "map", use the returned "file" from bdrv_get_block_status
  block: Use returned *file in bdrv_co_get_block_status
  vmdk: Return extent's file in bdrv_get_block_status
  vmdk: Fix calculation of block status's offset
  vpc: Assign bs->file->bs to file in vpc_co_get_block_status
  vdi: Assign bs->file->bs to file in vdi_co_get_block_status
  sheepdog: Assign bs to file in sd_co_get_block_status
  qed: Assign bs->file->bs to file in bdrv_qed_co_get_block_status
  parallels: Assign bs->file->bs to file in parallels_co_get_block_status
  iscsi: Assign bs to file in iscsi_co_get_block_status
  raw: Assign bs to file in raw_co_get_block_status
  qcow2: Assign bs->file->bs to file in qcow2_co_get_block_status
  qcow: Assign bs->file->bs to file in qcow_co_get_block_status
  block: Add "file" output parameter to block status query functions
  block: acquire in bdrv_query_image_info
  iotests: Add test for block jobs and BDS ejection
  ...

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents 3bb1e822 8983b670
Loading
Loading
Loading
Loading
+80 −34
Original line number Diff line number Diff line
@@ -79,6 +79,9 @@ struct BdrvStates bdrv_states = QTAILQ_HEAD_INITIALIZER(bdrv_states);
static QTAILQ_HEAD(, BlockDriverState) graph_bdrv_states =
    QTAILQ_HEAD_INITIALIZER(graph_bdrv_states);

static QTAILQ_HEAD(, BlockDriverState) all_bdrv_states =
    QTAILQ_HEAD_INITIALIZER(all_bdrv_states);

static QLIST_HEAD(, BlockDriver) bdrv_drivers =
    QLIST_HEAD_INITIALIZER(bdrv_drivers);

@@ -88,9 +91,13 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
                             const BdrvChildRole *child_role, Error **errp);

static void bdrv_dirty_bitmap_truncate(BlockDriverState *bs);
static void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs);

/* If non-zero, use only whitelisted block drivers */
static int use_bdrv_whitelist;

static void bdrv_close(BlockDriverState *bs);

#ifdef _WIN32
static int is_windows_drive_prefix(const char *filename)
{
@@ -257,19 +264,15 @@ BlockDriverState *bdrv_new(void)
    for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) {
        QLIST_INIT(&bs->op_blockers[i]);
    }
    notifier_list_init(&bs->close_notifiers);
    notifier_with_return_list_init(&bs->before_write_notifiers);
    qemu_co_queue_init(&bs->throttled_reqs[0]);
    qemu_co_queue_init(&bs->throttled_reqs[1]);
    bs->refcnt = 1;
    bs->aio_context = qemu_get_aio_context();

    return bs;
}
    QTAILQ_INSERT_TAIL(&all_bdrv_states, bs, bs_list);

void bdrv_add_close_notifier(BlockDriverState *bs, Notifier *notify)
{
    notifier_list_add(&bs->close_notifiers, notify);
    return bs;
}

BlockDriver *bdrv_find_format(const char *format_name)
@@ -2138,13 +2141,11 @@ void bdrv_reopen_abort(BDRVReopenState *reopen_state)
}


void bdrv_close(BlockDriverState *bs)
static void bdrv_close(BlockDriverState *bs)
{
    BdrvAioNotifier *ban, *ban_next;

    if (bs->job) {
        block_job_cancel_sync(bs->job);
    }
    assert(!bs->job);

    /* Disable I/O limits and drain all pending throttled requests */
    if (bs->throttle_state) {
@@ -2155,7 +2156,8 @@ void bdrv_close(BlockDriverState *bs)
    bdrv_flush(bs);
    bdrv_drain(bs); /* in case flush left pending I/O */

    notifier_list_notify(&bs->close_notifiers, bs);
    bdrv_release_named_dirty_bitmaps(bs);
    assert(QLIST_EMPTY(&bs->dirty_bitmaps));

    if (bs->blk) {
        blk_dev_change_media_cb(bs->blk, false);
@@ -2210,14 +2212,44 @@ void bdrv_close(BlockDriverState *bs)
void bdrv_close_all(void)
{
    BlockDriverState *bs;
    AioContext *aio_context;

    QTAILQ_FOREACH(bs, &bdrv_states, device_list) {
        AioContext *aio_context = bdrv_get_aio_context(bs);
    /* Drop references from requests still in flight, such as canceled block
     * jobs whose AIO context has not been polled yet */
    bdrv_drain_all();

    blk_remove_all_bs();
    blockdev_close_all_bdrv_states();

    /* Cancel all block jobs */
    while (!QTAILQ_EMPTY(&all_bdrv_states)) {
        QTAILQ_FOREACH(bs, &all_bdrv_states, bs_list) {
            aio_context = bdrv_get_aio_context(bs);

            aio_context_acquire(aio_context);
        bdrv_close(bs);
            if (bs->job) {
                block_job_cancel_sync(bs->job);
                aio_context_release(aio_context);
                break;
            }
            aio_context_release(aio_context);
        }

        /* All the remaining BlockDriverStates are referenced directly or
         * indirectly from block jobs, so there needs to be at least one BDS
         * directly used by a block job */
        assert(bs);
    }
}

/* Note that bs->device_list.tqe_prev is initially null,
 * and gets set to non-null by QTAILQ_INSERT_TAIL().  Establish
 * the useful invariant "bs in bdrv_states iff bs->tqe_prev" by
 * resetting it to null on remove.  */
void bdrv_device_remove(BlockDriverState *bs)
{
    QTAILQ_REMOVE(&bdrv_states, bs, device_list);
    bs->device_list.tqe_prev = NULL;
}

/* make a BlockDriverState anonymous by removing from bdrv_state and
@@ -2225,16 +2257,10 @@ void bdrv_close_all(void)
   Also, NULL terminate the device_name to prevent double remove */
void bdrv_make_anon(BlockDriverState *bs)
{
    /*
     * Take care to remove bs from bdrv_states only when it's actually
     * in it.  Note that bs->device_list.tqe_prev is initially null,
     * and gets set to non-null by QTAILQ_INSERT_TAIL().  Establish
     * the useful invariant "bs in bdrv_states iff bs->tqe_prev" by
     * resetting it to null on remove.
     */
    /* Take care to remove bs from bdrv_states only when it's actually
     * in it. */
    if (bs->device_list.tqe_prev) {
        QTAILQ_REMOVE(&bdrv_states, bs, device_list);
        bs->device_list.tqe_prev = NULL;
        bdrv_device_remove(bs);
    }
    if (bs->node_name[0] != '\0') {
        QTAILQ_REMOVE(&graph_bdrv_states, bs, node_list);
@@ -2275,7 +2301,7 @@ static void change_parent_backing_link(BlockDriverState *from,
        if (!to->device_list.tqe_prev) {
            QTAILQ_INSERT_BEFORE(from, to, device_list);
        }
        QTAILQ_REMOVE(&bdrv_states, from, device_list);
        bdrv_device_remove(from);
    }
}

@@ -2366,13 +2392,14 @@ static void bdrv_delete(BlockDriverState *bs)
    assert(!bs->job);
    assert(bdrv_op_blocker_is_empty(bs));
    assert(!bs->refcnt);
    assert(QLIST_EMPTY(&bs->dirty_bitmaps));

    bdrv_close(bs);

    /* remove from list, if necessary */
    bdrv_make_anon(bs);

    QTAILQ_REMOVE(&all_bdrv_states, bs, bs_list);

    g_free(bs);
}

@@ -3582,20 +3609,39 @@ static void bdrv_dirty_bitmap_truncate(BlockDriverState *bs)
    }
}

void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
static void bdrv_do_release_matching_dirty_bitmap(BlockDriverState *bs,
                                                  BdrvDirtyBitmap *bitmap,
                                                  bool only_named)
{
    BdrvDirtyBitmap *bm, *next;
    QLIST_FOREACH_SAFE(bm, &bs->dirty_bitmaps, list, next) {
        if (bm == bitmap) {
        if ((!bitmap || bm == bitmap) && (!only_named || bm->name)) {
            assert(!bdrv_dirty_bitmap_frozen(bm));
            QLIST_REMOVE(bitmap, list);
            hbitmap_free(bitmap->bitmap);
            g_free(bitmap->name);
            g_free(bitmap);
            QLIST_REMOVE(bm, list);
            hbitmap_free(bm->bitmap);
            g_free(bm->name);
            g_free(bm);

            if (bitmap) {
                return;
            }
        }
    }
}

void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
{
    bdrv_do_release_matching_dirty_bitmap(bs, bitmap, false);
}

/**
 * Release all named dirty bitmaps attached to a BDS (for use in bdrv_close()).
 * There must not be any frozen bitmaps attached.
 */
static void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs)
{
    bdrv_do_release_matching_dirty_bitmap(bs, NULL, true);
}

void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
{
+44 −9
Original line number Diff line number Diff line
@@ -49,6 +49,8 @@ struct BlockBackend {
    BlockdevOnError on_read_error, on_write_error;
    bool iostatus_enabled;
    BlockDeviceIoStatus iostatus;

    NotifierList remove_bs_notifiers, insert_bs_notifiers;
};

typedef struct BlockBackendAIOCB {
@@ -99,6 +101,8 @@ BlockBackend *blk_new(const char *name, Error **errp)
    blk = g_new0(BlockBackend, 1);
    blk->name = g_strdup(name);
    blk->refcnt = 1;
    notifier_list_init(&blk->remove_bs_notifiers);
    notifier_list_init(&blk->insert_bs_notifiers);
    QTAILQ_INSERT_TAIL(&blk_backends, blk, link);
    return blk;
}
@@ -162,11 +166,10 @@ static void blk_delete(BlockBackend *blk)
    assert(!blk->refcnt);
    assert(!blk->dev);
    if (blk->bs) {
        assert(blk->bs->blk == blk);
        blk->bs->blk = NULL;
        bdrv_unref(blk->bs);
        blk->bs = NULL;
        blk_remove_bs(blk);
    }
    assert(QLIST_EMPTY(&blk->remove_bs_notifiers.notifiers));
    assert(QLIST_EMPTY(&blk->insert_bs_notifiers.notifiers));
    if (blk->root_state.throttle_state) {
        g_free(blk->root_state.throttle_group);
        throttle_group_unref(blk->root_state.throttle_state);
@@ -220,6 +223,21 @@ void blk_unref(BlockBackend *blk)
    }
}

void blk_remove_all_bs(void)
{
    BlockBackend *blk;

    QTAILQ_FOREACH(blk, &blk_backends, link) {
        AioContext *ctx = blk_get_aio_context(blk);

        aio_context_acquire(ctx);
        if (blk->bs) {
            blk_remove_bs(blk);
        }
        aio_context_release(ctx);
    }
}

/*
 * Return the BlockBackend after @blk.
 * If @blk is null, return the first one.
@@ -345,6 +363,10 @@ void blk_hide_on_behalf_of_hmp_drive_del(BlockBackend *blk)
 */
void blk_remove_bs(BlockBackend *blk)
{
    assert(blk->bs->blk == blk);

    notifier_list_notify(&blk->remove_bs_notifiers, blk);

    blk_update_root_state(blk);

    blk->bs->blk = NULL;
@@ -361,6 +383,8 @@ void blk_insert_bs(BlockBackend *blk, BlockDriverState *bs)
    bdrv_ref(bs);
    blk->bs = bs;
    bs->blk = blk;

    notifier_list_notify(&blk->insert_bs_notifiers, blk);
}

/*
@@ -458,6 +482,14 @@ bool blk_dev_has_removable_media(BlockBackend *blk)
    return !blk->dev || (blk->dev_ops && blk->dev_ops->change_media_cb);
}

/*
 * Does @blk's attached device model have a tray?
 */
bool blk_dev_has_tray(BlockBackend *blk)
{
    return blk->dev_ops && blk->dev_ops->is_tray_open;
}

/*
 * Notify @blk's attached device model of a media eject request.
 * If @force is true, the medium is about to be yanked out forcefully.
@@ -474,7 +506,7 @@ void blk_dev_eject_request(BlockBackend *blk, bool force)
 */
bool blk_dev_is_tray_open(BlockBackend *blk)
{
    if (blk->dev_ops && blk->dev_ops->is_tray_open) {
    if (blk_dev_has_tray(blk)) {
        return blk->dev_ops->is_tray_open(blk->dev_opaque);
    }
    return false;
@@ -1118,11 +1150,14 @@ void blk_remove_aio_context_notifier(BlockBackend *blk,
    }
}

void blk_add_close_notifier(BlockBackend *blk, Notifier *notify)
void blk_add_remove_bs_notifier(BlockBackend *blk, Notifier *notify)
{
    if (blk->bs) {
        bdrv_add_close_notifier(blk->bs, notify);
    notifier_list_add(&blk->remove_bs_notifiers, notify);
}

void blk_add_insert_bs_notifier(BlockBackend *blk, Notifier *notify)
{
    notifier_list_add(&blk->insert_bs_notifiers, notify);
}

void blk_io_plug(BlockBackend *blk)
+30 −14
Original line number Diff line number Diff line
@@ -664,6 +664,7 @@ int bdrv_write_zeroes(BlockDriverState *bs, int64_t sector_num,
int bdrv_make_zero(BlockDriverState *bs, BdrvRequestFlags flags)
{
    int64_t target_sectors, ret, nb_sectors, sector_num = 0;
    BlockDriverState *file;
    int n;

    target_sectors = bdrv_nb_sectors(bs);
@@ -676,7 +677,7 @@ int bdrv_make_zero(BlockDriverState *bs, BdrvRequestFlags flags)
        if (nb_sectors <= 0) {
            return 0;
        }
        ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &n);
        ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &n, &file);
        if (ret < 0) {
            error_report("error getting block status at sector %" PRId64 ": %s",
                         sector_num, strerror(-ret));
@@ -1466,6 +1467,7 @@ int bdrv_flush_all(void)
typedef struct BdrvCoGetBlockStatusData {
    BlockDriverState *bs;
    BlockDriverState *base;
    BlockDriverState **file;
    int64_t sector_num;
    int nb_sectors;
    int *pnum;
@@ -1487,10 +1489,14 @@ typedef struct BdrvCoGetBlockStatusData {
 *
 * 'nb_sectors' is the max value 'pnum' should be set to.  If nb_sectors goes
 * beyond the end of the disk image it will be clamped.
 *
 * If returned value is positive and BDRV_BLOCK_OFFSET_VALID bit is set, 'file'
 * points to the BDS which the sector range is allocated in.
 */
static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
                                                     int64_t sector_num,
                                                     int nb_sectors, int *pnum)
                                                     int nb_sectors, int *pnum,
                                                     BlockDriverState **file)
{
    int64_t total_sectors;
    int64_t n;
@@ -1520,7 +1526,9 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
        return ret;
    }

    ret = bs->drv->bdrv_co_get_block_status(bs, sector_num, nb_sectors, pnum);
    *file = NULL;
    ret = bs->drv->bdrv_co_get_block_status(bs, sector_num, nb_sectors, pnum,
                                            file);
    if (ret < 0) {
        *pnum = 0;
        return ret;
@@ -1529,7 +1537,7 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
    if (ret & BDRV_BLOCK_RAW) {
        assert(ret & BDRV_BLOCK_OFFSET_VALID);
        return bdrv_get_block_status(bs->file->bs, ret >> BDRV_SECTOR_BITS,
                                     *pnum, pnum);
                                     *pnum, pnum, file);
    }

    if (ret & (BDRV_BLOCK_DATA | BDRV_BLOCK_ZERO)) {
@@ -1546,13 +1554,14 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
        }
    }

    if (bs->file &&
    if (*file && *file != bs &&
        (ret & BDRV_BLOCK_DATA) && !(ret & BDRV_BLOCK_ZERO) &&
        (ret & BDRV_BLOCK_OFFSET_VALID)) {
        BlockDriverState *file2;
        int file_pnum;

        ret2 = bdrv_co_get_block_status(bs->file->bs, ret >> BDRV_SECTOR_BITS,
                                        *pnum, &file_pnum);
        ret2 = bdrv_co_get_block_status(*file, ret >> BDRV_SECTOR_BITS,
                                        *pnum, &file_pnum, &file2);
        if (ret2 >= 0) {
            /* Ignore errors.  This is just providing extra information, it
             * is useful but not necessary.
@@ -1577,14 +1586,15 @@ static int64_t coroutine_fn bdrv_co_get_block_status_above(BlockDriverState *bs,
        BlockDriverState *base,
        int64_t sector_num,
        int nb_sectors,
        int *pnum)
        int *pnum,
        BlockDriverState **file)
{
    BlockDriverState *p;
    int64_t ret = 0;

    assert(bs != base);
    for (p = bs; p != base; p = backing_bs(p)) {
        ret = bdrv_co_get_block_status(p, sector_num, nb_sectors, pnum);
        ret = bdrv_co_get_block_status(p, sector_num, nb_sectors, pnum, file);
        if (ret < 0 || ret & BDRV_BLOCK_ALLOCATED) {
            break;
        }
@@ -1603,7 +1613,8 @@ static void coroutine_fn bdrv_get_block_status_above_co_entry(void *opaque)
    data->ret = bdrv_co_get_block_status_above(data->bs, data->base,
                                               data->sector_num,
                                               data->nb_sectors,
                                               data->pnum);
                                               data->pnum,
                                               data->file);
    data->done = true;
}

@@ -1615,12 +1626,14 @@ static void coroutine_fn bdrv_get_block_status_above_co_entry(void *opaque)
int64_t bdrv_get_block_status_above(BlockDriverState *bs,
                                    BlockDriverState *base,
                                    int64_t sector_num,
                                    int nb_sectors, int *pnum)
                                    int nb_sectors, int *pnum,
                                    BlockDriverState **file)
{
    Coroutine *co;
    BdrvCoGetBlockStatusData data = {
        .bs = bs,
        .base = base,
        .file = file,
        .sector_num = sector_num,
        .nb_sectors = nb_sectors,
        .pnum = pnum,
@@ -1644,16 +1657,19 @@ int64_t bdrv_get_block_status_above(BlockDriverState *bs,

int64_t bdrv_get_block_status(BlockDriverState *bs,
                              int64_t sector_num,
                              int nb_sectors, int *pnum)
                              int nb_sectors, int *pnum,
                              BlockDriverState **file)
{
    return bdrv_get_block_status_above(bs, backing_bs(bs),
                                       sector_num, nb_sectors, pnum);
                                       sector_num, nb_sectors, pnum, file);
}

int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num,
                                   int nb_sectors, int *pnum)
{
    int64_t ret = bdrv_get_block_status(bs, sector_num, nb_sectors, pnum);
    BlockDriverState *file;
    int64_t ret = bdrv_get_block_status(bs, sector_num, nb_sectors, pnum,
                                        &file);
    if (ret < 0) {
        return ret;
    }
+7 −2
Original line number Diff line number Diff line
@@ -532,7 +532,8 @@ static bool iscsi_allocationmap_is_allocated(IscsiLun *iscsilun,

static int64_t coroutine_fn iscsi_co_get_block_status(BlockDriverState *bs,
                                                  int64_t sector_num,
                                                  int nb_sectors, int *pnum)
                                                  int nb_sectors, int *pnum,
                                                  BlockDriverState **file)
{
    IscsiLun *iscsilun = bs->opaque;
    struct scsi_get_lba_status *lbas = NULL;
@@ -624,6 +625,9 @@ out:
    if (iTask.task != NULL) {
        scsi_free_scsi_task(iTask.task);
    }
    if (ret > 0 && ret & BDRV_BLOCK_OFFSET_VALID) {
        *file = bs;
    }
    return ret;
}

@@ -650,7 +654,8 @@ static int coroutine_fn iscsi_co_readv(BlockDriverState *bs,
        !iscsi_allocationmap_is_allocated(iscsilun, sector_num, nb_sectors)) {
        int64_t ret;
        int pnum;
        ret = iscsi_co_get_block_status(bs, sector_num, INT_MAX, &pnum);
        BlockDriverState *file;
        ret = iscsi_co_get_block_status(bs, sector_num, INT_MAX, &pnum, &file);
        if (ret < 0) {
            return ret;
        }
+2 −1
Original line number Diff line number Diff line
@@ -168,6 +168,7 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
    MirrorOp *op;
    int pnum;
    int64_t ret;
    BlockDriverState *file;

    max_iov = MIN(source->bl.max_iov, s->target->bl.max_iov);

@@ -306,7 +307,7 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
    trace_mirror_one_iteration(s, sector_num, nb_sectors);

    ret = bdrv_get_block_status_above(source, NULL, sector_num,
                                      nb_sectors, &pnum);
                                      nb_sectors, &pnum, &file);
    if (ret < 0 || pnum < nb_sectors ||
            (ret & BDRV_BLOCK_DATA && !(ret & BDRV_BLOCK_ZERO))) {
        bdrv_aio_readv(source, sector_num, &op->qiov, nb_sectors,
Loading