@@ -132,9 +132,10 @@ void bdrv_io_limits_disable(BlockDriverState *bs)
bs->block_timer = NULL;
}
- bs->slice_start = 0;
-
- bs->slice_end = 0;
+ bs->slice_time = 0;
+ bs->slice_start = 0;
+ bs->slice_end = 0;
+ bs->first_time_rw = false;
}
static void bdrv_block_timer(void *opaque)
@@ -151,9 +152,10 @@ void bdrv_io_limits_enable(BlockDriverState *bs)
bs->block_queue = qemu_new_block_queue();
bs->block_timer = qemu_new_timer_ns(vm_clock, bdrv_block_timer, bs);
+ bs->slice_time = BLOCK_IO_SLICE_TIME;
bs->slice_start = qemu_get_clock_ns(vm_clock);
-
- bs->slice_end = bs->slice_start + BLOCK_IO_SLICE_TIME;
+ bs->slice_end = bs->slice_start + bs->slice_time;
+ bs->first_time_rw = true;
}
bool bdrv_io_limits_enabled(BlockDriverState *bs)
@@ -2846,11 +2848,23 @@ static bool
bdrv_exceed_bps_limits(BlockDriverState *bs, int nb_sectors,
/* Calc approx time to dispatch */
wait_time = (bytes_disp + bytes_res) / bps_limit - elapsed_time;
- if (wait) {
- *wait = wait_time * BLOCK_IO_SLICE_TIME * 10;
- }
+ if (!bs->first_time_rw
+ || !qemu_block_queue_is_empty(bs->block_queue)) {
+ if (wait) {
+ *wait = wait_time * BLOCK_IO_SLICE_TIME * 10;
+ }
- return true;
+ return true;
+ } else {
+ bs->slice_time = wait_time * BLOCK_IO_SLICE_TIME * 10;
+ bs->slice_end += bs->slice_time - BLOCK_IO_SLICE_TIME;
+ if (wait) {
+ *wait = 0;
+ }
+
+ bs->first_time_rw = false;
+ return false;
+ }
}
static bool bdrv_exceed_iops_limits(BlockDriverState *bs, bool is_write,
@@ -2895,11 +2909,23 @@ static bool
bdrv_exceed_iops_limits(BlockDriverState *bs, bool is_write,
wait_time = 0;
}
- if (wait) {
- *wait = wait_time * BLOCK_IO_SLICE_TIME * 10;
- }
+ if (!bs->first_time_rw
+ || !qemu_block_queue_is_empty(bs->block_queue)) {
+ if (wait) {
+ *wait = wait_time * BLOCK_IO_SLICE_TIME * 10;
+ }
- return true;
+ return true;
+ } else {
+ bs->slice_time = wait_time * BLOCK_IO_SLICE_TIME * 10;
+ bs->slice_end += bs->slice_time - BLOCK_IO_SLICE_TIME;
+ if (wait) {
+ *wait = 0;
+ }
+
+ bs->first_time_rw = false;
+ return false;
+ }
}
static bool bdrv_exceed_io_limits(BlockDriverState *bs, int nb_sectors,
@@ -2912,10 +2938,10 @@ static bool
bdrv_exceed_io_limits(BlockDriverState *bs, int nb_sectors,
now = qemu_get_clock_ns(vm_clock);
if ((bs->slice_start < now)
&& (bs->slice_end > now)) {
- bs->slice_end = now + BLOCK_IO_SLICE_TIME;
+ bs->slice_end = now + bs->slice_time;
} else {
bs->slice_start = now;
- bs->slice_end = now + BLOCK_IO_SLICE_TIME;
+ bs->slice_end = now + bs->slice_time;
bs->io_disps.bytes[is_write] = 0;
bs->io_disps.bytes[!is_write] = 0;
@@ -199,3 +199,8 @@ bool qemu_block_queue_has_pending(BlockQueue *queue)
{
return !queue->flushing && !QTAILQ_EMPTY(&queue->requests);
}
+
+bool qemu_block_queue_is_empty(BlockQueue *queue)
+{
+ return QTAILQ_EMPTY(&queue->requests);
+}
@@ -56,4 +56,6 @@ void qemu_block_queue_flush(BlockQueue *queue);
bool qemu_block_queue_has_pending(BlockQueue *queue);
+bool qemu_block_queue_is_empty(BlockQueue *queue);
+
#endif /* QEMU_BLOCK_QUEUE_H */
@@ -199,6 +199,7 @@ struct BlockDriverState {
void *sync_aiocb;
/* the time for latest disk I/O */
+ int64_t slice_time;
int64_t slice_start;
int64_t slice_end;
BlockIOLimit io_limits;
@@ -206,6 +207,7 @@ struct BlockDriverState {
BlockQueue *block_queue;
QEMUTimer *block_timer;
bool io_limits_enabled;
+ bool first_time_rw;
/* I/O stats (display with "info blockstats"). */
uint64_t nr_bytes[BDRV_MAX_IOTYPE];
@@ -782,6 +782,8 @@ int do_block_set_io_throttle(Monitor *mon,
bs->io_limits.iops[BLOCK_IO_LIMIT_READ] = iops_rd;
bs->io_limits.iops[BLOCK_IO_LIMIT_WRITE] = iops_wr;
+ bs->slice_time = BLOCK_IO_SLICE_TIME;
+
if (!bs->io_limits_enabled && bdrv_io_limits_enabled(bs)) {
bdrv_io_limits_enable(bs);
} else if (bs->io_limits_enabled && !bdrv_io_limits_enabled(bs)) {