From nobody Sat Feb 7 10:44:29 2026 Delivered-To: importer@patchew.org Received-SPF: none (zohomail.com: 8.43.85.245 is neither permitted nor denied by domain of lists.libvirt.org) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; spf=none (zohomail.com: 8.43.85.245 is neither permitted nor denied by domain of lists.libvirt.org) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=fail(p=reject dis=none) header.from=linux.ibm.com Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1712721306389832.4560010511332; Tue, 9 Apr 2024 20:55:06 -0700 (PDT) Received: by lists.libvirt.org (Postfix, from userid 996) id 33ADE1A2A; Tue, 9 Apr 2024 23:55:05 -0400 (EDT) Received: from lists.libvirt.org (localhost [IPv6:::1]) by lists.libvirt.org (Postfix) with ESMTP id 3354919D1; Tue, 9 Apr 2024 23:53:11 -0400 (EDT) Received: by lists.libvirt.org (Postfix, from userid 996) id 3930817FC; Tue, 9 Apr 2024 23:53:09 -0400 (EDT) Received: from mx0b-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) (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 D02341873 for ; Tue, 9 Apr 2024 23:53:07 -0400 (EDT) Received: from pps.filterd (m0353722.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 43A2mbip011629 for ; Wed, 10 Apr 2024 03:14:29 GMT Received: from ppma13.dal12v.mail.ibm.com (dd.9e.1632.ip4.static.sl-reverse.com [50.22.158.221]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3xdja381qh-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Wed, 10 Apr 2024 03:14:29 +0000 Received: from pps.filterd (ppma13.dal12v.mail.ibm.com [127.0.0.1]) by ppma13.dal12v.mail.ibm.com (8.17.1.19/8.17.1.19) with ESMTP id 43A20lQS021523 for ; Wed, 10 Apr 2024 03:14:28 GMT Received: from smtprelay02.dal12v.mail.ibm.com ([172.16.1.4]) by ppma13.dal12v.mail.ibm.com (PPS) with ESMTPS id 3xbjxkt0t7-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Wed, 10 Apr 2024 03:14:28 +0000 Received: from smtpav03.dal12v.mail.ibm.com (smtpav03.dal12v.mail.ibm.com [10.241.53.102]) by smtprelay02.dal12v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 43A3EPAl46465716 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 10 Apr 2024 03:14:27 GMT Received: from smtpav03.dal12v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id AB5E958064; Wed, 10 Apr 2024 03:14:25 +0000 (GMT) Received: from smtpav03.dal12v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id B1E225803F; Wed, 10 Apr 2024 03:14:24 +0000 (GMT) Received: from libvirt-dev-u221.fyre.ibm.com (unknown [9.112.252.183]) by smtpav03.dal12v.mail.ibm.com (Postfix) with ESMTP; Wed, 10 Apr 2024 03:14:24 +0000 (GMT) X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-0.7 required=5.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, MAILING_LIST_MULTI,RCVD_IN_MSPIKE_H4,RCVD_IN_MSPIKE_WL,SPF_HELO_NONE autolearn=unavailable autolearn_force=no version=3.4.4 From: wucf@linux.ibm.com To: devel@lists.libvirt.org Cc: Chun Feng Wu Subject: [PATCH RFC 04/12] qemu: hotplug: Support hot attach block disk along with throttle filters Date: Tue, 9 Apr 2024 20:13:12 -0700 Message-Id: <20240410031320.1288203-5-wucf@linux.ibm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240410031320.1288203-1-wucf@linux.ibm.com> References: <20240410031320.1288203-1-wucf@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-ORIG-GUID: 3R7bioiBf7N2stR4u_bhqvwwaphYJ4T3 X-Proofpoint-GUID: 3R7bioiBf7N2stR4u_bhqvwwaphYJ4T3 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.272,Aquarius:18.0.1011,Hydra:6.0.619,FMLib:17.11.176.26 definitions=2024-04-09_12,2024-04-09_01,2023-05-22_02 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 mlxscore=0 spamscore=0 lowpriorityscore=0 adultscore=0 clxscore=1015 impostorscore=0 mlxlogscore=999 phishscore=0 bulkscore=0 suspectscore=0 malwarescore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2404010000 definitions=main-2404100022 Message-ID-Hash: KTYH7SINE4P465YDBMKDDASR6RD6IPIQ X-Message-ID-Hash: KTYH7SINE4P465YDBMKDDASR6RD6IPIQ X-MailFrom: wucf@linux.ibm.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 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: Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-ZM-MESSAGEID: 1712721307200100001 From: Chun Feng Wu When attaching disk along with specified throttle groups, those groups will= be chained up by parent node name, this change includes service side codes: * Each filter references one throttle group by group name * Each filter has a nodename, and those filters are chained up in sequence * Filter nodename index is persistented in virDomainObj->privateData(qemuDo= mainObjPrivate) * During hotplug, filter is created through QMP request("blockdev-add" with= "driver":"throttle") to QEMU * Finally, "device_add"(attach) QMP request is adjusted to set "drive" to b= e top filter nodename in chain. Signed-off-by: Chun Feng Wu --- src/qemu/qemu_block.c | 121 ++++++++++++++++++ src/qemu/qemu_block.h | 53 ++++++++ src/qemu/qemu_command.c | 61 +++++++++ src/qemu/qemu_command.h | 6 + src/qemu/qemu_domain.c | 67 ++++++++++ src/qemu/qemu_domain.h | 12 +- src/qemu/qemu_hotplug.c | 23 ++++ .../qemustatusxml2xmldata/backup-pull-in.xml | 1 + .../blockjob-blockdev-in.xml | 1 + .../blockjob-mirror-in.xml | 1 + .../migration-in-params-in.xml | 1 + .../migration-out-nbd-bitmaps-in.xml | 1 + .../migration-out-nbd-out.xml | 1 + .../migration-out-nbd-tls-out.xml | 1 + .../migration-out-params-in.xml | 1 + tests/qemustatusxml2xmldata/modern-in.xml | 1 + tests/qemustatusxml2xmldata/upgrade-out.xml | 1 + .../qemustatusxml2xmldata/vcpus-multi-in.xml | 1 + 18 files changed, 352 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c index 738b72d7ea..3c784d36ea 100644 --- a/src/qemu/qemu_block.c +++ b/src/qemu/qemu_block.c @@ -2738,6 +2738,127 @@ qemuBlockStorageSourceCreateDetectSize(GHashTable *= blockNamedNodeData, return 0; } =20 +void +qemuBlockThrottleFilterSetNodename(virDomainThrottleFilterDef *filter, + char *nodename) +{ + g_free(filter->nodename); + filter->nodename =3D nodename; +} + +const char * +qemuBlockThrottleFilterGetNodename(virDomainThrottleFilterDef *filter) +{ + return filter->nodename; +} + +/** + * qemuBlockThrottleFilterGetProps: + * @filter: throttle filter + * @parentNodeName: parent nodename of @filter + * + * Build "arguments" part of "blockdev-add" QMP cmd. + * e.g. {"execute":"blockdev-add", "arguments":{"driver":"throttle", + * "node-name":"libvirt-2-filter", "throttle-group":"limits0", + * "file": "libvirt-1-format"}} + */ +virJSONValue * +qemuBlockThrottleFilterGetProps(virDomainThrottleFilterDef *filter, + const char *parentNodeName) +{ + g_autoptr(virJSONValue) props =3D NULL; + + if (virJSONValueObjectAdd(&props, + "s:driver", "throttle", + "s:node-name", qemuBlockThrottleFilterGetNod= ename(filter), + "s:throttle-group", filter->group_name, + "s:file", parentNodeName, + NULL) < 0) + return 0; + + return g_steal_pointer(&props); +} + +void +qemuBlockThrottleFilterAttachDataFree(qemuBlockThrottleFilterAttachData *d= ata) +{ + if (!data) + return; + + virJSONValueFree(data->filterProps); + g_free(data); +} + +qemuBlockThrottleFilterAttachData * +qemuBlockThrottleFilterAttachPrepareBlockdev(virDomainThrottleFilterDef *f= ilter, + const char *parentNodeName) +{ + g_autoptr(qemuBlockThrottleFilterAttachData) data =3D NULL; + + data =3D g_new0(qemuBlockThrottleFilterAttachData, 1); + + if (!(data->filterProps =3D qemuBlockThrottleFilterGetProps(filter, pa= rentNodeName))) + return NULL; + + data->filterNodeName =3D qemuBlockThrottleFilterGetNodename(filter); + data->filterAttached =3D true; + + return g_steal_pointer(&data); +} + +void +qemuBlockThrottleFilterAttachRollback(qemuMonitor *mon, + qemuBlockThrottleFilterAttachData *da= ta) +{ + virErrorPtr orig_err; + + virErrorPreserveLast(&orig_err); + + if (data->filterAttached) + ignore_value(qemuMonitorBlockdevDel(mon, data->filterNodeName)); + + virErrorRestore(&orig_err); +} + +void +qemuBlockThrottleFilterChainDataFree(qemuBlockThrottleFilterChainData *dat= a) +{ + size_t i; + + if (!data) + return; + + for (i =3D 0; i < data->nfilterdata; i++) + qemuBlockThrottleFilterAttachDataFree(data->filterdata[i]); + + g_free(data->filterdata); + g_free(data); +} + +int +qemuBlockThrottleFilterChainAttach(qemuMonitor *mon, + qemuBlockThrottleFilterChainData *data) +{ + size_t i; + + for (i =3D 0; i < data->nfilterdata; i++) { + if (qemuMonitorBlockdevAdd(mon, &data->filterdata[i]->filterProps)= < 0) + return -1; + data->filterdata[i]->filterAttached =3D true; + } + + return 0; +} + +void +qemuBlockThrottleFilterChainDetach(qemuMonitor *mon, + qemuBlockThrottleFilterChainData *data) +{ + size_t i; + + for (i =3D data->nfilterdata; i > 0; i--) + qemuBlockThrottleFilterAttachRollback(mon, data->filterdata[i-1]); +} =20 int qemuBlockRemoveImageMetadata(virQEMUDriver *driver, diff --git a/src/qemu/qemu_block.h b/src/qemu/qemu_block.h index f9e961d85d..66bf7a97c3 100644 --- a/src/qemu/qemu_block.h +++ b/src/qemu/qemu_block.h @@ -214,6 +214,59 @@ qemuBlockStorageSourceCreateDetectSize(GHashTable *blo= ckNamedNodeData, virStorageSource *src, virStorageSource *templ); =20 +void +qemuBlockThrottleFilterSetNodename(virDomainThrottleFilterDef *filter, + char *nodename); + +const char * +qemuBlockThrottleFilterGetNodename(virDomainThrottleFilterDef *filter); + +virJSONValue * +qemuBlockThrottleFilterGetProps(virDomainThrottleFilterDef *filter, + const char *parentNodeName); + +typedef struct qemuBlockThrottleFilterAttachData qemuBlockThrottleFilterAt= tachData; +struct qemuBlockThrottleFilterAttachData { + virJSONValue *filterProps; + const char *filterNodeName; + bool filterAttached; +}; + +qemuBlockThrottleFilterAttachData * +qemuBlockThrottleFilterAttachPrepareBlockdev(virDomainThrottleFilterDef *t= hrottlefilter, + const char *parentNodeName); + +void +qemuBlockThrottleFilterAttachDataFree(qemuBlockThrottleFilterAttachData *d= ata); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(qemuBlockThrottleFilterAttachData, + qemuBlockThrottleFilterAttachDataFree); + +void +qemuBlockThrottleFilterAttachRollback(qemuMonitor *mon, + qemuBlockThrottleFilterAttachData *da= ta); + +struct _qemuBlockThrottleFilterChainData { + qemuBlockThrottleFilterAttachData **filterdata; + size_t nfilterdata; +}; + +typedef struct _qemuBlockThrottleFilterChainData qemuBlockThrottleFilterCh= ainData; + +void +qemuBlockThrottleFilterChainDataFree(qemuBlockThrottleFilterChainData *dat= a); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(qemuBlockThrottleFilterChainData, + qemuBlockThrottleFilterChainDataFree); + +int +qemuBlockThrottleFilterChainAttach(qemuMonitor *mon, + qemuBlockThrottleFilterChainData *data); + +void +qemuBlockThrottleFilterChainDetach(qemuMonitor *mon, + qemuBlockThrottleFilterChainData *data); + int qemuBlockRemoveImageMetadata(virQEMUDriver *driver, virDomainObj *vm, diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 9d4563861f..278b706616 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -1576,6 +1576,12 @@ qemuDiskConfigBlkdeviotuneEnabled(const virDomainDis= kDef *disk) virDomainBlockIoTuneInfoHasAny(&disk->blkdeviotune); } =20 +bool +qemuDiskConfigThrottleFilterChainEnabled(const virDomainDiskDef *disk) +{ + return disk->nthrottlefilters > 0; +} + =20 /** * qemuDiskBusIsSD: @@ -1936,6 +1942,10 @@ qemuBuildDiskDeviceProps(const virDomainDef *def, } else { if (qemuDomainDiskGetBackendAlias(disk, &drive) < 0) return NULL; + /* make sure device drive points to top throttle filter */ + if (qemuDiskConfigThrottleFilterChainEnabled(disk)) { + drive =3D g_strdup(disk->throttlefilters[disk->nthrottlefilter= s-1]->nodename); + } } =20 /* bootindex for floppies is configured via the fdc controller */ @@ -11025,6 +11035,57 @@ qemuBuildStorageSourceChainAttachPrepareBlockdevOn= e(qemuBlockStorageSourceChainD return 0; } =20 +/** + * qemuBuildThrottleFilterChainAttachPrepareBlockdevOne: + * @data: filter chain data, which consists of array of filters and size o= f such array + * @throttlefilter: new filter to be added into filter array + * @parentNodeName: parent nodename for this new throttlefilter, which is = used to build "blockdev-add" QMP request + * + * Build filter node chain to provide more flexibility for block disk I/O = limits + */ +static int +qemuBuildThrottleFilterChainAttachPrepareBlockdevOne(qemuBlockThrottleFilt= erChainData *data, + virDomainThrottleFilte= rDef *throttlefilter, + const char *parentNode= Name) +{ + g_autoptr(qemuBlockThrottleFilterAttachData) elem =3D NULL; + + if (!(elem =3D qemuBlockThrottleFilterAttachPrepareBlockdev(throttlefi= lter, parentNodeName))) + return -1; + + VIR_APPEND_ELEMENT(data->filterdata, data->nfilterdata, elem); + return 0; +} + +/** + * qemuBuildThrottleFilterChainAttachPrepareBlockdev: + * @disk: domain disk + * + * Build filter node chain to provide more flexibility for block disk I/O = limits + */ +qemuBlockThrottleFilterChainData * +qemuBuildThrottleFilterChainAttachPrepareBlockdev(virDomainDiskDef *disk) +{ + g_autoptr(qemuBlockThrottleFilterChainData) data =3D NULL; + size_t i; + const char * parentNodeName =3D NULL; + g_autofree char *tmp_nodename =3D NULL; + + data =3D g_new0(qemuBlockThrottleFilterChainData, 1); + /* get starting parentNodename, e.g. libvirt-1-format */ + parentNodeName =3D qemuBlockStorageSourceGetEffectiveNodename(disk->sr= c); + //build filterdata, which contains all filters info and sequence info = through parentNodeName + for (i =3D 0; i < disk->nthrottlefilters; i++) { + tmp_nodename =3D g_strdup(parentNodeName); + if (qemuBuildThrottleFilterChainAttachPrepareBlockdevOne(data, dis= k->throttlefilters[i], tmp_nodename) < 0) + return NULL; + parentNodeName =3D disk->throttlefilters[i]->nodename; + } + + return g_steal_pointer(&data); +} + + =20 /** * qemuBuildStorageSourceChainAttachPrepareBlockdev: diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h index 341ec43f9a..e2dee47906 100644 --- a/src/qemu/qemu_command.h +++ b/src/qemu/qemu_command.h @@ -116,6 +116,12 @@ qemuBlockStorageSourceChainData * qemuBuildStorageSourceChainAttachPrepareBlockdevTop(virStorageSource *top, virStorageSource *back= ingStore); =20 +qemuBlockThrottleFilterChainData * +qemuBuildThrottleFilterChainAttachPrepareBlockdev(virDomainDiskDef *disk); + +bool +qemuDiskConfigThrottleFilterChainEnabled(const virDomainDiskDef *disk); + virJSONValue * qemuBuildDiskDeviceProps(const virDomainDef *def, virDomainDiskDef *disk, diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 7d1c1430ab..c2f5d17c15 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -683,6 +683,17 @@ qemuDomainStorageIDNew(qemuDomainObjPrivate *priv) return ++priv->nodenameindex; } =20 +/** + * qemuDomainThrottleFilterIDNew: + * @priv: qemu VM private data object. + * + * Generate a new unique id for throttle filter object. Useful for node na= me generation. + */ +static unsigned int +qemuDomainThrottleFilterIDNew(qemuDomainObjPrivate *priv) +{ + return ++priv->filternodenameindex; +} =20 /** * qemuDomainStorageIDReset: @@ -697,6 +708,20 @@ qemuDomainStorageIDReset(qemuDomainObjPrivate *priv) priv->nodenameindex =3D 0; } =20 +/** + * qemuDomainThrottleFilterIDReset: + * @priv: qemu VM private data object. + * + * Resets the data for the node name generator. The node names need to be = unique + * for a single instance, so can be reset on VM shutdown. + */ +static void +qemuDomainThrottleFilterIDReset(qemuDomainObjPrivate *priv) +{ + priv->filternodenameindex =3D 0; +} + + =20 /** * qemuDomainFDSetIDNew: @@ -1853,6 +1878,8 @@ qemuDomainObjPrivateDataClear(qemuDomainObjPrivate *p= riv) /* reset node name allocator */ qemuDomainStorageIDReset(priv); =20 + qemuDomainThrottleFilterIDReset(priv); + qemuDomainFDSetIDReset(priv); =20 priv->dbusDaemonRunning =3D false; @@ -2649,6 +2676,8 @@ qemuDomainObjPrivateXMLFormat(virBuffer *buf, =20 virBufferAsprintf(buf, "\n", priv->nodenamei= ndex); =20 + virBufferAsprintf(buf, "\n", priv->fil= ternodenameindex); + virBufferAsprintf(buf, "\n", priv->fdsetindex); =20 if (priv->memPrealloc) @@ -3376,6 +3405,7 @@ qemuDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt, return -1; =20 qemuDomainStorageIDReset(priv); + qemuDomainThrottleFilterIDReset(priv); if (virXPathULongLong("string(./nodename/@index)", ctxt, &priv->nodenameindex) =3D=3D -2) { virReportError(VIR_ERR_XML_ERROR, "%s", @@ -3383,6 +3413,13 @@ qemuDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt, return -1; } =20 + if (virXPathULongLong("string(./filternodename/@index)", ctxt, + &priv->filternodenameindex) =3D=3D -2) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("failed to parse filter node name index")); + return -1; + } + if (virXPathUInt("string(./fdset/@index)", ctxt, &priv->fdsetindex) = =3D=3D 0) priv->fdsetindexParsed =3D true; =20 @@ -11345,6 +11382,30 @@ qemuDomainPrepareStorageSourceBlockdevNodename(vir= DomainDiskDef *disk, return 0; } =20 +int +qemuDomainPrepareThrottleFilterBlockdevNodename(virDomainThrottleFilterDef= *filter, + const char *nodenameprefix) +{ + char *nodename =3D g_strdup_printf("%s-filter", nodenameprefix); + + qemuBlockThrottleFilterSetNodename(filter, nodename); + + return 0; +} + +int +qemuDomainPrepareThrottleFilterBlockdev(virDomainThrottleFilterDef *filter, + qemuDomainObjPrivate *priv) +{ + g_autofree char *nodenameprefix =3D NULL; + + filter->id =3D qemuDomainThrottleFilterIDNew(priv); + + nodenameprefix =3D g_strdup_printf("libvirt-%u", filter->id); + + return qemuDomainPrepareThrottleFilterBlockdevNodename(filter, nodena= meprefix); +} + =20 int qemuDomainPrepareStorageSourceBlockdev(virDomainDiskDef *disk, @@ -11369,6 +11430,7 @@ qemuDomainPrepareDiskSourceBlockdev(virDomainDiskDe= f *disk, { qemuDomainDiskPrivate *diskPriv =3D QEMU_DOMAIN_DISK_PRIVATE(disk); virStorageSource *n; + size_t i; =20 if (disk->copy_on_read =3D=3D VIR_TRISTATE_SWITCH_ON && !diskPriv->nodeCopyOnRead) @@ -11379,6 +11441,11 @@ qemuDomainPrepareDiskSourceBlockdev(virDomainDiskD= ef *disk, return -1; } =20 + for (i =3D 0; i < disk->nthrottlefilters; i++) { + if (qemuDomainPrepareThrottleFilterBlockdev(disk->throttlefilters[= i], priv) < 0) + return -1; + } + return 0; } =20 diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 6343383bf7..ce5f5dfb6e 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -204,6 +204,9 @@ struct _qemuDomainObjPrivate { /* counter for generating node names for qemu disks */ unsigned long long nodenameindex; =20 + /* counter for generating node names for throttle filters */ + unsigned long long filternodenameindex; + /* counter for generating IDs of fdsets */ unsigned int fdsetindex; bool fdsetindexParsed; @@ -772,6 +775,13 @@ int qemuDomainPrepareStorageSourceBlockdev(virDomainDi= skDef *disk, qemuDomainObjPrivate *priv, virQEMUDriverConfig *cfg); =20 +int qemuDomainPrepareThrottleFilterBlockdev(virDomainThrottleFilterDef *fi= lter, + qemuDomainObjPrivate *priv); +int +qemuDomainPrepareThrottleFilterBlockdevNodename(virDomainThrottleFilterDef= *filter, + const char *nodenameprefix); +virDomainThrottleGroupDef *qemuDomainThrottleGroupByName(virDomainDef *def= , const char *name); + void qemuDomainCleanupAdd(virDomainObj *vm, qemuDomainCleanupCallback cb); void qemuDomainCleanupRemove(virDomainObj *vm, @@ -880,8 +890,6 @@ int qemuDomainSetPrivatePaths(virQEMUDriver *driver, =20 virDomainDiskDef *qemuDomainDiskByName(virDomainDef *def, const char *name= ); =20 -virDomainThrottleGroupDef *qemuDomainThrottleGroupByName(virDomainDef *def= , const char *name); - char *qemuDomainGetMasterKeyFilePath(const char *libDir); =20 int qemuDomainMasterKeyReadFile(qemuDomainObjPrivate *priv); diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 62dc879ed4..491d8b03ea 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -656,6 +656,7 @@ qemuDomainAttachDiskGeneric(virDomainObj *vm, virDomainAsyncJob asyncJob) { g_autoptr(qemuBlockStorageSourceChainData) data =3D NULL; + g_autoptr(qemuBlockThrottleFilterChainData) filterData =3D NULL; qemuDomainObjPrivate *priv =3D vm->privateData; g_autoptr(virJSONValue) devprops =3D NULL; bool extensionDeviceAttached =3D false; @@ -693,6 +694,18 @@ qemuDomainAttachDiskGeneric(virDomainObj *vm, =20 if (rc < 0) goto rollback; + /* Setup throttling filter chain + * add additional "blockdev-add"(throttle filter) between "blockdev= -add" (qemuBlockStorageSourceChainAttach) and "device_add" (qemuDomainAttac= hExtensionDevice) + */ + if ((filterData =3D qemuBuildThrottleFilterChainAttachPrepareBlock= dev(disk))) { + if (qemuDomainObjEnterMonitorAsync(vm, asyncJob) < 0) + return -1; + /* QMP requests("blockdev-add" with "driver":"throttle") to QE= MU */ + rc =3D qemuBlockThrottleFilterChainAttach(priv->mon, filterDat= a); + qemuDomainObjExitMonitor(vm); + if (rc < 0) + goto rollback; + } =20 if (disk->transient) { g_autoptr(qemuBlockStorageSourceAttachData) backend =3D NULL; @@ -765,6 +778,8 @@ qemuDomainAttachDiskGeneric(virDomainObj *vm, if (extensionDeviceAttached) ignore_value(qemuDomainDetachExtensionDevice(priv->mon, &disk->inf= o)); =20 + qemuBlockThrottleFilterChainDetach(priv->mon, filterData); + qemuBlockStorageSourceChainDetach(priv->mon, data); =20 qemuDomainObjExitMonitor(vm); @@ -4504,6 +4519,7 @@ qemuDomainRemoveDiskDevice(virQEMUDriver *driver, { qemuDomainDiskPrivate *diskPriv =3D QEMU_DOMAIN_DISK_PRIVATE(disk); g_autoptr(qemuBlockStorageSourceChainData) diskBackend =3D NULL; + g_autoptr(qemuBlockThrottleFilterChainData) filterData =3D NULL; size_t i; qemuDomainObjPrivate *priv =3D vm->privateData; int ret =3D -1; @@ -4542,6 +4558,13 @@ qemuDomainRemoveDiskDevice(virQEMUDriver *driver, } } =20 + qemuDomainObjEnterMonitor(vm); + /* QMP request("blockdev-del") to QEMU to delete throttle filter*/ + if ((filterData =3D qemuBuildThrottleFilterChainAttachPrepareBlockdev(= disk))) { + qemuBlockThrottleFilterChainDetach(priv->mon, filterData); + } + qemuDomainObjExitMonitor(vm); + qemuDomainObjEnterMonitor(vm); =20 if (diskBackend) diff --git a/tests/qemustatusxml2xmldata/backup-pull-in.xml b/tests/qemusta= tusxml2xmldata/backup-pull-in.xml index e7fdc6c478..0a7b8bc7ee 100644 --- a/tests/qemustatusxml2xmldata/backup-pull-in.xml +++ b/tests/qemustatusxml2xmldata/backup-pull-in.xml @@ -234,6 +234,7 @@ + diff --git a/tests/qemustatusxml2xmldata/blockjob-blockdev-in.xml b/tests/q= emustatusxml2xmldata/blockjob-blockdev-in.xml index 380ef053d2..c29bbaca81 100644 --- a/tests/qemustatusxml2xmldata/blockjob-blockdev-in.xml +++ b/tests/qemustatusxml2xmldata/blockjob-blockdev-in.xml @@ -233,6 +233,7 @@ + diff --git a/tests/qemustatusxml2xmldata/blockjob-mirror-in.xml b/tests/qem= ustatusxml2xmldata/blockjob-mirror-in.xml index 1bcdeffcb8..0e0f52fecf 100644 --- a/tests/qemustatusxml2xmldata/blockjob-mirror-in.xml +++ b/tests/qemustatusxml2xmldata/blockjob-mirror-in.xml @@ -23,6 +23,7 @@ + -2 diff --git a/tests/qemustatusxml2xmldata/migration-in-params-in.xml b/tests= /qemustatusxml2xmldata/migration-in-params-in.xml index 03773a089b..5510c139f8 100644 --- a/tests/qemustatusxml2xmldata/migration-in-params-in.xml +++ b/tests/qemustatusxml2xmldata/migration-in-params-in.xml @@ -257,6 +257,7 @@ + -2 diff --git a/tests/qemustatusxml2xmldata/migration-out-nbd-bitmaps-in.xml b= /tests/qemustatusxml2xmldata/migration-out-nbd-bitmaps-in.xml index 4ee44ffbd4..cd38bf3e30 100644 --- a/tests/qemustatusxml2xmldata/migration-out-nbd-bitmaps-in.xml +++ b/tests/qemustatusxml2xmldata/migration-out-nbd-bitmaps-in.xml @@ -343,6 +343,7 @@ + diff --git a/tests/qemustatusxml2xmldata/migration-out-nbd-out.xml b/tests/= qemustatusxml2xmldata/migration-out-nbd-out.xml index de92146eaa..0d8cb8be6a 100644 --- a/tests/qemustatusxml2xmldata/migration-out-nbd-out.xml +++ b/tests/qemustatusxml2xmldata/migration-out-nbd-out.xml @@ -260,6 +260,7 @@ + -2 diff --git a/tests/qemustatusxml2xmldata/migration-out-nbd-tls-out.xml b/te= sts/qemustatusxml2xmldata/migration-out-nbd-tls-out.xml index 6bdd128259..75b019cb23 100644 --- a/tests/qemustatusxml2xmldata/migration-out-nbd-tls-out.xml +++ b/tests/qemustatusxml2xmldata/migration-out-nbd-tls-out.xml @@ -289,6 +289,7 @@ + -2 diff --git a/tests/qemustatusxml2xmldata/migration-out-params-in.xml b/test= s/qemustatusxml2xmldata/migration-out-params-in.xml index 24ee86e4c0..1e786953e7 100644 --- a/tests/qemustatusxml2xmldata/migration-out-params-in.xml +++ b/tests/qemustatusxml2xmldata/migration-out-params-in.xml @@ -271,6 +271,7 @@ + -2 diff --git a/tests/qemustatusxml2xmldata/modern-in.xml b/tests/qemustatusxm= l2xmldata/modern-in.xml index f0f5df84ab..84240595ff 100644 --- a/tests/qemustatusxml2xmldata/modern-in.xml +++ b/tests/qemustatusxml2xmldata/modern-in.xml @@ -261,6 +261,7 @@ + -2 diff --git a/tests/qemustatusxml2xmldata/upgrade-out.xml b/tests/qemustatus= xml2xmldata/upgrade-out.xml index e663b3dbb5..2f33166579 100644 --- a/tests/qemustatusxml2xmldata/upgrade-out.xml +++ b/tests/qemustatusxml2xmldata/upgrade-out.xml @@ -259,6 +259,7 @@ + -2 diff --git a/tests/qemustatusxml2xmldata/vcpus-multi-in.xml b/tests/qemusta= tusxml2xmldata/vcpus-multi-in.xml index fa6a6a99f4..b07a04a840 100644 --- a/tests/qemustatusxml2xmldata/vcpus-multi-in.xml +++ b/tests/qemustatusxml2xmldata/vcpus-multi-in.xml @@ -309,6 +309,7 @@ + -2 --=20 2.34.1 _______________________________________________ Devel mailing list -- devel@lists.libvirt.org To unsubscribe send an email to devel-leave@lists.libvirt.org