mirror: fix throttling delay calculation
The throttling delay calculation was using an inaccurate sector count to calculate the time to sleep. This broke rate-limiting for the block mirror job. Move the delay calculation into mirror_iteration() where we know how many sectors were transferred. This lets us calculate an accurate delay time. Reported-by: Joaquim Barrera <jbarrera@ac.upc.edu> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
parent
dc6fb73d21
commit
cc8c9d6c6f
@ -139,11 +139,12 @@ static void mirror_read_complete(void *opaque, int ret)
|
|||||||
mirror_write_complete, op);
|
mirror_write_complete, op);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void coroutine_fn mirror_iteration(MirrorBlockJob *s)
|
static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
|
||||||
{
|
{
|
||||||
BlockDriverState *source = s->common.bs;
|
BlockDriverState *source = s->common.bs;
|
||||||
int nb_sectors, sectors_per_chunk, nb_chunks;
|
int nb_sectors, sectors_per_chunk, nb_chunks;
|
||||||
int64_t end, sector_num, next_chunk, next_sector, hbitmap_next_sector;
|
int64_t end, sector_num, next_chunk, next_sector, hbitmap_next_sector;
|
||||||
|
uint64_t delay_ns;
|
||||||
MirrorOp *op;
|
MirrorOp *op;
|
||||||
|
|
||||||
s->sector_num = hbitmap_iter_next(&s->hbi);
|
s->sector_num = hbitmap_iter_next(&s->hbi);
|
||||||
@ -231,7 +232,12 @@ static void coroutine_fn mirror_iteration(MirrorBlockJob *s)
|
|||||||
nb_chunks += added_chunks;
|
nb_chunks += added_chunks;
|
||||||
next_sector += added_sectors;
|
next_sector += added_sectors;
|
||||||
next_chunk += added_chunks;
|
next_chunk += added_chunks;
|
||||||
} while (next_sector < end);
|
if (!s->synced && s->common.speed) {
|
||||||
|
delay_ns = ratelimit_calculate_delay(&s->limit, added_sectors);
|
||||||
|
} else {
|
||||||
|
delay_ns = 0;
|
||||||
|
}
|
||||||
|
} while (delay_ns == 0 && next_sector < end);
|
||||||
|
|
||||||
/* Allocate a MirrorOp that is used as an AIO callback. */
|
/* Allocate a MirrorOp that is used as an AIO callback. */
|
||||||
op = g_slice_new(MirrorOp);
|
op = g_slice_new(MirrorOp);
|
||||||
@ -268,6 +274,7 @@ static void coroutine_fn mirror_iteration(MirrorBlockJob *s)
|
|||||||
trace_mirror_one_iteration(s, sector_num, nb_sectors);
|
trace_mirror_one_iteration(s, sector_num, nb_sectors);
|
||||||
bdrv_aio_readv(source, sector_num, &op->qiov, nb_sectors,
|
bdrv_aio_readv(source, sector_num, &op->qiov, nb_sectors,
|
||||||
mirror_read_complete, op);
|
mirror_read_complete, op);
|
||||||
|
return delay_ns;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mirror_free_init(MirrorBlockJob *s)
|
static void mirror_free_init(MirrorBlockJob *s)
|
||||||
@ -362,7 +369,7 @@ static void coroutine_fn mirror_run(void *opaque)
|
|||||||
bdrv_dirty_iter_init(bs, s->dirty_bitmap, &s->hbi);
|
bdrv_dirty_iter_init(bs, s->dirty_bitmap, &s->hbi);
|
||||||
last_pause_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
|
last_pause_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
uint64_t delay_ns;
|
uint64_t delay_ns = 0;
|
||||||
int64_t cnt;
|
int64_t cnt;
|
||||||
bool should_complete;
|
bool should_complete;
|
||||||
|
|
||||||
@ -386,10 +393,12 @@ static void coroutine_fn mirror_run(void *opaque)
|
|||||||
qemu_coroutine_yield();
|
qemu_coroutine_yield();
|
||||||
continue;
|
continue;
|
||||||
} else if (cnt != 0) {
|
} else if (cnt != 0) {
|
||||||
mirror_iteration(s);
|
delay_ns = mirror_iteration(s);
|
||||||
|
if (delay_ns == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
should_complete = false;
|
should_complete = false;
|
||||||
if (s->in_flight == 0 && cnt == 0) {
|
if (s->in_flight == 0 && cnt == 0) {
|
||||||
@ -432,17 +441,10 @@ static void coroutine_fn mirror_run(void *opaque)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
trace_mirror_before_sleep(s, cnt, s->synced);
|
trace_mirror_before_sleep(s, cnt, s->synced, delay_ns);
|
||||||
if (!s->synced) {
|
if (!s->synced) {
|
||||||
/* Publish progress */
|
/* Publish progress */
|
||||||
s->common.offset = (end - cnt) * BDRV_SECTOR_SIZE;
|
s->common.offset = (end - cnt) * BDRV_SECTOR_SIZE;
|
||||||
|
|
||||||
if (s->common.speed) {
|
|
||||||
delay_ns = ratelimit_calculate_delay(&s->limit, sectors_per_chunk);
|
|
||||||
} else {
|
|
||||||
delay_ns = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
block_job_sleep_ns(&s->common, QEMU_CLOCK_REALTIME, delay_ns);
|
block_job_sleep_ns(&s->common, QEMU_CLOCK_REALTIME, delay_ns);
|
||||||
if (block_job_is_cancelled(&s->common)) {
|
if (block_job_is_cancelled(&s->common)) {
|
||||||
break;
|
break;
|
||||||
|
@ -82,7 +82,7 @@ mirror_start(void *bs, void *s, void *co, void *opaque) "bs %p s %p co %p opaque
|
|||||||
mirror_restart_iter(void *s, int64_t cnt) "s %p dirty count %"PRId64
|
mirror_restart_iter(void *s, int64_t cnt) "s %p dirty count %"PRId64
|
||||||
mirror_before_flush(void *s) "s %p"
|
mirror_before_flush(void *s) "s %p"
|
||||||
mirror_before_drain(void *s, int64_t cnt) "s %p dirty count %"PRId64
|
mirror_before_drain(void *s, int64_t cnt) "s %p dirty count %"PRId64
|
||||||
mirror_before_sleep(void *s, int64_t cnt, int synced) "s %p dirty count %"PRId64" synced %d"
|
mirror_before_sleep(void *s, int64_t cnt, int synced, uint64_t delay_ns) "s %p dirty count %"PRId64" synced %d delay %"PRIu64"ns"
|
||||||
mirror_one_iteration(void *s, int64_t sector_num, int nb_sectors) "s %p sector_num %"PRId64" nb_sectors %d"
|
mirror_one_iteration(void *s, int64_t sector_num, int nb_sectors) "s %p sector_num %"PRId64" nb_sectors %d"
|
||||||
mirror_iteration_done(void *s, int64_t sector_num, int nb_sectors, int ret) "s %p sector_num %"PRId64" nb_sectors %d ret %d"
|
mirror_iteration_done(void *s, int64_t sector_num, int nb_sectors, int ret) "s %p sector_num %"PRId64" nb_sectors %d ret %d"
|
||||||
mirror_yield(void *s, int64_t cnt, int buf_free_count, int in_flight) "s %p dirty count %"PRId64" free buffers %d in_flight %d"
|
mirror_yield(void *s, int64_t cnt, int buf_free_count, int in_flight) "s %p dirty count %"PRId64" free buffers %d in_flight %d"
|
||||||
|
Loading…
Reference in New Issue
Block a user