27e4cf1303
throttle_config() cancels the timers of the calling BlockBackend. This doesn't make sense because other BlockBackends in the group remain untouched. There's no need to cancel the timers in the one specific BlockBackend so let's not do that. Throttled requests will run as scheduled and future requests will follow the new configuration. This also allows a throttle group's configuration to be changed even when it has no members. Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
119 lines
4.4 KiB
C
119 lines
4.4 KiB
C
/*
|
|
* Fsdev Throttle
|
|
*
|
|
* Copyright (C) 2016 Huawei Technologies Duesseldorf GmbH
|
|
*
|
|
* Author: Pradeep Jagadeesh <pradeep.jagadeesh@huawei.com>
|
|
*
|
|
* This work is licensed under the terms of the GNU GPL, version 2 or
|
|
* (at your option) any later version.
|
|
*
|
|
* See the COPYING file in the top-level directory for details.
|
|
*
|
|
*/
|
|
|
|
#include "qemu/osdep.h"
|
|
#include "qemu/error-report.h"
|
|
#include "qemu-fsdev-throttle.h"
|
|
#include "qemu/iov.h"
|
|
|
|
static void fsdev_throttle_read_timer_cb(void *opaque)
|
|
{
|
|
FsThrottle *fst = opaque;
|
|
qemu_co_enter_next(&fst->throttled_reqs[false]);
|
|
}
|
|
|
|
static void fsdev_throttle_write_timer_cb(void *opaque)
|
|
{
|
|
FsThrottle *fst = opaque;
|
|
qemu_co_enter_next(&fst->throttled_reqs[true]);
|
|
}
|
|
|
|
void fsdev_throttle_parse_opts(QemuOpts *opts, FsThrottle *fst, Error **errp)
|
|
{
|
|
throttle_config_init(&fst->cfg);
|
|
fst->cfg.buckets[THROTTLE_BPS_TOTAL].avg =
|
|
qemu_opt_get_number(opts, "throttling.bps-total", 0);
|
|
fst->cfg.buckets[THROTTLE_BPS_READ].avg =
|
|
qemu_opt_get_number(opts, "throttling.bps-read", 0);
|
|
fst->cfg.buckets[THROTTLE_BPS_WRITE].avg =
|
|
qemu_opt_get_number(opts, "throttling.bps-write", 0);
|
|
fst->cfg.buckets[THROTTLE_OPS_TOTAL].avg =
|
|
qemu_opt_get_number(opts, "throttling.iops-total", 0);
|
|
fst->cfg.buckets[THROTTLE_OPS_READ].avg =
|
|
qemu_opt_get_number(opts, "throttling.iops-read", 0);
|
|
fst->cfg.buckets[THROTTLE_OPS_WRITE].avg =
|
|
qemu_opt_get_number(opts, "throttling.iops-write", 0);
|
|
|
|
fst->cfg.buckets[THROTTLE_BPS_TOTAL].max =
|
|
qemu_opt_get_number(opts, "throttling.bps-total-max", 0);
|
|
fst->cfg.buckets[THROTTLE_BPS_READ].max =
|
|
qemu_opt_get_number(opts, "throttling.bps-read-max", 0);
|
|
fst->cfg.buckets[THROTTLE_BPS_WRITE].max =
|
|
qemu_opt_get_number(opts, "throttling.bps-write-max", 0);
|
|
fst->cfg.buckets[THROTTLE_OPS_TOTAL].max =
|
|
qemu_opt_get_number(opts, "throttling.iops-total-max", 0);
|
|
fst->cfg.buckets[THROTTLE_OPS_READ].max =
|
|
qemu_opt_get_number(opts, "throttling.iops-read-max", 0);
|
|
fst->cfg.buckets[THROTTLE_OPS_WRITE].max =
|
|
qemu_opt_get_number(opts, "throttling.iops-write-max", 0);
|
|
|
|
fst->cfg.buckets[THROTTLE_BPS_TOTAL].burst_length =
|
|
qemu_opt_get_number(opts, "throttling.bps-total-max-length", 1);
|
|
fst->cfg.buckets[THROTTLE_BPS_READ].burst_length =
|
|
qemu_opt_get_number(opts, "throttling.bps-read-max-length", 1);
|
|
fst->cfg.buckets[THROTTLE_BPS_WRITE].burst_length =
|
|
qemu_opt_get_number(opts, "throttling.bps-write-max-length", 1);
|
|
fst->cfg.buckets[THROTTLE_OPS_TOTAL].burst_length =
|
|
qemu_opt_get_number(opts, "throttling.iops-total-max-length", 1);
|
|
fst->cfg.buckets[THROTTLE_OPS_READ].burst_length =
|
|
qemu_opt_get_number(opts, "throttling.iops-read-max-length", 1);
|
|
fst->cfg.buckets[THROTTLE_OPS_WRITE].burst_length =
|
|
qemu_opt_get_number(opts, "throttling.iops-write-max-length", 1);
|
|
fst->cfg.op_size =
|
|
qemu_opt_get_number(opts, "throttling.iops-size", 0);
|
|
|
|
throttle_is_valid(&fst->cfg, errp);
|
|
}
|
|
|
|
void fsdev_throttle_init(FsThrottle *fst)
|
|
{
|
|
if (throttle_enabled(&fst->cfg)) {
|
|
throttle_init(&fst->ts);
|
|
throttle_timers_init(&fst->tt,
|
|
qemu_get_aio_context(),
|
|
QEMU_CLOCK_REALTIME,
|
|
fsdev_throttle_read_timer_cb,
|
|
fsdev_throttle_write_timer_cb,
|
|
fst);
|
|
throttle_config(&fst->ts, QEMU_CLOCK_REALTIME, &fst->cfg);
|
|
qemu_co_queue_init(&fst->throttled_reqs[0]);
|
|
qemu_co_queue_init(&fst->throttled_reqs[1]);
|
|
}
|
|
}
|
|
|
|
void coroutine_fn fsdev_co_throttle_request(FsThrottle *fst, bool is_write,
|
|
struct iovec *iov, int iovcnt)
|
|
{
|
|
if (throttle_enabled(&fst->cfg)) {
|
|
if (throttle_schedule_timer(&fst->ts, &fst->tt, is_write) ||
|
|
!qemu_co_queue_empty(&fst->throttled_reqs[is_write])) {
|
|
qemu_co_queue_wait(&fst->throttled_reqs[is_write], NULL);
|
|
}
|
|
|
|
throttle_account(&fst->ts, is_write, iov_size(iov, iovcnt));
|
|
|
|
if (!qemu_co_queue_empty(&fst->throttled_reqs[is_write]) &&
|
|
!throttle_schedule_timer(&fst->ts, &fst->tt, is_write)) {
|
|
qemu_co_queue_next(&fst->throttled_reqs[is_write]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void fsdev_throttle_cleanup(FsThrottle *fst)
|
|
{
|
|
if (throttle_enabled(&fst->cfg)) {
|
|
throttle_timers_destroy(&fst->tt);
|
|
}
|
|
}
|