mirror of https://gitee.com/openkylin/qemu.git
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: Max Reitz <mreitz@redhat.com> Reviewed-by: Fam Zheng <famz@redhat.com> Message-id: 20180613181823.13618-4-mreitz@redhat.com Signed-off-by: Max Reitz <mreitz@redhat.com>
This commit is contained in:
parent
2e1990b26e
commit
12aa40822d
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "qemu/cutils.h"
|
#include "qemu/cutils.h"
|
||||||
|
#include "qemu/coroutine.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
#include "block/blockjob_int.h"
|
#include "block/blockjob_int.h"
|
||||||
#include "block/block_int.h"
|
#include "block/block_int.h"
|
||||||
|
@ -33,6 +34,8 @@ typedef struct MirrorBuffer {
|
||||||
QSIMPLEQ_ENTRY(MirrorBuffer) next;
|
QSIMPLEQ_ENTRY(MirrorBuffer) next;
|
||||||
} MirrorBuffer;
|
} MirrorBuffer;
|
||||||
|
|
||||||
|
typedef struct MirrorOp MirrorOp;
|
||||||
|
|
||||||
typedef struct MirrorBlockJob {
|
typedef struct MirrorBlockJob {
|
||||||
BlockJob common;
|
BlockJob common;
|
||||||
BlockBackend *target;
|
BlockBackend *target;
|
||||||
|
@ -65,15 +68,15 @@ typedef struct MirrorBlockJob {
|
||||||
unsigned long *in_flight_bitmap;
|
unsigned long *in_flight_bitmap;
|
||||||
int in_flight;
|
int in_flight;
|
||||||
int64_t bytes_in_flight;
|
int64_t bytes_in_flight;
|
||||||
|
QTAILQ_HEAD(MirrorOpList, MirrorOp) ops_in_flight;
|
||||||
int ret;
|
int ret;
|
||||||
bool unmap;
|
bool unmap;
|
||||||
bool waiting_for_io;
|
|
||||||
int target_cluster_size;
|
int target_cluster_size;
|
||||||
int max_iov;
|
int max_iov;
|
||||||
bool initial_zeroing_ongoing;
|
bool initial_zeroing_ongoing;
|
||||||
} MirrorBlockJob;
|
} MirrorBlockJob;
|
||||||
|
|
||||||
typedef struct MirrorOp {
|
struct MirrorOp {
|
||||||
MirrorBlockJob *s;
|
MirrorBlockJob *s;
|
||||||
QEMUIOVector qiov;
|
QEMUIOVector qiov;
|
||||||
int64_t offset;
|
int64_t offset;
|
||||||
|
@ -82,7 +85,11 @@ typedef struct MirrorOp {
|
||||||
/* The pointee is set by mirror_co_read(), mirror_co_zero(), and
|
/* The pointee is set by mirror_co_read(), mirror_co_zero(), and
|
||||||
* mirror_co_discard() before yielding for the first time */
|
* mirror_co_discard() before yielding for the first time */
|
||||||
int64_t *bytes_handled;
|
int64_t *bytes_handled;
|
||||||
} MirrorOp;
|
|
||||||
|
CoQueue waiting_requests;
|
||||||
|
|
||||||
|
QTAILQ_ENTRY(MirrorOp) next;
|
||||||
|
};
|
||||||
|
|
||||||
typedef enum MirrorMethod {
|
typedef enum MirrorMethod {
|
||||||
MIRROR_METHOD_COPY,
|
MIRROR_METHOD_COPY,
|
||||||
|
@ -123,7 +130,9 @@ static void coroutine_fn mirror_iteration_done(MirrorOp *op, int ret)
|
||||||
|
|
||||||
chunk_num = op->offset / s->granularity;
|
chunk_num = op->offset / s->granularity;
|
||||||
nb_chunks = DIV_ROUND_UP(op->bytes, s->granularity);
|
nb_chunks = DIV_ROUND_UP(op->bytes, s->granularity);
|
||||||
|
|
||||||
bitmap_clear(s->in_flight_bitmap, chunk_num, nb_chunks);
|
bitmap_clear(s->in_flight_bitmap, chunk_num, nb_chunks);
|
||||||
|
QTAILQ_REMOVE(&s->ops_in_flight, op, next);
|
||||||
if (ret >= 0) {
|
if (ret >= 0) {
|
||||||
if (s->cow_bitmap) {
|
if (s->cow_bitmap) {
|
||||||
bitmap_set(s->cow_bitmap, chunk_num, nb_chunks);
|
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);
|
qemu_iovec_destroy(&op->qiov);
|
||||||
g_free(op);
|
|
||||||
|
|
||||||
if (s->waiting_for_io) {
|
qemu_co_queue_restart_all(&op->waiting_requests);
|
||||||
qemu_coroutine_enter(s->common.job.co);
|
g_free(op);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void coroutine_fn mirror_write_complete(MirrorOp *op, int ret)
|
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)
|
static inline void mirror_wait_for_io(MirrorBlockJob *s)
|
||||||
{
|
{
|
||||||
assert(!s->waiting_for_io);
|
MirrorOp *op;
|
||||||
s->waiting_for_io = true;
|
|
||||||
qemu_coroutine_yield();
|
op = QTAILQ_FIRST(&s->ops_in_flight);
|
||||||
s->waiting_for_io = false;
|
assert(op);
|
||||||
|
qemu_co_queue_wait(&op->waiting_requests, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Perform a mirror copy operation.
|
/* Perform a mirror copy operation.
|
||||||
|
@ -340,6 +348,7 @@ static unsigned mirror_perform(MirrorBlockJob *s, int64_t offset,
|
||||||
.bytes = bytes,
|
.bytes = bytes,
|
||||||
.bytes_handled = &bytes_handled,
|
.bytes_handled = &bytes_handled,
|
||||||
};
|
};
|
||||||
|
qemu_co_queue_init(&op->waiting_requests);
|
||||||
|
|
||||||
switch (mirror_method) {
|
switch (mirror_method) {
|
||||||
case MIRROR_METHOD_COPY:
|
case MIRROR_METHOD_COPY:
|
||||||
|
@ -355,6 +364,7 @@ static unsigned mirror_perform(MirrorBlockJob *s, int64_t offset,
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QTAILQ_INSERT_TAIL(&s->ops_in_flight, op, next);
|
||||||
qemu_coroutine_enter(co);
|
qemu_coroutine_enter(co);
|
||||||
/* At this point, ownership of op has been moved to the coroutine
|
/* At this point, ownership of op has been moved to the coroutine
|
||||||
* and the object may already be freed */
|
* 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);
|
trace_mirror_start(bs, s, opaque);
|
||||||
job_start(&s->common.job);
|
job_start(&s->common.job);
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Reference in New Issue