From nobody Sun Feb 8 15:54:18 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) client-ip=170.10.133.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 170.10.133.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=1661272365; cv=none; d=zohomail.com; s=zohoarc; b=jXIVtduxXlm81tHpb3U5n8fK94c8Ef5eZ2+RLOaa2vBq49cOWZmE1/Hsc1CKrf3W0QZRApoAsZ6QczyEEDXVzZBvdDzvd5eILW3UcEqHB7YI6IYGain6pr5p6IuyhbTWH+FKPYZYS/KTdLbxii41cUIEWt6KeBmty+OkKuHcy/I= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1661272365; 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=z29zmpxz0XecfW3bV/jWKGLIHh7GnV7SqbQcjUILZdk=; b=ZK9q4c86VS02yHSjmm/iNcrI86LGEplgFY9Sqkzs7ahf1rKdh92V7cEXdUiHl4DhAnOeVXVpHeAQKG3bJiR0ulqPdL/4l581ozvUArZLmg8gbnHTEi/sXGyyKj0G3NpxQBki5jeh33eERDzerZocVr11GaM01tQhx6M8a8wVHQA= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by mx.zohomail.com with SMTPS id 1661272365548821.5397102268864; Tue, 23 Aug 2022 09:32:45 -0700 (PDT) Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-56-4RRcXNSqMKOVHMUWRscs7g-1; Tue, 23 Aug 2022 12:32:40 -0400 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.rdu2.redhat.com [10.11.54.7]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id AA0833C0F368; Tue, 23 Aug 2022 16:32:35 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (unknown [10.30.29.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 92CE71415137; Tue, 23 Aug 2022 16:32:35 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (localhost [IPv6:::1]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id 76BEF1946A47; Tue, 23 Aug 2022 16:32:35 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id CE6FB1946A40 for ; Tue, 23 Aug 2022 16:32:33 +0000 (UTC) Received: by smtp.corp.redhat.com (Postfix) id BE519403349; Tue, 23 Aug 2022 16:32:33 +0000 (UTC) Received: from localhost.localdomain (unknown [10.40.192.194]) by smtp.corp.redhat.com (Postfix) with ESMTP id 40079492C3B for ; Tue, 23 Aug 2022 16:32:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1661272364; 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=z29zmpxz0XecfW3bV/jWKGLIHh7GnV7SqbQcjUILZdk=; b=ge4MNMUBMkq52Zkk6YaL/zpLHa3uvra8Z+ktJVlq/XXKYiO0kL+NTGxkhkjuBnn5qcS6Ei w+HHLbyV5w6xbARmRW6cWCXjjfARxAsE/2S8+TWtDkU6ubbcuY7/iBZzSN0Biwesr1Uq7e KqkiaD9eeXB9qIYGzNLVQCgyLa1qZlM= X-MC-Unique: 4RRcXNSqMKOVHMUWRscs7g-1 X-Original-To: libvir-list@listman.corp.redhat.com From: Pavel Hrdina To: libvir-list@redhat.com Subject: [libvirt RFC 01/24] qemu_block: extract block commit code to separate function Date: Tue, 23 Aug 2022 18:32:04 +0200 Message-Id: In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.85 on 10.11.54.10 X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libvir-list-bounces@redhat.com Sender: "libvir-list" X-Scanned-By: MIMEDefang 2.85 on 10.11.54.7 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1661272367322100003 Content-Type: text/plain; charset="utf-8"; x-default="true" Signed-off-by: Pavel Hrdina --- src/qemu/qemu_block.c | 197 +++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_block.h | 9 ++ src/qemu/qemu_driver.c | 181 +------------------------------------ 3 files changed, 207 insertions(+), 180 deletions(-) diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c index b82e3311e1..c0c4088cbf 100644 --- a/src/qemu/qemu_block.c +++ b/src/qemu/qemu_block.c @@ -3201,3 +3201,200 @@ qemuBlockExportAddNBD(virDomainObj *vm, =20 return qemuMonitorBlockExportAdd(priv->mon, &nbdprops); } + + +int +qemuBlockCommit(virDomainObj *vm, + virQEMUDriver *driver, + const char *path, + const char *base, + const char *top, + unsigned long bandwidth, + unsigned int flags) +{ + qemuDomainObjPrivate *priv =3D vm->privateData; + int rc =3D -1; + virDomainDiskDef *disk =3D NULL; + virStorageSource *topSource; + virStorageSource *baseSource =3D NULL; + virStorageSource *top_parent =3D NULL; + bool clean_access =3D false; + g_autofree char *backingPath =3D NULL; + qemuBlockJobData *job =3D NULL; + g_autoptr(virStorageSource) mirror =3D NULL; + + if (virDomainObjCheckActive(vm) < 0) + return -1; + + /* Convert bandwidth MiB to bytes, if necessary */ + if (!(flags & VIR_DOMAIN_BLOCK_COMMIT_BANDWIDTH_BYTES)) { + if (bandwidth > LLONG_MAX >> 20) { + virReportError(VIR_ERR_OVERFLOW, + _("bandwidth must be less than %llu"), + LLONG_MAX >> 20); + return -1; + } + bandwidth <<=3D 20; + } + + if (!(disk =3D qemuDomainDiskByName(vm->def, path))) + return -1; + + if (!qemuDomainDiskBlockJobIsSupported(disk)) + return -1; + + if (virStorageSourceIsEmpty(disk->src)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("disk %s has no source file to be committed"), + disk->dst); + return -1; + } + + if (qemuDomainDiskBlockJobIsActive(disk)) + return -1; + + if (qemuDomainSupportsCheckpointsBlockjobs(vm) < 0) + return -1; + + if (!top || STREQ(top, disk->dst)) + topSource =3D disk->src; + else if (!(topSource =3D virStorageSourceChainLookup(disk->src, NULL, = top, + disk->dst, &top_par= ent))) + return -1; + + if (topSource =3D=3D disk->src) { + /* XXX Should we auto-pivot when COMMIT_ACTIVE is not specified? */ + if (!(flags & VIR_DOMAIN_BLOCK_COMMIT_ACTIVE)) { + virReportError(VIR_ERR_INVALID_ARG, + _("commit of '%s' active layer requires active = flag"), + disk->dst); + return -1; + } + } else if (flags & VIR_DOMAIN_BLOCK_COMMIT_ACTIVE) { + virReportError(VIR_ERR_INVALID_ARG, + _("active commit requested but '%s' is not active"), + topSource->path); + return -1; + } + + if (!virStorageSourceHasBacking(topSource)) { + virReportError(VIR_ERR_INVALID_ARG, + _("top '%s' in chain for '%s' has no backing file"), + topSource->path, path); + return -1; + } + + if (!base && (flags & VIR_DOMAIN_BLOCK_COMMIT_SHALLOW)) + baseSource =3D topSource->backingStore; + else if (!(baseSource =3D virStorageSourceChainLookup(disk->src, topSo= urce, + base, disk->dst, N= ULL))) + return -1; + + if ((flags & VIR_DOMAIN_BLOCK_COMMIT_SHALLOW) && + baseSource !=3D topSource->backingStore) { + virReportError(VIR_ERR_INVALID_ARG, + _("base '%s' is not immediately below '%s' in chain= " + "for '%s'"), + base, topSource->path, path); + return -1; + } + + /* For an active commit, clone enough of the base to act as the mirror= */ + if (topSource =3D=3D disk->src) { + if (!(mirror =3D virStorageSourceCopy(baseSource, false))) + return -1; + if (virStorageSourceInitChainElement(mirror, + disk->src, + true) < 0) + return -1; + } + + if (flags & VIR_DOMAIN_BLOCK_COMMIT_RELATIVE && + topSource !=3D disk->src) { + if (top_parent && + qemuBlockUpdateRelativeBacking(vm, top_parent, disk->src) < 0) + return -1; + + if (virStorageSourceGetRelativeBackingPath(topSource, baseSource, + &backingPath) < 0) + return -1; + + if (!backingPath) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("can't keep relative backing relationship")); + return -1; + } + } + + /* For the commit to succeed, we must allow qemu to open both the + * 'base' image and the parent of 'top' as read/write; 'top' might + * not have a parent, or might already be read-write. XXX It + * would also be nice to revert 'base' to read-only, as well as + * revoke access to files removed from the chain, when the commit + * operation succeeds, but doing that requires tracking the + * operation in XML across libvirtd restarts. */ + clean_access =3D true; + if (qemuDomainStorageSourceAccessAllow(driver, vm, baseSource, + false, false, false) < 0) + goto error; + + if (top_parent && top_parent !=3D disk->src) { + /* While top_parent is topmost image, we don't need to remember its + * owner as it will be overwritten upon finishing the commit. Henc= e, + * pass chainTop =3D false. */ + if (qemuDomainStorageSourceAccessAllow(driver, vm, top_parent, + false, false, false) < 0) + goto error; + } + + if (!(job =3D qemuBlockJobDiskNewCommit(vm, disk, top_parent, topSourc= e, + baseSource, + flags & VIR_DOMAIN_BLOCK_COMMIT_= DELETE, + flags))) + goto error; + + disk->mirrorState =3D VIR_DOMAIN_DISK_MIRROR_STATE_NONE; + + if (!backingPath && top_parent && + !(backingPath =3D qemuBlockGetBackingStoreString(baseSource, false= ))) + goto error; + + qemuDomainObjEnterMonitor(vm); + + rc =3D qemuMonitorBlockCommit(priv->mon, + qemuDomainDiskGetTopNodename(disk), + job->name, + topSource->nodeformat, + baseSource->nodeformat, + backingPath, bandwidth); + + qemuDomainObjExitMonitor(vm); + + if (rc < 0) + goto error; + + if (mirror) { + disk->mirror =3D g_steal_pointer(&mirror); + disk->mirrorJob =3D VIR_DOMAIN_BLOCK_JOB_TYPE_ACTIVE_COMMIT; + } + qemuBlockJobStarted(job, vm); + + return 0; + + error: + if (clean_access) { + virErrorPtr orig_err; + virErrorPreserveLast(&orig_err); + /* Revert access to read-only, if possible. */ + qemuDomainStorageSourceAccessAllow(driver, vm, baseSource, + true, false, false); + if (top_parent && top_parent !=3D disk->src) + qemuDomainStorageSourceAccessAllow(driver, vm, top_parent, + true, false, false); + + virErrorRestore(&orig_err); + } + qemuBlockJobStartupFinalize(vm, job); + + return -1; +} diff --git a/src/qemu/qemu_block.h b/src/qemu/qemu_block.h index 8a3a10344e..be81ec3c7f 100644 --- a/src/qemu/qemu_block.h +++ b/src/qemu/qemu_block.h @@ -276,3 +276,12 @@ qemuBlockExportAddNBD(virDomainObj *vm, const char *exportname, bool writable, const char *bitmap); + +int +qemuBlockCommit(virDomainObj *vm, + virQEMUDriver *driver, + const char *path, + const char *base, + const char *top, + unsigned long bandwidth, + unsigned int flags); diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 707f4cc1bb..d353b6df93 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -15375,18 +15375,8 @@ qemuDomainBlockCommit(virDomainPtr dom, unsigned int flags) { virQEMUDriver *driver =3D dom->conn->privateData; - qemuDomainObjPrivate *priv; virDomainObj *vm =3D NULL; int ret =3D -1; - virDomainDiskDef *disk =3D NULL; - virStorageSource *topSource; - virStorageSource *baseSource =3D NULL; - virStorageSource *top_parent =3D NULL; - bool clean_access =3D false; - g_autofree char *backingPath =3D NULL; - unsigned long long speed =3D bandwidth; - qemuBlockJobData *job =3D NULL; - g_autoptr(virStorageSource) mirror =3D NULL; =20 virCheckFlags(VIR_DOMAIN_BLOCK_COMMIT_SHALLOW | VIR_DOMAIN_BLOCK_COMMIT_ACTIVE | @@ -15396,7 +15386,6 @@ qemuDomainBlockCommit(virDomainPtr dom, =20 if (!(vm =3D qemuDomainObjFromDomain(dom))) goto cleanup; - priv =3D vm->privateData; =20 if (virDomainBlockCommitEnsureACL(dom->conn, vm->def) < 0) goto cleanup; @@ -15404,176 +15393,8 @@ qemuDomainBlockCommit(virDomainPtr dom, if (qemuDomainObjBeginJob(vm, VIR_JOB_MODIFY) < 0) goto cleanup; =20 - if (virDomainObjCheckActive(vm) < 0) - goto endjob; + ret =3D qemuBlockCommit(vm, driver, path, base, top, bandwidth, flags); =20 - /* Convert bandwidth MiB to bytes, if necessary */ - if (!(flags & VIR_DOMAIN_BLOCK_COMMIT_BANDWIDTH_BYTES)) { - if (speed > LLONG_MAX >> 20) { - virReportError(VIR_ERR_OVERFLOW, - _("bandwidth must be less than %llu"), - LLONG_MAX >> 20); - goto endjob; - } - speed <<=3D 20; - } - - if (!(disk =3D qemuDomainDiskByName(vm->def, path))) - goto endjob; - - if (!qemuDomainDiskBlockJobIsSupported(disk)) - goto endjob; - - if (virStorageSourceIsEmpty(disk->src)) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("disk %s has no source file to be committed"), - disk->dst); - goto endjob; - } - - if (qemuDomainDiskBlockJobIsActive(disk)) - goto endjob; - - if (qemuDomainSupportsCheckpointsBlockjobs(vm) < 0) - goto endjob; - - if (!top || STREQ(top, disk->dst)) - topSource =3D disk->src; - else if (!(topSource =3D virStorageSourceChainLookup(disk->src, NULL, = top, - disk->dst, &top_par= ent))) - goto endjob; - - if (topSource =3D=3D disk->src) { - /* XXX Should we auto-pivot when COMMIT_ACTIVE is not specified? */ - if (!(flags & VIR_DOMAIN_BLOCK_COMMIT_ACTIVE)) { - virReportError(VIR_ERR_INVALID_ARG, - _("commit of '%s' active layer requires active = flag"), - disk->dst); - goto endjob; - } - } else if (flags & VIR_DOMAIN_BLOCK_COMMIT_ACTIVE) { - virReportError(VIR_ERR_INVALID_ARG, - _("active commit requested but '%s' is not active"), - topSource->path); - goto endjob; - } - - if (!virStorageSourceHasBacking(topSource)) { - virReportError(VIR_ERR_INVALID_ARG, - _("top '%s' in chain for '%s' has no backing file"), - topSource->path, path); - goto endjob; - } - - if (!base && (flags & VIR_DOMAIN_BLOCK_COMMIT_SHALLOW)) - baseSource =3D topSource->backingStore; - else if (!(baseSource =3D virStorageSourceChainLookup(disk->src, topSo= urce, - base, disk->dst, N= ULL))) - goto endjob; - - if ((flags & VIR_DOMAIN_BLOCK_COMMIT_SHALLOW) && - baseSource !=3D topSource->backingStore) { - virReportError(VIR_ERR_INVALID_ARG, - _("base '%s' is not immediately below '%s' in chain= " - "for '%s'"), - base, topSource->path, path); - goto endjob; - } - - /* For an active commit, clone enough of the base to act as the mirror= */ - if (topSource =3D=3D disk->src) { - if (!(mirror =3D virStorageSourceCopy(baseSource, false))) - goto endjob; - if (virStorageSourceInitChainElement(mirror, - disk->src, - true) < 0) - goto endjob; - } - - if (flags & VIR_DOMAIN_BLOCK_COMMIT_RELATIVE && - topSource !=3D disk->src) { - if (top_parent && - qemuBlockUpdateRelativeBacking(vm, top_parent, disk->src) < 0) - goto endjob; - - if (virStorageSourceGetRelativeBackingPath(topSource, baseSource, - &backingPath) < 0) - goto endjob; - - if (!backingPath) { - virReportError(VIR_ERR_OPERATION_INVALID, "%s", - _("can't keep relative backing relationship")); - goto endjob; - } - } - - /* For the commit to succeed, we must allow qemu to open both the - * 'base' image and the parent of 'top' as read/write; 'top' might - * not have a parent, or might already be read-write. XXX It - * would also be nice to revert 'base' to read-only, as well as - * revoke access to files removed from the chain, when the commit - * operation succeeds, but doing that requires tracking the - * operation in XML across libvirtd restarts. */ - clean_access =3D true; - if (qemuDomainStorageSourceAccessAllow(driver, vm, baseSource, - false, false, false) < 0) - goto endjob; - - if (top_parent && top_parent !=3D disk->src) { - /* While top_parent is topmost image, we don't need to remember its - * owner as it will be overwritten upon finishing the commit. Henc= e, - * pass chainTop =3D false. */ - if (qemuDomainStorageSourceAccessAllow(driver, vm, top_parent, - false, false, false) < 0) - goto endjob; - } - - if (!(job =3D qemuBlockJobDiskNewCommit(vm, disk, top_parent, topSourc= e, - baseSource, - flags & VIR_DOMAIN_BLOCK_COMMIT_= DELETE, - flags))) - goto endjob; - - disk->mirrorState =3D VIR_DOMAIN_DISK_MIRROR_STATE_NONE; - - if (!backingPath && top_parent && - !(backingPath =3D qemuBlockGetBackingStoreString(baseSource, false= ))) - goto endjob; - - qemuDomainObjEnterMonitor(vm); - - ret =3D qemuMonitorBlockCommit(priv->mon, - qemuDomainDiskGetTopNodename(disk), - job->name, - topSource->nodeformat, - baseSource->nodeformat, - backingPath, speed); - - qemuDomainObjExitMonitor(vm); - - if (ret < 0) - goto endjob; - - if (mirror) { - disk->mirror =3D g_steal_pointer(&mirror); - disk->mirrorJob =3D VIR_DOMAIN_BLOCK_JOB_TYPE_ACTIVE_COMMIT; - } - qemuBlockJobStarted(job, vm); - - endjob: - if (ret < 0 && clean_access) { - virErrorPtr orig_err; - virErrorPreserveLast(&orig_err); - /* Revert access to read-only, if possible. */ - qemuDomainStorageSourceAccessAllow(driver, vm, baseSource, - true, false, false); - if (top_parent && top_parent !=3D disk->src) - qemuDomainStorageSourceAccessAllow(driver, vm, top_parent, - true, false, false); - - virErrorRestore(&orig_err); - } - qemuBlockJobStartupFinalize(vm, job); qemuDomainObjEndJob(vm); =20 cleanup: --=20 2.37.2