|
@@ -0,0 +1,118 @@
|
|
|
|
+/*
|
|
|
|
+ * 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, &fst->tt, &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);
|
|
|
|
+ }
|
|
|
|
+}
|