Commit 12aa4082 authored by Max Reitz's avatar Max Reitz
Browse files

block/mirror: Use CoQueue to wait on in-flight ops



Attach a CoQueue to each in-flight operation so if we need to wait for
any we can use it to wait instead of just blindly yielding and hoping
for some operation to wake us.

A later patch will use this infrastructure to allow requests accessing
the same area of the virtual disk to specifically wait for each other.

Signed-off-by: default avatarMax Reitz <mreitz@redhat.com>
Reviewed-by: default avatarFam Zheng <famz@redhat.com>
Message-id: 20180613181823.13618-4-mreitz@redhat.com
Signed-off-by: default avatarMax Reitz <mreitz@redhat.com>
parent 2e1990b2
Loading
Loading
Loading
Loading
+23 −11
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@

#include "qemu/osdep.h"
#include "qemu/cutils.h"
#include "qemu/coroutine.h"
#include "trace.h"
#include "block/blockjob_int.h"
#include "block/block_int.h"
@@ -33,6 +34,8 @@ typedef struct MirrorBuffer {
    QSIMPLEQ_ENTRY(MirrorBuffer) next;
} MirrorBuffer;

typedef struct MirrorOp MirrorOp;

typedef struct MirrorBlockJob {
    BlockJob common;
    BlockBackend *target;
@@ -65,15 +68,15 @@ typedef struct MirrorBlockJob {
    unsigned long *in_flight_bitmap;
    int in_flight;
    int64_t bytes_in_flight;
    QTAILQ_HEAD(MirrorOpList, MirrorOp) ops_in_flight;
    int ret;
    bool unmap;
    bool waiting_for_io;
    int target_cluster_size;
    int max_iov;
    bool initial_zeroing_ongoing;
} MirrorBlockJob;

typedef struct MirrorOp {
struct MirrorOp {
    MirrorBlockJob *s;
    QEMUIOVector qiov;
    int64_t offset;
@@ -82,7 +85,11 @@ typedef struct MirrorOp {
    /* The pointee is set by mirror_co_read(), mirror_co_zero(), and
     * mirror_co_discard() before yielding for the first time */
    int64_t *bytes_handled;
} MirrorOp;

    CoQueue waiting_requests;

    QTAILQ_ENTRY(MirrorOp) next;
};

typedef enum MirrorMethod {
    MIRROR_METHOD_COPY,
@@ -123,7 +130,9 @@ static void coroutine_fn mirror_iteration_done(MirrorOp *op, int ret)

    chunk_num = op->offset / s->granularity;
    nb_chunks = DIV_ROUND_UP(op->bytes, s->granularity);

    bitmap_clear(s->in_flight_bitmap, chunk_num, nb_chunks);
    QTAILQ_REMOVE(&s->ops_in_flight, op, next);
    if (ret >= 0) {
        if (s->cow_bitmap) {
            bitmap_set(s->cow_bitmap, chunk_num, nb_chunks);
@@ -133,11 +142,9 @@ static void coroutine_fn mirror_iteration_done(MirrorOp *op, int ret)
        }
    }
    qemu_iovec_destroy(&op->qiov);
    g_free(op);

    if (s->waiting_for_io) {
        qemu_coroutine_enter(s->common.job.co);
    }
    qemu_co_queue_restart_all(&op->waiting_requests);
    g_free(op);
}

static void coroutine_fn mirror_write_complete(MirrorOp *op, int ret)
@@ -227,10 +234,11 @@ static int mirror_cow_align(MirrorBlockJob *s, int64_t *offset,

static inline void mirror_wait_for_io(MirrorBlockJob *s)
{
    assert(!s->waiting_for_io);
    s->waiting_for_io = true;
    qemu_coroutine_yield();
    s->waiting_for_io = false;
    MirrorOp *op;

    op = QTAILQ_FIRST(&s->ops_in_flight);
    assert(op);
    qemu_co_queue_wait(&op->waiting_requests, NULL);
}

/* Perform a mirror copy operation.
@@ -340,6 +348,7 @@ static unsigned mirror_perform(MirrorBlockJob *s, int64_t offset,
        .bytes          = bytes,
        .bytes_handled  = &bytes_handled,
    };
    qemu_co_queue_init(&op->waiting_requests);

    switch (mirror_method) {
    case MIRROR_METHOD_COPY:
@@ -355,6 +364,7 @@ static unsigned mirror_perform(MirrorBlockJob *s, int64_t offset,
        abort();
    }

    QTAILQ_INSERT_TAIL(&s->ops_in_flight, op, next);
    qemu_coroutine_enter(co);
    /* At this point, ownership of op has been moved to the coroutine
     * and the object may already be freed */
@@ -1290,6 +1300,8 @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
        }
    }

    QTAILQ_INIT(&s->ops_in_flight);

    trace_mirror_start(bs, s, opaque);
    job_start(&s->common.job);
    return;