2015-06-08 16:17:42 +00:00
|
|
|
/*
|
|
|
|
* QEMU block throttling group infrastructure
|
|
|
|
*
|
|
|
|
* Copyright (C) Nodalink, EURL. 2014
|
|
|
|
* Copyright (C) Igalia, S.L. 2015
|
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Benoît Canet <benoit.canet@nodalink.com>
|
|
|
|
* Alberto Garcia <berto@igalia.com>
|
|
|
|
*
|
|
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2016-01-18 18:01:42 +00:00
|
|
|
#include "qemu/osdep.h"
|
2016-03-21 10:30:57 +00:00
|
|
|
#include "sysemu/block-backend.h"
|
2015-06-08 16:17:42 +00:00
|
|
|
#include "block/throttle-groups.h"
|
block: convert ThrottleGroup to object with QOM
ThrottleGroup is converted to an object. This will allow the future
throttle block filter drive easy creation and configuration of throttle
groups in QMP and cli.
A new QAPI struct, ThrottleLimits, is introduced to provide a shared
struct for all throttle configuration needs in QMP.
ThrottleGroups can be created via CLI as
-object throttle-group,id=foo,x-iops-total=100,x-..
where x-* are individual limit properties. Since we can't add non-scalar
properties in -object this interface must be used instead. However,
setting these properties must be disabled after initialization because
certain combinations of limits are forbidden and thus configuration
changes should be done in one transaction. The individual properties
will go away when support for non-scalar values in CLI is implemented
and thus are marked as experimental.
ThrottleGroup also has a `limits` property that uses the ThrottleLimits
struct. It can be used to create ThrottleGroups or set the
configuration in existing groups as follows:
{ "execute": "object-add",
"arguments": {
"qom-type": "throttle-group",
"id": "foo",
"props" : {
"limits": {
"iops-total": 100
}
}
}
}
{ "execute" : "qom-set",
"arguments" : {
"path" : "foo",
"property" : "limits",
"value" : {
"iops-total" : 99
}
}
}
This also means a group's configuration can be fetched with qom-get.
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2017-08-25 13:20:26 +00:00
|
|
|
#include "qemu/throttle-options.h"
|
Include qemu/main-loop.h less
In my "build everything" tree, changing qemu/main-loop.h triggers a
recompile of some 5600 out of 6600 objects (not counting tests and
objects that don't depend on qemu/osdep.h). It includes block/aio.h,
which in turn includes qemu/event_notifier.h, qemu/notify.h,
qemu/processor.h, qemu/qsp.h, qemu/queue.h, qemu/thread-posix.h,
qemu/thread.h, qemu/timer.h, and a few more.
Include qemu/main-loop.h only where it's needed. Touching it now
recompiles only some 1700 objects. For block/aio.h and
qemu/event_notifier.h, these numbers drop from 5600 to 2800. For the
others, they shrink only slightly.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <20190812052359.30071-21-armbru@redhat.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
2019-08-12 05:23:50 +00:00
|
|
|
#include "qemu/main-loop.h"
|
2015-06-08 16:17:44 +00:00
|
|
|
#include "qemu/queue.h"
|
|
|
|
#include "qemu/thread.h"
|
|
|
|
#include "sysemu/qtest.h"
|
block: convert ThrottleGroup to object with QOM
ThrottleGroup is converted to an object. This will allow the future
throttle block filter drive easy creation and configuration of throttle
groups in QMP and cli.
A new QAPI struct, ThrottleLimits, is introduced to provide a shared
struct for all throttle configuration needs in QMP.
ThrottleGroups can be created via CLI as
-object throttle-group,id=foo,x-iops-total=100,x-..
where x-* are individual limit properties. Since we can't add non-scalar
properties in -object this interface must be used instead. However,
setting these properties must be disabled after initialization because
certain combinations of limits are forbidden and thus configuration
changes should be done in one transaction. The individual properties
will go away when support for non-scalar values in CLI is implemented
and thus are marked as experimental.
ThrottleGroup also has a `limits` property that uses the ThrottleLimits
struct. It can be used to create ThrottleGroups or set the
configuration in existing groups as follows:
{ "execute": "object-add",
"arguments": {
"qom-type": "throttle-group",
"id": "foo",
"props" : {
"limits": {
"iops-total": 100
}
}
}
}
{ "execute" : "qom-set",
"arguments" : {
"path" : "foo",
"property" : "limits",
"value" : {
"iops-total" : 99
}
}
}
This also means a group's configuration can be fetched with qom-get.
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2017-08-25 13:20:26 +00:00
|
|
|
#include "qapi/error.h"
|
2018-02-11 09:36:01 +00:00
|
|
|
#include "qapi/qapi-visit-block-core.h"
|
block: convert ThrottleGroup to object with QOM
ThrottleGroup is converted to an object. This will allow the future
throttle block filter drive easy creation and configuration of throttle
groups in QMP and cli.
A new QAPI struct, ThrottleLimits, is introduced to provide a shared
struct for all throttle configuration needs in QMP.
ThrottleGroups can be created via CLI as
-object throttle-group,id=foo,x-iops-total=100,x-..
where x-* are individual limit properties. Since we can't add non-scalar
properties in -object this interface must be used instead. However,
setting these properties must be disabled after initialization because
certain combinations of limits are forbidden and thus configuration
changes should be done in one transaction. The individual properties
will go away when support for non-scalar values in CLI is implemented
and thus are marked as experimental.
ThrottleGroup also has a `limits` property that uses the ThrottleLimits
struct. It can be used to create ThrottleGroups or set the
configuration in existing groups as follows:
{ "execute": "object-add",
"arguments": {
"qom-type": "throttle-group",
"id": "foo",
"props" : {
"limits": {
"iops-total": 100
}
}
}
}
{ "execute" : "qom-set",
"arguments" : {
"path" : "foo",
"property" : "limits",
"value" : {
"iops-total" : 99
}
}
}
This also means a group's configuration can be fetched with qom-get.
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2017-08-25 13:20:26 +00:00
|
|
|
#include "qom/object.h"
|
|
|
|
#include "qom/object_interfaces.h"
|
|
|
|
|
|
|
|
static void throttle_group_obj_init(Object *obj);
|
|
|
|
static void throttle_group_obj_complete(UserCreatable *obj, Error **errp);
|
2018-08-02 14:50:26 +00:00
|
|
|
static void timer_cb(ThrottleGroupMember *tgm, bool is_write);
|
2015-06-08 16:17:42 +00:00
|
|
|
|
|
|
|
/* The ThrottleGroup structure (with its ThrottleState) is shared
|
2017-08-25 13:20:23 +00:00
|
|
|
* among different ThrottleGroupMembers and it's independent from
|
2015-06-08 16:17:42 +00:00
|
|
|
* AioContext, so in order to use it from different threads it needs
|
|
|
|
* its own locking.
|
|
|
|
*
|
|
|
|
* This locking is however handled internally in this file, so it's
|
2015-10-21 18:36:05 +00:00
|
|
|
* transparent to outside users.
|
2015-06-08 16:17:42 +00:00
|
|
|
*
|
|
|
|
* The whole ThrottleGroup structure is private and invisible to
|
|
|
|
* outside users, that only use it through its ThrottleState.
|
|
|
|
*
|
2017-08-25 13:20:23 +00:00
|
|
|
* In addition to the ThrottleGroup structure, ThrottleGroupMember has
|
2015-06-08 16:17:42 +00:00
|
|
|
* fields that need to be accessed by other members of the group and
|
2016-03-21 11:56:44 +00:00
|
|
|
* therefore also need to be protected by this lock. Once a
|
2017-08-25 13:20:23 +00:00
|
|
|
* ThrottleGroupMember is registered in a group those fields can be accessed
|
2016-03-21 11:56:44 +00:00
|
|
|
* by other threads any time.
|
2015-06-08 16:17:42 +00:00
|
|
|
*
|
|
|
|
* Again, all this is handled internally and is mostly transparent to
|
|
|
|
* the outside. The 'throttle_timers' field however has an additional
|
|
|
|
* constraint because it may be temporarily invalid (see for example
|
2017-06-13 21:16:12 +00:00
|
|
|
* blk_set_aio_context()). Therefore in this file a thread will
|
2017-08-25 13:20:23 +00:00
|
|
|
* access some other ThrottleGroupMember's timers only after verifying that
|
|
|
|
* that ThrottleGroupMember has throttled requests in the queue.
|
2015-06-08 16:17:42 +00:00
|
|
|
*/
|
2020-08-25 19:20:12 +00:00
|
|
|
struct ThrottleGroup {
|
block: convert ThrottleGroup to object with QOM
ThrottleGroup is converted to an object. This will allow the future
throttle block filter drive easy creation and configuration of throttle
groups in QMP and cli.
A new QAPI struct, ThrottleLimits, is introduced to provide a shared
struct for all throttle configuration needs in QMP.
ThrottleGroups can be created via CLI as
-object throttle-group,id=foo,x-iops-total=100,x-..
where x-* are individual limit properties. Since we can't add non-scalar
properties in -object this interface must be used instead. However,
setting these properties must be disabled after initialization because
certain combinations of limits are forbidden and thus configuration
changes should be done in one transaction. The individual properties
will go away when support for non-scalar values in CLI is implemented
and thus are marked as experimental.
ThrottleGroup also has a `limits` property that uses the ThrottleLimits
struct. It can be used to create ThrottleGroups or set the
configuration in existing groups as follows:
{ "execute": "object-add",
"arguments": {
"qom-type": "throttle-group",
"id": "foo",
"props" : {
"limits": {
"iops-total": 100
}
}
}
}
{ "execute" : "qom-set",
"arguments" : {
"path" : "foo",
"property" : "limits",
"value" : {
"iops-total" : 99
}
}
}
This also means a group's configuration can be fetched with qom-get.
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2017-08-25 13:20:26 +00:00
|
|
|
Object parent_obj;
|
|
|
|
|
|
|
|
/* refuse individual property change if initialization is complete */
|
|
|
|
bool is_initialized;
|
2015-06-08 16:17:42 +00:00
|
|
|
char *name; /* This is constant during the lifetime of the group */
|
|
|
|
|
|
|
|
QemuMutex lock; /* This lock protects the following four fields */
|
|
|
|
ThrottleState ts;
|
2017-08-25 13:20:23 +00:00
|
|
|
QLIST_HEAD(, ThrottleGroupMember) head;
|
|
|
|
ThrottleGroupMember *tokens[2];
|
2015-06-08 16:17:42 +00:00
|
|
|
bool any_timer_armed[2];
|
2017-07-02 10:06:45 +00:00
|
|
|
QEMUClockType clock_type;
|
2015-06-08 16:17:42 +00:00
|
|
|
|
block: convert ThrottleGroup to object with QOM
ThrottleGroup is converted to an object. This will allow the future
throttle block filter drive easy creation and configuration of throttle
groups in QMP and cli.
A new QAPI struct, ThrottleLimits, is introduced to provide a shared
struct for all throttle configuration needs in QMP.
ThrottleGroups can be created via CLI as
-object throttle-group,id=foo,x-iops-total=100,x-..
where x-* are individual limit properties. Since we can't add non-scalar
properties in -object this interface must be used instead. However,
setting these properties must be disabled after initialization because
certain combinations of limits are forbidden and thus configuration
changes should be done in one transaction. The individual properties
will go away when support for non-scalar values in CLI is implemented
and thus are marked as experimental.
ThrottleGroup also has a `limits` property that uses the ThrottleLimits
struct. It can be used to create ThrottleGroups or set the
configuration in existing groups as follows:
{ "execute": "object-add",
"arguments": {
"qom-type": "throttle-group",
"id": "foo",
"props" : {
"limits": {
"iops-total": 100
}
}
}
}
{ "execute" : "qom-set",
"arguments" : {
"path" : "foo",
"property" : "limits",
"value" : {
"iops-total" : 99
}
}
}
This also means a group's configuration can be fetched with qom-get.
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2017-08-25 13:20:26 +00:00
|
|
|
/* This field is protected by the global QEMU mutex */
|
2015-06-08 16:17:42 +00:00
|
|
|
QTAILQ_ENTRY(ThrottleGroup) list;
|
2020-08-25 19:20:12 +00:00
|
|
|
};
|
2015-06-08 16:17:42 +00:00
|
|
|
|
block: convert ThrottleGroup to object with QOM
ThrottleGroup is converted to an object. This will allow the future
throttle block filter drive easy creation and configuration of throttle
groups in QMP and cli.
A new QAPI struct, ThrottleLimits, is introduced to provide a shared
struct for all throttle configuration needs in QMP.
ThrottleGroups can be created via CLI as
-object throttle-group,id=foo,x-iops-total=100,x-..
where x-* are individual limit properties. Since we can't add non-scalar
properties in -object this interface must be used instead. However,
setting these properties must be disabled after initialization because
certain combinations of limits are forbidden and thus configuration
changes should be done in one transaction. The individual properties
will go away when support for non-scalar values in CLI is implemented
and thus are marked as experimental.
ThrottleGroup also has a `limits` property that uses the ThrottleLimits
struct. It can be used to create ThrottleGroups or set the
configuration in existing groups as follows:
{ "execute": "object-add",
"arguments": {
"qom-type": "throttle-group",
"id": "foo",
"props" : {
"limits": {
"iops-total": 100
}
}
}
}
{ "execute" : "qom-set",
"arguments" : {
"path" : "foo",
"property" : "limits",
"value" : {
"iops-total" : 99
}
}
}
This also means a group's configuration can be fetched with qom-get.
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2017-08-25 13:20:26 +00:00
|
|
|
/* This is protected by the global QEMU mutex */
|
2015-06-08 16:17:42 +00:00
|
|
|
static QTAILQ_HEAD(, ThrottleGroup) throttle_groups =
|
|
|
|
QTAILQ_HEAD_INITIALIZER(throttle_groups);
|
|
|
|
|
block: convert ThrottleGroup to object with QOM
ThrottleGroup is converted to an object. This will allow the future
throttle block filter drive easy creation and configuration of throttle
groups in QMP and cli.
A new QAPI struct, ThrottleLimits, is introduced to provide a shared
struct for all throttle configuration needs in QMP.
ThrottleGroups can be created via CLI as
-object throttle-group,id=foo,x-iops-total=100,x-..
where x-* are individual limit properties. Since we can't add non-scalar
properties in -object this interface must be used instead. However,
setting these properties must be disabled after initialization because
certain combinations of limits are forbidden and thus configuration
changes should be done in one transaction. The individual properties
will go away when support for non-scalar values in CLI is implemented
and thus are marked as experimental.
ThrottleGroup also has a `limits` property that uses the ThrottleLimits
struct. It can be used to create ThrottleGroups or set the
configuration in existing groups as follows:
{ "execute": "object-add",
"arguments": {
"qom-type": "throttle-group",
"id": "foo",
"props" : {
"limits": {
"iops-total": 100
}
}
}
}
{ "execute" : "qom-set",
"arguments" : {
"path" : "foo",
"property" : "limits",
"value" : {
"iops-total" : 99
}
}
}
This also means a group's configuration can be fetched with qom-get.
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2017-08-25 13:20:26 +00:00
|
|
|
|
|
|
|
/* This function reads throttle_groups and must be called under the global
|
|
|
|
* mutex.
|
|
|
|
*/
|
|
|
|
static ThrottleGroup *throttle_group_by_name(const char *name)
|
|
|
|
{
|
|
|
|
ThrottleGroup *iter;
|
|
|
|
|
|
|
|
/* Look for an existing group with that name */
|
|
|
|
QTAILQ_FOREACH(iter, &throttle_groups, list) {
|
|
|
|
if (!g_strcmp0(name, iter->name)) {
|
|
|
|
return iter;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-08-25 13:20:27 +00:00
|
|
|
/* This function reads throttle_groups and must be called under the global
|
|
|
|
* mutex.
|
|
|
|
*/
|
|
|
|
bool throttle_group_exists(const char *name)
|
|
|
|
{
|
|
|
|
return throttle_group_by_name(name) != NULL;
|
|
|
|
}
|
|
|
|
|
2015-06-08 16:17:42 +00:00
|
|
|
/* Increments the reference count of a ThrottleGroup given its name.
|
|
|
|
*
|
|
|
|
* If no ThrottleGroup is found with the given name a new one is
|
|
|
|
* created.
|
|
|
|
*
|
block: convert ThrottleGroup to object with QOM
ThrottleGroup is converted to an object. This will allow the future
throttle block filter drive easy creation and configuration of throttle
groups in QMP and cli.
A new QAPI struct, ThrottleLimits, is introduced to provide a shared
struct for all throttle configuration needs in QMP.
ThrottleGroups can be created via CLI as
-object throttle-group,id=foo,x-iops-total=100,x-..
where x-* are individual limit properties. Since we can't add non-scalar
properties in -object this interface must be used instead. However,
setting these properties must be disabled after initialization because
certain combinations of limits are forbidden and thus configuration
changes should be done in one transaction. The individual properties
will go away when support for non-scalar values in CLI is implemented
and thus are marked as experimental.
ThrottleGroup also has a `limits` property that uses the ThrottleLimits
struct. It can be used to create ThrottleGroups or set the
configuration in existing groups as follows:
{ "execute": "object-add",
"arguments": {
"qom-type": "throttle-group",
"id": "foo",
"props" : {
"limits": {
"iops-total": 100
}
}
}
}
{ "execute" : "qom-set",
"arguments" : {
"path" : "foo",
"property" : "limits",
"value" : {
"iops-total" : 99
}
}
}
This also means a group's configuration can be fetched with qom-get.
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2017-08-25 13:20:26 +00:00
|
|
|
* This function edits throttle_groups and must be called under the global
|
|
|
|
* mutex.
|
|
|
|
*
|
2015-06-08 16:17:42 +00:00
|
|
|
* @name: the name of the ThrottleGroup
|
2015-10-19 15:53:23 +00:00
|
|
|
* @ret: the ThrottleState member of the ThrottleGroup
|
2015-06-08 16:17:42 +00:00
|
|
|
*/
|
2015-10-19 15:53:23 +00:00
|
|
|
ThrottleState *throttle_group_incref(const char *name)
|
2015-06-08 16:17:42 +00:00
|
|
|
{
|
|
|
|
ThrottleGroup *tg = NULL;
|
|
|
|
|
|
|
|
/* Look for an existing group with that name */
|
block: convert ThrottleGroup to object with QOM
ThrottleGroup is converted to an object. This will allow the future
throttle block filter drive easy creation and configuration of throttle
groups in QMP and cli.
A new QAPI struct, ThrottleLimits, is introduced to provide a shared
struct for all throttle configuration needs in QMP.
ThrottleGroups can be created via CLI as
-object throttle-group,id=foo,x-iops-total=100,x-..
where x-* are individual limit properties. Since we can't add non-scalar
properties in -object this interface must be used instead. However,
setting these properties must be disabled after initialization because
certain combinations of limits are forbidden and thus configuration
changes should be done in one transaction. The individual properties
will go away when support for non-scalar values in CLI is implemented
and thus are marked as experimental.
ThrottleGroup also has a `limits` property that uses the ThrottleLimits
struct. It can be used to create ThrottleGroups or set the
configuration in existing groups as follows:
{ "execute": "object-add",
"arguments": {
"qom-type": "throttle-group",
"id": "foo",
"props" : {
"limits": {
"iops-total": 100
}
}
}
}
{ "execute" : "qom-set",
"arguments" : {
"path" : "foo",
"property" : "limits",
"value" : {
"iops-total" : 99
}
}
}
This also means a group's configuration can be fetched with qom-get.
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2017-08-25 13:20:26 +00:00
|
|
|
tg = throttle_group_by_name(name);
|
|
|
|
|
|
|
|
if (tg) {
|
|
|
|
object_ref(OBJECT(tg));
|
|
|
|
} else {
|
|
|
|
/* Create a new one if not found */
|
|
|
|
/* new ThrottleGroup obj will have a refcnt = 1 */
|
|
|
|
tg = THROTTLE_GROUP(object_new(TYPE_THROTTLE_GROUP));
|
2015-06-08 16:17:42 +00:00
|
|
|
tg->name = g_strdup(name);
|
block: convert ThrottleGroup to object with QOM
ThrottleGroup is converted to an object. This will allow the future
throttle block filter drive easy creation and configuration of throttle
groups in QMP and cli.
A new QAPI struct, ThrottleLimits, is introduced to provide a shared
struct for all throttle configuration needs in QMP.
ThrottleGroups can be created via CLI as
-object throttle-group,id=foo,x-iops-total=100,x-..
where x-* are individual limit properties. Since we can't add non-scalar
properties in -object this interface must be used instead. However,
setting these properties must be disabled after initialization because
certain combinations of limits are forbidden and thus configuration
changes should be done in one transaction. The individual properties
will go away when support for non-scalar values in CLI is implemented
and thus are marked as experimental.
ThrottleGroup also has a `limits` property that uses the ThrottleLimits
struct. It can be used to create ThrottleGroups or set the
configuration in existing groups as follows:
{ "execute": "object-add",
"arguments": {
"qom-type": "throttle-group",
"id": "foo",
"props" : {
"limits": {
"iops-total": 100
}
}
}
}
{ "execute" : "qom-set",
"arguments" : {
"path" : "foo",
"property" : "limits",
"value" : {
"iops-total" : 99
}
}
}
This also means a group's configuration can be fetched with qom-get.
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2017-08-25 13:20:26 +00:00
|
|
|
throttle_group_obj_complete(USER_CREATABLE(tg), &error_abort);
|
2015-06-08 16:17:42 +00:00
|
|
|
}
|
|
|
|
|
2015-10-19 15:53:23 +00:00
|
|
|
return &tg->ts;
|
2015-06-08 16:17:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Decrease the reference count of a ThrottleGroup.
|
|
|
|
*
|
|
|
|
* When the reference count reaches zero the ThrottleGroup is
|
|
|
|
* destroyed.
|
|
|
|
*
|
block: convert ThrottleGroup to object with QOM
ThrottleGroup is converted to an object. This will allow the future
throttle block filter drive easy creation and configuration of throttle
groups in QMP and cli.
A new QAPI struct, ThrottleLimits, is introduced to provide a shared
struct for all throttle configuration needs in QMP.
ThrottleGroups can be created via CLI as
-object throttle-group,id=foo,x-iops-total=100,x-..
where x-* are individual limit properties. Since we can't add non-scalar
properties in -object this interface must be used instead. However,
setting these properties must be disabled after initialization because
certain combinations of limits are forbidden and thus configuration
changes should be done in one transaction. The individual properties
will go away when support for non-scalar values in CLI is implemented
and thus are marked as experimental.
ThrottleGroup also has a `limits` property that uses the ThrottleLimits
struct. It can be used to create ThrottleGroups or set the
configuration in existing groups as follows:
{ "execute": "object-add",
"arguments": {
"qom-type": "throttle-group",
"id": "foo",
"props" : {
"limits": {
"iops-total": 100
}
}
}
}
{ "execute" : "qom-set",
"arguments" : {
"path" : "foo",
"property" : "limits",
"value" : {
"iops-total" : 99
}
}
}
This also means a group's configuration can be fetched with qom-get.
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2017-08-25 13:20:26 +00:00
|
|
|
* This function edits throttle_groups and must be called under the global
|
|
|
|
* mutex.
|
|
|
|
*
|
2015-10-19 15:53:23 +00:00
|
|
|
* @ts: The ThrottleGroup to unref, given by its ThrottleState member
|
2015-06-08 16:17:42 +00:00
|
|
|
*/
|
2015-10-19 15:53:23 +00:00
|
|
|
void throttle_group_unref(ThrottleState *ts)
|
2015-06-08 16:17:42 +00:00
|
|
|
{
|
2015-10-19 15:53:23 +00:00
|
|
|
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
|
block: convert ThrottleGroup to object with QOM
ThrottleGroup is converted to an object. This will allow the future
throttle block filter drive easy creation and configuration of throttle
groups in QMP and cli.
A new QAPI struct, ThrottleLimits, is introduced to provide a shared
struct for all throttle configuration needs in QMP.
ThrottleGroups can be created via CLI as
-object throttle-group,id=foo,x-iops-total=100,x-..
where x-* are individual limit properties. Since we can't add non-scalar
properties in -object this interface must be used instead. However,
setting these properties must be disabled after initialization because
certain combinations of limits are forbidden and thus configuration
changes should be done in one transaction. The individual properties
will go away when support for non-scalar values in CLI is implemented
and thus are marked as experimental.
ThrottleGroup also has a `limits` property that uses the ThrottleLimits
struct. It can be used to create ThrottleGroups or set the
configuration in existing groups as follows:
{ "execute": "object-add",
"arguments": {
"qom-type": "throttle-group",
"id": "foo",
"props" : {
"limits": {
"iops-total": 100
}
}
}
}
{ "execute" : "qom-set",
"arguments" : {
"path" : "foo",
"property" : "limits",
"value" : {
"iops-total" : 99
}
}
}
This also means a group's configuration can be fetched with qom-get.
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2017-08-25 13:20:26 +00:00
|
|
|
object_unref(OBJECT(tg));
|
2015-06-08 16:17:42 +00:00
|
|
|
}
|
|
|
|
|
2017-08-25 13:20:23 +00:00
|
|
|
/* Get the name from a ThrottleGroupMember's group. The name (and the pointer)
|
2016-03-21 10:58:21 +00:00
|
|
|
* is guaranteed to remain constant during the lifetime of the group.
|
2015-06-08 16:17:42 +00:00
|
|
|
*
|
2017-08-25 13:20:23 +00:00
|
|
|
* @tgm: a ThrottleGroupMember
|
2015-06-08 16:17:42 +00:00
|
|
|
* @ret: the name of the group.
|
|
|
|
*/
|
2017-08-25 13:20:23 +00:00
|
|
|
const char *throttle_group_get_name(ThrottleGroupMember *tgm)
|
2015-06-08 16:17:42 +00:00
|
|
|
{
|
2017-08-25 13:20:23 +00:00
|
|
|
ThrottleGroup *tg = container_of(tgm->throttle_state, ThrottleGroup, ts);
|
2015-06-08 16:17:42 +00:00
|
|
|
return tg->name;
|
|
|
|
}
|
|
|
|
|
2017-08-25 13:20:23 +00:00
|
|
|
/* Return the next ThrottleGroupMember in the round-robin sequence, simulating
|
|
|
|
* a circular list.
|
2015-06-08 16:17:42 +00:00
|
|
|
*
|
|
|
|
* This assumes that tg->lock is held.
|
|
|
|
*
|
2017-08-25 13:20:23 +00:00
|
|
|
* @tgm: the current ThrottleGroupMember
|
|
|
|
* @ret: the next ThrottleGroupMember in the sequence
|
2015-06-08 16:17:42 +00:00
|
|
|
*/
|
2017-08-25 13:20:23 +00:00
|
|
|
static ThrottleGroupMember *throttle_group_next_tgm(ThrottleGroupMember *tgm)
|
2015-06-08 16:17:42 +00:00
|
|
|
{
|
2017-08-25 13:20:23 +00:00
|
|
|
ThrottleState *ts = tgm->throttle_state;
|
2015-06-08 16:17:42 +00:00
|
|
|
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
|
2017-08-25 13:20:23 +00:00
|
|
|
ThrottleGroupMember *next = QLIST_NEXT(tgm, round_robin);
|
2015-06-08 16:17:42 +00:00
|
|
|
|
|
|
|
if (!next) {
|
2016-03-21 10:30:57 +00:00
|
|
|
next = QLIST_FIRST(&tg->head);
|
2015-06-08 16:17:42 +00:00
|
|
|
}
|
|
|
|
|
2017-08-25 13:20:23 +00:00
|
|
|
return next;
|
2015-06-08 16:17:42 +00:00
|
|
|
}
|
|
|
|
|
2016-10-17 15:46:02 +00:00
|
|
|
/*
|
2017-08-25 13:20:23 +00:00
|
|
|
* Return whether a ThrottleGroupMember has pending requests.
|
2016-10-17 15:46:02 +00:00
|
|
|
*
|
|
|
|
* This assumes that tg->lock is held.
|
|
|
|
*
|
2017-08-25 13:20:23 +00:00
|
|
|
* @tgm: the ThrottleGroupMember
|
|
|
|
* @is_write: the type of operation (read/write)
|
|
|
|
* @ret: whether the ThrottleGroupMember has pending requests.
|
2016-10-17 15:46:02 +00:00
|
|
|
*/
|
2017-08-25 13:20:23 +00:00
|
|
|
static inline bool tgm_has_pending_reqs(ThrottleGroupMember *tgm,
|
2016-10-17 15:46:02 +00:00
|
|
|
bool is_write)
|
|
|
|
{
|
2017-08-25 13:20:23 +00:00
|
|
|
return tgm->pending_reqs[is_write];
|
2016-10-17 15:46:02 +00:00
|
|
|
}
|
|
|
|
|
2017-08-25 13:20:23 +00:00
|
|
|
/* Return the next ThrottleGroupMember in the round-robin sequence with pending
|
|
|
|
* I/O requests.
|
2015-06-08 16:17:44 +00:00
|
|
|
*
|
|
|
|
* This assumes that tg->lock is held.
|
|
|
|
*
|
2017-08-25 13:20:23 +00:00
|
|
|
* @tgm: the current ThrottleGroupMember
|
2015-06-08 16:17:44 +00:00
|
|
|
* @is_write: the type of operation (read/write)
|
2017-08-25 13:20:23 +00:00
|
|
|
* @ret: the next ThrottleGroupMember with pending requests, or tgm if
|
|
|
|
* there is none.
|
2015-06-08 16:17:44 +00:00
|
|
|
*/
|
2017-08-25 13:20:23 +00:00
|
|
|
static ThrottleGroupMember *next_throttle_token(ThrottleGroupMember *tgm,
|
|
|
|
bool is_write)
|
2015-06-08 16:17:44 +00:00
|
|
|
{
|
2017-08-25 13:20:23 +00:00
|
|
|
ThrottleState *ts = tgm->throttle_state;
|
|
|
|
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
|
|
|
|
ThrottleGroupMember *token, *start;
|
2015-06-08 16:17:44 +00:00
|
|
|
|
2018-08-02 14:50:24 +00:00
|
|
|
/* If this member has its I/O limits disabled then it means that
|
|
|
|
* it's being drained. Skip the round-robin search and return tgm
|
|
|
|
* immediately if it has pending requests. Otherwise we could be
|
|
|
|
* forcing it to wait for other member's throttled requests. */
|
|
|
|
if (tgm_has_pending_reqs(tgm, is_write) &&
|
2020-09-23 10:56:46 +00:00
|
|
|
qatomic_read(&tgm->io_limits_disabled)) {
|
2018-08-02 14:50:24 +00:00
|
|
|
return tgm;
|
|
|
|
}
|
|
|
|
|
2015-06-08 16:17:44 +00:00
|
|
|
start = token = tg->tokens[is_write];
|
|
|
|
|
|
|
|
/* get next bs round in round robin style */
|
2017-08-25 13:20:23 +00:00
|
|
|
token = throttle_group_next_tgm(token);
|
|
|
|
while (token != start && !tgm_has_pending_reqs(token, is_write)) {
|
|
|
|
token = throttle_group_next_tgm(token);
|
2015-06-08 16:17:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* If no IO are queued for scheduling on the next round robin token
|
2017-08-25 13:20:23 +00:00
|
|
|
* then decide the token is the current tgm because chances are
|
|
|
|
* the current tgm got the current request queued.
|
2015-06-08 16:17:44 +00:00
|
|
|
*/
|
2017-08-25 13:20:23 +00:00
|
|
|
if (token == start && !tgm_has_pending_reqs(token, is_write)) {
|
|
|
|
token = tgm;
|
2015-06-08 16:17:44 +00:00
|
|
|
}
|
|
|
|
|
2017-08-25 13:20:23 +00:00
|
|
|
/* Either we return the original TGM, or one with pending requests */
|
|
|
|
assert(token == tgm || tgm_has_pending_reqs(token, is_write));
|
2016-10-17 15:46:02 +00:00
|
|
|
|
2015-06-08 16:17:44 +00:00
|
|
|
return token;
|
|
|
|
}
|
|
|
|
|
2017-08-25 13:20:23 +00:00
|
|
|
/* Check if the next I/O request for a ThrottleGroupMember needs to be
|
|
|
|
* throttled or not. If there's no timer set in this group, set one and update
|
|
|
|
* the token accordingly.
|
2015-06-08 16:17:44 +00:00
|
|
|
*
|
|
|
|
* This assumes that tg->lock is held.
|
|
|
|
*
|
2017-08-25 13:20:23 +00:00
|
|
|
* @tgm: the current ThrottleGroupMember
|
2015-06-08 16:17:44 +00:00
|
|
|
* @is_write: the type of operation (read/write)
|
|
|
|
* @ret: whether the I/O request needs to be throttled or not
|
|
|
|
*/
|
2017-08-25 13:20:23 +00:00
|
|
|
static bool throttle_group_schedule_timer(ThrottleGroupMember *tgm,
|
|
|
|
bool is_write)
|
2015-06-08 16:17:44 +00:00
|
|
|
{
|
2017-08-25 13:20:23 +00:00
|
|
|
ThrottleState *ts = tgm->throttle_state;
|
2015-06-08 16:17:44 +00:00
|
|
|
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
|
2017-08-25 13:20:23 +00:00
|
|
|
ThrottleTimers *tt = &tgm->throttle_timers;
|
2015-06-08 16:17:44 +00:00
|
|
|
bool must_wait;
|
|
|
|
|
2020-09-23 10:56:46 +00:00
|
|
|
if (qatomic_read(&tgm->io_limits_disabled)) {
|
2016-04-07 16:33:33 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-06-08 16:17:44 +00:00
|
|
|
/* Check if any of the timers in this group is already armed */
|
|
|
|
if (tg->any_timer_armed[is_write]) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
must_wait = throttle_schedule_timer(ts, tt, is_write);
|
|
|
|
|
2017-08-25 13:20:23 +00:00
|
|
|
/* If a timer just got armed, set tgm as the current token */
|
2015-06-08 16:17:44 +00:00
|
|
|
if (must_wait) {
|
2017-08-25 13:20:23 +00:00
|
|
|
tg->tokens[is_write] = tgm;
|
2015-06-08 16:17:44 +00:00
|
|
|
tg->any_timer_armed[is_write] = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return must_wait;
|
|
|
|
}
|
|
|
|
|
2017-08-25 13:20:23 +00:00
|
|
|
/* Start the next pending I/O request for a ThrottleGroupMember. Return whether
|
2017-06-05 12:38:57 +00:00
|
|
|
* any request was actually pending.
|
|
|
|
*
|
2017-08-25 13:20:23 +00:00
|
|
|
* @tgm: the current ThrottleGroupMember
|
2017-06-05 12:38:57 +00:00
|
|
|
* @is_write: the type of operation (read/write)
|
|
|
|
*/
|
2017-08-25 13:20:23 +00:00
|
|
|
static bool coroutine_fn throttle_group_co_restart_queue(ThrottleGroupMember *tgm,
|
2017-06-05 12:38:57 +00:00
|
|
|
bool is_write)
|
|
|
|
{
|
2017-06-05 12:38:58 +00:00
|
|
|
bool ret;
|
2017-06-05 12:38:57 +00:00
|
|
|
|
2017-08-25 13:20:23 +00:00
|
|
|
qemu_co_mutex_lock(&tgm->throttled_reqs_lock);
|
|
|
|
ret = qemu_co_queue_next(&tgm->throttled_reqs[is_write]);
|
|
|
|
qemu_co_mutex_unlock(&tgm->throttled_reqs_lock);
|
2017-06-05 12:38:58 +00:00
|
|
|
|
|
|
|
return ret;
|
2017-06-05 12:38:57 +00:00
|
|
|
}
|
|
|
|
|
2015-06-08 16:17:44 +00:00
|
|
|
/* Look for the next pending I/O request and schedule it.
|
|
|
|
*
|
|
|
|
* This assumes that tg->lock is held.
|
|
|
|
*
|
2017-08-25 13:20:23 +00:00
|
|
|
* @tgm: the current ThrottleGroupMember
|
2015-06-08 16:17:44 +00:00
|
|
|
* @is_write: the type of operation (read/write)
|
|
|
|
*/
|
2017-08-25 13:20:23 +00:00
|
|
|
static void schedule_next_request(ThrottleGroupMember *tgm, bool is_write)
|
2015-06-08 16:17:44 +00:00
|
|
|
{
|
2017-08-25 13:20:23 +00:00
|
|
|
ThrottleState *ts = tgm->throttle_state;
|
|
|
|
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
|
2015-06-08 16:17:44 +00:00
|
|
|
bool must_wait;
|
2017-08-25 13:20:23 +00:00
|
|
|
ThrottleGroupMember *token;
|
2015-06-08 16:17:44 +00:00
|
|
|
|
|
|
|
/* Check if there's any pending request to schedule next */
|
2017-08-25 13:20:23 +00:00
|
|
|
token = next_throttle_token(tgm, is_write);
|
|
|
|
if (!tgm_has_pending_reqs(token, is_write)) {
|
2015-06-08 16:17:44 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set a timer for the request if it needs to be throttled */
|
|
|
|
must_wait = throttle_group_schedule_timer(token, is_write);
|
|
|
|
|
|
|
|
/* If it doesn't have to wait, queue it for immediate execution */
|
|
|
|
if (!must_wait) {
|
2017-08-25 13:20:23 +00:00
|
|
|
/* Give preference to requests from the current tgm */
|
2015-06-08 16:17:44 +00:00
|
|
|
if (qemu_in_coroutine() &&
|
2017-08-25 13:20:23 +00:00
|
|
|
throttle_group_co_restart_queue(tgm, is_write)) {
|
|
|
|
token = tgm;
|
2015-06-08 16:17:44 +00:00
|
|
|
} else {
|
2017-08-25 13:20:23 +00:00
|
|
|
ThrottleTimers *tt = &token->throttle_timers;
|
2017-07-02 10:06:45 +00:00
|
|
|
int64_t now = qemu_clock_get_ns(tg->clock_type);
|
2017-06-05 12:38:56 +00:00
|
|
|
timer_mod(tt->timers[is_write], now);
|
2015-06-08 16:17:44 +00:00
|
|
|
tg->any_timer_armed[is_write] = true;
|
|
|
|
}
|
|
|
|
tg->tokens[is_write] = token;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if an I/O request needs to be throttled, wait and set a timer
|
|
|
|
* if necessary, and schedule the next request using a round robin
|
|
|
|
* algorithm.
|
|
|
|
*
|
2017-08-25 13:20:23 +00:00
|
|
|
* @tgm: the current ThrottleGroupMember
|
2015-06-08 16:17:44 +00:00
|
|
|
* @bytes: the number of bytes for this I/O
|
|
|
|
* @is_write: the type of operation (read/write)
|
|
|
|
*/
|
2017-08-25 13:20:23 +00:00
|
|
|
void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember *tgm,
|
block/throttle-groups: throttle_group_co_io_limits_intercept(): 64bit bytes
The function is called from 64bit io handlers, and bytes is just passed
to throttle_account() which is 64bit too (unsigned though). So, let's
convert intermediate argument to 64bit too.
This patch is a first in the 64-bit-blocklayer series, so we are
generally moving to int64_t for both offset and bytes parameters on all
io paths. Main motivation is realization of 64-bit write_zeroes
operation for fast zeroing large disk chunks, up to the whole disk.
We chose signed type, to be consistent with off_t (which is signed) and
with possibility for signed return type (where negative value means
error).
Patch-correctness audit by Eric Blake:
Caller has 32-bit, this patch now causes widening which is safe:
block/block-backend.c: blk_do_preadv() passes 'unsigned int'
block/block-backend.c: blk_do_pwritev_part() passes 'unsigned int'
block/throttle.c: throttle_co_pwrite_zeroes() passes 'int'
block/throttle.c: throttle_co_pdiscard() passes 'int'
Caller has 64-bit, this patch fixes potential bug where pre-patch
could narrow, except it's easy enough to trace that callers are still
capped at 2G actions:
block/throttle.c: throttle_co_preadv() passes 'uint64_t'
block/throttle.c: throttle_co_pwritev() passes 'uint64_t'
Implementation in question: block/throttle-groups.c
throttle_group_co_io_limits_intercept() takes 'unsigned int bytes'
and uses it: argument to util/throttle.c throttle_account(uint64_t)
All safe: it patches a latent bug, and does not introduce any 64-bit
gotchas once throttle_co_p{read,write}v are relaxed, and assuming
throttle_account() is not buggy.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Message-Id: <20201211183934.169161-7-vsementsov@virtuozzo.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
2020-12-11 18:39:24 +00:00
|
|
|
int64_t bytes,
|
2015-06-08 16:17:44 +00:00
|
|
|
bool is_write)
|
|
|
|
{
|
|
|
|
bool must_wait;
|
2017-08-25 13:20:23 +00:00
|
|
|
ThrottleGroupMember *token;
|
|
|
|
ThrottleGroup *tg = container_of(tgm->throttle_state, ThrottleGroup, ts);
|
block/throttle-groups: throttle_group_co_io_limits_intercept(): 64bit bytes
The function is called from 64bit io handlers, and bytes is just passed
to throttle_account() which is 64bit too (unsigned though). So, let's
convert intermediate argument to 64bit too.
This patch is a first in the 64-bit-blocklayer series, so we are
generally moving to int64_t for both offset and bytes parameters on all
io paths. Main motivation is realization of 64-bit write_zeroes
operation for fast zeroing large disk chunks, up to the whole disk.
We chose signed type, to be consistent with off_t (which is signed) and
with possibility for signed return type (where negative value means
error).
Patch-correctness audit by Eric Blake:
Caller has 32-bit, this patch now causes widening which is safe:
block/block-backend.c: blk_do_preadv() passes 'unsigned int'
block/block-backend.c: blk_do_pwritev_part() passes 'unsigned int'
block/throttle.c: throttle_co_pwrite_zeroes() passes 'int'
block/throttle.c: throttle_co_pdiscard() passes 'int'
Caller has 64-bit, this patch fixes potential bug where pre-patch
could narrow, except it's easy enough to trace that callers are still
capped at 2G actions:
block/throttle.c: throttle_co_preadv() passes 'uint64_t'
block/throttle.c: throttle_co_pwritev() passes 'uint64_t'
Implementation in question: block/throttle-groups.c
throttle_group_co_io_limits_intercept() takes 'unsigned int bytes'
and uses it: argument to util/throttle.c throttle_account(uint64_t)
All safe: it patches a latent bug, and does not introduce any 64-bit
gotchas once throttle_co_p{read,write}v are relaxed, and assuming
throttle_account() is not buggy.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Message-Id: <20201211183934.169161-7-vsementsov@virtuozzo.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
2020-12-11 18:39:24 +00:00
|
|
|
|
|
|
|
assert(bytes >= 0);
|
|
|
|
|
2015-06-08 16:17:44 +00:00
|
|
|
qemu_mutex_lock(&tg->lock);
|
|
|
|
|
|
|
|
/* First we check if this I/O has to be throttled. */
|
2017-08-25 13:20:23 +00:00
|
|
|
token = next_throttle_token(tgm, is_write);
|
2015-06-08 16:17:44 +00:00
|
|
|
must_wait = throttle_group_schedule_timer(token, is_write);
|
|
|
|
|
|
|
|
/* Wait if there's a timer set or queued requests of this type */
|
2017-08-25 13:20:23 +00:00
|
|
|
if (must_wait || tgm->pending_reqs[is_write]) {
|
|
|
|
tgm->pending_reqs[is_write]++;
|
2015-06-08 16:17:44 +00:00
|
|
|
qemu_mutex_unlock(&tg->lock);
|
2017-08-25 13:20:23 +00:00
|
|
|
qemu_co_mutex_lock(&tgm->throttled_reqs_lock);
|
|
|
|
qemu_co_queue_wait(&tgm->throttled_reqs[is_write],
|
|
|
|
&tgm->throttled_reqs_lock);
|
|
|
|
qemu_co_mutex_unlock(&tgm->throttled_reqs_lock);
|
2015-06-08 16:17:44 +00:00
|
|
|
qemu_mutex_lock(&tg->lock);
|
2017-08-25 13:20:23 +00:00
|
|
|
tgm->pending_reqs[is_write]--;
|
2015-06-08 16:17:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* The I/O will be executed, so do the accounting */
|
2017-08-25 13:20:23 +00:00
|
|
|
throttle_account(tgm->throttle_state, is_write, bytes);
|
2015-06-08 16:17:44 +00:00
|
|
|
|
|
|
|
/* Schedule the next request */
|
2017-08-25 13:20:23 +00:00
|
|
|
schedule_next_request(tgm, is_write);
|
2015-06-08 16:17:44 +00:00
|
|
|
|
|
|
|
qemu_mutex_unlock(&tg->lock);
|
|
|
|
}
|
|
|
|
|
2017-06-05 12:38:57 +00:00
|
|
|
typedef struct {
|
2017-08-25 13:20:23 +00:00
|
|
|
ThrottleGroupMember *tgm;
|
2017-06-05 12:38:57 +00:00
|
|
|
bool is_write;
|
|
|
|
} RestartData;
|
|
|
|
|
|
|
|
static void coroutine_fn throttle_group_restart_queue_entry(void *opaque)
|
2017-06-05 12:38:56 +00:00
|
|
|
{
|
2017-06-05 12:38:57 +00:00
|
|
|
RestartData *data = opaque;
|
2017-08-25 13:20:23 +00:00
|
|
|
ThrottleGroupMember *tgm = data->tgm;
|
|
|
|
ThrottleState *ts = tgm->throttle_state;
|
|
|
|
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
|
2017-06-05 12:38:57 +00:00
|
|
|
bool is_write = data->is_write;
|
2017-06-05 12:38:56 +00:00
|
|
|
bool empty_queue;
|
|
|
|
|
2017-08-25 13:20:23 +00:00
|
|
|
empty_queue = !throttle_group_co_restart_queue(tgm, is_write);
|
2017-06-05 12:38:56 +00:00
|
|
|
|
|
|
|
/* If the request queue was empty then we have to take care of
|
|
|
|
* scheduling the next one */
|
|
|
|
if (empty_queue) {
|
|
|
|
qemu_mutex_lock(&tg->lock);
|
2017-08-25 13:20:23 +00:00
|
|
|
schedule_next_request(tgm, is_write);
|
2017-06-05 12:38:56 +00:00
|
|
|
qemu_mutex_unlock(&tg->lock);
|
|
|
|
}
|
2017-09-18 20:25:29 +00:00
|
|
|
|
|
|
|
g_free(data);
|
2019-01-14 13:32:56 +00:00
|
|
|
|
2020-09-23 10:56:46 +00:00
|
|
|
qatomic_dec(&tgm->restart_pending);
|
2019-01-14 13:32:56 +00:00
|
|
|
aio_wait_kick();
|
2017-06-05 12:38:56 +00:00
|
|
|
}
|
|
|
|
|
2017-08-25 13:20:23 +00:00
|
|
|
static void throttle_group_restart_queue(ThrottleGroupMember *tgm, bool is_write)
|
2017-06-05 12:38:57 +00:00
|
|
|
{
|
|
|
|
Coroutine *co;
|
2017-09-18 20:25:29 +00:00
|
|
|
RestartData *rd = g_new0(RestartData, 1);
|
|
|
|
|
|
|
|
rd->tgm = tgm;
|
|
|
|
rd->is_write = is_write;
|
2017-06-05 12:38:57 +00:00
|
|
|
|
2018-08-02 14:50:26 +00:00
|
|
|
/* This function is called when a timer is fired or when
|
|
|
|
* throttle_group_restart_tgm() is called. Either way, there can
|
|
|
|
* be no timer pending on this tgm at this point */
|
|
|
|
assert(!timer_pending(tgm->throttle_timers.timers[is_write]));
|
|
|
|
|
2020-09-23 10:56:46 +00:00
|
|
|
qatomic_inc(&tgm->restart_pending);
|
2019-01-14 13:32:56 +00:00
|
|
|
|
2017-09-18 20:25:29 +00:00
|
|
|
co = qemu_coroutine_create(throttle_group_restart_queue_entry, rd);
|
2017-08-25 13:20:24 +00:00
|
|
|
aio_co_enter(tgm->aio_context, co);
|
2017-06-05 12:38:57 +00:00
|
|
|
}
|
|
|
|
|
2017-08-25 13:20:23 +00:00
|
|
|
void throttle_group_restart_tgm(ThrottleGroupMember *tgm)
|
2016-04-07 16:33:31 +00:00
|
|
|
{
|
2018-08-02 14:50:26 +00:00
|
|
|
int i;
|
|
|
|
|
2017-08-25 13:20:23 +00:00
|
|
|
if (tgm->throttle_state) {
|
2018-08-02 14:50:26 +00:00
|
|
|
for (i = 0; i < 2; i++) {
|
|
|
|
QEMUTimer *t = tgm->throttle_timers.timers[i];
|
|
|
|
if (timer_pending(t)) {
|
|
|
|
/* If there's a pending timer on this tgm, fire it now */
|
|
|
|
timer_del(t);
|
|
|
|
timer_cb(tgm, i);
|
|
|
|
} else {
|
|
|
|
/* Else run the next request from the queue manually */
|
|
|
|
throttle_group_restart_queue(tgm, i);
|
|
|
|
}
|
|
|
|
}
|
2016-04-07 16:33:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-08 16:17:42 +00:00
|
|
|
/* Update the throttle configuration for a particular group. Similar
|
|
|
|
* to throttle_config(), but guarantees atomicity within the
|
|
|
|
* throttling group.
|
|
|
|
*
|
2017-08-25 13:20:23 +00:00
|
|
|
* @tgm: a ThrottleGroupMember that is a member of the group
|
2015-06-08 16:17:42 +00:00
|
|
|
* @cfg: the configuration to set
|
|
|
|
*/
|
2017-08-25 13:20:23 +00:00
|
|
|
void throttle_group_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg)
|
2015-06-08 16:17:42 +00:00
|
|
|
{
|
2017-08-25 13:20:23 +00:00
|
|
|
ThrottleState *ts = tgm->throttle_state;
|
2015-06-08 16:17:42 +00:00
|
|
|
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
|
|
|
|
qemu_mutex_lock(&tg->lock);
|
2017-07-02 10:06:46 +00:00
|
|
|
throttle_config(ts, tg->clock_type, cfg);
|
2015-06-08 16:17:42 +00:00
|
|
|
qemu_mutex_unlock(&tg->lock);
|
2016-04-07 16:33:31 +00:00
|
|
|
|
2017-08-25 13:20:23 +00:00
|
|
|
throttle_group_restart_tgm(tgm);
|
2015-06-08 16:17:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the throttle configuration from a particular group. Similar to
|
|
|
|
* throttle_get_config(), but guarantees atomicity within the
|
|
|
|
* throttling group.
|
|
|
|
*
|
2017-08-25 13:20:23 +00:00
|
|
|
* @tgm: a ThrottleGroupMember that is a member of the group
|
2015-06-08 16:17:42 +00:00
|
|
|
* @cfg: the configuration will be written here
|
|
|
|
*/
|
2017-08-25 13:20:23 +00:00
|
|
|
void throttle_group_get_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg)
|
2015-06-08 16:17:42 +00:00
|
|
|
{
|
2017-08-25 13:20:23 +00:00
|
|
|
ThrottleState *ts = tgm->throttle_state;
|
2015-06-08 16:17:42 +00:00
|
|
|
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
|
|
|
|
qemu_mutex_lock(&tg->lock);
|
|
|
|
throttle_get_config(ts, cfg);
|
|
|
|
qemu_mutex_unlock(&tg->lock);
|
|
|
|
}
|
|
|
|
|
2015-06-08 16:17:44 +00:00
|
|
|
/* ThrottleTimers callback. This wakes up a request that was waiting
|
|
|
|
* because it had been throttled.
|
|
|
|
*
|
2017-08-25 13:20:24 +00:00
|
|
|
* @tgm: the ThrottleGroupMember whose request had been throttled
|
2015-06-08 16:17:44 +00:00
|
|
|
* @is_write: the type of operation (read/write)
|
|
|
|
*/
|
2017-08-25 13:20:24 +00:00
|
|
|
static void timer_cb(ThrottleGroupMember *tgm, bool is_write)
|
2015-06-08 16:17:44 +00:00
|
|
|
{
|
2017-08-25 13:20:23 +00:00
|
|
|
ThrottleState *ts = tgm->throttle_state;
|
2015-06-08 16:17:44 +00:00
|
|
|
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
|
|
|
|
|
|
|
|
/* The timer has just been fired, so we can update the flag */
|
|
|
|
qemu_mutex_lock(&tg->lock);
|
|
|
|
tg->any_timer_armed[is_write] = false;
|
|
|
|
qemu_mutex_unlock(&tg->lock);
|
|
|
|
|
|
|
|
/* Run the request that was waiting for this timer */
|
2017-08-25 13:20:23 +00:00
|
|
|
throttle_group_restart_queue(tgm, is_write);
|
2015-06-08 16:17:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void read_timer_cb(void *opaque)
|
|
|
|
{
|
|
|
|
timer_cb(opaque, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void write_timer_cb(void *opaque)
|
|
|
|
{
|
|
|
|
timer_cb(opaque, true);
|
|
|
|
}
|
|
|
|
|
2017-08-25 13:20:23 +00:00
|
|
|
/* Register a ThrottleGroupMember from the throttling group, also initializing
|
|
|
|
* its timers and updating its throttle_state pointer to point to it. If a
|
2016-03-21 10:30:57 +00:00
|
|
|
* throttling group with that name does not exist yet, it will be created.
|
2015-06-08 16:17:42 +00:00
|
|
|
*
|
block: convert ThrottleGroup to object with QOM
ThrottleGroup is converted to an object. This will allow the future
throttle block filter drive easy creation and configuration of throttle
groups in QMP and cli.
A new QAPI struct, ThrottleLimits, is introduced to provide a shared
struct for all throttle configuration needs in QMP.
ThrottleGroups can be created via CLI as
-object throttle-group,id=foo,x-iops-total=100,x-..
where x-* are individual limit properties. Since we can't add non-scalar
properties in -object this interface must be used instead. However,
setting these properties must be disabled after initialization because
certain combinations of limits are forbidden and thus configuration
changes should be done in one transaction. The individual properties
will go away when support for non-scalar values in CLI is implemented
and thus are marked as experimental.
ThrottleGroup also has a `limits` property that uses the ThrottleLimits
struct. It can be used to create ThrottleGroups or set the
configuration in existing groups as follows:
{ "execute": "object-add",
"arguments": {
"qom-type": "throttle-group",
"id": "foo",
"props" : {
"limits": {
"iops-total": 100
}
}
}
}
{ "execute" : "qom-set",
"arguments" : {
"path" : "foo",
"property" : "limits",
"value" : {
"iops-total" : 99
}
}
}
This also means a group's configuration can be fetched with qom-get.
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2017-08-25 13:20:26 +00:00
|
|
|
* This function edits throttle_groups and must be called under the global
|
|
|
|
* mutex.
|
|
|
|
*
|
2017-08-25 13:20:23 +00:00
|
|
|
* @tgm: the ThrottleGroupMember to insert
|
2015-06-08 16:17:42 +00:00
|
|
|
* @groupname: the name of the group
|
2017-08-25 13:20:24 +00:00
|
|
|
* @ctx: the AioContext to use
|
2015-06-08 16:17:42 +00:00
|
|
|
*/
|
2017-08-25 13:20:23 +00:00
|
|
|
void throttle_group_register_tgm(ThrottleGroupMember *tgm,
|
2017-08-25 13:20:24 +00:00
|
|
|
const char *groupname,
|
|
|
|
AioContext *ctx)
|
2015-06-08 16:17:42 +00:00
|
|
|
{
|
|
|
|
int i;
|
2015-10-19 15:53:23 +00:00
|
|
|
ThrottleState *ts = throttle_group_incref(groupname);
|
|
|
|
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
|
2017-08-25 13:20:23 +00:00
|
|
|
|
|
|
|
tgm->throttle_state = ts;
|
2017-08-25 13:20:24 +00:00
|
|
|
tgm->aio_context = ctx;
|
2020-09-23 10:56:46 +00:00
|
|
|
qatomic_set(&tgm->restart_pending, 0);
|
2015-06-08 16:17:42 +00:00
|
|
|
|
2020-12-03 07:50:54 +00:00
|
|
|
QEMU_LOCK_GUARD(&tg->lock);
|
2017-08-25 13:20:23 +00:00
|
|
|
/* If the ThrottleGroup is new set this ThrottleGroupMember as the token */
|
2015-06-08 16:17:42 +00:00
|
|
|
for (i = 0; i < 2; i++) {
|
|
|
|
if (!tg->tokens[i]) {
|
2017-08-25 13:20:23 +00:00
|
|
|
tg->tokens[i] = tgm;
|
2015-06-08 16:17:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-25 13:20:23 +00:00
|
|
|
QLIST_INSERT_HEAD(&tg->head, tgm, round_robin);
|
2015-06-08 16:17:44 +00:00
|
|
|
|
2017-08-25 13:20:23 +00:00
|
|
|
throttle_timers_init(&tgm->throttle_timers,
|
2017-08-25 13:20:24 +00:00
|
|
|
tgm->aio_context,
|
2017-07-02 10:06:45 +00:00
|
|
|
tg->clock_type,
|
2015-06-08 16:17:44 +00:00
|
|
|
read_timer_cb,
|
|
|
|
write_timer_cb,
|
2017-08-25 13:20:24 +00:00
|
|
|
tgm);
|
2017-08-25 13:20:25 +00:00
|
|
|
qemu_co_mutex_init(&tgm->throttled_reqs_lock);
|
|
|
|
qemu_co_queue_init(&tgm->throttled_reqs[0]);
|
|
|
|
qemu_co_queue_init(&tgm->throttled_reqs[1]);
|
2015-06-08 16:17:42 +00:00
|
|
|
}
|
|
|
|
|
2017-08-25 13:20:23 +00:00
|
|
|
/* Unregister a ThrottleGroupMember from its group, removing it from the list,
|
2016-03-21 10:30:57 +00:00
|
|
|
* destroying the timers and setting the throttle_state pointer to NULL.
|
2015-06-08 16:17:42 +00:00
|
|
|
*
|
2017-08-25 13:20:23 +00:00
|
|
|
* The ThrottleGroupMember must not have pending throttled requests, so the
|
|
|
|
* caller has to drain them first.
|
2015-11-04 13:15:35 +00:00
|
|
|
*
|
2015-06-08 16:17:42 +00:00
|
|
|
* The group will be destroyed if it's empty after this operation.
|
|
|
|
*
|
2017-08-25 13:20:23 +00:00
|
|
|
* @tgm the ThrottleGroupMember to remove
|
2015-06-08 16:17:42 +00:00
|
|
|
*/
|
2017-08-25 13:20:23 +00:00
|
|
|
void throttle_group_unregister_tgm(ThrottleGroupMember *tgm)
|
2015-06-08 16:17:42 +00:00
|
|
|
{
|
2017-08-25 13:20:23 +00:00
|
|
|
ThrottleState *ts = tgm->throttle_state;
|
|
|
|
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
|
|
|
|
ThrottleGroupMember *token;
|
2015-06-08 16:17:42 +00:00
|
|
|
int i;
|
|
|
|
|
2017-08-25 13:20:27 +00:00
|
|
|
if (!ts) {
|
|
|
|
/* Discard already unregistered tgm */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-01-14 13:32:56 +00:00
|
|
|
/* Wait for throttle_group_restart_queue_entry() coroutines to finish */
|
2020-09-23 10:56:46 +00:00
|
|
|
AIO_WAIT_WHILE(tgm->aio_context, qatomic_read(&tgm->restart_pending) > 0);
|
2019-01-14 13:32:56 +00:00
|
|
|
|
2020-12-03 07:50:54 +00:00
|
|
|
WITH_QEMU_LOCK_GUARD(&tg->lock) {
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
|
|
assert(tgm->pending_reqs[i] == 0);
|
|
|
|
assert(qemu_co_queue_empty(&tgm->throttled_reqs[i]));
|
|
|
|
assert(!timer_pending(tgm->throttle_timers.timers[i]));
|
|
|
|
if (tg->tokens[i] == tgm) {
|
|
|
|
token = throttle_group_next_tgm(tgm);
|
|
|
|
/* Take care of the case where this is the last tgm in the group */
|
|
|
|
if (token == tgm) {
|
|
|
|
token = NULL;
|
|
|
|
}
|
|
|
|
tg->tokens[i] = token;
|
2015-06-08 16:17:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-03 07:50:54 +00:00
|
|
|
/* remove the current tgm from the list */
|
|
|
|
QLIST_REMOVE(tgm, round_robin);
|
|
|
|
throttle_timers_destroy(&tgm->throttle_timers);
|
|
|
|
}
|
2015-06-08 16:17:42 +00:00
|
|
|
|
2015-10-19 15:53:23 +00:00
|
|
|
throttle_group_unref(&tg->ts);
|
2017-08-25 13:20:23 +00:00
|
|
|
tgm->throttle_state = NULL;
|
2015-06-08 16:17:42 +00:00
|
|
|
}
|
|
|
|
|
2017-08-25 13:20:24 +00:00
|
|
|
void throttle_group_attach_aio_context(ThrottleGroupMember *tgm,
|
|
|
|
AioContext *new_context)
|
|
|
|
{
|
|
|
|
ThrottleTimers *tt = &tgm->throttle_timers;
|
|
|
|
throttle_timers_attach_aio_context(tt, new_context);
|
|
|
|
tgm->aio_context = new_context;
|
|
|
|
}
|
|
|
|
|
|
|
|
void throttle_group_detach_aio_context(ThrottleGroupMember *tgm)
|
|
|
|
{
|
2017-11-16 11:21:50 +00:00
|
|
|
ThrottleGroup *tg = container_of(tgm->throttle_state, ThrottleGroup, ts);
|
2017-08-25 13:20:24 +00:00
|
|
|
ThrottleTimers *tt = &tgm->throttle_timers;
|
2017-11-16 11:21:50 +00:00
|
|
|
int i;
|
2017-11-10 15:19:34 +00:00
|
|
|
|
|
|
|
/* Requests must have been drained */
|
|
|
|
assert(tgm->pending_reqs[0] == 0 && tgm->pending_reqs[1] == 0);
|
|
|
|
assert(qemu_co_queue_empty(&tgm->throttled_reqs[0]));
|
|
|
|
assert(qemu_co_queue_empty(&tgm->throttled_reqs[1]));
|
|
|
|
|
2017-11-16 11:21:50 +00:00
|
|
|
/* Kick off next ThrottleGroupMember, if necessary */
|
2020-12-03 07:50:54 +00:00
|
|
|
WITH_QEMU_LOCK_GUARD(&tg->lock) {
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
|
|
if (timer_pending(tt->timers[i])) {
|
|
|
|
tg->any_timer_armed[i] = false;
|
|
|
|
schedule_next_request(tgm, i);
|
|
|
|
}
|
2017-11-16 11:21:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-25 13:20:24 +00:00
|
|
|
throttle_timers_detach_aio_context(tt);
|
|
|
|
tgm->aio_context = NULL;
|
|
|
|
}
|
|
|
|
|
block: convert ThrottleGroup to object with QOM
ThrottleGroup is converted to an object. This will allow the future
throttle block filter drive easy creation and configuration of throttle
groups in QMP and cli.
A new QAPI struct, ThrottleLimits, is introduced to provide a shared
struct for all throttle configuration needs in QMP.
ThrottleGroups can be created via CLI as
-object throttle-group,id=foo,x-iops-total=100,x-..
where x-* are individual limit properties. Since we can't add non-scalar
properties in -object this interface must be used instead. However,
setting these properties must be disabled after initialization because
certain combinations of limits are forbidden and thus configuration
changes should be done in one transaction. The individual properties
will go away when support for non-scalar values in CLI is implemented
and thus are marked as experimental.
ThrottleGroup also has a `limits` property that uses the ThrottleLimits
struct. It can be used to create ThrottleGroups or set the
configuration in existing groups as follows:
{ "execute": "object-add",
"arguments": {
"qom-type": "throttle-group",
"id": "foo",
"props" : {
"limits": {
"iops-total": 100
}
}
}
}
{ "execute" : "qom-set",
"arguments" : {
"path" : "foo",
"property" : "limits",
"value" : {
"iops-total" : 99
}
}
}
This also means a group's configuration can be fetched with qom-get.
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2017-08-25 13:20:26 +00:00
|
|
|
#undef THROTTLE_OPT_PREFIX
|
|
|
|
#define THROTTLE_OPT_PREFIX "x-"
|
|
|
|
|
|
|
|
/* Helper struct and array for QOM property setter/getter */
|
|
|
|
typedef struct {
|
|
|
|
const char *name;
|
|
|
|
BucketType type;
|
|
|
|
enum {
|
|
|
|
AVG,
|
|
|
|
MAX,
|
|
|
|
BURST_LENGTH,
|
|
|
|
IOPS_SIZE,
|
|
|
|
} category;
|
|
|
|
} ThrottleParamInfo;
|
|
|
|
|
|
|
|
static ThrottleParamInfo properties[] = {
|
|
|
|
{
|
|
|
|
THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_TOTAL,
|
|
|
|
THROTTLE_OPS_TOTAL, AVG,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_TOTAL_MAX,
|
|
|
|
THROTTLE_OPS_TOTAL, MAX,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_TOTAL_MAX_LENGTH,
|
|
|
|
THROTTLE_OPS_TOTAL, BURST_LENGTH,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_READ,
|
|
|
|
THROTTLE_OPS_READ, AVG,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_READ_MAX,
|
|
|
|
THROTTLE_OPS_READ, MAX,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_READ_MAX_LENGTH,
|
|
|
|
THROTTLE_OPS_READ, BURST_LENGTH,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_WRITE,
|
|
|
|
THROTTLE_OPS_WRITE, AVG,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_WRITE_MAX,
|
|
|
|
THROTTLE_OPS_WRITE, MAX,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_WRITE_MAX_LENGTH,
|
|
|
|
THROTTLE_OPS_WRITE, BURST_LENGTH,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
THROTTLE_OPT_PREFIX QEMU_OPT_BPS_TOTAL,
|
|
|
|
THROTTLE_BPS_TOTAL, AVG,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
THROTTLE_OPT_PREFIX QEMU_OPT_BPS_TOTAL_MAX,
|
|
|
|
THROTTLE_BPS_TOTAL, MAX,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
THROTTLE_OPT_PREFIX QEMU_OPT_BPS_TOTAL_MAX_LENGTH,
|
|
|
|
THROTTLE_BPS_TOTAL, BURST_LENGTH,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
THROTTLE_OPT_PREFIX QEMU_OPT_BPS_READ,
|
|
|
|
THROTTLE_BPS_READ, AVG,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
THROTTLE_OPT_PREFIX QEMU_OPT_BPS_READ_MAX,
|
|
|
|
THROTTLE_BPS_READ, MAX,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
THROTTLE_OPT_PREFIX QEMU_OPT_BPS_READ_MAX_LENGTH,
|
|
|
|
THROTTLE_BPS_READ, BURST_LENGTH,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
THROTTLE_OPT_PREFIX QEMU_OPT_BPS_WRITE,
|
|
|
|
THROTTLE_BPS_WRITE, AVG,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
THROTTLE_OPT_PREFIX QEMU_OPT_BPS_WRITE_MAX,
|
|
|
|
THROTTLE_BPS_WRITE, MAX,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
THROTTLE_OPT_PREFIX QEMU_OPT_BPS_WRITE_MAX_LENGTH,
|
|
|
|
THROTTLE_BPS_WRITE, BURST_LENGTH,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_SIZE,
|
|
|
|
0, IOPS_SIZE,
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/* This function edits throttle_groups and must be called under the global
|
|
|
|
* mutex */
|
|
|
|
static void throttle_group_obj_init(Object *obj)
|
|
|
|
{
|
|
|
|
ThrottleGroup *tg = THROTTLE_GROUP(obj);
|
|
|
|
|
|
|
|
tg->clock_type = QEMU_CLOCK_REALTIME;
|
|
|
|
if (qtest_enabled()) {
|
|
|
|
/* For testing block IO throttling only */
|
|
|
|
tg->clock_type = QEMU_CLOCK_VIRTUAL;
|
|
|
|
}
|
|
|
|
tg->is_initialized = false;
|
|
|
|
qemu_mutex_init(&tg->lock);
|
|
|
|
throttle_init(&tg->ts);
|
|
|
|
QLIST_INIT(&tg->head);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This function edits throttle_groups and must be called under the global
|
|
|
|
* mutex */
|
|
|
|
static void throttle_group_obj_complete(UserCreatable *obj, Error **errp)
|
|
|
|
{
|
|
|
|
ThrottleGroup *tg = THROTTLE_GROUP(obj);
|
|
|
|
ThrottleConfig cfg;
|
|
|
|
|
|
|
|
/* set group name to object id if it exists */
|
|
|
|
if (!tg->name && tg->parent_obj.parent) {
|
2020-07-14 16:02:00 +00:00
|
|
|
tg->name = g_strdup(object_get_canonical_path_component(OBJECT(obj)));
|
block: convert ThrottleGroup to object with QOM
ThrottleGroup is converted to an object. This will allow the future
throttle block filter drive easy creation and configuration of throttle
groups in QMP and cli.
A new QAPI struct, ThrottleLimits, is introduced to provide a shared
struct for all throttle configuration needs in QMP.
ThrottleGroups can be created via CLI as
-object throttle-group,id=foo,x-iops-total=100,x-..
where x-* are individual limit properties. Since we can't add non-scalar
properties in -object this interface must be used instead. However,
setting these properties must be disabled after initialization because
certain combinations of limits are forbidden and thus configuration
changes should be done in one transaction. The individual properties
will go away when support for non-scalar values in CLI is implemented
and thus are marked as experimental.
ThrottleGroup also has a `limits` property that uses the ThrottleLimits
struct. It can be used to create ThrottleGroups or set the
configuration in existing groups as follows:
{ "execute": "object-add",
"arguments": {
"qom-type": "throttle-group",
"id": "foo",
"props" : {
"limits": {
"iops-total": 100
}
}
}
}
{ "execute" : "qom-set",
"arguments" : {
"path" : "foo",
"property" : "limits",
"value" : {
"iops-total" : 99
}
}
}
This also means a group's configuration can be fetched with qom-get.
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2017-08-25 13:20:26 +00:00
|
|
|
}
|
|
|
|
/* We must have a group name at this point */
|
|
|
|
assert(tg->name);
|
|
|
|
|
|
|
|
/* error if name is duplicate */
|
2017-08-25 13:20:27 +00:00
|
|
|
if (throttle_group_exists(tg->name)) {
|
block: convert ThrottleGroup to object with QOM
ThrottleGroup is converted to an object. This will allow the future
throttle block filter drive easy creation and configuration of throttle
groups in QMP and cli.
A new QAPI struct, ThrottleLimits, is introduced to provide a shared
struct for all throttle configuration needs in QMP.
ThrottleGroups can be created via CLI as
-object throttle-group,id=foo,x-iops-total=100,x-..
where x-* are individual limit properties. Since we can't add non-scalar
properties in -object this interface must be used instead. However,
setting these properties must be disabled after initialization because
certain combinations of limits are forbidden and thus configuration
changes should be done in one transaction. The individual properties
will go away when support for non-scalar values in CLI is implemented
and thus are marked as experimental.
ThrottleGroup also has a `limits` property that uses the ThrottleLimits
struct. It can be used to create ThrottleGroups or set the
configuration in existing groups as follows:
{ "execute": "object-add",
"arguments": {
"qom-type": "throttle-group",
"id": "foo",
"props" : {
"limits": {
"iops-total": 100
}
}
}
}
{ "execute" : "qom-set",
"arguments" : {
"path" : "foo",
"property" : "limits",
"value" : {
"iops-total" : 99
}
}
}
This also means a group's configuration can be fetched with qom-get.
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2017-08-25 13:20:26 +00:00
|
|
|
error_setg(errp, "A group with this name already exists");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check validity */
|
|
|
|
throttle_get_config(&tg->ts, &cfg);
|
|
|
|
if (!throttle_is_valid(&cfg, errp)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
throttle_config(&tg->ts, tg->clock_type, &cfg);
|
|
|
|
QTAILQ_INSERT_TAIL(&throttle_groups, tg, list);
|
|
|
|
tg->is_initialized = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This function edits throttle_groups and must be called under the global
|
|
|
|
* mutex */
|
|
|
|
static void throttle_group_obj_finalize(Object *obj)
|
|
|
|
{
|
|
|
|
ThrottleGroup *tg = THROTTLE_GROUP(obj);
|
|
|
|
if (tg->is_initialized) {
|
|
|
|
QTAILQ_REMOVE(&throttle_groups, tg, list);
|
|
|
|
}
|
|
|
|
qemu_mutex_destroy(&tg->lock);
|
|
|
|
g_free(tg->name);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void throttle_group_set(Object *obj, Visitor *v, const char * name,
|
|
|
|
void *opaque, Error **errp)
|
|
|
|
|
|
|
|
{
|
|
|
|
ThrottleGroup *tg = THROTTLE_GROUP(obj);
|
|
|
|
ThrottleConfig *cfg;
|
|
|
|
ThrottleParamInfo *info = opaque;
|
|
|
|
int64_t value;
|
|
|
|
|
|
|
|
/* If we have finished initialization, don't accept individual property
|
|
|
|
* changes through QOM. Throttle configuration limits must be set in one
|
|
|
|
* transaction, as certain combinations are invalid.
|
|
|
|
*/
|
|
|
|
if (tg->is_initialized) {
|
error: Avoid unnecessary error_propagate() after error_setg()
Replace
error_setg(&err, ...);
error_propagate(errp, err);
by
error_setg(errp, ...);
Related pattern:
if (...) {
error_setg(&err, ...);
goto out;
}
...
out:
error_propagate(errp, err);
return;
When all paths to label out are that way, replace by
if (...) {
error_setg(errp, ...);
return;
}
and delete the label along with the error_propagate().
When we have at most one other path that actually needs to propagate,
and maybe one at the end that where propagation is unnecessary, e.g.
foo(..., &err);
if (err) {
goto out;
}
...
bar(..., &err);
out:
error_propagate(errp, err);
return;
move the error_propagate() to where it's needed, like
if (...) {
foo(..., &err);
error_propagate(errp, err);
return;
}
...
bar(..., errp);
return;
and transform the error_setg() as above.
In some places, the transformation results in obviously unnecessary
error_propagate(). The next few commits will eliminate them.
Bonus: the elimination of gotos will make later patches in this series
easier to review.
Candidates for conversion tracked down with this Coccinelle script:
@@
identifier err, errp;
expression list args;
@@
- error_setg(&err, args);
+ error_setg(errp, args);
... when != err
error_propagate(errp, err);
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <20200707160613.848843-34-armbru@redhat.com>
2020-07-07 16:06:01 +00:00
|
|
|
error_setg(errp, "Property cannot be set after initialization");
|
|
|
|
return;
|
block: convert ThrottleGroup to object with QOM
ThrottleGroup is converted to an object. This will allow the future
throttle block filter drive easy creation and configuration of throttle
groups in QMP and cli.
A new QAPI struct, ThrottleLimits, is introduced to provide a shared
struct for all throttle configuration needs in QMP.
ThrottleGroups can be created via CLI as
-object throttle-group,id=foo,x-iops-total=100,x-..
where x-* are individual limit properties. Since we can't add non-scalar
properties in -object this interface must be used instead. However,
setting these properties must be disabled after initialization because
certain combinations of limits are forbidden and thus configuration
changes should be done in one transaction. The individual properties
will go away when support for non-scalar values in CLI is implemented
and thus are marked as experimental.
ThrottleGroup also has a `limits` property that uses the ThrottleLimits
struct. It can be used to create ThrottleGroups or set the
configuration in existing groups as follows:
{ "execute": "object-add",
"arguments": {
"qom-type": "throttle-group",
"id": "foo",
"props" : {
"limits": {
"iops-total": 100
}
}
}
}
{ "execute" : "qom-set",
"arguments" : {
"path" : "foo",
"property" : "limits",
"value" : {
"iops-total" : 99
}
}
}
This also means a group's configuration can be fetched with qom-get.
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2017-08-25 13:20:26 +00:00
|
|
|
}
|
|
|
|
|
error: Eliminate error_propagate() with Coccinelle, part 1
When all we do with an Error we receive into a local variable is
propagating to somewhere else, we can just as well receive it there
right away. Convert
if (!foo(..., &err)) {
...
error_propagate(errp, err);
...
return ...
}
to
if (!foo(..., errp)) {
...
...
return ...
}
where nothing else needs @err. Coccinelle script:
@rule1 forall@
identifier fun, err, errp, lbl;
expression list args, args2;
binary operator op;
constant c1, c2;
symbol false;
@@
if (
(
- fun(args, &err, args2)
+ fun(args, errp, args2)
|
- !fun(args, &err, args2)
+ !fun(args, errp, args2)
|
- fun(args, &err, args2) op c1
+ fun(args, errp, args2) op c1
)
)
{
... when != err
when != lbl:
when strict
- error_propagate(errp, err);
... when != err
(
return;
|
return c2;
|
return false;
)
}
@rule2 forall@
identifier fun, err, errp, lbl;
expression list args, args2;
expression var;
binary operator op;
constant c1, c2;
symbol false;
@@
- var = fun(args, &err, args2);
+ var = fun(args, errp, args2);
... when != err
if (
(
var
|
!var
|
var op c1
)
)
{
... when != err
when != lbl:
when strict
- error_propagate(errp, err);
... when != err
(
return;
|
return c2;
|
return false;
|
return var;
)
}
@depends on rule1 || rule2@
identifier err;
@@
- Error *err = NULL;
... when != err
Not exactly elegant, I'm afraid.
The "when != lbl:" is necessary to avoid transforming
if (fun(args, &err)) {
goto out
}
...
out:
error_propagate(errp, err);
even though other paths to label out still need the error_propagate().
For an actual example, see sclp_realize().
Without the "when strict", Coccinelle transforms vfio_msix_setup(),
incorrectly. I don't know what exactly "when strict" does, only that
it helps here.
The match of return is narrower than what I want, but I can't figure
out how to express "return where the operand doesn't use @err". For
an example where it's too narrow, see vfio_intx_enable().
Silently fails to convert hw/arm/armsse.c, because Coccinelle gets
confused by ARMSSE being used both as typedef and function-like macro
there. Converted manually.
Line breaks tidied up manually. One nested declaration of @local_err
deleted manually. Preexisting unwanted blank line dropped in
hw/riscv/sifive_e.c.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <20200707160613.848843-35-armbru@redhat.com>
2020-07-07 16:06:02 +00:00
|
|
|
if (!visit_type_int64(v, name, &value, errp)) {
|
error: Avoid unnecessary error_propagate() after error_setg()
Replace
error_setg(&err, ...);
error_propagate(errp, err);
by
error_setg(errp, ...);
Related pattern:
if (...) {
error_setg(&err, ...);
goto out;
}
...
out:
error_propagate(errp, err);
return;
When all paths to label out are that way, replace by
if (...) {
error_setg(errp, ...);
return;
}
and delete the label along with the error_propagate().
When we have at most one other path that actually needs to propagate,
and maybe one at the end that where propagation is unnecessary, e.g.
foo(..., &err);
if (err) {
goto out;
}
...
bar(..., &err);
out:
error_propagate(errp, err);
return;
move the error_propagate() to where it's needed, like
if (...) {
foo(..., &err);
error_propagate(errp, err);
return;
}
...
bar(..., errp);
return;
and transform the error_setg() as above.
In some places, the transformation results in obviously unnecessary
error_propagate(). The next few commits will eliminate them.
Bonus: the elimination of gotos will make later patches in this series
easier to review.
Candidates for conversion tracked down with this Coccinelle script:
@@
identifier err, errp;
expression list args;
@@
- error_setg(&err, args);
+ error_setg(errp, args);
... when != err
error_propagate(errp, err);
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <20200707160613.848843-34-armbru@redhat.com>
2020-07-07 16:06:01 +00:00
|
|
|
return;
|
block: convert ThrottleGroup to object with QOM
ThrottleGroup is converted to an object. This will allow the future
throttle block filter drive easy creation and configuration of throttle
groups in QMP and cli.
A new QAPI struct, ThrottleLimits, is introduced to provide a shared
struct for all throttle configuration needs in QMP.
ThrottleGroups can be created via CLI as
-object throttle-group,id=foo,x-iops-total=100,x-..
where x-* are individual limit properties. Since we can't add non-scalar
properties in -object this interface must be used instead. However,
setting these properties must be disabled after initialization because
certain combinations of limits are forbidden and thus configuration
changes should be done in one transaction. The individual properties
will go away when support for non-scalar values in CLI is implemented
and thus are marked as experimental.
ThrottleGroup also has a `limits` property that uses the ThrottleLimits
struct. It can be used to create ThrottleGroups or set the
configuration in existing groups as follows:
{ "execute": "object-add",
"arguments": {
"qom-type": "throttle-group",
"id": "foo",
"props" : {
"limits": {
"iops-total": 100
}
}
}
}
{ "execute" : "qom-set",
"arguments" : {
"path" : "foo",
"property" : "limits",
"value" : {
"iops-total" : 99
}
}
}
This also means a group's configuration can be fetched with qom-get.
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2017-08-25 13:20:26 +00:00
|
|
|
}
|
|
|
|
if (value < 0) {
|
error: Avoid unnecessary error_propagate() after error_setg()
Replace
error_setg(&err, ...);
error_propagate(errp, err);
by
error_setg(errp, ...);
Related pattern:
if (...) {
error_setg(&err, ...);
goto out;
}
...
out:
error_propagate(errp, err);
return;
When all paths to label out are that way, replace by
if (...) {
error_setg(errp, ...);
return;
}
and delete the label along with the error_propagate().
When we have at most one other path that actually needs to propagate,
and maybe one at the end that where propagation is unnecessary, e.g.
foo(..., &err);
if (err) {
goto out;
}
...
bar(..., &err);
out:
error_propagate(errp, err);
return;
move the error_propagate() to where it's needed, like
if (...) {
foo(..., &err);
error_propagate(errp, err);
return;
}
...
bar(..., errp);
return;
and transform the error_setg() as above.
In some places, the transformation results in obviously unnecessary
error_propagate(). The next few commits will eliminate them.
Bonus: the elimination of gotos will make later patches in this series
easier to review.
Candidates for conversion tracked down with this Coccinelle script:
@@
identifier err, errp;
expression list args;
@@
- error_setg(&err, args);
+ error_setg(errp, args);
... when != err
error_propagate(errp, err);
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <20200707160613.848843-34-armbru@redhat.com>
2020-07-07 16:06:01 +00:00
|
|
|
error_setg(errp, "Property values cannot be negative");
|
|
|
|
return;
|
block: convert ThrottleGroup to object with QOM
ThrottleGroup is converted to an object. This will allow the future
throttle block filter drive easy creation and configuration of throttle
groups in QMP and cli.
A new QAPI struct, ThrottleLimits, is introduced to provide a shared
struct for all throttle configuration needs in QMP.
ThrottleGroups can be created via CLI as
-object throttle-group,id=foo,x-iops-total=100,x-..
where x-* are individual limit properties. Since we can't add non-scalar
properties in -object this interface must be used instead. However,
setting these properties must be disabled after initialization because
certain combinations of limits are forbidden and thus configuration
changes should be done in one transaction. The individual properties
will go away when support for non-scalar values in CLI is implemented
and thus are marked as experimental.
ThrottleGroup also has a `limits` property that uses the ThrottleLimits
struct. It can be used to create ThrottleGroups or set the
configuration in existing groups as follows:
{ "execute": "object-add",
"arguments": {
"qom-type": "throttle-group",
"id": "foo",
"props" : {
"limits": {
"iops-total": 100
}
}
}
}
{ "execute" : "qom-set",
"arguments" : {
"path" : "foo",
"property" : "limits",
"value" : {
"iops-total" : 99
}
}
}
This also means a group's configuration can be fetched with qom-get.
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2017-08-25 13:20:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cfg = &tg->ts.cfg;
|
|
|
|
switch (info->category) {
|
|
|
|
case AVG:
|
|
|
|
cfg->buckets[info->type].avg = value;
|
|
|
|
break;
|
|
|
|
case MAX:
|
|
|
|
cfg->buckets[info->type].max = value;
|
|
|
|
break;
|
|
|
|
case BURST_LENGTH:
|
|
|
|
if (value > UINT_MAX) {
|
error: Avoid unnecessary error_propagate() after error_setg()
Replace
error_setg(&err, ...);
error_propagate(errp, err);
by
error_setg(errp, ...);
Related pattern:
if (...) {
error_setg(&err, ...);
goto out;
}
...
out:
error_propagate(errp, err);
return;
When all paths to label out are that way, replace by
if (...) {
error_setg(errp, ...);
return;
}
and delete the label along with the error_propagate().
When we have at most one other path that actually needs to propagate,
and maybe one at the end that where propagation is unnecessary, e.g.
foo(..., &err);
if (err) {
goto out;
}
...
bar(..., &err);
out:
error_propagate(errp, err);
return;
move the error_propagate() to where it's needed, like
if (...) {
foo(..., &err);
error_propagate(errp, err);
return;
}
...
bar(..., errp);
return;
and transform the error_setg() as above.
In some places, the transformation results in obviously unnecessary
error_propagate(). The next few commits will eliminate them.
Bonus: the elimination of gotos will make later patches in this series
easier to review.
Candidates for conversion tracked down with this Coccinelle script:
@@
identifier err, errp;
expression list args;
@@
- error_setg(&err, args);
+ error_setg(errp, args);
... when != err
error_propagate(errp, err);
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <20200707160613.848843-34-armbru@redhat.com>
2020-07-07 16:06:01 +00:00
|
|
|
error_setg(errp, "%s value must be in the" "range [0, %u]",
|
|
|
|
info->name, UINT_MAX);
|
|
|
|
return;
|
block: convert ThrottleGroup to object with QOM
ThrottleGroup is converted to an object. This will allow the future
throttle block filter drive easy creation and configuration of throttle
groups in QMP and cli.
A new QAPI struct, ThrottleLimits, is introduced to provide a shared
struct for all throttle configuration needs in QMP.
ThrottleGroups can be created via CLI as
-object throttle-group,id=foo,x-iops-total=100,x-..
where x-* are individual limit properties. Since we can't add non-scalar
properties in -object this interface must be used instead. However,
setting these properties must be disabled after initialization because
certain combinations of limits are forbidden and thus configuration
changes should be done in one transaction. The individual properties
will go away when support for non-scalar values in CLI is implemented
and thus are marked as experimental.
ThrottleGroup also has a `limits` property that uses the ThrottleLimits
struct. It can be used to create ThrottleGroups or set the
configuration in existing groups as follows:
{ "execute": "object-add",
"arguments": {
"qom-type": "throttle-group",
"id": "foo",
"props" : {
"limits": {
"iops-total": 100
}
}
}
}
{ "execute" : "qom-set",
"arguments" : {
"path" : "foo",
"property" : "limits",
"value" : {
"iops-total" : 99
}
}
}
This also means a group's configuration can be fetched with qom-get.
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2017-08-25 13:20:26 +00:00
|
|
|
}
|
|
|
|
cfg->buckets[info->type].burst_length = value;
|
|
|
|
break;
|
|
|
|
case IOPS_SIZE:
|
|
|
|
cfg->op_size = value;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void throttle_group_get(Object *obj, Visitor *v, const char *name,
|
|
|
|
void *opaque, Error **errp)
|
|
|
|
{
|
|
|
|
ThrottleGroup *tg = THROTTLE_GROUP(obj);
|
|
|
|
ThrottleConfig cfg;
|
|
|
|
ThrottleParamInfo *info = opaque;
|
|
|
|
int64_t value;
|
|
|
|
|
|
|
|
throttle_get_config(&tg->ts, &cfg);
|
|
|
|
switch (info->category) {
|
|
|
|
case AVG:
|
|
|
|
value = cfg.buckets[info->type].avg;
|
|
|
|
break;
|
|
|
|
case MAX:
|
|
|
|
value = cfg.buckets[info->type].max;
|
|
|
|
break;
|
|
|
|
case BURST_LENGTH:
|
|
|
|
value = cfg.buckets[info->type].burst_length;
|
|
|
|
break;
|
|
|
|
case IOPS_SIZE:
|
|
|
|
value = cfg.op_size;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
visit_type_int64(v, name, &value, errp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void throttle_group_set_limits(Object *obj, Visitor *v,
|
|
|
|
const char *name, void *opaque,
|
|
|
|
Error **errp)
|
|
|
|
|
|
|
|
{
|
|
|
|
ThrottleGroup *tg = THROTTLE_GROUP(obj);
|
|
|
|
ThrottleConfig cfg;
|
2019-11-27 06:20:14 +00:00
|
|
|
ThrottleLimits *argp;
|
block: convert ThrottleGroup to object with QOM
ThrottleGroup is converted to an object. This will allow the future
throttle block filter drive easy creation and configuration of throttle
groups in QMP and cli.
A new QAPI struct, ThrottleLimits, is introduced to provide a shared
struct for all throttle configuration needs in QMP.
ThrottleGroups can be created via CLI as
-object throttle-group,id=foo,x-iops-total=100,x-..
where x-* are individual limit properties. Since we can't add non-scalar
properties in -object this interface must be used instead. However,
setting these properties must be disabled after initialization because
certain combinations of limits are forbidden and thus configuration
changes should be done in one transaction. The individual properties
will go away when support for non-scalar values in CLI is implemented
and thus are marked as experimental.
ThrottleGroup also has a `limits` property that uses the ThrottleLimits
struct. It can be used to create ThrottleGroups or set the
configuration in existing groups as follows:
{ "execute": "object-add",
"arguments": {
"qom-type": "throttle-group",
"id": "foo",
"props" : {
"limits": {
"iops-total": 100
}
}
}
}
{ "execute" : "qom-set",
"arguments" : {
"path" : "foo",
"property" : "limits",
"value" : {
"iops-total" : 99
}
}
}
This also means a group's configuration can be fetched with qom-get.
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2017-08-25 13:20:26 +00:00
|
|
|
Error *local_err = NULL;
|
|
|
|
|
2020-07-07 16:05:47 +00:00
|
|
|
if (!visit_type_ThrottleLimits(v, name, &argp, errp)) {
|
|
|
|
return;
|
block: convert ThrottleGroup to object with QOM
ThrottleGroup is converted to an object. This will allow the future
throttle block filter drive easy creation and configuration of throttle
groups in QMP and cli.
A new QAPI struct, ThrottleLimits, is introduced to provide a shared
struct for all throttle configuration needs in QMP.
ThrottleGroups can be created via CLI as
-object throttle-group,id=foo,x-iops-total=100,x-..
where x-* are individual limit properties. Since we can't add non-scalar
properties in -object this interface must be used instead. However,
setting these properties must be disabled after initialization because
certain combinations of limits are forbidden and thus configuration
changes should be done in one transaction. The individual properties
will go away when support for non-scalar values in CLI is implemented
and thus are marked as experimental.
ThrottleGroup also has a `limits` property that uses the ThrottleLimits
struct. It can be used to create ThrottleGroups or set the
configuration in existing groups as follows:
{ "execute": "object-add",
"arguments": {
"qom-type": "throttle-group",
"id": "foo",
"props" : {
"limits": {
"iops-total": 100
}
}
}
}
{ "execute" : "qom-set",
"arguments" : {
"path" : "foo",
"property" : "limits",
"value" : {
"iops-total" : 99
}
}
}
This also means a group's configuration can be fetched with qom-get.
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2017-08-25 13:20:26 +00:00
|
|
|
}
|
|
|
|
qemu_mutex_lock(&tg->lock);
|
|
|
|
throttle_get_config(&tg->ts, &cfg);
|
|
|
|
throttle_limits_to_config(argp, &cfg, &local_err);
|
|
|
|
if (local_err) {
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
throttle_config(&tg->ts, tg->clock_type, &cfg);
|
|
|
|
|
|
|
|
unlock:
|
|
|
|
qemu_mutex_unlock(&tg->lock);
|
2019-11-27 06:20:14 +00:00
|
|
|
qapi_free_ThrottleLimits(argp);
|
block: convert ThrottleGroup to object with QOM
ThrottleGroup is converted to an object. This will allow the future
throttle block filter drive easy creation and configuration of throttle
groups in QMP and cli.
A new QAPI struct, ThrottleLimits, is introduced to provide a shared
struct for all throttle configuration needs in QMP.
ThrottleGroups can be created via CLI as
-object throttle-group,id=foo,x-iops-total=100,x-..
where x-* are individual limit properties. Since we can't add non-scalar
properties in -object this interface must be used instead. However,
setting these properties must be disabled after initialization because
certain combinations of limits are forbidden and thus configuration
changes should be done in one transaction. The individual properties
will go away when support for non-scalar values in CLI is implemented
and thus are marked as experimental.
ThrottleGroup also has a `limits` property that uses the ThrottleLimits
struct. It can be used to create ThrottleGroups or set the
configuration in existing groups as follows:
{ "execute": "object-add",
"arguments": {
"qom-type": "throttle-group",
"id": "foo",
"props" : {
"limits": {
"iops-total": 100
}
}
}
}
{ "execute" : "qom-set",
"arguments" : {
"path" : "foo",
"property" : "limits",
"value" : {
"iops-total" : 99
}
}
}
This also means a group's configuration can be fetched with qom-get.
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2017-08-25 13:20:26 +00:00
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void throttle_group_get_limits(Object *obj, Visitor *v,
|
|
|
|
const char *name, void *opaque,
|
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
ThrottleGroup *tg = THROTTLE_GROUP(obj);
|
|
|
|
ThrottleConfig cfg;
|
|
|
|
ThrottleLimits arg = { 0 };
|
|
|
|
ThrottleLimits *argp = &arg;
|
|
|
|
|
|
|
|
qemu_mutex_lock(&tg->lock);
|
|
|
|
throttle_get_config(&tg->ts, &cfg);
|
|
|
|
qemu_mutex_unlock(&tg->lock);
|
|
|
|
|
|
|
|
throttle_config_to_limits(&cfg, argp);
|
|
|
|
|
|
|
|
visit_type_ThrottleLimits(v, name, &argp, errp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool throttle_group_can_be_deleted(UserCreatable *uc)
|
|
|
|
{
|
|
|
|
return OBJECT(uc)->ref == 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void throttle_group_obj_class_init(ObjectClass *klass, void *class_data)
|
|
|
|
{
|
|
|
|
size_t i = 0;
|
|
|
|
UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass);
|
|
|
|
|
|
|
|
ucc->complete = throttle_group_obj_complete;
|
|
|
|
ucc->can_be_deleted = throttle_group_can_be_deleted;
|
|
|
|
|
|
|
|
/* individual properties */
|
|
|
|
for (i = 0; i < sizeof(properties) / sizeof(ThrottleParamInfo); i++) {
|
|
|
|
object_class_property_add(klass,
|
|
|
|
properties[i].name,
|
|
|
|
"int",
|
|
|
|
throttle_group_get,
|
|
|
|
throttle_group_set,
|
qom: Drop parameter @errp of object_property_add() & friends
The only way object_property_add() can fail is when a property with
the same name already exists. Since our property names are all
hardcoded, failure is a programming error, and the appropriate way to
handle it is passing &error_abort.
Same for its variants, except for object_property_add_child(), which
additionally fails when the child already has a parent. Parentage is
also under program control, so this is a programming error, too.
We have a bit over 500 callers. Almost half of them pass
&error_abort, slightly fewer ignore errors, one test case handles
errors, and the remaining few callers pass them to their own callers.
The previous few commits demonstrated once again that ignoring
programming errors is a bad idea.
Of the few ones that pass on errors, several violate the Error API.
The Error ** argument must be NULL, &error_abort, &error_fatal, or a
pointer to a variable containing NULL. Passing an argument of the
latter kind twice without clearing it in between is wrong: if the
first call sets an error, it no longer points to NULL for the second
call. ich9_pm_add_properties(), sparc32_ledma_realize(),
sparc32_dma_realize(), xilinx_axidma_realize(), xilinx_enet_realize()
are wrong that way.
When the one appropriate choice of argument is &error_abort, letting
users pick the argument is a bad idea.
Drop parameter @errp and assert the preconditions instead.
There's one exception to "duplicate property name is a programming
error": the way object_property_add() implements the magic (and
undocumented) "automatic arrayification". Don't drop @errp there.
Instead, rename object_property_add() to object_property_try_add(),
and add the obvious wrapper object_property_add().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20200505152926.18877-15-armbru@redhat.com>
[Two semantic rebase conflicts resolved]
2020-05-05 15:29:22 +00:00
|
|
|
NULL, &properties[i]);
|
block: convert ThrottleGroup to object with QOM
ThrottleGroup is converted to an object. This will allow the future
throttle block filter drive easy creation and configuration of throttle
groups in QMP and cli.
A new QAPI struct, ThrottleLimits, is introduced to provide a shared
struct for all throttle configuration needs in QMP.
ThrottleGroups can be created via CLI as
-object throttle-group,id=foo,x-iops-total=100,x-..
where x-* are individual limit properties. Since we can't add non-scalar
properties in -object this interface must be used instead. However,
setting these properties must be disabled after initialization because
certain combinations of limits are forbidden and thus configuration
changes should be done in one transaction. The individual properties
will go away when support for non-scalar values in CLI is implemented
and thus are marked as experimental.
ThrottleGroup also has a `limits` property that uses the ThrottleLimits
struct. It can be used to create ThrottleGroups or set the
configuration in existing groups as follows:
{ "execute": "object-add",
"arguments": {
"qom-type": "throttle-group",
"id": "foo",
"props" : {
"limits": {
"iops-total": 100
}
}
}
}
{ "execute" : "qom-set",
"arguments" : {
"path" : "foo",
"property" : "limits",
"value" : {
"iops-total" : 99
}
}
}
This also means a group's configuration can be fetched with qom-get.
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2017-08-25 13:20:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ThrottleLimits */
|
|
|
|
object_class_property_add(klass,
|
|
|
|
"limits", "ThrottleLimits",
|
|
|
|
throttle_group_get_limits,
|
|
|
|
throttle_group_set_limits,
|
qom: Drop parameter @errp of object_property_add() & friends
The only way object_property_add() can fail is when a property with
the same name already exists. Since our property names are all
hardcoded, failure is a programming error, and the appropriate way to
handle it is passing &error_abort.
Same for its variants, except for object_property_add_child(), which
additionally fails when the child already has a parent. Parentage is
also under program control, so this is a programming error, too.
We have a bit over 500 callers. Almost half of them pass
&error_abort, slightly fewer ignore errors, one test case handles
errors, and the remaining few callers pass them to their own callers.
The previous few commits demonstrated once again that ignoring
programming errors is a bad idea.
Of the few ones that pass on errors, several violate the Error API.
The Error ** argument must be NULL, &error_abort, &error_fatal, or a
pointer to a variable containing NULL. Passing an argument of the
latter kind twice without clearing it in between is wrong: if the
first call sets an error, it no longer points to NULL for the second
call. ich9_pm_add_properties(), sparc32_ledma_realize(),
sparc32_dma_realize(), xilinx_axidma_realize(), xilinx_enet_realize()
are wrong that way.
When the one appropriate choice of argument is &error_abort, letting
users pick the argument is a bad idea.
Drop parameter @errp and assert the preconditions instead.
There's one exception to "duplicate property name is a programming
error": the way object_property_add() implements the magic (and
undocumented) "automatic arrayification". Don't drop @errp there.
Instead, rename object_property_add() to object_property_try_add(),
and add the obvious wrapper object_property_add().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20200505152926.18877-15-armbru@redhat.com>
[Two semantic rebase conflicts resolved]
2020-05-05 15:29:22 +00:00
|
|
|
NULL, NULL);
|
block: convert ThrottleGroup to object with QOM
ThrottleGroup is converted to an object. This will allow the future
throttle block filter drive easy creation and configuration of throttle
groups in QMP and cli.
A new QAPI struct, ThrottleLimits, is introduced to provide a shared
struct for all throttle configuration needs in QMP.
ThrottleGroups can be created via CLI as
-object throttle-group,id=foo,x-iops-total=100,x-..
where x-* are individual limit properties. Since we can't add non-scalar
properties in -object this interface must be used instead. However,
setting these properties must be disabled after initialization because
certain combinations of limits are forbidden and thus configuration
changes should be done in one transaction. The individual properties
will go away when support for non-scalar values in CLI is implemented
and thus are marked as experimental.
ThrottleGroup also has a `limits` property that uses the ThrottleLimits
struct. It can be used to create ThrottleGroups or set the
configuration in existing groups as follows:
{ "execute": "object-add",
"arguments": {
"qom-type": "throttle-group",
"id": "foo",
"props" : {
"limits": {
"iops-total": 100
}
}
}
}
{ "execute" : "qom-set",
"arguments" : {
"path" : "foo",
"property" : "limits",
"value" : {
"iops-total" : 99
}
}
}
This also means a group's configuration can be fetched with qom-get.
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2017-08-25 13:20:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static const TypeInfo throttle_group_info = {
|
|
|
|
.name = TYPE_THROTTLE_GROUP,
|
|
|
|
.parent = TYPE_OBJECT,
|
|
|
|
.class_init = throttle_group_obj_class_init,
|
|
|
|
.instance_size = sizeof(ThrottleGroup),
|
|
|
|
.instance_init = throttle_group_obj_init,
|
|
|
|
.instance_finalize = throttle_group_obj_finalize,
|
|
|
|
.interfaces = (InterfaceInfo[]) {
|
|
|
|
{ TYPE_USER_CREATABLE },
|
|
|
|
{ }
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2015-06-08 16:17:42 +00:00
|
|
|
static void throttle_groups_init(void)
|
|
|
|
{
|
block: convert ThrottleGroup to object with QOM
ThrottleGroup is converted to an object. This will allow the future
throttle block filter drive easy creation and configuration of throttle
groups in QMP and cli.
A new QAPI struct, ThrottleLimits, is introduced to provide a shared
struct for all throttle configuration needs in QMP.
ThrottleGroups can be created via CLI as
-object throttle-group,id=foo,x-iops-total=100,x-..
where x-* are individual limit properties. Since we can't add non-scalar
properties in -object this interface must be used instead. However,
setting these properties must be disabled after initialization because
certain combinations of limits are forbidden and thus configuration
changes should be done in one transaction. The individual properties
will go away when support for non-scalar values in CLI is implemented
and thus are marked as experimental.
ThrottleGroup also has a `limits` property that uses the ThrottleLimits
struct. It can be used to create ThrottleGroups or set the
configuration in existing groups as follows:
{ "execute": "object-add",
"arguments": {
"qom-type": "throttle-group",
"id": "foo",
"props" : {
"limits": {
"iops-total": 100
}
}
}
}
{ "execute" : "qom-set",
"arguments" : {
"path" : "foo",
"property" : "limits",
"value" : {
"iops-total" : 99
}
}
}
This also means a group's configuration can be fetched with qom-get.
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2017-08-25 13:20:26 +00:00
|
|
|
type_register_static(&throttle_group_info);
|
2015-06-08 16:17:42 +00:00
|
|
|
}
|
|
|
|
|
block: convert ThrottleGroup to object with QOM
ThrottleGroup is converted to an object. This will allow the future
throttle block filter drive easy creation and configuration of throttle
groups in QMP and cli.
A new QAPI struct, ThrottleLimits, is introduced to provide a shared
struct for all throttle configuration needs in QMP.
ThrottleGroups can be created via CLI as
-object throttle-group,id=foo,x-iops-total=100,x-..
where x-* are individual limit properties. Since we can't add non-scalar
properties in -object this interface must be used instead. However,
setting these properties must be disabled after initialization because
certain combinations of limits are forbidden and thus configuration
changes should be done in one transaction. The individual properties
will go away when support for non-scalar values in CLI is implemented
and thus are marked as experimental.
ThrottleGroup also has a `limits` property that uses the ThrottleLimits
struct. It can be used to create ThrottleGroups or set the
configuration in existing groups as follows:
{ "execute": "object-add",
"arguments": {
"qom-type": "throttle-group",
"id": "foo",
"props" : {
"limits": {
"iops-total": 100
}
}
}
}
{ "execute" : "qom-set",
"arguments" : {
"path" : "foo",
"property" : "limits",
"value" : {
"iops-total" : 99
}
}
}
This also means a group's configuration can be fetched with qom-get.
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2017-08-25 13:20:26 +00:00
|
|
|
type_init(throttle_groups_init);
|