| /* | |
| * 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" | |
| #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, | |
| ThrottleDirection direction, | |
| struct iovec *iov, int iovcnt) | |
| { | |
| assert(direction < THROTTLE_MAX); | |
| if (throttle_enabled(&fst->cfg)) { | |
| if (throttle_schedule_timer(&fst->ts, &fst->tt, direction) || | |
| !qemu_co_queue_empty(&fst->throttled_reqs[direction])) { | |
| qemu_co_queue_wait(&fst->throttled_reqs[direction], NULL); | |
| } | |
| throttle_account(&fst->ts, direction, iov_size(iov, iovcnt)); | |
| if (!qemu_co_queue_empty(&fst->throttled_reqs[direction]) && | |
| !throttle_schedule_timer(&fst->ts, &fst->tt, direction)) { | |
| qemu_co_queue_next(&fst->throttled_reqs[direction]); | |
| } | |
| } | |
| } | |
| void fsdev_throttle_cleanup(FsThrottle *fst) | |
| { | |
| if (throttle_enabled(&fst->cfg)) { | |
| throttle_timers_destroy(&fst->tt); | |
| } | |
| } |