block: tidy ThrottleGroupMember initializations
[qemu/ericb.git] / block / throttle-groups.c
blob7749cf043f5306dcb69a2363a862ae350a2dfb86
1 /*
2 * QEMU block throttling group infrastructure
4 * Copyright (C) Nodalink, EURL. 2014
5 * Copyright (C) Igalia, S.L. 2015
7 * Authors:
8 * BenoƮt Canet <benoit.canet@nodalink.com>
9 * Alberto Garcia <berto@igalia.com>
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License as
13 * published by the Free Software Foundation; either version 2 or
14 * (at your option) version 3 of the License.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, see <http://www.gnu.org/licenses/>.
25 #include "qemu/osdep.h"
26 #include "sysemu/block-backend.h"
27 #include "block/throttle-groups.h"
28 #include "qemu/queue.h"
29 #include "qemu/thread.h"
30 #include "sysemu/qtest.h"
32 /* The ThrottleGroup structure (with its ThrottleState) is shared
33 * among different ThrottleGroupMembers and it's independent from
34 * AioContext, so in order to use it from different threads it needs
35 * its own locking.
37 * This locking is however handled internally in this file, so it's
38 * transparent to outside users.
40 * The whole ThrottleGroup structure is private and invisible to
41 * outside users, that only use it through its ThrottleState.
43 * In addition to the ThrottleGroup structure, ThrottleGroupMember has
44 * fields that need to be accessed by other members of the group and
45 * therefore also need to be protected by this lock. Once a
46 * ThrottleGroupMember is registered in a group those fields can be accessed
47 * by other threads any time.
49 * Again, all this is handled internally and is mostly transparent to
50 * the outside. The 'throttle_timers' field however has an additional
51 * constraint because it may be temporarily invalid (see for example
52 * blk_set_aio_context()). Therefore in this file a thread will
53 * access some other ThrottleGroupMember's timers only after verifying that
54 * that ThrottleGroupMember has throttled requests in the queue.
56 typedef struct ThrottleGroup {
57 char *name; /* This is constant during the lifetime of the group */
59 QemuMutex lock; /* This lock protects the following four fields */
60 ThrottleState ts;
61 QLIST_HEAD(, ThrottleGroupMember) head;
62 ThrottleGroupMember *tokens[2];
63 bool any_timer_armed[2];
64 QEMUClockType clock_type;
66 /* These two are protected by the global throttle_groups_lock */
67 unsigned refcount;
68 QTAILQ_ENTRY(ThrottleGroup) list;
69 } ThrottleGroup;
71 static QemuMutex throttle_groups_lock;
72 static QTAILQ_HEAD(, ThrottleGroup) throttle_groups =
73 QTAILQ_HEAD_INITIALIZER(throttle_groups);
75 /* Increments the reference count of a ThrottleGroup given its name.
77 * If no ThrottleGroup is found with the given name a new one is
78 * created.
80 * @name: the name of the ThrottleGroup
81 * @ret: the ThrottleState member of the ThrottleGroup
83 ThrottleState *throttle_group_incref(const char *name)
85 ThrottleGroup *tg = NULL;
86 ThrottleGroup *iter;
88 qemu_mutex_lock(&throttle_groups_lock);
90 /* Look for an existing group with that name */
91 QTAILQ_FOREACH(iter, &throttle_groups, list) {
92 if (!strcmp(name, iter->name)) {
93 tg = iter;
94 break;
98 /* Create a new one if not found */
99 if (!tg) {
100 tg = g_new0(ThrottleGroup, 1);
101 tg->name = g_strdup(name);
102 tg->clock_type = QEMU_CLOCK_REALTIME;
104 if (qtest_enabled()) {
105 /* For testing block IO throttling only */
106 tg->clock_type = QEMU_CLOCK_VIRTUAL;
108 qemu_mutex_init(&tg->lock);
109 throttle_init(&tg->ts);
110 QLIST_INIT(&tg->head);
112 QTAILQ_INSERT_TAIL(&throttle_groups, tg, list);
115 tg->refcount++;
117 qemu_mutex_unlock(&throttle_groups_lock);
119 return &tg->ts;
122 /* Decrease the reference count of a ThrottleGroup.
124 * When the reference count reaches zero the ThrottleGroup is
125 * destroyed.
127 * @ts: The ThrottleGroup to unref, given by its ThrottleState member
129 void throttle_group_unref(ThrottleState *ts)
131 ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
133 qemu_mutex_lock(&throttle_groups_lock);
134 if (--tg->refcount == 0) {
135 QTAILQ_REMOVE(&throttle_groups, tg, list);
136 qemu_mutex_destroy(&tg->lock);
137 g_free(tg->name);
138 g_free(tg);
140 qemu_mutex_unlock(&throttle_groups_lock);
143 /* Get the name from a ThrottleGroupMember's group. The name (and the pointer)
144 * is guaranteed to remain constant during the lifetime of the group.
146 * @tgm: a ThrottleGroupMember
147 * @ret: the name of the group.
149 const char *throttle_group_get_name(ThrottleGroupMember *tgm)
151 ThrottleGroup *tg = container_of(tgm->throttle_state, ThrottleGroup, ts);
152 return tg->name;
155 /* Return the next ThrottleGroupMember in the round-robin sequence, simulating
156 * a circular list.
158 * This assumes that tg->lock is held.
160 * @tgm: the current ThrottleGroupMember
161 * @ret: the next ThrottleGroupMember in the sequence
163 static ThrottleGroupMember *throttle_group_next_tgm(ThrottleGroupMember *tgm)
165 ThrottleState *ts = tgm->throttle_state;
166 ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
167 ThrottleGroupMember *next = QLIST_NEXT(tgm, round_robin);
169 if (!next) {
170 next = QLIST_FIRST(&tg->head);
173 return next;
177 * Return whether a ThrottleGroupMember has pending requests.
179 * This assumes that tg->lock is held.
181 * @tgm: the ThrottleGroupMember
182 * @is_write: the type of operation (read/write)
183 * @ret: whether the ThrottleGroupMember has pending requests.
185 static inline bool tgm_has_pending_reqs(ThrottleGroupMember *tgm,
186 bool is_write)
188 return tgm->pending_reqs[is_write];
191 /* Return the next ThrottleGroupMember in the round-robin sequence with pending
192 * I/O requests.
194 * This assumes that tg->lock is held.
196 * @tgm: the current ThrottleGroupMember
197 * @is_write: the type of operation (read/write)
198 * @ret: the next ThrottleGroupMember with pending requests, or tgm if
199 * there is none.
201 static ThrottleGroupMember *next_throttle_token(ThrottleGroupMember *tgm,
202 bool is_write)
204 ThrottleState *ts = tgm->throttle_state;
205 ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
206 ThrottleGroupMember *token, *start;
208 start = token = tg->tokens[is_write];
210 /* get next bs round in round robin style */
211 token = throttle_group_next_tgm(token);
212 while (token != start && !tgm_has_pending_reqs(token, is_write)) {
213 token = throttle_group_next_tgm(token);
216 /* If no IO are queued for scheduling on the next round robin token
217 * then decide the token is the current tgm because chances are
218 * the current tgm got the current request queued.
220 if (token == start && !tgm_has_pending_reqs(token, is_write)) {
221 token = tgm;
224 /* Either we return the original TGM, or one with pending requests */
225 assert(token == tgm || tgm_has_pending_reqs(token, is_write));
227 return token;
230 /* Check if the next I/O request for a ThrottleGroupMember needs to be
231 * throttled or not. If there's no timer set in this group, set one and update
232 * the token accordingly.
234 * This assumes that tg->lock is held.
236 * @tgm: the current ThrottleGroupMember
237 * @is_write: the type of operation (read/write)
238 * @ret: whether the I/O request needs to be throttled or not
240 static bool throttle_group_schedule_timer(ThrottleGroupMember *tgm,
241 bool is_write)
243 ThrottleState *ts = tgm->throttle_state;
244 ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
245 ThrottleTimers *tt = &tgm->throttle_timers;
246 bool must_wait;
248 if (atomic_read(&tgm->io_limits_disabled)) {
249 return false;
252 /* Check if any of the timers in this group is already armed */
253 if (tg->any_timer_armed[is_write]) {
254 return true;
257 must_wait = throttle_schedule_timer(ts, tt, is_write);
259 /* If a timer just got armed, set tgm as the current token */
260 if (must_wait) {
261 tg->tokens[is_write] = tgm;
262 tg->any_timer_armed[is_write] = true;
265 return must_wait;
268 /* Start the next pending I/O request for a ThrottleGroupMember. Return whether
269 * any request was actually pending.
271 * @tgm: the current ThrottleGroupMember
272 * @is_write: the type of operation (read/write)
274 static bool coroutine_fn throttle_group_co_restart_queue(ThrottleGroupMember *tgm,
275 bool is_write)
277 bool ret;
279 qemu_co_mutex_lock(&tgm->throttled_reqs_lock);
280 ret = qemu_co_queue_next(&tgm->throttled_reqs[is_write]);
281 qemu_co_mutex_unlock(&tgm->throttled_reqs_lock);
283 return ret;
286 /* Look for the next pending I/O request and schedule it.
288 * This assumes that tg->lock is held.
290 * @tgm: the current ThrottleGroupMember
291 * @is_write: the type of operation (read/write)
293 static void schedule_next_request(ThrottleGroupMember *tgm, bool is_write)
295 ThrottleState *ts = tgm->throttle_state;
296 ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
297 bool must_wait;
298 ThrottleGroupMember *token;
300 /* Check if there's any pending request to schedule next */
301 token = next_throttle_token(tgm, is_write);
302 if (!tgm_has_pending_reqs(token, is_write)) {
303 return;
306 /* Set a timer for the request if it needs to be throttled */
307 must_wait = throttle_group_schedule_timer(token, is_write);
309 /* If it doesn't have to wait, queue it for immediate execution */
310 if (!must_wait) {
311 /* Give preference to requests from the current tgm */
312 if (qemu_in_coroutine() &&
313 throttle_group_co_restart_queue(tgm, is_write)) {
314 token = tgm;
315 } else {
316 ThrottleTimers *tt = &token->throttle_timers;
317 int64_t now = qemu_clock_get_ns(tg->clock_type);
318 timer_mod(tt->timers[is_write], now);
319 tg->any_timer_armed[is_write] = true;
321 tg->tokens[is_write] = token;
325 /* Check if an I/O request needs to be throttled, wait and set a timer
326 * if necessary, and schedule the next request using a round robin
327 * algorithm.
329 * @tgm: the current ThrottleGroupMember
330 * @bytes: the number of bytes for this I/O
331 * @is_write: the type of operation (read/write)
333 void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember *tgm,
334 unsigned int bytes,
335 bool is_write)
337 bool must_wait;
338 ThrottleGroupMember *token;
339 ThrottleGroup *tg = container_of(tgm->throttle_state, ThrottleGroup, ts);
340 qemu_mutex_lock(&tg->lock);
342 /* First we check if this I/O has to be throttled. */
343 token = next_throttle_token(tgm, is_write);
344 must_wait = throttle_group_schedule_timer(token, is_write);
346 /* Wait if there's a timer set or queued requests of this type */
347 if (must_wait || tgm->pending_reqs[is_write]) {
348 tgm->pending_reqs[is_write]++;
349 qemu_mutex_unlock(&tg->lock);
350 qemu_co_mutex_lock(&tgm->throttled_reqs_lock);
351 qemu_co_queue_wait(&tgm->throttled_reqs[is_write],
352 &tgm->throttled_reqs_lock);
353 qemu_co_mutex_unlock(&tgm->throttled_reqs_lock);
354 qemu_mutex_lock(&tg->lock);
355 tgm->pending_reqs[is_write]--;
358 /* The I/O will be executed, so do the accounting */
359 throttle_account(tgm->throttle_state, is_write, bytes);
361 /* Schedule the next request */
362 schedule_next_request(tgm, is_write);
364 qemu_mutex_unlock(&tg->lock);
367 typedef struct {
368 ThrottleGroupMember *tgm;
369 bool is_write;
370 } RestartData;
372 static void coroutine_fn throttle_group_restart_queue_entry(void *opaque)
374 RestartData *data = opaque;
375 ThrottleGroupMember *tgm = data->tgm;
376 ThrottleState *ts = tgm->throttle_state;
377 ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
378 bool is_write = data->is_write;
379 bool empty_queue;
381 empty_queue = !throttle_group_co_restart_queue(tgm, is_write);
383 /* If the request queue was empty then we have to take care of
384 * scheduling the next one */
385 if (empty_queue) {
386 qemu_mutex_lock(&tg->lock);
387 schedule_next_request(tgm, is_write);
388 qemu_mutex_unlock(&tg->lock);
392 static void throttle_group_restart_queue(ThrottleGroupMember *tgm, bool is_write)
394 Coroutine *co;
395 RestartData rd = {
396 .tgm = tgm,
397 .is_write = is_write
400 co = qemu_coroutine_create(throttle_group_restart_queue_entry, &rd);
401 aio_co_enter(tgm->aio_context, co);
404 void throttle_group_restart_tgm(ThrottleGroupMember *tgm)
406 if (tgm->throttle_state) {
407 throttle_group_restart_queue(tgm, 0);
408 throttle_group_restart_queue(tgm, 1);
412 /* Update the throttle configuration for a particular group. Similar
413 * to throttle_config(), but guarantees atomicity within the
414 * throttling group.
416 * @tgm: a ThrottleGroupMember that is a member of the group
417 * @cfg: the configuration to set
419 void throttle_group_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg)
421 ThrottleState *ts = tgm->throttle_state;
422 ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
423 qemu_mutex_lock(&tg->lock);
424 throttle_config(ts, tg->clock_type, cfg);
425 qemu_mutex_unlock(&tg->lock);
427 throttle_group_restart_tgm(tgm);
430 /* Get the throttle configuration from a particular group. Similar to
431 * throttle_get_config(), but guarantees atomicity within the
432 * throttling group.
434 * @tgm: a ThrottleGroupMember that is a member of the group
435 * @cfg: the configuration will be written here
437 void throttle_group_get_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg)
439 ThrottleState *ts = tgm->throttle_state;
440 ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
441 qemu_mutex_lock(&tg->lock);
442 throttle_get_config(ts, cfg);
443 qemu_mutex_unlock(&tg->lock);
446 /* ThrottleTimers callback. This wakes up a request that was waiting
447 * because it had been throttled.
449 * @tgm: the ThrottleGroupMember whose request had been throttled
450 * @is_write: the type of operation (read/write)
452 static void timer_cb(ThrottleGroupMember *tgm, bool is_write)
454 ThrottleState *ts = tgm->throttle_state;
455 ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
457 /* The timer has just been fired, so we can update the flag */
458 qemu_mutex_lock(&tg->lock);
459 tg->any_timer_armed[is_write] = false;
460 qemu_mutex_unlock(&tg->lock);
462 /* Run the request that was waiting for this timer */
463 throttle_group_restart_queue(tgm, is_write);
466 static void read_timer_cb(void *opaque)
468 timer_cb(opaque, false);
471 static void write_timer_cb(void *opaque)
473 timer_cb(opaque, true);
476 /* Register a ThrottleGroupMember from the throttling group, also initializing
477 * its timers and updating its throttle_state pointer to point to it. If a
478 * throttling group with that name does not exist yet, it will be created.
480 * @tgm: the ThrottleGroupMember to insert
481 * @groupname: the name of the group
482 * @ctx: the AioContext to use
484 void throttle_group_register_tgm(ThrottleGroupMember *tgm,
485 const char *groupname,
486 AioContext *ctx)
488 int i;
489 ThrottleState *ts = throttle_group_incref(groupname);
490 ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
492 tgm->throttle_state = ts;
493 tgm->aio_context = ctx;
495 qemu_mutex_lock(&tg->lock);
496 /* If the ThrottleGroup is new set this ThrottleGroupMember as the token */
497 for (i = 0; i < 2; i++) {
498 if (!tg->tokens[i]) {
499 tg->tokens[i] = tgm;
503 QLIST_INSERT_HEAD(&tg->head, tgm, round_robin);
505 throttle_timers_init(&tgm->throttle_timers,
506 tgm->aio_context,
507 tg->clock_type,
508 read_timer_cb,
509 write_timer_cb,
510 tgm);
511 qemu_co_mutex_init(&tgm->throttled_reqs_lock);
512 qemu_co_queue_init(&tgm->throttled_reqs[0]);
513 qemu_co_queue_init(&tgm->throttled_reqs[1]);
515 qemu_mutex_unlock(&tg->lock);
518 /* Unregister a ThrottleGroupMember from its group, removing it from the list,
519 * destroying the timers and setting the throttle_state pointer to NULL.
521 * The ThrottleGroupMember must not have pending throttled requests, so the
522 * caller has to drain them first.
524 * The group will be destroyed if it's empty after this operation.
526 * @tgm the ThrottleGroupMember to remove
528 void throttle_group_unregister_tgm(ThrottleGroupMember *tgm)
530 ThrottleState *ts = tgm->throttle_state;
531 ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
532 ThrottleGroupMember *token;
533 int i;
535 assert(tgm->pending_reqs[0] == 0 && tgm->pending_reqs[1] == 0);
536 assert(qemu_co_queue_empty(&tgm->throttled_reqs[0]));
537 assert(qemu_co_queue_empty(&tgm->throttled_reqs[1]));
539 qemu_mutex_lock(&tg->lock);
540 for (i = 0; i < 2; i++) {
541 if (tg->tokens[i] == tgm) {
542 token = throttle_group_next_tgm(tgm);
543 /* Take care of the case where this is the last tgm in the group */
544 if (token == tgm) {
545 token = NULL;
547 tg->tokens[i] = token;
551 /* remove the current tgm from the list */
552 QLIST_REMOVE(tgm, round_robin);
553 throttle_timers_destroy(&tgm->throttle_timers);
554 qemu_mutex_unlock(&tg->lock);
556 throttle_group_unref(&tg->ts);
557 tgm->throttle_state = NULL;
560 void throttle_group_attach_aio_context(ThrottleGroupMember *tgm,
561 AioContext *new_context)
563 ThrottleTimers *tt = &tgm->throttle_timers;
564 throttle_timers_attach_aio_context(tt, new_context);
565 tgm->aio_context = new_context;
568 void throttle_group_detach_aio_context(ThrottleGroupMember *tgm)
570 ThrottleTimers *tt = &tgm->throttle_timers;
571 throttle_timers_detach_aio_context(tt);
572 tgm->aio_context = NULL;
575 static void throttle_groups_init(void)
577 qemu_mutex_init(&throttle_groups_lock);
580 block_init(throttle_groups_init);