From nobody Sun Dec 7 13:25:43 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=fail(p=none dis=none) header.from=gmail.com Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1739984651284292.07188290719296; Wed, 19 Feb 2025 09:04:11 -0800 (PST) Received: by lists.libvirt.org (Postfix, from userid 996) id A19ED1A7D; Wed, 19 Feb 2025 12:04:10 -0500 (EST) Received: from lists.libvirt.org (localhost [IPv6:::1]) by lists.libvirt.org (Postfix) with ESMTP id A1B5D1BDC; Wed, 19 Feb 2025 12:02:05 -0500 (EST) Received: by lists.libvirt.org (Postfix, from userid 996) id 8DA961BAB; Wed, 19 Feb 2025 12:02:00 -0500 (EST) Received: from mail-pl1-f181.google.com (mail-pl1-f181.google.com [209.85.214.181]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id 846531D49 for ; Wed, 19 Feb 2025 12:01:44 -0500 (EST) Received: by mail-pl1-f181.google.com with SMTP id d9443c01a7336-2211acda7f6so86698735ad.3 for ; Wed, 19 Feb 2025 09:01:44 -0800 (PST) Received: from localhost.localdomain ([2001:4490:4ea9:8374:8512:e327:fdaf:a56e]) by smtp.googlemail.com with ESMTPSA id d9443c01a7336-220d558fe3asm106651545ad.234.2025.02.19.09.01.40 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Wed, 19 Feb 2025 09:01:41 -0800 (PST) X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-0.8 required=5.0 tests=DKIM_ADSP_CUSTOM_MED, DKIM_INVALID,DKIM_SIGNED,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL,RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED,SPF_HELO_NONE autolearn=unavailable autolearn_force=no version=3.4.4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1739984503; x=1740589303; darn=lists.libvirt.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=0wVMQbFgeq5XwZ0LGnZaFHZhT8eVVaoPeS7ILSC5q8s=; b=Pn4G5eFqkpKLVZAU5NFTEz4sC83wnwG4nKVUc+26d/eUUqJpFhBIxYiAnr72jkXor0 VqAR2DWs2MBuHQIuc9C+q6mR0E8XEvgEytXwiCkl7XRg1hT8hZSqf+NgV1rJwbjafGIG xkKUPIxRUoMtBcgeyypJ6ZUws8CfZILyY1ynNxN2pg4Ndqlt8314JSPIVoxXwcFIcxZQ zZZzneYJL1oMkh/c2DAj3XInBM9hlpbKBclwV1z3gXiPNjGZnRHtj0OX1M+Pebmka4SJ sTkBMzQJ+SO0bT88HdAVE4juSqiN8fy2lP+YKBB6nYGFehWbC4Nrjw8dWbz3ZdI4ZZ4q KOIw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1739984503; x=1740589303; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=0wVMQbFgeq5XwZ0LGnZaFHZhT8eVVaoPeS7ILSC5q8s=; b=Lxb6Dk/Ge4G4WXYS05Rl4yVUp4iHrsCzZ/lcdYcrx6YGtgj86DF0bBxu+eQ1K4XOEa OrAGc5IUP/Va8DpsfKiYWRWyXir37Lj30dOEMoLox1b5O9KFzXhwfowAjbL2tk820B8Z j7PPlhFLLLn80B3U458fmdpiF5zQD+mz4a+YLb1YTPWlhUqGKh0z2LOj1WMahXcohGBQ cqphuKOVorNvO3EAl+zTGwGvQWoSJL4LHgYwn8fVXO0zwMJMWQLbsDWK0/l8UJgZHrNZ Yoazkx52RsSRn5HM7GaVmtiRGMp3lLmWEIS+xkbiIUaNK/nP4kpBYiefhtxJSaCbSLbf ybtQ== X-Gm-Message-State: AOJu0YyQAJkdHD82Avk/44rdOfkAzjDVSThby2x5z1fgQJFw7aoLEjfM 8I4ZunnGI9FQ0a2qdKxI8n3FzE6j4R6MJqPHNwUTRg1pcOlbUGDbSx3/D1uH8kM= X-Gm-Gg: ASbGncujULhMDhe5OM2xM9+i7r1bu8Vaw6vOgw6i0Nl3MOcuYs18F+sLFui8Z82W2mg Ev/IonBLObsdMmR8/0qyZMdzhl2w4WA7pfmyMBCSp32JQhCHXmyPlj0t4hcF0aybukGYrxNTLwJ qDIp8tbmGeNfsrYXqmV6bbMyMu/rJZU1QGv+lz+Jq7V6Bi+Ju3TEYBH9WJIyVnLl2n1uoaQkRB1 WesFmxVGKObHPMuVRx1mKpKgwRGy+RMg8hLAOJbYYCj5D8mD81yHin4kgMgsAbhPrAnXz5Z0BQv N07QD0bQ4cnvq0XqJKT39Bi2ekVqurR4TQ15rfK1K1z0G596HZGe3aS+uQ== X-Google-Smtp-Source: AGHT+IEaos9XJ9ZP2w3hhD+zPpFrx9iTHCC5so/hH8VqBQz7UuiTF8TyWydH1Jvr11MWQfBRkUNzbA== X-Received: by 2002:a17:902:fc48:b0:216:682f:175 with SMTP id d9443c01a7336-221711c4c39mr71586655ad.49.1739984502420; Wed, 19 Feb 2025 09:01:42 -0800 (PST) From: Harikumar Rajkumar To: devel@lists.libvirt.org Subject: [PATCH v8 03/18] config: Introduce ThrottleGroup and corresponding XML parsing Date: Wed, 19 Feb 2025 22:27:07 +0530 Message-Id: <20250219165722.26348-4-harirajkumar230@gmail.com> X-Mailer: git-send-email 2.39.5 (Apple Git-154) In-Reply-To: <20250219165722.26348-1-harirajkumar230@gmail.com> References: <20250219165722.26348-1-harirajkumar230@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Message-ID-Hash: 4GE63XFAP73A7N65UDZVPH43DEXQOPNC X-Message-ID-Hash: 4GE63XFAP73A7N65UDZVPH43DEXQOPNC X-MailFrom: harirajkumar230@gmail.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-config-1; header-match-config-2; header-match-config-3; header-match-devel.lists.libvirt.org-0; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header CC: sanjeev.ranjan@ibm.com, harikumar.rajkumar@ibm.com, earulana@in.ibm.com, Chun Feng Wu , Harikumar Rajkumar X-Mailman-Version: 3.2.2 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1739984657159019000 Content-Type: text/plain; charset="utf-8" From: Chun Feng Wu Introduce throttlegroup into domain and provide corresponding methods * Define new struct 'virDomainThrottleGroupDef' and corresponding destructor * Add operations(Add, Update, Del, ByName, Copy, Free) for 'virDomainThrott= leGroupDef' * Update _virDomainDef to include virDomainThrottleGroupDef * Support new resource "Parse" and "Format" for operations between struct a= nd DOM XML * Make sure "group_name" is defined in xml Signed-off-by: Chun Feng Wu * Validation check for zero throttle groups. * Update of code documentation comments. Signed-off-by: Harikumar Rajkumar Reviewed-by: Peter Krempa --- src/conf/domain_conf.c | 300 ++++++++++++++++++++++++++++++++++++++++ src/conf/domain_conf.h | 27 ++++ src/conf/virconftypes.h | 2 + 3 files changed, 329 insertions(+) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 49555efc56..40f4bf6f49 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -3799,6 +3799,32 @@ virDomainIOThreadIDDefArrayInit(virDomainDef *def, } =20 =20 +void +virDomainThrottleGroupDefFree(virDomainThrottleGroupDef *def) +{ + if (!def) + return; + g_free(def->group_name); + g_free(def); +} + + +static void +virDomainThrottleGroupDefArrayFree(virDomainThrottleGroupDef **def, + int nthrottlegroups) +{ + size_t i; + + if (!def) + return; + + for (i =3D 0; i < nthrottlegroups; i++) + virDomainThrottleGroupDefFree(def[i]); + + g_free(def); +} + + void virDomainResourceDefFree(virDomainResourceDef *resource) { @@ -4086,6 +4112,8 @@ void virDomainDefFree(virDomainDef *def) =20 virDomainIOThreadIDDefArrayFree(def->iothreadids, def->niothreadids); =20 + virDomainThrottleGroupDefArrayFree(def->throttlegroups, def->nthrottle= groups); + g_free(def->defaultIOThread); =20 virBitmapFree(def->cputune.emulatorpin); @@ -7830,6 +7858,123 @@ virDomainDiskDefIotuneParse(virDomainDiskDef *def, } #undef PARSE_IOTUNE =20 +/* the field changes must also be applied to the other function that forma= ts + * the throttling definition virDomainThrottleGroupFormat. */ +#define PARSE_THROTTLEGROUP(val) \ + if (virXPathULongLong("string(./" #val ")", \ + ctxt, &group->val) =3D=3D -2) { \ + virReportError(VIR_ERR_XML_ERROR, \ + _("throttle group field '%1$s' must be an integer")= , #val); \ + return NULL; \ + } + + +static virDomainThrottleGroupDef * +virDomainThrottleGroupDefParseXML(xmlNodePtr node, + xmlXPathContextPtr ctxt) +{ + g_autoptr(virDomainThrottleGroupDef) group =3D g_new0(virDomainThrottl= eGroupDef, 1); + + VIR_XPATH_NODE_AUTORESTORE(ctxt) + ctxt->node =3D node; + + PARSE_THROTTLEGROUP(total_bytes_sec); + PARSE_THROTTLEGROUP(read_bytes_sec); + PARSE_THROTTLEGROUP(write_bytes_sec); + PARSE_THROTTLEGROUP(total_iops_sec); + PARSE_THROTTLEGROUP(read_iops_sec); + PARSE_THROTTLEGROUP(write_iops_sec); + + PARSE_THROTTLEGROUP(total_bytes_sec_max); + PARSE_THROTTLEGROUP(read_bytes_sec_max); + PARSE_THROTTLEGROUP(write_bytes_sec_max); + PARSE_THROTTLEGROUP(total_iops_sec_max); + PARSE_THROTTLEGROUP(read_iops_sec_max); + PARSE_THROTTLEGROUP(write_iops_sec_max); + + PARSE_THROTTLEGROUP(size_iops_sec); + + PARSE_THROTTLEGROUP(total_bytes_sec_max_length); + PARSE_THROTTLEGROUP(read_bytes_sec_max_length); + PARSE_THROTTLEGROUP(write_bytes_sec_max_length); + PARSE_THROTTLEGROUP(total_iops_sec_max_length); + PARSE_THROTTLEGROUP(read_iops_sec_max_length); + PARSE_THROTTLEGROUP(write_iops_sec_max_length); + + /* group_name is required */ + if (!(group->group_name =3D virXPathString("string(./group_name)", ctx= t))) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing group name")); + return NULL; + } + + return g_steal_pointer(&group); +} +#undef PARSE_THROTTLEGROUP + + +/** + * virDomainThrottleGroupByName: + * @def: domain definition + * @name: throttle group name + * + * search throttle group within domain definition + * by @name + * + * Returns a pointer to throttle group found. + */ +virDomainThrottleGroupDef * +virDomainThrottleGroupByName(const virDomainDef *def, + const char *name) +{ + size_t i; + + if (!def->throttlegroups || def->nthrottlegroups =3D=3D 0) + return NULL; + + for (i =3D 0; i < def->nthrottlegroups; i++) { + if (STREQ(def->throttlegroups[i]->group_name, name)) + return def->throttlegroups[i]; + } + + return NULL; +} + + +static int +virDomainDefThrottleGroupsParse(virDomainDef *def, + xmlXPathContextPtr ctxt) +{ + size_t i; + int n =3D 0; + g_autofree xmlNodePtr *nodes =3D NULL; + + if ((n =3D virXPathNodeSet("./throttlegroups/throttlegroup", ctxt, &no= des)) < 0) + return -1; + + if (n =3D=3D 0) + return 0; + + def->throttlegroups =3D g_new0(virDomainThrottleGroupDef *, n); + + for (i =3D 0; i < n; i++) { + g_autoptr(virDomainThrottleGroupDef) group =3D NULL; + + if (!(group =3D virDomainThrottleGroupDefParseXML(nodes[i], ctxt))= ) { + return -1; + } + + if (virDomainThrottleGroupByName(def, group->group_name)) { + virReportError(VIR_ERR_XML_ERROR, + _("duplicate group name '%1$s' found"), + group->group_name); + return -1; + } + def->throttlegroups[def->nthrottlegroups++] =3D g_steal_pointer(&g= roup); + } + return 0; +} + =20 static int virDomainDiskDefMirrorParse(virDomainDiskDef *def, @@ -19212,6 +19357,9 @@ virDomainDefParseXML(xmlXPathContextPtr ctxt, if (virDomainDefParseBootOptions(def, ctxt, xmlopt, flags) < 0) return NULL; =20 + if (virDomainDefThrottleGroupsParse(def, ctxt) < 0) + return NULL; + /* analysis of the disk devices */ if ((n =3D virXPathNodeSet("./devices/disk", ctxt, &nodes)) < 0) return NULL; @@ -22510,6 +22658,94 @@ virDomainIOThreadIDDel(virDomainDef *def, } =20 =20 +/** + * virDomainThrottleGroupDefCopy: + * @src: throttle group to be copied from + * @dst: throttle group to be copied to + * + * copy throttle group content from @src to @dst, + * this function does not allocate memory for @dst - the caller must ensure + * @dst is already allocated before calling this function. + */ +void +virDomainThrottleGroupDefCopy(const virDomainThrottleGroupDef *src, + virDomainThrottleGroupDef *dst) +{ + *dst =3D *src; + dst->group_name =3D g_strdup(src->group_name); +} + + +/** + * virDomainThrottleGroupAdd: + * @def: domain definition + * @throttle_group: throttle group definition within domain + * + * add new throttle group into @def + * + * return a pointer to throttle group added + */ +virDomainThrottleGroupDef * +virDomainThrottleGroupAdd(virDomainDef *def, + virDomainThrottleGroupDef *throttle_group) +{ + virDomainThrottleGroupDef * new_group =3D g_new0(virDomainThrottleGro= upDef, 1); + virDomainThrottleGroupDefCopy(throttle_group, new_group); + VIR_APPEND_ELEMENT_COPY(def->throttlegroups, def->nthrottlegroups, new= _group); + return new_group; +} + + +/** + * virDomainThrottleGroupUpdate: + * @def: domain definition + * @info: throttle group definition within domain + * + * Update corresponding throttle group in @def using new config @info. If a + * throttle group with given name doesn't exist this function does nothing. + */ +void +virDomainThrottleGroupUpdate(virDomainDef *def, + virDomainThrottleGroupDef *info) +{ + size_t i; + + if (!info->group_name) + return; + + for (i =3D 0; i < def->nthrottlegroups; i++) { + virDomainThrottleGroupDef *t =3D def->throttlegroups[i]; + + if (STREQ_NULLABLE(t->group_name, info->group_name)) { + VIR_FREE(t->group_name); + virDomainThrottleGroupDefCopy(info, t); + } + } +} + + +/** + * virDomainThrottleGroupDel: + * @def: domain definition + * @name: throttle group name + * + * Delete throttle group @name in @def + */ +void +virDomainThrottleGroupDel(virDomainDef *def, + const char *name) +{ + size_t i; + for (i =3D 0; i < def->nthrottlegroups; i++) { + if (STREQ_NULLABLE(def->throttlegroups[i]->group_name, name)) { + virDomainThrottleGroupDefFree(def->throttlegroups[i]); + VIR_DELETE_ELEMENT(def->throttlegroups, i, def->nthrottlegroup= s); + return; + } + } +} + + static int virDomainEventActionDefFormat(virBuffer *buf, int type, @@ -27697,6 +27933,68 @@ virDomainDefIOThreadsFormat(virBuffer *buf, virDomainDefaultIOThreadDefFormat(buf, def); } =20 +/* + * the field changes must also be applied to the other function that parses + * the throttling definition virDomainThrottleGroupDefParseXML + */ +#define FORMAT_THROTTLE_GROUP(val) \ + if (group->val > 0) { \ + virBufferAsprintf(&childBuf, "<" #val ">%llu\n", \ + group->val); \ + } + + +static void +virDomainThrottleGroupFormat(virBuffer *buf, + virDomainThrottleGroupDef *group) +{ + g_auto(virBuffer) childBuf =3D VIR_BUFFER_INIT_CHILD(buf); + + FORMAT_THROTTLE_GROUP(total_bytes_sec); + FORMAT_THROTTLE_GROUP(read_bytes_sec); + FORMAT_THROTTLE_GROUP(write_bytes_sec); + FORMAT_THROTTLE_GROUP(total_iops_sec); + FORMAT_THROTTLE_GROUP(read_iops_sec); + FORMAT_THROTTLE_GROUP(write_iops_sec); + + FORMAT_THROTTLE_GROUP(total_bytes_sec_max); + FORMAT_THROTTLE_GROUP(read_bytes_sec_max); + FORMAT_THROTTLE_GROUP(write_bytes_sec_max); + FORMAT_THROTTLE_GROUP(total_iops_sec_max); + FORMAT_THROTTLE_GROUP(read_iops_sec_max); + FORMAT_THROTTLE_GROUP(write_iops_sec_max); + + FORMAT_THROTTLE_GROUP(size_iops_sec); + + FORMAT_THROTTLE_GROUP(total_bytes_sec_max_length); + FORMAT_THROTTLE_GROUP(read_bytes_sec_max_length); + FORMAT_THROTTLE_GROUP(write_bytes_sec_max_length); + FORMAT_THROTTLE_GROUP(total_iops_sec_max_length); + FORMAT_THROTTLE_GROUP(read_iops_sec_max_length); + FORMAT_THROTTLE_GROUP(write_iops_sec_max_length); + + virBufferEscapeString(&childBuf, "%s\n", + group->group_name); + + virXMLFormatElement(buf, "throttlegroup", NULL, &childBuf); +} + +#undef FORMAT_THROTTLE_GROUP + +static void +virDomainDefThrottleGroupsFormat(virBuffer *buf, + const virDomainDef *def) +{ + g_auto(virBuffer) childrenBuf =3D VIR_BUFFER_INIT_CHILD(buf); + size_t n; + + for (n =3D 0; n < def->nthrottlegroups; n++) { + virDomainThrottleGroupFormat(&childrenBuf, def->throttlegroups[n]); + } + + virXMLFormatElement(buf, "throttlegroups", NULL, &childrenBuf); +} + =20 static void virDomainIOMMUDefFormat(virBuffer *buf, @@ -28399,6 +28697,8 @@ virDomainDefFormatInternalSetRootName(virDomainDef = *def, =20 virDomainDefIOThreadsFormat(buf, def); =20 + virDomainDefThrottleGroupsFormat(buf, def); + if (virDomainCputuneDefFormat(buf, def, flags) < 0) return -1; =20 diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 9da6586e66..211054274f 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -3079,6 +3079,9 @@ struct _virDomainDef { =20 virDomainDefaultIOThreadDef *defaultIOThread; =20 + size_t nthrottlegroups; + virDomainThrottleGroupDef **throttlegroups; + virDomainCputune cputune; =20 virDomainResctrlDef **resctrls; @@ -4600,3 +4603,27 @@ virDomainObjGetMessages(virDomainObj *vm, =20 bool virDomainDefHasSpiceGraphics(const virDomainDef *def); + +void +virDomainThrottleGroupDefFree(virDomainThrottleGroupDef *def); +G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainThrottleGroupDef, virDomainThrottle= GroupDefFree); + +virDomainThrottleGroupDef * +virDomainThrottleGroupAdd(virDomainDef *def, + virDomainThrottleGroupDef *throttle_group); + +void +virDomainThrottleGroupUpdate(virDomainDef *def, + virDomainThrottleGroupDef *info); + +void +virDomainThrottleGroupDel(virDomainDef *def, + const char *name); + +virDomainThrottleGroupDef * +virDomainThrottleGroupByName(const virDomainDef *def, + const char *name); + +void +virDomainThrottleGroupDefCopy(const virDomainThrottleGroupDef *src, + virDomainThrottleGroupDef *dst); diff --git a/src/conf/virconftypes.h b/src/conf/virconftypes.h index 59be61cea4..1936ef6ab1 100644 --- a/src/conf/virconftypes.h +++ b/src/conf/virconftypes.h @@ -80,6 +80,8 @@ typedef struct _virDomainBlkiotune virDomainBlkiotune; =20 typedef struct _virDomainBlockIoTuneInfo virDomainBlockIoTuneInfo; =20 +typedef struct _virDomainBlockIoTuneInfo virDomainThrottleGroupDef; + typedef struct _virDomainCheckpointDef virDomainCheckpointDef; =20 typedef struct _virDomainCheckpointObj virDomainCheckpointObj; --=20 2.39.5 (Apple Git-154)