/* * Fsdev Throttle * * Copyright (C) 2016 Huawei Technologies Duesseldorf GmbH * * Author: Pradeep Jagadeesh * * 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" #include "qemu/main-loop.h" #include "qemu/option.h" static void fsdev_throttle_read_timer_cb(void *opaque) { FsThrottle *fst = opaque; qemu_co_enter_next(&fst->throttled_reqs[false], NULL); } static void fsdev_throttle_write_timer_cb(void *opaque) { FsThrottle *fst = opaque; qemu_co_enter_next(&fst->throttled_reqs[true], NULL); } int 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); return throttle_is_valid(&fst->cfg, errp) ? 0 : -1; } 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); } }