From nobody Sun Oct 5 00:14:11 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=pass(p=reject dis=none) header.from=lists.libvirt.org ARC-Seal: i=1; a=rsa-sha256; t=1758791162; cv=none; d=zohomail.com; s=zohoarc; b=k1f8DHVcHZlSxpR0mBxGG6Gnx/r+0zHHKXUL5SC4fDol4cow4odY9lOnDBE3TY/dO/x4Cyq38z+r1woumeNUrgb5KmCSqodsyqsZ+z1bUlMlGcJ2/H8jSxZicv5k+Mosdv87HoyvjwwMyCQtEjpe2DRM36mCE7KMSqfwI2cT8LI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1758791162; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Owner:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Subject:Subject:To:To:Message-Id; bh=mJqVUcaDrJX5mS42P9a5blUV5BJ8dWCpD0NQEJapY3o=; b=eIaG8i0XzNgmNGVu+JxbidmKVyzXIWf6K4l+0yLnbvRGZFxKsw3BO/AYS9pv6AGzqVA2amhaVmmmdgwRQ8CyXUQO0NXWlEXaOmqBJurTZEzkj0mff50oF73DHhhZCqkB3mogTYuyGKUjoxUe07WZgSm5JbxL73hJJWSZuzMbxRE= ARC-Authentication-Results: i=1; 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=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1758791162872158.45000554000364; Thu, 25 Sep 2025 02:06:02 -0700 (PDT) Received: by lists.libvirt.org (Postfix, from userid 993) id E292D43E63; Thu, 25 Sep 2025 05:06:01 -0400 (EDT) Received: from [172.19.199.14] (lists.libvirt.org [8.43.85.245]) by lists.libvirt.org (Postfix) with ESMTP id 36EBA43F5A; Thu, 25 Sep 2025 04:56:56 -0400 (EDT) Received: by lists.libvirt.org (Postfix, from userid 993) id 3C35541C8D; Thu, 25 Sep 2025 04:56:45 -0400 (EDT) Received: from relay.virtuozzo.com (relay.virtuozzo.com [130.117.225.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (3072 bits) server-digest SHA256) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id 68C7141C94 for ; Thu, 25 Sep 2025 04:56:37 -0400 (EDT) Received: from [130.117.225.5] (helo=dev012.ch-qa.vzint.dev) by relay.virtuozzo.com with esmtp (Exim 4.96) (envelope-from ) id 1v1hlt-00DyxO-1G; Thu, 25 Sep 2025 10:56:33 +0200 X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-26) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-3.1 required=5.0 tests=DKIM_INVALID,DKIM_SIGNED, MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED,RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED,SPF_PASS autolearn=unavailable autolearn_force=no version=4.0.1 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=virtuozzo.com; s=relay; h=MIME-Version:Message-ID:Date:Subject:From: Content-Type; bh=mJqVUcaDrJX5mS42P9a5blUV5BJ8dWCpD0NQEJapY3o=; b=hfE4voYsc0vC kiJCjAJXWwWoONPNqPZfgAaW9TyfD43ob0tmtKNQY611Q7crqLX+1MOwBWNNIKZgrkUsMbVeJX7VU ENeh4DoZNT/7bdN7Or4XnHtDlqmkrBFfNpeTo7yIYVcDa/TSnJ+U1RXZDNIrSoYRXkr8PhCFOakut g4h44ZG6oFpT6Lnk7jRREX6Ttt4Dy1r3o7zIP50/nSkcnidcs6pUSNmHHy2BEKgJV2wm0YmWyDnFj sOFRCSWGfwKZOBH6QP8TPE7c3PuvjW5VUUNgMI39R9fw9vmzMLRAfakgaaHwxWsWpnUwAeMG1kDYE 86b4hdik4ldEyBIVpI+xcw==; To: devel@lists.libvirt.org Subject: [PATCH 1/3] api: remote: introduce virDomainBlockRebaseParams API Date: Thu, 25 Sep 2025 11:53:09 +0300 Message-ID: <20250925085627.102886-2-nikolai.barybin@virtuozzo.com> X-Mailer: git-send-email 2.43.5 In-Reply-To: <20250925085627.102886-1-nikolai.barybin@virtuozzo.com> References: <20250925085627.102886-1-nikolai.barybin@virtuozzo.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Message-ID-Hash: BDTQT76XTCXVWMAYPX6SBXKACF2IPYUA X-Message-ID-Hash: BDTQT76XTCXVWMAYPX6SBXKACF2IPYUA X-MailFrom: nikolai.barybin@virtuozzo.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; header-match-devel.lists.libvirt.org-0; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: den@virtuozzo.com X-Mailman-Version: 3.3.10 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Nikolai Barybin via Devel Reply-To: Nikolai Barybin X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1758791164993116600 Content-Type: text/plain; charset="utf-8" This new API is a combination of virDomainBlockPull and virDomainBlockRebase (without copy mode) which supports extendable list of virTypedParameterPtr params. It is designed to allow more configurable use of underlying 'block-stream' QMP command. If "base" =3D=3D NULL and flags =3D=3D 0 it is equivalent to virDomainBlock= Pull. Signed-off-by: Nikolai Barybin Reviewed-by: J=C3=A1n Tomko --- include/libvirt/libvirt-domain.h | 34 +++++++++++++++++ src/driver-hypervisor.h | 8 ++++ src/libvirt-domain.c | 63 ++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 5 +++ src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 17 ++++++++- src/remote_protocol-structs | 10 +++++ 7 files changed, 137 insertions(+), 1 deletion(-) diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-dom= ain.h index 71bb49fe6c..7dae8987a2 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -4459,6 +4459,40 @@ int virDomainBlockRebase(virDomainPtr dom, const cha= r *disk, const char *base, unsigned long bandwidth, unsigned int flags); =20 +/** + * VIR_DOMAIN_BLOCK_REBASE_PARAM_BASE: + * Macro for the virDomainBlockRebaseParams parameter 'base'. + * Expects string specifying new base block device. + * + * Since: 11.8.0 + */ +#define VIR_DOMAIN_BLOCK_REBASE_PARAM_BASE "base" + +/** + * VIR_DOMAIN_BLOCK_REBASE_PARAM_BANDWIDTH: + * Macro for the virDomainBlockRebaseParams parameter 'bandwidth'. + * Expects unsigned long long bandwidth value in Bytes/s. + * + * Since: 11.8.0 + */ +#define VIR_DOMAIN_BLOCK_REBASE_PARAM_BANDWIDTH "bandwidth" + +/** + * virDomainBlockRebaseParamsFlags: + * + * Flags available for virDomainBlockRebaseParams(). + * + * Since: 11.8.0 + */ +typedef enum { + /* Keep backing chain referenced using relative names (Since: 11.8.0)= */ + VIR_DOMAIN_BLOCK_REBASE_PARAMS_RELATIVE =3D 1 << 4, +} virDomainBlockRebaseParamsFlags; + +int virDomainBlockRebaseParams(virDomainPtr dom, const char *disk, + virTypedParameterPtr params, int nparams, + unsigned int flags); + /** * virDomainBlockCopyFlags: * diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h index 6a43688b0c..83cf5c6205 100644 --- a/src/driver-hypervisor.h +++ b/src/driver-hypervisor.h @@ -1089,6 +1089,13 @@ typedef int unsigned long bandwidth, unsigned int flags); =20 +typedef int +(*virDrvDomainBlockRebaseParams)(virDomainPtr dom, + const char *path, + virTypedParameterPtr params, + int nparams, + unsigned int flags); + typedef int (*virDrvDomainBlockCopy)(virDomainPtr dom, const char *path, @@ -1681,6 +1688,7 @@ struct _virHypervisorDriver { virDrvDomainBlockJobSetSpeed domainBlockJobSetSpeed; virDrvDomainBlockPull domainBlockPull; virDrvDomainBlockRebase domainBlockRebase; + virDrvDomainBlockRebaseParams domainBlockRebaseParams; virDrvDomainBlockCopy domainBlockCopy; virDrvDomainBlockCommit domainBlockCommit; virDrvConnectSetKeepAlive connectSetKeepAlive; diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c index ca110bdf85..27ba0bac45 100644 --- a/src/libvirt-domain.c +++ b/src/libvirt-domain.c @@ -11197,6 +11197,69 @@ virDomainBlockRebase(virDomainPtr dom, const char = *disk, } =20 =20 +/** + * virDomainBlockRebaseParams: + * @dom: pointer to domain object + * @disk: path to the block device, or device shorthand + * @params: pointer to block rebase parameter + * @nparams: number of block rebase parameters + * @flags: bitwise-OR of virDomainBlockRebaseParamsFlags + * + * Generelized version of virDomainBlockPull with more precise params sett= ing. + * + * VIR_DOMAIN_BLOCK_REBASE_PARAM_BASE in @params specifies intermidiate bl= ock device + * in a disk backing chain which will result in a new base for a given dis= k. If ommitted + * or NULL it is equavivalent to normal block pull, when whole backing cha= in is pulled + * into top image. + * + * VIR_DOMAIN_BLOCK_REBASE_PARAM_BANDWIDTH in @params specifies bandwidth = in Bytes/s. + * + * If @flags contains VIR_DOMAIN_BLOCK_REBASE_PARAMS_RELATIVE, the name re= corded + * into the active disk as the location for @base will be kept relative. + * The operation will fail if libvirt can't infer the name. + * + * Returns 0 if the operation has started, -1 on failure. + * + * Since: 11.8.0 + */ +int +virDomainBlockRebaseParams(virDomainPtr dom, + const char *disk, + virTypedParameterPtr params, + int nparams, + unsigned int flags) +{ + virConnectPtr conn; + + VIR_DOMAIN_DEBUG(dom, "disk=3D%s, nparams=3D%u, flags=3D0x%x", + disk, nparams, flags); + VIR_TYPED_PARAMS_DEBUG(params, nparams); + + virResetLastError(); + + virCheckDomainReturn(dom, -1); + conn =3D dom->conn; + + virCheckReadOnlyGoto(conn->flags, error); + virCheckNonNullArgGoto(disk, error); + + if (conn->driver->domainBlockRebaseParams) { + int ret; + ret =3D conn->driver->domainBlockRebaseParams(dom, disk, params, n= params, + flags); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(dom->conn); + return -1; +} + + /** * virDomainBlockCopy: * @dom: pointer to domain object diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index c506acd2ed..0b8365cd2c 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -956,4 +956,9 @@ LIBVIRT_11.2.0 { virDomainDelThrottleGroup; } LIBVIRT_10.2.0; =20 +LIBVIRT_11.8.0 { + global: + virDomainBlockRebaseParams; +} LIBVIRT_11.2.0; + # .... define new API here using predicted next version number .... diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index ec71eaed87..d9ca026aef 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -7865,6 +7865,7 @@ static virHypervisorDriver hypervisor_driver =3D { .domainBlockJobSetSpeed =3D remoteDomainBlockJobSetSpeed, /* 0.9.4 */ .domainBlockPull =3D remoteDomainBlockPull, /* 0.9.4 */ .domainBlockRebase =3D remoteDomainBlockRebase, /* 0.9.10 */ + .domainBlockRebaseParams =3D remoteDomainBlockRebaseParams, /* 11.8.0 = */ .domainBlockCopy =3D remoteDomainBlockCopy, /* 1.2.9 */ .domainBlockCommit =3D remoteDomainBlockCommit, /* 0.10.2 */ .connectSetKeepAlive =3D remoteConnectSetKeepAlive, /* 0.9.8 */ diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 3c93203210..762614b1fa 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -119,6 +119,9 @@ const REMOTE_DOMAIN_NUMA_PARAMETERS_MAX =3D 16; /* Upper limit on list of perf events. */ const REMOTE_DOMAIN_PERF_EVENTS_MAX =3D 64; =20 +/* Upper limit on block_rebase_params tunable parameters. */ +const REMOTE_DOMAIN_BLOCK_REBASE_PARAMS_PARAMETERS_MAX =3D 16; + /* Upper limit on block copy tunable parameters. */ const REMOTE_DOMAIN_BLOCK_COPY_PARAMETERS_MAX =3D 16; =20 @@ -1440,6 +1443,12 @@ struct remote_domain_block_rebase_args { unsigned hyper bandwidth; unsigned int flags; }; +struct remote_domain_block_rebase_params_args { + remote_nonnull_domain dom; + remote_nonnull_string path; + remote_typed_param params; + unsigned int flags; +}; struct remote_domain_block_copy_args { remote_nonnull_domain dom; remote_nonnull_string path; @@ -7119,5 +7128,11 @@ enum remote_procedure { * @generate: both * @acl: none */ - REMOTE_PROC_DOMAIN_EVENT_NIC_MAC_CHANGE =3D 453 + REMOTE_PROC_DOMAIN_EVENT_NIC_MAC_CHANGE =3D 453, + + /** + * @generate: both + * @acl: domain:block_write + */ + REMOTE_PROC_DOMAIN_BLOCK_REBASE_PARAMS =3D 454 }; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 0f87d13a5a..ec0963550a 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -1010,6 +1010,15 @@ struct remote_domain_block_rebase_args { uint64_t bandwidth; u_int flags; }; +struct remote_domain_block_rebase_params_args { + remote_nonnull_domain dom; + remote_nonnull_string path; + struct { + u_int params_len; + remote_typed_param * params_val; + } params; + u_int flags; +}; struct remote_domain_block_copy_args { remote_nonnull_domain dom; remote_nonnull_string path; @@ -3791,4 +3800,5 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_SET_THROTTLE_GROUP =3D 451, REMOTE_PROC_DOMAIN_DEL_THROTTLE_GROUP =3D 452, REMOTE_PROC_DOMAIN_EVENT_NIC_MAC_CHANGE =3D 453, + REMOTE_PROC_DOMAIN_BLOCK_REBASE_PARAMS =3D 454, }; --=20 2.43.5 From nobody Sun Oct 5 00:14:11 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=pass(p=reject dis=none) header.from=lists.libvirt.org ARC-Seal: i=1; a=rsa-sha256; t=1758790956; cv=none; d=zohomail.com; s=zohoarc; b=fHDvNayEN6tVJVeW+xEnzNnae8zuH8t5QrzkO2oKS5tg3JUf5L5B7DtT/PI6sy0nhKBW6f60PZx6OO4eCRItTtqQ72IP085KZBfAqLgCwpAoMUKY6VdCTSRFhPbcdTvu5OQe0TEtves29Rq7JrJCcJ7bFtWX6nagHC8afdC4Oas= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1758790956; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Owner:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Subject:Subject:To:To:Message-Id; bh=Bq8nxg8Tfs6NEt/q3veksv8JATnJzdY4G+IJXYMFKag=; b=kOWsvwaxIMVInBW8OF20A1uSL7AxehUlaptNr1a1eVbBA4UOTAXkMWrbKxbLBA8ts3B3m5XCS9Srj1w2igLfMCt+x1kY4K//4X6OfuAWVS6gGrvZO7obm0mfbGWlXSCWHlx+R22stFzVFDRUK4yGVir5G3WkmBKY8t62dibZcHg= ARC-Authentication-Results: i=1; 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=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1758790956063479.12945656545753; Thu, 25 Sep 2025 02:02:36 -0700 (PDT) Received: by lists.libvirt.org (Postfix, from userid 993) id 242E543E2B; Thu, 25 Sep 2025 05:02:35 -0400 (EDT) Received: from [172.19.199.14] (lists.libvirt.org [8.43.85.245]) by lists.libvirt.org (Postfix) with ESMTP id 2D03343F10; Thu, 25 Sep 2025 04:56:53 -0400 (EDT) Received: by lists.libvirt.org (Postfix, from userid 993) id 8BD4541C8D; Thu, 25 Sep 2025 04:56:41 -0400 (EDT) Received: from relay.virtuozzo.com (relay.virtuozzo.com [130.117.225.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (3072 bits) server-digest SHA256) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id 4DE234197F for ; Thu, 25 Sep 2025 04:56:37 -0400 (EDT) Received: from [130.117.225.5] (helo=dev012.ch-qa.vzint.dev) by relay.virtuozzo.com with esmtp (Exim 4.96) (envelope-from ) id 1v1hlu-00DyxO-0y; Thu, 25 Sep 2025 10:56:34 +0200 X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-26) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-3.1 required=5.0 tests=DKIM_INVALID,DKIM_SIGNED, MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED,RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED,SPF_PASS autolearn=unavailable autolearn_force=no version=4.0.1 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=virtuozzo.com; s=relay; h=MIME-Version:Message-ID:Date:Subject:From: Content-Type; bh=Bq8nxg8Tfs6NEt/q3veksv8JATnJzdY4G+IJXYMFKag=; b=bgw52Ij0D/k6 +bXnbWkOAqpyj6wUHZlA5CF8uwuutPlJFohD02/95pYGEmj8/8qZq9jYDWCkRlxCfRVnFcMyHMOx2 ZEB/DTnjhNjHnTvH+OzYU57H2CyISNMEqnicV9DDBpReev3OZWWMDDgPOSXPiS3s/4ILhL3oblRs3 NxbhswBlp2HXscxzWVbMBRDy9++p10dXE46C194h5D3tmLsNL7M4M1ecatL+myGldZ0U7eQl766Ox NErkNQfpVS6iK1/7xTqvumBpgcSCRUF8TQKvS9af+LpQZZt453lRD8Yf65IlNjBzLFDeNAgXPCf3s KTDt9+vV2xORRQqyOXppPg==; To: devel@lists.libvirt.org Subject: [PATCH 2/3] qemu: implement driver support for domainBlockRebaseParams API Date: Thu, 25 Sep 2025 11:53:10 +0300 Message-ID: <20250925085627.102886-3-nikolai.barybin@virtuozzo.com> X-Mailer: git-send-email 2.43.5 In-Reply-To: <20250925085627.102886-1-nikolai.barybin@virtuozzo.com> References: <20250925085627.102886-1-nikolai.barybin@virtuozzo.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Message-ID-Hash: NL2UZR2JB4HB4QP5WH4HLONRXA3QBTS6 X-Message-ID-Hash: NL2UZR2JB4HB4QP5WH4HLONRXA3QBTS6 X-MailFrom: nikolai.barybin@virtuozzo.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; header-match-devel.lists.libvirt.org-0; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: den@virtuozzo.com X-Mailman-Version: 3.3.10 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Nikolai Barybin via Devel Reply-To: Nikolai Barybin X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1758790960319116600 Content-Type: text/plain; charset="utf-8" Factor out qemuDomainBlockPullCommon, reuse its code in qemuDomainBlockRebaseParams and call it from older API. Add qemuDomainBlockRebasePrepareParams to ease params list preparation. Now bandwidth unit of messurement is passed as param VIR_DOMAIN_BLOCK_REBASE_PARAM_BANDWIDTH in Bytes/s. Signed-off-by: Nikolai Barybin --- src/qemu/qemu_driver.c | 327 ++++++++++++++++++++++++++--------------- 1 file changed, 205 insertions(+), 122 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index ac72ea5cb0..8133925ee1 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -13747,113 +13747,6 @@ qemuDomainOpenChannel(virDomainPtr dom, } =20 =20 -/* bandwidth in MiB/s per public API. Caller must lock vm beforehand, - * and not access it afterwards. */ -static int -qemuDomainBlockPullCommon(virDomainObj *vm, - const char *path, - const char *base, - unsigned long bandwidth, - unsigned int flags) -{ - qemuDomainObjPrivate *priv =3D vm->privateData; - virDomainDiskDef *disk; - virStorageSource *baseSource =3D NULL; - g_autofree char *backingPath =3D NULL; - unsigned long long speed =3D bandwidth; - qemuBlockJobData *job =3D NULL; - const char *nodebase =3D NULL; - int ret =3D -1; - - if (flags & VIR_DOMAIN_BLOCK_REBASE_RELATIVE && !base) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("flag VIR_DOMAIN_BLOCK_REBASE_RELATIVE is valid o= nly with non-null base")); - goto cleanup; - } - - if (virDomainObjBeginJob(vm, VIR_JOB_MODIFY) < 0) - goto cleanup; - - if (virDomainObjCheckActive(vm) < 0) - goto endjob; - - if (!(disk =3D qemuDomainDiskByName(vm->def, path))) - goto endjob; - - if (qemuDomainDiskBlockJobIsActive(disk)) - goto endjob; - - if (!qemuDomainDiskBlockJobIsSupported(disk)) - goto endjob; - - if (base && - !(baseSource =3D virStorageSourceChainLookup(disk->src, disk->src, - base, disk->dst, NULL))) - goto endjob; - - if (baseSource) { - if (flags & VIR_DOMAIN_BLOCK_REBASE_RELATIVE) { - if (qemuBlockUpdateRelativeBacking(vm, disk->src, disk->src) <= 0) - goto endjob; - - if (virStorageSourceGetRelativeBackingPath(disk->src->backingS= tore, - baseSource, - &backingPath) < 0) - goto endjob; - - if (!backingPath) { - virReportError(VIR_ERR_OPERATION_INVALID, "%s", - _("can't keep relative backing relationship= ")); - goto endjob; - } - } - } - - /* Convert bandwidth MiB to bytes, if needed */ - if (!(flags & VIR_DOMAIN_BLOCK_PULL_BANDWIDTH_BYTES)) { - if (speed > LLONG_MAX >> 20) { - virReportError(VIR_ERR_OVERFLOW, - _("bandwidth must be less than %1$llu"), - LLONG_MAX >> 20); - goto endjob; - } - speed <<=3D 20; - } - - if (!(job =3D qemuBlockJobDiskNewPull(vm, disk, baseSource, flags))) - goto endjob; - - if (baseSource) { - nodebase =3D qemuBlockStorageSourceGetEffectiveNodename(baseSource= ); - if (!backingPath && - !(backingPath =3D qemuBlockGetBackingStoreString(baseSource, f= alse))) - goto endjob; - } - - qemuDomainObjEnterMonitor(vm); - ret =3D qemuMonitorBlockStream(priv->mon, - qemuBlockStorageSourceGetEffectiveNodenam= e(disk->src), - job->name, - nodebase, - backingPath, - speed); - qemuDomainObjExitMonitor(vm); - - if (ret < 0) - goto endjob; - - qemuBlockJobStarted(job, vm); - - endjob: - virDomainObjEndJob(vm); - - cleanup: - qemuBlockJobStartupFinalize(vm, job); - virDomainObjEndAPI(&vm); - return ret; -} - - static int qemuDomainBlockJobAbort(virDomainPtr dom, const char *path, @@ -14239,6 +14132,179 @@ qemuDomainBlockCopyCommonValidateUserMirrorBackin= gStore(virStorageSource *mirror } =20 =20 +static int +qemuDomainBlockRebasePrepareParams(const char *base, + unsigned long bandwidth, + unsigned int flags, + int *nparams, + virTypedParameterPtr *params, + unsigned int *rebaseFlags) +{ + int maxparams =3D 0; + + /* Legacy support: convert bandwidth MiB to bytes, if needed */ + if (!(flags & VIR_DOMAIN_BLOCK_PULL_BANDWIDTH_BYTES)) { + if (bandwidth > LLONG_MAX >> 20) { + virReportError(VIR_ERR_OVERFLOW, + _("bandwidth must be less than %1$llu"), + LLONG_MAX >> 20); + return -1; + } + bandwidth <<=3D 20; + } + + if (base && + virTypedParamsAddString(params, nparams, &maxparams, + VIR_DOMAIN_BLOCK_REBASE_PARAM_BASE, + base) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to add param %1$s:%2$s to params list"), + VIR_DOMAIN_BLOCK_REBASE_PARAM_BASE, base); + return -1; + } + + if (bandwidth > 0 && + virTypedParamsAddULLong(params, nparams, &maxparams, + VIR_DOMAIN_BLOCK_REBASE_PARAM_BANDWIDTH, + bandwidth) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to add param %1$s:%2$lu to params list"), + VIR_DOMAIN_BLOCK_REBASE_PARAM_BANDWIDTH, bandwidth); + return -1; + } + + if (flags & VIR_DOMAIN_BLOCK_REBASE_RELATIVE) + *rebaseFlags |=3D VIR_DOMAIN_BLOCK_REBASE_PARAMS_RELATIVE; + + return 0; +} + + +static int +qemuDomainBlockRebaseParams(virDomainPtr dom, + const char *path, + virTypedParameterPtr params, + int nparams, + unsigned int flags) +{ + virDomainObj *vm =3D NULL; + size_t i =3D 0; + unsigned long long bandwidth =3D 0; + const char *base =3D NULL; + virDomainDiskDef *disk; + virStorageSource *baseSource =3D NULL; + qemuDomainObjPrivate *priv =3D NULL; + g_autofree char *backingPath =3D NULL; + qemuBlockJobData *job =3D NULL; + const char *nodebase =3D NULL; + int ret =3D -1; + + virCheckFlags(VIR_DOMAIN_BLOCK_REBASE_PARAMS_RELATIVE, -1); + + if (virTypedParamsValidate(params, nparams, + VIR_DOMAIN_BLOCK_REBASE_PARAM_BASE, + VIR_TYPED_PARAM_STRING, + VIR_DOMAIN_BLOCK_REBASE_PARAM_BANDWIDTH, + VIR_TYPED_PARAM_ULLONG, + NULL) < 0) + return -1; + + if (!(vm =3D qemuDomainObjFromDomain(dom))) + return -1; + + priv =3D vm->privateData; + + if (virDomainBlockRebaseParamsEnsureACL(dom->conn, vm->def) < 0) + return -1; + + for (i =3D 0; i < nparams; i++) { + virTypedParameterPtr param =3D ¶ms[i]; + + if (STREQ(param->field, VIR_DOMAIN_BLOCK_REBASE_PARAM_BANDWIDTH)) { + bandwidth =3D param->value.ul; + } else if (STREQ(param->field, VIR_DOMAIN_BLOCK_REBASE_PARAM_BASE)= ) { + base =3D param->value.s; + } + } + + if (flags & VIR_DOMAIN_BLOCK_REBASE_PARAMS_RELATIVE && !base) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("flag VIR_DOMAIN_BLOCK_REBASE_PARAMS_RELATIVE is= valid only with non-null base")); + goto cleanup; + } + + if (virDomainObjBeginJob(vm, VIR_JOB_MODIFY) < 0) + goto cleanup; + + if (virDomainObjCheckActive(vm) < 0) + goto endjob; + + if (!(disk =3D qemuDomainDiskByName(vm->def, path))) + goto endjob; + + if (qemuDomainDiskBlockJobIsActive(disk)) + goto endjob; + + if (!qemuDomainDiskBlockJobIsSupported(disk)) + goto endjob; + + if (base && + !(baseSource =3D virStorageSourceChainLookup(disk->src, disk->src, + base, disk->dst, NULL))) + goto endjob; + + if (baseSource) { + if (flags & VIR_DOMAIN_BLOCK_REBASE_RELATIVE) { + if (qemuBlockUpdateRelativeBacking(vm, disk->src, disk->src) <= 0) + goto endjob; + + if (virStorageSourceGetRelativeBackingPath(disk->src->backingS= tore, + baseSource, + &backingPath) < 0) + goto endjob; + + if (!backingPath) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("can't keep relative backing relationship= ")); + goto endjob; + } + } + } + + if (!(job =3D qemuBlockJobDiskNewPull(vm, disk, baseSource, flags))) + goto endjob; + + if (baseSource) { + nodebase =3D qemuBlockStorageSourceGetEffectiveNodename(baseSource= ); + if (!backingPath && + !(backingPath =3D qemuBlockGetBackingStoreString(baseSource, f= alse))) + goto endjob; + } + + qemuDomainObjEnterMonitor(vm); + ret =3D qemuMonitorBlockStream(priv->mon, + qemuBlockStorageSourceGetEffectiveNodenam= e(disk->src), + job->name, + nodebase, + backingPath, + bandwidth); + qemuDomainObjExitMonitor(vm); + + if (ret < 0) + goto endjob; + + qemuBlockJobStarted(job, vm); + + endjob: + virDomainObjEndJob(vm); + + cleanup: + qemuBlockJobStartupFinalize(vm, job); + virDomainObjEndAPI(&vm); + return ret; +} + + /* bandwidth in bytes/s. Caller must lock vm beforehand, and not * access mirror afterwards. */ static int @@ -14579,17 +14645,30 @@ qemuDomainBlockRebase(virDomainPtr dom, VIR_DOMAIN_BLOCK_REBASE_COPY_DEV | VIR_DOMAIN_BLOCK_REBASE_BANDWIDTH_BYTES, -1); =20 + /* For normal rebase (enhanced blockpull), the common code handles + * everything, including vm cleanup. */ + if (!(flags & VIR_DOMAIN_BLOCK_REBASE_COPY)) { + virTypedParameterPtr params =3D NULL; + int nparams =3D 0; + unsigned int rebaseFlags =3D 0; + + ret =3D qemuDomainBlockRebasePrepareParams(base, bandwidth, flags, + &nparams, ¶ms, &rebas= eFlags); + if (ret =3D=3D 0) + ret =3D qemuDomainBlockRebaseParams(dom, path, params, nparams= , rebaseFlags); + + virTypedParamsFree(params, nparams); + params =3D NULL; + nparams =3D 0; + return ret; + } + if (!(vm =3D qemuDomainObjFromDomain(dom))) return -1; =20 if (virDomainBlockRebaseEnsureACL(dom->conn, vm->def) < 0) goto cleanup; =20 - /* For normal rebase (enhanced blockpull), the common code handles - * everything, including vm cleanup. */ - if (!(flags & VIR_DOMAIN_BLOCK_REBASE_COPY)) - return qemuDomainBlockPullCommon(vm, path, base, bandwidth, flags); - /* If we got here, we are doing a block copy rebase. */ dest =3D virStorageSourceNew(); if (flags & VIR_DOMAIN_BLOCK_REBASE_COPY_DEV) @@ -14722,19 +14801,22 @@ qemuDomainBlockPull(virDomainPtr dom, unsigned long bandwidth, unsigned int flags) { - virDomainObj *vm; - virCheckFlags(VIR_DOMAIN_BLOCK_PULL_BANDWIDTH_BYTES, -1); + virTypedParameterPtr params =3D NULL; + int nparams =3D 0; + unsigned int rebaseFlags =3D 0; + int ret =3D 0; =20 - if (!(vm =3D qemuDomainObjFromDomain(dom))) - return -1; + virCheckFlags(VIR_DOMAIN_BLOCK_PULL_BANDWIDTH_BYTES, -1); =20 - if (virDomainBlockPullEnsureACL(dom->conn, vm->def) < 0) { - virDomainObjEndAPI(&vm); - return -1; - } + ret =3D qemuDomainBlockRebasePrepareParams(NULL, bandwidth, flags, + &nparams, ¶ms, &rebaseFla= gs); + if (ret =3D=3D 0) + ret =3D qemuDomainBlockRebaseParams(dom, path, params, nparams, re= baseFlags); =20 - /* qemuDomainBlockPullCommon consumes the reference on @vm */ - return qemuDomainBlockPullCommon(vm, path, NULL, bandwidth, flags); + virTypedParamsFree(params, nparams); + params =3D NULL; + nparams =3D 0; + return ret; } =20 =20 @@ -20579,6 +20661,7 @@ static virHypervisorDriver qemuHypervisorDriver =3D= { .domainBlockJobSetSpeed =3D qemuDomainBlockJobSetSpeed, /* 0.9.4 */ .domainBlockPull =3D qemuDomainBlockPull, /* 0.9.4 */ .domainBlockRebase =3D qemuDomainBlockRebase, /* 0.9.10 */ + .domainBlockRebaseParams =3D qemuDomainBlockRebaseParams, /* 11.8.0 */ .domainBlockCopy =3D qemuDomainBlockCopy, /* 1.2.9 */ .domainBlockCommit =3D qemuDomainBlockCommit, /* 1.0.0 */ .connectIsAlive =3D qemuConnectIsAlive, /* 0.9.8 */ --=20 2.43.5 From nobody Sun Oct 5 00:14:11 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=pass(p=reject dis=none) header.from=lists.libvirt.org ARC-Seal: i=1; a=rsa-sha256; t=1758791338; cv=none; d=zohomail.com; s=zohoarc; b=lBwXWsMR4mMaE6eJroB+OA8ttxLEKaFPQjbPcv006ILNjc2bB5rJ3ICwet9Dk4YEd5sYRHC+WrzGibYVp5awu1FhX2PwJxBe3v+qdy3udZCYQNaaG74V+sPHMu/4F4T5qoaRQG7lVSeLVnda5yOT1SjlROTEnBJp2m9SDe8zfSc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1758791338; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Owner:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Subject:Subject:To:To:Message-Id; bh=kqVGcXFR4T38RbP1r5MOgBpXI3OHTtWZ7Y9EaUOEl1o=; b=PL1++YVJIYmEyqNwxWnFvdDuDfvUtTf9TNTtLiYznp2MCep6cA8jgfFpHIrWr9pqkdrujuq+idbwVOQetFEsd6YLcCv8ClCkc6odl00tY3texbKkFfgYZ3kaC8+3CcZp04DTVrckXNdyWrdGykKVZiJxxVw+Z+p6vzNE+KEW69g= ARC-Authentication-Results: i=1; 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=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 17587913384083.998483505586478; Thu, 25 Sep 2025 02:08:58 -0700 (PDT) Received: by lists.libvirt.org (Postfix, from userid 993) id 7A7D741B30; Thu, 25 Sep 2025 05:08:57 -0400 (EDT) Received: from [172.19.199.14] (lists.libvirt.org [8.43.85.245]) by lists.libvirt.org (Postfix) with ESMTP id 38B0D43FAD; Thu, 25 Sep 2025 04:56:59 -0400 (EDT) Received: by lists.libvirt.org (Postfix, from userid 993) id 1BD3E41C95; Thu, 25 Sep 2025 04:56:46 -0400 (EDT) Received: from relay.virtuozzo.com (relay.virtuozzo.com [130.117.225.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (3072 bits) server-digest SHA256) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id 82E9341C95 for ; Thu, 25 Sep 2025 04:56:37 -0400 (EDT) Received: from [130.117.225.5] (helo=dev012.ch-qa.vzint.dev) by relay.virtuozzo.com with esmtp (Exim 4.96) (envelope-from ) id 1v1hlu-00DyxO-30; Thu, 25 Sep 2025 10:56:34 +0200 X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-26) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-3.1 required=5.0 tests=DKIM_INVALID,DKIM_SIGNED, MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED,RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED,SPF_PASS autolearn=unavailable autolearn_force=no version=4.0.1 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=virtuozzo.com; s=relay; h=MIME-Version:Message-ID:Date:Subject:From: Content-Type; bh=kqVGcXFR4T38RbP1r5MOgBpXI3OHTtWZ7Y9EaUOEl1o=; b=GDmVxd3BlIrh 5BMa057QewLTRVdf++YgYGxov7TD+jf/zng2wtTSdGfNi9bp2CcWStOuXykyc6kFduwM6c60j3Hxp 8tL0sULt55Y790ULtJwFsEraZ83mnp+8CD97njm+GoJQczi6JjkndE/JX05fw8Z5CIxAoOjbiTCIf OJR21X99xYXGiwdmKcumHc3qMbU0wQnI33bwsI0+bT+JG9bQWK3DFhcJLbX8bF1ibBpkg18aIE6Y0 7gHrRcSwYoObNj7mHp37M0fF/KJS5nByWYEe9Uk/qtegTelanqIhNNh5dwRC0TeUFpD2KLvdVopJq hqZi+vJGkxztFvTjHC9qRQ==; To: devel@lists.libvirt.org Subject: [PATCH 3/3] tools: virsh: introduce blockrebase-params cmd Date: Thu, 25 Sep 2025 11:53:11 +0300 Message-ID: <20250925085627.102886-4-nikolai.barybin@virtuozzo.com> X-Mailer: git-send-email 2.43.5 In-Reply-To: <20250925085627.102886-1-nikolai.barybin@virtuozzo.com> References: <20250925085627.102886-1-nikolai.barybin@virtuozzo.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Message-ID-Hash: YK3EEYQNXQOVREUNR3IPZB55KDDDCAN4 X-Message-ID-Hash: YK3EEYQNXQOVREUNR3IPZB55KDDDCAN4 X-MailFrom: nikolai.barybin@virtuozzo.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; header-match-devel.lists.libvirt.org-0; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: den@virtuozzo.com X-Mailman-Version: 3.3.10 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Nikolai Barybin via Devel Reply-To: Nikolai Barybin X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1758791341006116600 Content-Type: text/plain; charset="utf-8" Signed-off-by: Nikolai Barybin --- docs/manpages/virsh.rst | 39 ++++++++++ tools/virsh-domain.c | 160 ++++++++++++++++++++++++++++++++++++++++ tools/vsh.c | 14 ++++ tools/vsh.h | 2 + 4 files changed, 215 insertions(+) diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst index bcb5495ed9..16c4f5d28d 100644 --- a/docs/manpages/virsh.rst +++ b/docs/manpages/virsh.rst @@ -1626,6 +1626,45 @@ on the *bandwidth* argument see the corresponding se= ction for the ``blockjob`` command. =20 =20 +blockrebase-params +------------------ + +**Syntax:** + +:: + + blockrebase-params domain path [bandwidth] [base] + [--wait [--verbose] [--timeout seconds] [--async]] + [--keep-relative] + +Populate a disk from its backing image chain. By default, this command +flattens the entire chain; but if *base* is specified, containing the +name of one of the backing files in the chain, then that file becomes +the new backing file and only the intermediate portion of the chain is +pulled. Once all requested data from the backing image chain has been +pulled, the disk no longer depends on that portion of the backing chain. + +By default, this command returns as soon as possible, and data for +the entire disk is pulled in the background; the progress of the +operation can be checked with ``blockjob``. However, if *--wait* is +specified, then this command will block until the operation completes, +or cancel the operation if the optional *timeout* in seconds elapses +or SIGINT is sent (usually with ``Ctrl-C``). Using *--verbose* along +with *--wait* will produce periodic status updates. If job cancellation +is triggered, *--async* will return control to the user as fast as +possible, otherwise the command may continue to block a little while +longer until the job is done cleaning up. + +Using the *--keep-relative* flag will keep the backing chain names +relative. + +*path* specifies fully-qualified path of the disk; it corresponds +to a unique target name () or source file () for one of the disk devices attached to *domain* (see +also ``domblklist`` for listing these names). +*bandwidth* specifies copying bandwidth limit in Bytes/s. + + blockresize ----------- =20 diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 6e18d195e6..9023f8f72d 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -3306,6 +3306,160 @@ cmdBlockpull(vshControl *ctl, const vshCmd *cmd) return ret; } =20 +/* + * "blockrebase-params" command + */ +static const vshCmdInfo info_blockrebase_params =3D { + .help =3D N_("Populate a disk from its backing image."), + .desc =3D N_("Populate a disk from its backing image."), +}; + +static const vshCmdOptDef opts_blockrebase_params[] =3D { + VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE), + {.name =3D "path", + .type =3D VSH_OT_STRING, + .positional =3D true, + .required =3D true, + .completer =3D virshDomainDiskTargetCompleter, + .help =3D N_("fully-qualified path of disk") + }, + {.name =3D "bandwidth", + .type =3D VSH_OT_INT, + .unwanted_positional =3D true, + .help =3D N_("bandwidth limit in bytes/s") + }, + {.name =3D "base", + .type =3D VSH_OT_STRING, + .unwanted_positional =3D true, + .completer =3D virshDomainBlockjobBaseTopCompleter, + .help =3D N_("path of backing file in chain specifying a new base") + }, + {.name =3D "wait", + .type =3D VSH_OT_BOOL, + .help =3D N_("wait for job to finish") + }, + {.name =3D "verbose", + .type =3D VSH_OT_BOOL, + .help =3D N_("with --wait, display the progress") + }, + {.name =3D "timeout", + .type =3D VSH_OT_INT, + .unwanted_positional =3D true, + .help =3D N_("with --wait, abort if rebase exceeds timeout (in second= s)") + }, + {.name =3D "async", + .type =3D VSH_OT_BOOL, + .help =3D N_("with --wait, don't wait for cancel to finish") + }, + {.name =3D "keep-relative", + .type =3D VSH_OT_BOOL, + .help =3D N_("keep the backing chain relatively referenced") + }, + {.name =3D NULL} +}; + +static bool +cmdBlockrebaseParams(vshControl *ctl, const vshCmd *cmd) +{ + g_autoptr(virshDomain) dom =3D NULL; + bool ret =3D false; + bool blocking =3D vshCommandOptBool(cmd, "wait"); + bool verbose =3D vshCommandOptBool(cmd, "verbose"); + bool async =3D vshCommandOptBool(cmd, "async"); + int timeout =3D 0; + const char *path =3D NULL; + const char *base =3D NULL; + unsigned long long bandwidth =3D 0; + unsigned int flags =3D 0; + virshBlockJobWaitData *bjWait =3D NULL; + int nparams =3D 0; + int maxparams =3D 0; + virTypedParameterPtr params =3D NULL; + + VSH_REQUIRE_OPTION("verbose", "wait"); + VSH_REQUIRE_OPTION("async", "wait"); + + if (vshCommandOptString(ctl, cmd, "path", &path) < 0) + return false; + + if (vshCommandOptString(ctl, cmd, "base", &base) < 0) + return false; + + if (vshBlockRebaseParamsOptionBandwidth(cmd, &bandwidth) < 0) + return false; + + if (vshCommandOptTimeoutToMs(ctl, cmd, &timeout) < 0) + return false; + + if (vshCommandOptBool(cmd, "keep-relative")) + flags |=3D VIR_DOMAIN_BLOCK_REBASE_PARAMS_RELATIVE; + + if (!(dom =3D virshCommandOptDomain(ctl, cmd, NULL))) + return false; + + if (blocking && + !(bjWait =3D virshBlockJobWaitInit(ctl, dom, path, _("Block Rebase= Params"), + verbose, timeout, async))) + goto cleanup; + + if (base && + virTypedParamsAddString(¶ms, &nparams, &maxparams, + VIR_DOMAIN_BLOCK_REBASE_PARAM_BASE, + base) < 0) { + vshError(ctl, _("failed to add param %1$s:%2$s to params list"), + VIR_DOMAIN_BLOCK_REBASE_PARAM_BASE, base); + goto cleanup; + } + + if (bandwidth > 0 && + virTypedParamsAddULLong(¶ms, &nparams, &maxparams, + VIR_DOMAIN_BLOCK_REBASE_PARAM_BANDWIDTH, + bandwidth) < 0) { + vshError(ctl, _("failed to add param %1$s:%2$llu to params list"), + VIR_DOMAIN_BLOCK_REBASE_PARAM_BANDWIDTH, bandwidth); + goto cleanup; + } + + if (virDomainBlockRebaseParams(dom, path, params, nparams, flags) < 0) + goto cleanup; + + if (!blocking) { + vshPrintExtra(ctl, "%s", _("Block Rebase started")); + ret =3D true; + goto cleanup; + } + + /* Execution continues here only if --wait or friends were specified */ + switch (virshBlockJobWait(bjWait)) { + case -1: + goto cleanup; + + case VIR_DOMAIN_BLOCK_JOB_CANCELED: + vshPrintExtra(ctl, "\n%s", _("Rebase aborted")); + goto cleanup; + break; + + case VIR_DOMAIN_BLOCK_JOB_FAILED: + vshPrintExtra(ctl, "\n%s", _("Rebase failed")); + goto cleanup; + break; + + case VIR_DOMAIN_BLOCK_JOB_READY: + case VIR_DOMAIN_BLOCK_JOB_COMPLETED: + vshPrintExtra(ctl, "\n%s", _("Rebase complete")); + break; + } + + ret =3D true; + + cleanup: + virshBlockJobWaitFree(bjWait); + virTypedParamsFree(params, nparams); + params =3D NULL; + nparams =3D 0; + return ret; +} + /* * "blockresize" command */ @@ -13976,6 +14130,12 @@ const vshCmdDef domManagementCmds[] =3D { .info =3D &info_blockpull, .flags =3D 0 }, + {.name =3D "blockrebase-params", + .handler =3D cmdBlockrebaseParams, + .opts =3D opts_blockrebase_params, + .info =3D &info_blockrebase_params, + .flags =3D 0 + }, {.name =3D "blockresize", .handler =3D cmdBlockresize, .opts =3D opts_blockresize, diff --git a/tools/vsh.c b/tools/vsh.c index 4aacc5feac..480b54b572 100644 --- a/tools/vsh.c +++ b/tools/vsh.c @@ -1346,6 +1346,20 @@ vshBlockJobOptionBandwidth(vshControl *ctl, } =20 =20 +int +vshBlockRebaseParamsOptionBandwidth(const vshCmd *cmd, + unsigned long long *bandwidth) +{ + vshCmdOpt *arg; + int ret; + + if ((ret =3D vshCommandOpt(cmd, "bandwidth", &arg, true)) <=3D 0) + return ret; + + return virStrToLong_ull(arg->data, NULL, 10, bandwidth); +} + + /** * vshCommandRun: * @ctl: virt shell data diff --git a/tools/vsh.h b/tools/vsh.h index bd2494e899..0f79c32d41 100644 --- a/tools/vsh.h +++ b/tools/vsh.h @@ -287,6 +287,8 @@ int vshBlockJobOptionBandwidth(vshControl *ctl, const vshCmd *cmd, bool bytes, unsigned long *bandwidth); +int vshBlockRebaseParamsOptionBandwidth(const vshCmd *cmd, + unsigned long long *bandwidth); bool vshCommandOptBool(const vshCmd *cmd, const char *name); int vshCommandRun(vshControl *ctl, const vshCmd *cmd); bool vshCommandStringParse(vshControl *ctl, char *cmdstr, --=20 2.43.5