From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:52203) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XbUnL-0004CK-Tm for qemu-devel@nongnu.org; Tue, 07 Oct 2014 09:27:20 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1XbUnG-0007ij-LA for qemu-devel@nongnu.org; Tue, 07 Oct 2014 09:27:15 -0400 Received: from lputeaux-656-01-25-125.w80-12.abo.wanadoo.fr ([80.12.84.125]:60868 helo=paradis.irqsave.net) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XbUnG-0007hg-AM for qemu-devel@nongnu.org; Tue, 07 Oct 2014 09:27:10 -0400 From: =?UTF-8?q?Beno=C3=AEt=20Canet?= Date: Tue, 7 Oct 2014 15:24:33 +0200 Message-Id: <1412688279-8312-3-git-send-email-benoit.canet@nodalink.com> In-Reply-To: <1412688279-8312-1-git-send-email-benoit.canet@nodalink.com> References: <1412688279-8312-1-git-send-email-benoit.canet@nodalink.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Subject: [Qemu-devel] [PATCH v1 2/8] throttle: Add throttle group infrastructure List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: kwolf@redhat.com, famz@redhat.com, =?UTF-8?q?Beno=C3=AEt=20Canet?= , stefanha@redhat.com The throttle_group_incref increment the refcount of a throttle group give= n it's name and return the associated throttle state. The throttle_group_unref is the mirror function for cleaning up. Signed-off-by: Benoit Canet --- block/Makefile.objs | 1 + block/throttle-groups.c | 212 ++++++++++++++++++++++++++++++++++= ++++++ include/block/block_int.h | 1 + include/block/throttle-groups.h | 45 +++++++++ 4 files changed, 259 insertions(+) create mode 100644 block/throttle-groups.c create mode 100644 include/block/throttle-groups.h diff --git a/block/Makefile.objs b/block/Makefile.objs index a833ed5..d257b05 100644 --- a/block/Makefile.objs +++ b/block/Makefile.objs @@ -10,6 +10,7 @@ block-obj-$(CONFIG_WIN32) +=3D raw-win32.o win32-aio.o block-obj-$(CONFIG_POSIX) +=3D raw-posix.o block-obj-$(CONFIG_LINUX_AIO) +=3D linux-aio.o block-obj-y +=3D null.o +block-obj-y +=3D throttle-groups.o =20 block-obj-y +=3D nbd.o nbd-client.o sheepdog.o block-obj-$(CONFIG_LIBISCSI) +=3D iscsi.o diff --git a/block/throttle-groups.c b/block/throttle-groups.c new file mode 100644 index 0000000..ea5baca --- /dev/null +++ b/block/throttle-groups.c @@ -0,0 +1,212 @@ +/* + * QEMU block throttling group infrastructure + * + * Copyright (C) Nodalink, EURL. 2014 + * + * Author: + * Beno=C3=AEt Canet + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "block/throttle-groups.h" +#include "qemu/queue.h" +#include "qemu/thread.h" + +typedef struct ThrottleGroup { + char name[32]; + ThrottleState ts; + uint64_t refcount; + QTAILQ_ENTRY(ThrottleGroup) list; + QLIST_HEAD(, BlockDriverState) head; + BlockDriverState *tokens[2]; /* current round-robin tokens */ + QemuMutex lock; /* Used to synchronize all elements belonging to a g= roup */ +} ThrottleGroup; + +static QTAILQ_HEAD(, ThrottleGroup) throttle_groups =3D + QTAILQ_HEAD_INITIALIZER(throttle_groups); + +/* increments a ThrottleGroup reference count given it's name + * + * If no ThrottleGroup is found with the given name a new one is created= . + * + * @name: the name of the ThrottleGroup + * @ret: the ThrottleGroup's ThrottleState address + */ +ThrottleState *throttle_group_incref(const char *name) +{ + ThrottleGroup *tg; + + /* return the correct ThrottleState if a group with this name exists= */ + QTAILQ_FOREACH(tg, &throttle_groups, list) { + /* group not found -> continue */ + if (strcmp(name, tg->name)) { + continue; + } + /* group found -> increment it's refcount and return ThrottleSta= te */ + tg->refcount++; + return &tg->ts; + } + + /* throttle group not found -> prepare new entry */ + tg =3D g_new0(ThrottleGroup, 1); + pstrcpy(tg->name, sizeof(tg->name), name); + qemu_mutex_init(&tg->lock); + throttle_init(&tg->ts); + QLIST_INIT(&tg->head); + tg->refcount =3D 1; + + /* insert new entry in the list */ + QTAILQ_INSERT_TAIL(&throttle_groups, tg, list); + + /* return newly allocated ThrottleState */ + return &tg->ts; +} + +/* decrement a ThrottleGroup given it's ThrottleState address + * + * When the refcount reach zero the ThrottleGroup is destroyed + * + * @ts: The ThrottleState address belonging to the ThrottleGroup to unr= ef + * @ret: true on success else false + */ +bool throttle_group_unref(ThrottleState *ts) +{ + ThrottleGroup *tg; + bool found =3D false; + + /* Find the ThrottleGroup of the given ThrottleState */ + QTAILQ_FOREACH(tg, &throttle_groups, list) { + /* correct group found stop iterating */ + if (&tg->ts =3D=3D ts) { + qemu_mutex_lock(&tg->lock); + found =3D true; + break; + } + } + + /* If the ThrottleState was not found something is seriously broken = */ + if (!found) { + return false; + } + + tg->refcount--; + + /* If ThrottleGroup is used keep it. */ + if (tg->refcount) { + qemu_mutex_unlock(&tg->lock); + return true; + } + + /* Else destroy it */ + QTAILQ_REMOVE(&throttle_groups, tg, list); + qemu_mutex_unlock(&tg->lock); + qemu_mutex_destroy(&tg->lock); + g_free(tg); + return true; +} + +/* Compare a name with a given ThrottleState group name + * + * @ts: the throttle state whose group we are inspecting + * @name: the name to compare + * @ret: true if names are equal else false + */ +bool throttle_group_compare(ThrottleState *ts, const char *name) +{ + ThrottleGroup *tg =3D container_of(ts, ThrottleGroup, ts); + + if (!name) { + return false; + } + + return !strcmp(name, tg->name); +} + +/* Register a BlockDriverState in the doubly linked list + * + * @ts: the ThrottleState the code is working on + * @bs: the BlockDriverState to insert + */ +void throttle_group_register_bs(ThrottleState *ts, BlockDriverState *bs) +{ + ThrottleGroup *tg =3D container_of(ts, ThrottleGroup, ts); + QLIST_INSERT_HEAD(&tg->head, bs, round_robin); +} + +/* Return the next BlockDriverState in the round-robin sequence + * + * This takes care of simulating a circular list + * + * @bs: the input current BlockDriverState + * @ret: the next BlockDriverState in the sequence + */ +BlockDriverState *throttle_group_next_bs(BlockDriverState *bs) +{ + ThrottleState *ts =3D &bs->throttle_state; + ThrottleGroup *tg =3D container_of(ts, ThrottleGroup, ts); + BlockDriverState *next =3D QLIST_NEXT(bs, round_robin); + + if (!next) { + return QLIST_FIRST(&tg->head); + } + + return next; +} + +/* Used to set a token BlockDriverState into a ThrottleState's ThrottleG= roup + * + * @ts: the ThrottleState the code is working on + * @token: the token BlockDriverState to set + * @is_write: true if we are talking about write operations else false + */ +void throttle_group_set_token(ThrottleState *ts, + BlockDriverState *token, + bool is_write) +{ + ThrottleGroup *tg =3D container_of(ts, ThrottleGroup, ts); + tg->tokens[is_write] =3D token; +} + +/* Used to get the token BlockDriverState of a ThrottleState's ThrottleG= roup + * + * @ts: the ThrottleState the code is working on + * @ret: the token BlockDriverState that is retrieved + * @is_write: true if we are talking about write operations else false + */ +BlockDriverState *throttle_group_token(ThrottleState *ts, bool is_write) +{ + ThrottleGroup *tg =3D container_of(ts, ThrottleGroup, ts); + return tg->tokens[is_write]; +} + +/* Used to lock a ThrottleState's ThrottleGroup + * + * @ts: the ThrottleState the code is working on + */ +void throttle_group_lock(ThrottleState *ts) +{ + ThrottleGroup *tg =3D container_of(ts, ThrottleGroup, ts); + qemu_mutex_lock(&tg->lock); +} + +/* Used to unlock a ThrottleState's ThrottleGroup + * + * @ts: the ThrottleState the code is working on + */ +void throttle_group_unlock(ThrottleState *ts) +{ + ThrottleGroup *tg =3D container_of(ts, ThrottleGroup, ts); + qemu_mutex_unlock(&tg->lock); +} diff --git a/include/block/block_int.h b/include/block/block_int.h index 7af126f..4b199f1 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -359,6 +359,7 @@ struct BlockDriverState { ThrottleTimers throttle_timers;=20 CoQueue throttled_reqs[2]; bool io_limits_enabled; + QLIST_ENTRY(BlockDriverState) round_robin; =20 /* I/O stats (display with "info blockstats"). */ BlockAcctStats stats; diff --git a/include/block/throttle-groups.h b/include/block/throttle-gro= ups.h new file mode 100644 index 0000000..d000067 --- /dev/null +++ b/include/block/throttle-groups.h @@ -0,0 +1,45 @@ +/* + * QEMU block throttling group infrastructure + * + * Copyright (C) Nodalink, EURL. 2014 + * + * Author: + * Beno=C3=AEt Canet + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef THROTTLE_GROUPS_H +#define THROTTLE_GROUPS_H + +#include "qemu/throttle.h" +#include "block/block_int.h" + +ThrottleState *throttle_group_incref(const char *name); +bool throttle_group_unref(ThrottleState *ts); + +bool throttle_group_compare(ThrottleState *ts, const char *name); + +void throttle_group_register_bs(ThrottleState *ts, BlockDriverState *bs)= ; +BlockDriverState *throttle_group_next_bs(BlockDriverState *bs); + +void throttle_group_set_token(ThrottleState *ts, + BlockDriverState *token, + bool is_write); +BlockDriverState *throttle_group_token(ThrottleState *ts, bool is_write)= ; + +void throttle_group_lock(ThrottleState *ts); +void throttle_group_unlock(ThrottleState *ts); + +#endif --=20 2.1.1