From nobody Tue Feb 10 04:15:57 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 216.205.24.124 as permitted sender) client-ip=216.205.24.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 216.205.24.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1613057925; cv=none; d=zohomail.com; s=zohoarc; b=h16B7Q/cVB6Vhz8Mg9GGIM7TS81/mnyFm9H6/2a5QNHbZwjI+D7rwS9qEDXFiDdr1CwdZIC+krO9VoQgQM3tef59sDn1zuPEtEoYdCHwFejvYJg8m4S6kgnh3QEj/gqD+XOpOdNP2CwHTxTQeSYE7SX1y70DrrcTGlVg6U8EKds= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1613057925; h=Content-Type:Content-Transfer-Encoding:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=UJPsGnhD7ljDkrBM6N1IFnYwNPpxbBfo1NJQxoceHBQ=; b=KR964p5exZODhz7a6IUaoHCNWzV4EhQQKDf5yrGqefohol+UgSSIMPSWT08+H25Asb9ZTUyF91uJvjtwt16isKo2O/qukwgP7DxEEM7bbupvyApb+lQdZAHHBx55qeheyBREyPLnBfsVZlYPOv6o2ch5z5hW34c3KnnugpOMXCo= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 216.205.24.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) header.from= Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [216.205.24.124]) by mx.zohomail.com with SMTPS id 1613057924593217.95413323689866; Thu, 11 Feb 2021 07:38:44 -0800 (PST) Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-203-hnGQGs4HM2-73wwPwCseXw-1; Thu, 11 Feb 2021 10:38:37 -0500 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 584E3107ACC7; Thu, 11 Feb 2021 15:38:31 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 2F06E5D6B1; Thu, 11 Feb 2021 15:38:31 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id E665918089D2; Thu, 11 Feb 2021 15:38:30 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 11BFcH9E019203 for ; Thu, 11 Feb 2021 10:38:17 -0500 Received: by smtp.corp.redhat.com (Postfix) id DF36C5D767; Thu, 11 Feb 2021 15:38:17 +0000 (UTC) Received: from speedmetal.lan (unknown [10.40.208.53]) by smtp.corp.redhat.com (Postfix) with ESMTP id 490F45D74F for ; Thu, 11 Feb 2021 15:38:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1613057923; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=UJPsGnhD7ljDkrBM6N1IFnYwNPpxbBfo1NJQxoceHBQ=; b=FW1BzwDR4xFsDIgdqHSDhWzZnr/VZIozqB6D+UPnBDc8mCPfsoQ2mqXs8INE6/0UO/p6Ck mLb2I9RjPJHf+Xv63gNNyASoZYyuuIseCb0GLMLOU8T2bOaMD+EiTlnMyCOB5XGTHNJKWs vWFSW/qSSLa1aa0w6g03REV65fm8KV0= X-MC-Unique: hnGQGs4HM2-73wwPwCseXw-1 From: Peter Krempa To: libvir-list@redhat.com Subject: [PATCH 12/19] qemu: migration_cookie: Add XML handling for setting up bitmap migration Date: Thu, 11 Feb 2021 16:37:51 +0100 Message-Id: <3ba5864a1d10d7f5ae5991089551dac4e7c85754.1613057278.git.pkrempa@redhat.com> In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-loop: libvir-list@redhat.com X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=libvir-list-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) Content-Type: text/plain; charset="utf-8" In cases where we are copying the storage we need to ensure that also bitmaps are copied properly. This patch adds migration cookie XML infrastructure which will allow the migration sides reach consensus on which bitmaps to migrate. Signed-off-by: Peter Krempa Reviewed-by: Jiri Denemark --- src/qemu/qemu_migration_cookie.c | 134 +++++++++++++++++++++++++++++++ src/qemu/qemu_migration_cookie.h | 34 ++++++++ 2 files changed, 168 insertions(+) diff --git a/src/qemu/qemu_migration_cookie.c b/src/qemu/qemu_migration_coo= kie.c index 6f2b1b2f57..94ba9c83d0 100644 --- a/src/qemu/qemu_migration_cookie.c +++ b/src/qemu/qemu_migration_cookie.c @@ -51,6 +51,7 @@ VIR_ENUM_IMPL(qemuMigrationCookieFlag, "cpu", "allowReboot", "capabilities", + "block-dirty-bitmaps", ); @@ -116,6 +117,39 @@ qemuMigrationCookieCapsFree(qemuMigrationCookieCapsPtr= caps) G_DEFINE_AUTOPTR_CLEANUP_FUNC(qemuMigrationCookieCaps, qemuMigrationCookieCapsFree); +static void +qemuMigrationBlockDirtyBitmapsDiskBitmapFree(qemuMigrationBlockDirtyBitmap= sDiskBitmapPtr bmp) +{ + if (!bmp) + return; + + g_free(bmp->bitmapname); + g_free(bmp->alias); + g_free(bmp->sourcebitmap); + g_free(bmp); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(qemuMigrationBlockDirtyBitmapsDiskBitmap, + qemuMigrationBlockDirtyBitmapsDiskBitmapFree= ); + + +static void +qemuMigrationBlockDirtyBitmapsDiskFree(qemuMigrationBlockDirtyBitmapsDiskP= tr dsk) +{ + if (!dsk) + return; + + g_free(dsk->target); + if (dsk->bitmaps) + g_slist_free_full(dsk->bitmaps, + (GDestroyNotify) qemuMigrationBlockDirtyBitmapsD= iskBitmapFree); + g_free(dsk); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(qemuMigrationBlockDirtyBitmapsDisk, + qemuMigrationBlockDirtyBitmapsDiskFree); + + void qemuMigrationCookieFree(qemuMigrationCookiePtr mig) { @@ -135,6 +169,9 @@ qemuMigrationCookieFree(qemuMigrationCookiePtr mig) g_clear_pointer(&mig->jobInfo, qemuDomainJobInfoFree); virCPUDefFree(mig->cpu); qemuMigrationCookieCapsFree(mig->caps); + if (mig->blockDirtyBitmaps) + g_slist_free_full(mig->blockDirtyBitmaps, + (GDestroyNotify) qemuMigrationBlockDirtyBitmapsD= iskFree); g_free(mig); } @@ -758,6 +795,48 @@ qemuMigrationCookieNBDXMLFormat(qemuMigrationCookieNBD= Ptr nbd, } +static void +qemuMigrationCookieBlockDirtyBitmapsFormat(virBufferPtr buf, + GSList *bitmaps) +{ + g_auto(virBuffer) disksBuf =3D VIR_BUFFER_INIT_CHILD(buf); + GSList *nextdisk; + + for (nextdisk =3D bitmaps; nextdisk; nextdisk =3D nextdisk->next) { + qemuMigrationBlockDirtyBitmapsDiskPtr disk =3D nextdisk->data; + g_auto(virBuffer) diskAttrBuf =3D VIR_BUFFER_INITIALIZER; + g_auto(virBuffer) diskChildBuf =3D VIR_BUFFER_INIT_CHILD(&disksBuf= ); + bool hasBitmaps =3D false; + GSList *nextbitmap; + + if (disk->skip || !disk->bitmaps) + continue; + + for (nextbitmap =3D disk->bitmaps; nextbitmap; nextbitmap =3D next= bitmap->next) { + qemuMigrationBlockDirtyBitmapsDiskBitmapPtr bitmap =3D nextbit= map->data; + + if (bitmap->skip) + continue; + + virBufferAsprintf(&diskChildBuf, + "\n", + bitmap->bitmapname, bitmap->alias); + + hasBitmaps =3D true; + } + + if (!hasBitmaps) + continue; + + virBufferAsprintf(&diskAttrBuf, " target=3D'%s'", disk->target); + virXMLFormatElement(&disksBuf, "disk", &diskAttrBuf, &diskChildBuf= ); + } + + + virXMLFormatElement(buf, "blockDirtyBitmaps", NULL, &disksBuf); +} + + int qemuMigrationCookieXMLFormat(virQEMUDriverPtr driver, virQEMUCapsPtr qemuCaps, @@ -829,6 +908,9 @@ qemuMigrationCookieXMLFormat(virQEMUDriverPtr driver, if (mig->flags & QEMU_MIGRATION_COOKIE_CAPS) qemuMigrationCookieCapsXMLFormat(buf, mig->caps); + if (mig->flags & QEMU_MIGRATION_COOKIE_BLOCK_DIRTY_BITMAPS) + qemuMigrationCookieBlockDirtyBitmapsFormat(buf, mig->blockDirtyBit= maps); + virBufferAdjustIndent(buf, -2); virBufferAddLit(buf, "\n"); return 0; @@ -1132,6 +1214,53 @@ qemuMigrationCookieXMLParseMandatoryFeatures(xmlXPat= hContextPtr ctxt, } +static int +qemuMigrationCookieBlockDirtyBitmapsParse(xmlXPathContextPtr ctxt, + qemuMigrationCookiePtr mig) +{ + g_autoslist(qemuMigrationBlockDirtyBitmapsDisk) disks =3D NULL; + g_autofree xmlNodePtr *disknodes =3D NULL; + int ndisknodes; + size_t i; + VIR_XPATH_NODE_AUTORESTORE(ctxt) + + if ((ndisknodes =3D virXPathNodeSet("./blockDirtyBitmaps/disk", ctxt, = &disknodes)) < 0) + return -1; + + for (i =3D 0; i < ndisknodes; i++) { + GSList *bitmaps =3D NULL; + qemuMigrationBlockDirtyBitmapsDiskPtr disk; + g_autofree xmlNodePtr *bitmapnodes =3D NULL; + int nbitmapnodes; + size_t j; + + ctxt->node =3D disknodes[i]; + + if ((nbitmapnodes =3D virXPathNodeSet("./bitmap", ctxt, &bitmapnod= es)) < 0) + return -1; + + for (j =3D 0; j < nbitmapnodes; j++) { + qemuMigrationBlockDirtyBitmapsDiskBitmapPtr bitmap; + + bitmap =3D g_new0(qemuMigrationBlockDirtyBitmapsDiskBitmap, 1); + bitmap->bitmapname =3D virXMLPropString(bitmapnodes[j], "name"= ); + bitmap->alias =3D virXMLPropString(bitmapnodes[j], "alias"); + bitmaps =3D g_slist_prepend(bitmaps, bitmap); + } + + disk =3D g_new0(qemuMigrationBlockDirtyBitmapsDisk, 1); + disk->target =3D virXMLPropString(disknodes[i], "target"); + disk->bitmaps =3D g_slist_reverse(bitmaps); + + disks =3D g_slist_prepend(disks, disk); + } + + mig->blockDirtyBitmaps =3D g_slist_reverse(g_steal_pointer(&disks)); + + return 0; +} + + static int qemuMigrationCookieXMLParse(qemuMigrationCookiePtr mig, virQEMUDriverPtr driver, @@ -1275,6 +1404,11 @@ qemuMigrationCookieXMLParse(qemuMigrationCookiePtr m= ig, !(mig->caps =3D qemuMigrationCookieCapsXMLParse(ctxt))) return -1; + if (flags & QEMU_MIGRATION_COOKIE_BLOCK_DIRTY_BITMAPS && + virXPathBoolean("boolean(./blockDirtyBitmaps)", ctxt) && + qemuMigrationCookieBlockDirtyBitmapsParse(ctxt, mig) < 0) + return -1; + return 0; } diff --git a/src/qemu/qemu_migration_cookie.h b/src/qemu/qemu_migration_coo= kie.h index ecd1a01375..8636f955da 100644 --- a/src/qemu/qemu_migration_cookie.h +++ b/src/qemu/qemu_migration_cookie.h @@ -35,6 +35,7 @@ typedef enum { QEMU_MIGRATION_COOKIE_FLAG_CPU, QEMU_MIGRATION_COOKIE_FLAG_ALLOW_REBOOT, QEMU_MIGRATION_COOKIE_FLAG_CAPS, + QEMU_MIGRATION_COOKIE_FLAG_BLOCK_DIRTY_BITMAPS, QEMU_MIGRATION_COOKIE_FLAG_LAST } qemuMigrationCookieFlags; @@ -53,6 +54,7 @@ typedef enum { QEMU_MIGRATION_COOKIE_CPU =3D (1 << QEMU_MIGRATION_COOKIE_FLAG_CPU), QEMU_MIGRATION_COOKIE_ALLOW_REBOOT =3D (1 << QEMU_MIGRATION_COOKIE_FLA= G_ALLOW_REBOOT), QEMU_MIGRATION_COOKIE_CAPS =3D (1 << QEMU_MIGRATION_COOKIE_FLAG_CAPS), + QEMU_MIGRATION_COOKIE_BLOCK_DIRTY_BITMAPS =3D (1 << QEMU_MIGRATION_COO= KIE_FLAG_BLOCK_DIRTY_BITMAPS), } qemuMigrationCookieFeatures; typedef struct _qemuMigrationCookieGraphics qemuMigrationCookieGraphics; @@ -107,6 +109,35 @@ struct _qemuMigrationCookieCaps { virBitmapPtr automatic; }; +typedef struct _qemuMigrationBlockDirtyBitmapsDiskBitmap qemuMigrationBloc= kDirtyBitmapsDiskBitmap; +typedef qemuMigrationBlockDirtyBitmapsDiskBitmap *qemuMigrationBlockDirtyB= itmapsDiskBitmapPtr; +struct _qemuMigrationBlockDirtyBitmapsDiskBitmap { + /* config */ + char *bitmapname; + char *alias; + + /* runtime */ + virTristateBool persistent; /* force persisting of the bitmap */ + char *sourcebitmap; /* optional, actual bitmap to migrate in case we n= eeded + to create a temporary one by merging */ + bool skip; /* omit this bitmap */ +}; + + +typedef struct _qemuMigrationBlockDirtyBitmapsDisk qemuMigrationBlockDirty= BitmapsDisk; +typedef qemuMigrationBlockDirtyBitmapsDisk *qemuMigrationBlockDirtyBitmaps= DiskPtr; +struct _qemuMigrationBlockDirtyBitmapsDisk { + char *target; + + GSList *bitmaps; + + /* runtime data */ + virDomainDiskDefPtr disk; /* disk object corresponding to 'target' */ + const char *nodename; /* nodename of the top level source of 'disk' */ + bool skip; /* omit this disk */ +}; + + typedef struct _qemuMigrationCookie qemuMigrationCookie; typedef qemuMigrationCookie *qemuMigrationCookiePtr; struct _qemuMigrationCookie { @@ -150,6 +181,9 @@ struct _qemuMigrationCookie { /* If flags & QEMU_MIGRATION_COOKIE_CAPS */ qemuMigrationCookieCapsPtr caps; + + /* If flags & QEMU_MIGRATION_COOKIE_BLOCK_DIRTY_BITMAPS */ + GSList *blockDirtyBitmaps; }; --=20 2.29.2