From nobody Wed Feb 11 01:09:06 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 150366791161416.949570882023863; Fri, 25 Aug 2017 06:31:51 -0700 (PDT) Received: from localhost ([::1]:53347 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dlEiE-00051c-EV for importer@patchew.org; Fri, 25 Aug 2017 09:31:50 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38440) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dlEbV-00077t-JH for qemu-devel@nongnu.org; Fri, 25 Aug 2017 09:24:55 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dlEbT-0003Sl-0Q for qemu-devel@nongnu.org; Fri, 25 Aug 2017 09:24:53 -0400 Received: from smtp1.ntua.gr ([2001:648:2000:de::183]:40256) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dlEbO-0003PL-6a; Fri, 25 Aug 2017 09:24:46 -0400 Received: from mail.ntua.gr (carp0.noc.ntua.gr [147.102.222.60]) (authenticated bits=0) by smtp1.ntua.gr (8.15.2/8.15.2) with ESMTPSA id v7PDOCit025232 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 25 Aug 2017 16:24:12 +0300 (EEST) (envelope-from el13635@mail.ntua.gr) X-Authentication-Warning: smtp1.ntua.gr: Host carp0.noc.ntua.gr [147.102.222.60] claimed to be mail.ntua.gr From: Manos Pitsidianakis To: qemu-devel Date: Fri, 25 Aug 2017 16:23:30 +0300 Message-Id: <20170825132332.6734-6-el13635@mail.ntua.gr> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20170825132332.6734-1-el13635@mail.ntua.gr> References: <20170825132332.6734-1-el13635@mail.ntua.gr> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2001:648:2000:de::183 Subject: [Qemu-devel] [PATCH v3 5/7] block/throttle-groups.c: remove throttle-groups list X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Alberto Garcia , Stefan Hajnoczi , qemu-block Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" block/throttle-groups.c uses a list to keep track of all groups and make sure all names are unique. This patch moves all ThrottleGroup objects under the root container. While block/throttle.c requires that all throttle groups are created with object-add or -object, the legacy throttling interface still used the throttle_groups list. By using the root container we get the name collision check for free and have all groups, legacy or not, available through the qom-get/qom-set commands. Legacy groups are marked and freed when they have no users left instead of waiting for an explicit object-del. Signed-off-by: Manos Pitsidianakis --- include/block/throttle-groups.h | 1 + block/block-backend.c | 15 +++-- block/throttle-groups.c | 145 +++++++++++++++++++++++-------------= ---- tests/test-throttle.c | 3 + 4 files changed, 96 insertions(+), 68 deletions(-) diff --git a/include/block/throttle-groups.h b/include/block/throttle-group= s.h index 8493540766..13fbc63f1e 100644 --- a/include/block/throttle-groups.h +++ b/include/block/throttle-groups.h @@ -58,6 +58,7 @@ typedef struct ThrottleGroupMember { =20 const char *throttle_group_get_name(ThrottleGroupMember *tgm); =20 +void throttle_group_new_legacy(const char *name, Error **errp); ThrottleState *throttle_group_incref(const char *name); void throttle_group_unref(ThrottleState *ts); =20 diff --git a/block/block-backend.c b/block/block-backend.c index 693ad27fc9..65f458ce8f 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -1957,12 +1957,18 @@ void blk_io_limits_enable(BlockBackend *blk, const = char *group, Error **errp) BlockDriverState *bs =3D blk_bs(blk), *throttle_node; QDict *options =3D qdict_new(); Error *local_err =3D NULL; - ThrottleState *ts; - - bdrv_drained_begin(bs); =20 /* Force creation of group in case it doesn't exist */ - ts =3D throttle_group_incref(group); + if (!throttle_group_exists(group)) { + throttle_group_new_legacy(group, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + } + + bdrv_drained_begin(bs); + qdict_set_default_str(options, "file", bs->node_name); qdict_set_default_str(options, QEMU_OPT_THROTTLE_GROUP_NAME, group); throttle_node =3D bdrv_new_open_driver(bdrv_find_format("throttle"), N= ULL, @@ -1987,7 +1993,6 @@ void blk_io_limits_enable(BlockBackend *blk, const ch= ar *group, Error **errp) assert(throttle_node->refcnt =3D=3D 1); =20 end: - throttle_group_unref(ts); bdrv_drained_end(bs); blk_get_public(blk)->throttle_node =3D throttle_node; } diff --git a/block/throttle-groups.c b/block/throttle-groups.c index 454bfcb067..238b648489 100644 --- a/block/throttle-groups.c +++ b/block/throttle-groups.c @@ -33,8 +33,10 @@ #include "qapi-visit.h" #include "qom/object.h" #include "qom/object_interfaces.h" +#include "qapi/qobject-input-visitor.h" =20 static void throttle_group_obj_init(Object *obj); +static bool throttle_group_can_be_deleted(UserCreatable *uc, Error **errp); static void throttle_group_obj_complete(UserCreatable *obj, Error **errp); =20 /* The ThrottleGroup structure (with its ThrottleState) is shared @@ -66,6 +68,7 @@ typedef struct ThrottleGroup { =20 /* refuse individual property change if initialization is complete */ bool is_initialized; + bool legacy; char *name; /* This is constant during the lifetime of the group */ =20 QemuMutex lock; /* This lock protects the following four fields */ @@ -74,34 +77,47 @@ typedef struct ThrottleGroup { ThrottleGroupMember *tokens[2]; bool any_timer_armed[2]; QEMUClockType clock_type; - - /* This field is protected by the global QEMU mutex */ - QTAILQ_ENTRY(ThrottleGroup) list; } ThrottleGroup; =20 -/* This is protected by the global QEMU mutex */ -static QTAILQ_HEAD(, ThrottleGroup) throttle_groups =3D - QTAILQ_HEAD_INITIALIZER(throttle_groups); =20 +struct ThrottleGroupQuery { + const char *name; + ThrottleGroup *result; +}; =20 -/* This function reads throttle_groups and must be called under the global - * mutex. +static int query_throttle_groups_foreach(Object *obj, void *data) +{ + ThrottleGroup *tg; + struct ThrottleGroupQuery *query =3D data; + + tg =3D (ThrottleGroup *)object_dynamic_cast(obj, TYPE_THROTTLE_GROUP); + if (!tg) { + return 0; + } + + if (!g_strcmp0(query->name, tg->name)) { + query->result =3D tg; + return 1; + } + + return 0; +} + + +/* This function reads the QOM root container and must be called under the + * global mutex. */ static ThrottleGroup *throttle_group_by_name(const char *name) { - ThrottleGroup *iter; + struct ThrottleGroupQuery query =3D { name =3D name }; =20 /* Look for an existing group with that name */ - QTAILQ_FOREACH(iter, &throttle_groups, list) { - if (!g_strcmp0(name, iter->name)) { - return iter; - } - } - - return NULL; + object_child_foreach(object_get_objects_root(), + query_throttle_groups_foreach, &query); + return query.result; } =20 -/* This function reads throttle_groups and must be called under the global +/* This function must be called under the global * mutex. */ bool throttle_group_exists(const char *name) @@ -109,34 +125,49 @@ bool throttle_group_exists(const char *name) return throttle_group_by_name(name) !=3D NULL; } =20 +/* + * Create a new ThrottleGroup, insert it in the object root container so t= hat + * we can refer to it by id and set tg->legacy to true + * + * This function edits the QOM root container and must be called under the + * global mutex. + * + * @name: the name of the ThrottleGroup. + * @errp: Error object. Will be set if @name collides with a non-ThrottleG= roup + * QOM object + */ +void throttle_group_new_legacy(const char *name, Error **errp) +{ + ThrottleGroup *tg =3D NULL; + + /* Create an empty property qdict. Caller is responsible for + * setting up limits */ + QDict *pdict =3D qdict_new(); + Visitor *v =3D qobject_input_visitor_new(QOBJECT(pdict)); + + /* tg will have a ref count of 2, one for the object root container + * and one for the caller */ + tg =3D THROTTLE_GROUP(user_creatable_add_type(TYPE_THROTTLE_GROUP, + name, pdict, v, errp)); + visit_free(v); + QDECREF(pdict); + if (!tg) { + return; + } + tg->legacy =3D true; +} + /* Increments the reference count of a ThrottleGroup given its name. * - * If no ThrottleGroup is found with the given name a new one is - * created. - * - * This function edits throttle_groups and must be called under the global - * mutex. - * * @name: the name of the ThrottleGroup * @ret: the ThrottleState member of the ThrottleGroup */ ThrottleState *throttle_group_incref(const char *name) { - ThrottleGroup *tg =3D NULL; - - /* Look for an existing group with that name */ - tg =3D 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 =3D 1 */ - tg =3D THROTTLE_GROUP(object_new(TYPE_THROTTLE_GROUP)); - tg->name =3D g_strdup(name); - throttle_group_obj_complete(USER_CREATABLE(tg), &error_abort); - } + ThrottleGroup *tg =3D throttle_group_by_name(name); =20 + assert(tg); + object_ref(OBJECT(tg)); return &tg->ts; } =20 @@ -145,8 +176,8 @@ ThrottleState *throttle_group_incref(const char *name) * When the reference count reaches zero the ThrottleGroup is * destroyed. * - * This function edits throttle_groups and must be called under the global - * mutex. + * This function edits the QOM root container and must be called under the + * global mutex. * * @ts: The ThrottleGroup to unref, given by its ThrottleState member */ @@ -154,6 +185,13 @@ void throttle_group_unref(ThrottleState *ts) { ThrottleGroup *tg =3D container_of(ts, ThrottleGroup, ts); object_unref(OBJECT(tg)); + /* ThrottleGroups will always have an extra reference from their conta= iner, + * so accessing it now is safe */ + if (tg->legacy && OBJECT(tg)->ref =3D=3D 1) { + tg->legacy =3D false; + /* Drop object created from legacy interface manually */ + user_creatable_del(tg->name, &error_abort); + } } =20 /* Get the name from a ThrottleGroupMember's group. The name (and the poin= ter) @@ -490,14 +528,10 @@ static void write_timer_cb(void *opaque) } =20 /* Register a ThrottleGroupMember from the throttling group, also initiali= zing - * its timers and updating its throttle_state pointer to point to it. If a - * throttling group with that name does not exist yet, it will be created. - * - * This function edits throttle_groups and must be called under the global - * mutex. + * its timers and updating its throttle_state pointer to point to it. * * @tgm: the ThrottleGroupMember to insert - * @groupname: the name of the group + * @groupname: the name of the group. It must already exist. * @ctx: the AioContext to use */ void throttle_group_register_tgm(ThrottleGroupMember *tgm, @@ -690,8 +724,6 @@ static ThrottleParamInfo properties[] =3D { } }; =20 -/* This function edits throttle_groups and must be called under the global - * mutex */ static void throttle_group_obj_init(Object *obj) { ThrottleGroup *tg =3D THROTTLE_GROUP(obj); @@ -702,49 +734,36 @@ static void throttle_group_obj_init(Object *obj) tg->clock_type =3D QEMU_CLOCK_VIRTUAL; } tg->is_initialized =3D false; + tg->legacy =3D false; qemu_mutex_init(&tg->lock); throttle_init(&tg->ts); QLIST_INIT(&tg->head); } =20 -/* 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 =3D THROTTLE_GROUP(obj); ThrottleConfig cfg; =20 - /* set group name to object id if it exists */ + /* set group name to object id */ if (!tg->name && tg->parent_obj.parent) { tg->name =3D object_get_canonical_path_component(OBJECT(obj)); } /* We must have a group name at this point */ assert(tg->name); =20 - /* error if name is duplicate */ - if (throttle_group_exists(tg->name)) { - 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 =3D true; } =20 -/* This function edits throttle_groups and must be called under the global - * mutex */ static void throttle_group_obj_finalize(Object *obj) { ThrottleGroup *tg =3D THROTTLE_GROUP(obj); - if (tg->is_initialized) { - QTAILQ_REMOVE(&throttle_groups, tg, list); - } qemu_mutex_destroy(&tg->lock); g_free(tg->name); } @@ -881,7 +900,7 @@ static void throttle_group_get_limits(Object *obj, Visi= tor *v, =20 static bool throttle_group_can_be_deleted(UserCreatable *uc, Error **errp) { - return OBJECT(uc)->ref =3D=3D 1; + return OBJECT(uc)->ref =3D=3D 1 && THROTTLE_GROUP(uc)->legacy =3D=3D f= alse; } =20 static void throttle_group_obj_class_init(ObjectClass *klass, void *class_= data) diff --git a/tests/test-throttle.c b/tests/test-throttle.c index eef2b1c707..927117ecab 100644 --- a/tests/test-throttle.c +++ b/tests/test-throttle.c @@ -609,6 +609,9 @@ static void test_groups(void) g_assert(tgm2->throttle_state =3D=3D NULL); g_assert(tgm3->throttle_state =3D=3D NULL); =20 + throttle_group_new_legacy("foo", &error_fatal); + throttle_group_new_legacy("bar", &error_fatal); + throttle_group_register_tgm(tgm1, "bar", blk_get_aio_context(blk1)); throttle_group_register_tgm(tgm2, "foo", blk_get_aio_context(blk2)); throttle_group_register_tgm(tgm3, "bar", blk_get_aio_context(blk3)); --=20 2.11.0