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/main-loop.h" 20 #include "qemu/option.h" 21 22 static void fsdev_throttle_read_timer_cb(void *opaque) 23 { 24 FsThrottle *fst = opaque; 25 qemu_co_enter_next(&fst->throttled_reqs[false], NULL); 26 } 27 28 static void fsdev_throttle_write_timer_cb(void *opaque) 29 { 30 FsThrottle *fst = opaque; 31 qemu_co_enter_next(&fst->throttled_reqs[true], NULL); 32 } 33 34 int fsdev_throttle_parse_opts(QemuOpts *opts, FsThrottle *fst, Error **errp) 35 { 36 throttle_config_init(&fst->cfg); 37 fst->cfg.buckets[THROTTLE_BPS_TOTAL].avg = 38 qemu_opt_get_number(opts, "throttling.bps-total", 0); 39 fst->cfg.buckets[THROTTLE_BPS_READ].avg = 40 qemu_opt_get_number(opts, "throttling.bps-read", 0); 41 fst->cfg.buckets[THROTTLE_BPS_WRITE].avg = 42 qemu_opt_get_number(opts, "throttling.bps-write", 0); 43 fst->cfg.buckets[THROTTLE_OPS_TOTAL].avg = 44 qemu_opt_get_number(opts, "throttling.iops-total", 0); 45 fst->cfg.buckets[THROTTLE_OPS_READ].avg = 46 qemu_opt_get_number(opts, "throttling.iops-read", 0); 47 fst->cfg.buckets[THROTTLE_OPS_WRITE].avg = 48 qemu_opt_get_number(opts, "throttling.iops-write", 0); 49 50 fst->cfg.buckets[THROTTLE_BPS_TOTAL].max = 51 qemu_opt_get_number(opts, "throttling.bps-total-max", 0); 52 fst->cfg.buckets[THROTTLE_BPS_READ].max = 53 qemu_opt_get_number(opts, "throttling.bps-read-max", 0); 54 fst->cfg.buckets[THROTTLE_BPS_WRITE].max = 55 qemu_opt_get_number(opts, "throttling.bps-write-max", 0); 56 fst->cfg.buckets[THROTTLE_OPS_TOTAL].max = 57 qemu_opt_get_number(opts, "throttling.iops-total-max", 0); 58 fst->cfg.buckets[THROTTLE_OPS_READ].max = 59 qemu_opt_get_number(opts, "throttling.iops-read-max", 0); 60 fst->cfg.buckets[THROTTLE_OPS_WRITE].max = 61 qemu_opt_get_number(opts, "throttling.iops-write-max", 0); 62 63 fst->cfg.buckets[THROTTLE_BPS_TOTAL].burst_length = 64 qemu_opt_get_number(opts, "throttling.bps-total-max-length", 1); 65 fst->cfg.buckets[THROTTLE_BPS_READ].burst_length = 66 qemu_opt_get_number(opts, "throttling.bps-read-max-length", 1); 67 fst->cfg.buckets[THROTTLE_BPS_WRITE].burst_length = 68 qemu_opt_get_number(opts, "throttling.bps-write-max-length", 1); 69 fst->cfg.buckets[THROTTLE_OPS_TOTAL].burst_length = 70 qemu_opt_get_number(opts, "throttling.iops-total-max-length", 1); 71 fst->cfg.buckets[THROTTLE_OPS_READ].burst_length = 72 qemu_opt_get_number(opts, "throttling.iops-read-max-length", 1); 73 fst->cfg.buckets[THROTTLE_OPS_WRITE].burst_length = 74 qemu_opt_get_number(opts, "throttling.iops-write-max-length", 1); 75 fst->cfg.op_size = 76 qemu_opt_get_number(opts, "throttling.iops-size", 0); 77 78 return throttle_is_valid(&fst->cfg, errp) ? 0 : -1; 79 } 80 81 void fsdev_throttle_init(FsThrottle *fst) 82 { 83 if (throttle_enabled(&fst->cfg)) { 84 throttle_init(&fst->ts); 85 throttle_timers_init(&fst->tt, 86 qemu_get_aio_context(), 87 QEMU_CLOCK_REALTIME, 88 fsdev_throttle_read_timer_cb, 89 fsdev_throttle_write_timer_cb, 90 fst); 91 throttle_config(&fst->ts, QEMU_CLOCK_REALTIME, &fst->cfg); 92 qemu_co_queue_init(&fst->throttled_reqs[0]); 93 qemu_co_queue_init(&fst->throttled_reqs[1]); 94 } 95 } 96 97 void coroutine_fn fsdev_co_throttle_request(FsThrottle *fst, 98 ThrottleDirection direction, 99 struct iovec *iov, int iovcnt) 100 { 101 assert(direction < THROTTLE_MAX); 102 if (throttle_enabled(&fst->cfg)) { 103 if (throttle_schedule_timer(&fst->ts, &fst->tt, direction) || 104 !qemu_co_queue_empty(&fst->throttled_reqs[direction])) { 105 qemu_co_queue_wait(&fst->throttled_reqs[direction], NULL); 106 } 107 108 throttle_account(&fst->ts, direction, iov_size(iov, iovcnt)); 109 110 if (!qemu_co_queue_empty(&fst->throttled_reqs[direction]) && 111 !throttle_schedule_timer(&fst->ts, &fst->tt, direction)) { 112 qemu_co_queue_next(&fst->throttled_reqs[direction]); 113 } 114 } 115 } 116 117 void fsdev_throttle_cleanup(FsThrottle *fst) 118 { 119 if (throttle_enabled(&fst->cfg)) { 120 throttle_timers_destroy(&fst->tt); 121 } 122 } 123