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