1 /* 2 * Fsdev Throttle 3 * 4 * Copyright (C) 2016 Huawei Technologies Duesseldorf GmbH 5 * 6 * Author: Pradeep Jagadeesh <pradeep.jagadeesh@huawei.com> 7 * 8 * This work is licensed under the terms of the GNU GPL, version 2 or 9 * (at your option) any later version. 10 * 11 * See the COPYING file in the top-level directory for details. 12 * 13 */ 14 15 #include "qemu/osdep.h" 16 #include "qemu/error-report.h" 17 #include "qemu-fsdev-throttle.h" 18 #include "qemu/iov.h" 19 #include "qemu/option.h" 20 21 static void fsdev_throttle_read_timer_cb(void *opaque) 22 { 23 FsThrottle *fst = opaque; 24 qemu_co_enter_next(&fst->throttled_reqs[false], NULL); 25 } 26 27 static void fsdev_throttle_write_timer_cb(void *opaque) 28 { 29 FsThrottle *fst = opaque; 30 qemu_co_enter_next(&fst->throttled_reqs[true], NULL); 31 } 32 33 void fsdev_throttle_parse_opts(QemuOpts *opts, FsThrottle *fst, Error **errp) 34 { 35 throttle_config_init(&fst->cfg); 36 fst->cfg.buckets[THROTTLE_BPS_TOTAL].avg = 37 qemu_opt_get_number(opts, "throttling.bps-total", 0); 38 fst->cfg.buckets[THROTTLE_BPS_READ].avg = 39 qemu_opt_get_number(opts, "throttling.bps-read", 0); 40 fst->cfg.buckets[THROTTLE_BPS_WRITE].avg = 41 qemu_opt_get_number(opts, "throttling.bps-write", 0); 42 fst->cfg.buckets[THROTTLE_OPS_TOTAL].avg = 43 qemu_opt_get_number(opts, "throttling.iops-total", 0); 44 fst->cfg.buckets[THROTTLE_OPS_READ].avg = 45 qemu_opt_get_number(opts, "throttling.iops-read", 0); 46 fst->cfg.buckets[THROTTLE_OPS_WRITE].avg = 47 qemu_opt_get_number(opts, "throttling.iops-write", 0); 48 49 fst->cfg.buckets[THROTTLE_BPS_TOTAL].max = 50 qemu_opt_get_number(opts, "throttling.bps-total-max", 0); 51 fst->cfg.buckets[THROTTLE_BPS_READ].max = 52 qemu_opt_get_number(opts, "throttling.bps-read-max", 0); 53 fst->cfg.buckets[THROTTLE_BPS_WRITE].max = 54 qemu_opt_get_number(opts, "throttling.bps-write-max", 0); 55 fst->cfg.buckets[THROTTLE_OPS_TOTAL].max = 56 qemu_opt_get_number(opts, "throttling.iops-total-max", 0); 57 fst->cfg.buckets[THROTTLE_OPS_READ].max = 58 qemu_opt_get_number(opts, "throttling.iops-read-max", 0); 59 fst->cfg.buckets[THROTTLE_OPS_WRITE].max = 60 qemu_opt_get_number(opts, "throttling.iops-write-max", 0); 61 62 fst->cfg.buckets[THROTTLE_BPS_TOTAL].burst_length = 63 qemu_opt_get_number(opts, "throttling.bps-total-max-length", 1); 64 fst->cfg.buckets[THROTTLE_BPS_READ].burst_length = 65 qemu_opt_get_number(opts, "throttling.bps-read-max-length", 1); 66 fst->cfg.buckets[THROTTLE_BPS_WRITE].burst_length = 67 qemu_opt_get_number(opts, "throttling.bps-write-max-length", 1); 68 fst->cfg.buckets[THROTTLE_OPS_TOTAL].burst_length = 69 qemu_opt_get_number(opts, "throttling.iops-total-max-length", 1); 70 fst->cfg.buckets[THROTTLE_OPS_READ].burst_length = 71 qemu_opt_get_number(opts, "throttling.iops-read-max-length", 1); 72 fst->cfg.buckets[THROTTLE_OPS_WRITE].burst_length = 73 qemu_opt_get_number(opts, "throttling.iops-write-max-length", 1); 74 fst->cfg.op_size = 75 qemu_opt_get_number(opts, "throttling.iops-size", 0); 76 77 throttle_is_valid(&fst->cfg, errp); 78 } 79 80 void fsdev_throttle_init(FsThrottle *fst) 81 { 82 if (throttle_enabled(&fst->cfg)) { 83 throttle_init(&fst->ts); 84 throttle_timers_init(&fst->tt, 85 qemu_get_aio_context(), 86 QEMU_CLOCK_REALTIME, 87 fsdev_throttle_read_timer_cb, 88 fsdev_throttle_write_timer_cb, 89 fst); 90 throttle_config(&fst->ts, QEMU_CLOCK_REALTIME, &fst->cfg); 91 qemu_co_queue_init(&fst->throttled_reqs[0]); 92 qemu_co_queue_init(&fst->throttled_reqs[1]); 93 } 94 } 95 96 void coroutine_fn fsdev_co_throttle_request(FsThrottle *fst, bool is_write, 97 struct iovec *iov, int iovcnt) 98 { 99 if (throttle_enabled(&fst->cfg)) { 100 if (throttle_schedule_timer(&fst->ts, &fst->tt, is_write) || 101 !qemu_co_queue_empty(&fst->throttled_reqs[is_write])) { 102 qemu_co_queue_wait(&fst->throttled_reqs[is_write], NULL); 103 } 104 105 throttle_account(&fst->ts, is_write, iov_size(iov, iovcnt)); 106 107 if (!qemu_co_queue_empty(&fst->throttled_reqs[is_write]) && 108 !throttle_schedule_timer(&fst->ts, &fst->tt, is_write)) { 109 qemu_co_queue_next(&fst->throttled_reqs[is_write]); 110 } 111 } 112 } 113 114 void fsdev_throttle_cleanup(FsThrottle *fst) 115 { 116 if (throttle_enabled(&fst->cfg)) { 117 throttle_timers_destroy(&fst->tt); 118 } 119 } 120