From nobody Mon Sep 16 19:47:43 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1540495805090615.8999907627498; Thu, 25 Oct 2018 12:30:05 -0700 (PDT) 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 mx1.redhat.com (Postfix) with ESMTPS id E533B300271A; Thu, 25 Oct 2018 19:30:02 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 4711D5D781; Thu, 25 Oct 2018 19:30:02 +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 3FD414BB74; Thu, 25 Oct 2018 19:30:01 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id w9PJLQwt028118 for ; Thu, 25 Oct 2018 15:21:26 -0400 Received: by smtp.corp.redhat.com (Postfix) id 2DB7A60F80; Thu, 25 Oct 2018 19:21:26 +0000 (UTC) Received: from red.redhat.com (ovpn-122-116.rdu2.redhat.com [10.10.122.116]) by smtp.corp.redhat.com (Postfix) with ESMTP id D7DB360C60; Thu, 25 Oct 2018 19:21:20 +0000 (UTC) From: Eric Blake To: libvir-list@redhat.com Date: Thu, 25 Oct 2018 20:20:21 +0100 Message-Id: <20181025192021.350438-21-eblake@redhat.com> In-Reply-To: <20181025192021.350438-1-eblake@redhat.com> References: <20181025192021.350438-1-eblake@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-loop: libvir-list@redhat.com Cc: amureini@redhat.com, derez@redhat.com, vsementsov@virtuozzo.com, ydary@redhat.com, nsoffer@redhat.com, jsnow@redhat.com Subject: [libvirt] [PATCH v3 20/20] backup: implement qemu incremental pull backup 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: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.46]); Thu, 25 Oct 2018 19:30:03 +0000 (UTC) Content-Type: text/plain; charset="utf-8" Complete wiring up incremental backup, by adding in support for creating a checkpoint at the same time as a backup (make the transaction have a few more steps) as well as exposing the dirty bitmap for a prior backup over NBD (requires creating a temporary bitmap, merging all appropriate bitmaps in, then exposing that bitmap over NBD). Signed-off-by: Eric Blake --- src/qemu/qemu_driver.c | 164 ++++++++++++++++++++++++++++++++++------- 1 file changed, 139 insertions(+), 25 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index f8f05599ce..6b397ddf11 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -16785,6 +16785,24 @@ qemuDomainCheckpointPrepare(virQEMUDriverPtr drive= r, virCapsPtr caps, if (disk->type !=3D VIR_DOMAIN_CHECKPOINT_TYPE_BITMAP) continue; + /* We want to name temporary bitmap after disk name during + * incremental backup, which is not possible if that is a + * persistent bitmap name. We can also make life easier by + * enforcing bitmap names match checkpoint name, although this + * is not technically necessary. */ + if (STREQ(disk->name, disk->bitmap)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("checkpoint for disk %s must have distinct bi= tmap name"), + disk->name); + goto cleanup; + } + if (STRNEQ(disk->bitmap, def->name)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("disk %s bitmap should match checkpoint name = %s"), + disk->name, def->name); + goto cleanup; + } + if (vm->def->disks[i]->src->format > 0 && vm->def->disks[i]->src->format !=3D VIR_STORAGE_FILE_QCOW2) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, @@ -17450,19 +17468,42 @@ qemuDomainCheckpointDelete(virDomainCheckpointPtr= checkpoint, static int qemuDomainBackupPrepare(virQEMUDriverPtr driver, virDomainObjPtr vm, - virDomainBackupDefPtr def) + virDomainBackupDefPtr def, + virDomainCheckpointObjPtr chk) { int ret =3D -1; int i; + if (chk && def->ndisks !=3D chk->def->ndisks) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("inconsistency between backup and checkpoint disk= s")); + goto cleanup; + } if (qemuBlockNodeNamesDetect(driver, vm, QEMU_ASYNC_JOB_NONE) < 0) goto cleanup; for (i =3D 0; i < def->ndisks; i++) { virDomainBackupDiskDef *disk =3D &def->disks[i]; virStorageSourcePtr src =3D vm->def->disks[disk->idx]->src; - if (!disk->store) + /* For now, insist that atomic checkpoint affect same disks as + * those being backed up. */ + if (!disk->store) { + if (chk && + chk->def->disks[i].type !=3D VIR_DOMAIN_CHECKPOINT_TYPE_NO= NE) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, + _("disk %s requested checkpoint without bac= kup"), + disk->name); + goto cleanup; + } continue; + } + if (chk && + chk->def->disks[i].type !=3D VIR_DOMAIN_CHECKPOINT_TYPE_BITMAP= ) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, + _("disk %s requested backup without checkpoint"= ), + disk->name); + goto cleanup; + } if (virAsprintf(&disk->store->nodeformat, "tmp-%s", disk->name) < = 0) goto cleanup; if (!disk->store->format) @@ -17494,10 +17535,10 @@ qemuDomainBackupDiskCleanup(virQEMUDriverPtr driv= er, virDomainObjPtr vm, return 0; if (disk->state >=3D VIR_DOMAIN_BACKUP_DISK_STATE_EXPORT) { /* No real need to use nbd-server-remove, since we will - * shortly be calling nbd-server-stsop. */ + * shortly be calling nbd-server-stop. */ } if (incremental && disk->state >=3D VIR_DOMAIN_BACKUP_DISK_STATE_BITMA= P && - qemuMonitorDeleteBitmap(priv->mon, node, disk->store->nodeformat) = < 0) { + qemuMonitorDeleteBitmap(priv->mon, node, disk->name) < 0) { VIR_WARN("Unable to remove temp bitmap for disk %s after backup", disk->name); ret =3D -1; @@ -17538,23 +17579,14 @@ qemuDomainBackupBegin(virDomainPtr domain, const = char *diskXml, char *suffix =3D NULL; virCommandPtr cmd =3D NULL; const char *qemuImgPath; + virDomainCheckpointDefPtr chkdef =3D NULL; + virDomainCheckpointObjPtr chk =3D NULL; + virDomainCheckpointObjPtr other =3D NULL; + virDomainCheckpointObjPtr parent =3D NULL; virCheckFlags(VIR_DOMAIN_BACKUP_BEGIN_NO_METADATA, -1); /* TODO: VIR_DOMAIN_BACKUP_BEGIN_QUIESCE */ - // FIXME: Support non-null checkpointXML for incremental - what - // code can be shared with CheckpointCreateXML, then add to transaction - // to create new checkpoint at same time as starting blockdev-backup - if (checkpointXml) { - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("cannot create incremental backups yet")); - return -1; - } - // if (chk) VIR_STRDUP(suffix, chk->name); - gettimeofday(&tv, NULL); - if (virAsprintf(&suffix, "%lld", (long long)tv.tv_sec) < 0) - goto cleanup; - if (!(vm =3D qemuDomObjFromDomain(domain))) goto cleanup; @@ -17580,6 +17612,17 @@ qemuDomainBackupBegin(virDomainPtr domain, const c= har *diskXml, if (!(def =3D virDomainBackupDefParseString(diskXml, driver->xmlopt, 0= ))) goto cleanup; + if (checkpointXml) { + if (!(chkdef =3D qemuDomainCheckpointDefParseString(driver, caps, + checkpointXml, 0= )) || + VIR_STRDUP(suffix, chkdef->name) < 0) + goto cleanup; + } else { + gettimeofday(&tv, NULL); + if (virAsprintf(&suffix, "%lld", (long long)tv.tv_sec) < 0) + goto cleanup; + } + if (def->type =3D=3D VIR_DOMAIN_BACKUP_TYPE_PULL && (!def->server || def->server->transport !=3D VIR_STORAGE_NET_HOST_TRANS_TCP)) { @@ -17588,9 +17631,18 @@ qemuDomainBackupBegin(virDomainPtr domain, const c= har *diskXml, goto cleanup; } if (def->incremental) { - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("cannot create incremental backups yet")); - goto cleanup; + for (other =3D vm->current_checkpoint; other; + other =3D other->def->parent ? + virDomainCheckpointFindByName(vm->checkpoints, + other->def->parent) : NULL) + if (STREQ(other->def->name, def->incremental)) + break; + if (!other) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("could not locate checkpoint '%s' for increme= ntal backup"), + def->incremental); + goto cleanup; + } } if (!(qemuImgPath =3D qemuFindQemuImgBinary(driver))) @@ -17607,14 +17659,34 @@ qemuDomainBackupBegin(virDomainPtr domain, const = char *diskXml, goto endjob; } + if (chkdef) { + if (qemuDomainCheckpointPrepare(driver, caps, vm, chkdef) < 0) + goto endjob; + if (!(chk =3D virDomainCheckpointAssignDef(vm->checkpoints, chkdef= ))) + goto endjob; + chkdef =3D NULL; + chk->def->current =3D true; + if (vm->current_checkpoint) { + parent =3D vm->current_checkpoint; + if (VIR_STRDUP(chk->def->parent, parent->def->name) < 0) + goto endjob; + if (qemuDomainCheckpointWriteMetadata(vm, parent, driver->caps, + driver->xmlopt, + cfg->checkpointDir) < 0) + goto endjob; + vm->current_checkpoint =3D NULL; + } + } + if (virDomainBackupAlignDisks(def, vm->def, suffix) < 0 || - qemuDomainBackupPrepare(driver, vm, def) < 0) + qemuDomainBackupPrepare(driver, vm, def, chk) < 0) goto endjob; /* actually start the checkpoint. 2x2 array of push/pull, full/incr, plus additional tweak if checkpoint requested */ qemuDomainObjEnterMonitor(driver, vm); - /* - push/pull: blockdev-add per */ + /* - push/pull: blockdev-add per + - incr: bitmap-add of tmp, x-bitmap-merge per */ for (i =3D 0; i < def->ndisks; i++) { virDomainBackupDiskDef *disk =3D &def->disks[i]; virJSONValuePtr file; @@ -17672,11 +17744,25 @@ qemuDomainBackupBegin(virDomainPtr domain, const = char *diskXml, goto endmon; json =3D NULL; disk->state =3D VIR_DOMAIN_BACKUP_DISK_STATE_READY; + + if (def->incremental) { + if (qemuMonitorAddBitmap(priv->mon, node, disk->name) < 0) + goto endmon; + disk->state =3D VIR_DOMAIN_BACKUP_DISK_STATE_BITMAP; + for (other =3D parent ?: vm->current_checkpoint; other; + other =3D other->def->parent ? + virDomainCheckpointFindByName(vm->checkpoints, + other->def->parent) : N= ULL) { + if (qemuMonitorMergeBitmaps(priv->mon, node, disk->name, + other->def->name) < 0) + goto endmon; + if (STREQ(other->def->name, def->incremental)) + break; + } + } } - /* TODO: - - incr: bitmap-add of tmp, x-bitmap-merge per - - transaction, containing: + /* - transaction, containing: - push+full: blockdev-backup sync:full - push+incr: blockdev-backup sync:incremental bitmap:tmp - pull+full: blockdev-backup sync:none @@ -17699,10 +17785,37 @@ qemuDomainBackupBegin(virDomainPtr domain, const = char *diskXml, "s:job-id", disk->store->nodefor= mat, NULL) < 0) goto endmon; + if (def->incremental && def->type =3D=3D VIR_DOMAIN_BACKUP_TYPE_PU= LL && + qemuMonitorJSONTransactionAdd(json, + "x-block-dirty-bitmap-disable", + "s:node", src->nodeformat, + "s:name", disk->name, + NULL) < 0) + goto endmon; } + if (chk && qemuDomainCheckpointAddActions(json, parent, chk->def) < 0) + goto endmon; if (qemuMonitorTransaction(priv->mon, &json) < 0) goto endmon; job_started =3D true; + if (chk) { + if (qemuDomainCheckpointWriteMetadata(vm, chk, driver->caps, + driver->xmlopt, + cfg->checkpointDir) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unable to save metadata for checkpoint %s"), + chk->def->name); + virDomainCheckpointObjListRemove(vm->checkpoints, chk); + goto endmon; + } + vm->current_checkpoint =3D chk; + other =3D virDomainCheckpointFindByName(vm->checkpoints, + chk->def->parent); + chk->parent =3D other; + other->nchildren++; + chk->sibling =3D other->first_child; + other->first_child =3D chk; + } /* - pull: nbd-server-start with from user (or autogenerate s= erver) @@ -17769,6 +17882,7 @@ qemuDomainBackupBegin(virDomainPtr domain, const ch= ar *diskXml, qemuDomainObjEndJob(driver, vm); cleanup: + virDomainCheckpointDefFree(chkdef); virCommandFree(cmd); VIR_FREE(suffix); virJSONValueFree(json); --=20 2.17.2 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list