From nobody Mon Feb 9 04:29:57 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 63.128.21.124 as permitted sender) client-ip=63.128.21.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of redhat.com designates 63.128.21.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=fail(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1611364541; cv=none; d=zohomail.com; s=zohoarc; b=Kn2pG0oyg13StfPbhUq/9V+19JISHT8q+0lgg1izwMq5TzzB6zxwNKB7JRrQz76Q6YosqSki15noIsqqPOKfR318RXpI/QDdY3z5QtC8iaS58VS2pQNQbQFM4j31dz7Dg+Y/qV9r+J3g77TPz7v5tTPI9fi6BDm9f0BiAR8RN7I= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1611364541; h=Content-Type:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:Message-ID:References:Sender:Subject:To; bh=VInge0N38beT/UVHQOO0BxocwAiKP/MfHTX4CD/a3vc=; b=W3sZwDM9ZRqi3/E15DTsrYnAGWUqEJ1I+E2u8T+j5fokqDCn35etevq2oF/AijbOhMloqz7hTPGFJl5S2qJPJ/pdR6JXrR3MJtmgLgmYz27vgeJPrZrxSC7ZH8PdvMgrNZHMhfA8n1g9b1zHSuSTANSqrCelZntXbtRUx2vTdGk= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=pass (zohomail.com: domain of redhat.com designates 63.128.21.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [63.128.21.124]) by mx.zohomail.com with SMTPS id 1611364541758981.342945839966; Fri, 22 Jan 2021 17:15:41 -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-186-ZZTD_OaZMNa0UPn2Yy-ZYQ-1; Fri, 22 Jan 2021 20:15:38 -0500 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 01C42107ACFA; Sat, 23 Jan 2021 01:15:33 +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 D2AF410023BD; Sat, 23 Jan 2021 01:15:32 +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 A15CC1809CA2; Sat, 23 Jan 2021 01:15:32 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 10N1BaaN001173 for ; Fri, 22 Jan 2021 20:11:36 -0500 Received: by smtp.corp.redhat.com (Postfix) id EFB8C2166B2F; Sat, 23 Jan 2021 01:11:35 +0000 (UTC) Received: from mimecast-mx02.redhat.com (mimecast06.extmail.prod.ext.rdu2.redhat.com [10.11.55.22]) by smtp.corp.redhat.com (Postfix) with ESMTPS id EA79B2166B27 for ; Sat, 23 Jan 2021 01:11:33 +0000 (UTC) Received: from us-smtp-1.mimecast.com (us-smtp-delivery-1.mimecast.com [205.139.110.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 6233D185A794 for ; Sat, 23 Jan 2021 01:11:33 +0000 (UTC) Received: from mail-qt1-f175.google.com (mail-qt1-f175.google.com [209.85.160.175]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-220-WloGq7ChO-e7H1jyjyvrkQ-1; Fri, 22 Jan 2021 20:11:31 -0500 Received: by mail-qt1-f175.google.com with SMTP id t17so5626549qtq.2 for ; Fri, 22 Jan 2021 17:11:31 -0800 (PST) Received: from localhost (209-6-122-159.s2973.c3-0.arl-cbr1.sbo-arl.ma.cable.rcncustomer.com. [209.6.122.159]) by smtp.gmail.com with ESMTPSA id u5sm7491440qka.86.2021.01.22.17.11.29 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Fri, 22 Jan 2021 17:11:30 -0800 (PST) X-MC-Unique: ZZTD_OaZMNa0UPn2Yy-ZYQ-1 X-MC-Unique: WloGq7ChO-e7H1jyjyvrkQ-1 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=VInge0N38beT/UVHQOO0BxocwAiKP/MfHTX4CD/a3vc=; b=WmBe/tL0VpKhA57gBNSdNW28azoQuZVqJFoAlBf1I117jtWhrksFNOcgy/oIIqKuyF ezxWpNWvS2Ey+dCGgURzV+Zh783VINOfQceJvc1taRDBuwboy24yvfns8v/FbQ+fvY/0 LzIdnGJ6PVN48kPKtCu6MEYBzhde9avXhBVhqqw2jBtzP9+EdNhGJ61/vTpWPBXOrFJ1 8BrciLozcuq8kgKi2V9ouFx4rc/OnRhSe4GiPo23fDp7sU5zL3v8EAkrpVuqj96V6Qau KtImI+/49f2tSHpUY+MdB1kSkJbYkT5lC2sSvWr+4Et8IJ1OiHENmBrqzKubUXgpxp3Q n/ow== X-Gm-Message-State: AOAM531MIeCNmoDxvgkrre24JbhdNjvtNGvfmb+xRCPjg/dnUZ2jkzUw 8OLRmLLdXZiz+3StdPTpfVjJKkU4Fw== X-Google-Smtp-Source: ABdhPJywHFZMRW1+s5BfXWpoFwh8yLa4hTz3MWP2P2l/tnkz7ldS6NFlo/0IfY5/yh3hrW2fOHHVAQ== X-Received: by 2002:ac8:7b45:: with SMTP id m5mr6767958qtu.323.1611364290536; Fri, 22 Jan 2021 17:11:30 -0800 (PST) From: Masayoshi Mizuma To: libvir-list@redhat.com Subject: [RFC PATCH 5/7] qemu_hotplug: make disk sharable Date: Fri, 22 Jan 2021 20:11:04 -0500 Message-Id: <20210123011106.11126-6-msys.mizuma@gmail.com> In-Reply-To: <20210123011106.11126-1-msys.mizuma@gmail.com> References: <20210123011106.11126-1-msys.mizuma@gmail.com> X-Mimecast-Impersonation-Protect: Policy=CLT - Impersonation Protection Definition; Similar Internal Domain=false; Similar Monitored External Domain=false; Custom External Domain=false; Mimecast External Domain=false; Newly Observed Domain=false; Internal User Name=false; Custom Display Name List=false; Reply-to Address Mismatch=false; Targeted Threat Dictionary=false; Mimecast Threat Dictionary=false; Custom Threat Dictionary=false X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-loop: libvir-list@redhat.com Cc: Masayoshi Mizuma , Masayoshi Mizuma 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.84 on 10.5.11.22 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=libvir-list-bounces@redhat.com X-Mimecast-Spam-Score: 2 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Masayoshi Mizuma Add qemuHotplugCreateDisksTransient() to make disk sharable. The procedure is followings. First, create the overlay disk with the original disk is set as the backingStore. Then, blockdev-del the StorageProgs and FormatProgs of the disk. That's because to fix the bootindex of the disk. Lastly, device_add the disks. Signed-off-by: Masayoshi Mizuma --- src/qemu/qemu_command.c | 3 + src/qemu/qemu_hotplug.c | 285 ++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_hotplug.h | 3 + 3 files changed, 291 insertions(+) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 1ec302d4ac..81a27703c5 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -2139,6 +2139,9 @@ qemuBuildDisksCommandLine(virCommandPtr cmd, bootCD =3D 0; break; case VIR_DOMAIN_DISK_DEVICE_DISK: + /* to use bootindex later for transient disk */ + disk->info.bootIndex =3D bootDisk; + G_GNUC_FALLTHROUGH; case VIR_DOMAIN_DISK_DEVICE_LUN: bootindex =3D bootDisk; bootDisk =3D 0; diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index a2535949b7..5d0445538d 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -6710,3 +6710,288 @@ qemuDomainSetVcpuInternal(virQEMUDriverPtr driver, virBitmapFree(livevcpus); return ret; } + +struct _qemuHotplugTransientDiskContext { + virDomainDeviceDefPtr trandev; + virDomainDiskDefPtr *domdisk; + size_t ndd; +}; + +typedef struct _qemuHotplugTransientDiskContext qemuHotplugTransientDisk= Context; +typedef qemuHotplugTransientDiskContext *qemuHotplugTransientDiskContextPt= r; + +static qemuHotplugTransientDiskContextPtr +qemuHotplugTransientDiskContextNew(size_t ndisks) +{ + qemuHotplugTransientDiskContextPtr ret =3D g_new0(qemuHotplugTransient= DiskContext, 1); + + ret->trandev =3D g_new0(virDomainDeviceDef, ndisks); + ret->domdisk =3D g_new0(virDomainDiskDefPtr, ndisks); + + return ret; +} + +static void +qemuHotplugTransientDiskCleanup(virDomainDeviceDefPtr data, + virDomainDiskDefPtr *domdisk) +{ + VIR_FREE(data); + VIR_FREE(domdisk); + + return; +} + +static void +qemuHotplugTransientDiskContextCleanup(qemuHotplugTransientDiskContextPtr = hptctxt) +{ + if (!hptctxt) + return; + + qemuHotplugTransientDiskCleanup(hptctxt->trandev, hptctxt->domdisk); + + g_free(hptctxt); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(qemuHotplugTransientDiskContext, qemuHotplug= TransientDiskContextCleanup); + +static int +qemuHotplugDiskPrepareOneBlockdev(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virQEMUDriverConfigPtr cfg, + virDomainDiskDefPtr domdisk, + virDomainDiskDefPtr trandisk, + GHashTable *blockNamedNodeData, + qemuDomainAsyncJob asyncJob) +{ + qemuDomainObjPrivatePtr priv =3D vm->privateData; + g_autoptr(qemuBlockStorageSourceChainData) data =3D NULL; + g_autoptr(virStorageSource) terminator =3D NULL; + + terminator =3D virStorageSourceNew(); + + if (qemuDomainPrepareStorageSourceBlockdev(trandisk, trandisk->src, + priv, cfg) < 0) + return -1; + + if (!(data =3D qemuBuildStorageSourceChainAttachPrepareBlockdevTop(tra= ndisk->src, + termi= nator, + priv-= >qemuCaps))) + return -1; + + if (qemuBlockStorageSourceCreateDetectSize(blockNamedNodeData, + trandisk->src, domdisk->src= ) < 0) + return -1; + + if (qemuBlockStorageSourceCreate(vm, trandisk->src, domdisk->src, + NULL, data->srcdata[0], + asyncJob) < 0) + return -1; + + /* blockdev-del the transient disk src. The disk is blockdev-add'ed + * while the disk is hot-added */ + if (qemuBlockStorageSourceDetachOneBlockdev(driver, vm, + asyncJob, trandisk->src) <= 0) + return -1; + + return 0; +} + +static int +qemuHotplugDiskTransientPrepareOne(virDomainObjPtr vm, + virQEMUDriverConfigPtr cfg, + virDomainDiskDefPtr domdisk, + virDomainDiskDefPtr trandisk, + GHashTable *blockNamedNodeData, + qemuDomainAsyncJob asyncJob) +{ + qemuDomainObjPrivatePtr priv =3D vm->privateData; + virQEMUDriverPtr driver =3D priv->driver; + bool supportsCreate; + + if (qemuDomainStorageSourceValidateDepth(trandisk->src, 1, trandisk->d= st) < 0) + return -1; + + if (virStorageSourceInitChainElement(trandisk->src, domdisk->src, fals= e) < 0) + return -1; + + trandisk->src->readonly =3D false; + supportsCreate =3D virStorageSourceSupportsCreate(trandisk->src); + + if (supportsCreate) { + if (qemuDomainStorageFileInit(driver, vm, trandisk->src, NULL) < 0) + return -1; + + if (virStorageSourceCreate(trandisk->src) < 0) { + virReportSystemError(errno, _("failed to create image file '%s= '"), + NULLSTR(trandisk->src->path)); + return -1; + } + } + + if (qemuDomainStorageSourceAccessAllow(driver, vm, trandisk->src, + false, true, true) < 0) + return -1; + + if (qemuHotplugDiskPrepareOneBlockdev(driver, vm, cfg, domdisk, trandi= sk, + blockNamedNodeData, asyncJob) < = 0) + return -1; + + return 0; +} + +static qemuHotplugTransientDiskContextPtr +qemuHotplugDiskPrepareDisksTransient(virDomainObjPtr vm, + virQEMUDriverConfigPtr cfg, + GHashTable *blockNamedNodeData, + qemuDomainAsyncJob asyncJob) +{ + g_autoptr(qemuHotplugTransientDiskContext) hptctxt =3D NULL; + qemuDomainObjPrivatePtr priv =3D vm->privateData; + virQEMUDriverPtr driver =3D priv->driver; + size_t i; + + hptctxt =3D qemuHotplugTransientDiskContextNew(vm->def->ndisks); + + for (i =3D 0; i < vm->def->ndisks; i++) { + virDomainDiskDefPtr domdisk =3D vm->def->disks[i]; + virDomainDiskDefPtr trandisk; + virDomainDeviceDefPtr trandev; + + if (!(trandisk =3D virDomainDiskDefNew(driver->xmlopt))) + return NULL; + + trandev =3D hptctxt->trandev + hptctxt->ndd; + trandev->type =3D VIR_DOMAIN_DEVICE_DISK; + + memcpy(&trandisk->info, &domdisk->info, sizeof(virDomainDeviceInfo= )); + trandisk->info.alias =3D NULL; + trandisk->info.romfile =3D NULL; + + if (domdisk->transient) { + trandisk->src =3D virStorageSourceNew(); + trandisk->src->type =3D VIR_STORAGE_TYPE_FILE; + trandisk->src->format =3D VIR_STORAGE_FILE_QCOW2; + trandisk->src->path =3D g_strdup_printf("%s.TRANSIENT-%s", + domdisk->src->path, vm->def= ->name); + + if (!(trandisk->src->backingStore =3D + virStorageSourceCopy(domdisk->src, false)= )) + return NULL; + + if (virFileExists(trandisk->src->path)) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, + _("Overlay file '%s' for transient disk '%s= ' already exists"), + trandisk->src->path, domdisk->dst); + return NULL; + } + + if (qemuHotplugDiskTransientPrepareOne(vm, cfg, domdisk, trand= isk, + blockNamedNodeData, + asyncJob) < 0) + return NULL; + } else { + /* The disks without transient option will be device_add as we= ll + * because to fix the bootindex */ + if (!(trandisk->src =3D virStorageSourceCopy(domdisk->src, fal= se))) + return NULL; + } + + trandisk->bus =3D domdisk->bus; + trandisk->dst =3D g_strdup(domdisk->dst); + trandev->data.disk =3D trandisk; + + hptctxt->domdisk[hptctxt->ndd] =3D domdisk; + + hptctxt->ndd++; + } + + return g_steal_pointer(&hptctxt); +} + +static int +qemuHotplugDiskTransientCreate(virDomainObjPtr vm, + qemuHotplugTransientDiskContextPtr hptctxt, + virQEMUDriverConfigPtr cfg, + qemuDomainAsyncJob asyncJob) +{ + qemuDomainObjPrivatePtr priv =3D vm->privateData; + virQEMUDriverPtr driver =3D priv->driver; + const char *alias =3D NULL; + size_t i; + int ret; + + for (i =3D 0; i < hptctxt->ndd; i++) { + virDomainDeviceDefPtr trandev =3D hptctxt->trandev + i; + virDomainDiskDefPtr domdisk =3D hptctxt->domdisk[i]; + bool transient =3D domdisk->transient; + + /* transient disk doesn't support disk hotplug. Disable it here te= mporarily + * to remove it */ + if (transient) + domdisk->transient =3D false; + + /* blockdev-del StorageProgs and FormatProps of domdisk so that + * qemuDomainAttachDeviceDiskLiveInternal() can blockdev-add without + * write lock issue */ + if (qemuDomainRemoveDiskDevice(driver, vm, domdisk, asyncJob) < 0) + return -1; + + ret =3D qemuDomainAttachDeviceDiskLiveInternal(driver, vm, trandev= , asyncJob); + if (!ret) { + alias =3D trandev->data.disk->info.alias; + if (transient) { + trandev->data.disk->transient =3D true; + } + } else { + VIR_DEBUG("Failed to attach disk %s (transient: %d) with disk = hotplug.", + trandev->data.disk->dst, transient); + return -1; + } + + if (alias) { + virObjectEventPtr event; + event =3D virDomainEventDeviceAddedNewFromObj(vm, alias); + virObjectEventStateQueue(driver->domainEventState, event); + } + + if (qemuDomainUpdateDeviceList(driver, vm, asyncJob) < 0) + return -1; + } + + if (virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0) + return -1; + + return 0; +} + +int +qemuHotplugCreateDisksTransient(virDomainObjPtr vm, + qemuDomainAsyncJob asyncJob) +{ + qemuDomainObjPrivatePtr priv =3D vm->privateData; + virQEMUDriverPtr driver =3D priv->driver; + g_autoptr(virQEMUDriverConfig) cfg =3D virQEMUDriverGetConfig(driver); + g_autoptr(qemuHotplugTransientDiskContext) hptctxt =3D NULL; + g_autoptr(GHashTable) blockNamedNodeData =3D NULL; + + if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV) && + virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_PCIE_ROOT_PORT_HOTPLUG)) { + + VIR_DEBUG("prepare transient disks with disk hotplug"); + + if (!(blockNamedNodeData =3D qemuBlockGetNamedNodeData(vm, asyncJo= b))) + return -1; + + if (!(hptctxt =3D qemuHotplugDiskPrepareDisksTransient(vm, cfg, + blockNamedNodeData, + asyncJob))) + return -1; + + if (qemuHotplugDiskTransientCreate(vm, hptctxt, cfg, asyncJob) < 0) + return -1; + } + + priv->inhibitDiskTransientDelete =3D false; + + return 0; +} diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h index 6287c5b5e8..baef2dba42 100644 --- a/src/qemu/qemu_hotplug.h +++ b/src/qemu/qemu_hotplug.h @@ -160,3 +160,6 @@ int qemuHotplugAttachDBusVMState(virQEMUDriverPtr drive= r, int qemuHotplugRemoveDBusVMState(virQEMUDriverPtr driver, virDomainObjPtr vm, qemuDomainAsyncJob asyncJob); + +int qemuHotplugCreateDisksTransient(virDomainObjPtr vm, + qemuDomainAsyncJob asyncJob); --=20 2.27.0