From nobody Sat Jan 4 23:11:46 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 1733750863375737.7556409455988; Mon, 9 Dec 2024 05:27:43 -0800 (PST) Received: by lists.libvirt.org (Postfix, from userid 996) id E0AF31422; Mon, 9 Dec 2024 08:27:39 -0500 (EST) Received: from lists.libvirt.org (localhost [IPv6:::1]) by lists.libvirt.org (Postfix) with ESMTP id E99351373; Mon, 9 Dec 2024 08:20:13 -0500 (EST) Received: by lists.libvirt.org (Postfix, from userid 996) id 7236611CC; Mon, 9 Dec 2024 07:42:45 -0500 (EST) Received: from mail-pl1-f171.google.com (mail-pl1-f171.google.com [209.85.214.171]) (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 47DFB11C7 for ; Mon, 9 Dec 2024 07:42:44 -0500 (EST) Received: by mail-pl1-f171.google.com with SMTP id d9443c01a7336-21634338cfdso17182525ad.2 for ; Mon, 09 Dec 2024 04:42:44 -0800 (PST) Received: from localhost.localdomain ([120.60.110.156]) by smtp.googlemail.com with ESMTPSA id d9443c01a7336-2164d103993sm18113195ad.193.2024.12.09.04.42.40 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Mon, 09 Dec 2024 04:42: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.5 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_H2,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=1733748162; x=1734352962; 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=1OvUjIo7w5xHYGmNYTKZnSEfpecNVXs5M0kNmlHeQI0=; b=DXvILNZmcqE8Nsn+CUmQNZEXqMnS6o2FPna2p2glDCTCyCqOG4B409j3NBwLR/dic+ A3fTpDG6P33jVV2VpH2G/wpZZFp31JT2mEjhNv3GH7acrryoU9jvHn9cmt6jOGW3xvpv blAiW8KMOaB2FRQk/3c3a1hapu7btSMr4peYjGJj/blKWo36m0c63Y7Gnc/fomR6P3Ok P+75oMC9jG+ilsd3fqbcEG3PZ350xsX5Sdv3+RXRlBNI6iRtny28En2NpuCHr0EH4uz+ J3FsH/Mn3twl6Nd63QUSMUt99xG8fxxBJ49sin/5HBjbjvMc1eFGSzpFnHQRoUGhvb8C UzVw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733748162; x=1734352962; 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=1OvUjIo7w5xHYGmNYTKZnSEfpecNVXs5M0kNmlHeQI0=; b=v3BPgep3P1Dmk4yOKYlXhMZQjxhCIACxaFflAk6X3HwZBdU6A/SpltK9Wm5yjkHsmE S+7lTC7R74o2WFtDOLH72tJuJdVxUwvhLK0uhwEmqc/sBdiMTFiI/PVymJEjY2385vMU ERVpLIzGDzDevB9rQHa5rggeEXtV4IIBg1tLD4MnwpbpECS0mxVCRvHNSJiLwtXwuPJf 14XcQg1KsxU4MbxiIxcqa8uKKDbNVmZkASepYfEUrR2gGWv7+TufBHOtvt490Slw0/ij KwlrrDX6xuk2h/pCWIhVihZZ7dioNofX9JqdDmOKCh91L3hGP1yh1WYGKZfcTUcV+vlM iUVg== X-Gm-Message-State: AOJu0YxiuaimmczrL0oy4B6p1izW6uiys5QEx5CY/CfgNxYzQmkSb7hy LksS0rzGGsgBEdsAK4GmmxwGRBa6GbOdaupyn+S8UQHt0AbCqucj96CtcX2n X-Gm-Gg: ASbGncuvh/GMHYHl4Bi8Zm8eTncE/PpXUh03vzVjLX3oGU7X1ak8zF2xzLdgaGewTJo nHGPbdY7kcAtO9FEG0fZz/wSd/5SJ/X7jRB9z70O16E5Icjm0q1Hzv+iTV1kwk7smS5ZJl17MXZ KP/WncGtK9xIA0xyAKYNuyl0HiBxr58J6UiVOuVb4MrNZWFjH+bPV8QOOGKLDgnbtG//Lc2GBGd Yw7ArGAeSaA6n/BBqZh5KrQqpdm2iaw1kqhHqkRErAeNBKotKxLUr4rQd/egn5Fqwnke4tmaywy uJZDNA== X-Google-Smtp-Source: AGHT+IGbFapzU+A4aIgFoJKpB1bE1LV4B9dXS/0uo2+k42X/5vd2ujj/jHvB94pKaxosORq6z8Fn+A== X-Received: by 2002:a17:902:e843:b0:215:5d43:6f0e with SMTP id d9443c01a7336-2166a07d649mr4775485ad.41.1733748162359; Mon, 09 Dec 2024 04:42:42 -0800 (PST) From: Harikumar R To: devel@lists.libvirt.org Subject: [PATCH v6 10/18] qemu: helper: throttle filter nodename and preparation processing Date: Mon, 9 Dec 2024 18:11:10 +0530 Message-Id: <20241209124118.39471-11-harirajkumar230@gmail.com> X-Mailer: git-send-email 2.39.5 (Apple Git-154) In-Reply-To: <20241209124118.39471-1-harirajkumar230@gmail.com> References: <20241209124118.39471-1-harirajkumar230@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-MailFrom: harirajkumar230@gmail.com X-Mailman-Rule-Hits: nonmember-moderation 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 Message-ID-Hash: AT7WSJGPVQJDJ45LDLHBCTTJDB5CEA35 X-Message-ID-Hash: AT7WSJGPVQJDJ45LDLHBCTTJDB5CEA35 X-Mailman-Approved-At: Mon, 09 Dec 2024 13:19:47 -0500 CC: earulana@in.ibm.com, sanjeev.ranjan@ibm.com, harikumar.rajkumar@ibm.com, Chun Feng Wu 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: 1733750896813116600 Content-Type: text/plain; charset="utf-8" From: Chun Feng Wu It contains throttle filter nodename processing(new nodename, topnodename, parse and format nodename), throttle filter attaching/detaching preparation and implementation. * Updated "qemuDomainDiskGetTopNodename", so if throttlefilter is used together with copyOnRead, top node is throttle filter node, e.g. device -> throttle -> copyOnRead Layer-> image chain * In qemuBuildThrottleFiltersAttachPrepareBlockdev, if copy_on_read is on, build throttle nodename chain on top of copy_on_read nodename * In status xml, throttle filter nodename(virDomainDiskDef.nodename) is saved at disk/privateData/nodenames/nodename(type=3D'throttle-filter'), corresponding parse/format sits in qemuDomainDiskPrivateParse and qemuDomainDiskPrivateFormat * If filter nodename hasn't been set by qemuDomainDiskPrivateParse, in qemuDomainPrepareThrottleFilterBlockdev, filter nodename index can be generated by reusing qemuDomainStorageIDNew and current global sequence number is persistented in virDomainObj- >privateData(qemuDomainObjPrivate)->nodenameindex. qemuDomainPrepareThrottleFilterBlockdev is called by qemuDomainPrepareDiskSourceBlockdev, which in turn used by both hotplug and qemuProcessStart to prepare throttle filter node name * Define method qemuBlockThrottleFilterGetProps, which is used by both hotplug and command to build throttle object for QEMU * Define methods for throttle filter attach/detach/rollback Signed-off-by: Chun Feng Wu --- src/qemu/qemu_block.c | 136 ++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_block.h | 49 +++++++++++++++ src/qemu/qemu_command.c | 81 ++++++++++++++++++++++++ src/qemu/qemu_command.h | 6 ++ src/qemu/qemu_domain.c | 73 +++++++++++++++++++-- 5 files changed, 341 insertions(+), 4 deletions(-) diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c index 35dca8ee7b..fe5098d7b4 100644 --- a/src/qemu/qemu_block.c +++ b/src/qemu/qemu_block.c @@ -2775,6 +2775,142 @@ qemuBlockStorageSourceCreateDetectSize(GHashTable *= blockNamedNodeData, } =20 =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. + */ +static virJSONValue * +qemuBlockThrottleFilterGetProps(virDomainThrottleFilterDef *filter, + const char *parentNodeName) +{ + g_autoptr(virJSONValue) props =3D NULL; + /* prefix group name with "throttle-" in QOM */ + g_autofree char *prefixed_group_name =3D g_strdup_printf("throttle-%s"= , filter->group_name); + if (virJSONValueObjectAdd(&props, + "s:driver", "throttle", + "s:node-name", qemuBlockThrottleFilterGetNod= ename(filter), + "s:throttle-group", prefixed_group_name, + "s:file", parentNodeName, + NULL) < 0) + return NULL; + + 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); + + return g_steal_pointer(&data); +} + + +void +qemuBlockThrottleFilterAttachRollback(qemuMonitor *mon, + qemuBlockThrottleFilterAttachData *d= ata) +{ + virErrorPtr orig_err; + + virErrorPreserveLast(&orig_err); + + if (data->filterAttached) + ignore_value(qemuMonitorBlockdevDel(mon, data->filterNodeName)); + + virErrorRestore(&orig_err); +} + + +void +qemuBlockThrottleFiltersDataFree(qemuBlockThrottleFiltersData *data) +{ + 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); +} + + +/** + * qemuBlockThrottleFiltersAttach: + * @mon: monitor object + * @data: filter chain data + * + * Attach throttle filters. + * Caller must enter @mon prior calling this function. + */ +int +qemuBlockThrottleFiltersAttach(qemuMonitor *mon, + qemuBlockThrottleFiltersData *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 +qemuBlockThrottleFiltersDetach(qemuMonitor *mon, + qemuBlockThrottleFiltersData *data) +{ + size_t i; + + for (i =3D data->nfilterdata; i > 0; i--) + qemuBlockThrottleFilterAttachRollback(mon, data->filterdata[i-1]); +} + + int qemuBlockRemoveImageMetadata(virQEMUDriver *driver, virDomainObj *vm, diff --git a/src/qemu/qemu_block.h b/src/qemu/qemu_block.h index f13a4a4a9a..b9e950e494 100644 --- a/src/qemu/qemu_block.h +++ b/src/qemu/qemu_block.h @@ -215,6 +215,55 @@ qemuBlockStorageSourceCreateDetectSize(GHashTable *blo= ckNamedNodeData, virStorageSource *src, virStorageSource *templ); =20 +void +qemuBlockThrottleFilterSetNodename(virDomainThrottleFilterDef *filter, + char *nodename); + +const char * +qemuBlockThrottleFilterGetNodename(virDomainThrottleFilterDef *filter); + +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 *d= ata); + +struct _qemuBlockThrottleFiltersData { + qemuBlockThrottleFilterAttachData **filterdata; + size_t nfilterdata; +}; + +typedef struct _qemuBlockThrottleFiltersData qemuBlockThrottleFiltersData; + +void +qemuBlockThrottleFiltersDataFree(qemuBlockThrottleFiltersData *data); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(qemuBlockThrottleFiltersData, + qemuBlockThrottleFiltersDataFree); + +int +qemuBlockThrottleFiltersAttach(qemuMonitor *mon, + qemuBlockThrottleFiltersData *data); + +void +qemuBlockThrottleFiltersDetach(qemuMonitor *mon, + qemuBlockThrottleFiltersData *data); + int qemuBlockRemoveImageMetadata(virQEMUDriver *driver, virDomainObj *vm, diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index dcb9c4934e..a209452594 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -11004,6 +11004,87 @@ qemuBuildStorageSourceChainAttachPrepareBlockdevOn= e(qemuBlockStorageSourceChainD } =20 =20 +/** + * qemuBuildThrottleFiltersAttachPrepareBlockdevOne: + * @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 + * + * Build filter node chain to provide more flexibility for block disk I/O = limits + */ +static int +qemuBuildThrottleFiltersAttachPrepareBlockdevOne(qemuBlockThrottleFiltersD= ata *data, + virDomainThrottleFilterDe= f *throttlefilter, + const char *parentNodeNam= e) +{ + 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; +} + + +/** + * qemuBuildThrottleFiltersAttachPrepareBlockdev: + * @disk: domain disk + * + * Build filter node chain to provide more flexibility for block disk I/O = limits + */ +qemuBlockThrottleFiltersData * +qemuBuildThrottleFiltersAttachPrepareBlockdev(virDomainDiskDef *disk) +{ + g_autoptr(qemuBlockThrottleFiltersData) data =3D NULL; + size_t i; + const char * parentNodeName =3D NULL; + qemuDomainDiskPrivate *priv =3D QEMU_DOMAIN_DISK_PRIVATE(disk); + + data =3D g_new0(qemuBlockThrottleFiltersData, 1); + /* if copy_on_read is enabled, put throttle chain on top of it */ + if (disk->copy_on_read =3D=3D VIR_TRISTATE_SWITCH_ON) { + parentNodeName =3D priv->nodeCopyOnRead; + } else { + /* get starting parentNodename, e.g. libvirt-1-format */ + parentNodeName =3D qemuBlockStorageSourceGetEffectiveNodename(disk= ->src); + } + /* build filterdata, which contains all filters info and sequence info= through parentNodeName */ + for (i =3D 0; i < disk->nthrottlefilters; i++) { + if (qemuBuildThrottleFiltersAttachPrepareBlockdevOne(data, disk->t= hrottlefilters[i], parentNodeName) < 0) + return NULL; + parentNodeName =3D disk->throttlefilters[i]->nodename; + } + + return g_steal_pointer(&data); +} + + +/** + * qemuBuildThrottleFiltersDetachPrepareBlockdev: + * @disk: domain disk + * + * Build filters data for later "blockdev-del" + */ +qemuBlockThrottleFiltersData * +qemuBuildThrottleFiltersDetachPrepareBlockdev(virDomainDiskDef *disk) +{ + g_autoptr(qemuBlockThrottleFiltersData) data =3D g_new0(qemuBlockThrot= tleFiltersData, 1); + size_t i; + + /* build filterdata, which contains filters info and sequence info */ + for (i =3D 0; i < disk->nthrottlefilters; i++) { + g_autoptr(qemuBlockThrottleFilterAttachData) elem =3D g_new0(qemuB= lockThrottleFilterAttachData, 1); + /* ignore other fields since the following info are enough for "bl= ockdev-del" */ + elem->filterNodeName =3D qemuBlockThrottleFilterGetNodename(disk->= throttlefilters[i]); + elem->filterAttached =3D true; + + VIR_APPEND_ELEMENT(data->filterdata, data->nfilterdata, elem); + } + return g_steal_pointer(&data); +} + + /** * qemuBuildStorageSourceChainAttachPrepareBlockdev: * @top: storage source chain diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h index 76c514b5f7..1b0296ea42 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 +qemuBlockThrottleFiltersData * +qemuBuildThrottleFiltersAttachPrepareBlockdev(virDomainDiskDef *disk); + +qemuBlockThrottleFiltersData * +qemuBuildThrottleFiltersDetachPrepareBlockdev(virDomainDiskDef *disk); + virJSONValue * qemuBuildDiskDeviceProps(const virDomainDef *def, virDomainDiskDef *disk, diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 1fc4e2f33f..16bd9a22d0 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -2235,6 +2235,34 @@ qemuStorageSourcePrivateDataFormat(virStorageSource = *src, } =20 =20 +static int +virDomainDiskThrottleFilterNodeNamesParse(xmlXPathContextPtr ctxt, + virDomainDiskDef *def) +{ + size_t i; + int n =3D 0; + g_autofree xmlNodePtr *nodes =3D NULL; + g_autoptr(GHashTable) throttleFiltersMap =3D virHashNew(g_free); + + if ((n =3D virXPathNodeSet("./nodenames/nodename[@type=3D'throttle-fil= ter']", ctxt, &nodes)) < 0) + return -1; + + for (i =3D 0; i < n; i++) { + g_hash_table_insert(throttleFiltersMap, virXMLPropString(nodes[i],= "group"), virXMLPropString(nodes[i], "name")); + } + + for (i =3D 0; i < def->nthrottlefilters; i++) { + char* nodename =3D g_hash_table_lookup(throttleFiltersMap, def->th= rottlefilters[i]->group_name); + if (nodename) { + /* first time to set nodename in filter */ + def->throttlefilters[i]->nodename =3D g_strdup(nodename); + } + } + + return 0; +} + + static int qemuDomainDiskPrivateParse(xmlXPathContextPtr ctxt, virDomainDiskDef *disk) @@ -2244,6 +2272,9 @@ qemuDomainDiskPrivateParse(xmlXPathContextPtr ctxt, priv->qomName =3D virXPathString("string(./qom/@name)", ctxt); priv->nodeCopyOnRead =3D virXPathString("string(./nodenames/nodename[@= type=3D'copyOnRead']/@name)", ctxt); =20 + if (virDomainDiskThrottleFilterNodeNamesParse(ctxt, disk) < 0) + return -1; + return 0; } =20 @@ -2253,14 +2284,22 @@ qemuDomainDiskPrivateFormat(virDomainDiskDef *disk, virBuffer *buf) { qemuDomainDiskPrivate *priv =3D QEMU_DOMAIN_DISK_PRIVATE(disk); + size_t i; =20 virBufferEscapeString(buf, "\n", priv->qomName); =20 - if (priv->nodeCopyOnRead) { + if (priv->nodeCopyOnRead || disk->nthrottlefilters > 0) { virBufferAddLit(buf, "\n"); virBufferAdjustIndent(buf, 2); - virBufferEscapeString(buf, "\n", - priv->nodeCopyOnRead); + if (priv->nodeCopyOnRead) + virBufferEscapeString(buf, "\n", + priv->nodeCopyOnRead); + if (disk->nthrottlefilters > 0) { + for (i =3D 0; i < disk->nthrottlefilters; i++) { + virBufferEscapeString(buf, "throttlefilters[i]->nodename); + virBufferEscapeString(buf, "group=3D'%s'/>\n", disk->throt= tlefilters[i]->group_name); + } + } virBufferAdjustIndent(buf, -2); virBufferAddLit(buf, "\n"); } @@ -6293,7 +6332,8 @@ qemuDomainDetermineDiskChain(virQEMUDriver *driver, * @disk: disk definition object * * Returns the pointer to the node-name of the topmost layer used by @disk= as - * backend. Currently returns the nodename of the copy-on-read filter if e= nabled + * backend. Currently returns the nodename of top throttle filter if enabl= ed + * or the nodename of the copy-on-read filter if enabled * or the nodename of the top image's format driver. Empty disks return NU= LL. * This must be used only with disks instantiated via -blockdev (thus not * for SD cards). @@ -6306,6 +6346,10 @@ qemuDomainDiskGetTopNodename(virDomainDiskDef *disk) if (virStorageSourceIsEmpty(disk->src)) return NULL; =20 + /* If disk has throttles, take top throttle node name */ + if (disk->nthrottlefilters > 0) + return disk->throttlefilters[disk->nthrottlefilters - 1]->nodename; + if (disk->copy_on_read =3D=3D VIR_TRISTATE_SWITCH_ON) return priv->nodeCopyOnRead; =20 @@ -9724,6 +9768,22 @@ qemuDomainPrepareStorageSourceBlockdevNodename(virDo= mainDiskDef *disk, } =20 =20 +static void +qemuDomainPrepareThrottleFilterBlockdev(virDomainThrottleFilterDef *filter, + qemuDomainObjPrivate *priv) +{ + g_autofree char *nodenameprefix =3D NULL; + + /* skip setting throttle filter nodename if it's set by parsing status= xml */ + if (filter->nodename) { + return; + } + nodenameprefix =3D g_strdup_printf("libvirt-%u", qemuDomainStorageIDNe= w(priv)); + /* generate and set nodename into filter for later QEMU cmd preparatio= n */ + qemuBlockThrottleFilterSetNodename(filter, g_strdup_printf("%s-filter"= , nodenameprefix)); +} + + int qemuDomainPrepareStorageSourceBlockdev(virDomainDiskDef *disk, virStorageSource *src, @@ -9747,6 +9807,7 @@ qemuDomainPrepareDiskSourceBlockdev(virDomainDiskDef = *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) @@ -9761,6 +9822,10 @@ qemuDomainPrepareDiskSourceBlockdev(virDomainDiskDef= *disk, return -1; } =20 + for (i =3D 0; i < disk->nthrottlefilters; i++) { + qemuDomainPrepareThrottleFilterBlockdev(disk->throttlefilters[i], = priv); + } + return 0; } =20 --=20 2.39.5 (Apple Git-154)