Package init

Signed-off-by: yezengruan <yezengruan@huawei.com>
This commit is contained in:
liuxiangdong 2022-01-29 09:56:33 +08:00 committed by yezengruan
parent cff59dc576
commit 787ea25064
563 changed files with 60 additions and 64962 deletions

View File

@ -1,38 +0,0 @@
From 841b8d099c462cd4282c4ced8c2a6512899fd8d9 Mon Sep 17 00:00:00 2001
From: Jiajun Chen <chenjiajun8@huawei.com>
Date: Mon, 20 Jan 2020 15:11:39 +0100
Subject: [PATCH] 9pfs: local: Fix possible memory leak in local_link()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
There is a possible memory leak while local_link return -1 without free
odirpath and oname.
Reported-by: Euler Robot <euler.robot@huawei.com>
Signed-off-by: Jaijun Chen <chenjiajun8@huawei.com>
Signed-off-by: Xiang Zheng <zhengxiang9@huawei.com>
Reviewed-by: Christian Schoenebeck <qemu_oss@crudebyte.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Signed-off-by: Greg Kurz <groug@kaod.org>
(cherry picked from commit 841b8d099c462cd4282c4ced8c2a6512899fd8d9)
---
hw/9pfs/9p-local.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c
index ca64139..d0592c3 100644
--- a/hw/9pfs/9p-local.c
+++ b/hw/9pfs/9p-local.c
@@ -947,7 +947,7 @@ static int local_link(FsContext *ctx, V9fsPath *oldpath,
if (ctx->export_flags & V9FS_SM_MAPPED_FILE &&
local_is_mapped_file_metadata(ctx, name)) {
errno = EINVAL;
- return -1;
+ goto out;
}
odirfd = local_opendir_nofollow(ctx, odirpath);
--
1.8.3.1

View File

@ -1,64 +0,0 @@
From e3a7ec839fa4f823666d726989c375dcf73348a4 Mon Sep 17 00:00:00 2001
From: Ying Fang <fangying1@huawei.com>
Date: Wed, 15 Apr 2020 16:14:50 +0800
Subject: [PATCH] ARM: KVM: Check KVM_CAP_ARM_IRQ_LINE_LAYOUT_2 for smp_cpus >
256
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Host kernel within [4.18, 5.3] report an erroneous KVM_MAX_VCPUS=512
for ARM. The actual capability to instantiate more than 256 vcpus
was fixed in 5.4 with the upgrade of the KVM_IRQ_LINE ABI to support
vcpu id encoded on 12 bits instead of 8 and a redistributor consuming
a single KVM IO device instead of 2.
So let's check this capability when attempting to use more than 256
vcpus within any ARM kvm accelerated machine.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Andrew Jones <drjones@redhat.com>
Acked-by: Marc Zyngier <maz@kernel.org>
Message-id: 20191003154640.22451-4-eric.auger@redhat.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry-picked from commit fff9f5558d0e0813d4f80bfe1602acf225eca4fd)
[yu: Use the legacy smp_cpus instead of ms->smp.cpus, as we don't have
¦struct CpuTopology in MachineState at that time. See commit
¦edeeec911702 for details.]
Signed-off-by: Zenghui Yu <yuzenghui@huawei.com>
---
target/arm/kvm.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 50e86f8b..cc7a46df 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -173,6 +173,8 @@ int kvm_arm_get_max_vm_ipa_size(MachineState *ms)
int kvm_arch_init(MachineState *ms, KVMState *s)
{
+ int ret = 0;
+ unsigned int smp_cpus = ms->smp.cpus;
/* For ARM interrupt delivery is always asynchronous,
* whether we are using an in-kernel VGIC or not.
*/
@@ -186,7 +188,14 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE);
- return 0;
+ if (smp_cpus > 256 &&
+ !kvm_check_extension(s, KVM_CAP_ARM_IRQ_LINE_LAYOUT_2)) {
+ error_report("Using more than 256 vcpus requires a host kernel "
+ "with KVM_CAP_ARM_IRQ_LINE_LAYOUT_2");
+ ret = -EINVAL;
+ }
+
+ return ret;
}
unsigned long kvm_arch_vcpu_id(CPUState *cpu)
--
2.23.0

View File

@ -1,134 +0,0 @@
From 4646a24045cf53f2cc5e0ef1974da88ef50ef676 Mon Sep 17 00:00:00 2001
From: Ying Fang <fangying1@huawei.com>
Date: Wed, 27 May 2020 11:54:31 +0800
Subject: [PATCH] ARM64: record vtimer tick when cpu is stopped
The vtimer kick still increases even if the vcpu is stopped when VM has
save/restore or suspend/resume operation. This will cause guest watchdog
soft-lockup if the VM has lots of memory in use.
Signed-off-by: Hao Hong <honghao5@huawei.com>
Signed-off-by: Haibin Wang <wanghaibin.wang@huawei.com>
Signed-off-by: Ying Fang <fangying1@huawei.com>
---
cpus.c | 58 ++++++++++++++++++++++++++++++++++++++++++++
target/arm/cpu.h | 2 ++
target/arm/machine.c | 1 +
3 files changed, 61 insertions(+)
diff --git a/cpus.c b/cpus.c
index 927a00aa..b9aa51f8 100644
--- a/cpus.c
+++ b/cpus.c
@@ -1066,6 +1066,28 @@ void cpu_synchronize_all_pre_loadvm(void)
}
}
+#ifdef __aarch64__
+static void get_vcpu_timer_tick(CPUState *cs)
+{
+ CPUARMState *env = &ARM_CPU(cs)->env;
+ int err;
+ struct kvm_one_reg reg;
+ uint64_t timer_tick;
+
+ reg.id = KVM_REG_ARM_TIMER_CNT;
+ reg.addr = (uintptr_t) &timer_tick;
+
+ err = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+ if (err < 0) {
+ error_report("get vcpu tick failed, ret = %d", err);
+ env->vtimer = 0;
+ return;
+ }
+ env->vtimer = timer_tick;
+ return;
+}
+#endif
+
static int do_vm_stop(RunState state, bool send_stop)
{
int ret = 0;
@@ -1073,6 +1095,11 @@ static int do_vm_stop(RunState state, bool send_stop)
if (runstate_is_running()) {
cpu_disable_ticks();
pause_all_vcpus();
+#ifdef __aarch64__
+ if (first_cpu) {
+ get_vcpu_timer_tick(first_cpu);
+ }
+#endif
runstate_set(state);
vm_state_notify(0, state);
if (send_stop) {
@@ -1918,11 +1945,42 @@ void cpu_resume(CPUState *cpu)
qemu_cpu_kick(cpu);
}
+#ifdef __aarch64__
+static void set_vcpu_timer_tick(CPUState *cs)
+{
+ CPUARMState *env = &ARM_CPU(cs)->env;
+
+ if (env->vtimer == 0) {
+ return;
+ }
+
+ int err;
+ struct kvm_one_reg reg;
+ uint64_t timer_tick = env->vtimer;
+ env->vtimer = 0;
+
+ reg.id = KVM_REG_ARM_TIMER_CNT;
+ reg.addr = (uintptr_t) &timer_tick;
+
+ err = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+ if (err < 0) {
+ error_report("Set vcpu tick failed, ret = %d", err);
+ return;
+ }
+ return;
+}
+#endif
+
void resume_all_vcpus(void)
{
CPUState *cpu;
qemu_clock_enable(QEMU_CLOCK_VIRTUAL, true);
+#ifdef __aarch64__
+ if (first_cpu) {
+ set_vcpu_timer_tick(first_cpu);
+ }
+#endif
CPU_FOREACH(cpu) {
cpu_resume(cpu);
}
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 86eb79cd..aec6a214 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -262,6 +262,8 @@ typedef struct CPUARMState {
uint64_t sp_el[4]; /* AArch64 banked stack pointers */
+ uint64_t vtimer; /* Timer tick when vcpu stop */
+
/* System control coprocessor (cp15) */
struct {
uint32_t c0_cpuid;
diff --git a/target/arm/machine.c b/target/arm/machine.c
index ee3c59a6..ec28b839 100644
--- a/target/arm/machine.c
+++ b/target/arm/machine.c
@@ -814,6 +814,7 @@ const VMStateDescription vmstate_arm_cpu = {
VMSTATE_UINT32(env.exception.syndrome, ARMCPU),
VMSTATE_UINT32(env.exception.fsr, ARMCPU),
VMSTATE_UINT64(env.exception.vaddress, ARMCPU),
+ VMSTATE_UINT64(env.vtimer, ARMCPU),
VMSTATE_TIMER_PTR(gt_timer[GTIMER_PHYS], ARMCPU),
VMSTATE_TIMER_PTR(gt_timer[GTIMER_VIRT], ARMCPU),
{
--
2.23.0

View File

@ -1,54 +0,0 @@
From 8cb4d202d4e5713e9b2b5f0ec817234941623f10 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
Date: Fri, 4 Jun 2021 15:58:25 +0400
Subject: [PATCH 1/6] Add mtod_check()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Recent security issues demonstrate the lack of safety care when casting
a mbuf to a particular structure type. At least, it should check that
the buffer is large enough. The following patches will make use of this
function.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: imxcc <xingchaochao@huawei.com>
---
slirp/src/mbuf.c | 11 +++++++++++
slirp/src/mbuf.h | 1 +
2 files changed, 12 insertions(+)
diff --git a/slirp/src/mbuf.c b/slirp/src/mbuf.c
index 4fd62282..6d0653ed 100644
--- a/slirp/src/mbuf.c
+++ b/slirp/src/mbuf.c
@@ -222,3 +222,14 @@ struct mbuf *dtom(Slirp *slirp, void *dat)
return (struct mbuf *)0;
}
+
+void *mtod_check(struct mbuf *m, size_t len)
+{
+ if (m->m_len >= len) {
+ return m->m_data;
+ }
+
+ DEBUG_ERROR("mtod failed");
+
+ return NULL;
+}
diff --git a/slirp/src/mbuf.h b/slirp/src/mbuf.h
index 546e7852..2015e323 100644
--- a/slirp/src/mbuf.h
+++ b/slirp/src/mbuf.h
@@ -118,6 +118,7 @@ void m_inc(struct mbuf *, int);
void m_adj(struct mbuf *, int);
int m_copy(struct mbuf *, struct mbuf *, int, int);
struct mbuf *dtom(Slirp *, void *);
+void *mtod_check(struct mbuf *, size_t len);
static inline void ifs_init(struct mbuf *ifm)
{
--
2.27.0

View File

@ -1,32 +0,0 @@
From 38734e26ce3840d459da13607a9d46de24a15388 Mon Sep 17 00:00:00 2001
From: kevinZhu <zhukeqian94@163.com>
Date: Thu, 29 Oct 2020 19:24:48 +0800
Subject: [PATCH] Bugfix: hw/acpi: Use max_cpus instead of cpus when build PPTT
table
The field "cpus" is the initial number of CPU for guest, and the field "max_cpus"
is the max number of CPU after CPU hotplug. When building PPTT for guest, we
should take all CPUs into account, otherwise the "smp_sockets" is wrong.
Fixes: 7cfcd8c8a2fe ("build smt processor structure to support smt topology")
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
---
hw/acpi/aml-build.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index 8a3b51c835..f01669df57 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -167,7 +167,7 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, int possible_cpus)
struct offset_status offset;
const MachineState *ms = MACHINE(qdev_get_machine());
unsigned int smp_cores = ms->smp.cores;
- unsigned int smp_sockets = ms->smp.cpus / (smp_cores * ms->smp.threads);
+ unsigned int smp_sockets = ms->smp.max_cpus / (smp_cores * ms->smp.threads);
acpi_data_push(table_data, sizeof(AcpiTableHeader));
--
2.27.0

View File

@ -1,60 +0,0 @@
From 124032e79e354f5e7cc28958f2ca6b9f898da719 Mon Sep 17 00:00:00 2001
From: Fan Yang <Fan_Yang@sjtu.edu.cn>
Date: Tue, 24 Sep 2019 22:08:29 +0800
Subject: [PATCH] COLO-compare: Fix incorrect `if` logic
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
'colo_mark_tcp_pkt' should return 'true' when packets are the same, and
'false' otherwise. However, it returns 'true' when
'colo_compare_packet_payload' returns non-zero while
'colo_compare_packet_payload' is just a 'memcmp'. The result is that
COLO-compare reports inconsistent TCP packets when they are actually
the same.
Fixes: f449c9e549c ("colo: compare the packet based on the tcp sequence number")
Cc: qemu-stable@nongnu.org
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Signed-off-by: Fan Yang <Fan_Yang@sjtu.edu.cn>
Signed-off-by: Jason Wang <jasowang@redhat.com>
(cherry picked from commit 1e907a32b77e5d418538453df5945242e43224fa)
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
net/colo-compare.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/net/colo-compare.c b/net/colo-compare.c
index bf10526..9827c0e 100644
--- a/net/colo-compare.c
+++ b/net/colo-compare.c
@@ -287,7 +287,7 @@ static bool colo_mark_tcp_pkt(Packet *ppkt, Packet *spkt,
*mark = 0;
if (ppkt->tcp_seq == spkt->tcp_seq && ppkt->seq_end == spkt->seq_end) {
- if (colo_compare_packet_payload(ppkt, spkt,
+ if (!colo_compare_packet_payload(ppkt, spkt,
ppkt->header_size, spkt->header_size,
ppkt->payload_size)) {
*mark = COLO_COMPARE_FREE_SECONDARY | COLO_COMPARE_FREE_PRIMARY;
@@ -297,7 +297,7 @@ static bool colo_mark_tcp_pkt(Packet *ppkt, Packet *spkt,
/* one part of secondary packet payload still need to be compared */
if (!after(ppkt->seq_end, spkt->seq_end)) {
- if (colo_compare_packet_payload(ppkt, spkt,
+ if (!colo_compare_packet_payload(ppkt, spkt,
ppkt->header_size + ppkt->offset,
spkt->header_size + spkt->offset,
ppkt->payload_size - ppkt->offset)) {
@@ -316,7 +316,7 @@ static bool colo_mark_tcp_pkt(Packet *ppkt, Packet *spkt,
/* primary packet is longer than secondary packet, compare
* the same part and mark the primary packet offset
*/
- if (colo_compare_packet_payload(ppkt, spkt,
+ if (!colo_compare_packet_payload(ppkt, spkt,
ppkt->header_size + ppkt->offset,
spkt->header_size + spkt->offset,
spkt->payload_size - spkt->offset)) {
--
1.8.3.1

View File

@ -1,30 +0,0 @@
From e8b555c08061ad78920611a5e98ee14fcd967692 Mon Sep 17 00:00:00 2001
From: Ralf Haferkamp <rhafer@suse.com>
Date: Fri, 11 Sep 2020 10:55:49 +0800
Subject: [PATCH] Drop bogus IPv6 messages
Drop IPv6 message shorter than what's mentioned in the playload
length header (+the size of IPv6 header). They're invalid and could
lead to data leakage in icmp6_send_echoreply().
diff --git a/slirp/src/ip6_input.c b/slirp/src/ip6_input.c
index d9d2b7e..c2dce52 100644
--- a/slirp/src/ip6_input.c
+++ b/slirp/src/ip6_input.c
@@ -49,6 +49,13 @@ void ip6_input(struct mbuf *m)
goto bad;
}
+ // Check if the message size is big enough to hold what's
+ // set in the payload length header. If not this is an invalid
+ // packet
+ if (m->m_len < ntohs(ip6->ip_pl) + sizeof(struct ip6)) {
+ goto bad;
+ }
+
/* check ip_ttl for a correct ICMP reply */
if (ip6->ip_hl == 0) {
icmp6_send_error(m, ICMP6_TIMXCEED, ICMP6_TIMXCEED_INTRANS);
--
1.8.3.1

View File

@ -1,39 +0,0 @@
From 126fc13ebe9c5e58a5b1daeb4e102e6fa5845779 Mon Sep 17 00:00:00 2001
From: Kirti Wankhede <kwankhede@nvidia.com>
Date: Fri, 6 Nov 2020 23:32:24 +0530
Subject: [PATCH] Fix use after free in vfio_migration_probe
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Fixes Coverity issue:
CID 1436126: Memory - illegal accesses (USE_AFTER_FREE)
Fixes: a9e271ec9b36 ("vfio: Add migration region initialization and finalize function")
Signed-off-by: Kirti Wankhede <kwankhede@nvidia.com>
Reviewed-by: David Edmondson <dme@dme.org>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Signed-off-by: Kunkun Jiang <jiangkunkun@huawei.com>
---
hw/vfio/migration.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c
index 1a97784486..8546075706 100644
--- a/hw/vfio/migration.c
+++ b/hw/vfio/migration.c
@@ -903,8 +903,8 @@ int vfio_migration_probe(VFIODevice *vbasedev, Error **errp)
goto add_blocker;
}
- g_free(info);
trace_vfio_migration_probe(vbasedev->name, info->index);
+ g_free(info);
return 0;
add_blocker:
--
2.27.0

View File

@ -1,40 +0,0 @@
From 41077af2c4283c15c0a822017ea51612d15b68f8 Mon Sep 17 00:00:00 2001
From: Andrew Melnychenko <andrew@daynix.com>
Date: Wed, 4 Mar 2020 16:20:58 +0200
Subject: [PATCH 1/5] Fixed integer overflow in e1000e
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1737400
Fixed setting max_queue_num if there are no peers in
NICConf. qemu_new_nic() creates NICState with 1 NetClientState(index
0) without peers, set max_queue_num to 0 - It prevents undefined
behavior and possible crashes, especially during pcie hotplug.
Fixes: 6f3fbe4ed06 ("net: Introduce e1000e device emulation")
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Reviewed-by: Dmitry Fleytman <dmitry.fleytman@gmail.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Zhenyu Ye <yezhenyu2@huawei.com>
---
hw/net/e1000e.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c
index 581f7d03..1e827c4f 100644
--- a/hw/net/e1000e.c
+++ b/hw/net/e1000e.c
@@ -325,7 +325,7 @@ e1000e_init_net_peer(E1000EState *s, PCIDevice *pci_dev, uint8_t *macaddr)
s->nic = qemu_new_nic(&net_e1000e_info, &s->conf,
object_get_typename(OBJECT(s)), dev->id, s);
- s->core.max_queue_num = s->conf.peers.queues - 1;
+ s->core.max_queue_num = s->conf.peers.queues ? s->conf.peers.queues - 1 : 0;
trace_e1000e_mac_set_permanent(MAC_ARG(macaddr));
memcpy(s->core.permanent_mac, macaddr, sizeof(s->core.permanent_mac));
--
2.22.0.windows.1

View File

@ -1,88 +0,0 @@
From 73a5bf472921068e6db10e7e325b7ac46f111834 Mon Sep 17 00:00:00 2001
From: John Snow <jsnow@redhat.com>
Date: Mon, 29 Jul 2019 18:36:05 -0400
Subject: [PATCH] Revert "ide/ahci: Check for -ECANCELED in aio callbacks"
This reverts commit 0d910cfeaf2076b116b4517166d5deb0fea76394.
It's not correct to just ignore an error code in a callback; we need to
handle that error and possible report failure to the guest so that they
don't wait indefinitely for an operation that will now never finish.
This ought to help cases reported by Nutanix where iSCSI returns a
legitimate -ECANCELED for certain operations which should be propagated
normally.
Reported-by: Shaju Abraham <shaju.abraham@nutanix.com>
Signed-off-by: John Snow <jsnow@redhat.com>
Message-id: 20190729223605.7163-1-jsnow@redhat.com
Signed-off-by: John Snow <jsnow@redhat.com>
(cherry picked from commit 8ec41c4265714255d5a138f8b538faf3583dcff6)
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
hw/ide/ahci.c | 3 ---
hw/ide/core.c | 14 --------------
2 files changed, 17 deletions(-)
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 00ba422a48..6aaf66534a 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -1023,9 +1023,6 @@ static void ncq_cb(void *opaque, int ret)
IDEState *ide_state = &ncq_tfs->drive->port.ifs[0];
ncq_tfs->aiocb = NULL;
- if (ret == -ECANCELED) {
- return;
- }
if (ret < 0) {
bool is_read = ncq_tfs->cmd == READ_FPDMA_QUEUED;
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 6afadf894f..8e1624f7ce 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -722,9 +722,6 @@ static void ide_sector_read_cb(void *opaque, int ret)
s->pio_aiocb = NULL;
s->status &= ~BUSY_STAT;
- if (ret == -ECANCELED) {
- return;
- }
if (ret != 0) {
if (ide_handle_rw_error(s, -ret, IDE_RETRY_PIO |
IDE_RETRY_READ)) {
@@ -840,10 +837,6 @@ static void ide_dma_cb(void *opaque, int ret)
uint64_t offset;
bool stay_active = false;
- if (ret == -ECANCELED) {
- return;
- }
-
if (ret == -EINVAL) {
ide_dma_error(s);
return;
@@ -975,10 +968,6 @@ static void ide_sector_write_cb(void *opaque, int ret)
IDEState *s = opaque;
int n;
- if (ret == -ECANCELED) {
- return;
- }
-
s->pio_aiocb = NULL;
s->status &= ~BUSY_STAT;
@@ -1058,9 +1047,6 @@ static void ide_flush_cb(void *opaque, int ret)
s->pio_aiocb = NULL;
- if (ret == -ECANCELED) {
- return;
- }
if (ret < 0) {
/* XXX: What sector number to set here? */
if (ide_handle_rw_error(s, -ret, IDE_RETRY_FLUSH)) {
--
2.23.0

View File

@ -1,37 +0,0 @@
From ced290d644a00e18e70046194d042bcaa2703b65 Mon Sep 17 00:00:00 2001
From: Ying Fang <fangying1@huawei.com>
Date: Wed, 27 May 2020 11:16:53 +0800
Subject: [PATCH] Revert: "vtimer: compat cross version migration from v4.0.1"
This reverts commit patch:
vtimer-compat-cross-version-migration-from-v4.0.1.patch
Signed-off-by: Ying Fang <fangying1@huawei.com>
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 2609113d..86eb79cd 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -261,7 +261,6 @@ typedef struct CPUARMState {
uint64_t elr_el[4]; /* AArch64 exception link regs */
uint64_t sp_el[4]; /* AArch64 banked stack pointers */
- uint64_t vtimer; /* Timer tick when vcpu is stopped */
/* System control coprocessor (cp15) */
struct {
diff --git a/target/arm/machine.c b/target/arm/machine.c
index ec28b839..ee3c59a6 100644
--- a/target/arm/machine.c
+++ b/target/arm/machine.c
@@ -814,7 +814,6 @@ const VMStateDescription vmstate_arm_cpu = {
VMSTATE_UINT32(env.exception.syndrome, ARMCPU),
VMSTATE_UINT32(env.exception.fsr, ARMCPU),
VMSTATE_UINT64(env.exception.vaddress, ARMCPU),
- VMSTATE_UINT64(env.vtimer, ARMCPU),
VMSTATE_TIMER_PTR(gt_timer[GTIMER_PHYS], ARMCPU),
VMSTATE_TIMER_PTR(gt_timer[GTIMER_VIRT], ARMCPU),
{
--
2.23.0

View File

@ -1,27 +0,0 @@
From 843f593280b93e03bb7b0d0001da7488d61f13f6 Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Mon, 6 Apr 2020 08:55:17 +0800
Subject: [PATCH] Typo: Correct the name of CPU hotplug memory region
Replace "acpi-mem-hotplug" with "acpi-cpu-hotplug"
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
---
hw/acpi/cpu.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c
index 7a90c8f82d..0c0bfe479a 100644
--- a/hw/acpi/cpu.c
+++ b/hw/acpi/cpu.c
@@ -203,7 +203,7 @@ void cpu_hotplug_hw_init(MemoryRegion *as, Object *owner,
state->devs[i].arch_id = id_list->cpus[i].arch_id;
}
memory_region_init_io(&state->ctrl_reg, owner, &cpu_hotplug_ops, state,
- "acpi-mem-hotplug", ACPI_CPU_HOTPLUG_REG_LEN);
+ "acpi-cpu-hotplug", ACPI_CPU_HOTPLUG_REG_LEN);
memory_region_add_subregion(as, base_addr, &state->ctrl_reg);
}
--
2.19.1

View File

@ -1,63 +0,0 @@
From 135119d2e82e99adc67346572c761fbe54d73e4a Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Fri, 10 Apr 2020 13:04:40 +0800
Subject: [PATCH] accel/kvm: Add pre-park vCPU support
For that KVM do not support dynamic adjustment of vCPU count,
we must pre-park all possible vCPU at start.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
accel/kvm/kvm-all.c | 23 +++++++++++++++++++++++
include/sysemu/kvm.h | 1 +
2 files changed, 24 insertions(+)
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index f450f25295..84edbe8bb1 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -339,6 +339,29 @@ err:
return ret;
}
+int kvm_create_parked_vcpu(unsigned long vcpu_id)
+{
+ KVMState *s = kvm_state;
+ struct KVMParkedVcpu *vcpu = NULL;
+ int ret;
+
+ DPRINTF("kvm_create_parked_vcpu\n");
+
+ ret = kvm_vm_ioctl(s, KVM_CREATE_VCPU, (void *)vcpu_id);
+ if (ret < 0) {
+ DPRINTF("kvm_create_vcpu failed\n");
+ goto err;
+ }
+
+ vcpu = g_malloc0(sizeof(*vcpu));
+ vcpu->vcpu_id = vcpu_id;
+ vcpu->kvm_fd = ret;
+ QLIST_INSERT_HEAD(&s->kvm_parked_vcpus, vcpu, node);
+
+err:
+ return ret;
+}
+
static int kvm_get_vcpu(KVMState *s, unsigned long vcpu_id)
{
struct KVMParkedVcpu *cpu;
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index acd90aebb6..565adb4e2c 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -216,6 +216,7 @@ int kvm_has_many_ioeventfds(void);
int kvm_has_gsi_routing(void);
int kvm_has_intx_set_mask(void);
+int kvm_create_parked_vcpu(unsigned long vcpu_id);
int kvm_init_vcpu(CPUState *cpu);
int kvm_cpu_exec(CPUState *cpu);
int kvm_destroy_vcpu(CPUState *cpu);
--
2.19.1

View File

@ -1,45 +0,0 @@
From b50b9a0e2e5e8262c830df5994f3abbe0a37655a Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Thu, 17 Dec 2020 09:49:40 +0800
Subject: [PATCH] accel: kvm: Fix memory waste under mismatch page size
When handle dirty log, we face qemu_real_host_page_size and
TARGET_PAGE_SIZE. The first one is the granule of KVM dirty
bitmap, and the second one is the granule of QEMU dirty bitmap.
As qemu_real_host_page_size >= TARGET_PAGE_SIZE (kvm_init()
enforced it), misuse TARGET_PAGE_SIZE to init kvmslot dirty_bmap
may waste memory. For example, when qemu_real_host_page_size is
64K and TARGET_PAGE_SIZE is 4K, it wastes 93.75% (15/16) memory.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Reviewed-by: Andrew Jones <drjones@redhat.com>
Reviewed-by: Peter Xu <peterx@redhat.com>
Message-Id: <20201217014941.22872-2-zhukeqian1@huawei.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kunkun Jiang <jiangkunkun@huawei.com>
---
accel/kvm/kvm-all.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 5a6b89cc2a..4daff563a0 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -551,8 +551,12 @@ static void kvm_memslot_init_dirty_bitmap(KVMSlot *mem)
* too, in most cases).
* So for now, let's align to 64 instead of HOST_LONG_BITS here, in
* a hope that sizeof(long) won't become >8 any time soon.
+ *
+ * Note: the granule of kvm dirty log is qemu_real_host_page_size.
+ * And mem->memory_size is aligned to it (otherwise this mem can't
+ * be registered to KVM).
*/
- hwaddr bitmap_size = ALIGN(((mem->memory_size) >> TARGET_PAGE_BITS),
+ hwaddr bitmap_size = ALIGN(mem->memory_size / qemu_real_host_page_size,
/*HOST_LONG_BITS*/ 64) / 8;
mem->dirty_bmap = g_malloc0(bitmap_size);
}
--
2.27.0

View File

@ -1,128 +0,0 @@
From 107c267ebe5b8c461268a4ff8384ad2f2b9e8ce0 Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Wed, 22 Apr 2020 16:11:13 +0800
Subject: [PATCH] acpi/cpu: Prepare build_cpus_aml for arm virt
We will reuse build_cpus_aml to build DSDT cpus aml in arm/virt
ACPI to realize cpu hotplug. Three points are added.
1. Make ACPI IO address space configurable, because ARM64 platforms
don't use port IO for ACPI IO space.
2. Add GICC struct building support in _MAT of cpu aml.
3. Let the hotplug method parameter can be NULL, because ACPI GED
will realize it.
Besides, CPU CPPC building is injected.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
hw/acpi/cpu.c | 32 +++++++++++++++++++++++++-------
hw/i386/acpi-build.c | 2 +-
include/hw/acpi/cpu.h | 3 ++-
3 files changed, 28 insertions(+), 9 deletions(-)
diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c
index 0c0bfe479a..72ad1fcff2 100644
--- a/hw/acpi/cpu.c
+++ b/hw/acpi/cpu.c
@@ -314,7 +314,8 @@ const VMStateDescription vmstate_cpu_hotplug = {
void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
hwaddr io_base,
const char *res_root,
- const char *event_handler_method)
+ const char *event_handler_method,
+ AmlRegionSpace rs)
{
Aml *ifctx;
Aml *field;
@@ -342,13 +343,18 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
aml_append(cpu_ctrl_dev, aml_mutex(CPU_LOCK, 0));
crs = aml_resource_template();
- aml_append(crs, aml_io(AML_DECODE16, io_base, io_base, 1,
- ACPI_CPU_HOTPLUG_REG_LEN));
+ if (rs == AML_SYSTEM_IO) {
+ aml_append(crs, aml_io(AML_DECODE16, io_base, io_base, 1,
+ ACPI_CPU_HOTPLUG_REG_LEN));
+ } else {
+ aml_append(crs, aml_memory32_fixed(io_base,
+ ACPI_CPU_HOTPLUG_REG_LEN, AML_READ_WRITE));
+ }
aml_append(cpu_ctrl_dev, aml_name_decl("_CRS", crs));
/* declare CPU hotplug MMIO region with related access fields */
aml_append(cpu_ctrl_dev,
- aml_operation_region("PRST", AML_SYSTEM_IO, aml_int(io_base),
+ aml_operation_region("PRST", rs, aml_int(io_base),
ACPI_CPU_HOTPLUG_REG_LEN));
field = aml_field("PRST", AML_BYTE_ACC, AML_NOLOCK,
@@ -517,6 +523,11 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
aml_append(dev, aml_name_decl("_UID", uid));
}
+ assert(adevc);
+ if (adevc->cpu_cppc) {
+ adevc->cpu_cppc(adev, i, arch_ids->len, dev);
+ }
+
method = aml_method("_STA", 0, AML_SERIALIZED);
aml_append(method, aml_return(aml_call1(CPU_STS_METHOD, uid)));
aml_append(dev, method);
@@ -535,6 +546,11 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
apic->flags = cpu_to_le32(1);
break;
}
+ case ACPI_APIC_GENERIC_CPU_INTERFACE: {
+ AcpiMadtGenericCpuInterface *gicc = (void *)madt_buf->data;
+ gicc->flags = cpu_to_le32(1);
+ break;
+ }
default:
assert(0);
}
@@ -570,9 +586,11 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
aml_append(sb_scope, cpus_dev);
aml_append(table, sb_scope);
- method = aml_method(event_handler_method, 0, AML_NOTSERIALIZED);
- aml_append(method, aml_call0("\\_SB.CPUS." CPU_SCAN_METHOD));
- aml_append(table, method);
+ if (event_handler_method) {
+ method = aml_method(event_handler_method, 0, AML_NOTSERIALIZED);
+ aml_append(method, aml_call0("\\_SB.CPUS." CPU_SCAN_METHOD));
+ aml_append(table, method);
+ }
g_free(cphp_res_path);
}
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 749218561a..c97731ecb3 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -1869,7 +1869,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
.acpi_1_compatible = true, .has_legacy_cphp = true
};
build_cpus_aml(dsdt, machine, opts, pm->cpu_hp_io_base,
- "\\_SB.PCI0", "\\_GPE._E02");
+ "\\_SB.PCI0", "\\_GPE._E02", AML_SYSTEM_IO);
}
if (pcms->memhp_io_base && nr_mem) {
diff --git a/include/hw/acpi/cpu.h b/include/hw/acpi/cpu.h
index 62f0278ba2..a30ec84a4f 100644
--- a/include/hw/acpi/cpu.h
+++ b/include/hw/acpi/cpu.h
@@ -55,7 +55,8 @@ typedef struct CPUHotplugFeatures {
void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
hwaddr io_base,
const char *res_root,
- const char *event_handler_method);
+ const char *event_handler_method,
+ AmlRegionSpace rs);
void acpi_cpu_ospm_status(CPUHotplugState *cpu_st, ACPIOSTInfoList ***list);
--
2.19.1

View File

@ -1,41 +0,0 @@
From 3cd6df0b9e7d7b544673ce9a63b405e236d8265b Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Fri, 10 Apr 2020 10:05:54 +0800
Subject: [PATCH] acpi/ged: Add virt_madt_cpu_entry to madt_cpu hook
In build_cpus_aml, we will invoke this hook to build _MAT
aml mehtod for cpus.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
hw/acpi/generic_event_device.c | 1 +
include/hw/acpi/generic_event_device.h | 1 +
2 files changed, 2 insertions(+)
diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c
index 9cee90cc70..b834ae3ff6 100644
--- a/hw/acpi/generic_event_device.c
+++ b/hw/acpi/generic_event_device.c
@@ -288,6 +288,7 @@ static void acpi_ged_class_init(ObjectClass *class, void *data)
hc->plug = acpi_ged_device_plug_cb;
adevc->send_event = acpi_ged_send_event;
+ adevc->madt_cpu = virt_madt_cpu_entry;
}
static const TypeInfo acpi_ged_info = {
diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h
index d157eac088..f99efad7a3 100644
--- a/include/hw/acpi/generic_event_device.h
+++ b/include/hw/acpi/generic_event_device.h
@@ -61,6 +61,7 @@
#include "hw/sysbus.h"
#include "hw/acpi/memory_hotplug.h"
+#include "hw/arm/virt.h"
#define ACPI_POWER_BUTTON_DEVICE "PWRB"
--
2.19.1

View File

@ -1,204 +0,0 @@
From 05d22b55133db1a2526cfe305102e075e883b5e2 Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Fri, 3 Apr 2020 15:41:01 +0800
Subject: [PATCH] acpi/ged: Extend ACPI GED to support CPU hotplug
This adds a new GED event called ACPI_GED_CPU_HOTPLUG_EVT.
The basic workflow is that: GED sends this event to guest,
then ACPI driver in guest will call _EVT method of GED aml,
then _EVT will call CSCN method in cpus aml to get status of
all cpus.
The status of cpus is maintained by CPUHotplugState in GED and
is made accessable to guest through memory region.
This also adds migration support to CPUHotplugState.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
docs/specs/acpi_hw_reduced_hotplug.rst | 3 ++-
hw/acpi/cpu.c | 1 -
hw/acpi/generic_event_device.c | 35 ++++++++++++++++++++++++++
hw/arm/Kconfig | 1 +
include/hw/acpi/cpu.h | 2 ++
include/hw/acpi/generic_event_device.h | 4 +++
6 files changed, 44 insertions(+), 2 deletions(-)
diff --git a/docs/specs/acpi_hw_reduced_hotplug.rst b/docs/specs/acpi_hw_reduced_hotplug.rst
index 911a98255b..deb481555d 100644
--- a/docs/specs/acpi_hw_reduced_hotplug.rst
+++ b/docs/specs/acpi_hw_reduced_hotplug.rst
@@ -63,7 +63,8 @@ GED IO interface (4 byte access)
bits:
0: Memory hotplug event
1: System power down event
- 2-31: Reserved
+ 2: CPU hotplug event
+ 3-31: Reserved
**write_access:**
diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c
index 72ad1fcff2..cb6bb67f3c 100644
--- a/hw/acpi/cpu.c
+++ b/hw/acpi/cpu.c
@@ -6,7 +6,6 @@
#include "trace.h"
#include "sysemu/numa.h"
-#define ACPI_CPU_HOTPLUG_REG_LEN 12
#define ACPI_CPU_SELECTOR_OFFSET_WR 0
#define ACPI_CPU_FLAGS_OFFSET_RW 4
#define ACPI_CPU_CMD_OFFSET_WR 5
diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c
index 82139b4314..478a4ee87c 100644
--- a/hw/acpi/generic_event_device.c
+++ b/hw/acpi/generic_event_device.c
@@ -23,6 +23,7 @@
static const uint32_t ged_supported_events[] = {
ACPI_GED_MEM_HOTPLUG_EVT,
ACPI_GED_PWR_DOWN_EVT,
+ ACPI_GED_CPU_HOTPLUG_EVT,
};
/*
@@ -110,6 +111,9 @@ void build_ged_aml(Aml *table, const char *name, HotplugHandler *hotplug_dev,
aml_notify(aml_name(ACPI_POWER_BUTTON_DEVICE),
aml_int(0x80)));
break;
+ case ACPI_GED_CPU_HOTPLUG_EVT:
+ aml_append(if_ctx, aml_call0("\\_SB.CPUS.CSCN"));
+ break;
default:
/*
* Please make sure all the events in ged_supported_events[]
@@ -176,6 +180,8 @@ static void acpi_ged_device_plug_cb(HotplugHandler *hotplug_dev,
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
acpi_memory_plug_cb(hotplug_dev, &s->memhp_state, dev, errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
+ acpi_cpu_plug_cb(hotplug_dev, &s->cpuhp_state, dev, errp);
} else {
error_setg(errp, "virt: device plug request for unsupported device"
" type: %s", object_get_typename(OBJECT(dev)));
@@ -192,6 +198,8 @@ static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev)
sel = ACPI_GED_MEM_HOTPLUG_EVT;
} else if (ev & ACPI_POWER_DOWN_STATUS) {
sel = ACPI_GED_PWR_DOWN_EVT;
+ } else if (ev & ACPI_CPU_HOTPLUG_STATUS) {
+ sel = ACPI_GED_CPU_HOTPLUG_EVT;
} else {
/* Unknown event. Return without generating interrupt. */
warn_report("GED: Unsupported event %d. No irq injected", ev);
@@ -224,6 +232,16 @@ static const VMStateDescription vmstate_memhp_state = {
}
};
+static const VMStateDescription vmstate_cpuhp_state = {
+ .name = "acpi-ged/cpuhp",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_CPU_HOTPLUG(cpuhp_state, AcpiGedState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_ged_state = {
.name = "acpi-ged-state",
.version_id = 1,
@@ -244,6 +262,7 @@ static const VMStateDescription vmstate_acpi_ged = {
},
.subsections = (const VMStateDescription * []) {
&vmstate_memhp_state,
+ &vmstate_cpuhp_state,
NULL
}
};
@@ -254,6 +273,7 @@ static void acpi_ged_initfn(Object *obj)
AcpiGedState *s = ACPI_GED(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
GEDState *ged_st = &s->ged_state;
+ MachineClass *mc;
memory_region_init_io(&ged_st->io, obj, &ged_ops, ged_st,
TYPE_ACPI_GED, ACPI_GED_EVT_SEL_LEN);
@@ -273,6 +293,21 @@ static void acpi_ged_initfn(Object *obj)
sysbus_init_mmio(sbd, &s->container_memhp);
acpi_memory_hotplug_init(&s->container_memhp, OBJECT(dev),
&s->memhp_state, 0);
+
+ mc = MACHINE_GET_CLASS(qdev_get_machine());
+ if (!mc->possible_cpu_arch_ids) {
+ /*
+ * MachineClass should support possible_cpu_arch_ids in
+ * cpu_hotplug_hw_init below.
+ */
+ return;
+ }
+
+ memory_region_init(&s->container_cpuhp, OBJECT(dev), "cpuhp container",
+ ACPI_CPU_HOTPLUG_REG_LEN);
+ sysbus_init_mmio(sbd, &s->container_cpuhp);
+ cpu_hotplug_hw_init(&s->container_cpuhp, OBJECT(dev),
+ &s->cpuhp_state, 0);
}
static void acpi_ged_class_init(ObjectClass *class, void *data)
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index ad7f7c089b..15e18b0a48 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -24,6 +24,7 @@ config ARM_VIRT
select DIMM
select ACPI_MEMORY_HOTPLUG
select ACPI_HW_REDUCED
+ select ACPI_CPU_HOTPLUG
config CHEETAH
bool
diff --git a/include/hw/acpi/cpu.h b/include/hw/acpi/cpu.h
index a30ec84a4f..e726414459 100644
--- a/include/hw/acpi/cpu.h
+++ b/include/hw/acpi/cpu.h
@@ -17,6 +17,8 @@
#include "hw/acpi/aml-build.h"
#include "hw/hotplug.h"
+#define ACPI_CPU_HOTPLUG_REG_LEN 12
+
typedef struct AcpiCpuStatus {
struct CPUState *cpu;
uint64_t arch_id;
diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h
index f99efad7a3..e702ff1e18 100644
--- a/include/hw/acpi/generic_event_device.h
+++ b/include/hw/acpi/generic_event_device.h
@@ -62,6 +62,7 @@
#include "hw/sysbus.h"
#include "hw/acpi/memory_hotplug.h"
#include "hw/arm/virt.h"
+#include "hw/acpi/cpu.h"
#define ACPI_POWER_BUTTON_DEVICE "PWRB"
@@ -83,6 +84,7 @@
*/
#define ACPI_GED_MEM_HOTPLUG_EVT 0x1
#define ACPI_GED_PWR_DOWN_EVT 0x2
+#define ACPI_GED_CPU_HOTPLUG_EVT 0x4
typedef struct GEDState {
MemoryRegion io;
@@ -93,6 +95,8 @@ typedef struct AcpiGedState {
SysBusDevice parent_obj;
MemHotplugState memhp_state;
MemoryRegion container_memhp;
+ CPUHotplugState cpuhp_state;
+ MemoryRegion container_cpuhp;
GEDState ged_state;
uint32_t ged_event_bitmap;
qemu_irq irq;
--
2.19.1

View File

@ -1,95 +0,0 @@
From 0288d98f0ef4d17a73cf2bad1b928cd7c044e318 Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Fri, 10 Apr 2020 13:40:44 +0800
Subject: [PATCH] acpi/madt: Add pre-sizing capability to MADT GICC struct
The count of possible CPUs is exposed to guest through the count
of MADT GICC struct, so we should pre-sizing MADT GICC too.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
hw/arm/virt-acpi-build.c | 26 +++++++++++++++++++++-----
include/hw/acpi/acpi-defs.h | 1 +
2 files changed, 22 insertions(+), 5 deletions(-)
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index dbe9acb148..efac788ba1 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -678,6 +678,13 @@ void virt_madt_cpu_entry(AcpiDeviceIf *adev, int uid,
const MemMapEntry *memmap = vms->memmap;
AcpiMadtGenericCpuInterface *gicc = acpi_data_push(entry, sizeof(*gicc));
ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(uid));
+ static bool pmu;
+
+ if (uid == 0) {
+ pmu = arm_feature(&armcpu->env, ARM_FEATURE_PMU);
+ }
+ /* FEATURE_PMU should be all enabled or disabled for CPUs */
+ assert(!armcpu || arm_feature(&armcpu->env, ARM_FEATURE_PMU) == pmu);
gicc->type = ACPI_APIC_GENERIC_CPU_INTERFACE;
gicc->length = sizeof(*gicc);
@@ -687,11 +694,15 @@ void virt_madt_cpu_entry(AcpiDeviceIf *adev, int uid,
gicc->gicv_base_address = cpu_to_le64(memmap[VIRT_GIC_VCPU].base);
}
gicc->cpu_interface_number = cpu_to_le32(uid);
- gicc->arm_mpidr = cpu_to_le64(armcpu->mp_affinity);
+ gicc->arm_mpidr = possible_cpus->cpus[uid].arch_id;
gicc->uid = cpu_to_le32(uid);
- gicc->flags = cpu_to_le32(ACPI_MADT_GICC_ENABLED);
+ if (armcpu) {
+ gicc->flags = cpu_to_le32(ACPI_MADT_GICC_ENABLED);
+ } else {
+ gicc->flags = cpu_to_le32(ACPI_MADT_GICC_DISABLED);
+ }
- if (arm_feature(&armcpu->env, ARM_FEATURE_PMU)) {
+ if (pmu) {
gicc->performance_interrupt = cpu_to_le32(PPI(VIRTUAL_PMU_IRQ));
}
if (vms->virt) {
@@ -704,12 +715,17 @@ static void
build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
{
VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
+ MachineClass *mc = MACHINE_GET_CLASS(vms);
+ MachineState *ms = MACHINE(vms);
+ const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms);
int madt_start = table_data->len;
const MemMapEntry *memmap = vms->memmap;
const int *irqmap = vms->irqmap;
AcpiMultipleApicTable *madt;
AcpiMadtGenericDistributor *gicd;
AcpiMadtGenericMsiFrame *gic_msi;
+ /* The MADT GICC numbers */
+ int num_cpu = vms->smp_cpus;
int i;
madt = acpi_data_push(table_data, sizeof *madt);
@@ -720,8 +736,8 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
gicd->base_address = cpu_to_le64(memmap[VIRT_GIC_DIST].base);
gicd->version = vms->gic_version;
- for (i = 0; i < vms->smp_cpus; i++) {
- virt_madt_cpu_entry(NULL, i, NULL, table_data);
+ for (i = 0; i < num_cpu; i++) {
+ virt_madt_cpu_entry(NULL, i, possible_cpus, table_data);
}
if (vms->gic_version == 3) {
diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h
index 39ae91d3b8..6bfa7f9152 100644
--- a/include/hw/acpi/acpi-defs.h
+++ b/include/hw/acpi/acpi-defs.h
@@ -306,6 +306,7 @@ typedef struct AcpiMadtGenericCpuInterface AcpiMadtGenericCpuInterface;
/* GICC CPU Interface Flags */
#define ACPI_MADT_GICC_ENABLED 1
+#define ACPI_MADT_GICC_DISABLED 0
struct AcpiMadtGenericDistributor {
ACPI_SUB_HEADER_DEF
--
2.19.1

View File

@ -1,108 +0,0 @@
From a3097eed8b642dc6fe891112340821e869b90cc2 Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Mon, 13 Jan 2020 19:02:20 +0800
Subject: [PATCH] acpi/madt: Factor out the building of MADT GICC struct
To realize CPU hotplug, the cpus aml within ACPI DSDT should contain
_MAT mathod, which is equal to the GICC struct in ACPI MADT. Factor
out the GICC building code from ACPI MADT and reuse it in build_cpus_aml.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
hw/arm/virt-acpi-build.c | 51 +++++++++++++++++++++++-----------------
include/hw/arm/virt.h | 3 +++
2 files changed, 32 insertions(+), 22 deletions(-)
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index f48733d9f2..4b6aace433 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -664,6 +664,34 @@ build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
table_data->len - gtdt_start, 2, NULL, NULL);
}
+void virt_madt_cpu_entry(AcpiDeviceIf *adev, int uid,
+ const CPUArchIdList *possible_cpus, GArray *entry)
+{
+ VirtMachineState *vms = VIRT_MACHINE(qdev_get_machine());
+ const MemMapEntry *memmap = vms->memmap;
+ AcpiMadtGenericCpuInterface *gicc = acpi_data_push(entry, sizeof(*gicc));
+ ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(uid));
+
+ gicc->type = ACPI_APIC_GENERIC_CPU_INTERFACE;
+ gicc->length = sizeof(*gicc);
+ if (vms->gic_version == 2) {
+ gicc->base_address = cpu_to_le64(memmap[VIRT_GIC_CPU].base);
+ gicc->gich_base_address = cpu_to_le64(memmap[VIRT_GIC_HYP].base);
+ gicc->gicv_base_address = cpu_to_le64(memmap[VIRT_GIC_VCPU].base);
+ }
+ gicc->cpu_interface_number = cpu_to_le32(uid);
+ gicc->arm_mpidr = cpu_to_le64(armcpu->mp_affinity);
+ gicc->uid = cpu_to_le32(uid);
+ gicc->flags = cpu_to_le32(ACPI_MADT_GICC_ENABLED);
+
+ if (arm_feature(&armcpu->env, ARM_FEATURE_PMU)) {
+ gicc->performance_interrupt = cpu_to_le32(PPI(VIRTUAL_PMU_IRQ));
+ }
+ if (vms->virt) {
+ gicc->vgic_interrupt = cpu_to_le32(PPI(ARCH_GIC_MAINT_IRQ));
+ }
+}
+
/* MADT */
static void
build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
@@ -686,28 +714,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
gicd->version = vms->gic_version;
for (i = 0; i < vms->smp_cpus; i++) {
- AcpiMadtGenericCpuInterface *gicc = acpi_data_push(table_data,
- sizeof(*gicc));
- ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(i));
-
- gicc->type = ACPI_APIC_GENERIC_CPU_INTERFACE;
- gicc->length = sizeof(*gicc);
- if (vms->gic_version == 2) {
- gicc->base_address = cpu_to_le64(memmap[VIRT_GIC_CPU].base);
- gicc->gich_base_address = cpu_to_le64(memmap[VIRT_GIC_HYP].base);
- gicc->gicv_base_address = cpu_to_le64(memmap[VIRT_GIC_VCPU].base);
- }
- gicc->cpu_interface_number = cpu_to_le32(i);
- gicc->arm_mpidr = cpu_to_le64(armcpu->mp_affinity);
- gicc->uid = cpu_to_le32(i);
- gicc->flags = cpu_to_le32(ACPI_MADT_GICC_ENABLED);
-
- if (arm_feature(&armcpu->env, ARM_FEATURE_PMU)) {
- gicc->performance_interrupt = cpu_to_le32(PPI(VIRTUAL_PMU_IRQ));
- }
- if (vms->virt) {
- gicc->vgic_interrupt = cpu_to_le32(PPI(ARCH_GIC_MAINT_IRQ));
- }
+ virt_madt_cpu_entry(NULL, i, NULL, table_data);
}
if (vms->gic_version == 3) {
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index 3dfefca93b..6b1f10b231 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -37,6 +37,7 @@
#include "hw/block/flash.h"
#include "sysemu/kvm.h"
#include "hw/intc/arm_gicv3_common.h"
+#include "hw/acpi/acpi_dev_interface.h"
#define NUM_GICV2M_SPIS 64
#define NUM_VIRTIO_TRANSPORTS 32
@@ -154,6 +155,8 @@ typedef struct {
OBJECT_CLASS_CHECK(VirtMachineClass, klass, TYPE_VIRT_MACHINE)
void virt_acpi_setup(VirtMachineState *vms);
+void virt_madt_cpu_entry(AcpiDeviceIf *adev, int uid,
+ const CPUArchIdList *cpu_list, GArray *entry);
/* Return the number of used redistributor regions */
static inline int virt_gicv3_redist_region_count(VirtMachineState *vms)
--
2.19.1

View File

@ -1,73 +0,0 @@
From ea7a395de920cfecd9bf99f0cf55914d47718edf Mon Sep 17 00:00:00 2001
From: Jiadong Zeng <zengjiadong@phytium.com.cn>
Date: Thu, 11 Nov 2021 14:25:38 +0800
Subject: [PATCH] add Phytium's CPU models: FT-2000+ and Tengyun-S2500.
Signed-off-by: Jiadong Zeng <zengjiadong@phytium.com.cn>
---
hw/arm/virt.c | 2 ++
target/arm/cpu64.c | 28 ++++++++++++++++++++++++++++
2 files changed, 30 insertions(+)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 7506d0ff32..0e46260116 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -195,6 +195,8 @@ static const char *valid_cpus[] = {
ARM_CPU_TYPE_NAME("cortex-a57"),
ARM_CPU_TYPE_NAME("cortex-a72"),
ARM_CPU_TYPE_NAME("Kunpeng-920"),
+ ARM_CPU_TYPE_NAME("FT-2000+"),
+ ARM_CPU_TYPE_NAME("Tengyun-S2500"),
ARM_CPU_TYPE_NAME("host"),
ARM_CPU_TYPE_NAME("max"),
};
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index a1649f8844..4cf5b89db0 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -327,6 +327,32 @@ static void cpu_max_set_sve_vq(Object *obj, Visitor *v, const char *name,
error_propagate(errp, err);
}
+static void aarch64_max_ft2000plus_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+
+ if (kvm_enabled()) {
+ kvm_arm_set_cpu_features_from_host(cpu);
+ kvm_arm_add_vcpu_properties(obj);
+ } else {
+ aarch64_a72_initfn(obj);
+ cpu->midr = 0x70186622;
+ }
+}
+
+static void aarch64_max_tengyun_s2500_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+
+ if (kvm_enabled()) {
+ kvm_arm_set_cpu_features_from_host(cpu);
+ kvm_arm_add_vcpu_properties(obj);
+ } else {
+ aarch64_a72_initfn(obj);
+ cpu->midr = 0x70186632;
+ }
+}
+
/* -cpu max: if KVM is enabled, like -cpu host (best possible with this host);
* otherwise, a CPU with as many features enabled as our emulation supports.
* The version of '-cpu max' for qemu-system-arm is defined in cpu.c;
@@ -442,6 +468,8 @@ static const ARMCPUInfo aarch64_cpus[] = {
{ .name = "cortex-a53", .initfn = aarch64_a53_initfn },
{ .name = "cortex-a72", .initfn = aarch64_a72_initfn },
{ .name = "Kunpeng-920", .initfn = aarch64_kunpeng_920_initfn },
+ { .name = "FT-2000+", .initfn = aarch64_max_ft2000plus_initfn },
+ { .name = "Tengyun-S2500", .initfn = aarch64_max_tengyun_s2500_initfn },
{ .name = "max", .initfn = aarch64_max_initfn },
{ .name = NULL }
};
--
2.27.0

View File

@ -1,116 +0,0 @@
From 929d29ec7bf9dd6ec3802bea2148a041ff30d59b Mon Sep 17 00:00:00 2001
From: Paolo Bonzini <pbonzini@redhat.com>
Date: Tue, 14 Apr 2020 21:17:09 +0800
Subject: [PATCH] aio-wait: delegate polling of main AioContext if BQL not held
Any thread that is not a iothread returns NULL for qemu_get_current_aio_context().
As a result, it would also return true for
in_aio_context_home_thread(qemu_get_aio_context()), causing
AIO_WAIT_WHILE to invoke aio_poll() directly. This is incorrect
if the BQL is not held, because aio_poll() does not expect to
run concurrently from multiple threads, and it can actually
happen when savevm writes to the vmstate file from the
migration thread.
Therefore, restrict in_aio_context_home_thread to return true
for the main AioContext only if the BQL is held.
The function is moved to aio-wait.h because it is mostly used
there and to avoid a circular reference between main-loop.h
and block/aio.h.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20200407140746.8041-5-pbonzini@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
include/block/aio-wait.h | 22 ++++++++++++++++++++++
include/block/aio.h | 29 ++++++++++-------------------
2 files changed, 32 insertions(+), 19 deletions(-)
diff --git a/include/block/aio-wait.h b/include/block/aio-wait.h
index afeeb18f..716d2639 100644
--- a/include/block/aio-wait.h
+++ b/include/block/aio-wait.h
@@ -26,6 +26,7 @@
#define QEMU_AIO_WAIT_H
#include "block/aio.h"
+#include "qemu/main-loop.h"
/**
* AioWait:
@@ -124,4 +125,25 @@ void aio_wait_kick(void);
*/
void aio_wait_bh_oneshot(AioContext *ctx, QEMUBHFunc *cb, void *opaque);
+/**
+ * in_aio_context_home_thread:
+ * @ctx: the aio context
+ *
+ * Return whether we are running in the thread that normally runs @ctx. Note
+ * that acquiring/releasing ctx does not affect the outcome, each AioContext
+ * still only has one home thread that is responsible for running it.
+ */
+static inline bool in_aio_context_home_thread(AioContext *ctx)
+{
+ if (ctx == qemu_get_current_aio_context()) {
+ return true;
+ }
+
+ if (ctx == qemu_get_aio_context()) {
+ return qemu_mutex_iothread_locked();
+ } else {
+ return false;
+ }
+}
+
#endif /* QEMU_AIO_WAIT_H */
diff --git a/include/block/aio.h b/include/block/aio.h
index 6b0d52f7..9d28e247 100644
--- a/include/block/aio.h
+++ b/include/block/aio.h
@@ -60,12 +60,16 @@ struct AioContext {
QLIST_HEAD(, AioHandler) aio_handlers;
/* Used to avoid unnecessary event_notifier_set calls in aio_notify;
- * accessed with atomic primitives. If this field is 0, everything
- * (file descriptors, bottom halves, timers) will be re-evaluated
- * before the next blocking poll(), thus the event_notifier_set call
- * can be skipped. If it is non-zero, you may need to wake up a
- * concurrent aio_poll or the glib main event loop, making
- * event_notifier_set necessary.
+ * only written from the AioContext home thread, or under the BQL in
+ * the case of the main AioContext. However, it is read from any
+ * thread so it is still accessed with atomic primitives.
+ *
+ * If this field is 0, everything (file descriptors, bottom halves,
+ * timers) will be re-evaluated before the next blocking poll() or
+ * io_uring wait; therefore, the event_notifier_set call can be
+ * skipped. If it is non-zero, you may need to wake up a concurrent
+ * aio_poll or the glib main event loop, making event_notifier_set
+ * necessary.
*
* Bit 0 is reserved for GSource usage of the AioContext, and is 1
* between a call to aio_ctx_prepare and the next call to aio_ctx_check.
@@ -580,19 +584,6 @@ void aio_co_enter(AioContext *ctx, struct Coroutine *co);
*/
AioContext *qemu_get_current_aio_context(void);
-/**
- * in_aio_context_home_thread:
- * @ctx: the aio context
- *
- * Return whether we are running in the thread that normally runs @ctx. Note
- * that acquiring/releasing ctx does not affect the outcome, each AioContext
- * still only has one home thread that is responsible for running it.
- */
-static inline bool in_aio_context_home_thread(AioContext *ctx)
-{
- return ctx == qemu_get_current_aio_context();
-}
-
/**
* aio_context_setup:
* @ctx: the aio context
--
2.23.0

View File

@ -1,50 +0,0 @@
From 3bdd21c4b7d80cacc6b5f1b26ab52ef3a0aceb06 Mon Sep 17 00:00:00 2001
From: Peter Xu <peterx@redhat.com>
Date: Wed, 16 Oct 2019 10:29:32 +0800
Subject: [PATCH 7/8] apic: Use 32bit APIC ID for migration instance ID
Migration is silently broken now with x2apic config like this:
-smp 200,maxcpus=288,sockets=2,cores=72,threads=2 \
-device intel-iommu,intremap=on,eim=on
After migration, the guest kernel could hang at anything, due to
x2apic bit not migrated correctly in IA32_APIC_BASE on some vcpus, so
any operations related to x2apic could be broken then (e.g., RDMSR on
x2apic MSRs could fail because KVM would think that the vcpu hasn't
enabled x2apic at all).
The issue is that the x2apic bit was never applied correctly for vcpus
whose ID > 255 when migrate completes, and that's because when we
migrate APIC we use the APICCommonState.id as instance ID of the
migration stream, while that's too short for x2apic.
Let's use the newly introduced initial_apic_id for that.
Signed-off-by: Peter Xu <peterx@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Reviewed-by: Eduardo Habkost <ehabkost@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
---
hw/intc/apic_common.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c
index 07adba0..2c0cb1e 100644
--- a/hw/intc/apic_common.c
+++ b/hw/intc/apic_common.c
@@ -313,7 +313,10 @@ static void apic_common_realize(DeviceState *dev, Error **errp)
APICCommonState *s = APIC_COMMON(dev);
APICCommonClass *info;
static DeviceState *vapic;
- uint32_t instance_id = s->id;
+ uint32_t instance_id = s->initial_apic_id;
+
+ /* Normally initial APIC ID should be no more than hundreds */
+ assert(instance_id != VMSTATE_INSTANCE_ID_ANY);
info = APIC_COMMON_GET_CLASS(s);
info->realize(dev, errp);
--
1.8.3.1

View File

@ -1,68 +0,0 @@
From 6d795b30ff09bc1f799daa454f776d682cc77197 Mon Sep 17 00:00:00 2001
From: zhanghao1 <zhanghao1@kylinos.cn>
Date: Tue, 11 May 2021 20:17:16 +0800
Subject: [PATCH] arm/cpu: Fixed function undefined error at compile time under
arm
Add the compilation option CONFIG_KVM while using
"kvm_arm_cpu_feature_supported" and "kvm_arm_get_one_reg".
In arm, the default value of CONFIG_KVM is no.
While the target is arm, the compilation fails because
the function "kvm_arm_cpu_feature_supporte" is declared
or the function "kvm_arm_get_one_reg" is not defined.
Signed-off-by: zhanghao1 <zhanghao1@kylinos.cn>
---
target/arm/helper.c | 4 ++++
target/arm/kvm_arm.h | 4 ++++
2 files changed, 8 insertions(+)
diff --git a/target/arm/helper.c b/target/arm/helper.c
index bddd355fa0..9d2b2659f6 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -284,6 +284,7 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync)
newval = read_raw_cp_reg(&cpu->env, ri);
if (kvm_sync) {
+#ifdef CONFIG_KVM
if (is_id_reg(ri)) {
/* Only sync if we can sync to KVM successfully. */
uint64_t oldval;
@@ -306,6 +307,7 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync)
kvm_arm_set_one_reg(cpu, cpu->cpreg_indexes[i], &oldval);
} else {
+#endif
/*
* Only sync if the previous list->cpustate sync succeeded.
* Rather than tracking the success/failure state for every
@@ -324,7 +326,9 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync)
}
write_raw_cp_reg(&cpu->env, ri, newval);
+#ifdef CONFIG_KVM
}
+#endif
}
cpu->cpreg_values[i] = newval;
}
diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
index 49e80878f4..a223967d4d 100644
--- a/target/arm/kvm_arm.h
+++ b/target/arm/kvm_arm.h
@@ -312,6 +312,10 @@ static inline void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu)
static inline void kvm_arm_add_vcpu_properties(Object *obj) {}
+static inline bool kvm_arm_cpu_feature_supported(void) {
+ return false;
+}
+
static inline int kvm_arm_get_max_vm_ipa_size(MachineState *ms)
{
return -ENOENT;
--
2.27.0

View File

@ -1,42 +0,0 @@
From d8e0b51447d8c64788cd7f9b0fa75c4ccb06f8eb Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Fri, 10 Apr 2020 10:17:27 +0800
Subject: [PATCH] arm/cpu: assign arm_get_arch_id handler to get_arch_id hook
This hook will be called in get_cpu_status, which is called
during cpu hotplug.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
target/arm/cpu.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 39bbe7e2d7..1ccb30e5eb 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -2575,6 +2575,13 @@ static gchar *arm_gdb_arch_name(CPUState *cs)
return g_strdup("arm");
}
+static int64_t arm_cpu_get_arch_id(CPUState *cs)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+
+ return cpu->mp_affinity;
+}
+
static void arm_cpu_class_init(ObjectClass *oc, void *data)
{
ARMCPUClass *acc = ARM_CPU_CLASS(oc);
@@ -2596,6 +2603,7 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
cc->synchronize_from_tb = arm_cpu_synchronize_from_tb;
cc->gdb_read_register = arm_cpu_gdb_read_register;
cc->gdb_write_register = arm_cpu_gdb_write_register;
+ cc->get_arch_id = arm_cpu_get_arch_id;
#ifndef CONFIG_USER_ONLY
cc->do_interrupt = arm_cpu_do_interrupt;
cc->get_phys_page_attrs_debug = arm_cpu_get_phys_page_attrs_debug;
--
2.19.1

View File

@ -1,36 +0,0 @@
From b4bab3bf6a75d97d2f1098c4dc52d35ced003c70 Mon Sep 17 00:00:00 2001
From: Pan Nengyuan <pannengyuan@huawei.com>
Date: Mon, 13 Jan 2020 17:01:11 +0800
Subject: [PATCH] arm/translate-a64: fix uninitialized variable warning
Fixes:
target/arm/translate-a64.c: In function 'disas_crypto_three_reg_sha512':
target/arm/translate-a64.c:13625:9: error: 'genfn' may be used uninitialized in this function [-Werror=maybe-uninitialized]
genfn(tcg_rd_ptr, tcg_rn_ptr, tcg_rm_ptr);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
qemu/target/arm/translate-a64.c:13609:8: error: 'feature' may be used uninitialized in this function [-Werror=maybe-uninitialized]
if (!feature) {
Reported-by: Euler Robot <euler.robot@huawei.com>
Signed-off-by: Pan Nengyuan <pannengyuan@huawei.com>
---
target/arm/translate-a64.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index dcdeb801..5f423d5d 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -13767,6 +13767,8 @@ static void disas_crypto_three_reg_sha512(DisasContext *s, uint32_t insn)
feature = dc_isar_feature(aa64_sha3, s);
genfn = NULL;
break;
+ default:
+ g_assert_not_reached();
}
} else {
switch (opcode) {
--
2.18.1

View File

@ -1,66 +0,0 @@
From 6d287b3f1d961cc4adda1c6a452f41db84466f5a Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Fri, 3 Apr 2020 16:16:18 +0800
Subject: [PATCH] arm/virt: Add CPU hotplug framework
Establish the CPU hotplug framework for arm/virt, we will add
necessary code legs to this framework gradually to realize CPU
hotplug finally.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
hw/arm/virt.c | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index d09a5773df..0bd37af26c 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -2077,11 +2077,25 @@ out:
error_propagate(errp, local_err);
}
+static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ /* Currently nothing to do */
+}
+
+static void virt_cpu_plug(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ /* Currently nothing to do */
+}
+
static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
virt_memory_pre_plug(hotplug_dev, dev, errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
+ virt_cpu_pre_plug(hotplug_dev, dev, errp);
}
}
@@ -2098,6 +2112,8 @@ static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev,
}
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
virt_memory_plug(hotplug_dev, dev, errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
+ virt_cpu_plug(hotplug_dev, dev, errp);
}
}
@@ -2112,7 +2128,8 @@ static HotplugHandler *virt_machine_get_hotplug_handler(MachineState *machine,
DeviceState *dev)
{
if (object_dynamic_cast(OBJECT(dev), TYPE_SYS_BUS_DEVICE) ||
- (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM))) {
+ object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) ||
+ object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
return HOTPLUG_HANDLER(machine);
}
--
2.19.1

View File

@ -1,219 +0,0 @@
From cde57fcae2ed16a10e1ef7f2da0ec368883988ba Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Mon, 6 Apr 2020 10:54:35 +0800
Subject: [PATCH] arm/virt: Add CPU topology support
The CPU topology specified by user (through -smp options) is used in
ACPI PPTT. Now we will use this information to locate which CPU to
plug or unplug.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
hw/arm/virt.c | 68 +++++++++++++++++++++++++++++++++++++--
include/hw/arm/topology.h | 61 +++++++++++++++++++++++++++++++++++
target/arm/cpu.c | 3 ++
target/arm/cpu.h | 3 ++
4 files changed, 133 insertions(+), 2 deletions(-)
create mode 100644 include/hw/arm/topology.h
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 0bd37af26c..64532b61b2 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -36,6 +36,7 @@
#include "hw/sysbus.h"
#include "hw/arm/boot.h"
#include "hw/arm/primecell.h"
+#include "hw/arm/topology.h"
#include "hw/arm/virt.h"
#include "hw/block/flash.h"
#include "hw/vfio/vfio-calxeda-xgmac.h"
@@ -2020,6 +2021,7 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms)
int n;
unsigned int max_cpus = ms->smp.max_cpus;
VirtMachineState *vms = VIRT_MACHINE(ms);
+ ARMCPUTopoInfo topo;
if (ms->possible_cpus) {
assert(ms->possible_cpus->len == max_cpus);
@@ -2031,10 +2033,17 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms)
ms->possible_cpus->len = max_cpus;
for (n = 0; n < ms->possible_cpus->len; n++) {
ms->possible_cpus->cpus[n].type = ms->cpu_type;
+ ms->possible_cpus->cpus[n].vcpus_count = 1;
ms->possible_cpus->cpus[n].arch_id =
virt_cpu_mp_affinity(vms, n);
+
+ topo_ids_from_idx(n, ms->smp.cores, ms->smp.threads, &topo);
+ ms->possible_cpus->cpus[n].props.has_socket_id = true;
+ ms->possible_cpus->cpus[n].props.socket_id = topo.pkg_id;
+ ms->possible_cpus->cpus[n].props.has_core_id = true;
+ ms->possible_cpus->cpus[n].props.core_id = topo.core_id;
ms->possible_cpus->cpus[n].props.has_thread_id = true;
- ms->possible_cpus->cpus[n].props.thread_id = n;
+ ms->possible_cpus->cpus[n].props.thread_id = topo.smt_id;
}
return ms->possible_cpus;
}
@@ -2080,7 +2089,62 @@ out:
static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
- /* Currently nothing to do */
+ CPUState *cs = CPU(dev);
+ ARMCPUTopoInfo topo;
+ ARMCPU *cpu = ARM_CPU(dev);
+ MachineState *ms = MACHINE(hotplug_dev);
+ int smp_cores = ms->smp.cores;
+ int smp_threads = ms->smp.threads;
+
+ /* if cpu idx is not set, set it based on socket/core/thread properties */
+ if (cs->cpu_index == UNASSIGNED_CPU_INDEX) {
+ int max_socket = ms->smp.max_cpus / smp_threads / smp_cores;
+ if (cpu->socket_id < 0 || cpu->socket_id >= max_socket) {
+ error_setg(errp, "Invalid CPU socket-id: %u must be in range 0:%u",
+ cpu->socket_id, max_socket - 1);
+ return;
+ }
+ if (cpu->core_id < 0 || cpu->core_id >= smp_cores) {
+ error_setg(errp, "Invalid CPU core-id: %u must be in range 0:%u",
+ cpu->core_id, smp_cores - 1);
+ return;
+ }
+ if (cpu->thread_id < 0 || cpu->thread_id >= smp_threads) {
+ error_setg(errp, "Invalid CPU thread-id: %u must be in range 0:%u",
+ cpu->thread_id, smp_threads - 1);
+ return;
+ }
+
+ topo.pkg_id = cpu->socket_id;
+ topo.core_id = cpu->core_id;
+ topo.smt_id = cpu->thread_id;
+ cs->cpu_index = idx_from_topo_ids(smp_cores, smp_threads, &topo);
+ }
+
+ /* if 'address' properties socket-id/core-id/thread-id are not set, set them
+ * so that machine_query_hotpluggable_cpus would show correct values
+ */
+ topo_ids_from_idx(cs->cpu_index, smp_cores, smp_threads, &topo);
+ if (cpu->socket_id != -1 && cpu->socket_id != topo.pkg_id) {
+ error_setg(errp, "property socket-id: %u doesn't match set idx:"
+ " 0x%x (socket-id: %u)", cpu->socket_id, cs->cpu_index, topo.pkg_id);
+ return;
+ }
+ cpu->socket_id = topo.pkg_id;
+
+ if (cpu->core_id != -1 && cpu->core_id != topo.core_id) {
+ error_setg(errp, "property core-id: %u doesn't match set idx:"
+ " 0x%x (core-id: %u)", cpu->core_id, cs->cpu_index, topo.core_id);
+ return;
+ }
+ cpu->core_id = topo.core_id;
+
+ if (cpu->thread_id != -1 && cpu->thread_id != topo.smt_id) {
+ error_setg(errp, "property thread-id: %u doesn't match set idx:"
+ " 0x%x (thread-id: %u)", cpu->thread_id, cs->cpu_index, topo.smt_id);
+ return;
+ }
+ cpu->thread_id = topo.smt_id;
}
static void virt_cpu_plug(HotplugHandler *hotplug_dev,
diff --git a/include/hw/arm/topology.h b/include/hw/arm/topology.h
new file mode 100644
index 0000000000..a3e5f436c5
--- /dev/null
+++ b/include/hw/arm/topology.h
@@ -0,0 +1,61 @@
+/*
+ * ARM CPU topology data structures and functions
+ *
+ * Copyright (c) 2020 HUAWEI TECHNOLOGIES CO.,LTD.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HW_ARM_TOPOLOGY_H
+#define HW_ARM_TOPOLOGY_H
+
+typedef struct ARMCPUTopoInfo {
+ unsigned pkg_id;
+ unsigned core_id;
+ unsigned smt_id;
+} ARMCPUTopoInfo;
+
+/* Calculate (contiguous) CPU index based on topology */
+static inline unsigned idx_from_topo_ids(unsigned nr_cores,
+ unsigned nr_threads,
+ const ARMCPUTopoInfo *topo)
+{
+ assert(nr_cores > 0);
+ assert(nr_threads > 0);
+ assert(topo != NULL);
+
+ return topo->pkg_id * nr_cores * nr_threads +
+ topo->core_id * nr_threads +
+ topo->smt_id;
+}
+
+/* Calculate thread/core/package topology
+ * based on (contiguous) CPU index
+ */
+static inline void topo_ids_from_idx(unsigned cpu_index,
+ unsigned nr_cores,
+ unsigned nr_threads,
+ ARMCPUTopoInfo *topo)
+{
+ assert(nr_cores > 0);
+ assert(nr_threads > 0);
+ assert(topo != NULL);
+
+ topo->smt_id = cpu_index % nr_threads;
+ topo->core_id = cpu_index / nr_threads % nr_cores;
+ topo->pkg_id = cpu_index / nr_threads / nr_cores;
+}
+
+#endif /* HW_ARM_TOPOLOGY_H */
+
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 1ccb30e5eb..91f1e36cd8 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -2560,6 +2560,9 @@ static Property arm_cpu_properties[] = {
DEFINE_PROP_UINT64("mp-affinity", ARMCPU,
mp_affinity, ARM64_AFFINITY_INVALID),
DEFINE_PROP_INT32("node-id", ARMCPU, node_id, CPU_UNSET_NUMA_NODE_ID),
+ DEFINE_PROP_INT32("socket-id", ARMCPU, socket_id, -1),
+ DEFINE_PROP_INT32("core-id", ARMCPU, core_id, -1),
+ DEFINE_PROP_INT32("thread-id", ARMCPU, thread_id, -1),
DEFINE_PROP_INT32("core-count", ARMCPU, core_count, -1),
DEFINE_PROP_END_OF_LIST()
};
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index e19531a77b..219c222b89 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -916,6 +916,9 @@ struct ARMCPU {
QLIST_HEAD(, ARMELChangeHook) el_change_hooks;
int32_t node_id; /* NUMA node this CPU belongs to */
+ int32_t socket_id;
+ int32_t core_id;
+ int32_t thread_id;
/* Used to synchronize KVM and QEMU in-kernel device levels */
uint8_t device_irq_level;
--
2.19.1

View File

@ -1,61 +0,0 @@
From 31873c4c0454fb17654f57adece2bc396415f8bf Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Fri, 10 Apr 2020 13:50:40 +0800
Subject: [PATCH] arm/virt: Add cpu_hotplug_enabled field
Some conditions must be satisfied to support CPU hotplug, including
ACPI, GED, 64bit CPU, GICv3.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
hw/arm/virt.c | 7 +++++++
include/hw/arm/virt.h | 1 +
2 files changed, 8 insertions(+)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index dda22194b5..304a4c2d31 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -1645,6 +1645,7 @@ static void machvirt_init(MachineState *machine)
{
VirtMachineState *vms = VIRT_MACHINE(machine);
VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(machine);
+ MachineState *ms = MACHINE(machine);
MachineClass *mc = MACHINE_GET_CLASS(machine);
const CPUArchIdList *possible_cpus;
MemoryRegion *sysmem = get_system_memory();
@@ -1655,6 +1656,7 @@ static void machvirt_init(MachineState *machine)
bool has_ged = !vmc->no_ged;
unsigned int smp_cpus = machine->smp.cpus;
unsigned int max_cpus = machine->smp.max_cpus;
+ ObjectClass *cpu_class;
/*
* In accelerated mode, the memory map is computed earlier in kvm_type()
@@ -1760,6 +1762,11 @@ static void machvirt_init(MachineState *machine)
create_fdt(vms);
+ cpu_class = object_class_by_name(ms->cpu_type);
+ vms->cpu_hotplug_enabled = has_ged && firmware_loaded &&
+ acpi_enabled && vms->gic_version == 3 &&
+ !!object_class_dynamic_cast(cpu_class, TYPE_AARCH64_CPU);
+
possible_cpus = mc->possible_cpu_arch_ids(machine);
for (n = 0; n < possible_cpus->len; n++) {
Object *cpuobj;
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index beef4c8002..b4c53d920e 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -126,6 +126,7 @@ typedef struct {
bool highmem_ecam;
bool its;
bool virt;
+ bool cpu_hotplug_enabled;
int32_t gic_version;
VirtIOMMUType iommu;
struct arm_boot_info bootinfo;
--
2.19.1

View File

@ -1,66 +0,0 @@
From 7cfb37c50209208f853c6fbd0df6673a95e03ef9 Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Fri, 10 Apr 2020 14:16:40 +0800
Subject: [PATCH] arm/virt: Add some sanity checks in cpu_pre_plug hook
For that user will try to hotplug a CPU when preconditions
are not satisfied, check these CPU hotplug preconditions in
pre_plug hook.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
hw/arm/virt.c | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 983084c459..c6a99e683a 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -2086,10 +2086,30 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev,
VirtMachineState *vms = VIRT_MACHINE(hotplug_dev);
VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(hotplug_dev);
const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms);
+ const CPUArchId *cpu_slot = NULL;
MemoryRegion *sysmem = get_system_memory();
int smp_cores = ms->smp.cores;
int smp_threads = ms->smp.threads;
+ /* Some hotplug capability checks */
+
+ if (!object_dynamic_cast(OBJECT(cpu), ms->cpu_type)) {
+ error_setg(errp, "Invalid CPU type, expected cpu type: '%s'",
+ ms->cpu_type);
+ return;
+ }
+
+ if (dev->hotplugged && !vms->acpi_dev) {
+ error_setg(errp, "CPU hotplug is disabled: missing acpi device.");
+ return;
+ }
+
+ if (dev->hotplugged && !vms->cpu_hotplug_enabled) {
+ error_setg(errp, "CPU hotplug is disabled: "
+ "should use AArch64 CPU and GICv3.");
+ return;
+ }
+
/* if cpu idx is not set, set it based on socket/core/thread properties */
if (cs->cpu_index == UNASSIGNED_CPU_INDEX) {
int max_socket = ms->smp.max_cpus / smp_threads / smp_cores;
@@ -2145,6 +2165,13 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev,
object_property_set_int(cpuobj, possible_cpus->cpus[cs->cpu_index].arch_id,
"mp-affinity", NULL);
+ cpu_slot = &possible_cpus->cpus[cs->cpu_index];
+ if (cpu_slot->cpu) {
+ error_setg(errp, "CPU[%d] with mp_affinity %" PRIu64 " exists",
+ cs->cpu_index, cpu->mp_affinity);
+ return;
+ }
+
numa_cpu_pre_plug(&possible_cpus->cpus[cs->cpu_index], DEVICE(cpuobj),
&error_fatal);
--
2.19.1

View File

@ -1,100 +0,0 @@
From d38d1d4e859450535ddc6bf0c7a59f6217b1403c Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Sun, 5 Apr 2020 16:03:15 +0800
Subject: [PATCH] arm/virt: Attach ACPI CPU hotplug support to virt
Attach cpus aml building and GED support for CPU hotplug to
arm/virt, but currently we make it diabled by not add CPU
hotplug event to GED.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
hw/arm/virt-acpi-build.c | 15 ++++++++++++++-
hw/arm/virt.c | 6 ++++++
include/hw/arm/virt.h | 1 +
3 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 8b68a15d76..dbe9acb148 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -806,6 +806,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
MachineState *ms = MACHINE(vms);
const MemMapEntry *memmap = vms->memmap;
const int *irqmap = vms->irqmap;
+ bool cpu_aml_built = false;
dsdt = init_aml_allocator();
/* Reserve space for header */
@@ -817,7 +818,6 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
* the RTC ACPI device at all when using UEFI.
*/
scope = aml_scope("\\_SB");
- acpi_dsdt_add_cpus(scope, vms->smp_cpus, vms);
acpi_dsdt_add_uart(scope, &memmap[VIRT_UART],
(irqmap[VIRT_UART] + ARM_SPI_BASE));
acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]);
@@ -845,6 +845,19 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
AML_SYSTEM_MEMORY,
memmap[VIRT_PCDIMM_ACPI].base);
}
+
+ if (event & ACPI_GED_CPU_HOTPLUG_EVT) {
+ CPUHotplugFeatures opts = {
+ .acpi_1_compatible = false, .has_legacy_cphp = false
+ };
+ build_cpus_aml(dsdt, ms, opts, memmap[VIRT_CPU_ACPI].base,
+ "\\_SB", NULL, AML_SYSTEM_MEMORY);
+ cpu_aml_built = true;
+ }
+ }
+
+ if (!cpu_aml_built) {
+ acpi_dsdt_add_cpus(scope, vms->smp_cpus, vms);
}
acpi_dsdt_add_power_button(scope);
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 8638aeedb7..d09a5773df 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -140,6 +140,7 @@ static const MemMapEntry base_memmap[] = {
[VIRT_SMMU] = { 0x09050000, 0x00020000 },
[VIRT_PCDIMM_ACPI] = { 0x09070000, MEMORY_HOTPLUG_IO_LEN },
[VIRT_ACPI_GED] = { 0x09080000, ACPI_GED_EVT_SEL_LEN },
+ [VIRT_CPU_ACPI] = { 0x09090000, ACPI_CPU_HOTPLUG_REG_LEN },
[VIRT_MMIO] = { 0x0a000000, 0x00000200 },
[VIRT_CPUFREQ] = { 0x0b000000, 0x00010000 },
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
@@ -645,11 +646,16 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms)
event |= ACPI_GED_MEM_HOTPLUG_EVT;
}
+ /* event |= ACPI_GED_CPU_HOTPLUG_EVT;
+ * Currently CPU hotplug is not enabled.
+ */
+
dev = qdev_create(NULL, TYPE_ACPI_GED);
qdev_prop_set_uint32(dev, "ged-event", event);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_ACPI_GED].base);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, vms->memmap[VIRT_PCDIMM_ACPI].base);
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, vms->memmap[VIRT_CPU_ACPI].base);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(vms->gic, irq));
qdev_init_nofail(dev);
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index cbdea7ff32..6880ebe07c 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -81,6 +81,7 @@ enum {
VIRT_SECURE_MEM,
VIRT_PCDIMM_ACPI,
VIRT_ACPI_GED,
+ VIRT_CPU_ACPI,
VIRT_LOWMEMMAP_LAST,
};
--
2.19.1

View File

@ -1,124 +0,0 @@
From bf47ef282bfe8b0a98e1f87d8708051ffa7192a1 Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Fri, 10 Apr 2020 13:55:11 +0800
Subject: [PATCH] arm/virt: Pre-sizing MADT-GICC PPTT GICv3 and Pre-park KVM
vCPU
Establish all pre-sizing facilities based on cpu_hotplug_enabled
field.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
hw/arm/virt-acpi-build.c | 12 +++++++++++-
hw/arm/virt.c | 14 ++++++++++++--
target/arm/kvm.c | 6 +++---
3 files changed, 26 insertions(+), 6 deletions(-)
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index efac788ba1..2cfac7b84f 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -736,6 +736,9 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
gicd->base_address = cpu_to_le64(memmap[VIRT_GIC_DIST].base);
gicd->version = vms->gic_version;
+ if (vms->cpu_hotplug_enabled) {
+ num_cpu = ms->smp.max_cpus;
+ }
for (i = 0; i < num_cpu; i++) {
virt_madt_cpu_entry(NULL, i, possible_cpus, table_data);
}
@@ -902,9 +905,11 @@ static
void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
{
VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
+ MachineState *ms = MACHINE(vms);
GArray *table_offsets;
unsigned dsdt, xsdt;
GArray *tables_blob = tables->table_data;
+ int num_cpus;
table_offsets = g_array_new(false, true /* clear */,
sizeof(uint32_t));
@@ -923,7 +928,12 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
acpi_add_table(table_offsets, tables_blob);
- build_pptt(tables_blob, tables->linker, vms->smp_cpus);
+ if (vms->cpu_hotplug_enabled) {
+ num_cpus = ms->smp.max_cpus;
+ } else {
+ num_cpus = ms->smp.cpus;
+ }
+ build_pptt(tables_blob, tables->linker, num_cpus);
acpi_add_table(table_offsets, tables_blob);
build_madt(tables_blob, tables->linker, vms);
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 304a4c2d31..983084c459 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -767,6 +767,9 @@ static void create_gic(VirtMachineState *vms)
unsigned int smp_cpus = ms->smp.cpus;
uint32_t nb_redist_regions = 0;
+ if (vms->cpu_hotplug_enabled) {
+ num_cpus = ms->smp.max_cpus;
+ }
assert(num_cpus >= smp_cpus);
gictype = (type == 3) ? gicv3_class_name() : gic_class_name();
@@ -1772,8 +1775,15 @@ static void machvirt_init(MachineState *machine)
Object *cpuobj;
CPUState *cs;
+ if (kvm_enabled() && vms->cpu_hotplug_enabled) {
+ if (kvm_create_parked_vcpu(n) < 0) {
+ error_report("mach-virt: Create KVM parked vCPU failed");
+ exit(1);
+ }
+ }
+
if (n >= smp_cpus) {
- break;
+ continue;
}
cpuobj = object_new(possible_cpus->cpus[n].type);
@@ -1857,7 +1867,7 @@ static void machvirt_init(MachineState *machine)
vms->bootinfo.kernel_filename = machine->kernel_filename;
vms->bootinfo.kernel_cmdline = machine->kernel_cmdline;
vms->bootinfo.initrd_filename = machine->initrd_filename;
- vms->bootinfo.nb_cpus = smp_cpus;
+ vms->bootinfo.nb_cpus = vms->cpu_hotplug_enabled ? max_cpus : smp_cpus;
vms->bootinfo.board_id = -1;
vms->bootinfo.loader_start = vms->memmap[VIRT_MEM].base;
vms->bootinfo.get_dtb = machvirt_dtb;
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 327b3bc338..4f131f687d 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -202,7 +202,7 @@ int kvm_arm_get_max_vm_ipa_size(MachineState *ms)
int kvm_arch_init(MachineState *ms, KVMState *s)
{
int ret = 0;
- unsigned int smp_cpus = ms->smp.cpus;
+ unsigned int max_cpus = ms->smp.max_cpus;
/* For ARM interrupt delivery is always asynchronous,
* whether we are using an in-kernel VGIC or not.
*/
@@ -216,9 +216,9 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE);
- if (smp_cpus > 256 &&
+ if (max_cpus > 256 &&
!kvm_check_extension(s, KVM_CAP_ARM_IRQ_LINE_LAYOUT_2)) {
- error_report("Using more than 256 vcpus requires a host kernel "
+ error_report("Using more than max 256 vcpus requires a host kernel "
"with KVM_CAP_ARM_IRQ_LINE_LAYOUT_2");
ret = -EINVAL;
}
--
2.19.1

View File

@ -1,159 +0,0 @@
From 11f9628ceff019259ff12ce469deafbf50eb3075 Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Fri, 10 Apr 2020 14:20:59 +0800
Subject: [PATCH] arm/virt: Start up CPU hot-plug
All the CPU hotplug facilities are ready. Assemble them
to start up CPU hot-plug capability for arm/virt.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
hw/arm/virt.c | 61 ++++++++++++++++++++++++++++++++++++++++---
include/hw/arm/virt.h | 1 +
qom/cpu.c | 5 ++++
target/arm/cpu.c | 2 ++
4 files changed, 65 insertions(+), 4 deletions(-)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index c6a99e683a..112a6ae7cb 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -48,6 +48,8 @@
#include "sysemu/cpus.h"
#include "sysemu/sysemu.h"
#include "sysemu/kvm.h"
+#include "sysemu/cpus.h"
+#include "sysemu/hw_accel.h"
#include "hw/loader.h"
#include "exec/address-spaces.h"
#include "qemu/bitops.h"
@@ -649,9 +651,9 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms)
event |= ACPI_GED_MEM_HOTPLUG_EVT;
}
- /* event |= ACPI_GED_CPU_HOTPLUG_EVT;
- * Currently CPU hotplug is not enabled.
- */
+ if (vms->cpu_hotplug_enabled) {
+ event |= ACPI_GED_CPU_HOTPLUG_EVT;
+ }
dev = qdev_create(NULL, TYPE_ACPI_GED);
qdev_prop_set_uint32(dev, "ged-event", event);
@@ -2214,12 +2216,62 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev,
object_property_set_link(cpuobj, OBJECT(secure_sysmem),
"secure-memory", &error_abort);
}
+
+ /* If we use KVM accel, we should pause all vcpus to
+ * allow hot access of vcpu registers.
+ */
+ if (dev->hotplugged && kvm_enabled()) {
+ pause_all_vcpus();
+ }
}
static void virt_cpu_plug(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
- /* Currently nothing to do */
+ CPUArchId *cpu_slot;
+ CPUState *cs = CPU(dev);
+ int ncpu = cs->cpu_index;
+ MachineState *ms = MACHINE(hotplug_dev);
+ VirtMachineState *vms = VIRT_MACHINE(hotplug_dev);
+ GICv3State *gicv3;
+ ARMGICv3CommonClass *agcc;
+ Error *local_err = NULL;
+
+ if (dev->hotplugged) {
+ /* Realize GIC related parts of CPU */
+ assert(vms->gic_version == 3);
+ gicv3 = ARM_GICV3_COMMON(vms->gic);
+ agcc = ARM_GICV3_COMMON_GET_CLASS(gicv3);
+ agcc->cpu_hotplug_realize(gicv3, ncpu);
+ connect_gic_cpu_irqs(vms, ncpu);
+
+ /* Register CPU reset and trigger it manually */
+ cpu_synchronize_state(cs);
+ cpu_hotplug_register_reset(ncpu);
+ cpu_hotplug_reset_manually(ncpu);
+ cpu_synchronize_post_reset(cs);
+
+ if (kvm_enabled()) {
+ resume_all_vcpus();
+ }
+ }
+
+ if (vms->acpi_dev) {
+ hotplug_handler_plug(HOTPLUG_HANDLER(vms->acpi_dev), dev, &local_err);
+ if (local_err) {
+ goto out;
+ }
+ }
+
+ vms->boot_cpus++;
+ if (vms->fw_cfg) {
+ fw_cfg_modify_i16(vms->fw_cfg, FW_CFG_NB_CPUS, vms->boot_cpus);
+ }
+
+ cpu_slot = &ms->possible_cpus->cpus[ncpu];
+ cpu_slot->cpu = OBJECT(dev);
+out:
+ error_propagate(errp, local_err);
}
static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
@@ -2324,6 +2376,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a15");
mc->get_default_cpu_node_id = virt_get_default_cpu_node_id;
mc->kvm_type = virt_kvm_type;
+ mc->has_hotpluggable_cpus = true;
assert(!mc->get_hotplug_handler);
mc->get_hotplug_handler = virt_machine_get_hotplug_handler;
hc->pre_plug = virt_machine_device_pre_plug_cb;
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index b4c53d920e..a9429bed25 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -140,6 +140,7 @@ typedef struct {
uint32_t msi_phandle;
uint32_t iommu_phandle;
int psci_conduit;
+ uint32_t boot_cpus;
hwaddr highest_gpa;
DeviceState *gic;
DeviceState *acpi_dev;
diff --git a/qom/cpu.c b/qom/cpu.c
index f376f782d8..58cd9d5bbc 100644
--- a/qom/cpu.c
+++ b/qom/cpu.c
@@ -342,7 +342,12 @@ static void cpu_common_realizefn(DeviceState *dev, Error **errp)
if (dev->hotplugged) {
cpu_synchronize_post_init(cpu);
+
+#ifdef __aarch64__
+ if (!kvm_enabled())
+#endif
cpu_resume(cpu);
+
}
/* NOTE: latest generic point where the cpu is fully realized */
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 91f1e36cd8..811e5c6365 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -2598,6 +2598,8 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
acc->parent_reset = cc->reset;
cc->reset = arm_cpu_reset;
+ dc->user_creatable = true;
+
cc->class_by_name = arm_cpu_class_by_name;
cc->has_work = arm_cpu_has_work;
cc->cpu_exec_interrupt = arm_cpu_exec_interrupt;
--
2.19.1

View File

@ -1,92 +0,0 @@
From e3a1af72fca5bbcc840fba44d512bbe69ec55ca9 Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Tue, 12 May 2020 15:05:06 +0800
Subject: [PATCH] arm/virt: Support CPU cold plug
This adds CPU cold plug support to arm virt machine board.
CPU cold plug means adding CPU by using "-device xx-arm-cpu"
when we bring up Qemu.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
---
hw/arm/virt.c | 36 +++++++++++++++++++-----------------
1 file changed, 19 insertions(+), 17 deletions(-)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 112a6ae7cb..4c7279392f 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -2093,25 +2093,12 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev,
int smp_cores = ms->smp.cores;
int smp_threads = ms->smp.threads;
- /* Some hotplug capability checks */
-
if (!object_dynamic_cast(OBJECT(cpu), ms->cpu_type)) {
error_setg(errp, "Invalid CPU type, expected cpu type: '%s'",
ms->cpu_type);
return;
}
- if (dev->hotplugged && !vms->acpi_dev) {
- error_setg(errp, "CPU hotplug is disabled: missing acpi device.");
- return;
- }
-
- if (dev->hotplugged && !vms->cpu_hotplug_enabled) {
- error_setg(errp, "CPU hotplug is disabled: "
- "should use AArch64 CPU and GICv3.");
- return;
- }
-
/* if cpu idx is not set, set it based on socket/core/thread properties */
if (cs->cpu_index == UNASSIGNED_CPU_INDEX) {
int max_socket = ms->smp.max_cpus / smp_threads / smp_cores;
@@ -2137,6 +2124,20 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev,
cs->cpu_index = idx_from_topo_ids(smp_cores, smp_threads, &topo);
}
+ /* Some hotplug capability checks */
+ if (cs->cpu_index >= ms->smp.cpus) {
+ if (!vms->acpi_dev) {
+ error_setg(errp, "CPU cold/hot plug is disabled: "
+ "missing acpi device.");
+ return;
+ }
+ if (!vms->cpu_hotplug_enabled) {
+ error_setg(errp, "CPU cold/hot plug is disabled: "
+ "should use AArch64 CPU and GICv3.");
+ return;
+ }
+ }
+
/* if 'address' properties socket-id/core-id/thread-id are not set, set them
* so that machine_query_hotpluggable_cpus would show correct values
*/
@@ -2237,7 +2238,8 @@ static void virt_cpu_plug(HotplugHandler *hotplug_dev,
ARMGICv3CommonClass *agcc;
Error *local_err = NULL;
- if (dev->hotplugged) {
+ /* For CPU that is cold/hot plugged */
+ if (ncpu >= ms->smp.cpus) {
/* Realize GIC related parts of CPU */
assert(vms->gic_version == 3);
gicv3 = ARM_GICV3_COMMON(vms->gic);
@@ -2250,10 +2252,10 @@ static void virt_cpu_plug(HotplugHandler *hotplug_dev,
cpu_hotplug_register_reset(ncpu);
cpu_hotplug_reset_manually(ncpu);
cpu_synchronize_post_reset(cs);
+ }
- if (kvm_enabled()) {
- resume_all_vcpus();
- }
+ if (dev->hotplugged && kvm_enabled()) {
+ resume_all_vcpus();
}
if (vms->acpi_dev) {
--
2.19.1

View File

@ -1,65 +0,0 @@
From 91fed8840b004ec7bc91969afa10f03e13f311c4 Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Wed, 22 Apr 2020 19:52:58 +0800
Subject: [PATCH] arm/virt/acpi: Extend cpufreq to support max_cpus
We will support CPU hotplug soon, so extend memory region size to
allow hotplugged CPU access cpufreq space.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
---
hw/acpi/cpufreq.c | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/hw/acpi/cpufreq.c b/hw/acpi/cpufreq.c
index d02a25a6de..38dcab5683 100644
--- a/hw/acpi/cpufreq.c
+++ b/hw/acpi/cpufreq.c
@@ -84,6 +84,7 @@ typedef struct CpuhzState {
uint32_t PerformanceLimited;
uint32_t LowestFreq;
uint32_t NominalFreq;
+ uint32_t num_cpu;
uint32_t reg_size;
} CpuhzState;
@@ -95,10 +96,7 @@ static uint64_t cpufreq_read(void *opaque, hwaddr offset,
uint64_t r;
uint64_t n;
- MachineState *ms = MACHINE(qdev_get_machine());
- unsigned int smp_cpus = ms->smp.cpus;
-
- if (offset >= smp_cpus * CPPC_REG_PER_CPU_STRIDE) {
+ if (offset >= s->num_cpu * CPPC_REG_PER_CPU_STRIDE) {
warn_report("cpufreq_read: offset 0x%lx out of range", offset);
return 0;
}
@@ -166,11 +164,10 @@ static uint64_t cpufreq_read(void *opaque, hwaddr offset,
static void cpufreq_write(void *opaque, hwaddr offset,
uint64_t value, unsigned size)
{
+ CpuhzState *s = CPUFREQ(opaque);
uint64_t n;
- MachineState *ms = MACHINE(qdev_get_machine());
- unsigned int smp_cpus = ms->smp.cpus;
- if (offset >= smp_cpus * CPPC_REG_PER_CPU_STRIDE) {
+ if (offset >= s->num_cpu * CPPC_REG_PER_CPU_STRIDE) {
error_printf("cpufreq_write: offset 0x%lx out of range", offset);
return;
}
@@ -251,9 +248,9 @@ static void cpufreq_init(Object *obj)
CpuhzState *s = CPUFREQ(obj);
MachineState *ms = MACHINE(qdev_get_machine());
- unsigned int smp_cpus = ms->smp.cpus;
+ s->num_cpu = ms->smp.max_cpus;
- s->reg_size = smp_cpus * CPPC_REG_PER_CPU_STRIDE;
+ s->reg_size = s->num_cpu * CPPC_REG_PER_CPU_STRIDE;
if (s->reg_size > MAX_SUPPORT_SPACE) {
error_report("Required space 0x%x excesses the max support 0x%x",
s->reg_size, MAX_SUPPORT_SPACE);
--
2.19.1

View File

@ -1,121 +0,0 @@
From 2fdece10dac6161cb6c1f0f05247391aa3269eed Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Wed, 22 Apr 2020 15:58:27 +0800
Subject: [PATCH] arm/virt/acpi: Factor out CPPC building from DSDT CPU aml
When CPU hotplug is enabled, we will use build_cpus_aml instead of
acpi_dsdt_add_cpus, so factor out CPPC building and we can reuse it
in build_cpus_aml.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
---
hw/acpi/generic_event_device.c | 1 +
hw/arm/virt-acpi-build.c | 33 +++++++++++++++++-----------
include/hw/acpi/acpi_dev_interface.h | 2 ++
include/hw/arm/virt.h | 2 ++
4 files changed, 25 insertions(+), 13 deletions(-)
diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c
index b834ae3ff6..82139b4314 100644
--- a/hw/acpi/generic_event_device.c
+++ b/hw/acpi/generic_event_device.c
@@ -289,6 +289,7 @@ static void acpi_ged_class_init(ObjectClass *class, void *data)
adevc->send_event = acpi_ged_send_event;
adevc->madt_cpu = virt_madt_cpu_entry;
+ adevc->cpu_cppc = virt_acpi_dsdt_cpu_cppc;
}
static const TypeInfo acpi_ged_info = {
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 4b6aace433..8b68a15d76 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -111,8 +111,24 @@ static void acpi_dsdt_add_cppc(Aml *dev, uint64_t cpu_base, int *regs_offset)
aml_append(dev, aml_name_decl("_CPC", cpc));
}
-static void acpi_dsdt_add_cpus(Aml *scope, int smp_cpus,
- const MemMapEntry *cppc_memmap)
+void virt_acpi_dsdt_cpu_cppc(AcpiDeviceIf *adev, int ncpu, int num_cpu, Aml *dev)
+{
+ VirtMachineState *vms = VIRT_MACHINE(qdev_get_machine());
+ const MemMapEntry *cppc_memmap = &vms->memmap[VIRT_CPUFREQ];
+
+ /*
+ * Append _CPC and _PSD to support CPU frequence show
+ * Check CPPC available by DESIRED_PERF register
+ */
+ if (cppc_regs_offset[DESIRED_PERF] != -1) {
+ acpi_dsdt_add_cppc(dev,
+ cppc_memmap->base + ncpu * CPPC_REG_PER_CPU_STRIDE,
+ cppc_regs_offset);
+ acpi_dsdt_add_psd(dev, num_cpu);
+ }
+}
+
+static void acpi_dsdt_add_cpus(Aml *scope, int smp_cpus, VirtMachineState *vms)
{
uint16_t i;
@@ -121,16 +137,7 @@ static void acpi_dsdt_add_cpus(Aml *scope, int smp_cpus,
aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0007")));
aml_append(dev, aml_name_decl("_UID", aml_int(i)));
- /*
- * Append _CPC and _PSD to support CPU frequence show
- * Check CPPC available by DESIRED_PERF register
- */
- if (cppc_regs_offset[DESIRED_PERF] != -1) {
- acpi_dsdt_add_cppc(dev,
- cppc_memmap->base + i * CPPC_REG_PER_CPU_STRIDE,
- cppc_regs_offset);
- acpi_dsdt_add_psd(dev, smp_cpus);
- }
+ virt_acpi_dsdt_cpu_cppc(NULL, i, smp_cpus, dev);
aml_append(scope, dev);
}
@@ -810,7 +817,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
* the RTC ACPI device at all when using UEFI.
*/
scope = aml_scope("\\_SB");
- acpi_dsdt_add_cpus(scope, vms->smp_cpus, &memmap[VIRT_CPUFREQ]);
+ acpi_dsdt_add_cpus(scope, vms->smp_cpus, vms);
acpi_dsdt_add_uart(scope, &memmap[VIRT_UART],
(irqmap[VIRT_UART] + ARM_SPI_BASE));
acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]);
diff --git a/include/hw/acpi/acpi_dev_interface.h b/include/hw/acpi/acpi_dev_interface.h
index adcb3a816c..2952914569 100644
--- a/include/hw/acpi/acpi_dev_interface.h
+++ b/include/hw/acpi/acpi_dev_interface.h
@@ -3,6 +3,7 @@
#include "qom/object.h"
#include "hw/boards.h"
+#include "hw/acpi/aml-build.h"
/* These values are part of guest ABI, and can not be changed */
typedef enum {
@@ -55,5 +56,6 @@ typedef struct AcpiDeviceIfClass {
void (*send_event)(AcpiDeviceIf *adev, AcpiEventStatusBits ev);
void (*madt_cpu)(AcpiDeviceIf *adev, int uid,
const CPUArchIdList *apic_ids, GArray *entry);
+ void (*cpu_cppc)(AcpiDeviceIf *adev, int uid, int num_cpu, Aml *dev);
} AcpiDeviceIfClass;
#endif
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index 6b1f10b231..cbdea7ff32 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -157,6 +157,8 @@ typedef struct {
void virt_acpi_setup(VirtMachineState *vms);
void virt_madt_cpu_entry(AcpiDeviceIf *adev, int uid,
const CPUArchIdList *cpu_list, GArray *entry);
+void virt_acpi_dsdt_cpu_cppc(AcpiDeviceIf *adev, int uid,
+ int num_cpu, Aml *dev);
/* Return the number of used redistributor regions */
static inline int virt_gicv3_redist_region_count(VirtMachineState *vms)
--
2.19.1

View File

@ -1,123 +0,0 @@
From 92124743f4560c490780a229f53ea5881f706383 Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Sun, 5 Apr 2020 15:29:16 +0800
Subject: [PATCH] arm/virt/gic: Construct irqs connection from create_gic
Make the irqs can be connected to for individual CPU.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
hw/arm/virt.c | 90 ++++++++++++++++++++++++++++-----------------------
1 file changed, 49 insertions(+), 41 deletions(-)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 83f4887e57..55d403bad6 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -706,6 +706,54 @@ static void create_v2m(VirtMachineState *vms)
fdt_add_v2m_gic_node(vms);
}
+static void connect_gic_cpu_irqs(VirtMachineState *vms, int i)
+{
+ DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
+ SysBusDevice *gicbusdev = SYS_BUS_DEVICE(vms->gic);
+ int ppibase = NUM_IRQS + i * GIC_INTERNAL + GIC_NR_SGIS;
+ int num_cpus = object_property_get_uint(OBJECT(vms->gic), "num-cpu", NULL);
+ int gic_type = vms->gic_version;
+ int irq;
+ /* Mapping from the output timer irq lines from the CPU to the
+ * GIC PPI inputs we use for the virt board.
+ */
+ const int timer_irq[] = {
+ [GTIMER_PHYS] = ARCH_TIMER_NS_EL1_IRQ,
+ [GTIMER_VIRT] = ARCH_TIMER_VIRT_IRQ,
+ [GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ,
+ [GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ,
+ };
+
+ for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) {
+ qdev_connect_gpio_out(cpudev, irq,
+ qdev_get_gpio_in(vms->gic,
+ ppibase + timer_irq[irq]));
+ }
+
+ if (gic_type == 3) {
+ qemu_irq irq = qdev_get_gpio_in(vms->gic,
+ ppibase + ARCH_GIC_MAINT_IRQ);
+ qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt",
+ 0, irq);
+ } else if (vms->virt) {
+ qemu_irq irq = qdev_get_gpio_in(vms->gic,
+ ppibase + ARCH_GIC_MAINT_IRQ);
+ sysbus_connect_irq(gicbusdev, i + 4 * num_cpus, irq);
+ }
+
+ qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0,
+ qdev_get_gpio_in(vms->gic, ppibase
+ + VIRTUAL_PMU_IRQ));
+
+ sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
+ sysbus_connect_irq(gicbusdev, i + num_cpus,
+ qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
+ sysbus_connect_irq(gicbusdev, i + 2 * num_cpus,
+ qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
+ sysbus_connect_irq(gicbusdev, i + 3 * num_cpus,
+ qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
+}
+
static void create_gic(VirtMachineState *vms)
{
MachineState *ms = MACHINE(vms);
@@ -775,47 +823,7 @@ static void create_gic(VirtMachineState *vms)
* and the GIC's IRQ/FIQ/VIRQ/VFIQ interrupt outputs to the CPU's inputs.
*/
for (i = 0; i < smp_cpus; i++) {
- DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
- int ppibase = NUM_IRQS + i * GIC_INTERNAL + GIC_NR_SGIS;
- int irq;
- /* Mapping from the output timer irq lines from the CPU to the
- * GIC PPI inputs we use for the virt board.
- */
- const int timer_irq[] = {
- [GTIMER_PHYS] = ARCH_TIMER_NS_EL1_IRQ,
- [GTIMER_VIRT] = ARCH_TIMER_VIRT_IRQ,
- [GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ,
- [GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ,
- };
-
- for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) {
- qdev_connect_gpio_out(cpudev, irq,
- qdev_get_gpio_in(vms->gic,
- ppibase + timer_irq[irq]));
- }
-
- if (type == 3) {
- qemu_irq irq = qdev_get_gpio_in(vms->gic,
- ppibase + ARCH_GIC_MAINT_IRQ);
- qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt",
- 0, irq);
- } else if (vms->virt) {
- qemu_irq irq = qdev_get_gpio_in(vms->gic,
- ppibase + ARCH_GIC_MAINT_IRQ);
- sysbus_connect_irq(gicbusdev, i + 4 * smp_cpus, irq);
- }
-
- qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0,
- qdev_get_gpio_in(vms->gic, ppibase
- + VIRTUAL_PMU_IRQ));
-
- sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
- sysbus_connect_irq(gicbusdev, i + smp_cpus,
- qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
- sysbus_connect_irq(gicbusdev, i + 2 * smp_cpus,
- qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
- sysbus_connect_irq(gicbusdev, i + 3 * smp_cpus,
- qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
+ connect_gic_cpu_irqs(vms, i);
}
fdt_add_gic_node(vms);
--
2.19.1

View File

@ -1,171 +0,0 @@
From 787af8ed2bc86dc8688727d62a251965d9c42e00 Mon Sep 17 00:00:00 2001
From: Ying Fang <fangying1@huawei.com>
Date: Fri, 10 Apr 2020 16:19:50 +0000
Subject: [PATCH 2/2] async: use explicit memory barriers
When using C11 atomics, non-seqcst reads and writes do not participate
in the total order of seqcst operations. In util/async.c and util/aio-posix.c,
in particular, the pattern that we use
write ctx->notify_me write bh->scheduled
read bh->scheduled read ctx->notify_me
if !bh->scheduled, sleep if ctx->notify_me, notify
needs to use seqcst operations for both the write and the read. In
general this is something that we do not want, because there can be
many sources that are polled in addition to bottom halves. The
alternative is to place a seqcst memory barrier between the write
and the read. This also comes with a disadvantage, in that the
memory barrier is implicit on strongly-ordered architectures and
it wastes a few dozen clock cycles.
Fortunately, ctx->notify_me is never written concurrently by two
threads, so we can assert that and relax the writes to ctx->notify_me.
The resulting solution works and performs well on both aarch64 and x86.
Note that the atomic_set/atomic_read combination is not an atomic
read-modify-write, and therefore it is even weaker than C11 ATOMIC_RELAXED;
on x86, ATOMIC_RELAXED compiles to a locked operation.
upstream_url: https://patchwork.kernel.org/patch/11482103/
Analyzed-by: Ying Fang <fangying1@huawei.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Tested-by: Ying Fang <fangying1@huawei.com>
Message-Id: <20200407140746.8041-6-pbonzini@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
util/aio-posix.c | 16 ++++++++++++++--
util/aio-win32.c | 17 ++++++++++++++---
util/async.c | 16 ++++++++++++----
3 files changed, 40 insertions(+), 9 deletions(-)
diff --git a/util/aio-posix.c b/util/aio-posix.c
index 6fbfa792..ca58b9a4 100644
--- a/util/aio-posix.c
+++ b/util/aio-posix.c
@@ -613,6 +613,11 @@ bool aio_poll(AioContext *ctx, bool blocking)
int64_t timeout;
int64_t start = 0;
+ /*
+ * There cannot be two concurrent aio_poll calls for the same AioContext (or
+ * an aio_poll concurrent with a GSource prepare/check/dispatch callback).
+ * We rely on this below to avoid slow locked accesses to ctx->notify_me.
+ */
assert(in_aio_context_home_thread(ctx));
/* aio_notify can avoid the expensive event_notifier_set if
@@ -623,7 +628,13 @@ bool aio_poll(AioContext *ctx, bool blocking)
* so disable the optimization now.
*/
if (blocking) {
- atomic_add(&ctx->notify_me, 2);
+ atomic_set(&ctx->notify_me, atomic_read(&ctx->notify_me) + 2);
+ /*
+ * Write ctx->notify_me before computing the timeout
+ * (reading bottom half flags, etc.). Pairs with
+ * smp_mb in aio_notify().
+ */
+ smp_mb();
}
qemu_lockcnt_inc(&ctx->list_lock);
@@ -668,7 +679,8 @@ bool aio_poll(AioContext *ctx, bool blocking)
}
if (blocking) {
- atomic_sub(&ctx->notify_me, 2);
+ /* Finish the poll before clearing the flag. */
+ atomic_store_release(&ctx->notify_me, atomic_read(&ctx->notify_me) - 2);
aio_notify_accept(ctx);
}
diff --git a/util/aio-win32.c b/util/aio-win32.c
index a23b9c36..729d533f 100644
--- a/util/aio-win32.c
+++ b/util/aio-win32.c
@@ -321,6 +321,12 @@ bool aio_poll(AioContext *ctx, bool blocking)
int count;
int timeout;
+ /*
+ * There cannot be two concurrent aio_poll calls for the same AioContext (or
+ * an aio_poll concurrent with a GSource prepare/check/dispatch callback).
+ * We rely on this below to avoid slow locked accesses to ctx->notify_me.
+ */
+ assert(in_aio_context_home_thread(ctx));
progress = false;
/* aio_notify can avoid the expensive event_notifier_set if
@@ -331,7 +337,13 @@ bool aio_poll(AioContext *ctx, bool blocking)
* so disable the optimization now.
*/
if (blocking) {
- atomic_add(&ctx->notify_me, 2);
+ atomic_set(&ctx->notify_me, atomic_read(&ctx->notify_me) + 2);
+ /*
+ * Write ctx->notify_me before computing the timeout
+ * (reading bottom half flags, etc.). Pairs with
+ * smp_mb in aio_notify().
+ */
+ smp_mb();
}
qemu_lockcnt_inc(&ctx->list_lock);
@@ -364,8 +376,7 @@ bool aio_poll(AioContext *ctx, bool blocking)
ret = WaitForMultipleObjects(count, events, FALSE, timeout);
if (blocking) {
assert(first);
- assert(in_aio_context_home_thread(ctx));
- atomic_sub(&ctx->notify_me, 2);
+ atomic_store_release(&ctx->notify_me, atomic_read(&ctx->notify_me) - 2);
aio_notify_accept(ctx);
}
diff --git a/util/async.c b/util/async.c
index afc17fb3..12b33204 100644
--- a/util/async.c
+++ b/util/async.c
@@ -221,7 +221,14 @@ aio_ctx_prepare(GSource *source, gint *timeout)
{
AioContext *ctx = (AioContext *) source;
- atomic_or(&ctx->notify_me, 1);
+ atomic_set(&ctx->notify_me, atomic_read(&ctx->notify_me) | 1);
+
+ /*
+ * Write ctx->notify_me before computing the timeout
+ * (reading bottom half flags, etc.). Pairs with
+ * smp_mb in aio_notify().
+ */
+ smp_mb();
/* We assume there is no timeout already supplied */
*timeout = qemu_timeout_ns_to_ms(aio_compute_timeout(ctx));
@@ -239,7 +246,8 @@ aio_ctx_check(GSource *source)
AioContext *ctx = (AioContext *) source;
QEMUBH *bh;
- atomic_and(&ctx->notify_me, ~1);
+ /* Finish computing the timeout before clearing the flag. */
+ atomic_store_release(&ctx->notify_me, atomic_read(&ctx->notify_me) & ~1);
aio_notify_accept(ctx);
for (bh = ctx->first_bh; bh; bh = bh->next) {
@@ -344,10 +352,10 @@ LinuxAioState *aio_get_linux_aio(AioContext *ctx)
void aio_notify(AioContext *ctx)
{
/* Write e.g. bh->scheduled before reading ctx->notify_me. Pairs
- * with atomic_or in aio_ctx_prepare or atomic_add in aio_poll.
+ * with smp_mb in aio_ctx_prepare or aio_poll.
*/
smp_mb();
- if (ctx->notify_me) {
+ if (atomic_read(&ctx->notify_me)) {
event_notifier_set(&ctx->notifier);
atomic_mb_set(&ctx->notified, true);
}
--
2.25.2

View File

@ -1,53 +0,0 @@
From 9557ba506470517668ffecb4d5ef4804eca4fd88 Mon Sep 17 00:00:00 2001
From: Prasad J Pandit <pjp@fedoraproject.org>
Date: Wed, 18 Nov 2020 10:22:32 +0800
Subject: [PATCH] ati: check x y display parameter values
fix CVE-2020-24352
The source and destination x,y display parameters in ati_2d_blt()
may run off the vga limits if either of s->regs.[src|dst]_[xy] is
zero. Check the parameter values to avoid potential crash.
Reported-by: Gaoning Pan <pgn@zju.edu.cn>
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
Message-id: 20201021103818.1704030-1-ppandit@redhat.com
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
cherry-pick from commit ca1f9cbfdce4d63b10d57de80fef89a89d92a540
Signed-off-by: Jiajie Li <lijiajie11@huawei.com>
---
hw/display/ati_2d.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/hw/display/ati_2d.c b/hw/display/ati_2d.c
index 23a8ae0cd8..4dc10ea795 100644
--- a/hw/display/ati_2d.c
+++ b/hw/display/ati_2d.c
@@ -75,8 +75,9 @@ void ati_2d_blt(ATIVGAState *s)
dst_stride *= bpp;
}
uint8_t *end = s->vga.vram_ptr + s->vga.vram_size;
- if (dst_bits >= end || dst_bits + dst_x + (dst_y + s->regs.dst_height) *
- dst_stride >= end) {
+ if (dst_x > 0x3fff || dst_y > 0x3fff || dst_bits >= end
+ || dst_bits + dst_x
+ + (dst_y + s->regs.dst_height) * dst_stride >= end) {
qemu_log_mask(LOG_UNIMP, "blt outside vram not implemented\n");
return;
}
@@ -107,8 +108,9 @@ void ati_2d_blt(ATIVGAState *s)
src_bits += s->regs.crtc_offset & 0x07ffffff;
src_stride *= bpp;
}
- if (src_bits >= end || src_bits + src_x +
- (src_y + s->regs.dst_height) * src_stride >= end) {
+ if (src_x > 0x3fff || src_y > 0x3fff || src_bits >= end
+ || src_bits + src_x
+ + (src_y + s->regs.dst_height) * src_stride >= end) {
qemu_log_mask(LOG_UNIMP, "blt outside vram not implemented\n");
return;
}
--
2.27.0

View File

@ -1,198 +0,0 @@
From 1ebe0e71d04bfdc76777a3a672e873f006d207e2 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Fri, 5 Feb 2021 10:38:24 +0800
Subject: [PATCH] ati: use vga_read_byte in ati_cursor_define
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
fix CVE-2019-20808
This makes sure reads are confined to vga video memory.
v3: use uint32_t, fix cut+paste bug.
v2: fix ati_cursor_draw_line too.
Reported-by: xu hang <flier_m@outlook.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: BALATON Zoltan <balaton@eik.bme.hu>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Message-id: 20190917111441.27405-3-kraxel@redhat.com
cherry-pick from aab0e2a661b2b6bf7915c0aefe807fb60d6d9d13
Signed-off-by: Jiajie Li <lijiajie11@huawei.com>
---
hw/display/ati.c | 21 ++++++++---------
hw/display/vga-access.h | 49 ++++++++++++++++++++++++++++++++++++++++
hw/display/vga-helpers.h | 27 +---------------------
3 files changed, 60 insertions(+), 37 deletions(-)
create mode 100644 hw/display/vga-access.h
diff --git a/hw/display/ati.c b/hw/display/ati.c
index 5943040416..b17569874e 100644
--- a/hw/display/ati.c
+++ b/hw/display/ati.c
@@ -19,6 +19,7 @@
#include "qemu/osdep.h"
#include "ati_int.h"
#include "ati_regs.h"
+#include "vga-access.h"
#include "vga_regs.h"
#include "qemu/log.h"
#include "qemu/module.h"
@@ -125,20 +126,19 @@ static void ati_vga_switch_mode(ATIVGAState *s)
static void ati_cursor_define(ATIVGAState *s)
{
uint8_t data[1024];
- uint8_t *src;
+ uint32_t srcoff;
int i, j, idx = 0;
if ((s->regs.cur_offset & BIT(31)) || s->cursor_guest_mode) {
return; /* Do not update cursor if locked or rendered by guest */
}
/* FIXME handle cur_hv_offs correctly */
- src = s->vga.vram_ptr + (s->regs.crtc_offset & 0x07ffffff) +
- s->regs.cur_offset - (s->regs.cur_hv_offs >> 16) -
- (s->regs.cur_hv_offs & 0xffff) * 16;
+ srcoff = s->regs.cur_offset -
+ (s->regs.cur_hv_offs >> 16) - (s->regs.cur_hv_offs & 0xffff) * 16;
for (i = 0; i < 64; i++) {
for (j = 0; j < 8; j++, idx++) {
- data[idx] = src[i * 16 + j];
- data[512 + idx] = src[i * 16 + j + 8];
+ data[idx] = vga_read_byte(&s->vga, srcoff + i * 16 + j);
+ data[512 + idx] = vga_read_byte(&s->vga, srcoff + i * 16 + j + 8);
}
}
if (!s->cursor) {
@@ -180,7 +180,7 @@ static void ati_cursor_invalidate(VGACommonState *vga)
static void ati_cursor_draw_line(VGACommonState *vga, uint8_t *d, int scr_y)
{
ATIVGAState *s = container_of(vga, ATIVGAState, vga);
- uint8_t *src;
+ uint32_t srcoff;
uint32_t *dp = (uint32_t *)d;
int i, j, h;
@@ -190,14 +190,13 @@ static void ati_cursor_draw_line(VGACommonState *vga, uint8_t *d, int scr_y)
return;
}
/* FIXME handle cur_hv_offs correctly */
- src = s->vga.vram_ptr + (s->regs.crtc_offset & 0x07ffffff) +
- s->cursor_offset + (scr_y - vga->hw_cursor_y) * 16;
+ srcoff = s->cursor_offset + (scr_y - vga->hw_cursor_y) * 16;
dp = &dp[vga->hw_cursor_x];
h = ((s->regs.crtc_h_total_disp >> 16) + 1) * 8;
for (i = 0; i < 8; i++) {
uint32_t color;
- uint8_t abits = src[i];
- uint8_t xbits = src[i + 8];
+ uint8_t abits = vga_read_byte(vga, srcoff + i);
+ uint8_t xbits = vga_read_byte(vga, srcoff + i + 8);
for (j = 0; j < 8; j++, abits <<= 1, xbits <<= 1) {
if (abits & BIT(7)) {
if (xbits & BIT(7)) {
diff --git a/hw/display/vga-access.h b/hw/display/vga-access.h
new file mode 100644
index 0000000000..c0fbd9958b
--- /dev/null
+++ b/hw/display/vga-access.h
@@ -0,0 +1,49 @@
+/*
+ * QEMU VGA Emulator templates
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+static inline uint8_t vga_read_byte(VGACommonState *vga, uint32_t addr)
+{
+ return vga->vram_ptr[addr & vga->vbe_size_mask];
+}
+
+static inline uint16_t vga_read_word_le(VGACommonState *vga, uint32_t addr)
+{
+ uint32_t offset = addr & vga->vbe_size_mask & ~1;
+ uint16_t *ptr = (uint16_t *)(vga->vram_ptr + offset);
+ return lduw_le_p(ptr);
+}
+
+static inline uint16_t vga_read_word_be(VGACommonState *vga, uint32_t addr)
+{
+ uint32_t offset = addr & vga->vbe_size_mask & ~1;
+ uint16_t *ptr = (uint16_t *)(vga->vram_ptr + offset);
+ return lduw_be_p(ptr);
+}
+
+static inline uint32_t vga_read_dword_le(VGACommonState *vga, uint32_t addr)
+{
+ uint32_t offset = addr & vga->vbe_size_mask & ~3;
+ uint32_t *ptr = (uint32_t *)(vga->vram_ptr + offset);
+ return ldl_le_p(ptr);
+}
diff --git a/hw/display/vga-helpers.h b/hw/display/vga-helpers.h
index 5a752b3f9e..5b6c02faa6 100644
--- a/hw/display/vga-helpers.h
+++ b/hw/display/vga-helpers.h
@@ -21,6 +21,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
+#include "vga-access.h"
static inline void vga_draw_glyph_line(uint8_t *d, uint32_t font_data,
uint32_t xorcol, uint32_t bgcol)
@@ -95,32 +96,6 @@ static void vga_draw_glyph9(uint8_t *d, int linesize,
} while (--h);
}
-static inline uint8_t vga_read_byte(VGACommonState *vga, uint32_t addr)
-{
- return vga->vram_ptr[addr & vga->vbe_size_mask];
-}
-
-static inline uint16_t vga_read_word_le(VGACommonState *vga, uint32_t addr)
-{
- uint32_t offset = addr & vga->vbe_size_mask & ~1;
- uint16_t *ptr = (uint16_t *)(vga->vram_ptr + offset);
- return lduw_le_p(ptr);
-}
-
-static inline uint16_t vga_read_word_be(VGACommonState *vga, uint32_t addr)
-{
- uint32_t offset = addr & vga->vbe_size_mask & ~1;
- uint16_t *ptr = (uint16_t *)(vga->vram_ptr + offset);
- return lduw_be_p(ptr);
-}
-
-static inline uint32_t vga_read_dword_le(VGACommonState *vga, uint32_t addr)
-{
- uint32_t offset = addr & vga->vbe_size_mask & ~3;
- uint32_t *ptr = (uint32_t *)(vga->vram_ptr + offset);
- return ldl_le_p(ptr);
-}
-
/*
* 4 color mode
*/
--
2.27.0

View File

@ -1,91 +0,0 @@
From ac2071c3791b67fc7af78b8ceb320c01ca1b5df7 Mon Sep 17 00:00:00 2001
From: BALATON Zoltan <balaton@eik.bme.hu>
Date: Mon, 6 Apr 2020 22:34:26 +0200
Subject: [PATCH] ati-vga: Fix checks in ati_2d_blt() to avoid crash
In some corner cases (that never happen during normal operation but a
malicious guest could program wrong values) pixman functions were
called with parameters that result in a crash. Fix this and add more
checks to disallow such cases.
Reported-by: Ziming Zhang <ezrakiez@gmail.com>
Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
Message-id: 20200406204029.19559747D5D@zero.eik.bme.hu
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
diff --git a/hw/display/ati_2d.c b/hw/display/ati_2d.c
index 42e82311eb..23a8ae0cd8 100644
--- a/hw/display/ati_2d.c
+++ b/hw/display/ati_2d.c
@@ -53,12 +53,20 @@ void ati_2d_blt(ATIVGAState *s)
s->vga.vbe_start_addr, surface_data(ds), surface_stride(ds),
surface_bits_per_pixel(ds),
(s->regs.dp_mix & GMC_ROP3_MASK) >> 16);
- int dst_x = (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ?
- s->regs.dst_x : s->regs.dst_x + 1 - s->regs.dst_width);
- int dst_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ?
- s->regs.dst_y : s->regs.dst_y + 1 - s->regs.dst_height);
+ unsigned dst_x = (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ?
+ s->regs.dst_x : s->regs.dst_x + 1 - s->regs.dst_width);
+ unsigned dst_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ?
+ s->regs.dst_y : s->regs.dst_y + 1 - s->regs.dst_height);
int bpp = ati_bpp_from_datatype(s);
+ if (!bpp) {
+ qemu_log_mask(LOG_GUEST_ERROR, "Invalid bpp\n");
+ return;
+ }
int dst_stride = DEFAULT_CNTL ? s->regs.dst_pitch : s->regs.default_pitch;
+ if (!dst_stride) {
+ qemu_log_mask(LOG_GUEST_ERROR, "Zero dest pitch\n");
+ return;
+ }
uint8_t *dst_bits = s->vga.vram_ptr + (DEFAULT_CNTL ?
s->regs.dst_offset : s->regs.default_offset);
@@ -82,12 +90,16 @@ void ati_2d_blt(ATIVGAState *s)
switch (s->regs.dp_mix & GMC_ROP3_MASK) {
case ROP3_SRCCOPY:
{
- int src_x = (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ?
- s->regs.src_x : s->regs.src_x + 1 - s->regs.dst_width);
- int src_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ?
- s->regs.src_y : s->regs.src_y + 1 - s->regs.dst_height);
+ unsigned src_x = (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ?
+ s->regs.src_x : s->regs.src_x + 1 - s->regs.dst_width);
+ unsigned src_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ?
+ s->regs.src_y : s->regs.src_y + 1 - s->regs.dst_height);
int src_stride = DEFAULT_CNTL ?
s->regs.src_pitch : s->regs.default_pitch;
+ if (!src_stride) {
+ qemu_log_mask(LOG_GUEST_ERROR, "Zero source pitch\n");
+ return;
+ }
uint8_t *src_bits = s->vga.vram_ptr + (DEFAULT_CNTL ?
s->regs.src_offset : s->regs.default_offset);
@@ -137,8 +149,10 @@ void ati_2d_blt(ATIVGAState *s)
dst_y * surface_stride(ds),
s->regs.dst_height * surface_stride(ds));
}
- s->regs.dst_x += s->regs.dst_width;
- s->regs.dst_y += s->regs.dst_height;
+ s->regs.dst_x = (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ?
+ dst_x + s->regs.dst_width : dst_x);
+ s->regs.dst_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ?
+ dst_y + s->regs.dst_height : dst_y);
break;
}
case ROP3_PATCOPY:
@@ -179,7 +193,8 @@ void ati_2d_blt(ATIVGAState *s)
dst_y * surface_stride(ds),
s->regs.dst_height * surface_stride(ds));
}
- s->regs.dst_y += s->regs.dst_height;
+ s->regs.dst_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ?
+ dst_y + s->regs.dst_height : dst_y);
break;
}
default:
--
2.23.0

View File

@ -1,59 +0,0 @@
From 89554d2f71d4c79c5d8e804d90d74f3985d7ded5 Mon Sep 17 00:00:00 2001
From: Prasad J Pandit <pjp@fedoraproject.org>
Date: Thu, 4 Jun 2020 14:38:30 +0530
Subject: [PATCH 3/9] ati-vga: check mm_index before recursive call
(CVE-2020-13800)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
While accessing VGA registers via ati_mm_read/write routines,
a guest may set 's->regs.mm_index' such that it leads to infinite
recursion. Check mm_index value to avoid such recursion. Log an
error message for wrong values.
Reported-by: Ren Ding <rding@gatech.edu>
Reported-by: Hanqing Zhao <hanqing@gatech.edu>
Reported-by: Yi Ren <c4tren@gmail.com>
Message-id: 20200604090830.33885-1-ppandit@redhat.com
Suggested-by: BALATON Zoltan <balaton@eik.bme.hu>
Suggested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/display/ati.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/hw/display/ati.c b/hw/display/ati.c
index a747c4cc98..5943040416 100644
--- a/hw/display/ati.c
+++ b/hw/display/ati.c
@@ -261,8 +261,11 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size)
if (idx <= s->vga.vram_size - size) {
val = ldn_le_p(s->vga.vram_ptr + idx, size);
}
- } else {
+ } else if (s->regs.mm_index > MM_DATA + 3) {
val = ati_mm_read(s, s->regs.mm_index + addr - MM_DATA, size);
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "ati_mm_read: mm_index too small: %u\n", s->regs.mm_index);
}
break;
case BIOS_0_SCRATCH ... BUS_CNTL - 1:
@@ -472,8 +475,11 @@ static void ati_mm_write(void *opaque, hwaddr addr,
if (idx <= s->vga.vram_size - size) {
stn_le_p(s->vga.vram_ptr + idx, size, data);
}
- } else {
+ } else if (s->regs.mm_index > MM_DATA + 3) {
ati_mm_write(s, s->regs.mm_index + addr - MM_DATA, data, size);
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "ati_mm_write: mm_index too small: %u\n", s->regs.mm_index);
}
break;
case BIOS_0_SCRATCH ... BUS_CNTL - 1:
--
2.25.1

View File

@ -1,37 +0,0 @@
From d0c4e8cc25dc3bfed1659c35fb59b2f0418ba1d5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Volker=20R=C3=BCmelin?= <vr_qemu@t-online.de>
Date: Thu, 19 Dec 2019 21:34:05 +0100
Subject: [PATCH 2/8] audio: fix integer overflow
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Tell the compiler to do a 32bit * 32bit -> 64bit multiplication
because period_ticks is a 64bit variable. The overflow occurs
for audio timer periods larger than 4294967us.
Fixes: be1092afa0 "audio: fix audio timer rate conversion bug"
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Message-id: 8893a235-66a8-8fbe-7d95-862e29da90b1@t-online.de
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
audio/audio.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/audio/audio.c b/audio/audio.c
index 05adf7f..efcb5d4 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -1473,7 +1473,7 @@ static int audio_init(Audiodev *dev)
if (dev->timer_period <= 0) {
s->period_ticks = 1;
} else {
- s->period_ticks = dev->timer_period * SCALE_US;
+ s->period_ticks = dev->timer_period * (int64_t)SCALE_US;
}
e = qemu_add_vm_change_state_handler (audio_vm_change_state_handler, s);
--
1.8.3.1

View File

@ -1,51 +0,0 @@
From 0b66aef5389d622434128fc7db9abd2cd4724b51 Mon Sep 17 00:00:00 2001
From: Kevin Wolf <kwolf@redhat.com>
Date: Wed, 3 Jun 2020 16:03:19 +0100
Subject: [PATCH] backup: Improve error for bdrv_getlength() failure
RH-Author: Kevin Wolf <kwolf@redhat.com>
Message-id: <20200603160325.67506-6-kwolf@redhat.com>
Patchwork-id: 97103
O-Subject: [RHEL-AV-8.2.1 qemu-kvm PATCH v2 05/11] backup: Improve error for bdrv_getlength() failure
Bugzilla: 1778593
RH-Acked-by: Eric Blake <eblake@redhat.com>
RH-Acked-by: Max Reitz <mreitz@redhat.com>
RH-Acked-by: Stefano Garzarella <sgarzare@redhat.com>
bdrv_get_device_name() will be an empty string with modern management
tools that don't use -drive. Use bdrv_get_device_or_node_name() instead
so that the node name is used if the BlockBackend is anonymous.
While at it, start with upper case to make the message consistent with
the rest of the function.
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Message-Id: <20200430142755.315494-3-kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 58226634c4b02af7b10862f7fbd3610a344bfb7f)
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
---
block/backup.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/block/backup.c b/block/backup.c
index 8761f1f9a7..88354dcb32 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -613,8 +613,8 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
len = bdrv_getlength(bs);
if (len < 0) {
- error_setg_errno(errp, -len, "unable to get length for '%s'",
- bdrv_get_device_name(bs));
+ error_setg_errno(errp, -len, "Unable to get length for '%s'",
+ bdrv_get_device_or_node_name(bs));
goto error;
}
--
2.27.0

View File

@ -1,24 +0,0 @@
From 2892a4b1f7dfc75e06d0ce770d44a062b6334eb0 Mon Sep 17 00:00:00 2001
From: Ying Fang <fangying1@huawei.com>
Date: Wed, 15 Apr 2020 17:03:54 +0800
Subject: [PATCH] bios-tables-test: prepare to change ARM virt ACPI DSDT
We will change ARM virt ACPI DSDT table in order to add the cpufreq device,
which use ACPI CPPC to show CPU frequency info to guest.
Signed-off-by: Ying Fang <fangying1@huawei.com>
---
tests/bios-tables-test-allowed-diff.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/tests/bios-tables-test-allowed-diff.h b/tests/bios-tables-test-allowed-diff.h
index dfb8523c..32a401ae 100644
--- a/tests/bios-tables-test-allowed-diff.h
+++ b/tests/bios-tables-test-allowed-diff.h
@@ -1 +1,4 @@
/* List of comma-separated changed AML files to ignore */
+"tests/data/acpi/virt/DSDT",
+"tests/data/acpi/virt/DSDT.memhp",
+"tests/data/acpi/virt/DSDT.numamem",
--
2.23.0

View File

@ -1,59 +0,0 @@
From d9b88f7e0d56feb4d7daa2506e2756fc48e975a1 Mon Sep 17 00:00:00 2001
From: Max Reitz <mreitz@redhat.com>
Date: Fri, 1 Nov 2019 16:25:09 +0100
Subject: [PATCH] block: Add bdrv_co_get_self_request()
Cc: qemu-stable@nongnu.org
Signed-off-by: Max Reitz <mreitz@redhat.com>
Message-id: 20191101152510.11719-3-mreitz@redhat.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
(cherry picked from commit c28107e9e55b11cd35cf3dc2505e3e69d10dcf13)
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
block/io.c | 18 ++++++++++++++++++
include/block/block_int.h | 1 +
2 files changed, 19 insertions(+)
diff --git a/block/io.c b/block/io.c
index d4ceaaa2ce..65b5102714 100644
--- a/block/io.c
+++ b/block/io.c
@@ -721,6 +721,24 @@ static bool is_request_serialising_and_aligned(BdrvTrackedRequest *req)
(req->bytes == req->overlap_bytes);
}
+/**
+ * Return the tracked request on @bs for the current coroutine, or
+ * NULL if there is none.
+ */
+BdrvTrackedRequest *coroutine_fn bdrv_co_get_self_request(BlockDriverState *bs)
+{
+ BdrvTrackedRequest *req;
+ Coroutine *self = qemu_coroutine_self();
+
+ QLIST_FOREACH(req, &bs->tracked_requests, list) {
+ if (req->co == self) {
+ return req;
+ }
+ }
+
+ return NULL;
+}
+
/**
* Round a region to cluster boundaries
*/
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 4465b02242..05ee6b4866 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -964,6 +964,7 @@ void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent);
bool coroutine_fn bdrv_wait_serialising_requests(BdrvTrackedRequest *self);
void bdrv_mark_request_serialising(BdrvTrackedRequest *req, uint64_t align);
+BdrvTrackedRequest *coroutine_fn bdrv_co_get_self_request(BlockDriverState *bs);
int get_tmp_filename(char *filename, int size);
BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size,
--
2.23.0

View File

@ -1,226 +0,0 @@
From 3464a135565d718d0fedadd67081a0f76d81a9c6 Mon Sep 17 00:00:00 2001
From: Jiahui Cen <cenjiahui@huawei.com>
Date: Thu, 21 Jan 2021 15:46:50 +0800
Subject: [PATCH] block: Add error retry param setting
Add "retry_interval" and "retry_timeout" parameter for drive and device
option. These parameter are valid only when werror/rerror=retry.
eg. --drive file=image,rerror=retry,retry_interval=1000,retry_timeout=5000
Signed-off-by: Jiahui Cen <cenjiahui(a)huawei.com>
Signed-off-by: Ying Fang <fangying1(a)huawei.com>
---
block/block-backend.c | 13 +++++++--
blockdev.c | 50 ++++++++++++++++++++++++++++++++++
hw/block/block.c | 10 +++++++
include/hw/block/block.h | 7 ++++-
include/sysemu/block-backend.h | 5 ++++
5 files changed, 81 insertions(+), 4 deletions(-)
diff --git a/block/block-backend.c b/block/block-backend.c
index 0fe99ffe52..2d812e2254 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -31,9 +31,6 @@
static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb);
-/* block backend default retry interval */
-#define BLOCK_BACKEND_DEFAULT_RETRY_INTERVAL 1000
-
typedef struct BlockBackendAioNotifier {
void (*attached_aio_context)(AioContext *new_context, void *opaque);
void (*detach_aio_context)(void *opaque);
@@ -1633,6 +1630,16 @@ void blk_drain_all(void)
bdrv_drain_all_end();
}
+void blk_set_on_error_retry_interval(BlockBackend *blk, int64_t interval)
+{
+ blk->retry_interval = interval;
+}
+
+void blk_set_on_error_retry_timeout(BlockBackend *blk, int64_t timeout)
+{
+ blk->retry_timeout = timeout;
+}
+
static bool blk_error_retry_timeout(BlockBackend *blk)
{
/* No timeout set, infinite retries. */
diff --git a/blockdev.c b/blockdev.c
index 0f49fd290e..99c92b96d2 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -470,6 +470,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
const char *buf;
int bdrv_flags = 0;
int on_read_error, on_write_error;
+ int64_t retry_interval, retry_timeout;
bool account_invalid, account_failed;
bool writethrough, read_only;
BlockBackend *blk;
@@ -565,6 +566,10 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
}
}
+ retry_interval = qemu_opt_get_number(opts, "retry_interval",
+ BLOCK_BACKEND_DEFAULT_RETRY_INTERVAL);
+ retry_timeout = qemu_opt_get_number(opts, "retry_timeout", 0);
+
if (snapshot) {
bdrv_flags |= BDRV_O_SNAPSHOT;
}
@@ -629,6 +634,11 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
blk_set_enable_write_cache(blk, !writethrough);
blk_set_on_error(blk, on_read_error, on_write_error);
+ if (on_read_error == BLOCKDEV_ON_ERROR_RETRY ||
+ on_write_error == BLOCKDEV_ON_ERROR_RETRY) {
+ blk_set_on_error_retry_interval(blk, retry_interval);
+ blk_set_on_error_retry_timeout(blk, retry_timeout);
+ }
if (!monitor_add_blk(blk, id, errp)) {
blk_unref(blk);
@@ -754,6 +764,14 @@ QemuOptsList qemu_legacy_drive_opts = {
.name = "werror",
.type = QEMU_OPT_STRING,
.help = "write error action",
+ },{
+ .name = "retry_interval",
+ .type = QEMU_OPT_NUMBER,
+ .help = "interval for retry action in millisecond",
+ },{
+ .name = "retry_timeout",
+ .type = QEMU_OPT_NUMBER,
+ .help = "timeout for retry action in millisecond",
},{
.name = "copy-on-read",
.type = QEMU_OPT_BOOL,
@@ -776,6 +794,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type,
BlockInterfaceType type;
int max_devs, bus_id, unit_id, index;
const char *werror, *rerror;
+ int64_t retry_interval, retry_timeout;
bool read_only = false;
bool copy_on_read;
const char *filename;
@@ -992,6 +1011,29 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type,
qdict_put_str(bs_opts, "rerror", rerror);
}
+ if (qemu_opt_find(legacy_opts, "retry_interval")) {
+ if ((werror == NULL || strcmp(werror, "retry")) &&
+ (rerror == NULL || strcmp(rerror, "retry"))) {
+ error_setg(errp, "retry_interval is only supported "
+ "by werror/rerror=retry");
+ goto fail;
+ }
+ retry_interval = qemu_opt_get_number(legacy_opts, "retry_interval",
+ BLOCK_BACKEND_DEFAULT_RETRY_INTERVAL);
+ qdict_put_int(bs_opts, "retry_interval", retry_interval);
+ }
+
+ if (qemu_opt_find(legacy_opts, "retry_timeout")) {
+ if ((werror == NULL || strcmp(werror, "retry")) &&
+ (rerror == NULL || strcmp(rerror, "retry"))) {
+ error_setg(errp, "retry_timeout is only supported "
+ "by werror/rerror=retry");
+ goto fail;
+ }
+ retry_timeout = qemu_opt_get_number(legacy_opts, "retry_timeout", 0);
+ qdict_put_int(bs_opts, "retry_timeout", retry_timeout);
+ }
+
/* Actual block device init: Functionality shared with blockdev-add */
blk = blockdev_init(filename, bs_opts, &local_err);
bs_opts = NULL;
@@ -4593,6 +4635,14 @@ QemuOptsList qemu_common_drive_opts = {
.name = "werror",
.type = QEMU_OPT_STRING,
.help = "write error action",
+ },{
+ .name = "retry_interval",
+ .type = QEMU_OPT_NUMBER,
+ .help = "interval for retry action in millisecond",
+ },{
+ .name = "retry_timeout",
+ .type = QEMU_OPT_NUMBER,
+ .help = "timeout for retry action in millisecond",
},{
.name = BDRV_OPT_READ_ONLY,
.type = QEMU_OPT_BOOL,
diff --git a/hw/block/block.c b/hw/block/block.c
index bf56c7612b..56141940ca 100644
--- a/hw/block/block.c
+++ b/hw/block/block.c
@@ -134,6 +134,16 @@ bool blkconf_apply_backend_options(BlockConf *conf, bool readonly,
blk_set_enable_write_cache(blk, wce);
blk_set_on_error(blk, rerror, werror);
+ if (rerror == BLOCKDEV_ON_ERROR_RETRY ||
+ werror == BLOCKDEV_ON_ERROR_RETRY) {
+ if (conf->retry_interval >= 0) {
+ blk_set_on_error_retry_interval(blk, conf->retry_interval);
+ }
+ if (conf->retry_timeout >= 0) {
+ blk_set_on_error_retry_timeout(blk, conf->retry_timeout);
+ }
+ }
+
return true;
}
diff --git a/include/hw/block/block.h b/include/hw/block/block.h
index 607539057a..d12603aabd 100644
--- a/include/hw/block/block.h
+++ b/include/hw/block/block.h
@@ -30,6 +30,8 @@ typedef struct BlockConf {
bool share_rw;
BlockdevOnError rerror;
BlockdevOnError werror;
+ int64_t retry_interval;
+ int64_t retry_timeout;
} BlockConf;
static inline unsigned int get_physical_block_exp(BlockConf *conf)
@@ -71,7 +73,10 @@ static inline unsigned int get_physical_block_exp(BlockConf *conf)
DEFINE_PROP_BLOCKDEV_ON_ERROR("rerror", _state, _conf.rerror, \
BLOCKDEV_ON_ERROR_AUTO), \
DEFINE_PROP_BLOCKDEV_ON_ERROR("werror", _state, _conf.werror, \
- BLOCKDEV_ON_ERROR_AUTO)
+ BLOCKDEV_ON_ERROR_AUTO), \
+ DEFINE_PROP_INT64("retry_interval", _state, _conf.retry_interval, \
+ -1), \
+ DEFINE_PROP_INT64("retry_timeout", _state, _conf.retry_timeout, -1)
/* Backend access helpers */
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
index 58dde446ca..dc10e507ae 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -25,6 +25,9 @@
*/
#include "block/block.h"
+/* block backend default retry interval */
+#define BLOCK_BACKEND_DEFAULT_RETRY_INTERVAL 1000
+
/* Callbacks for block device models */
typedef struct BlockDevOps {
/*
@@ -184,6 +187,8 @@ void blk_inc_in_flight(BlockBackend *blk);
void blk_dec_in_flight(BlockBackend *blk);
void blk_drain(BlockBackend *blk);
void blk_drain_all(void);
+void blk_set_on_error_retry_interval(BlockBackend *blk, int64_t interval);
+void blk_set_on_error_retry_timeout(BlockBackend *blk, int64_t timeout);
void blk_error_retry_reset_timeout(BlockBackend *blk);
void blk_set_on_error(BlockBackend *blk, BlockdevOnError on_read_error,
BlockdevOnError on_write_error);
--
2.27.0

View File

@ -1,118 +0,0 @@
From 6642b2c6fcad2e1099c61b56f4fe78f3180d005e Mon Sep 17 00:00:00 2001
From: Jiahui Cen <cenjiahui@huawei.com>
Date: Thu, 18 Mar 2021 19:45:11 +0800
Subject: [PATCH] block: Add sanity check when setting retry parameters
Add sanity check when setting retry parameters to avoid invalid retry
configuration.
Signed-off-by: Jiahui Cen <cenjiahui@huawei.com>
---
hw/core/qdev-properties.c | 45 ++++++++++++++++++++++++++++++++++++
include/hw/block/block.h | 7 +++---
include/hw/qdev-properties.h | 8 +++++++
3 files changed, 57 insertions(+), 3 deletions(-)
diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
index 709f9e0f9d..2601091f8f 100644
--- a/hw/core/qdev-properties.c
+++ b/hw/core/qdev-properties.c
@@ -628,6 +628,51 @@ const PropertyInfo qdev_prop_blockdev_on_error = {
.set_default_value = set_default_value_enum,
};
+static void set_retry_time(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ DeviceState *dev = DEVICE(obj);
+ Property *prop = opaque;
+ int64_t value, *ptr = qdev_get_prop_ptr(dev, prop);
+ Error *local_err = NULL;
+
+ if (dev->realized) {
+ qdev_prop_set_after_realize(dev, name, errp);
+ return;
+ }
+
+ visit_type_int64(v, name, &value, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ /* value should not be negative */
+ if (value < 0) {
+ error_setg(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
+ dev->id ? : "", name, (int64_t)value, 0L, LONG_MAX);
+ return;
+ }
+
+ *ptr = value;
+}
+
+const PropertyInfo qdev_prop_blockdev_retry_interval = {
+ .name = "BlockdevRetryInterval",
+ .description = "Interval for retry error handling policy",
+ .get = get_int64,
+ .set = set_retry_time,
+ .set_default_value = set_default_value_int,
+};
+
+const PropertyInfo qdev_prop_blockdev_retry_timeout = {
+ .name = "BlockdevRetryTimeout",
+ .description = "Timeout for retry error handling policy",
+ .get = get_int64,
+ .set = set_retry_time,
+ .set_default_value = set_default_value_int,
+};
+
/* --- BIOS CHS translation */
QEMU_BUILD_BUG_ON(sizeof(BiosAtaTranslation) != sizeof(int));
diff --git a/include/hw/block/block.h b/include/hw/block/block.h
index d12603aabd..c5276fec0d 100644
--- a/include/hw/block/block.h
+++ b/include/hw/block/block.h
@@ -74,9 +74,10 @@ static inline unsigned int get_physical_block_exp(BlockConf *conf)
BLOCKDEV_ON_ERROR_AUTO), \
DEFINE_PROP_BLOCKDEV_ON_ERROR("werror", _state, _conf.werror, \
BLOCKDEV_ON_ERROR_AUTO), \
- DEFINE_PROP_INT64("retry_interval", _state, _conf.retry_interval, \
- -1), \
- DEFINE_PROP_INT64("retry_timeout", _state, _conf.retry_timeout, -1)
+ DEFINE_PROP_BLOCKDEV_RETRY_INTERVAL("retry_interval", _state, \
+ _conf.retry_interval, 1000), \
+ DEFINE_PROP_BLOCKDEV_RETRY_TIMEOUT("retry_timeout", _state, \
+ _conf.retry_timeout, 0)
/* Backend access helpers */
diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h
index a22a532eb8..d7742be3bc 100644
--- a/include/hw/qdev-properties.h
+++ b/include/hw/qdev-properties.h
@@ -26,6 +26,8 @@ extern const PropertyInfo qdev_prop_on_off_auto;
extern const PropertyInfo qdev_prop_compress_method;
extern const PropertyInfo qdev_prop_losttickpolicy;
extern const PropertyInfo qdev_prop_blockdev_on_error;
+extern const PropertyInfo qdev_prop_blockdev_retry_interval;
+extern const PropertyInfo qdev_prop_blockdev_retry_timeout;
extern const PropertyInfo qdev_prop_bios_chs_trans;
extern const PropertyInfo qdev_prop_fdc_drive_type;
extern const PropertyInfo qdev_prop_drive;
@@ -215,6 +217,12 @@ extern const PropertyInfo qdev_prop_pcie_link_width;
#define DEFINE_PROP_BLOCKDEV_ON_ERROR(_n, _s, _f, _d) \
DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_blockdev_on_error, \
BlockdevOnError)
+#define DEFINE_PROP_BLOCKDEV_RETRY_INTERVAL(_n, _s, _f, _d) \
+ DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_blockdev_retry_interval, \
+ int64_t)
+#define DEFINE_PROP_BLOCKDEV_RETRY_TIMEOUT(_n, _s, _f, _d) \
+ DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_blockdev_retry_timeout, \
+ int64_t)
#define DEFINE_PROP_BIOS_CHS_TRANS(_n, _s, _f, _d) \
DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_bios_chs_trans, int)
#define DEFINE_PROP_BLOCKSIZE(_n, _s, _f) \
--
2.27.0

View File

@ -1,35 +0,0 @@
From 6a39af8880c18fb3bcbfb715aef909c64286524e Mon Sep 17 00:00:00 2001
From: Eric Blake <eblake@redhat.com>
Date: Fri, 20 Mar 2020 13:36:20 -0500
Subject: [PATCH 04/14] block: Avoid memleak on qcow2 image info failure
If we fail to get bitmap info, we must not leak the encryption info.
Fixes: b8968c875f403
Fixes: Coverity CID 1421894
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <20200320183620.1112123-1-eblake@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
Tested-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
Signed-off-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Peng Liang <liangpeng10@huawei.com>
---
block/qcow2.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/block/qcow2.c b/block/qcow2.c
index 27c54b9905aa..0f4b0940d457 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -4588,6 +4588,7 @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs,
if (local_err) {
error_propagate(errp, local_err);
qapi_free_ImageInfoSpecific(spec_info);
+ qapi_free_QCryptoBlockInfo(encrypt_info);
return NULL;
}
*spec_info->u.qcow2.data = (ImageInfoSpecificQCow2){
--
2.26.2

View File

@ -1,105 +0,0 @@
From e94c1625c0f8155740b1bb7b2c749df759e04526 Mon Sep 17 00:00:00 2001
From: Eric Blake <eblake@redhat.com>
Date: Wed, 10 Jun 2020 18:32:02 -0400
Subject: [PATCH] block: Call attention to truncation of long NBD exports
RH-Author: Eric Blake <eblake@redhat.com>
Message-id: <20200610183202.3780750-3-eblake@redhat.com>
Patchwork-id: 97495
O-Subject: [RHEL-AV-8.2.1 qemu-kvm PATCH 2/2] block: Call attention to truncation of long NBD exports
Bugzilla: 1845384
RH-Acked-by: Sergio Lopez Pascual <slp@redhat.com>
RH-Acked-by: Max Reitz <mreitz@redhat.com>
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
Commit 93676c88 relaxed our NBD client code to request export names up
to the NBD protocol maximum of 4096 bytes without NUL terminator, even
though the block layer can't store anything longer than 4096 bytes
including NUL terminator for display to the user. Since this means
there are some export names where we have to truncate things, we can
at least try to make the truncation a bit more obvious for the user.
Note that in spite of the truncated display name, we can still
communicate with an NBD server using such a long export name; this was
deemed nicer than refusing to even connect to such a server (since the
server may not be under our control, and since determining our actual
length limits gets tricky when nbd://host:port/export and
nbd+unix:///export?socket=/path are themselves variable-length
expansions beyond the export name but count towards the block layer
name length).
Reported-by: Xueqiang Wei <xuwei@redhat.com>
Fixes: https://bugzilla.redhat.com/1843684
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Message-Id: <20200610163741.3745251-3-eblake@redhat.com>
(cherry picked from commit 5c86bdf1208916ece0b87e1151c9b48ee54faa3e)
Signed-off-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
---
block.c | 7 +++++--
block/nbd.c | 21 +++++++++++++--------
2 files changed, 18 insertions(+), 10 deletions(-)
diff --git a/block.c b/block.c
index 38880eabf8..ba36b53a00 100644
--- a/block.c
+++ b/block.c
@@ -6444,8 +6444,11 @@ void bdrv_refresh_filename(BlockDriverState *bs)
pstrcpy(bs->filename, sizeof(bs->filename), bs->exact_filename);
} else {
QString *json = qobject_to_json(QOBJECT(bs->full_open_options));
- snprintf(bs->filename, sizeof(bs->filename), "json:%s",
- qstring_get_str(json));
+ if (snprintf(bs->filename, sizeof(bs->filename), "json:%s",
+ qstring_get_str(json)) >= sizeof(bs->filename)) {
+ /* Give user a hint if we truncated things. */
+ strcpy(bs->filename + sizeof(bs->filename) - 4, "...");
+ }
qobject_unref(json);
}
}
diff --git a/block/nbd.c b/block/nbd.c
index 3977b1efc7..63cdd051ab 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -1714,6 +1714,7 @@ static void nbd_refresh_filename(BlockDriverState *bs)
{
BDRVNBDState *s = bs->opaque;
const char *host = NULL, *port = NULL, *path = NULL;
+ size_t len = 0;
if (s->saddr->type == SOCKET_ADDRESS_TYPE_INET) {
const InetSocketAddress *inet = &s->saddr->u.inet;
@@ -1726,17 +1727,21 @@ static void nbd_refresh_filename(BlockDriverState *bs)
} /* else can't represent as pseudo-filename */
if (path && s->export) {
- snprintf(bs->exact_filename, sizeof(bs->exact_filename),
- "nbd+unix:///%s?socket=%s", s->export, path);
+ len = snprintf(bs->exact_filename, sizeof(bs->exact_filename),
+ "nbd+unix:///%s?socket=%s", s->export, path);
} else if (path && !s->export) {
- snprintf(bs->exact_filename, sizeof(bs->exact_filename),
- "nbd+unix://?socket=%s", path);
+ len = snprintf(bs->exact_filename, sizeof(bs->exact_filename),
+ "nbd+unix://?socket=%s", path);
} else if (host && s->export) {
- snprintf(bs->exact_filename, sizeof(bs->exact_filename),
- "nbd://%s:%s/%s", host, port, s->export);
+ len = snprintf(bs->exact_filename, sizeof(bs->exact_filename),
+ "nbd://%s:%s/%s", host, port, s->export);
} else if (host && !s->export) {
- snprintf(bs->exact_filename, sizeof(bs->exact_filename),
- "nbd://%s:%s", host, port);
+ len = snprintf(bs->exact_filename, sizeof(bs->exact_filename),
+ "nbd://%s:%s", host, port);
+ }
+ if (len > sizeof(bs->exact_filename)) {
+ /* Name is too long to represent exactly, so leave it empty. */
+ bs->exact_filename[0] = '\0';
}
}
--
2.27.0

View File

@ -1,78 +0,0 @@
From ec96b9f64c239736003413d70dc3999ad0b8271c Mon Sep 17 00:00:00 2001
From: Kevin Wolf <kwolf@redhat.com>
Date: Tue, 10 Mar 2020 12:38:29 +0100
Subject: [PATCH] block: Fix cross-AioContext blockdev-snapshot
external_snapshot_prepare() tries to move the overlay to the AioContext
of the backing file (the snapshotted node). However, it's possible that
this doesn't work, but the backing file can instead be moved to the
overlay's AioContext (e.g. opening the backing chain for a mirror
target).
bdrv_append() already indirectly uses bdrv_attach_node(), which takes
care to move nodes to make sure they use the same AioContext and which
tries both directions.
So the problem has a simple fix: Just delete the unnecessary extra
bdrv_try_set_aio_context() call in external_snapshot_prepare() and
instead assert in bdrv_append() that both nodes were indeed moved to the
same AioContext.
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-Id: <20200310113831.27293-6-kwolf@redhat.com>
Tested-by: Peter Krempa <pkrempa@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
block.c | 1 +
blockdev.c | 16 ----------------
2 files changed, 1 insertion(+), 16 deletions(-)
diff --git a/block.c b/block.c
index ba36b53a00..824025f781 100644
--- a/block.c
+++ b/block.c
@@ -4165,6 +4165,7 @@ void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
bdrv_ref(from);
assert(qemu_get_current_aio_context() == qemu_get_aio_context());
+ assert(bdrv_get_aio_context(from) == bdrv_get_aio_context(to));
bdrv_drained_begin(from);
/* Put all parents into @list and calculate their cumulative permissions */
diff --git a/blockdev.c b/blockdev.c
index 79112be2e6..d1a3b6a630 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1578,8 +1578,6 @@ static void external_snapshot_prepare(BlkActionState *common,
DO_UPCAST(ExternalSnapshotState, common, common);
TransactionAction *action = common->action;
AioContext *aio_context;
- AioContext *old_context;
- int ret;
/* 'blockdev-snapshot' and 'blockdev-snapshot-sync' have similar
* purpose but a different set of parameters */
@@ -1719,20 +1717,6 @@ static void external_snapshot_prepare(BlkActionState *common,
goto out;
}
- /* Honor bdrv_try_set_aio_context() context acquisition requirements. */
- old_context = bdrv_get_aio_context(state->new_bs);
- aio_context_release(aio_context);
- aio_context_acquire(old_context);
-
- ret = bdrv_try_set_aio_context(state->new_bs, aio_context, errp);
-
- aio_context_release(old_context);
- aio_context_acquire(aio_context);
-
- if (ret < 0) {
- goto out;
- }
-
/* This removes our old bs and adds the new bs. This is an operation that
* can fail, so we need to do it in .prepare; undoing it for abort is
* always possible. */
--
2.27.0

View File

@ -1,131 +0,0 @@
From 590cff8230749794ba09b38f3ea4eb6b0f2f73b5 Mon Sep 17 00:00:00 2001
From: Max Reitz <mreitz@redhat.com>
Date: Fri, 1 Nov 2019 16:25:08 +0100
Subject: [PATCH] block: Make wait/mark serialising requests public
Make both bdrv_mark_request_serialising() and
bdrv_wait_serialising_requests() public so they can be used from block
drivers.
Cc: qemu-stable@nongnu.org
Signed-off-by: Max Reitz <mreitz@redhat.com>
Message-id: 20191101152510.11719-2-mreitz@redhat.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
(cherry picked from commit 304d9d7f034ff7f5e1e66a65b7f720f63a72c57e)
Conflicts:
block/io.c
*drop context dependency on 1acc3466a2
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
block/io.c | 24 ++++++++++++------------
include/block/block_int.h | 3 +++
2 files changed, 15 insertions(+), 12 deletions(-)
diff --git a/block/io.c b/block/io.c
index 07d2d825c3..d4ceaaa2ce 100644
--- a/block/io.c
+++ b/block/io.c
@@ -694,7 +694,7 @@ static void tracked_request_begin(BdrvTrackedRequest *req,
qemu_co_mutex_unlock(&bs->reqs_lock);
}
-static void mark_request_serialising(BdrvTrackedRequest *req, uint64_t align)
+void bdrv_mark_request_serialising(BdrvTrackedRequest *req, uint64_t align)
{
int64_t overlap_offset = req->offset & ~(align - 1);
uint64_t overlap_bytes = ROUND_UP(req->offset + req->bytes, align)
@@ -784,7 +784,7 @@ void bdrv_dec_in_flight(BlockDriverState *bs)
bdrv_wakeup(bs);
}
-static bool coroutine_fn wait_serialising_requests(BdrvTrackedRequest *self)
+bool coroutine_fn bdrv_wait_serialising_requests(BdrvTrackedRequest *self)
{
BlockDriverState *bs = self->bs;
BdrvTrackedRequest *req;
@@ -1340,14 +1340,14 @@ static int coroutine_fn bdrv_aligned_preadv(BdrvChild *child,
* with each other for the same cluster. For example, in copy-on-read
* it ensures that the CoR read and write operations are atomic and
* guest writes cannot interleave between them. */
- mark_request_serialising(req, bdrv_get_cluster_size(bs));
+ bdrv_mark_request_serialising(req, bdrv_get_cluster_size(bs));
}
/* BDRV_REQ_SERIALISING is only for write operation */
assert(!(flags & BDRV_REQ_SERIALISING));
if (!(flags & BDRV_REQ_NO_SERIALISING)) {
- wait_serialising_requests(req);
+ bdrv_wait_serialising_requests(req);
}
if (flags & BDRV_REQ_COPY_ON_READ) {
@@ -1736,10 +1736,10 @@ bdrv_co_write_req_prepare(BdrvChild *child, int64_t offset, uint64_t bytes,
assert(!(flags & ~BDRV_REQ_MASK));
if (flags & BDRV_REQ_SERIALISING) {
- mark_request_serialising(req, bdrv_get_cluster_size(bs));
+ bdrv_mark_request_serialising(req, bdrv_get_cluster_size(bs));
}
- waited = wait_serialising_requests(req);
+ waited = bdrv_wait_serialising_requests(req);
assert(!waited || !req->serialising ||
is_request_serialising_and_aligned(req));
@@ -1905,8 +1905,8 @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BdrvChild *child,
padding = bdrv_init_padding(bs, offset, bytes, &pad);
if (padding) {
- mark_request_serialising(req, align);
- wait_serialising_requests(req);
+ bdrv_mark_request_serialising(req, align);
+ bdrv_wait_serialising_requests(req);
bdrv_padding_rmw_read(child, req, &pad, true);
@@ -1993,8 +1993,8 @@ int coroutine_fn bdrv_co_pwritev(BdrvChild *child,
}
if (bdrv_pad_request(bs, &qiov, &offset, &bytes, &pad)) {
- mark_request_serialising(&req, align);
- wait_serialising_requests(&req);
+ bdrv_mark_request_serialising(&req, align);
+ bdrv_wait_serialising_requests(&req);
bdrv_padding_rmw_read(child, &req, &pad, false);
}
@@ -3078,7 +3078,7 @@ static int coroutine_fn bdrv_co_copy_range_internal(
/* BDRV_REQ_SERIALISING is only for write operation */
assert(!(read_flags & BDRV_REQ_SERIALISING));
if (!(read_flags & BDRV_REQ_NO_SERIALISING)) {
- wait_serialising_requests(&req);
+ bdrv_wait_serialising_requests(&req);
}
ret = src->bs->drv->bdrv_co_copy_range_from(src->bs,
@@ -3205,7 +3205,7 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset,
* new area, we need to make sure that no write requests are made to it
* concurrently or they might be overwritten by preallocation. */
if (new_bytes) {
- mark_request_serialising(&req, 1);
+ bdrv_mark_request_serialising(&req, 1);
}
if (bs->read_only) {
error_setg(errp, "Image is read-only");
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 3aa1e832a8..4465b02242 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -962,6 +962,9 @@ extern unsigned int bdrv_drain_all_count;
void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent);
void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent);
+bool coroutine_fn bdrv_wait_serialising_requests(BdrvTrackedRequest *self);
+void bdrv_mark_request_serialising(BdrvTrackedRequest *req, uint64_t align);
+
int get_tmp_filename(char *filename, int size);
BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size,
const char *filename);
--
2.23.0

View File

@ -1,31 +0,0 @@
From b353d059bddf4b211c2560e7c123f874ed5c8cf6 Mon Sep 17 00:00:00 2001
From: AlexChen <alex.chen@huawei.com>
Date: Wed, 21 Oct 2020 17:12:52 +0800
Subject: [PATCH] block: Remove unused include
The "qemu-common.h" include is not used, remove it.
Reported-by: Euler Robot <euler.robot@huawei.com>
Signed-off-by: AlexChen <alex.chen@huawei.com>
Message-Id: <5F8FFB94.3030209@huawei.com>
Signed-off-by: Max Reitz <mreitz@redhat.com>
(cherry-picked from commit 3d86af858e)
---
block/dmg-lzfse.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/block/dmg-lzfse.c b/block/dmg-lzfse.c
index 19d25bc646..6798cf4fbf 100644
--- a/block/dmg-lzfse.c
+++ b/block/dmg-lzfse.c
@@ -22,7 +22,6 @@
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "dmg.h"
#include <lzfse.h>
--
2.27.0

View File

@ -1,53 +0,0 @@
From f74edc7c8c85874691daf8801c159874ef45aae0 Mon Sep 17 00:00:00 2001
From: Jiahui Cen <cenjiahui@huawei.com>
Date: Thu, 21 Jan 2021 15:46:47 +0800
Subject: [PATCH] block-backend: Add device specific retry callback
Add retry_request_cb in BlockDevOps to do device specific retry action.
Backend's timer would be registered only when the backend is set 'retry'
on errors and the device supports retry action.
Signed-off-by: Jiahui Cen <cenjiahui(a)huawei.com>
Signed-off-by: Ying Fang <fangying1(a)huawei.com>
---
block/block-backend.c | 8 ++++++++
include/sysemu/block-backend.h | 4 ++++
2 files changed, 12 insertions(+)
diff --git a/block/block-backend.c b/block/block-backend.c
index a9a43b1440..b8f535a5fd 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -958,6 +958,14 @@ void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops,
blk->dev_ops = ops;
blk->dev_opaque = opaque;
+ if ((blk->on_read_error == BLOCKDEV_ON_ERROR_RETRY ||
+ blk->on_write_error == BLOCKDEV_ON_ERROR_RETRY) &&
+ ops->retry_request_cb) {
+ blk->retry_timer = aio_timer_new(blk->ctx, QEMU_CLOCK_REALTIME,
+ SCALE_MS, ops->retry_request_cb,
+ opaque);
+ }
+
/* Are we currently quiesced? Should we enforce this right now? */
if (blk->quiesce_counter && ops->drained_begin) {
ops->drained_begin(opaque);
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
index 733c4957eb..b58dc6bde8 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -66,6 +66,10 @@ typedef struct BlockDevOps {
* Runs when the backend's last drain request ends.
*/
void (*drained_end)(void *opaque);
+ /*
+ * Runs when retrying failed requests.
+ */
+ void (*retry_request_cb)(void *opaque);
} BlockDevOps;
/* This struct is embedded in (the private) BlockBackend struct and contains
--
2.27.0

View File

@ -1,74 +0,0 @@
From c58269c64af18bc2a22bbef8b92e489214272429 Mon Sep 17 00:00:00 2001
From: Jiahui Cen <cenjiahui@huawei.com>
Date: Thu, 21 Jan 2021 15:46:49 +0800
Subject: [PATCH] block-backend: Add timeout support for retry
Retry should only be triggered when timeout is not reached, so let's check
timeout before retry. Device should also reset retry_start_time after
successful retry.
Signed-off-by: Jiahui Cen <cenjiahui(a)huawei.com>
Signed-off-by: Ying Fang <fangying1(a)huawei.com>
---
block/block-backend.c | 25 ++++++++++++++++++++++++-
include/sysemu/block-backend.h | 1 +
2 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/block/block-backend.c b/block/block-backend.c
index 11f8ff4301..0fe99ffe52 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -1633,6 +1633,29 @@ void blk_drain_all(void)
bdrv_drain_all_end();
}
+static bool blk_error_retry_timeout(BlockBackend *blk)
+{
+ /* No timeout set, infinite retries. */
+ if (!blk->retry_timeout) {
+ return false;
+ }
+
+ /* The first time an error occurs. */
+ if (!blk->retry_start_time) {
+ blk->retry_start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
+ return false;
+ }
+
+ return qemu_clock_get_ms(QEMU_CLOCK_REALTIME) > (blk->retry_start_time +
+ blk->retry_timeout);
+}
+
+void blk_error_retry_reset_timeout(BlockBackend *blk)
+{
+ if (blk->retry_timer && blk->retry_start_time)
+ blk->retry_start_time = 0;
+}
+
void blk_set_on_error(BlockBackend *blk, BlockdevOnError on_read_error,
BlockdevOnError on_write_error)
{
@@ -1661,7 +1684,7 @@ BlockErrorAction blk_get_error_action(BlockBackend *blk, bool is_read,
case BLOCKDEV_ON_ERROR_IGNORE:
return BLOCK_ERROR_ACTION_IGNORE;
case BLOCKDEV_ON_ERROR_RETRY:
- return (blk->retry_timer) ?
+ return (blk->retry_timer && !blk_error_retry_timeout(blk)) ?
BLOCK_ERROR_ACTION_RETRY : BLOCK_ERROR_ACTION_REPORT;
case BLOCKDEV_ON_ERROR_AUTO:
default:
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
index b58dc6bde8..58dde446ca 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -184,6 +184,7 @@ void blk_inc_in_flight(BlockBackend *blk);
void blk_dec_in_flight(BlockBackend *blk);
void blk_drain(BlockBackend *blk);
void blk_drain_all(void);
+void blk_error_retry_reset_timeout(BlockBackend *blk);
void blk_set_on_error(BlockBackend *blk, BlockdevOnError on_read_error,
BlockdevOnError on_write_error);
BlockdevOnError blk_get_on_error(BlockBackend *blk, bool is_read);
--
2.27.0

View File

@ -1,42 +0,0 @@
From 8df36cddd1e5e2b3c3598c83a70e8cbb81c26cec Mon Sep 17 00:00:00 2001
From: Jiahui Cen <cenjiahui@huawei.com>
Date: Thu, 21 Jan 2021 15:46:48 +0800
Subject: [PATCH] block-backend: Enable retry action on errors
Enable retry action when backend's retry timer is available. It would
trigger the timer to do device specific retry action.
Signed-off-by: Jiahui Cen <cenjiahui(a)huawei.com>
Signed-off-by: Ying Fang <fangying1(a)huawei.com>
---
block/block-backend.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/block/block-backend.c b/block/block-backend.c
index b8f535a5fd..11f8ff4301 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -1660,6 +1660,9 @@ BlockErrorAction blk_get_error_action(BlockBackend *blk, bool is_read,
return BLOCK_ERROR_ACTION_REPORT;
case BLOCKDEV_ON_ERROR_IGNORE:
return BLOCK_ERROR_ACTION_IGNORE;
+ case BLOCKDEV_ON_ERROR_RETRY:
+ return (blk->retry_timer) ?
+ BLOCK_ERROR_ACTION_RETRY : BLOCK_ERROR_ACTION_REPORT;
case BLOCKDEV_ON_ERROR_AUTO:
default:
abort();
@@ -1707,6 +1710,10 @@ void blk_error_action(BlockBackend *blk, BlockErrorAction action,
qemu_system_vmstop_request_prepare();
send_qmp_error_event(blk, action, is_read, error);
qemu_system_vmstop_request(RUN_STATE_IO_ERROR);
+ } else if (action == BLOCK_ERROR_ACTION_RETRY) {
+ timer_mod(blk->retry_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) +
+ blk->retry_interval);
+ send_qmp_error_event(blk, action, is_read, error);
} else {
send_qmp_error_event(blk, action, is_read, error);
}
--
2.27.0

View File

@ -1,69 +0,0 @@
From 805c2e121e1ad612f63bafec458284554e76d034 Mon Sep 17 00:00:00 2001
From: Jiahui Cen <cenjiahui@huawei.com>
Date: Thu, 21 Jan 2021 15:46:46 +0800
Subject: [PATCH] block-backend: Introduce retry timer
Add a timer to regularly trigger retry on errors.
Signed-off-by: Jiahui Cen <cenjiahui(a)huawei.com>
Signed-off-by: Ying Fang <fangying1(a)huawei.com>
---
block/block-backend.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/block/block-backend.c b/block/block-backend.c
index 0056b526b8..a9a43b1440 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -31,6 +31,9 @@
static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb);
+/* block backend default retry interval */
+#define BLOCK_BACKEND_DEFAULT_RETRY_INTERVAL 1000
+
typedef struct BlockBackendAioNotifier {
void (*attached_aio_context)(AioContext *new_context, void *opaque);
void (*detach_aio_context)(void *opaque);
@@ -88,6 +91,15 @@ struct BlockBackend {
* Accessed with atomic ops.
*/
unsigned int in_flight;
+
+ /* Timer for retry on errors. */
+ QEMUTimer *retry_timer;
+ /* Interval in ms to trigger next retry. */
+ int64_t retry_interval;
+ /* Start time of the first error. Used to check timeout. */
+ int64_t retry_start_time;
+ /* Retry timeout. 0 represents infinite retry. */
+ int64_t retry_timeout;
};
typedef struct BlockBackendAIOCB {
@@ -337,6 +349,11 @@ BlockBackend *blk_new(AioContext *ctx, uint64_t perm, uint64_t shared_perm)
blk->on_read_error = BLOCKDEV_ON_ERROR_REPORT;
blk->on_write_error = BLOCKDEV_ON_ERROR_ENOSPC;
+ blk->retry_timer = NULL;
+ blk->retry_interval = BLOCK_BACKEND_DEFAULT_RETRY_INTERVAL;
+ blk->retry_start_time = 0;
+ blk->retry_timeout = 0;
+
block_acct_init(&blk->stats);
notifier_list_init(&blk->remove_bs_notifiers);
@@ -423,6 +440,10 @@ static void blk_delete(BlockBackend *blk)
QTAILQ_REMOVE(&block_backends, blk, link);
drive_info_del(blk->legacy_dinfo);
block_acct_cleanup(&blk->stats);
+ if (blk->retry_timer) {
+ timer_del(blk->retry_timer);
+ timer_free(blk->retry_timer);
+ }
g_free(blk);
}
--
2.27.0

View File

@ -1,37 +0,0 @@
From da64af4b1e92c345296d937e66136f86027d1ca2 Mon Sep 17 00:00:00 2001
From: Jiahui Cen <cenjiahui@huawei.com>
Date: Thu, 25 Feb 2021 18:03:57 +0800
Subject: [PATCH] block-backend: Stop retrying when draining
Retrying failed requests when draining would make the draining hung. So it
is better not to trigger the retry timer when draining. And after the
virtual devices go back to work, they would retry those queued requests.
Signed-off-by: Jiahui Cen <cenjiahui@huawei.com>
Signed-off-by: Ying Fang <fangying1@huawei.com>
---
block/block-backend.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/block/block-backend.c b/block/block-backend.c
index 2d812e2254..f6c918f1d9 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -1741,9 +1741,11 @@ void blk_error_action(BlockBackend *blk, BlockErrorAction action,
send_qmp_error_event(blk, action, is_read, error);
qemu_system_vmstop_request(RUN_STATE_IO_ERROR);
} else if (action == BLOCK_ERROR_ACTION_RETRY) {
- timer_mod(blk->retry_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) +
- blk->retry_interval);
- send_qmp_error_event(blk, action, is_read, error);
+ if (!blk->quiesce_counter) {
+ timer_mod(blk->retry_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) +
+ blk->retry_interval);
+ send_qmp_error_event(blk, action, is_read, error);
+ }
} else {
send_qmp_error_event(blk, action, is_read, error);
}
--
2.27.0

View File

@ -1,252 +0,0 @@
From e0a0150e671e8129f11aa3df907e444e91711f53 Mon Sep 17 00:00:00 2001
From: John Snow <jsnow@redhat.com>
Date: Mon, 29 Jul 2019 16:35:52 -0400
Subject: [PATCH] block/backup: Add mirror sync mode 'bitmap'
We don't need or want a new sync mode for simple differences in
semantics. Create a new mode simply named "BITMAP" that is designed to
make use of the new Bitmap Sync Mode field.
Because the only bitmap sync mode is 'on-success', this adds no new
functionality to the backup job (yet). The old incremental backup mode
is maintained as a syntactic sugar for sync=bitmap, mode=on-success.
Add all of the plumbing necessary to support this new instruction.
Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Message-id: 20190709232550.10724-6-jsnow@redhat.com
Signed-off-by: John Snow <jsnow@redhat.com>
---
block/backup.c | 20 ++++++++++++--------
block/mirror.c | 6 ++++--
block/replication.c | 2 +-
blockdev.c | 25 +++++++++++++++++++++++--
include/block/block_int.h | 4 +++-
qapi/block-core.json | 21 +++++++++++++++------
6 files changed, 58 insertions(+), 20 deletions(-)
diff --git a/block/backup.c b/block/backup.c
index 88354dcb32..e37eda80cd 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -38,9 +38,9 @@ typedef struct CowRequest {
typedef struct BackupBlockJob {
BlockJob common;
BlockBackend *target;
- /* bitmap for sync=incremental */
BdrvDirtyBitmap *sync_bitmap;
MirrorSyncMode sync_mode;
+ BitmapSyncMode bitmap_mode;
BlockdevOnError on_source_error;
BlockdevOnError on_target_error;
CoRwlock flush_rwlock;
@@ -461,7 +461,7 @@ static int coroutine_fn backup_run(Job *job, Error **errp)
job_progress_set_remaining(job, s->len);
- if (s->sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) {
+ if (s->sync_mode == MIRROR_SYNC_MODE_BITMAP) {
backup_incremental_init_copy_bitmap(s);
} else {
hbitmap_set(s->copy_bitmap, 0, s->len);
@@ -545,6 +545,7 @@ static int64_t backup_calculate_cluster_size(BlockDriverState *target,
BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
BlockDriverState *target, int64_t speed,
MirrorSyncMode sync_mode, BdrvDirtyBitmap *sync_bitmap,
+ BitmapSyncMode bitmap_mode,
bool compress,
BlockdevOnError on_source_error,
BlockdevOnError on_target_error,
@@ -592,10 +593,13 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
return NULL;
}
- if (sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) {
+ /* QMP interface should have handled translating this to bitmap mode */
+ assert(sync_mode != MIRROR_SYNC_MODE_INCREMENTAL);
+
+ if (sync_mode == MIRROR_SYNC_MODE_BITMAP) {
if (!sync_bitmap) {
error_setg(errp, "must provide a valid bitmap name for "
- "\"incremental\" sync mode");
+ "'%s' sync mode", MirrorSyncMode_str(sync_mode));
return NULL;
}
@@ -605,8 +609,8 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
}
} else if (sync_bitmap) {
error_setg(errp,
- "a sync_bitmap was provided to backup_run, "
- "but received an incompatible sync_mode (%s)",
+ "a bitmap was given to backup_job_create, "
+ "but it received an incompatible sync_mode (%s)",
MirrorSyncMode_str(sync_mode));
return NULL;
}
@@ -648,8 +652,8 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
job->on_source_error = on_source_error;
job->on_target_error = on_target_error;
job->sync_mode = sync_mode;
- job->sync_bitmap = sync_mode == MIRROR_SYNC_MODE_INCREMENTAL ?
- sync_bitmap : NULL;
+ job->sync_bitmap = sync_bitmap;
+ job->bitmap_mode = bitmap_mode;
job->compress = compress;
/* Detect image-fleecing (and similar) schemes */
diff --git a/block/mirror.c b/block/mirror.c
index abcf60a961..ccae49a28e 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -1770,8 +1770,10 @@ void mirror_start(const char *job_id, BlockDriverState *bs,
bool is_none_mode;
BlockDriverState *base;
- if (mode == MIRROR_SYNC_MODE_INCREMENTAL) {
- error_setg(errp, "Sync mode 'incremental' not supported");
+ if ((mode == MIRROR_SYNC_MODE_INCREMENTAL) ||
+ (mode == MIRROR_SYNC_MODE_BITMAP)) {
+ error_setg(errp, "Sync mode '%s' not supported",
+ MirrorSyncMode_str(mode));
return;
}
is_none_mode = mode == MIRROR_SYNC_MODE_NONE;
diff --git a/block/replication.c b/block/replication.c
index 23b2993d74..936b2f8b5a 100644
--- a/block/replication.c
+++ b/block/replication.c
@@ -543,7 +543,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
s->backup_job = backup_job_create(
NULL, s->secondary_disk->bs, s->hidden_disk->bs,
- 0, MIRROR_SYNC_MODE_NONE, NULL, false,
+ 0, MIRROR_SYNC_MODE_NONE, NULL, 0, false,
BLOCKDEV_ON_ERROR_REPORT,
BLOCKDEV_ON_ERROR_REPORT, JOB_INTERNAL,
backup_job_completed, bs, NULL, &local_err);
diff --git a/blockdev.c b/blockdev.c
index aa15ed1f00..34c8b651e1 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -3508,12 +3508,31 @@ static BlockJob *do_backup_common(BackupCommon *backup,
return NULL;
}
+ if (backup->sync == MIRROR_SYNC_MODE_INCREMENTAL) {
+ if (backup->has_bitmap_mode &&
+ backup->bitmap_mode != BITMAP_SYNC_MODE_ON_SUCCESS) {
+ error_setg(errp, "Bitmap sync mode must be '%s' "
+ "when using sync mode '%s'",
+ BitmapSyncMode_str(BITMAP_SYNC_MODE_ON_SUCCESS),
+ MirrorSyncMode_str(backup->sync));
+ return NULL;
+ }
+ backup->has_bitmap_mode = true;
+ backup->sync = MIRROR_SYNC_MODE_BITMAP;
+ backup->bitmap_mode = BITMAP_SYNC_MODE_ON_SUCCESS;
+ }
+
if (backup->has_bitmap) {
bmap = bdrv_find_dirty_bitmap(bs, backup->bitmap);
if (!bmap) {
error_setg(errp, "Bitmap '%s' could not be found", backup->bitmap);
return NULL;
}
+ if (!backup->has_bitmap_mode) {
+ error_setg(errp, "Bitmap sync mode must be given "
+ "when providing a bitmap");
+ return NULL;
+ }
if (bdrv_dirty_bitmap_check(bmap, BDRV_BITMAP_DEFAULT, errp)) {
return NULL;
}
@@ -3527,8 +3546,10 @@ static BlockJob *do_backup_common(BackupCommon *backup,
}
job = backup_job_create(backup->job_id, bs, target_bs, backup->speed,
- backup->sync, bmap, backup->compress,
- backup->on_source_error, backup->on_target_error,
+ backup->sync, bmap, backup->bitmap_mode,
+ backup->compress,
+ backup->on_source_error,
+ backup->on_target_error,
job_flags, NULL, NULL, txn, errp);
return job;
}
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 05ee6b4866..76117a761a 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -1152,7 +1152,8 @@ void mirror_start(const char *job_id, BlockDriverState *bs,
* @target: Block device to write to.
* @speed: The maximum speed, in bytes per second, or 0 for unlimited.
* @sync_mode: What parts of the disk image should be copied to the destination.
- * @sync_bitmap: The dirty bitmap if sync_mode is MIRROR_SYNC_MODE_INCREMENTAL.
+ * @sync_bitmap: The dirty bitmap if sync_mode is 'bitmap' or 'incremental'
+ * @bitmap_mode: The bitmap synchronization policy to use.
* @on_source_error: The action to take upon error reading from the source.
* @on_target_error: The action to take upon error writing to the target.
* @creation_flags: Flags that control the behavior of the Job lifetime.
@@ -1168,6 +1169,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
BlockDriverState *target, int64_t speed,
MirrorSyncMode sync_mode,
BdrvDirtyBitmap *sync_bitmap,
+ BitmapSyncMode bitmap_mode,
bool compress,
BlockdevOnError on_source_error,
BlockdevOnError on_target_error,
diff --git a/qapi/block-core.json b/qapi/block-core.json
index b8d12a4951..97baff3a8c 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1127,12 +1127,15 @@
#
# @none: only copy data written from now on
#
-# @incremental: only copy data described by the dirty bitmap. Since: 2.4
+# @incremental: only copy data described by the dirty bitmap. (since: 2.4)
+#
+# @bitmap: only copy data described by the dirty bitmap. (since: 4.2)
+# Behavior on completion is determined by the BitmapSyncMode.
#
# Since: 1.3
##
{ 'enum': 'MirrorSyncMode',
- 'data': ['top', 'full', 'none', 'incremental'] }
+ 'data': ['top', 'full', 'none', 'incremental', 'bitmap'] }
##
# @BitmapSyncMode:
@@ -1343,9 +1346,14 @@
# @speed: the maximum speed, in bytes per second. The default is 0,
# for unlimited.
#
-# @bitmap: the name of dirty bitmap if sync is "incremental".
-# Must be present if sync is "incremental", must NOT be present
-# otherwise. (Since 2.4 (drive-backup), 3.1 (blockdev-backup))
+# @bitmap: the name of a dirty bitmap if sync is "bitmap" or "incremental".
+# Must be present if sync is "bitmap" or "incremental".
+# Must not be present otherwise.
+# (Since 2.4 (drive-backup), 3.1 (blockdev-backup))
+#
+# @bitmap-mode: Specifies the type of data the bitmap should contain after
+# the operation concludes. Must be present if sync is "bitmap".
+# Must NOT be present otherwise. (Since 4.2)
#
# @compress: true to compress data, if the target format supports it.
# (default: false) (since 2.8)
@@ -1380,7 +1388,8 @@
{ 'struct': 'BackupCommon',
'data': { '*job-id': 'str', 'device': 'str',
'sync': 'MirrorSyncMode', '*speed': 'int',
- '*bitmap': 'str', '*compress': 'bool',
+ '*bitmap': 'str', '*bitmap-mode': 'BitmapSyncMode',
+ '*compress': 'bool',
'*on-source-error': 'BlockdevOnError',
'*on-target-error': 'BlockdevOnError',
'*auto-finalize': 'bool', '*auto-dismiss': 'bool' } }
--
2.27.0

View File

@ -1,59 +0,0 @@
From 98ed0f915cf3335768ed84ee5dfa54f4e99aaf00 Mon Sep 17 00:00:00 2001
From: John Snow <jsnow@redhat.com>
Date: Mon, 29 Jul 2019 16:35:53 -0400
Subject: [PATCH] block/backup: add 'never' policy to bitmap sync mode
This adds a "never" policy for bitmap synchronization. Regardless of if
the job succeeds or fails, we never update the bitmap. This can be used
to perform differential backups, or simply to avoid the job modifying a
bitmap.
Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Message-id: 20190709232550.10724-7-jsnow@redhat.com
Signed-off-by: John Snow <jsnow@redhat.com>
---
block/backup.c | 7 +++++--
qapi/block-core.json | 5 ++++-
2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/block/backup.c b/block/backup.c
index e37eda80cd..84a56337ac 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -274,8 +274,11 @@ static void backup_cleanup_sync_bitmap(BackupBlockJob *job, int ret)
BdrvDirtyBitmap *bm;
BlockDriverState *bs = blk_bs(job->common.blk);
- if (ret < 0) {
- /* Merge the successor back into the parent, delete nothing. */
+ if (ret < 0 || job->bitmap_mode == BITMAP_SYNC_MODE_NEVER) {
+ /*
+ * Failure, or we don't want to synchronize the bitmap.
+ * Merge the successor back into the parent, delete nothing.
+ */
bm = bdrv_reclaim_dirty_bitmap(bs, job->sync_bitmap, NULL);
assert(bm);
} else {
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 97baff3a8c..48a0bfab63 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1146,10 +1146,13 @@
# @on-success: The bitmap is only synced when the operation is successful.
# This is the behavior always used for 'INCREMENTAL' backups.
#
+# @never: The bitmap is never synchronized with the operation, and is
+# treated solely as a read-only manifest of blocks to copy.
+#
# Since: 4.2
##
{ 'enum': 'BitmapSyncMode',
- 'data': ['on-success'] }
+ 'data': ['on-success', 'never'] }
##
# @MirrorCopyMode:
--
2.27.0

View File

@ -1,83 +0,0 @@
From 3cf14b9a7daf0a40eb2af7a86e67cb05f6d2bea6 Mon Sep 17 00:00:00 2001
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Date: Tue, 30 Jul 2019 19:32:49 +0300
Subject: [PATCH] block/backup: deal with zero detection
We have detect_zeroes option, so at least for blockdev-backup user
should define it if zero-detection is needed. For drive-backup leave
detection enabled by default but do it through existing option instead
of open-coding.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: John Snow <jsnow@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Message-id: 20190730163251.755248-2-vsementsov@virtuozzo.com
Signed-off-by: John Snow <jsnow@redhat.com>
---
block/backup.c | 15 ++++++---------
blockdev.c | 8 ++++----
2 files changed, 10 insertions(+), 13 deletions(-)
diff --git a/block/backup.c b/block/backup.c
index cc19643b47..6023573299 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -110,7 +110,10 @@ static int coroutine_fn backup_cow_with_bounce_buffer(BackupBlockJob *job,
BlockBackend *blk = job->common.blk;
int nbytes;
int read_flags = is_write_notifier ? BDRV_REQ_NO_SERIALISING : 0;
- int write_flags = job->serialize_target_writes ? BDRV_REQ_SERIALISING : 0;
+ int write_flags =
+ (job->serialize_target_writes ? BDRV_REQ_SERIALISING : 0) |
+ (job->compress ? BDRV_REQ_WRITE_COMPRESSED : 0);
+
assert(QEMU_IS_ALIGNED(start, job->cluster_size));
hbitmap_reset(job->copy_bitmap, start, job->cluster_size);
@@ -128,14 +131,8 @@ static int coroutine_fn backup_cow_with_bounce_buffer(BackupBlockJob *job,
goto fail;
}
- if (buffer_is_zero(*bounce_buffer, nbytes)) {
- ret = blk_co_pwrite_zeroes(job->target, start,
- nbytes, write_flags | BDRV_REQ_MAY_UNMAP);
- } else {
- ret = blk_co_pwrite(job->target, start,
- nbytes, *bounce_buffer, write_flags |
- (job->compress ? BDRV_REQ_WRITE_COMPRESSED : 0));
- }
+ ret = blk_co_pwrite(job->target, start, nbytes, *bounce_buffer,
+ write_flags);
if (ret < 0) {
trace_backup_do_cow_write_fail(job, start, ret);
if (error_is_read) {
diff --git a/blockdev.c b/blockdev.c
index 0a71a15fa2..94e5aee30b 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -3572,7 +3572,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
BlockDriverState *source = NULL;
BlockJob *job = NULL;
AioContext *aio_context;
- QDict *options = NULL;
+ QDict *options;
Error *local_err = NULL;
int flags;
int64_t size;
@@ -3645,10 +3645,10 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
goto out;
}
+ options = qdict_new();
+ qdict_put_str(options, "discard", "unmap");
+ qdict_put_str(options, "detect-zeroes", "unmap");
if (backup->format) {
- if (!options) {
- options = qdict_new();
- }
qdict_put_str(options, "driver", backup->format);
}
--
2.27.0

View File

@ -1,35 +0,0 @@
From adb934c8d2cfd8b920e69712f07a8fb9399fdc2d Mon Sep 17 00:00:00 2001
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Date: Fri, 20 Sep 2019 17:20:43 +0300
Subject: [PATCH] block/backup: fix backup_cow_with_offload for last cluster
We shouldn't try to copy bytes beyond EOF. Fix it.
Fixes: 9ded4a0114968e
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: John Snow <jsnow@redhat.com>
Message-id: 20190920142056.12778-3-vsementsov@virtuozzo.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
(cherry picked from commit 1048ddf0a32dcdaa952e581bd503d49adad527cc)
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
block/backup.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/block/backup.c b/block/backup.c
index 8119d3c..55736ea 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -169,7 +169,7 @@ static int coroutine_fn backup_cow_with_offload(BackupBlockJob *job,
assert(QEMU_IS_ALIGNED(job->copy_range_size, job->cluster_size));
assert(QEMU_IS_ALIGNED(start, job->cluster_size));
- nbytes = MIN(job->copy_range_size, end - start);
+ nbytes = MIN(job->copy_range_size, MIN(end, job->len) - start);
nr_clusters = DIV_ROUND_UP(nbytes, job->cluster_size);
hbitmap_reset(job->copy_bitmap, start, job->cluster_size * nr_clusters);
ret = blk_co_copy_range(blk, start, job->target, start, nbytes,
--
1.8.3.1

View File

@ -1,51 +0,0 @@
From bad8a640a29f16b4d333673577b06880894766e1 Mon Sep 17 00:00:00 2001
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Date: Fri, 20 Sep 2019 17:20:42 +0300
Subject: [PATCH] block/backup: fix max_transfer handling for copy_range
Of course, QEMU_ALIGN_UP is a typo, it should be QEMU_ALIGN_DOWN, as we
are trying to find aligned size which satisfy both source and target.
Also, don't ignore too small max_transfer. In this case seems safer to
disable copy_range.
Fixes: 9ded4a0114968e
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Message-id: 20190920142056.12778-2-vsementsov@virtuozzo.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
(cherry picked from commit 981fb5810aa3f68797ee6e261db338bd78857614)
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
block/backup.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/block/backup.c b/block/backup.c
index 381659d..8119d3c 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -666,12 +666,19 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
job->cluster_size = cluster_size;
job->copy_bitmap = copy_bitmap;
copy_bitmap = NULL;
- job->use_copy_range = !compress; /* compression isn't supported for it */
job->copy_range_size = MIN_NON_ZERO(blk_get_max_transfer(job->common.blk),
blk_get_max_transfer(job->target));
- job->copy_range_size = MAX(job->cluster_size,
- QEMU_ALIGN_UP(job->copy_range_size,
- job->cluster_size));
+ job->copy_range_size = QEMU_ALIGN_DOWN(job->copy_range_size,
+ job->cluster_size);
+ /*
+ * Set use_copy_range, consider the following:
+ * 1. Compression is not supported for copy_range.
+ * 2. copy_range does not respect max_transfer (it's a TODO), so we factor
+ * that in here. If max_transfer is smaller than the job->cluster_size,
+ * we do not use copy_range (in that case it's zero after aligning down
+ * above).
+ */
+ job->use_copy_range = !compress && job->copy_range_size > 0;
/* Required permissions are already taken with target's blk_new() */
block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL,
--
1.8.3.1

View File

@ -1,73 +0,0 @@
From 9cc9e9657aad126502183fa4ceb9b962b55471cb Mon Sep 17 00:00:00 2001
From: John Snow <jsnow@redhat.com>
Date: Mon, 29 Jul 2019 16:35:55 -0400
Subject: [PATCH] block/backup: hoist bitmap check into QMP interface
This is nicer to do in the unified QMP interface that we have now,
because it lets us use the right terminology back at the user.
Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Message-id: 20190716000117.25219-5-jsnow@redhat.com
Signed-off-by: John Snow <jsnow@redhat.com>
---
block/backup.c | 13 ++++---------
blockdev.c | 10 ++++++++++
2 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/block/backup.c b/block/backup.c
index 59ac2c0396..cc19643b47 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -565,6 +565,10 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
assert(bs);
assert(target);
+ /* QMP interface protects us from these cases */
+ assert(sync_mode != MIRROR_SYNC_MODE_INCREMENTAL);
+ assert(sync_bitmap || sync_mode != MIRROR_SYNC_MODE_BITMAP);
+
if (bs == target) {
error_setg(errp, "Source and target cannot be the same");
return NULL;
@@ -596,16 +600,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
return NULL;
}
- /* QMP interface should have handled translating this to bitmap mode */
- assert(sync_mode != MIRROR_SYNC_MODE_INCREMENTAL);
-
if (sync_mode == MIRROR_SYNC_MODE_BITMAP) {
- if (!sync_bitmap) {
- error_setg(errp, "must provide a valid bitmap name for "
- "'%s' sync mode", MirrorSyncMode_str(sync_mode));
- return NULL;
- }
-
/* If we need to write to this bitmap, check that we can: */
if (bitmap_mode != BITMAP_SYNC_MODE_NEVER &&
bdrv_dirty_bitmap_check(sync_bitmap, BDRV_BITMAP_DEFAULT, errp)) {
diff --git a/blockdev.c b/blockdev.c
index efb69d343a..0a71a15fa2 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -3508,6 +3508,16 @@ static BlockJob *do_backup_common(BackupCommon *backup,
return NULL;
}
+ if ((backup->sync == MIRROR_SYNC_MODE_BITMAP) ||
+ (backup->sync == MIRROR_SYNC_MODE_INCREMENTAL)) {
+ /* done before desugaring 'incremental' to print the right message */
+ if (!backup->has_bitmap) {
+ error_setg(errp, "must provide a valid bitmap name for "
+ "'%s' sync mode", MirrorSyncMode_str(backup->sync));
+ return NULL;
+ }
+ }
+
if (backup->sync == MIRROR_SYNC_MODE_INCREMENTAL) {
if (backup->has_bitmap_mode &&
backup->bitmap_mode != BITMAP_SYNC_MODE_ON_SUCCESS) {
--
2.27.0

View File

@ -1,51 +0,0 @@
From 801e9452bc80a38ee26fe12ba42356851acd6a9e Mon Sep 17 00:00:00 2001
From: John Snow <jsnow@redhat.com>
Date: Mon, 29 Jul 2019 16:35:54 -0400
Subject: [PATCH] block/backup: loosen restriction on readonly bitmaps
With the "never" sync policy, we actually can utilize readonly bitmaps
now. Loosen the check at the QMP level, and tighten it based on
provided arguments down at the job creation level instead.
Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Message-id: 20190709232550.10724-19-jsnow@redhat.com
Signed-off-by: John Snow <jsnow@redhat.com>
---
block/backup.c | 6 ++++++
blockdev.c | 2 +-
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/block/backup.c b/block/backup.c
index 84a56337ac..59ac2c0396 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -606,6 +606,12 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
return NULL;
}
+ /* If we need to write to this bitmap, check that we can: */
+ if (bitmap_mode != BITMAP_SYNC_MODE_NEVER &&
+ bdrv_dirty_bitmap_check(sync_bitmap, BDRV_BITMAP_DEFAULT, errp)) {
+ return NULL;
+ }
+
/* Create a new bitmap, and freeze/disable this one. */
if (bdrv_dirty_bitmap_create_successor(bs, sync_bitmap, errp) < 0) {
return NULL;
diff --git a/blockdev.c b/blockdev.c
index 34c8b651e1..efb69d343a 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -3533,7 +3533,7 @@ static BlockJob *do_backup_common(BackupCommon *backup,
"when providing a bitmap");
return NULL;
}
- if (bdrv_dirty_bitmap_check(bmap, BDRV_BITMAP_DEFAULT, errp)) {
+ if (bdrv_dirty_bitmap_check(bmap, BDRV_BITMAP_ALLOW_RO, errp)) {
return NULL;
}
}
--
2.27.0

View File

@ -1,116 +0,0 @@
From 3754525eb383f91869634766ccd041cfe40bbf17 Mon Sep 17 00:00:00 2001
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Date: Mon, 16 Mar 2020 09:06:30 +0300
Subject: [PATCH 05/14] block: bdrv_set_backing_bs: fix use-after-free
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
There is a use-after-free possible: bdrv_unref_child() leaves
bs->backing freed but not NULL. bdrv_attach_child may produce nested
polling loop due to drain, than access of freed pointer is possible.
I've produced the following crash on 30 iotest with modified code. It
does not reproduce on master, but still seems possible:
#0 __strcmp_avx2 () at /lib64/libc.so.6
#1 bdrv_backing_overridden (bs=0x55c9d3cc2060) at block.c:6350
#2 bdrv_refresh_filename (bs=0x55c9d3cc2060) at block.c:6404
#3 bdrv_backing_attach (c=0x55c9d48e5520) at block.c:1063
#4 bdrv_replace_child_noperm
(child=child@entry=0x55c9d48e5520,
new_bs=new_bs@entry=0x55c9d3cc2060) at block.c:2290
#5 bdrv_replace_child
(child=child@entry=0x55c9d48e5520,
new_bs=new_bs@entry=0x55c9d3cc2060) at block.c:2320
#6 bdrv_root_attach_child
(child_bs=child_bs@entry=0x55c9d3cc2060,
child_name=child_name@entry=0x55c9d241d478 "backing",
child_role=child_role@entry=0x55c9d26ecee0 <child_backing>,
ctx=<optimized out>, perm=<optimized out>, shared_perm=21,
opaque=0x55c9d3c5a3d0, errp=0x7ffd117108e0) at block.c:2424
#7 bdrv_attach_child
(parent_bs=parent_bs@entry=0x55c9d3c5a3d0,
child_bs=child_bs@entry=0x55c9d3cc2060,
child_name=child_name@entry=0x55c9d241d478 "backing",
child_role=child_role@entry=0x55c9d26ecee0 <child_backing>,
errp=errp@entry=0x7ffd117108e0) at block.c:5876
#8 in bdrv_set_backing_hd
(bs=bs@entry=0x55c9d3c5a3d0,
backing_hd=backing_hd@entry=0x55c9d3cc2060,
errp=errp@entry=0x7ffd117108e0)
at block.c:2576
#9 stream_prepare (job=0x55c9d49d84a0) at block/stream.c:150
#10 job_prepare (job=0x55c9d49d84a0) at job.c:761
#11 job_txn_apply (txn=<optimized out>, fn=<optimized out>) at
job.c:145
#12 job_do_finalize (job=0x55c9d49d84a0) at job.c:778
#13 job_completed_txn_success (job=0x55c9d49d84a0) at job.c:832
#14 job_completed (job=0x55c9d49d84a0) at job.c:845
#15 job_completed (job=0x55c9d49d84a0) at job.c:836
#16 job_exit (opaque=0x55c9d49d84a0) at job.c:864
#17 aio_bh_call (bh=0x55c9d471a160) at util/async.c:117
#18 aio_bh_poll (ctx=ctx@entry=0x55c9d3c46720) at util/async.c:117
#19 aio_poll (ctx=ctx@entry=0x55c9d3c46720,
blocking=blocking@entry=true)
at util/aio-posix.c:728
#20 bdrv_parent_drained_begin_single (poll=true, c=0x55c9d3d558f0)
at block/io.c:121
#21 bdrv_parent_drained_begin_single (c=c@entry=0x55c9d3d558f0,
poll=poll@entry=true)
at block/io.c:114
#22 bdrv_replace_child_noperm
(child=child@entry=0x55c9d3d558f0,
new_bs=new_bs@entry=0x55c9d3d27300) at block.c:2258
#23 bdrv_replace_child
(child=child@entry=0x55c9d3d558f0,
new_bs=new_bs@entry=0x55c9d3d27300) at block.c:2320
#24 bdrv_root_attach_child
(child_bs=child_bs@entry=0x55c9d3d27300,
child_name=child_name@entry=0x55c9d241d478 "backing",
child_role=child_role@entry=0x55c9d26ecee0 <child_backing>,
ctx=<optimized out>, perm=<optimized out>, shared_perm=21,
opaque=0x55c9d3cc2060, errp=0x7ffd11710c60) at block.c:2424
#25 bdrv_attach_child
(parent_bs=parent_bs@entry=0x55c9d3cc2060,
child_bs=child_bs@entry=0x55c9d3d27300,
child_name=child_name@entry=0x55c9d241d478 "backing",
child_role=child_role@entry=0x55c9d26ecee0 <child_backing>,
errp=errp@entry=0x7ffd11710c60) at block.c:5876
#26 bdrv_set_backing_hd
(bs=bs@entry=0x55c9d3cc2060,
backing_hd=backing_hd@entry=0x55c9d3d27300,
errp=errp@entry=0x7ffd11710c60)
at block.c:2576
#27 stream_prepare (job=0x55c9d495ead0) at block/stream.c:150
...
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Message-Id: <20200316060631.30052-2-vsementsov@virtuozzo.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Reviewed-by: John Snow <jsnow@redhat.com>
Signed-off-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Peng Liang <liangpeng10@huawei.com>
---
block.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/block.c b/block.c
index 29e504b86aff..e834102c87f7 100644
--- a/block.c
+++ b/block.c
@@ -2549,10 +2549,10 @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
if (bs->backing) {
bdrv_unref_child(bs, bs->backing);
+ bs->backing = NULL;
}
if (!backing_hd) {
- bs->backing = NULL;
goto out;
}
--
2.26.2

View File

@ -1,95 +0,0 @@
From 088f1e8fd9e790bc5766bd43af134230abcff6dd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= <philmd@redhat.com>
Date: Thu, 12 Sep 2019 00:08:49 +0200
Subject: [PATCH] block/create: Do not abort if a block driver is not available
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The 'blockdev-create' QMP command was introduced as experimental
feature in commit b0292b851b8, using the assert() debug call.
It got promoted to 'stable' command in 3fb588a0f2c, but the
assert call was not removed.
Some block drivers are optional, and bdrv_find_format() might
return a NULL value, triggering the assertion.
Stable code is not expected to abort, so return an error instead.
This is easily reproducible when libnfs is not installed:
./configure
[...]
module support no
Block whitelist (rw)
Block whitelist (ro)
libiscsi support yes
libnfs support no
[...]
Start QEMU:
$ qemu-system-x86_64 -S -qmp unix:/tmp/qemu.qmp,server,nowait
Send the 'blockdev-create' with the 'nfs' driver:
$ ( cat << 'EOF'
{'execute': 'qmp_capabilities'}
{'execute': 'blockdev-create', 'arguments': {'job-id': 'x', 'options': {'size': 0, 'driver': 'nfs', 'location': {'path': '/', 'server': {'host': '::1', 'type': 'inet'}}}}, 'id': 'x'}
EOF
) | socat STDIO UNIX:/tmp/qemu.qmp
{"QMP": {"version": {"qemu": {"micro": 50, "minor": 1, "major": 4}, "package": "v4.1.0-733-g89ea03a7dc"}, "capabilities": ["oob"]}}
{"return": {}}
QEMU crashes:
$ gdb qemu-system-x86_64 core
Program received signal SIGSEGV, Segmentation fault.
(gdb) bt
#0 0x00007ffff510957f in raise () at /lib64/libc.so.6
#1 0x00007ffff50f3895 in abort () at /lib64/libc.so.6
#2 0x00007ffff50f3769 in _nl_load_domain.cold.0 () at /lib64/libc.so.6
#3 0x00007ffff5101a26 in .annobin_assert.c_end () at /lib64/libc.so.6
#4 0x0000555555d7e1f1 in qmp_blockdev_create (job_id=0x555556baee40 "x", options=0x555557666610, errp=0x7fffffffc770) at block/create.c:69
#5 0x0000555555c96b52 in qmp_marshal_blockdev_create (args=0x7fffdc003830, ret=0x7fffffffc7f8, errp=0x7fffffffc7f0) at qapi/qapi-commands-block-core.c:1314
#6 0x0000555555deb0a0 in do_qmp_dispatch (cmds=0x55555645de70 <qmp_commands>, request=0x7fffdc005c70, allow_oob=false, errp=0x7fffffffc898) at qapi/qmp-dispatch.c:131
#7 0x0000555555deb2a1 in qmp_dispatch (cmds=0x55555645de70 <qmp_commands>, request=0x7fffdc005c70, allow_oob=false) at qapi/qmp-dispatch.c:174
With this patch applied, QEMU returns a QMP error:
{'execute': 'blockdev-create', 'arguments': {'job-id': 'x', 'options': {'size': 0, 'driver': 'nfs', 'location': {'path': '/', 'server': {'host': '::1', 'type': 'inet'}}}}, 'id': 'x'}
{"id": "x", "error": {"class": "GenericError", "desc": "Block driver 'nfs' not found or not supported"}}
Cc: qemu-stable@nongnu.org
Reported-by: Xu Tian <xutian@redhat.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: John Snow <jsnow@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit d90d5cae2b10efc0e8d0b3cc91ff16201853d3ba)
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
block/create.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/block/create.c b/block/create.c
index 95341219ef..de5e97bb18 100644
--- a/block/create.c
+++ b/block/create.c
@@ -63,9 +63,13 @@ void qmp_blockdev_create(const char *job_id, BlockdevCreateOptions *options,
const char *fmt = BlockdevDriver_str(options->driver);
BlockDriver *drv = bdrv_find_format(fmt);
+ if (!drv) {
+ error_setg(errp, "Block driver '%s' not found or not supported", fmt);
+ return;
+ }
+
/* If the driver is in the schema, we know that it exists. But it may not
* be whitelisted. */
- assert(drv);
if (bdrv_uses_whitelist() && !bdrv_is_whitelisted(drv, false)) {
error_setg(errp, "Driver is not whitelisted");
return;
--
2.23.0

View File

@ -1,54 +0,0 @@
From ae2c6d13c4ac625a2c6b217a7f6a17506a2b26e5 Mon Sep 17 00:00:00 2001
From: Richard Jones <rjones@redhat.com>
Date: Thu, 28 May 2020 14:27:37 +0100
Subject: [PATCH] block/curl: HTTP header field names are case insensitive
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
RH-Author: Richard Jones <rjones@redhat.com>
Message-id: <20200528142737.17318-3-rjones@redhat.com>
Patchwork-id: 96895
O-Subject: [RHEL-AV-8.2.1 qemu-kvm PATCH 2/2] block/curl: HTTP header field names are case insensitive
Bugzilla: 1841038
RH-Acked-by: Eric Blake <eblake@redhat.com>
RH-Acked-by: Max Reitz <mreitz@redhat.com>
RH-Acked-by: Philippe Mathieu-Daudé <philmd@redhat.com>
From: David Edmondson <david.edmondson@oracle.com>
RFC 7230 section 3.2 indicates that HTTP header field names are case
insensitive.
Signed-off-by: David Edmondson <david.edmondson@oracle.com>
Message-Id: <20200224101310.101169-3-david.edmondson@oracle.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Max Reitz <mreitz@redhat.com>
(cherry picked from commit 69032253c33ae1774233c63cedf36d32242a85fc)
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
---
block/curl.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/block/curl.c b/block/curl.c
index bfabe7eabd..a298fcc591 100644
--- a/block/curl.c
+++ b/block/curl.c
@@ -214,11 +214,12 @@ static size_t curl_header_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
size_t realsize = size * nmemb;
const char *header = (char *)ptr;
const char *end = header + realsize;
- const char *accept_ranges = "Accept-Ranges:";
+ const char *accept_ranges = "accept-ranges:";
const char *bytes = "bytes";
if (realsize >= strlen(accept_ranges)
- && strncmp(header, accept_ranges, strlen(accept_ranges)) == 0) {
+ && g_ascii_strncasecmp(header, accept_ranges,
+ strlen(accept_ranges)) == 0) {
char *p = strchr(header, ':') + 1;
--
2.27.0

View File

@ -1,75 +0,0 @@
From c8fd37c06fd24d1242629dda329dd16bea20f319 Mon Sep 17 00:00:00 2001
From: Richard Jones <rjones@redhat.com>
Date: Thu, 28 May 2020 14:27:36 +0100
Subject: [PATCH] block/curl: HTTP header fields allow whitespace around values
RH-Author: Richard Jones <rjones@redhat.com>
Message-id: <20200528142737.17318-2-rjones@redhat.com>
Patchwork-id: 96894
O-Subject: [RHEL-AV-8.2.1 qemu-kvm PATCH 1/2] block/curl: HTTP header fields allow whitespace around values
Bugzilla: 1841038
RH-Acked-by: Eric Blake <eblake@redhat.com>
RH-Acked-by: Max Reitz <mreitz@redhat.com>
RH-Acked-by: Danilo de Paula <ddepaula@redhat.com>
From: David Edmondson <david.edmondson@oracle.com>
RFC 7230 section 3.2 indicates that whitespace is permitted between
the field name and field value and after the field value.
Signed-off-by: David Edmondson <david.edmondson@oracle.com>
Message-Id: <20200224101310.101169-2-david.edmondson@oracle.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Max Reitz <mreitz@redhat.com>
(cherry picked from commit 7788a319399f17476ff1dd43164c869e320820a2)
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
---
block/curl.c | 31 +++++++++++++++++++++++++++----
1 file changed, 27 insertions(+), 4 deletions(-)
diff --git a/block/curl.c b/block/curl.c
index d4c8e94f3e..bfabe7eabd 100644
--- a/block/curl.c
+++ b/block/curl.c
@@ -212,11 +212,34 @@ static size_t curl_header_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
{
BDRVCURLState *s = opaque;
size_t realsize = size * nmemb;
- const char *accept_line = "Accept-Ranges: bytes";
+ const char *header = (char *)ptr;
+ const char *end = header + realsize;
+ const char *accept_ranges = "Accept-Ranges:";
+ const char *bytes = "bytes";
- if (realsize >= strlen(accept_line)
- && strncmp((char *)ptr, accept_line, strlen(accept_line)) == 0) {
- s->accept_range = true;
+ if (realsize >= strlen(accept_ranges)
+ && strncmp(header, accept_ranges, strlen(accept_ranges)) == 0) {
+
+ char *p = strchr(header, ':') + 1;
+
+ /* Skip whitespace between the header name and value. */
+ while (p < end && *p && g_ascii_isspace(*p)) {
+ p++;
+ }
+
+ if (end - p >= strlen(bytes)
+ && strncmp(p, bytes, strlen(bytes)) == 0) {
+
+ /* Check that there is nothing but whitespace after the value. */
+ p += strlen(bytes);
+ while (p < end && *p && g_ascii_isspace(*p)) {
+ p++;
+ }
+
+ if (p == end || !*p) {
+ s->accept_range = true;
+ }
+ }
}
return realsize;
--
2.27.0

View File

@ -1,69 +0,0 @@
From 7db05c8a732fbdc986a40aadf0de6dd23057d044 Mon Sep 17 00:00:00 2001
From: Max Reitz <mreitz@redhat.com>
Date: Fri, 1 Nov 2019 16:25:10 +0100
Subject: [PATCH] block/file-posix: Let post-EOF fallocate serialize
The XFS kernel driver has a bug that may cause data corruption for qcow2
images as of qemu commit c8bb23cbdbe32f. We can work around it by
treating post-EOF fallocates as serializing up until infinity (INT64_MAX
in practice).
Cc: qemu-stable@nongnu.org
Signed-off-by: Max Reitz <mreitz@redhat.com>
Message-id: 20191101152510.11719-4-mreitz@redhat.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
(cherry picked from commit 292d06b925b2787ee6f2430996b95651cae42fce)
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
block/file-posix.c | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/block/file-posix.c b/block/file-posix.c
index 992eb4a798..c5df61b477 100644
--- a/block/file-posix.c
+++ b/block/file-posix.c
@@ -2623,6 +2623,42 @@ raw_do_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int bytes,
RawPosixAIOData acb;
ThreadPoolFunc *handler;
+#ifdef CONFIG_FALLOCATE
+ if (offset + bytes > bs->total_sectors * BDRV_SECTOR_SIZE) {
+ BdrvTrackedRequest *req;
+ uint64_t end;
+
+ /*
+ * This is a workaround for a bug in the Linux XFS driver,
+ * where writes submitted through the AIO interface will be
+ * discarded if they happen beyond a concurrently running
+ * fallocate() that increases the file length (i.e., both the
+ * write and the fallocate() happen beyond the EOF).
+ *
+ * To work around it, we extend the tracked request for this
+ * zero write until INT64_MAX (effectively infinity), and mark
+ * it as serializing.
+ *
+ * We have to enable this workaround for all filesystems and
+ * AIO modes (not just XFS with aio=native), because for
+ * remote filesystems we do not know the host configuration.
+ */
+
+ req = bdrv_co_get_self_request(bs);
+ assert(req);
+ assert(req->type == BDRV_TRACKED_WRITE);
+ assert(req->offset <= offset);
+ assert(req->offset + req->bytes >= offset + bytes);
+
+ end = INT64_MAX & -(uint64_t)bs->bl.request_alignment;
+ req->bytes = end - req->offset;
+ req->overlap_bytes = req->bytes;
+
+ bdrv_mark_request_serialising(req, bs->bl.request_alignment);
+ bdrv_wait_serialising_requests(req);
+ }
+#endif
+
acb = (RawPosixAIOData) {
.bs = bs,
.aio_fildes = s->fd,
--
2.23.0

View File

@ -1,165 +0,0 @@
From 6f1a94035b02d3676a897ea5fa4cda4c62128228 Mon Sep 17 00:00:00 2001
From: Max Reitz <mreitz@redhat.com>
Date: Fri, 23 Aug 2019 15:03:40 +0200
Subject: [PATCH] block/file-posix: Reduce xfsctl() use
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This patch removes xfs_write_zeroes() and xfs_discard(). Both functions
have been added just before the same feature was present through
fallocate():
- fallocate() has supported PUNCH_HOLE for XFS since Linux 2.6.38 (March
2011); xfs_discard() was added in December 2010.
- fallocate() has supported ZERO_RANGE for XFS since Linux 3.15 (June
2014); xfs_write_zeroes() was added in November 2013.
Nowadays, all systems that qemu runs on should support both fallocate()
features (RHEL 7's kernel does).
xfsctl() is still useful for getting the request alignment for O_DIRECT,
so this patch does not remove our dependency on it completely.
Note that xfs_write_zeroes() had a bug: It calls ftruncate() when the
file is shorter than the specified range (because ZERO_RANGE does not
increase the file length). ftruncate() may yield and then discard data
that parallel write requests have written past the EOF in the meantime.
Dropping the function altogether fixes the bug.
Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
Fixes: 50ba5b2d994853b38fed10e0841b119da0f8b8e5
Reported-by: Lukáš Doktor <ldoktor@redhat.com>
Cc: qemu-stable@nongnu.org
Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
Reviewed-by: John Snow <jsnow@redhat.com>
Tested-by: Stefano Garzarella <sgarzare@redhat.com>
Tested-by: John Snow <jsnow@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit b2c6f23f4a9f6d8f1b648705cd46d3713b78d6a2)
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
block/file-posix.c | 77 +---------------------------------------------
1 file changed, 1 insertion(+), 76 deletions(-)
diff --git a/block/file-posix.c b/block/file-posix.c
index 4479cc7ab4..992eb4a798 100644
--- a/block/file-posix.c
+++ b/block/file-posix.c
@@ -1445,59 +1445,6 @@ out:
}
}
-#ifdef CONFIG_XFS
-static int xfs_write_zeroes(BDRVRawState *s, int64_t offset, uint64_t bytes)
-{
- int64_t len;
- struct xfs_flock64 fl;
- int err;
-
- len = lseek(s->fd, 0, SEEK_END);
- if (len < 0) {
- return -errno;
- }
-
- if (offset + bytes > len) {
- /* XFS_IOC_ZERO_RANGE does not increase the file length */
- if (ftruncate(s->fd, offset + bytes) < 0) {
- return -errno;
- }
- }
-
- memset(&fl, 0, sizeof(fl));
- fl.l_whence = SEEK_SET;
- fl.l_start = offset;
- fl.l_len = bytes;
-
- if (xfsctl(NULL, s->fd, XFS_IOC_ZERO_RANGE, &fl) < 0) {
- err = errno;
- trace_file_xfs_write_zeroes(strerror(errno));
- return -err;
- }
-
- return 0;
-}
-
-static int xfs_discard(BDRVRawState *s, int64_t offset, uint64_t bytes)
-{
- struct xfs_flock64 fl;
- int err;
-
- memset(&fl, 0, sizeof(fl));
- fl.l_whence = SEEK_SET;
- fl.l_start = offset;
- fl.l_len = bytes;
-
- if (xfsctl(NULL, s->fd, XFS_IOC_UNRESVSP64, &fl) < 0) {
- err = errno;
- trace_file_xfs_discard(strerror(errno));
- return -err;
- }
-
- return 0;
-}
-#endif
-
static int translate_err(int err)
{
if (err == -ENODEV || err == -ENOSYS || err == -EOPNOTSUPP ||
@@ -1553,10 +1500,8 @@ static ssize_t handle_aiocb_write_zeroes_block(RawPosixAIOData *aiocb)
static int handle_aiocb_write_zeroes(void *opaque)
{
RawPosixAIOData *aiocb = opaque;
-#if defined(CONFIG_FALLOCATE) || defined(CONFIG_XFS)
- BDRVRawState *s = aiocb->bs->opaque;
-#endif
#ifdef CONFIG_FALLOCATE
+ BDRVRawState *s = aiocb->bs->opaque;
int64_t len;
#endif
@@ -1564,12 +1509,6 @@ static int handle_aiocb_write_zeroes(void *opaque)
return handle_aiocb_write_zeroes_block(aiocb);
}
-#ifdef CONFIG_XFS
- if (s->is_xfs) {
- return xfs_write_zeroes(s, aiocb->aio_offset, aiocb->aio_nbytes);
- }
-#endif
-
#ifdef CONFIG_FALLOCATE_ZERO_RANGE
if (s->has_write_zeroes) {
int ret = do_fallocate(s->fd, FALLOC_FL_ZERO_RANGE,
@@ -1632,14 +1571,6 @@ static int handle_aiocb_write_zeroes_unmap(void *opaque)
}
#endif
-#ifdef CONFIG_XFS
- if (s->is_xfs) {
- /* xfs_discard() guarantees that the discarded area reads as all-zero
- * afterwards, so we can use it here. */
- return xfs_discard(s, aiocb->aio_offset, aiocb->aio_nbytes);
- }
-#endif
-
/* If we couldn't manage to unmap while guaranteed that the area reads as
* all-zero afterwards, just write zeroes without unmapping */
ret = handle_aiocb_write_zeroes(aiocb);
@@ -1716,12 +1647,6 @@ static int handle_aiocb_discard(void *opaque)
ret = -errno;
#endif
} else {
-#ifdef CONFIG_XFS
- if (s->is_xfs) {
- return xfs_discard(s, aiocb->aio_offset, aiocb->aio_nbytes);
- }
-#endif
-
#ifdef CONFIG_FALLOCATE_PUNCH_HOLE
ret = do_fallocate(s->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
aiocb->aio_offset, aiocb->aio_nbytes);
--
2.23.0

View File

@ -1,33 +0,0 @@
From 5060ef71fa4621061101a30fa9e0d1690696c5c1 Mon Sep 17 00:00:00 2001
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Date: Tue, 24 Mar 2020 18:59:21 +0300
Subject: [PATCH 10/14] block: fix bdrv_root_attach_child forget to unref
child_bs
bdrv_root_attach_child promises to drop child_bs reference on failure.
It does it on first handled failure path, but not on the second. Fix
that.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Message-Id: <20200324155921.23822-1-vsementsov@virtuozzo.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Peng Liang <liangpeng10@huawei.com>
---
block.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/block.c b/block.c
index e834102c87f7..38880eabf801 100644
--- a/block.c
+++ b/block.c
@@ -2399,6 +2399,7 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
error_propagate(errp, local_err);
g_free(child);
bdrv_abort_perm_update(child_bs);
+ bdrv_unref(child_bs);
return NULL;
}
}
--
2.26.2

View File

@ -1,56 +0,0 @@
From d09b8364d9f89c9d5f36dc983c4d4a36bb7388b9 Mon Sep 17 00:00:00 2001
From: Pan Nengyuan <pannengyuan@huawei.com>
Date: Thu, 16 Jan 2020 17:29:29 +0800
Subject: [PATCH] block: fix memleaks in bdrv_refresh_filename
If we call the qmp 'query-block' while qemu is working on 'block-commit',
it will cause memleaks. The memory leak stack is as follow:
Indirect leak of 12360 byte(s) in 3 object(s) allocated from:
#0 0x7f80f0b6d970 in __interceptor_calloc (/lib64/libasan.so.5+0xef970)
#1 0x7f80ee86049d in g_malloc0 (/lib64/libglib-2.0.so.0+0x5249d)
#2 0x55ea95b5bb67 in qdict_new /mnt/sdb/qemu/qobject/qdict.c
#3 0x55ea956cd043 in bdrv_refresh_filename /mnt/sdb/qemu/block.c
#4 0x55ea956cc950 in bdrv_refresh_filename /mnt/sdb/qemu/block.c
#5 0x55ea956cc950 in bdrv_refresh_filename /mnt/sdb/qemu/block.c
#6 0x55ea956cc950 in bdrv_refresh_filename /mnt/sdb/qemu/block.c
#7 0x55ea958818ea in bdrv_block_device_info /mnt/sdb/qemu/block/qapi.c
#8 0x55ea958879de in bdrv_query_info /mnt/sdb/qemu/block/qapi.c
#9 0x55ea9588b58f in qmp_query_block /mnt/sdb/qemu/block/qapi.c
#10 0x55ea95567392 in qmp_marshal_query_block qapi/qapi-commands-block-core.c
Indirect leak of 4120 byte(s) in 1 object(s) allocated from:
#0 0x7f80f0b6d970 in __interceptor_calloc (/lib64/libasan.so.5+0xef970)
#1 0x7f80ee86049d in g_malloc0 (/lib64/libglib-2.0.so.0+0x5249d)
#2 0x55ea95b5bb67 in qdict_new /mnt/sdb/qemu/qobject/qdict.c
#3 0x55ea956cd043 in bdrv_refresh_filename /mnt/sdb/qemu/block.c
#4 0x55ea956cc950 in bdrv_refresh_filename /mnt/sdb/qemu/block.c
#5 0x55ea956cc950 in bdrv_refresh_filename /mnt/sdb/qemu/block.c
#6 0x55ea9569f301 in bdrv_backing_attach /mnt/sdb/qemu/block.c
#7 0x55ea956a99dd in bdrv_replace_child_noperm /mnt/sdb/qemu/block.c
#8 0x55ea956b9b53 in bdrv_replace_node /mnt/sdb/qemu/block.c
#9 0x55ea956b9e49 in bdrv_append /mnt/sdb/qemu/block.c
#10 0x55ea958c3472 in commit_start /mnt/sdb/qemu/block/commit.c
#11 0x55ea94b68ab0 in qmp_block_commit /mnt/sdb/qemu/blockdev.c
Reported-by: Euler Robot <euler.robot@huawei.com>
Signed-off-by: Pan Nengyuan <pannengyuan@huawei.com>
---
block.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/block.c b/block.c
index 9ae5c0e..52bad05 100644
--- a/block.c
+++ b/block.c
@@ -6048,6 +6048,7 @@ void bdrv_refresh_filename(BlockDriverState *bs)
child->bs->exact_filename);
pstrcpy(bs->filename, sizeof(bs->filename), child->bs->filename);
+ qobject_unref(bs->full_open_options);
bs->full_open_options = qobject_ref(child->bs->full_open_options);
return;
--
1.8.3.1

View File

@ -1,481 +0,0 @@
From 2e2ad02f2cecf419eaad0df982ceb5b41170cc7e Mon Sep 17 00:00:00 2001
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Date: Tue, 4 Jun 2019 19:15:05 +0300
Subject: [PATCH] block/io: refactor padding
We have similar padding code in bdrv_co_pwritev,
bdrv_co_do_pwrite_zeroes and bdrv_co_preadv. Let's combine and unify
it.
[Squashed in Vladimir's qemu-iotests 077 fix
--Stefan]
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-id: 20190604161514.262241-4-vsementsov@virtuozzo.com
Message-Id: <20190604161514.262241-4-vsementsov@virtuozzo.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
(cherry picked from commit 7a3f542fbdfd799be4fa6f8b96dc8c1e6933fce4)
*prereq for 292d06b9
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
block/io.c | 365 +++++++++++++++++++++++++++++------------------------
1 file changed, 200 insertions(+), 165 deletions(-)
diff --git a/block/io.c b/block/io.c
index dccf687acc..07d2d825c3 100644
--- a/block/io.c
+++ b/block/io.c
@@ -1408,28 +1408,177 @@ out:
}
/*
- * Handle a read request in coroutine context
+ * Request padding
+ *
+ * |<---- align ----->| |<----- align ---->|
+ * |<- head ->|<------------- bytes ------------->|<-- tail -->|
+ * | | | | | |
+ * -*----------$-------*-------- ... --------*-----$------------*---
+ * | | | | | |
+ * | offset | | end |
+ * ALIGN_DOWN(offset) ALIGN_UP(offset) ALIGN_DOWN(end) ALIGN_UP(end)
+ * [buf ... ) [tail_buf )
+ *
+ * @buf is an aligned allocation needed to store @head and @tail paddings. @head
+ * is placed at the beginning of @buf and @tail at the @end.
+ *
+ * @tail_buf is a pointer to sub-buffer, corresponding to align-sized chunk
+ * around tail, if tail exists.
+ *
+ * @merge_reads is true for small requests,
+ * if @buf_len == @head + bytes + @tail. In this case it is possible that both
+ * head and tail exist but @buf_len == align and @tail_buf == @buf.
+ */
+typedef struct BdrvRequestPadding {
+ uint8_t *buf;
+ size_t buf_len;
+ uint8_t *tail_buf;
+ size_t head;
+ size_t tail;
+ bool merge_reads;
+ QEMUIOVector local_qiov;
+} BdrvRequestPadding;
+
+static bool bdrv_init_padding(BlockDriverState *bs,
+ int64_t offset, int64_t bytes,
+ BdrvRequestPadding *pad)
+{
+ uint64_t align = bs->bl.request_alignment;
+ size_t sum;
+
+ memset(pad, 0, sizeof(*pad));
+
+ pad->head = offset & (align - 1);
+ pad->tail = ((offset + bytes) & (align - 1));
+ if (pad->tail) {
+ pad->tail = align - pad->tail;
+ }
+
+ if ((!pad->head && !pad->tail) || !bytes) {
+ return false;
+ }
+
+ sum = pad->head + bytes + pad->tail;
+ pad->buf_len = (sum > align && pad->head && pad->tail) ? 2 * align : align;
+ pad->buf = qemu_blockalign(bs, pad->buf_len);
+ pad->merge_reads = sum == pad->buf_len;
+ if (pad->tail) {
+ pad->tail_buf = pad->buf + pad->buf_len - align;
+ }
+
+ return true;
+}
+
+static int bdrv_padding_rmw_read(BdrvChild *child,
+ BdrvTrackedRequest *req,
+ BdrvRequestPadding *pad,
+ bool zero_middle)
+{
+ QEMUIOVector local_qiov;
+ BlockDriverState *bs = child->bs;
+ uint64_t align = bs->bl.request_alignment;
+ int ret;
+
+ assert(req->serialising && pad->buf);
+
+ if (pad->head || pad->merge_reads) {
+ uint64_t bytes = pad->merge_reads ? pad->buf_len : align;
+
+ qemu_iovec_init_buf(&local_qiov, pad->buf, bytes);
+
+ if (pad->head) {
+ bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_HEAD);
+ }
+ if (pad->merge_reads && pad->tail) {
+ bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_TAIL);
+ }
+ ret = bdrv_aligned_preadv(child, req, req->overlap_offset, bytes,
+ align, &local_qiov, 0);
+ if (ret < 0) {
+ return ret;
+ }
+ if (pad->head) {
+ bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_HEAD);
+ }
+ if (pad->merge_reads && pad->tail) {
+ bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL);
+ }
+
+ if (pad->merge_reads) {
+ goto zero_mem;
+ }
+ }
+
+ if (pad->tail) {
+ qemu_iovec_init_buf(&local_qiov, pad->tail_buf, align);
+
+ bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_TAIL);
+ ret = bdrv_aligned_preadv(
+ child, req,
+ req->overlap_offset + req->overlap_bytes - align,
+ align, align, &local_qiov, 0);
+ if (ret < 0) {
+ return ret;
+ }
+ bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL);
+ }
+
+zero_mem:
+ if (zero_middle) {
+ memset(pad->buf + pad->head, 0, pad->buf_len - pad->head - pad->tail);
+ }
+
+ return 0;
+}
+
+static void bdrv_padding_destroy(BdrvRequestPadding *pad)
+{
+ if (pad->buf) {
+ qemu_vfree(pad->buf);
+ qemu_iovec_destroy(&pad->local_qiov);
+ }
+}
+
+/*
+ * bdrv_pad_request
+ *
+ * Exchange request parameters with padded request if needed. Don't include RMW
+ * read of padding, bdrv_padding_rmw_read() should be called separately if
+ * needed.
+ *
+ * All parameters except @bs are in-out: they represent original request at
+ * function call and padded (if padding needed) at function finish.
+ *
+ * Function always succeeds.
*/
+static bool bdrv_pad_request(BlockDriverState *bs, QEMUIOVector **qiov,
+ int64_t *offset, unsigned int *bytes,
+ BdrvRequestPadding *pad)
+{
+ if (!bdrv_init_padding(bs, *offset, *bytes, pad)) {
+ return false;
+ }
+
+ qemu_iovec_init_extended(&pad->local_qiov, pad->buf, pad->head,
+ *qiov, 0, *bytes,
+ pad->buf + pad->buf_len - pad->tail, pad->tail);
+ *bytes += pad->head + pad->tail;
+ *offset -= pad->head;
+ *qiov = &pad->local_qiov;
+
+ return true;
+}
+
int coroutine_fn bdrv_co_preadv(BdrvChild *child,
int64_t offset, unsigned int bytes, QEMUIOVector *qiov,
BdrvRequestFlags flags)
{
BlockDriverState *bs = child->bs;
- BlockDriver *drv = bs->drv;
BdrvTrackedRequest req;
-
- uint64_t align = bs->bl.request_alignment;
- uint8_t *head_buf = NULL;
- uint8_t *tail_buf = NULL;
- QEMUIOVector local_qiov;
- bool use_local_qiov = false;
+ BdrvRequestPadding pad;
int ret;
- trace_bdrv_co_preadv(child->bs, offset, bytes, flags);
-
- if (!drv) {
- return -ENOMEDIUM;
- }
+ trace_bdrv_co_preadv(bs, offset, bytes, flags);
ret = bdrv_check_byte_request(bs, offset, bytes);
if (ret < 0) {
@@ -1443,43 +1592,16 @@ int coroutine_fn bdrv_co_preadv(BdrvChild *child,
flags |= BDRV_REQ_COPY_ON_READ;
}
- /* Align read if necessary by padding qiov */
- if (offset & (align - 1)) {
- head_buf = qemu_blockalign(bs, align);
- qemu_iovec_init(&local_qiov, qiov->niov + 2);
- qemu_iovec_add(&local_qiov, head_buf, offset & (align - 1));
- qemu_iovec_concat(&local_qiov, qiov, 0, qiov->size);
- use_local_qiov = true;
-
- bytes += offset & (align - 1);
- offset = offset & ~(align - 1);
- }
-
- if ((offset + bytes) & (align - 1)) {
- if (!use_local_qiov) {
- qemu_iovec_init(&local_qiov, qiov->niov + 1);
- qemu_iovec_concat(&local_qiov, qiov, 0, qiov->size);
- use_local_qiov = true;
- }
- tail_buf = qemu_blockalign(bs, align);
- qemu_iovec_add(&local_qiov, tail_buf,
- align - ((offset + bytes) & (align - 1)));
-
- bytes = ROUND_UP(bytes, align);
- }
+ bdrv_pad_request(bs, &qiov, &offset, &bytes, &pad);
tracked_request_begin(&req, bs, offset, bytes, BDRV_TRACKED_READ);
- ret = bdrv_aligned_preadv(child, &req, offset, bytes, align,
- use_local_qiov ? &local_qiov : qiov,
- flags);
+ ret = bdrv_aligned_preadv(child, &req, offset, bytes,
+ bs->bl.request_alignment,
+ qiov, flags);
tracked_request_end(&req);
bdrv_dec_in_flight(bs);
- if (use_local_qiov) {
- qemu_iovec_destroy(&local_qiov);
- qemu_vfree(head_buf);
- qemu_vfree(tail_buf);
- }
+ bdrv_padding_destroy(&pad);
return ret;
}
@@ -1775,44 +1897,34 @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BdrvChild *child,
BdrvTrackedRequest *req)
{
BlockDriverState *bs = child->bs;
- uint8_t *buf = NULL;
QEMUIOVector local_qiov;
uint64_t align = bs->bl.request_alignment;
- unsigned int head_padding_bytes, tail_padding_bytes;
int ret = 0;
+ bool padding;
+ BdrvRequestPadding pad;
- head_padding_bytes = offset & (align - 1);
- tail_padding_bytes = (align - (offset + bytes)) & (align - 1);
-
-
- assert(flags & BDRV_REQ_ZERO_WRITE);
- if (head_padding_bytes || tail_padding_bytes) {
- buf = qemu_blockalign(bs, align);
- qemu_iovec_init_buf(&local_qiov, buf, align);
- }
- if (head_padding_bytes) {
- uint64_t zero_bytes = MIN(bytes, align - head_padding_bytes);
-
- /* RMW the unaligned part before head. */
+ padding = bdrv_init_padding(bs, offset, bytes, &pad);
+ if (padding) {
mark_request_serialising(req, align);
wait_serialising_requests(req);
- bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_HEAD);
- ret = bdrv_aligned_preadv(child, req, offset & ~(align - 1), align,
- align, &local_qiov, 0);
- if (ret < 0) {
- goto fail;
- }
- bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_HEAD);
- memset(buf + head_padding_bytes, 0, zero_bytes);
- ret = bdrv_aligned_pwritev(child, req, offset & ~(align - 1), align,
- align, &local_qiov,
- flags & ~BDRV_REQ_ZERO_WRITE);
- if (ret < 0) {
- goto fail;
+ bdrv_padding_rmw_read(child, req, &pad, true);
+
+ if (pad.head || pad.merge_reads) {
+ int64_t aligned_offset = offset & ~(align - 1);
+ int64_t write_bytes = pad.merge_reads ? pad.buf_len : align;
+
+ qemu_iovec_init_buf(&local_qiov, pad.buf, write_bytes);
+ ret = bdrv_aligned_pwritev(child, req, aligned_offset, write_bytes,
+ align, &local_qiov,
+ flags & ~BDRV_REQ_ZERO_WRITE);
+ if (ret < 0 || pad.merge_reads) {
+ /* Error or all work is done */
+ goto out;
+ }
+ offset += write_bytes - pad.head;
+ bytes -= write_bytes - pad.head;
}
- offset += zero_bytes;
- bytes -= zero_bytes;
}
assert(!bytes || (offset & (align - 1)) == 0);
@@ -1822,7 +1934,7 @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BdrvChild *child,
ret = bdrv_aligned_pwritev(child, req, offset, aligned_bytes, align,
NULL, flags);
if (ret < 0) {
- goto fail;
+ goto out;
}
bytes -= aligned_bytes;
offset += aligned_bytes;
@@ -1830,26 +1942,17 @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BdrvChild *child,
assert(!bytes || (offset & (align - 1)) == 0);
if (bytes) {
- assert(align == tail_padding_bytes + bytes);
- /* RMW the unaligned part after tail. */
- mark_request_serialising(req, align);
- wait_serialising_requests(req);
- bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_TAIL);
- ret = bdrv_aligned_preadv(child, req, offset, align,
- align, &local_qiov, 0);
- if (ret < 0) {
- goto fail;
- }
- bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL);
+ assert(align == pad.tail + bytes);
- memset(buf, 0, bytes);
+ qemu_iovec_init_buf(&local_qiov, pad.tail_buf, align);
ret = bdrv_aligned_pwritev(child, req, offset, align, align,
&local_qiov, flags & ~BDRV_REQ_ZERO_WRITE);
}
-fail:
- qemu_vfree(buf);
- return ret;
+out:
+ bdrv_padding_destroy(&pad);
+
+ return ret;
}
/*
@@ -1862,10 +1965,7 @@ int coroutine_fn bdrv_co_pwritev(BdrvChild *child,
BlockDriverState *bs = child->bs;
BdrvTrackedRequest req;
uint64_t align = bs->bl.request_alignment;
- uint8_t *head_buf = NULL;
- uint8_t *tail_buf = NULL;
- QEMUIOVector local_qiov;
- bool use_local_qiov = false;
+ BdrvRequestPadding pad;
int ret;
trace_bdrv_co_pwritev(child->bs, offset, bytes, flags);
@@ -1892,86 +1992,21 @@ int coroutine_fn bdrv_co_pwritev(BdrvChild *child,
goto out;
}
- if (offset & (align - 1)) {
- QEMUIOVector head_qiov;
-
+ if (bdrv_pad_request(bs, &qiov, &offset, &bytes, &pad)) {
mark_request_serialising(&req, align);
wait_serialising_requests(&req);
-
- head_buf = qemu_blockalign(bs, align);
- qemu_iovec_init_buf(&head_qiov, head_buf, align);
-
- bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_HEAD);
- ret = bdrv_aligned_preadv(child, &req, offset & ~(align - 1), align,
- align, &head_qiov, 0);
- if (ret < 0) {
- goto fail;
- }
- bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_HEAD);
-
- qemu_iovec_init(&local_qiov, qiov->niov + 2);
- qemu_iovec_add(&local_qiov, head_buf, offset & (align - 1));
- qemu_iovec_concat(&local_qiov, qiov, 0, qiov->size);
- use_local_qiov = true;
-
- bytes += offset & (align - 1);
- offset = offset & ~(align - 1);
-
- /* We have read the tail already if the request is smaller
- * than one aligned block.
- */
- if (bytes < align) {
- qemu_iovec_add(&local_qiov, head_buf + bytes, align - bytes);
- bytes = align;
- }
- }
-
- if ((offset + bytes) & (align - 1)) {
- QEMUIOVector tail_qiov;
- size_t tail_bytes;
- bool waited;
-
- mark_request_serialising(&req, align);
- waited = wait_serialising_requests(&req);
- assert(!waited || !use_local_qiov);
-
- tail_buf = qemu_blockalign(bs, align);
- qemu_iovec_init_buf(&tail_qiov, tail_buf, align);
-
- bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_TAIL);
- ret = bdrv_aligned_preadv(child, &req, (offset + bytes) & ~(align - 1),
- align, align, &tail_qiov, 0);
- if (ret < 0) {
- goto fail;
- }
- bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL);
-
- if (!use_local_qiov) {
- qemu_iovec_init(&local_qiov, qiov->niov + 1);
- qemu_iovec_concat(&local_qiov, qiov, 0, qiov->size);
- use_local_qiov = true;
- }
-
- tail_bytes = (offset + bytes) & (align - 1);
- qemu_iovec_add(&local_qiov, tail_buf + tail_bytes, align - tail_bytes);
-
- bytes = ROUND_UP(bytes, align);
+ bdrv_padding_rmw_read(child, &req, &pad, false);
}
ret = bdrv_aligned_pwritev(child, &req, offset, bytes, align,
- use_local_qiov ? &local_qiov : qiov,
- flags);
+ qiov, flags);
-fail:
+ bdrv_padding_destroy(&pad);
- if (use_local_qiov) {
- qemu_iovec_destroy(&local_qiov);
- }
- qemu_vfree(head_buf);
- qemu_vfree(tail_buf);
out:
tracked_request_end(&req);
bdrv_dec_in_flight(bs);
+
return ret;
}
--
2.23.0

View File

@ -1,30 +0,0 @@
From 547b06bb04287eb97ffb02e213aa8466c15cce65 Mon Sep 17 00:00:00 2001
From: Chen Qun <kuhn.chenqun@huawei.com>
Date: Mon, 16 Mar 2020 14:35:34 +0800
Subject: [PATCH] block/iscsi: use MIN() between mx_sb_len and sb_len_wr
Use MIN() macro between mx_sb_len and sb_len_wr the len for sbp copy data.
Reported-by: Euler Robot <euler.robot@huawei.com>
Signed-off-by: Chen Qun <kuhn.chenqun@huawei.com>
---
block/iscsi.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/block/iscsi.c b/block/iscsi.c
index 3f86aaf..5c3c598 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -989,8 +989,7 @@ iscsi_aio_ioctl_cb(struct iscsi_context *iscsi, int status,
acb->ioh->driver_status |= SG_ERR_DRIVER_SENSE;
acb->ioh->sb_len_wr = acb->task->datain.size - 2;
- ss = (acb->ioh->mx_sb_len >= acb->ioh->sb_len_wr) ?
- acb->ioh->mx_sb_len : acb->ioh->sb_len_wr;
+ ss = MIN(acb->ioh->mx_sb_len, acb->ioh->sb_len_wr);
memcpy(acb->ioh->sbp, &acb->task->datain.data[2], ss);
}
--
1.8.3.1

View File

@ -1,34 +0,0 @@
From 682d23829adf0a872d5a3ca6eb4b31c424f558fc Mon Sep 17 00:00:00 2001
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Date: Tue, 24 Mar 2020 18:36:26 +0300
Subject: [PATCH 09/14] block/mirror: fix use after free of local_err
local_err is used again in mirror_exit_common() after
bdrv_set_backing_hd(), so we must zero it. Otherwise try to set
non-NULL local_err will crash.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Message-Id: <20200324153630.11882-3-vsementsov@virtuozzo.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: John Snow <jsnow@redhat.com>
Signed-off-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Peng Liang <liangpeng10@huawei.com>
---
block/mirror.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/block/mirror.c b/block/mirror.c
index 681b305de650..ef6c958ff9b3 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -674,6 +674,7 @@ static int mirror_exit_common(Job *job)
bdrv_set_backing_hd(target_bs, backing, &local_err);
if (local_err) {
error_report_err(local_err);
+ local_err = NULL;
ret = -EPERM;
}
}
--
2.26.2

View File

@ -1,67 +0,0 @@
From 1196a2079a558cbb673e06142fa67a401c5e6c30 Mon Sep 17 00:00:00 2001
From: Pan Nengyuan <pannengyuan@huawei.com>
Date: Thu, 5 Dec 2019 11:45:27 +0800
Subject: [PATCH 6/9] block/nbd: extract the common cleanup code
The BDRVNBDState cleanup code is common in two places, add
nbd_clear_bdrvstate() function to do these cleanups.
Suggested-by: Stefano Garzarella <sgarzare@redhat.com>
Signed-off-by: Pan Nengyuan <pannengyuan@huawei.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Message-Id: <1575517528-44312-2-git-send-email-pannengyuan@huawei.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
[eblake: fix compilation error and commit message]
Signed-off-by: Eric Blake <eblake@redhat.com>
Signed-off-by: AlexChen <alex.chen@huawei.com>
---
block/nbd.c | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/block/nbd.c b/block/nbd.c
index 57c1a20..3977b1e 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -73,6 +73,16 @@ typedef struct BDRVNBDState {
char *export, *tlscredsid;
} BDRVNBDState;
+static void nbd_clear_bdrvstate(BDRVNBDState *s)
+{
+ qapi_free_SocketAddress(s->saddr);
+ s->saddr = NULL;
+ g_free(s->export);
+ s->export = NULL;
+ g_free(s->tlscredsid);
+ s->tlscredsid = NULL;
+}
+
static void nbd_recv_coroutines_wake_all(BDRVNBDState *s)
{
int i;
@@ -1640,9 +1650,7 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
object_unref(OBJECT(tlscreds));
}
if (ret < 0) {
- qapi_free_SocketAddress(s->saddr);
- g_free(s->export);
- g_free(s->tlscredsid);
+ nbd_clear_bdrvstate(s);
}
qemu_opts_del(opts);
return ret;
@@ -1692,10 +1700,7 @@ static void nbd_close(BlockDriverState *bs)
BDRVNBDState *s = bs->opaque;
nbd_client_close(bs);
-
- qapi_free_SocketAddress(s->saddr);
- g_free(s->export);
- g_free(s->tlscredsid);
+ nbd_clear_bdrvstate(s);
}
static int64_t nbd_getlength(BlockDriverState *bs)
--
1.8.3.1

View File

@ -1,41 +0,0 @@
From 0694c489cd240620fee5675e8d24c7ce02d1d67d Mon Sep 17 00:00:00 2001
From: Peter Lieven <pl@kamp.de>
Date: Tue, 10 Sep 2019 17:41:09 +0200
Subject: [PATCH] block/nfs: tear down aio before nfs_close
nfs_close is a sync call from libnfs and has its own event
handler polling on the nfs FD. Avoid that both QEMU and libnfs
are intefering here.
CC: qemu-stable@nongnu.org
Signed-off-by: Peter Lieven <pl@kamp.de>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 601dc6559725f7a614b6f893611e17ff0908e914)
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
block/nfs.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/block/nfs.c b/block/nfs.c
index d93241b3bb..2b7a078241 100644
--- a/block/nfs.c
+++ b/block/nfs.c
@@ -390,12 +390,14 @@ static void nfs_attach_aio_context(BlockDriverState *bs,
static void nfs_client_close(NFSClient *client)
{
if (client->context) {
+ qemu_mutex_lock(&client->mutex);
+ aio_set_fd_handler(client->aio_context, nfs_get_fd(client->context),
+ false, NULL, NULL, NULL, NULL);
+ qemu_mutex_unlock(&client->mutex);
if (client->fh) {
nfs_close(client->context, client->fh);
client->fh = NULL;
}
- aio_set_fd_handler(client->aio_context, nfs_get_fd(client->context),
- false, NULL, NULL, NULL, NULL);
nfs_destroy_context(client->context);
client->context = NULL;
}
--
2.23.0

View File

@ -1,343 +0,0 @@
From 3d018ff3bdd8aec260254036b600cfa8d694ced4 Mon Sep 17 00:00:00 2001
From: Nir Soffer <nirsof@gmail.com>
Date: Tue, 27 Aug 2019 04:05:27 +0300
Subject: [PATCH] block: posix: Always allocate the first block
When creating an image with preallocation "off" or "falloc", the first
block of the image is typically not allocated. When using Gluster
storage backed by XFS filesystem, reading this block using direct I/O
succeeds regardless of request length, fooling alignment detection.
In this case we fallback to a safe value (4096) instead of the optimal
value (512), which may lead to unneeded data copying when aligning
requests. Allocating the first block avoids the fallback.
Since we allocate the first block even with preallocation=off, we no
longer create images with zero disk size:
$ ./qemu-img create -f raw test.raw 1g
Formatting 'test.raw', fmt=raw size=1073741824
$ ls -lhs test.raw
4.0K -rw-r--r--. 1 nsoffer nsoffer 1.0G Aug 16 23:48 test.raw
And converting the image requires additional cluster:
$ ./qemu-img measure -f raw -O qcow2 test.raw
required size: 458752
fully allocated size: 1074135040
When using format like vmdk with multiple files per image, we allocate
one block per file:
$ ./qemu-img create -f vmdk -o subformat=twoGbMaxExtentFlat test.vmdk 4g
Formatting 'test.vmdk', fmt=vmdk size=4294967296 compat6=off hwversion=undefined subformat=twoGbMaxExtentFlat
$ ls -lhs test*.vmdk
4.0K -rw-r--r--. 1 nsoffer nsoffer 2.0G Aug 27 03:23 test-f001.vmdk
4.0K -rw-r--r--. 1 nsoffer nsoffer 2.0G Aug 27 03:23 test-f002.vmdk
4.0K -rw-r--r--. 1 nsoffer nsoffer 353 Aug 27 03:23 test.vmdk
I did quick performance test for copying disks with qemu-img convert to
new raw target image to Gluster storage with sector size of 512 bytes:
for i in $(seq 10); do
rm -f dst.raw
sleep 10
time ./qemu-img convert -f raw -O raw -t none -T none src.raw dst.raw
done
Here is a table comparing the total time spent:
Type Before(s) After(s) Diff(%)
---------------------------------------
real 530.028 469.123 -11.4
user 17.204 10.768 -37.4
sys 17.881 7.011 -60.7
We can see very clear improvement in CPU usage.
Signed-off-by: Nir Soffer <nsoffer@redhat.com>
Message-id: 20190827010528.8818-2-nsoffer@redhat.com
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Max Reitz <mreitz@redhat.com>
(cherry picked from commit 3a20013fbb26d2a1bd11ef148eefdb1508783787)
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
block/file-posix.c | 51 +++++++++++++++++++
tests/qemu-iotests/059.out | 2 +-
tests/qemu-iotests/{150.out => 150.out.qcow2} | 0
tests/qemu-iotests/150.out.raw | 12 +++++
tests/qemu-iotests/175 | 19 ++++---
tests/qemu-iotests/175.out | 8 +--
tests/qemu-iotests/178.out.qcow2 | 4 +-
tests/qemu-iotests/221.out | 12 +++--
tests/qemu-iotests/253.out | 12 +++--
9 files changed, 99 insertions(+), 21 deletions(-)
rename tests/qemu-iotests/{150.out => 150.out.qcow2} (100%)
create mode 100644 tests/qemu-iotests/150.out.raw
diff --git a/block/file-posix.c b/block/file-posix.c
index be32dd8c51..2184aa980c 100644
--- a/block/file-posix.c
+++ b/block/file-posix.c
@@ -1674,6 +1674,43 @@ static int handle_aiocb_discard(void *opaque)
return ret;
}
+/*
+ * Help alignment probing by allocating the first block.
+ *
+ * When reading with direct I/O from unallocated area on Gluster backed by XFS,
+ * reading succeeds regardless of request length. In this case we fallback to
+ * safe alignment which is not optimal. Allocating the first block avoids this
+ * fallback.
+ *
+ * fd may be opened with O_DIRECT, but we don't know the buffer alignment or
+ * request alignment, so we use safe values.
+ *
+ * Returns: 0 on success, -errno on failure. Since this is an optimization,
+ * caller may ignore failures.
+ */
+static int allocate_first_block(int fd, size_t max_size)
+{
+ size_t write_size = (max_size < MAX_BLOCKSIZE)
+ ? BDRV_SECTOR_SIZE
+ : MAX_BLOCKSIZE;
+ size_t max_align = MAX(MAX_BLOCKSIZE, getpagesize());
+ void *buf;
+ ssize_t n;
+ int ret;
+
+ buf = qemu_memalign(max_align, write_size);
+ memset(buf, 0, write_size);
+
+ do {
+ n = pwrite(fd, buf, write_size, 0);
+ } while (n == -1 && errno == EINTR);
+
+ ret = (n == -1) ? -errno : 0;
+
+ qemu_vfree(buf);
+ return ret;
+}
+
static int handle_aiocb_truncate(void *opaque)
{
RawPosixAIOData *aiocb = opaque;
@@ -1713,6 +1750,17 @@ static int handle_aiocb_truncate(void *opaque)
/* posix_fallocate() doesn't set errno. */
error_setg_errno(errp, -result,
"Could not preallocate new data");
+ } else if (current_length == 0) {
+ /*
+ * posix_fallocate() uses fallocate() if the filesystem
+ * supports it, or fallback to manually writing zeroes. If
+ * fallocate() was used, unaligned reads from the fallocated
+ * area in raw_probe_alignment() will succeed, hence we need to
+ * allocate the first block.
+ *
+ * Optimize future alignment probing; ignore failures.
+ */
+ allocate_first_block(fd, offset);
}
} else {
result = 0;
@@ -1774,6 +1822,9 @@ static int handle_aiocb_truncate(void *opaque)
if (ftruncate(fd, offset) != 0) {
result = -errno;
error_setg_errno(errp, -result, "Could not resize file");
+ } else if (current_length == 0 && offset > current_length) {
+ /* Optimize future alignment probing; ignore failures. */
+ allocate_first_block(fd, offset);
}
return result;
default:
diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out
index 4fab42a28c..fe3f861f3c 100644
--- a/tests/qemu-iotests/059.out
+++ b/tests/qemu-iotests/059.out
@@ -27,7 +27,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824000 subformat=twoGbMax
image: TEST_DIR/t.vmdk
file format: vmdk
virtual size: 0.977 TiB (1073741824000 bytes)
-disk size: 16 KiB
+disk size: 1.97 MiB
Format specific information:
cid: XXXXXXXX
parent cid: XXXXXXXX
diff --git a/tests/qemu-iotests/150.out b/tests/qemu-iotests/150.out.qcow2
similarity index 100%
rename from tests/qemu-iotests/150.out
rename to tests/qemu-iotests/150.out.qcow2
diff --git a/tests/qemu-iotests/150.out.raw b/tests/qemu-iotests/150.out.raw
new file mode 100644
index 0000000000..3cdc7727a5
--- /dev/null
+++ b/tests/qemu-iotests/150.out.raw
@@ -0,0 +1,12 @@
+QA output created by 150
+
+=== Mapping sparse conversion ===
+
+Offset Length File
+0 0x1000 TEST_DIR/t.IMGFMT
+
+=== Mapping non-sparse conversion ===
+
+Offset Length File
+0 0x100000 TEST_DIR/t.IMGFMT
+*** done
diff --git a/tests/qemu-iotests/175 b/tests/qemu-iotests/175
index 51e62c8276..7ba28b3c1b 100755
--- a/tests/qemu-iotests/175
+++ b/tests/qemu-iotests/175
@@ -37,14 +37,16 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
# the file size. This function hides the resulting difference in the
# stat -c '%b' output.
# Parameter 1: Number of blocks an empty file occupies
-# Parameter 2: Image size in bytes
+# Parameter 2: Minimal number of blocks in an image
+# Parameter 3: Image size in bytes
_filter_blocks()
{
extra_blocks=$1
- img_size=$2
+ min_blocks=$2
+ img_size=$3
- sed -e "s/blocks=$extra_blocks\\(\$\\|[^0-9]\\)/nothing allocated/" \
- -e "s/blocks=$((extra_blocks + img_size / 512))\\(\$\\|[^0-9]\\)/everything allocated/"
+ sed -e "s/blocks=$min_blocks\\(\$\\|[^0-9]\\)/min allocation/" \
+ -e "s/blocks=$((extra_blocks + img_size / 512))\\(\$\\|[^0-9]\\)/max allocation/"
}
# get standard environment, filters and checks
@@ -60,16 +62,21 @@ size=$((1 * 1024 * 1024))
touch "$TEST_DIR/empty"
extra_blocks=$(stat -c '%b' "$TEST_DIR/empty")
+# We always write the first byte; check how many blocks this filesystem
+# allocates to match empty image alloation.
+printf "\0" > "$TEST_DIR/empty"
+min_blocks=$(stat -c '%b' "$TEST_DIR/empty")
+
echo
echo "== creating image with default preallocation =="
_make_test_img $size | _filter_imgfmt
-stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $size
+stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $min_blocks $size
for mode in off full falloc; do
echo
echo "== creating image with preallocation $mode =="
IMGOPTS=preallocation=$mode _make_test_img $size | _filter_imgfmt
- stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $size
+ stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $min_blocks $size
done
# success, all done
diff --git a/tests/qemu-iotests/175.out b/tests/qemu-iotests/175.out
index 6d9a5ed84e..263e521262 100644
--- a/tests/qemu-iotests/175.out
+++ b/tests/qemu-iotests/175.out
@@ -2,17 +2,17 @@ QA output created by 175
== creating image with default preallocation ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
-size=1048576, nothing allocated
+size=1048576, min allocation
== creating image with preallocation off ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=off
-size=1048576, nothing allocated
+size=1048576, min allocation
== creating image with preallocation full ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=full
-size=1048576, everything allocated
+size=1048576, max allocation
== creating image with preallocation falloc ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=falloc
-size=1048576, everything allocated
+size=1048576, max allocation
*** done
diff --git a/tests/qemu-iotests/178.out.qcow2 b/tests/qemu-iotests/178.out.qcow2
index 55a8dc926f..9e7d8c44df 100644
--- a/tests/qemu-iotests/178.out.qcow2
+++ b/tests/qemu-iotests/178.out.qcow2
@@ -101,7 +101,7 @@ converted image file size in bytes: 196608
== raw input image with data (human) ==
Formatting 'TEST_DIR/t.qcow2', fmt=IMGFMT size=1073741824
-required size: 393216
+required size: 458752
fully allocated size: 1074135040
wrote 512/512 bytes at offset 512
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -257,7 +257,7 @@ converted image file size in bytes: 196608
Formatting 'TEST_DIR/t.qcow2', fmt=IMGFMT size=1073741824
{
- "required": 393216,
+ "required": 458752,
"fully-allocated": 1074135040
}
wrote 512/512 bytes at offset 512
diff --git a/tests/qemu-iotests/221.out b/tests/qemu-iotests/221.out
index 9f9dd52bb0..dca024a0c3 100644
--- a/tests/qemu-iotests/221.out
+++ b/tests/qemu-iotests/221.out
@@ -3,14 +3,18 @@ QA output created by 221
=== Check mapping of unaligned raw image ===
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=65537
-[{ "start": 0, "length": 66048, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
-[{ "start": 0, "length": 66048, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 4096, "length": 61952, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 4096, "length": 61952, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
wrote 1/1 bytes at offset 65536
1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-[{ "start": 0, "length": 65536, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 4096, "length": 61440, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
{ "start": 65536, "length": 1, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
{ "start": 65537, "length": 511, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
-[{ "start": 0, "length": 65536, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 4096, "length": 61440, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
{ "start": 65536, "length": 1, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
{ "start": 65537, "length": 511, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
*** done
diff --git a/tests/qemu-iotests/253.out b/tests/qemu-iotests/253.out
index 607c0baa0b..3d08b305d7 100644
--- a/tests/qemu-iotests/253.out
+++ b/tests/qemu-iotests/253.out
@@ -3,12 +3,16 @@ QA output created by 253
=== Check mapping of unaligned raw image ===
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048575
-[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
-[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 4096, "length": 1044480, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 4096, "length": 1044480, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
wrote 65535/65535 bytes at offset 983040
63.999 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-[{ "start": 0, "length": 983040, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 4096, "length": 978944, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
{ "start": 983040, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": OFFSET}]
-[{ "start": 0, "length": 983040, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 4096, "length": 978944, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
{ "start": 983040, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": OFFSET}]
*** done
--
2.23.0

View File

@ -1,66 +0,0 @@
From 84f22c728520792f1010074e0d5ac2ec8e2e372c Mon Sep 17 00:00:00 2001
From: Maxim Levitsky <mlevitsk@redhat.com>
Date: Sun, 15 Sep 2019 23:36:53 +0300
Subject: [PATCH] block/qcow2: Fix corruption introduced by commit 8ac0f15f335
This fixes subtle corruption introduced by luks threaded encryption
in commit 8ac0f15f335
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1745922
The corruption happens when we do a write that
* writes to two or more unallocated clusters at once
* doesn't fully cover the first sector
* doesn't fully cover the last sector
* uses luks encryption
In this case, when allocating the new clusters we COW both areas
prior to the write and after the write, and we encrypt them.
The above mentioned commit accidentally made it so we encrypt the
second COW area using the physical cluster offset of the first area.
The problem is that offset_in_cluster in do_perform_cow_encrypt
can be larger that the cluster size, thus cluster_offset
will no longer point to the start of the cluster at which encrypted
area starts.
Next patch in this series will refactor the code to avoid all these
assumptions.
In the bugreport that was triggered by rebasing a luks image to new,
zero filled base, which lot of such writes, and causes some files
with zero areas to contain garbage there instead.
But as described above it can happen elsewhere as well
Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Message-id: 20190915203655.21638-2-mlevitsk@redhat.com
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Max Reitz <mreitz@redhat.com>
(cherry picked from commit 38e7d54bdc518b5a05a922467304bcace2396945)
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
block/qcow2-cluster.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index cc5609e27a..760564c8fb 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -473,9 +473,10 @@ static bool coroutine_fn do_perform_cow_encrypt(BlockDriverState *bs,
assert((offset_in_cluster & ~BDRV_SECTOR_MASK) == 0);
assert((bytes & ~BDRV_SECTOR_MASK) == 0);
assert(s->crypto);
- if (qcow2_co_encrypt(bs, cluster_offset,
- src_cluster_offset + offset_in_cluster,
- buffer, bytes) < 0) {
+ if (qcow2_co_encrypt(bs,
+ start_of_cluster(s, cluster_offset + offset_in_cluster),
+ src_cluster_offset + offset_in_cluster,
+ buffer, bytes) < 0) {
return false;
}
}
--
2.23.0

View File

@ -1,54 +0,0 @@
From 88ef4e1862987227f8b87228cff94be3af66d054 Mon Sep 17 00:00:00 2001
From: Pan Nengyuan <pannengyuan@huawei.com>
Date: Thu, 27 Feb 2020 09:29:49 +0800
Subject: [PATCH 01/14] block/qcow2: do free crypto_opts in qcow2_close()
'crypto_opts' forgot to free in qcow2_close(), this patch fix the bellow leak stack:
Direct leak of 24 byte(s) in 1 object(s) allocated from:
#0 0x7f0edd81f970 in __interceptor_calloc (/lib64/libasan.so.5+0xef970)
#1 0x7f0edc6d149d in g_malloc0 (/lib64/libglib-2.0.so.0+0x5249d)
#2 0x55d7eaede63d in qobject_input_start_struct /mnt/sdb/qemu-new/qemu_test/qemu/qapi/qobject-input-visitor.c:295
#3 0x55d7eaed78b8 in visit_start_struct /mnt/sdb/qemu-new/qemu_test/qemu/qapi/qapi-visit-core.c:49
#4 0x55d7eaf5140b in visit_type_QCryptoBlockOpenOptions qapi/qapi-visit-crypto.c:290
#5 0x55d7eae43af3 in block_crypto_open_opts_init /mnt/sdb/qemu-new/qemu_test/qemu/block/crypto.c:163
#6 0x55d7eacd2924 in qcow2_update_options_prepare /mnt/sdb/qemu-new/qemu_test/qemu/block/qcow2.c:1148
#7 0x55d7eacd33f7 in qcow2_update_options /mnt/sdb/qemu-new/qemu_test/qemu/block/qcow2.c:1232
#8 0x55d7eacd9680 in qcow2_do_open /mnt/sdb/qemu-new/qemu_test/qemu/block/qcow2.c:1512
#9 0x55d7eacdc55e in qcow2_open_entry /mnt/sdb/qemu-new/qemu_test/qemu/block/qcow2.c:1792
#10 0x55d7eacdc8fe in qcow2_open /mnt/sdb/qemu-new/qemu_test/qemu/block/qcow2.c:1819
#11 0x55d7eac3742d in bdrv_open_driver /mnt/sdb/qemu-new/qemu_test/qemu/block.c:1317
#12 0x55d7eac3e990 in bdrv_open_common /mnt/sdb/qemu-new/qemu_test/qemu/block.c:1575
#13 0x55d7eac4442c in bdrv_open_inherit /mnt/sdb/qemu-new/qemu_test/qemu/block.c:3126
#14 0x55d7eac45c3f in bdrv_open /mnt/sdb/qemu-new/qemu_test/qemu/block.c:3219
#15 0x55d7ead8e8a4 in blk_new_open /mnt/sdb/qemu-new/qemu_test/qemu/block/block-backend.c:397
#16 0x55d7eacde74c in qcow2_co_create /mnt/sdb/qemu-new/qemu_test/qemu/block/qcow2.c:3534
#17 0x55d7eacdfa6d in qcow2_co_create_opts /mnt/sdb/qemu-new/qemu_test/qemu/block/qcow2.c:3668
#18 0x55d7eac1c678 in bdrv_create_co_entry /mnt/sdb/qemu-new/qemu_test/qemu/block.c:485
#19 0x55d7eb0024d2 in coroutine_trampoline /mnt/sdb/qemu-new/qemu_test/qemu/util/coroutine-ucontext.c:115
Reported-by: Euler Robot <euler.robot@huawei.com>
Signed-off-by: Pan Nengyuan <pannengyuan@huawei.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Message-Id: <20200227012950.12256-2-pannengyuan@huawei.com>
Signed-off-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Peng Liang <liangpeng10@huawei.com>
---
block/qcow2.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/block/qcow2.c b/block/qcow2.c
index 1909df6e1d24..27c54b9905aa 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -2408,6 +2408,7 @@ static void qcow2_close(BlockDriverState *bs)
qcrypto_block_free(s->crypto);
s->crypto = NULL;
+ qapi_free_QCryptoBlockOpenOptions(s->crypto_opts);
g_free(s->unknown_header_fields);
cleanup_unknown_header_ext(bs);
--
2.26.2

View File

@ -1,75 +0,0 @@
From a583b6b616b086d3fdce93e255d24ab2c865efd3 Mon Sep 17 00:00:00 2001
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Date: Mon, 2 Mar 2020 18:09:30 +0300
Subject: [PATCH 03/14] block/qcow2-threads: fix qcow2_decompress
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
On success path we return what inflate() returns instead of 0. And it
most probably works for Z_STREAM_END as it is positive, but is
definitely broken for Z_BUF_ERROR.
While being here, switch to errno return code, to be closer to
qcow2_compress API (and usual expectations).
Revert condition in if to be more positive. Drop dead initialization of
ret.
Cc: qemu-stable@nongnu.org # v4.0
Fixes: 341926ab83e2b
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Message-Id: <20200302150930.16218-1-vsementsov@virtuozzo.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
Signed-off-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Peng Liang <liangpeng10@huawei.com>
---
block/qcow2-threads.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/block/qcow2-threads.c b/block/qcow2-threads.c
index 3b1e63fe414d..449cd3c0a1f4 100644
--- a/block/qcow2-threads.c
+++ b/block/qcow2-threads.c
@@ -128,12 +128,12 @@ static ssize_t qcow2_compress(void *dest, size_t dest_size,
* @src - source buffer, @src_size bytes
*
* Returns: 0 on success
- * -1 on fail
+ * -EIO on fail
*/
static ssize_t qcow2_decompress(void *dest, size_t dest_size,
const void *src, size_t src_size)
{
- int ret = 0;
+ int ret;
z_stream strm;
memset(&strm, 0, sizeof(strm));
@@ -144,17 +144,19 @@ static ssize_t qcow2_decompress(void *dest, size_t dest_size,
ret = inflateInit2(&strm, -12);
if (ret != Z_OK) {
- return -1;
+ return -EIO;
}
ret = inflate(&strm, Z_FINISH);
- if ((ret != Z_STREAM_END && ret != Z_BUF_ERROR) || strm.avail_out != 0) {
+ if ((ret == Z_STREAM_END || ret == Z_BUF_ERROR) && strm.avail_out == 0) {
/*
* We approve Z_BUF_ERROR because we need @dest buffer to be filled, but
* @src buffer may be processed partly (because in qcow2 we know size of
* compressed data with precision of one sector)
*/
- ret = -1;
+ ret = 0;
+ } else {
+ ret = -EIO;
}
inflateEnd(&strm);
--
2.26.2

View File

@ -1,124 +0,0 @@
From 7a8aa6c734bb1c2927ad0cc1d10bcacb53cf4ae3 Mon Sep 17 00:00:00 2001
From: Kevin Wolf <kwolf@redhat.com>
Date: Tue, 17 Sep 2019 12:26:23 +0200
Subject: [PATCH] block/snapshot: Restrict set of snapshot nodes
Nodes involved in internal snapshots were those that were returned by
bdrv_next(), inserted and not read-only. bdrv_next() in turn returns all
nodes that are either the root node of a BlockBackend or monitor-owned
nodes.
With the typical -drive use, this worked well enough. However, in the
typical -blockdev case, the user defines one node per option, making all
nodes monitor-owned nodes. This includes protocol nodes etc. which often
are not snapshottable, so "savevm" only returns an error.
Change the conditions so that internal snapshot still include all nodes
that have a BlockBackend attached (we definitely want to snapshot
anything attached to a guest device and probably also the built-in NBD
server; snapshotting block job BlockBackends is more of an accident, but
a preexisting one), but other monitor-owned nodes are only included if
they have no parents.
This makes internal snapshots usable again with typical -blockdev
configurations.
Cc: qemu-stable@nongnu.org
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
Tested-by: Peter Krempa <pkrempa@redhat.com>
(cherry picked from commit 05f4aced658a02b02d3e89a6c7a2281008fcf26c)
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
block/snapshot.c | 26 +++++++++++++++++++-------
1 file changed, 19 insertions(+), 7 deletions(-)
diff --git a/block/snapshot.c b/block/snapshot.c
index f2f48f926a..8081616ae9 100644
--- a/block/snapshot.c
+++ b/block/snapshot.c
@@ -31,6 +31,7 @@
#include "qapi/qmp/qerror.h"
#include "qapi/qmp/qstring.h"
#include "qemu/option.h"
+#include "sysemu/block-backend.h"
QemuOptsList internal_snapshot_opts = {
.name = "snapshot",
@@ -384,6 +385,16 @@ int bdrv_snapshot_load_tmp_by_id_or_name(BlockDriverState *bs,
return ret;
}
+static bool bdrv_all_snapshots_includes_bs(BlockDriverState *bs)
+{
+ if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) {
+ return false;
+ }
+
+ /* Include all nodes that are either in use by a BlockBackend, or that
+ * aren't attached to any node, but owned by the monitor. */
+ return bdrv_has_blk(bs) || QLIST_EMPTY(&bs->parents);
+}
/* Group operations. All block drivers are involved.
* These functions will properly handle dataplane (take aio_context_acquire
@@ -399,7 +410,7 @@ bool bdrv_all_can_snapshot(BlockDriverState **first_bad_bs)
AioContext *ctx = bdrv_get_aio_context(bs);
aio_context_acquire(ctx);
- if (bdrv_is_inserted(bs) && !bdrv_is_read_only(bs)) {
+ if (bdrv_all_snapshots_includes_bs(bs)) {
ok = bdrv_can_snapshot(bs);
}
aio_context_release(ctx);
@@ -426,8 +437,9 @@ int bdrv_all_delete_snapshot(const char *name, BlockDriverState **first_bad_bs,
AioContext *ctx = bdrv_get_aio_context(bs);
aio_context_acquire(ctx);
- if (bdrv_can_snapshot(bs) &&
- bdrv_snapshot_find(bs, snapshot, name) >= 0) {
+ if (bdrv_all_snapshots_includes_bs(bs) &&
+ bdrv_snapshot_find(bs, snapshot, name) >= 0)
+ {
ret = bdrv_snapshot_delete(bs, snapshot->id_str,
snapshot->name, err);
}
@@ -455,7 +467,7 @@ int bdrv_all_goto_snapshot(const char *name, BlockDriverState **first_bad_bs,
AioContext *ctx = bdrv_get_aio_context(bs);
aio_context_acquire(ctx);
- if (bdrv_can_snapshot(bs)) {
+ if (bdrv_all_snapshots_includes_bs(bs)) {
ret = bdrv_snapshot_goto(bs, name, errp);
}
aio_context_release(ctx);
@@ -481,7 +493,7 @@ int bdrv_all_find_snapshot(const char *name, BlockDriverState **first_bad_bs)
AioContext *ctx = bdrv_get_aio_context(bs);
aio_context_acquire(ctx);
- if (bdrv_can_snapshot(bs)) {
+ if (bdrv_all_snapshots_includes_bs(bs)) {
err = bdrv_snapshot_find(bs, &sn, name);
}
aio_context_release(ctx);
@@ -512,7 +524,7 @@ int bdrv_all_create_snapshot(QEMUSnapshotInfo *sn,
if (bs == vm_state_bs) {
sn->vm_state_size = vm_state_size;
err = bdrv_snapshot_create(bs, sn);
- } else if (bdrv_can_snapshot(bs)) {
+ } else if (bdrv_all_snapshots_includes_bs(bs)) {
sn->vm_state_size = 0;
err = bdrv_snapshot_create(bs, sn);
}
@@ -538,7 +550,7 @@ BlockDriverState *bdrv_all_find_vmstate_bs(void)
bool found;
aio_context_acquire(ctx);
- found = bdrv_can_snapshot(bs);
+ found = bdrv_all_snapshots_includes_bs(bs) && bdrv_can_snapshot(bs);
aio_context_release(ctx);
if (found) {
--
2.23.0

View File

@ -1,77 +0,0 @@
From c9a4e85610bffe1803648c431e4cff4539a42323 Mon Sep 17 00:00:00 2001
From: AlexChen <alex.chen@huawei.com>
Date: Tue, 3 Nov 2020 17:42:56 +0800
Subject: [PATCH] block/vvfat: Fix bad printf format specifiers
We should use printf format specifier "%u" instead of "%d" for
argument of type "unsigned int".
In addition, fix two error format problems found by checkpatch.pl:
ERROR: space required after that ',' (ctx:VxV)
+ fprintf(stderr,"%s attributes=0x%02x begin=%u size=%d\n",
^
ERROR: line over 90 characters
+ fprintf(stderr, "%d, %s (%u, %d)\n", i, commit->path ? commit->path : "(null)", commit->param.rename.cluster, commit->action);
Reported-by: Euler Robot <euler.robot@huawei.com>
Signed-off-by: Alex Chen <alex.chen@huawei.com>
Message-Id: <5FA12620.6030705@huawei.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry-picked from commit c9eb2f3e38)
---
block/vvfat.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/block/vvfat.c b/block/vvfat.c
index f6c28805dd..5dc8d6eb4c 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -1453,7 +1453,7 @@ static void print_direntry(const direntry_t* direntry)
for(i=0;i<11;i++)
ADD_CHAR(direntry->name[i]);
buffer[j] = 0;
- fprintf(stderr,"%s attributes=0x%02x begin=%d size=%d\n",
+ fprintf(stderr, "%s attributes=0x%02x begin=%u size=%u\n",
buffer,
direntry->attributes,
begin_of_direntry(direntry),le32_to_cpu(direntry->size));
@@ -1462,7 +1462,7 @@ static void print_direntry(const direntry_t* direntry)
static void print_mapping(const mapping_t* mapping)
{
- fprintf(stderr, "mapping (%p): begin, end = %d, %d, dir_index = %d, "
+ fprintf(stderr, "mapping (%p): begin, end = %u, %u, dir_index = %u, "
"first_mapping_index = %d, name = %s, mode = 0x%x, " ,
mapping, mapping->begin, mapping->end, mapping->dir_index,
mapping->first_mapping_index, mapping->path, mapping->mode);
@@ -1470,7 +1470,7 @@ static void print_mapping(const mapping_t* mapping)
if (mapping->mode & MODE_DIRECTORY)
fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index);
else
- fprintf(stderr, "offset = %d\n", mapping->info.file.offset);
+ fprintf(stderr, "offset = %u\n", mapping->info.file.offset);
}
#endif
@@ -1604,7 +1604,7 @@ typedef struct commit_t {
static void clear_commits(BDRVVVFATState* s)
{
int i;
-DLOG(fprintf(stderr, "clear_commits (%d commits)\n", s->commits.next));
+DLOG(fprintf(stderr, "clear_commits (%u commits)\n", s->commits.next));
for (i = 0; i < s->commits.next; i++) {
commit_t* commit = array_get(&(s->commits), i);
assert(commit->path || commit->action == ACTION_WRITEOUT);
@@ -2660,7 +2660,9 @@ static int handle_renames_and_mkdirs(BDRVVVFATState* s)
fprintf(stderr, "handle_renames\n");
for (i = 0; i < s->commits.next; i++) {
commit_t* commit = array_get(&(s->commits), i);
- fprintf(stderr, "%d, %s (%d, %d)\n", i, commit->path ? commit->path : "(null)", commit->param.rename.cluster, commit->action);
+ fprintf(stderr, "%d, %s (%u, %d)\n", i,
+ commit->path ? commit->path : "(null)",
+ commit->param.rename.cluster, commit->action);
}
#endif
--
2.27.0

View File

@ -1,93 +0,0 @@
From dc6b61f12750b3ab5a3965af2ec758750389233d Mon Sep 17 00:00:00 2001
From: Sergio Lopez <slp@redhat.com>
Date: Wed, 8 Jan 2020 15:31:37 +0100
Subject: [PATCH] blockdev: Return bs to the proper context on snapshot abort
external_snapshot_abort() calls to bdrv_set_backing_hd(), which
returns state->old_bs to the main AioContext, as it's intended to be
used then the BDS is going to be released. As that's not the case when
aborting an external snapshot, return it to the AioContext it was
before the call.
This issue can be triggered by issuing a transaction with two actions,
a proper blockdev-snapshot-sync and a bogus one, so the second will
trigger a transaction abort. This results in a crash with an stack
trace like this one:
#0 0x00007fa1048b28df in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
#1 0x00007fa10489ccf5 in __GI_abort () at abort.c:79
#2 0x00007fa10489cbc9 in __assert_fail_base
(fmt=0x7fa104a03300 "%s%s%s:%u: %s%sAssertion `%s' failed.\n%n", assertion=0x5572240b44d8 "bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs)", file=0x557224014d30 "block.c", line=2240, function=<optimized out>) at assert.c:92
#3 0x00007fa1048aae96 in __GI___assert_fail
(assertion=assertion@entry=0x5572240b44d8 "bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs)", file=file@entry=0x557224014d30 "block.c", line=line@entry=2240, function=function@entry=0x5572240b5d60 <__PRETTY_FUNCTION__.31620> "bdrv_replace_child_noperm") at assert.c:101
#4 0x0000557223e631f8 in bdrv_replace_child_noperm (child=0x557225b9c980, new_bs=new_bs@entry=0x557225c42e40) at block.c:2240
#5 0x0000557223e68be7 in bdrv_replace_node (from=0x557226951a60, to=0x557225c42e40, errp=0x5572247d6138 <error_abort>) at block.c:4196
#6 0x0000557223d069c4 in external_snapshot_abort (common=0x557225d7e170) at blockdev.c:1731
#7 0x0000557223d069c4 in external_snapshot_abort (common=0x557225d7e170) at blockdev.c:1717
#8 0x0000557223d09013 in qmp_transaction (dev_list=<optimized out>, has_props=<optimized out>, props=0x557225cc7d70, errp=errp@entry=0x7ffe704c0c98) at blockdev.c:2360
#9 0x0000557223e32085 in qmp_marshal_transaction (args=<optimized out>, ret=<optimized out>, errp=0x7ffe704c0d08) at qapi/qapi-commands-transaction.c:44
#10 0x0000557223ee798c in do_qmp_dispatch (errp=0x7ffe704c0d00, allow_oob=<optimized out>, request=<optimized out>, cmds=0x5572247d3cc0 <qmp_commands>) at qapi/qmp-dispatch.c:132
#11 0x0000557223ee798c in qmp_dispatch (cmds=0x5572247d3cc0 <qmp_commands>, request=<optimized out>, allow_oob=<optimized out>) at qapi/qmp-dispatch.c:175
#12 0x0000557223e06141 in monitor_qmp_dispatch (mon=0x557225c69ff0, req=<optimized out>) at monitor/qmp.c:120
#13 0x0000557223e0678a in monitor_qmp_bh_dispatcher (data=<optimized out>) at monitor/qmp.c:209
#14 0x0000557223f2f366 in aio_bh_call (bh=0x557225b9dc60) at util/async.c:117
#15 0x0000557223f2f366 in aio_bh_poll (ctx=ctx@entry=0x557225b9c840) at util/async.c:117
#16 0x0000557223f32754 in aio_dispatch (ctx=0x557225b9c840) at util/aio-posix.c:459
#17 0x0000557223f2f242 in aio_ctx_dispatch (source=<optimized out>, callback=<optimized out>, user_data=<optimized out>) at util/async.c:260
#18 0x00007fa10913467d in g_main_dispatch (context=0x557225c28e80) at gmain.c:3176
#19 0x00007fa10913467d in g_main_context_dispatch (context=context@entry=0x557225c28e80) at gmain.c:3829
#20 0x0000557223f31808 in glib_pollfds_poll () at util/main-loop.c:219
#21 0x0000557223f31808 in os_host_main_loop_wait (timeout=<optimized out>) at util/main-loop.c:242
#22 0x0000557223f31808 in main_loop_wait (nonblocking=<optimized out>) at util/main-loop.c:518
#23 0x0000557223d13201 in main_loop () at vl.c:1828
#24 0x0000557223bbfb82 in main (argc=<optimized out>, argv=<optimized out>, envp=<optimized out>) at vl.c:4504
RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1779036
Signed-off-by: Sergio Lopez <slp@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
blockdev.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/blockdev.c b/blockdev.c
index 5088541591..79112be2e6 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1774,6 +1774,8 @@ static void external_snapshot_abort(BlkActionState *common)
if (state->new_bs) {
if (state->overlay_appended) {
AioContext *aio_context;
+ AioContext *tmp_context;
+ int ret;
aio_context = bdrv_get_aio_context(state->old_bs);
aio_context_acquire(aio_context);
@@ -1781,6 +1783,25 @@ static void external_snapshot_abort(BlkActionState *common)
bdrv_ref(state->old_bs); /* we can't let bdrv_set_backind_hd()
close state->old_bs; we need it */
bdrv_set_backing_hd(state->new_bs, NULL, &error_abort);
+
+ /*
+ * The call to bdrv_set_backing_hd() above returns state->old_bs to
+ * the main AioContext. As we're still going to be using it, return
+ * it to the AioContext it was before.
+ */
+ tmp_context = bdrv_get_aio_context(state->old_bs);
+ if (aio_context != tmp_context) {
+ aio_context_release(aio_context);
+ aio_context_acquire(tmp_context);
+
+ ret = bdrv_try_set_aio_context(state->old_bs,
+ aio_context, NULL);
+ assert(ret == 0);
+
+ aio_context_release(tmp_context);
+ aio_context_acquire(aio_context);
+ }
+
bdrv_replace_node(state->new_bs, state->old_bs, &error_abort);
bdrv_unref(state->old_bs); /* bdrv_replace_node() ref'ed old_bs */
--
2.27.0

View File

@ -1,105 +0,0 @@
From e5456acf2332efd0ed6106eb13cf24e6bca1ee64 Mon Sep 17 00:00:00 2001
From: John Snow <jsnow@redhat.com>
Date: Mon, 29 Jul 2019 16:35:52 -0400
Subject: [PATCH] blockdev-backup: utilize do_backup_common
Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Message-id: 20190709232550.10724-4-jsnow@redhat.com
Signed-off-by: John Snow <jsnow@redhat.com>
---
blockdev.c | 65 +++++-------------------------------------------------
1 file changed, 6 insertions(+), 59 deletions(-)
diff --git a/blockdev.c b/blockdev.c
index a29838a1c8..aa15ed1f00 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -3668,78 +3668,25 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn,
{
BlockDriverState *bs;
BlockDriverState *target_bs;
- Error *local_err = NULL;
- BdrvDirtyBitmap *bmap = NULL;
AioContext *aio_context;
- BlockJob *job = NULL;
- int job_flags = JOB_DEFAULT;
- int ret;
-
- if (!backup->has_speed) {
- backup->speed = 0;
- }
- if (!backup->has_on_source_error) {
- backup->on_source_error = BLOCKDEV_ON_ERROR_REPORT;
- }
- if (!backup->has_on_target_error) {
- backup->on_target_error = BLOCKDEV_ON_ERROR_REPORT;
- }
- if (!backup->has_job_id) {
- backup->job_id = NULL;
- }
- if (!backup->has_auto_finalize) {
- backup->auto_finalize = true;
- }
- if (!backup->has_auto_dismiss) {
- backup->auto_dismiss = true;
- }
- if (!backup->has_compress) {
- backup->compress = false;
- }
+ BlockJob *job;
bs = bdrv_lookup_bs(backup->device, backup->device, errp);
if (!bs) {
return NULL;
}
- aio_context = bdrv_get_aio_context(bs);
- aio_context_acquire(aio_context);
-
target_bs = bdrv_lookup_bs(backup->target, backup->target, errp);
if (!target_bs) {
- goto out;
+ return NULL;
}
- ret = bdrv_try_set_aio_context(target_bs, aio_context, errp);
- if (ret < 0) {
- goto out;
- }
+ aio_context = bdrv_get_aio_context(bs);
+ aio_context_acquire(aio_context);
- if (backup->has_bitmap) {
- bmap = bdrv_find_dirty_bitmap(bs, backup->bitmap);
- if (!bmap) {
- error_setg(errp, "Bitmap '%s' could not be found", backup->bitmap);
- goto out;
- }
- if (bdrv_dirty_bitmap_check(bmap, BDRV_BITMAP_DEFAULT, errp)) {
- goto out;
- }
- }
+ job = do_backup_common(qapi_BlockdevBackup_base(backup),
+ bs, target_bs, aio_context, txn, errp);
- if (!backup->auto_finalize) {
- job_flags |= JOB_MANUAL_FINALIZE;
- }
- if (!backup->auto_dismiss) {
- job_flags |= JOB_MANUAL_DISMISS;
- }
- job = backup_job_create(backup->job_id, bs, target_bs, backup->speed,
- backup->sync, bmap, backup->compress,
- backup->on_source_error, backup->on_target_error,
- job_flags, NULL, NULL, txn, &local_err);
- if (local_err != NULL) {
- error_propagate(errp, local_err);
- }
-out:
aio_context_release(aio_context);
return job;
}
--
2.27.0

View File

@ -1,44 +0,0 @@
From ffbf1e237d0311512c411e195278e69d710fb9cf Mon Sep 17 00:00:00 2001
From: Sergio Lopez <slp@redhat.com>
Date: Wed, 8 Jan 2020 15:31:31 +0100
Subject: [PATCH] blockdev: fix coding style issues in drive_backup_prepare
Fix a couple of minor coding style issues in drive_backup_prepare.
Signed-off-by: Sergio Lopez <slp@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
blockdev.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/blockdev.c b/blockdev.c
index 4435795b6d..99b1cafb8f 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -3597,7 +3597,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
if (!backup->has_format) {
backup->format = backup->mode == NEW_IMAGE_MODE_EXISTING ?
- NULL : (char*) bs->drv->format_name;
+ NULL : (char *) bs->drv->format_name;
}
/* Early check to avoid creating target */
@@ -3607,8 +3607,10 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
flags = bs->open_flags | BDRV_O_RDWR;
- /* See if we have a backing HD we can use to create our new image
- * on top of. */
+ /*
+ * See if we have a backing HD we can use to create our new image
+ * on top of.
+ */
if (backup->sync == MIRROR_SYNC_MODE_TOP) {
source = backing_bs(bs);
if (!source) {
--
2.27.0

View File

@ -1,191 +0,0 @@
From 64c6b3b911f65c19f3a235c8394f5db894c1ee6a Mon Sep 17 00:00:00 2001
From: Sergio Lopez <slp@redhat.com>
Date: Wed, 8 Jan 2020 15:31:34 +0100
Subject: [PATCH] blockdev: honor bdrv_try_set_aio_context() context
requirements
bdrv_try_set_aio_context() requires that the old context is held, and
the new context is not held. Fix all the occurrences where it's not
done this way.
Suggested-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Sergio Lopez <slp@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
blockdev.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 60 insertions(+), 8 deletions(-)
diff --git a/blockdev.c b/blockdev.c
index d3309c205a..5088541591 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1578,6 +1578,7 @@ static void external_snapshot_prepare(BlkActionState *common,
DO_UPCAST(ExternalSnapshotState, common, common);
TransactionAction *action = common->action;
AioContext *aio_context;
+ AioContext *old_context;
int ret;
/* 'blockdev-snapshot' and 'blockdev-snapshot-sync' have similar
@@ -1718,7 +1719,16 @@ static void external_snapshot_prepare(BlkActionState *common,
goto out;
}
+ /* Honor bdrv_try_set_aio_context() context acquisition requirements. */
+ old_context = bdrv_get_aio_context(state->new_bs);
+ aio_context_release(aio_context);
+ aio_context_acquire(old_context);
+
ret = bdrv_try_set_aio_context(state->new_bs, aio_context, errp);
+
+ aio_context_release(old_context);
+ aio_context_acquire(aio_context);
+
if (ret < 0) {
goto out;
}
@@ -1818,11 +1828,13 @@ static void drive_backup_prepare(BlkActionState *common, Error **errp)
BlockDriverState *target_bs;
BlockDriverState *source = NULL;
AioContext *aio_context;
+ AioContext *old_context;
QDict *options;
Error *local_err = NULL;
int flags;
int64_t size;
bool set_backing_hd = false;
+ int ret;
assert(common->action->type == TRANSACTION_ACTION_KIND_DRIVE_BACKUP);
backup = common->action->u.drive_backup.data;
@@ -1911,6 +1923,21 @@ static void drive_backup_prepare(BlkActionState *common, Error **errp)
goto out;
}
+ /* Honor bdrv_try_set_aio_context() context acquisition requirements. */
+ old_context = bdrv_get_aio_context(target_bs);
+ aio_context_release(aio_context);
+ aio_context_acquire(old_context);
+
+ ret = bdrv_try_set_aio_context(target_bs, aio_context, errp);
+ if (ret < 0) {
+ bdrv_unref(target_bs);
+ aio_context_release(old_context);
+ return;
+ }
+
+ aio_context_release(old_context);
+ aio_context_acquire(aio_context);
+
if (set_backing_hd) {
bdrv_set_backing_hd(target_bs, source, &local_err);
if (local_err) {
@@ -1990,6 +2017,8 @@ static void blockdev_backup_prepare(BlkActionState *common, Error **errp)
BlockDriverState *bs;
BlockDriverState *target_bs;
AioContext *aio_context;
+ AioContext *old_context;
+ int ret;
assert(common->action->type == TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP);
backup = common->action->u.blockdev_backup.data;
@@ -2004,7 +2033,18 @@ static void blockdev_backup_prepare(BlkActionState *common, Error **errp)
return;
}
+ /* Honor bdrv_try_set_aio_context() context acquisition requirements. */
aio_context = bdrv_get_aio_context(bs);
+ old_context = bdrv_get_aio_context(target_bs);
+ aio_context_acquire(old_context);
+
+ ret = bdrv_try_set_aio_context(target_bs, aio_context, errp);
+ if (ret < 0) {
+ aio_context_release(old_context);
+ return;
+ }
+
+ aio_context_release(old_context);
aio_context_acquire(aio_context);
state->bs = bs;
@@ -3562,7 +3602,6 @@ static BlockJob *do_backup_common(BackupCommon *backup,
BlockJob *job = NULL;
BdrvDirtyBitmap *bmap = NULL;
int job_flags = JOB_DEFAULT;
- int ret;
if (!backup->has_speed) {
backup->speed = 0;
@@ -3586,11 +3625,6 @@ static BlockJob *do_backup_common(BackupCommon *backup,
backup->compress = false;
}
- ret = bdrv_try_set_aio_context(target_bs, aio_context, errp);
- if (ret < 0) {
- return NULL;
- }
-
if ((backup->sync == MIRROR_SYNC_MODE_BITMAP) ||
(backup->sync == MIRROR_SYNC_MODE_INCREMENTAL)) {
/* done before desugaring 'incremental' to print the right message */
@@ -3802,6 +3836,7 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
BlockDriverState *bs;
BlockDriverState *source, *target_bs;
AioContext *aio_context;
+ AioContext *old_context;
BlockMirrorBackingMode backing_mode;
Error *local_err = NULL;
QDict *options = NULL;
@@ -3914,12 +3949,22 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
(arg->mode == NEW_IMAGE_MODE_EXISTING ||
!bdrv_has_zero_init(target_bs)));
+
+ /* Honor bdrv_try_set_aio_context() context acquisition requirements. */
+ old_context = bdrv_get_aio_context(target_bs);
+ aio_context_release(aio_context);
+ aio_context_acquire(old_context);
+
ret = bdrv_try_set_aio_context(target_bs, aio_context, errp);
if (ret < 0) {
bdrv_unref(target_bs);
- goto out;
+ aio_context_release(old_context);
+ return;
}
+ aio_context_release(old_context);
+ aio_context_acquire(aio_context);
+
blockdev_mirror_common(arg->has_job_id ? arg->job_id : NULL, bs, target_bs,
arg->has_replaces, arg->replaces, arg->sync,
backing_mode, zero_target,
@@ -3961,6 +4006,7 @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id,
BlockDriverState *bs;
BlockDriverState *target_bs;
AioContext *aio_context;
+ AioContext *old_context;
BlockMirrorBackingMode backing_mode = MIRROR_LEAVE_BACKING_CHAIN;
Error *local_err = NULL;
bool zero_target;
@@ -3978,10 +4024,16 @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id,
zero_target = (sync == MIRROR_SYNC_MODE_FULL);
+ /* Honor bdrv_try_set_aio_context() context acquisition requirements. */
+ old_context = bdrv_get_aio_context(target_bs);
aio_context = bdrv_get_aio_context(bs);
- aio_context_acquire(aio_context);
+ aio_context_acquire(old_context);
ret = bdrv_try_set_aio_context(target_bs, aio_context, errp);
+
+ aio_context_release(old_context);
+ aio_context_acquire(aio_context);
+
if (ret < 0) {
goto out;
}
--
2.27.0

View File

@ -1,131 +0,0 @@
From 6d89e4923e9c341975dbfdd2bae153ba367a1b79 Mon Sep 17 00:00:00 2001
From: Sergio Lopez <slp@redhat.com>
Date: Wed, 8 Jan 2020 15:31:33 +0100
Subject: [PATCH] blockdev: unify qmp_blockdev_backup and blockdev-backup
transaction paths
Issuing a blockdev-backup from qmp_blockdev_backup takes a slightly
different path than when it's issued from a transaction. In the code,
this is manifested as some redundancy between do_blockdev_backup() and
blockdev_backup_prepare().
This change unifies both paths, merging do_blockdev_backup() and
blockdev_backup_prepare(), and changing qmp_blockdev_backup() to
create a transaction instead of calling do_backup_common() direcly.
As a side-effect, now qmp_blockdev_backup() is executed inside a
drained section, as it happens when creating a blockdev-backup
transaction. This change is visible from the user's perspective, as
the job gets paused and immediately resumed before starting the actual
work.
Signed-off-by: Sergio Lopez <slp@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
blockdev.c | 60 ++++++++++++------------------------------------------
1 file changed, 13 insertions(+), 47 deletions(-)
diff --git a/blockdev.c b/blockdev.c
index 7016054688..d3309c205a 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1983,16 +1983,13 @@ typedef struct BlockdevBackupState {
BlockJob *job;
} BlockdevBackupState;
-static BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn,
- Error **errp);
-
static void blockdev_backup_prepare(BlkActionState *common, Error **errp)
{
BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common);
BlockdevBackup *backup;
- BlockDriverState *bs, *target;
+ BlockDriverState *bs;
+ BlockDriverState *target_bs;
AioContext *aio_context;
- Error *local_err = NULL;
assert(common->action->type == TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP);
backup = common->action->u.blockdev_backup.data;
@@ -2002,8 +1999,8 @@ static void blockdev_backup_prepare(BlkActionState *common, Error **errp)
return;
}
- target = bdrv_lookup_bs(backup->target, backup->target, errp);
- if (!target) {
+ target_bs = bdrv_lookup_bs(backup->target, backup->target, errp);
+ if (!target_bs) {
return;
}
@@ -2014,13 +2011,10 @@ static void blockdev_backup_prepare(BlkActionState *common, Error **errp)
/* Paired with .clean() */
bdrv_drained_begin(state->bs);
- state->job = do_blockdev_backup(backup, common->block_job_txn, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- goto out;
- }
+ state->job = do_backup_common(qapi_BlockdevBackup_base(backup),
+ bs, target_bs, aio_context,
+ common->block_job_txn, errp);
-out:
aio_context_release(aio_context);
}
@@ -3672,41 +3666,13 @@ XDbgBlockGraph *qmp_x_debug_query_block_graph(Error **errp)
return bdrv_get_xdbg_block_graph(errp);
}
-BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn,
- Error **errp)
+void qmp_blockdev_backup(BlockdevBackup *backup, Error **errp)
{
- BlockDriverState *bs;
- BlockDriverState *target_bs;
- AioContext *aio_context;
- BlockJob *job;
-
- bs = bdrv_lookup_bs(backup->device, backup->device, errp);
- if (!bs) {
- return NULL;
- }
-
- target_bs = bdrv_lookup_bs(backup->target, backup->target, errp);
- if (!target_bs) {
- return NULL;
- }
-
- aio_context = bdrv_get_aio_context(bs);
- aio_context_acquire(aio_context);
-
- job = do_backup_common(qapi_BlockdevBackup_base(backup),
- bs, target_bs, aio_context, txn, errp);
-
- aio_context_release(aio_context);
- return job;
-}
-
-void qmp_blockdev_backup(BlockdevBackup *arg, Error **errp)
-{
- BlockJob *job;
- job = do_blockdev_backup(arg, NULL, errp);
- if (job) {
- job_start(&job->job);
- }
+ TransactionAction action = {
+ .type = TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP,
+ .u.blockdev_backup.data = backup,
+ };
+ blockdev_do_action(&action, errp);
}
/* Parameter check and block job starting for drive mirroring.
--
2.27.0

View File

@ -1,406 +0,0 @@
From 952f7f53cdd4320d1a0328481fa578dd199eb1ce Mon Sep 17 00:00:00 2001
From: Sergio Lopez <slp@redhat.com>
Date: Wed, 8 Jan 2020 15:31:32 +0100
Subject: [PATCH] blockdev: unify qmp_drive_backup and drive-backup transaction
paths
Issuing a drive-backup from qmp_drive_backup takes a slightly
different path than when it's issued from a transaction. In the code,
this is manifested as some redundancy between do_drive_backup() and
drive_backup_prepare().
This change unifies both paths, merging do_drive_backup() and
drive_backup_prepare(), and changing qmp_drive_backup() to create a
transaction instead of calling do_backup_common() direcly.
As a side-effect, now qmp_drive_backup() is executed inside a drained
section, as it happens when creating a drive-backup transaction. This
change is visible from the user's perspective, as the job gets paused
and immediately resumed before starting the actual work.
Also fix tests 141, 185 and 219 to cope with the extra
JOB_STATUS_CHANGE lines.
Signed-off-by: Sergio Lopez <slp@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
blockdev.c | 224 +++++++++++++++++--------------------
tests/qemu-iotests/141.out | 2 +
tests/qemu-iotests/185.out | 2 +
tests/qemu-iotests/219 | 7 +-
tests/qemu-iotests/219.out | 8 ++
5 files changed, 117 insertions(+), 126 deletions(-)
diff --git a/blockdev.c b/blockdev.c
index 99b1cafb8f..7016054688 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1804,39 +1804,128 @@ typedef struct DriveBackupState {
BlockJob *job;
} DriveBackupState;
-static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
- Error **errp);
+static BlockJob *do_backup_common(BackupCommon *backup,
+ BlockDriverState *bs,
+ BlockDriverState *target_bs,
+ AioContext *aio_context,
+ JobTxn *txn, Error **errp);
static void drive_backup_prepare(BlkActionState *common, Error **errp)
{
DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common);
- BlockDriverState *bs;
DriveBackup *backup;
+ BlockDriverState *bs;
+ BlockDriverState *target_bs;
+ BlockDriverState *source = NULL;
AioContext *aio_context;
+ QDict *options;
Error *local_err = NULL;
+ int flags;
+ int64_t size;
+ bool set_backing_hd = false;
assert(common->action->type == TRANSACTION_ACTION_KIND_DRIVE_BACKUP);
backup = common->action->u.drive_backup.data;
+ if (!backup->has_mode) {
+ backup->mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
+ }
+
bs = bdrv_lookup_bs(backup->device, backup->device, errp);
if (!bs) {
return;
}
+ if (!bs->drv) {
+ error_setg(errp, "Device has no medium");
+ return;
+ }
+
aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context);
/* Paired with .clean() */
bdrv_drained_begin(bs);
- state->bs = bs;
+ if (!backup->has_format) {
+ backup->format = backup->mode == NEW_IMAGE_MODE_EXISTING ?
+ NULL : (char *) bs->drv->format_name;
+ }
+
+ /* Early check to avoid creating target */
+ if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
+ goto out;
+ }
+
+ flags = bs->open_flags | BDRV_O_RDWR;
+
+ /*
+ * See if we have a backing HD we can use to create our new image
+ * on top of.
+ */
+ if (backup->sync == MIRROR_SYNC_MODE_TOP) {
+ source = backing_bs(bs);
+ if (!source) {
+ backup->sync = MIRROR_SYNC_MODE_FULL;
+ }
+ }
+ if (backup->sync == MIRROR_SYNC_MODE_NONE) {
+ source = bs;
+ flags |= BDRV_O_NO_BACKING;
+ set_backing_hd = true;
+ }
+
+ size = bdrv_getlength(bs);
+ if (size < 0) {
+ error_setg_errno(errp, -size, "bdrv_getlength failed");
+ goto out;
+ }
+
+ if (backup->mode != NEW_IMAGE_MODE_EXISTING) {
+ assert(backup->format);
+ if (source) {
+ bdrv_refresh_filename(source);
+ bdrv_img_create(backup->target, backup->format, source->filename,
+ source->drv->format_name, NULL,
+ size, flags, false, &local_err);
+ } else {
+ bdrv_img_create(backup->target, backup->format, NULL, NULL, NULL,
+ size, flags, false, &local_err);
+ }
+ }
- state->job = do_drive_backup(backup, common->block_job_txn, &local_err);
if (local_err) {
error_propagate(errp, local_err);
goto out;
}
+ options = qdict_new();
+ qdict_put_str(options, "discard", "unmap");
+ qdict_put_str(options, "detect-zeroes", "unmap");
+ if (backup->format) {
+ qdict_put_str(options, "driver", backup->format);
+ }
+
+ target_bs = bdrv_open(backup->target, NULL, options, flags, errp);
+ if (!target_bs) {
+ goto out;
+ }
+
+ if (set_backing_hd) {
+ bdrv_set_backing_hd(target_bs, source, &local_err);
+ if (local_err) {
+ goto unref;
+ }
+ }
+
+ state->bs = bs;
+
+ state->job = do_backup_common(qapi_DriveBackup_base(backup),
+ bs, target_bs, aio_context,
+ common->block_job_txn, errp);
+
+unref:
+ bdrv_unref(target_bs);
out:
aio_context_release(aio_context);
}
@@ -3564,126 +3653,13 @@ static BlockJob *do_backup_common(BackupCommon *backup,
return job;
}
-static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
- Error **errp)
-{
- BlockDriverState *bs;
- BlockDriverState *target_bs;
- BlockDriverState *source = NULL;
- BlockJob *job = NULL;
- AioContext *aio_context;
- QDict *options;
- Error *local_err = NULL;
- int flags;
- int64_t size;
- bool set_backing_hd = false;
-
- if (!backup->has_mode) {
- backup->mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
- }
-
- bs = bdrv_lookup_bs(backup->device, backup->device, errp);
- if (!bs) {
- return NULL;
- }
-
- if (!bs->drv) {
- error_setg(errp, "Device has no medium");
- return NULL;
- }
-
- aio_context = bdrv_get_aio_context(bs);
- aio_context_acquire(aio_context);
-
- if (!backup->has_format) {
- backup->format = backup->mode == NEW_IMAGE_MODE_EXISTING ?
- NULL : (char *) bs->drv->format_name;
- }
-
- /* Early check to avoid creating target */
- if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
- goto out;
- }
-
- flags = bs->open_flags | BDRV_O_RDWR;
-
- /*
- * See if we have a backing HD we can use to create our new image
- * on top of.
- */
- if (backup->sync == MIRROR_SYNC_MODE_TOP) {
- source = backing_bs(bs);
- if (!source) {
- backup->sync = MIRROR_SYNC_MODE_FULL;
- }
- }
- if (backup->sync == MIRROR_SYNC_MODE_NONE) {
- source = bs;
- flags |= BDRV_O_NO_BACKING;
- set_backing_hd = true;
- }
-
- size = bdrv_getlength(bs);
- if (size < 0) {
- error_setg_errno(errp, -size, "bdrv_getlength failed");
- goto out;
- }
-
- if (backup->mode != NEW_IMAGE_MODE_EXISTING) {
- assert(backup->format);
- if (source) {
- bdrv_refresh_filename(source);
- bdrv_img_create(backup->target, backup->format, source->filename,
- source->drv->format_name, NULL,
- size, flags, false, &local_err);
- } else {
- bdrv_img_create(backup->target, backup->format, NULL, NULL, NULL,
- size, flags, false, &local_err);
- }
- }
-
- if (local_err) {
- error_propagate(errp, local_err);
- goto out;
- }
-
- options = qdict_new();
- qdict_put_str(options, "discard", "unmap");
- qdict_put_str(options, "detect-zeroes", "unmap");
- if (backup->format) {
- qdict_put_str(options, "driver", backup->format);
- }
-
- target_bs = bdrv_open(backup->target, NULL, options, flags, errp);
- if (!target_bs) {
- goto out;
- }
-
- if (set_backing_hd) {
- bdrv_set_backing_hd(target_bs, source, &local_err);
- if (local_err) {
- goto unref;
- }
- }
-
- job = do_backup_common(qapi_DriveBackup_base(backup),
- bs, target_bs, aio_context, txn, errp);
-
-unref:
- bdrv_unref(target_bs);
-out:
- aio_context_release(aio_context);
- return job;
-}
-
-void qmp_drive_backup(DriveBackup *arg, Error **errp)
+void qmp_drive_backup(DriveBackup *backup, Error **errp)
{
-
- BlockJob *job;
- job = do_drive_backup(arg, NULL, errp);
- if (job) {
- job_start(&job->job);
- }
+ TransactionAction action = {
+ .type = TRANSACTION_ACTION_KIND_DRIVE_BACKUP,
+ .u.drive_backup.data = backup,
+ };
+ blockdev_do_action(&action, errp);
}
BlockDeviceInfoList *qmp_query_named_block_nodes(Error **errp)
diff --git a/tests/qemu-iotests/141.out b/tests/qemu-iotests/141.out
index 4d71d9dcae..07e0ec66d7 100644
--- a/tests/qemu-iotests/141.out
+++ b/tests/qemu-iotests/141.out
@@ -10,6 +10,8 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/m.
Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "job0"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}}
{"return": {}}
{"error": {"class": "GenericError", "desc": "Node drv0 is in use"}}
{"return": {}}
diff --git a/tests/qemu-iotests/185.out b/tests/qemu-iotests/185.out
index ddfbf3c765..a233be7f58 100644
--- a/tests/qemu-iotests/185.out
+++ b/tests/qemu-iotests/185.out
@@ -51,6 +51,8 @@ Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 l
Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "disk"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "disk"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}}
{"return": {}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
diff --git a/tests/qemu-iotests/219 b/tests/qemu-iotests/219
index e0c51662c0..655f54d881 100755
--- a/tests/qemu-iotests/219
+++ b/tests/qemu-iotests/219
@@ -63,7 +63,7 @@ def test_pause_resume(vm):
# logged immediately
iotests.log(vm.qmp('query-jobs'))
-def test_job_lifecycle(vm, job, job_args, has_ready=False):
+def test_job_lifecycle(vm, job, job_args, has_ready=False, is_mirror=False):
global img_size
iotests.log('')
@@ -135,6 +135,9 @@ def test_job_lifecycle(vm, job, job_args, has_ready=False):
iotests.log('Waiting for PENDING state...')
iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
+ if is_mirror:
+ iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
+ iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
if not job_args.get('auto-finalize', True):
# PENDING state:
@@ -218,7 +221,7 @@ with iotests.FilePath('disk.img') as disk_path, \
for auto_finalize in [True, False]:
for auto_dismiss in [True, False]:
- test_job_lifecycle(vm, 'drive-backup', job_args={
+ test_job_lifecycle(vm, 'drive-backup', is_mirror=True, job_args={
'device': 'drive0-node',
'target': copy_path,
'sync': 'full',
diff --git a/tests/qemu-iotests/219.out b/tests/qemu-iotests/219.out
index 8ebd3fee60..0ea5d0b9d5 100644
--- a/tests/qemu-iotests/219.out
+++ b/tests/qemu-iotests/219.out
@@ -135,6 +135,8 @@ Pause/resume in RUNNING
{"return": {}}
Waiting for PENDING state...
+{"data": {"id": "job0", "status": "paused"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
+{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"id": "job0", "status": "waiting"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"id": "job0", "status": "pending"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"id": "job0", "status": "concluded"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
@@ -186,6 +188,8 @@ Pause/resume in RUNNING
{"return": {}}
Waiting for PENDING state...
+{"data": {"id": "job0", "status": "paused"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
+{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"id": "job0", "status": "waiting"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"id": "job0", "status": "pending"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"id": "job0", "status": "concluded"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
@@ -245,6 +249,8 @@ Pause/resume in RUNNING
{"return": {}}
Waiting for PENDING state...
+{"data": {"id": "job0", "status": "paused"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
+{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"id": "job0", "status": "waiting"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"id": "job0", "status": "pending"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"return": [{"current-progress": 4194304, "id": "job0", "status": "pending", "total-progress": 4194304, "type": "backup"}]}
@@ -304,6 +310,8 @@ Pause/resume in RUNNING
{"return": {}}
Waiting for PENDING state...
+{"data": {"id": "job0", "status": "paused"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
+{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"id": "job0", "status": "waiting"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"id": "job0", "status": "pending"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"return": [{"current-progress": 4194304, "id": "job0", "status": "pending", "total-progress": 4194304, "type": "backup"}]}
--
2.27.0

View File

@ -1,114 +0,0 @@
From e37cda3452309d147f1f7aec3c74249001e3db0c Mon Sep 17 00:00:00 2001
From: Michael Qiu <qiudayu@huayun.com>
Date: Wed, 12 May 2021 21:54:37 +0800
Subject: [PATCH] blockjob: Fix crash with IOthread when block commit after
snapshot
Currently, if guest has workloads, IO thread will acquire aio_context
lock before do io_submit, it leads to segmentfault when do block commit
after snapshot. Just like below:
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7f7c7d91f700 (LWP 99907)]
0x00005576d0f65aab in bdrv_mirror_top_pwritev at ../block/mirror.c:1437
1437 ../block/mirror.c: No such file or directory.
(gdb) p s->job
$17 = (MirrorBlockJob *) 0x0
(gdb) p s->stop
$18 = false
Call trace of IO thread:
0 0x00005576d0f65aab in bdrv_mirror_top_pwritev at ../block/mirror.c:1437
1 0x00005576d0f7f3ab in bdrv_driver_pwritev at ../block/io.c:1174
2 0x00005576d0f8139d in bdrv_aligned_pwritev at ../block/io.c:1988
3 0x00005576d0f81b65 in bdrv_co_pwritev_part at ../block/io.c:2156
4 0x00005576d0f8e6b7 in blk_do_pwritev_part at ../block/block-backend.c:1260
5 0x00005576d0f8e84d in blk_aio_write_entry at ../block/block-backend.c:1476
...
Switch to qemu main thread:
0 0x00007f903be704ed in __lll_lock_wait at
/lib/../lib64/libpthread.so.0
1 0x00007f903be6bde6 in _L_lock_941 at /lib/../lib64/libpthread.so.0
2 0x00007f903be6bcdf in pthread_mutex_lock at
/lib/../lib64/libpthread.so.0
3 0x0000564b21456889 in qemu_mutex_lock_impl at
../util/qemu-thread-posix.c:79
4 0x0000564b213af8a5 in block_job_add_bdrv at ../blockjob.c:224
5 0x0000564b213b00ad in block_job_create at ../blockjob.c:440
6 0x0000564b21357c0a in mirror_start_job at ../block/mirror.c:1622
7 0x0000564b2135a9af in commit_active_start at ../block/mirror.c:1867
8 0x0000564b2133d132 in qmp_block_commit at ../blockdev.c:2768
9 0x0000564b2141fef3 in qmp_marshal_block_commit at
qapi/qapi-commands-block-core.c:346
10 0x0000564b214503c9 in do_qmp_dispatch_bh at
../qapi/qmp-dispatch.c:110
11 0x0000564b21451996 in aio_bh_poll at ../util/async.c:164
12 0x0000564b2146018e in aio_dispatch at ../util/aio-posix.c:381
13 0x0000564b2145187e in aio_ctx_dispatch at ../util/async.c:306
14 0x00007f9040239049 in g_main_context_dispatch at
/lib/../lib64/libglib-2.0.so.0
15 0x0000564b21447368 in main_loop_wait at ../util/main-loop.c:232
16 0x0000564b21447368 in main_loop_wait at ../util/main-loop.c:255
17 0x0000564b21447368 in main_loop_wait at ../util/main-loop.c:531
18 0x0000564b212304e1 in qemu_main_loop at ../softmmu/runstate.c:721
19 0x0000564b20f7975e in main at ../softmmu/main.c:50
In IO thread when do bdrv_mirror_top_pwritev, the job is NULL, and stop field
is false, this means the MirrorBDSOpaque "s" object has not been initialized
yet, and this object is initialized by block_job_create(), but the initialize
process is stuck in acquiring the lock.
In this situation, IO thread come to bdrv_mirror_top_pwritev(),which means that
mirror-top node is already inserted into block graph, but its bs->opaque->job
is not initialized.
The root cause is that qemu main thread do release/acquire when hold the lock,
at the same time, IO thread get the lock after release stage, and the crash
occured.
Actually, in this situation, job->job.aio_context will not equal to
qemu_get_aio_context(), and will be the same as bs->aio_context,
thus, no need to release the lock, becasue bdrv_root_attach_child()
will not change the context.
This patch fix this issue.
Fixes: 132ada80 "block: Adjust AioContexts when attaching nodes"
Signed-off-by: Michael Qiu <qiudayu@huayun.com>
Message-Id: <20210203024059.52683-1-08005325@163.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
blockjob.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/blockjob.c b/blockjob.c
index 74abb97bfd..72865a4a6e 100644
--- a/blockjob.c
+++ b/blockjob.c
@@ -223,14 +223,18 @@ int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs,
uint64_t perm, uint64_t shared_perm, Error **errp)
{
BdrvChild *c;
+ bool need_context_ops;
bdrv_ref(bs);
- if (job->job.aio_context != qemu_get_aio_context()) {
+
+ need_context_ops = bdrv_get_aio_context(bs) != job->job.aio_context;
+
+ if (need_context_ops && job->job.aio_context != qemu_get_aio_context()) {
aio_context_release(job->job.aio_context);
}
c = bdrv_root_attach_child(bs, name, &child_job, job->job.aio_context,
perm, shared_perm, job, errp);
- if (job->job.aio_context != qemu_get_aio_context()) {
+ if (need_context_ops && job->job.aio_context != qemu_get_aio_context()) {
aio_context_acquire(job->job.aio_context);
}
if (c == NULL) {
--
2.27.0

View File

@ -1,61 +0,0 @@
From 86b0f4022bb43b16979ba5300e8d40a1e6d44b79 Mon Sep 17 00:00:00 2001
From: Sergio Lopez <slp@redhat.com>
Date: Wed, 11 Sep 2019 12:03:16 +0200
Subject: [PATCH] blockjob: update nodes head while removing all bdrv
block_job_remove_all_bdrv() iterates through job->nodes, calling
bdrv_root_unref_child() for each entry. The call to the latter may
reach child_job_[can_]set_aio_ctx(), which will also attempt to
traverse job->nodes, potentially finding entries that where freed
on previous iterations.
To avoid this situation, update job->nodes head on each iteration to
ensure that already freed entries are no longer linked to the list.
RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1746631
Signed-off-by: Sergio Lopez <slp@redhat.com>
Cc: qemu-stable@nongnu.org
Signed-off-by: Max Reitz <mreitz@redhat.com>
Message-id: 20190911100316.32282-1-mreitz@redhat.com
Reviewed-by: Sergio Lopez <slp@redhat.com>
Signed-off-by: Max Reitz <mreitz@redhat.com>
(cherry picked from commit d876bf676f5e7c6aa9ac64555e48cba8734ecb2f)
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
blockjob.c | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/blockjob.c b/blockjob.c
index 20b7f557da..74abb97bfd 100644
--- a/blockjob.c
+++ b/blockjob.c
@@ -186,14 +186,23 @@ static const BdrvChildRole child_job = {
void block_job_remove_all_bdrv(BlockJob *job)
{
- GSList *l;
- for (l = job->nodes; l; l = l->next) {
+ /*
+ * bdrv_root_unref_child() may reach child_job_[can_]set_aio_ctx(),
+ * which will also traverse job->nodes, so consume the list one by
+ * one to make sure that such a concurrent access does not attempt
+ * to process an already freed BdrvChild.
+ */
+ while (job->nodes) {
+ GSList *l = job->nodes;
BdrvChild *c = l->data;
+
+ job->nodes = l->next;
+
bdrv_op_unblock_all(c->bs, job->blocker);
bdrv_root_unref_child(c);
+
+ g_slist_free_1(l);
}
- g_slist_free(job->nodes);
- job->nodes = NULL;
}
bool block_job_has_bdrv(BlockJob *job, BlockDriverState *bs)
--
2.23.0

View File

@ -1,36 +0,0 @@
From ab454ca5f45a842b2517a0f4eb786b6ea3019d5a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
Date: Fri, 4 Jun 2021 16:15:14 +0400
Subject: [PATCH 3/6] bootp: check bootp_input buffer size
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Fixes: CVE-2021-3592
Fixes: https://gitlab.freedesktop.org/slirp/libslirp/-/issues/44
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: imxcc <xingchaochao@huawei.com>
---
slirp/src/bootp.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/slirp/src/bootp.c b/slirp/src/bootp.c
index 57543271..57891871 100644
--- a/slirp/src/bootp.c
+++ b/slirp/src/bootp.c
@@ -366,9 +366,9 @@ udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
void bootp_input(struct mbuf *m)
{
- struct bootp_t *bp = mtod(m, struct bootp_t *);
+ struct bootp_t *bp = mtod_check(m, sizeof(struct bootp_t));
- if (bp->bp_op == BOOTP_REQUEST) {
+ if (bp && bp->bp_op == BOOTP_REQUEST) {
bootp_reply(m->slirp, bp, m_end(m));
}
}
--
2.27.0

View File

@ -1,161 +0,0 @@
From 3369988416bd98e97dc3d0400af165c0d9e536e0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
Date: Fri, 4 Jun 2021 19:25:28 +0400
Subject: [PATCH 2/6] bootp: limit vendor-specific area to input packet memory
buffer
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
sizeof(bootp_t) currently holds DHCP_OPT_LEN. Remove this optional field
from the structure, to help with the following patch checking for
minimal header size. Modify the bootp_reply() function to take the
buffer boundaries and avoiding potential buffer overflow.
Related to CVE-2021-3592.
https://gitlab.freedesktop.org/slirp/libslirp/-/issues/44
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: imxcc <xingchaochao@huawei.com>
---
slirp/src/bootp.c | 26 +++++++++++++++-----------
slirp/src/bootp.h | 2 +-
slirp/src/mbuf.c | 5 +++++
slirp/src/mbuf.h | 1 +
4 files changed, 22 insertions(+), 12 deletions(-)
diff --git a/slirp/src/bootp.c b/slirp/src/bootp.c
index 3f9ce255..57543271 100644
--- a/slirp/src/bootp.c
+++ b/slirp/src/bootp.c
@@ -92,21 +92,22 @@ found:
return bc;
}
-static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type,
+static void dhcp_decode(const struct bootp_t *bp,
+ const uint8_t *bp_end,
+ int *pmsg_type,
struct in_addr *preq_addr)
{
- const uint8_t *p, *p_end;
+ const uint8_t *p;
int len, tag;
*pmsg_type = 0;
preq_addr->s_addr = htonl(0L);
p = bp->bp_vend;
- p_end = p + DHCP_OPT_LEN;
if (memcmp(p, rfc1533_cookie, 4) != 0)
return;
p += 4;
- while (p < p_end) {
+ while (p < bp_end) {
tag = p[0];
if (tag == RFC1533_PAD) {
p++;
@@ -114,10 +115,10 @@ static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type,
break;
} else {
p++;
- if (p >= p_end)
+ if (p >= bp_end)
break;
len = *p++;
- if (p + len > p_end) {
+ if (p + len > bp_end) {
break;
}
DPRINTF("dhcp: tag=%d len=%d\n", tag, len);
@@ -144,7 +145,9 @@ static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type,
}
}
-static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
+static void bootp_reply(Slirp *slirp,
+ const struct bootp_t *bp,
+ const uint8_t *bp_end)
{
BOOTPClient *bc = NULL;
struct mbuf *m;
@@ -157,7 +160,7 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
uint8_t client_ethaddr[ETH_ALEN];
/* extract exact DHCP msg type */
- dhcp_decode(bp, &dhcp_msg_type, &preq_addr);
+ dhcp_decode(bp, bp_end, &dhcp_msg_type, &preq_addr);
DPRINTF("bootp packet op=%d msgtype=%d", bp->bp_op, dhcp_msg_type);
if (preq_addr.s_addr != htonl(0L))
DPRINTF(" req_addr=%08" PRIx32 "\n", ntohl(preq_addr.s_addr));
@@ -179,9 +182,10 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
return;
}
m->m_data += IF_MAXLINKHDR;
+ m_inc(m, sizeof(struct bootp_t) + DHCP_OPT_LEN);
rbp = (struct bootp_t *)m->m_data;
m->m_data += sizeof(struct udpiphdr);
- memset(rbp, 0, sizeof(struct bootp_t));
+ memset(rbp, 0, sizeof(struct bootp_t) + DHCP_OPT_LEN);
if (dhcp_msg_type == DHCPDISCOVER) {
if (preq_addr.s_addr != htonl(0L)) {
@@ -235,7 +239,7 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */
q = rbp->bp_vend;
- end = (uint8_t *)&rbp[1];
+ end = rbp->bp_vend + DHCP_OPT_LEN;
memcpy(q, rfc1533_cookie, 4);
q += 4;
@@ -365,6 +369,6 @@ void bootp_input(struct mbuf *m)
struct bootp_t *bp = mtod(m, struct bootp_t *);
if (bp->bp_op == BOOTP_REQUEST) {
- bootp_reply(m->slirp, bp);
+ bootp_reply(m->slirp, bp, m_end(m));
}
}
diff --git a/slirp/src/bootp.h b/slirp/src/bootp.h
index 03ece9bf..0d20a944 100644
--- a/slirp/src/bootp.h
+++ b/slirp/src/bootp.h
@@ -114,7 +114,7 @@ struct bootp_t {
uint8_t bp_hwaddr[16];
uint8_t bp_sname[64];
uint8_t bp_file[128];
- uint8_t bp_vend[DHCP_OPT_LEN];
+ uint8_t bp_vend[];
};
typedef struct {
diff --git a/slirp/src/mbuf.c b/slirp/src/mbuf.c
index 6d0653ed..7db07c08 100644
--- a/slirp/src/mbuf.c
+++ b/slirp/src/mbuf.c
@@ -233,3 +233,8 @@ void *mtod_check(struct mbuf *m, size_t len)
return NULL;
}
+
+void *m_end(struct mbuf *m)
+{
+ return m->m_data + m->m_len;
+}
diff --git a/slirp/src/mbuf.h b/slirp/src/mbuf.h
index 2015e323..a9752a36 100644
--- a/slirp/src/mbuf.h
+++ b/slirp/src/mbuf.h
@@ -119,6 +119,7 @@ void m_adj(struct mbuf *, int);
int m_copy(struct mbuf *, struct mbuf *, int, int);
struct mbuf *dtom(Slirp *, void *);
void *mtod_check(struct mbuf *, size_t len);
+void *m_end(struct mbuf *);
static inline void ifs_init(struct mbuf *ifm)
{
--
2.27.0

View File

@ -1,794 +0,0 @@
From f9ab92373813cfccd31f29c0d963232f65cb5f88 Mon Sep 17 00:00:00 2001
From: Prasad J Pandit <pjp@fedoraproject.org>
Date: Fri, 22 May 2020 12:22:26 +0800
Subject: [PATCH] bt: use size_t type for length parameters instead of int
From: Prasad J Pandit <pjp@fedoraproject.org>
The length parameter values are not negative, thus use an unsigned
type 'size_t' for them. Many routines pass 'len' values to memcpy(3)
calls. If it was negative, it could lead to memory corruption issues.
Add check to avoid it.
Reported-by: Arash TC <tohidi.arash@gmail.com>
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
diff --git a/bt-host.c b/bt-host.c
index 2f8f631..b73a44d 100644
--- a/bt-host.c
+++ b/bt-host.c
@@ -43,7 +43,7 @@ struct bt_host_hci_s {
};
static void bt_host_send(struct HCIInfo *hci,
- int type, const uint8_t *data, int len)
+ int type, const uint8_t *data, size_t len)
{
struct bt_host_hci_s *s = (struct bt_host_hci_s *) hci;
uint8_t pkt = type;
@@ -63,17 +63,17 @@ static void bt_host_send(struct HCIInfo *hci,
}
}
-static void bt_host_cmd(struct HCIInfo *hci, const uint8_t *data, int len)
+static void bt_host_cmd(struct HCIInfo *hci, const uint8_t *data, size_t len)
{
bt_host_send(hci, HCI_COMMAND_PKT, data, len);
}
-static void bt_host_acl(struct HCIInfo *hci, const uint8_t *data, int len)
+static void bt_host_acl(struct HCIInfo *hci, const uint8_t *data, size_t len)
{
bt_host_send(hci, HCI_ACLDATA_PKT, data, len);
}
-static void bt_host_sco(struct HCIInfo *hci, const uint8_t *data, int len)
+static void bt_host_sco(struct HCIInfo *hci, const uint8_t *data, size_t len)
{
bt_host_send(hci, HCI_SCODATA_PKT, data, len);
}
diff --git a/bt-vhci.c b/bt-vhci.c
index 886e146..32ef1c5 100644
--- a/bt-vhci.c
+++ b/bt-vhci.c
@@ -89,7 +89,7 @@ static void vhci_read(void *opaque)
}
static void vhci_host_send(void *opaque,
- int type, const uint8_t *data, int len)
+ int type, const uint8_t *data, size_t len)
{
struct bt_vhci_s *s = (struct bt_vhci_s *) opaque;
#if 0
@@ -112,6 +112,7 @@ static void vhci_host_send(void *opaque,
static uint8_t buf[4096];
buf[0] = type;
+ assert(len < sizeof(buf));
memcpy(buf + 1, data, len);
while (write(s->fd, buf, len + 1) < 0)
@@ -124,13 +125,13 @@ static void vhci_host_send(void *opaque,
}
static void vhci_out_hci_packet_event(void *opaque,
- const uint8_t *data, int len)
+ const uint8_t *data, size_t len)
{
vhci_host_send(opaque, HCI_EVENT_PKT, data, len);
}
static void vhci_out_hci_packet_acl(void *opaque,
- const uint8_t *data, int len)
+ const uint8_t *data, size_t len)
{
vhci_host_send(opaque, HCI_ACLDATA_PKT, data, len);
}
diff --git a/hw/bt/core.c b/hw/bt/core.c
index dfb196e..f548b3d 100644
--- a/hw/bt/core.c
+++ b/hw/bt/core.c
@@ -44,7 +44,7 @@ static void bt_dummy_lmp_disconnect_master(struct bt_link_s *link)
}
static void bt_dummy_lmp_acl_resp(struct bt_link_s *link,
- const uint8_t *data, int start, int len)
+ const uint8_t *data, int start, size_t len)
{
error_report("%s: stray ACL response PDU, fixme", __func__);
exit(-1);
diff --git a/hw/bt/hci-csr.c b/hw/bt/hci-csr.c
index 3d60654..f7a74c0 100644
--- a/hw/bt/hci-csr.c
+++ b/hw/bt/hci-csr.c
@@ -103,7 +103,7 @@ static inline void csrhci_fifo_wake(struct csrhci_s *s)
}
#define csrhci_out_packetz(s, len) memset(csrhci_out_packet(s, len), 0, len)
-static uint8_t *csrhci_out_packet(struct csrhci_s *s, int len)
+static uint8_t *csrhci_out_packet(struct csrhci_s *s, size_t len)
{
int off = s->out_start + s->out_len;
@@ -112,14 +112,14 @@ static uint8_t *csrhci_out_packet(struct csrhci_s *s, int len)
if (off < FIFO_LEN) {
if (off + len > FIFO_LEN && (s->out_size = off + len) > FIFO_LEN * 2) {
- error_report("%s: can't alloc %i bytes", __func__, len);
+ error_report("%s: can't alloc %zu bytes", __func__, len);
exit(-1);
}
return s->outfifo + off;
}
if (s->out_len > s->out_size) {
- error_report("%s: can't alloc %i bytes", __func__, len);
+ error_report("%s: can't alloc %zu bytes", __func__, len);
exit(-1);
}
@@ -127,7 +127,7 @@ static uint8_t *csrhci_out_packet(struct csrhci_s *s, int len)
}
static inline uint8_t *csrhci_out_packet_csr(struct csrhci_s *s,
- int type, int len)
+ int type, size_t len)
{
uint8_t *ret = csrhci_out_packetz(s, len + 2);
@@ -138,7 +138,7 @@ static inline uint8_t *csrhci_out_packet_csr(struct csrhci_s *s,
}
static inline uint8_t *csrhci_out_packet_event(struct csrhci_s *s,
- int evt, int len)
+ int evt, size_t len)
{
uint8_t *ret = csrhci_out_packetz(s,
len + 1 + sizeof(struct hci_event_hdr));
@@ -151,7 +151,7 @@ static inline uint8_t *csrhci_out_packet_event(struct csrhci_s *s,
}
static void csrhci_in_packet_vendor(struct csrhci_s *s, int ocf,
- uint8_t *data, int len)
+ uint8_t *data, size_t len)
{
int offset;
uint8_t *rpkt;
@@ -320,18 +320,18 @@ static int csrhci_write(struct Chardev *chr,
struct csrhci_s *s = (struct csrhci_s *)chr;
int total = 0;
- if (!s->enable)
+ if (!s->enable || len <= 0)
return 0;
for (;;) {
int cnt = MIN(len, s->in_needed - s->in_len);
- if (cnt) {
- memcpy(s->inpkt + s->in_len, buf, cnt);
- s->in_len += cnt;
- buf += cnt;
- len -= cnt;
- total += cnt;
- }
+ assert(cnt > 0);
+
+ memcpy(s->inpkt + s->in_len, buf, cnt);
+ s->in_len += cnt;
+ buf += cnt;
+ len -= cnt;
+ total += cnt;
if (s->in_len < s->in_needed) {
break;
@@ -363,7 +363,7 @@ static int csrhci_write(struct Chardev *chr,
}
static void csrhci_out_hci_packet_event(void *opaque,
- const uint8_t *data, int len)
+ const uint8_t *data, size_t len)
{
struct csrhci_s *s = (struct csrhci_s *) opaque;
uint8_t *pkt = csrhci_out_packet(s, (len + 2) & ~1); /* Align */
@@ -375,7 +375,7 @@ static void csrhci_out_hci_packet_event(void *opaque,
}
static void csrhci_out_hci_packet_acl(void *opaque,
- const uint8_t *data, int len)
+ const uint8_t *data, size_t len)
{
struct csrhci_s *s = (struct csrhci_s *) opaque;
uint8_t *pkt = csrhci_out_packet(s, (len + 2) & ~1); /* Align */
diff --git a/hw/bt/hci.c b/hw/bt/hci.c
index c7958f6..9c4f957 100644
--- a/hw/bt/hci.c
+++ b/hw/bt/hci.c
@@ -31,7 +31,7 @@
struct bt_hci_s {
uint8_t *(*evt_packet)(void *opaque);
- void (*evt_submit)(void *opaque, int len);
+ void (*evt_submit)(void *opaque, size_t len);
void *opaque;
uint8_t evt_buf[256];
@@ -61,7 +61,7 @@ struct bt_hci_s {
struct bt_hci_master_link_s {
struct bt_link_s *link;
void (*lmp_acl_data)(struct bt_link_s *link,
- const uint8_t *data, int start, int len);
+ const uint8_t *data, int start, size_t len);
QEMUTimer *acl_mode_timer;
} handle[HCI_HANDLES_MAX];
uint32_t role_bmp;
@@ -433,7 +433,7 @@ static const uint8_t bt_event_reserved_mask[8] = {
};
-static void null_hci_send(struct HCIInfo *hci, const uint8_t *data, int len)
+static void null_hci_send(struct HCIInfo *hci, const uint8_t *data, size_t len)
{
}
@@ -451,13 +451,13 @@ struct HCIInfo null_hci = {
static inline uint8_t *bt_hci_event_start(struct bt_hci_s *hci,
- int evt, int len)
+ int evt, size_t len)
{
uint8_t *packet, mask;
int mask_byte;
if (len > 255) {
- error_report("%s: HCI event params too long (%ib)", __func__, len);
+ error_report("%s: HCI event params too long (%zub)", __func__, len);
exit(-1);
}
@@ -474,7 +474,7 @@ static inline uint8_t *bt_hci_event_start(struct bt_hci_s *hci,
}
static inline void bt_hci_event(struct bt_hci_s *hci, int evt,
- void *params, int len)
+ void *params, size_t len)
{
uint8_t *packet = bt_hci_event_start(hci, evt, len);
@@ -499,7 +499,7 @@ static inline void bt_hci_event_status(struct bt_hci_s *hci, int status)
}
static inline void bt_hci_event_complete(struct bt_hci_s *hci,
- void *ret, int len)
+ void *ret, size_t len)
{
uint8_t *packet = bt_hci_event_start(hci, EVT_CMD_COMPLETE,
len + EVT_CMD_COMPLETE_SIZE);
@@ -1476,7 +1476,7 @@ static inline void bt_hci_event_num_comp_pkts(struct bt_hci_s *hci,
}
static void bt_submit_hci(struct HCIInfo *info,
- const uint8_t *data, int length)
+ const uint8_t *data, size_t length)
{
struct bt_hci_s *hci = hci_from_info(info);
uint16_t cmd;
@@ -1970,7 +1970,7 @@ static void bt_submit_hci(struct HCIInfo *info,
break;
short_hci:
- error_report("%s: HCI packet too short (%iB)", __func__, length);
+ error_report("%s: HCI packet too short (%zuB)", __func__, length);
bt_hci_event_status(hci, HCI_INVALID_PARAMETERS);
break;
}
@@ -1981,7 +1981,7 @@ static void bt_submit_hci(struct HCIInfo *info,
* know that a packet contained the last fragment of the SDU when the next
* SDU starts. */
static inline void bt_hci_lmp_acl_data(struct bt_hci_s *hci, uint16_t handle,
- const uint8_t *data, int start, int len)
+ const uint8_t *data, int start, size_t len)
{
struct hci_acl_hdr *pkt = (void *) hci->acl_buf;
@@ -1989,7 +1989,7 @@ static inline void bt_hci_lmp_acl_data(struct bt_hci_s *hci, uint16_t handle,
/* TODO: avoid memcpy'ing */
if (len + HCI_ACL_HDR_SIZE > sizeof(hci->acl_buf)) {
- error_report("%s: can't take ACL packets %i bytes long",
+ error_report("%s: can't take ACL packets %zu bytes long",
__func__, len);
return;
}
@@ -2003,7 +2003,7 @@ static inline void bt_hci_lmp_acl_data(struct bt_hci_s *hci, uint16_t handle,
}
static void bt_hci_lmp_acl_data_slave(struct bt_link_s *btlink,
- const uint8_t *data, int start, int len)
+ const uint8_t *data, int start, size_t len)
{
struct bt_hci_link_s *link = (struct bt_hci_link_s *) btlink;
@@ -2012,14 +2012,14 @@ static void bt_hci_lmp_acl_data_slave(struct bt_link_s *btlink,
}
static void bt_hci_lmp_acl_data_host(struct bt_link_s *link,
- const uint8_t *data, int start, int len)
+ const uint8_t *data, int start, size_t len)
{
bt_hci_lmp_acl_data(hci_from_device(link->host),
link->handle, data, start, len);
}
static void bt_submit_acl(struct HCIInfo *info,
- const uint8_t *data, int length)
+ const uint8_t *data, size_t length)
{
struct bt_hci_s *hci = hci_from_info(info);
uint16_t handle;
@@ -2027,7 +2027,7 @@ static void bt_submit_acl(struct HCIInfo *info,
struct bt_link_s *link;
if (length < HCI_ACL_HDR_SIZE) {
- error_report("%s: ACL packet too short (%iB)", __func__, length);
+ error_report("%s: ACL packet too short (%zuB)", __func__, length);
return;
}
@@ -2045,7 +2045,7 @@ static void bt_submit_acl(struct HCIInfo *info,
handle &= ~HCI_HANDLE_OFFSET;
if (datalen > length) {
- error_report("%s: ACL packet too short (%iB < %iB)",
+ error_report("%s: ACL packet too short (%zuB < %iB)",
__func__, length, datalen);
return;
}
@@ -2087,7 +2087,7 @@ static void bt_submit_acl(struct HCIInfo *info,
}
static void bt_submit_sco(struct HCIInfo *info,
- const uint8_t *data, int length)
+ const uint8_t *data, size_t length)
{
struct bt_hci_s *hci = hci_from_info(info);
uint16_t handle;
@@ -2106,7 +2106,7 @@ static void bt_submit_sco(struct HCIInfo *info,
}
if (datalen > length) {
- error_report("%s: SCO packet too short (%iB < %iB)",
+ error_report("%s: SCO packet too short (%zuB < %iB)",
__func__, length, datalen);
return;
}
@@ -2127,7 +2127,7 @@ static uint8_t *bt_hci_evt_packet(void *opaque)
return s->evt_buf;
}
-static void bt_hci_evt_submit(void *opaque, int len)
+static void bt_hci_evt_submit(void *opaque, size_t len)
{
/* TODO: notify upper layer */
struct bt_hci_s *s = opaque;
diff --git a/hw/bt/hid.c b/hw/bt/hid.c
index 066ca99..fe15434 100644
--- a/hw/bt/hid.c
+++ b/hw/bt/hid.c
@@ -95,7 +95,7 @@ struct bt_hid_device_s {
int data_type;
int intr_state;
struct {
- int len;
+ size_t len;
uint8_t buffer[1024];
} dataother, datain, dataout, feature, intrdataout;
enum {
@@ -168,7 +168,7 @@ static void bt_hid_disconnect(struct bt_hid_device_s *s)
}
static void bt_hid_send_data(struct bt_l2cap_conn_params_s *ch, int type,
- const uint8_t *data, int len)
+ const uint8_t *data, size_t len)
{
uint8_t *pkt, hdr = (BT_DATA << 4) | type;
int plen;
@@ -189,7 +189,7 @@ static void bt_hid_send_data(struct bt_l2cap_conn_params_s *ch, int type,
}
static void bt_hid_control_transaction(struct bt_hid_device_s *s,
- const uint8_t *data, int len)
+ const uint8_t *data, size_t len)
{
uint8_t type, parameter;
int rlen, ret = -1;
@@ -361,7 +361,7 @@ static void bt_hid_control_transaction(struct bt_hid_device_s *s,
bt_hid_send_handshake(s, ret);
}
-static void bt_hid_control_sdu(void *opaque, const uint8_t *data, int len)
+static void bt_hid_control_sdu(void *opaque, const uint8_t *data, size_t len)
{
struct bt_hid_device_s *hid = opaque;
@@ -387,7 +387,7 @@ static void bt_hid_datain(HIDState *hs)
hid->datain.buffer, hid->datain.len);
}
-static void bt_hid_interrupt_sdu(void *opaque, const uint8_t *data, int len)
+static void bt_hid_interrupt_sdu(void *opaque, const uint8_t *data, size_t len)
{
struct bt_hid_device_s *hid = opaque;
diff --git a/hw/bt/l2cap.c b/hw/bt/l2cap.c
index d67098a..2f70a03 100644
--- a/hw/bt/l2cap.c
+++ b/hw/bt/l2cap.c
@@ -31,10 +31,10 @@ struct l2cap_instance_s {
int role;
uint8_t frame_in[65535 + L2CAP_HDR_SIZE] __attribute__ ((aligned (4)));
- int frame_in_len;
+ uint32_t frame_in_len;
uint8_t frame_out[65535 + L2CAP_HDR_SIZE] __attribute__ ((aligned (4)));
- int frame_out_len;
+ uint32_t frame_out_len;
/* Signalling channel timers. They exist per-request but we can make
* sure we have no more than one outstanding request at any time. */
@@ -48,7 +48,7 @@ struct l2cap_instance_s {
struct bt_l2cap_conn_params_s params;
void (*frame_in)(struct l2cap_chan_s *chan, uint16_t cid,
- const l2cap_hdr *hdr, int len);
+ const l2cap_hdr *hdr, size_t len);
int mps;
int min_mtu;
@@ -67,7 +67,7 @@ struct l2cap_instance_s {
/* Only flow-controlled, connection-oriented channels */
uint8_t sdu[65536]; /* TODO: dynamically allocate */
- int len_cur, len_total;
+ uint32_t len_cur, len_total;
int rexmit;
int monitor_timeout;
QEMUTimer *monitor_timer;
@@ -139,7 +139,7 @@ static const uint16_t l2cap_fcs16_table[256] = {
0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040,
};
-static uint16_t l2cap_fcs16(const uint8_t *message, int len)
+static uint16_t l2cap_fcs16(const uint8_t *message, size_t len)
{
uint16_t fcs = 0x0000;
@@ -185,7 +185,7 @@ static void l2cap_monitor_timer_update(struct l2cap_chan_s *ch)
}
static void l2cap_command_reject(struct l2cap_instance_s *l2cap, int id,
- uint16_t reason, const void *data, int plen)
+ uint16_t reason, const void *data, size_t plen)
{
uint8_t *pkt;
l2cap_cmd_hdr *hdr;
@@ -246,7 +246,7 @@ static void l2cap_connection_response(struct l2cap_instance_s *l2cap,
}
static void l2cap_configuration_request(struct l2cap_instance_s *l2cap,
- int dcid, int flag, const uint8_t *data, int len)
+ int dcid, int flag, const uint8_t *data, size_t len)
{
uint8_t *pkt;
l2cap_cmd_hdr *hdr;
@@ -274,7 +274,7 @@ static void l2cap_configuration_request(struct l2cap_instance_s *l2cap,
}
static void l2cap_configuration_response(struct l2cap_instance_s *l2cap,
- int scid, int flag, int result, const uint8_t *data, int len)
+ int scid, int flag, int result, const uint8_t *data, size_t len)
{
uint8_t *pkt;
l2cap_cmd_hdr *hdr;
@@ -321,7 +321,7 @@ static void l2cap_disconnection_response(struct l2cap_instance_s *l2cap,
}
static void l2cap_echo_response(struct l2cap_instance_s *l2cap,
- const uint8_t *data, int len)
+ const uint8_t *data, size_t len)
{
uint8_t *pkt;
l2cap_cmd_hdr *hdr;
@@ -342,7 +342,7 @@ static void l2cap_echo_response(struct l2cap_instance_s *l2cap,
}
static void l2cap_info_response(struct l2cap_instance_s *l2cap, int type,
- int result, const uint8_t *data, int len)
+ int result, const uint8_t *data, size_t len)
{
uint8_t *pkt;
l2cap_cmd_hdr *hdr;
@@ -365,16 +365,18 @@ static void l2cap_info_response(struct l2cap_instance_s *l2cap, int type,
l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
}
-static uint8_t *l2cap_bframe_out(struct bt_l2cap_conn_params_s *parm, int len);
+static uint8_t *l2cap_bframe_out(struct bt_l2cap_conn_params_s *parm,
+ size_t len);
static void l2cap_bframe_submit(struct bt_l2cap_conn_params_s *parms);
#if 0
-static uint8_t *l2cap_iframe_out(struct bt_l2cap_conn_params_s *parm, int len);
+static uint8_t *l2cap_iframe_out(struct bt_l2cap_conn_params_s *parm,
+ size_t len);
static void l2cap_iframe_submit(struct bt_l2cap_conn_params_s *parm);
#endif
static void l2cap_bframe_in(struct l2cap_chan_s *ch, uint16_t cid,
- const l2cap_hdr *hdr, int len);
+ const l2cap_hdr *hdr, size_t len);
static void l2cap_iframe_in(struct l2cap_chan_s *ch, uint16_t cid,
- const l2cap_hdr *hdr, int len);
+ const l2cap_hdr *hdr, size_t len);
static int l2cap_cid_new(struct l2cap_instance_s *l2cap)
{
@@ -498,7 +500,7 @@ static void l2cap_channel_config_req_event(struct l2cap_instance_s *l2cap,
static int l2cap_channel_config(struct l2cap_instance_s *l2cap,
struct l2cap_chan_s *ch, int flag,
- const uint8_t *data, int len)
+ const uint8_t *data, size_t len)
{
l2cap_conf_opt *opt;
l2cap_conf_opt_qos *qos;
@@ -683,7 +685,7 @@ static int l2cap_channel_config(struct l2cap_instance_s *l2cap,
}
static void l2cap_channel_config_req_msg(struct l2cap_instance_s *l2cap,
- int flag, int cid, const uint8_t *data, int len)
+ int flag, int cid, const uint8_t *data, size_t len)
{
struct l2cap_chan_s *ch;
@@ -715,7 +717,7 @@ static void l2cap_channel_config_req_msg(struct l2cap_instance_s *l2cap,
}
static int l2cap_channel_config_rsp_msg(struct l2cap_instance_s *l2cap,
- int result, int flag, int cid, const uint8_t *data, int len)
+ int result, int flag, int cid, const uint8_t *data, size_t len)
{
struct l2cap_chan_s *ch;
@@ -783,7 +785,7 @@ static void l2cap_info(struct l2cap_instance_s *l2cap, int type)
}
static void l2cap_command(struct l2cap_instance_s *l2cap, int code, int id,
- const uint8_t *params, int len)
+ const uint8_t *params, size_t len)
{
int err;
@@ -938,7 +940,7 @@ static void l2cap_rexmit_enable(struct l2cap_chan_s *ch, int enable)
}
/* Command frame SDU */
-static void l2cap_cframe_in(void *opaque, const uint8_t *data, int len)
+static void l2cap_cframe_in(void *opaque, const uint8_t *data, size_t len)
{
struct l2cap_instance_s *l2cap = opaque;
const l2cap_cmd_hdr *hdr;
@@ -966,7 +968,7 @@ static void l2cap_cframe_in(void *opaque, const uint8_t *data, int len)
}
/* Group frame SDU */
-static void l2cap_gframe_in(void *opaque, const uint8_t *data, int len)
+static void l2cap_gframe_in(void *opaque, const uint8_t *data, size_t len)
{
}
@@ -977,7 +979,7 @@ static void l2cap_sframe_in(struct l2cap_chan_s *ch, uint16_t ctrl)
/* Basic L2CAP mode Information frame */
static void l2cap_bframe_in(struct l2cap_chan_s *ch, uint16_t cid,
- const l2cap_hdr *hdr, int len)
+ const l2cap_hdr *hdr, size_t len)
{
/* We have a full SDU, no further processing */
ch->params.sdu_in(ch->params.opaque, hdr->data, len);
@@ -985,7 +987,7 @@ static void l2cap_bframe_in(struct l2cap_chan_s *ch, uint16_t cid,
/* Flow Control and Retransmission mode frame */
static void l2cap_iframe_in(struct l2cap_chan_s *ch, uint16_t cid,
- const l2cap_hdr *hdr, int len)
+ const l2cap_hdr *hdr, size_t len)
{
uint16_t fcs = lduw_le_p(hdr->data + len - 2);
@@ -1076,7 +1078,7 @@ static void l2cap_frame_in(struct l2cap_instance_s *l2cap,
/* "Recombination" */
static void l2cap_pdu_in(struct l2cap_instance_s *l2cap,
- const uint8_t *data, int len)
+ const uint8_t *data, size_t len)
{
const l2cap_hdr *hdr = (void *) l2cap->frame_in;
@@ -1123,7 +1125,7 @@ static inline void l2cap_pdu_submit(struct l2cap_instance_s *l2cap)
(l2cap->link, l2cap->frame_out, 1, l2cap->frame_out_len);
}
-static uint8_t *l2cap_bframe_out(struct bt_l2cap_conn_params_s *parm, int len)
+static uint8_t *l2cap_bframe_out(struct bt_l2cap_conn_params_s *parm, size_t len)
{
struct l2cap_chan_s *chan = (struct l2cap_chan_s *) parm;
@@ -1146,7 +1148,7 @@ static void l2cap_bframe_submit(struct bt_l2cap_conn_params_s *parms)
#if 0
/* Stub: Only used if an emulated device requests outgoing flow control */
-static uint8_t *l2cap_iframe_out(struct bt_l2cap_conn_params_s *parm, int len)
+static uint8_t *l2cap_iframe_out(struct bt_l2cap_conn_params_s *parm, size_t len)
{
struct l2cap_chan_s *chan = (struct l2cap_chan_s *) parm;
@@ -1291,7 +1293,7 @@ static void l2cap_lmp_disconnect_slave(struct bt_link_s *link)
}
static void l2cap_lmp_acl_data_slave(struct bt_link_s *link,
- const uint8_t *data, int start, int len)
+ const uint8_t *data, int start, size_t len)
{
struct slave_l2cap_instance_s *l2cap =
(struct slave_l2cap_instance_s *) link;
@@ -1304,7 +1306,7 @@ static void l2cap_lmp_acl_data_slave(struct bt_link_s *link,
/* Stub */
static void l2cap_lmp_acl_data_host(struct bt_link_s *link,
- const uint8_t *data, int start, int len)
+ const uint8_t *data, int start, size_t len)
{
struct bt_l2cap_device_s *dev = (struct bt_l2cap_device_s *) link->host;
struct l2cap_instance_s *l2cap =
diff --git a/hw/bt/sdp.c b/hw/bt/sdp.c
index 2860d76..6bfb174 100644
--- a/hw/bt/sdp.c
+++ b/hw/bt/sdp.c
@@ -496,7 +496,7 @@ static ssize_t sdp_svc_search_attr_get(struct bt_l2cap_sdp_state_s *sdp,
return end + 2;
}
-static void bt_l2cap_sdp_sdu_in(void *opaque, const uint8_t *data, int len)
+static void bt_l2cap_sdp_sdu_in(void *opaque, const uint8_t *data, size_t len)
{
struct bt_l2cap_sdp_state_s *sdp = opaque;
enum bt_sdp_cmd pdu_id;
@@ -506,7 +506,7 @@ static void bt_l2cap_sdp_sdu_in(void *opaque, const uint8_t *data, int len)
int rsp_len = 0;
if (len < 5) {
- error_report("%s: short SDP PDU (%iB).", __func__, len);
+ error_report("%s: short SDP PDU (%zuB).", __func__, len);
return;
}
@@ -517,7 +517,7 @@ static void bt_l2cap_sdp_sdu_in(void *opaque, const uint8_t *data, int len)
len -= 5;
if (len != plen) {
- error_report("%s: wrong SDP PDU length (%iB != %iB).",
+ error_report("%s: wrong SDP PDU length (%iB != %zuB).",
__func__, plen, len);
err = SDP_INVALID_PDU_SIZE;
goto respond;
diff --git a/hw/usb/dev-bluetooth.c b/hw/usb/dev-bluetooth.c
index 670ba32..240a901 100644
--- a/hw/usb/dev-bluetooth.c
+++ b/hw/usb/dev-bluetooth.c
@@ -265,7 +265,7 @@ static void usb_bt_fifo_reset(struct usb_hci_in_fifo_s *fifo)
}
static void usb_bt_fifo_enqueue(struct usb_hci_in_fifo_s *fifo,
- const uint8_t *data, int len)
+ const uint8_t *data, size_t len)
{
int off = fifo->dstart + fifo->dlen;
uint8_t *buf;
@@ -274,13 +274,13 @@ static void usb_bt_fifo_enqueue(struct usb_hci_in_fifo_s *fifo,
if (off <= DFIFO_LEN_MASK) {
if (off + len > DFIFO_LEN_MASK + 1 &&
(fifo->dsize = off + len) > (DFIFO_LEN_MASK + 1) * 2) {
- fprintf(stderr, "%s: can't alloc %i bytes\n", __func__, len);
+ fprintf(stderr, "%s: can't alloc %zu bytes\n", __func__, len);
exit(-1);
}
buf = fifo->data + off;
} else {
if (fifo->dlen > fifo->dsize) {
- fprintf(stderr, "%s: can't alloc %i bytes\n", __func__, len);
+ fprintf(stderr, "%s: can't alloc %zu bytes\n", __func__, len);
exit(-1);
}
buf = fifo->data + off - fifo->dsize;
@@ -319,7 +319,7 @@ static inline void usb_bt_fifo_dequeue(struct usb_hci_in_fifo_s *fifo,
static inline void usb_bt_fifo_out_enqueue(struct USBBtState *s,
struct usb_hci_out_fifo_s *fifo,
- void (*send)(struct HCIInfo *, const uint8_t *, int),
+ void (*send)(struct HCIInfo *, const uint8_t *, size_t),
int (*complete)(const uint8_t *, int),
USBPacket *p)
{
@@ -478,7 +478,7 @@ static void usb_bt_handle_data(USBDevice *dev, USBPacket *p)
}
static void usb_bt_out_hci_packet_event(void *opaque,
- const uint8_t *data, int len)
+ const uint8_t *data, size_t len)
{
struct USBBtState *s = (struct USBBtState *) opaque;
@@ -489,7 +489,7 @@ static void usb_bt_out_hci_packet_event(void *opaque,
}
static void usb_bt_out_hci_packet_acl(void *opaque,
- const uint8_t *data, int len)
+ const uint8_t *data, size_t len)
{
struct USBBtState *s = (struct USBBtState *) opaque;
diff --git a/include/hw/bt.h b/include/hw/bt.h
index b5e11d4..bc362aa 100644
--- a/include/hw/bt.h
+++ b/include/hw/bt.h
@@ -94,9 +94,9 @@ struct bt_device_s {
void (*lmp_disconnect_master)(struct bt_link_s *link);
void (*lmp_disconnect_slave)(struct bt_link_s *link);
void (*lmp_acl_data)(struct bt_link_s *link, const uint8_t *data,
- int start, int len);
+ int start, size_t len);
void (*lmp_acl_resp)(struct bt_link_s *link, const uint8_t *data,
- int start, int len);
+ int start, size_t len);
void (*lmp_mode_change)(struct bt_link_s *link);
void (*handle_destroy)(struct bt_device_s *device);
@@ -148,12 +148,12 @@ struct bt_l2cap_device_s {
struct bt_l2cap_conn_params_s {
/* Input */
- uint8_t *(*sdu_out)(struct bt_l2cap_conn_params_s *chan, int len);
+ uint8_t *(*sdu_out)(struct bt_l2cap_conn_params_s *chan, size_t len);
void (*sdu_submit)(struct bt_l2cap_conn_params_s *chan);
int remote_mtu;
/* Output */
void *opaque;
- void (*sdu_in)(void *opaque, const uint8_t *data, int len);
+ void (*sdu_in)(void *opaque, const uint8_t *data, size_t len);
void (*close)(void *opaque);
};
diff --git a/include/sysemu/bt.h b/include/sysemu/bt.h
index 2fd8c0f..df8fb63 100644
--- a/include/sysemu/bt.h
+++ b/include/sysemu/bt.h
@@ -5,12 +5,12 @@
typedef struct HCIInfo {
int (*bdaddr_set)(struct HCIInfo *hci, const uint8_t *bd_addr);
- void (*cmd_send)(struct HCIInfo *hci, const uint8_t *data, int len);
- void (*sco_send)(struct HCIInfo *hci, const uint8_t *data, int len);
- void (*acl_send)(struct HCIInfo *hci, const uint8_t *data, int len);
+ void (*cmd_send)(struct HCIInfo *hci, const uint8_t *data, size_t len);
+ void (*sco_send)(struct HCIInfo *hci, const uint8_t *data, size_t len);
+ void (*acl_send)(struct HCIInfo *hci, const uint8_t *data, size_t len);
void *opaque;
- void (*evt_recv)(void *opaque, const uint8_t *data, int len);
- void (*acl_recv)(void *opaque, const uint8_t *data, int len);
+ void (*evt_recv)(void *opaque, const uint8_t *data, size_t len);
+ void (*acl_recv)(void *opaque, const uint8_t *data, size_t len);
} HCIInfo;
/* bt-host.c */
--
1.8.3.1

View File

@ -1,44 +0,0 @@
From b9e4a4ff6f3292927adb1463777c86cd4063a6ef Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Sat, 18 Apr 2020 12:10:11 +0800
Subject: [PATCH] bugfix: Use gicr_typer in arm_gicv3_icc_reset
The KVM_VGIC_ATTR macro expect the second parameter as gicr_typer,
of which high 32bit is constructed by mp_affinity. For most case,
the high 32bit of mp_affinity is zero, so it will always access the
ICC_CTLR_EL1 of CPU0.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
---
hw/intc/arm_gicv3_kvm.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c
index d9c72f85be..b1e74147ba 100644
--- a/hw/intc/arm_gicv3_kvm.c
+++ b/hw/intc/arm_gicv3_kvm.c
@@ -661,13 +661,11 @@ static void kvm_arm_gicv3_get(GICv3State *s)
static void arm_gicv3_icc_reset(CPUARMState *env, const ARMCPRegInfo *ri)
{
- ARMCPU *cpu;
GICv3State *s;
GICv3CPUState *c;
c = (GICv3CPUState *)env->gicv3state;
s = c->gic;
- cpu = ARM_CPU(c->cpu);
c->icc_pmr_el1 = 0;
c->icc_bpr[GICV3_G0] = GIC_MIN_BPR;
@@ -684,7 +682,7 @@ static void arm_gicv3_icc_reset(CPUARMState *env, const ARMCPRegInfo *ri)
/* Initialize to actual HW supported configuration */
kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS,
- KVM_VGIC_ATTR(ICC_CTLR_EL1, cpu->mp_affinity),
+ KVM_VGIC_ATTR(ICC_CTLR_EL1, c->gicr_typer),
&c->icc_ctlr_el1[GICV3_NS], false, &error_abort);
c->icc_ctlr_el1[GICV3_S] = c->icc_ctlr_el1[GICV3_NS];
--
2.19.1

View File

@ -1,104 +0,0 @@
From af8740502815be450709e88df44ad322da2b071f Mon Sep 17 00:00:00 2001
From: Henglong Fan <fanhenglong@huawei.com>
Date: Tue, 18 Aug 2020 21:42:33 +0800
Subject: [PATCH] build smt processor structure to support smt topology
if vcpu support smt, create new smt hierarchy according to
Processor Properties Topology Table(PPTT) in acpi spec 6.3.
Threads sharing a core must be grouped under a unique Processor
hierarchy node structure for each group of threads
Signed-off-by: Henglong Fan <fanhenglong@huawei.com>
---
hw/acpi/aml-build.c | 40 ++++++++++++++++++++++++++++++++--------
1 file changed, 32 insertions(+), 8 deletions(-)
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index 74e95005..8a3b51c8 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -53,7 +53,7 @@ static void build_append_array(GArray *array, GArray *val)
}
/*
- * ACPI 6.2 Processor Properties Topology Table (PPTT)
+ * ACPI 6.3 Processor Properties Topology Table (PPTT)
*/
#ifdef __aarch64__
static void build_cache_head(GArray *tbl, uint32_t next_level)
@@ -126,7 +126,7 @@ static void build_arm_socket_hierarchy(GArray *tbl,
build_append_int_noprefix(tbl, offset, 4);
}
-static void build_arm_cpu_hierarchy(GArray *tbl,
+static void build_arm_core_hierarchy(GArray *tbl,
struct offset_status *offset, uint32_t id)
{
if (!offset) {
@@ -144,18 +144,35 @@ static void build_arm_cpu_hierarchy(GArray *tbl,
build_append_int_noprefix(tbl, offset->l2_offset, 4);
}
+static void build_arm_smt_hierarchy(GArray *tbl,
+ uint32_t offset, uint32_t id)
+{
+ if (!offset) {
+ return;
+ }
+ build_append_byte(tbl, 0); /* Type 0 - processor */
+ build_append_byte(tbl, 20); /* Length, add private resources */
+ build_append_int_noprefix(tbl, 0, 2); /* Reserved */
+ build_append_int_noprefix(tbl, 14, 4); /* Valid id*/
+ build_append_int_noprefix(tbl, offset, 4);
+ build_append_int_noprefix(tbl, id, 4);
+ build_append_int_noprefix(tbl, 0, 4); /* Num private resources */
+}
+
void build_pptt(GArray *table_data, BIOSLinker *linker, int possible_cpus)
{
int pptt_start = table_data->len;
- int uid = 0, cpus = 0, socket;
+ int uid = 0, socket;
+ uint32_t core_offset;
struct offset_status offset;
const MachineState *ms = MACHINE(qdev_get_machine());
unsigned int smp_cores = ms->smp.cores;
+ unsigned int smp_sockets = ms->smp.cpus / (smp_cores * ms->smp.threads);
acpi_data_push(table_data, sizeof(AcpiTableHeader));
- for (socket = 0; cpus < possible_cpus; socket++) {
- int core;
+ for (socket = 0; socket < smp_sockets; socket++) {
+ int core,thread;
uint32_t l3_offset = table_data->len - pptt_start;
build_cache_hierarchy(table_data, 0, ARM_L3_CACHE);
@@ -169,14 +186,21 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, int possible_cpus)
build_cache_hierarchy(table_data, offset.l2_offset, ARM_L1D_CACHE);
offset.l1i_offset = table_data->len - pptt_start;
build_cache_hierarchy(table_data, offset.l2_offset, ARM_L1I_CACHE);
- build_arm_cpu_hierarchy(table_data, &offset, uid++);
- cpus++;
+ core_offset = table_data->len - pptt_start;
+ if (ms->smp.threads <= 1) {
+ build_arm_core_hierarchy(table_data, &offset, uid++);
+ } else {
+ build_arm_core_hierarchy(table_data, &offset, core);
+ for (thread = 0; thread < ms->smp.threads; thread++) {
+ build_arm_smt_hierarchy(table_data, core_offset, uid++);
+ }
+ }
}
}
build_header(linker, table_data,
(void *)(table_data->data + pptt_start), "PPTT",
- table_data->len - pptt_start, 1, NULL, NULL);
+ table_data->len - pptt_start, 2, NULL, NULL);
}
#else
--
2.23.0

View File

@ -1,126 +0,0 @@
From 902a8192600ff81681a162509e23bf95619d1f04 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
Date: Mon, 20 Apr 2020 13:20:12 +0200
Subject: [PATCH] char: fix use-after-free with dup chardev & reconnect
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
With a reconnect socket, qemu_char_open() will start a background
thread. It should keep a reference on the chardev.
Fixes invalid read:
READ of size 8 at 0x6040000ac858 thread T7
#0 0x5555598d37b8 in unix_connect_saddr /home/elmarco/src/qq/util/qemu-sockets.c:954
#1 0x5555598d4751 in socket_connect /home/elmarco/src/qq/util/qemu-sockets.c:1109
#2 0x555559707c34 in qio_channel_socket_connect_sync /home/elmarco/src/qq/io/channel-socket.c:145
#3 0x5555596adebb in tcp_chr_connect_client_task /home/elmarco/src/qq/chardev/char-socket.c:1104
#4 0x555559723d55 in qio_task_thread_worker /home/elmarco/src/qq/io/task.c:123
#5 0x5555598a6731 in qemu_thread_start /home/elmarco/src/qq/util/qemu-thread-posix.c:519
#6 0x7ffff40d4431 in start_thread (/lib64/libpthread.so.0+0x9431)
#7 0x7ffff40029d2 in __clone (/lib64/libc.so.6+0x1019d2)
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Message-Id: <20200420112012.567284-1-marcandre.lureau@redhat.com>
Signed-off-by: Zhenyu Ye <yezhenyu2@huawei.com>
---
chardev/char-socket.c | 3 ++-
tests/test-char.c | 53 ++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 54 insertions(+), 2 deletions(-)
diff --git a/chardev/char-socket.c b/chardev/char-socket.c
index 7ca5d97a..701b62f9 100644
--- a/chardev/char-socket.c
+++ b/chardev/char-socket.c
@@ -1118,7 +1118,8 @@ static void tcp_chr_connect_client_async(Chardev *chr)
*/
s->connect_task = qio_task_new(OBJECT(sioc),
qemu_chr_socket_connected,
- chr, NULL);
+ object_ref(OBJECT(chr)),
+ (GDestroyNotify)object_unref);
qio_task_run_in_thread(s->connect_task,
tcp_chr_connect_client_task,
s->addr,
diff --git a/tests/test-char.c b/tests/test-char.c
index f9440cdc..0e4069fb 100644
--- a/tests/test-char.c
+++ b/tests/test-char.c
@@ -871,6 +871,53 @@ typedef struct {
} CharSocketClientTestConfig;
+static void char_socket_client_dupid_test(gconstpointer opaque)
+{
+ const CharSocketClientTestConfig *config = opaque;
+ QIOChannelSocket *ioc;
+ char *optstr;
+ Chardev *chr1, *chr2;
+ SocketAddress *addr;
+ QemuOpts *opts;
+ Error *local_err = NULL;
+
+ /*
+ * Setup a listener socket and determine get its address
+ * so we know the TCP port for the client later
+ */
+ ioc = qio_channel_socket_new();
+ g_assert_nonnull(ioc);
+ qio_channel_socket_listen_sync(ioc, config->addr, &error_abort);
+ addr = qio_channel_socket_get_local_address(ioc, &error_abort);
+ g_assert_nonnull(addr);
+
+ /*
+ * Populate the chardev address based on what the server
+ * is actually listening on
+ */
+ optstr = char_socket_addr_to_opt_str(addr,
+ config->fd_pass,
+ config->reconnect,
+ false);
+
+ opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"),
+ optstr, true);
+ g_assert_nonnull(opts);
+ chr1 = qemu_chr_new_from_opts(opts, NULL, &error_abort);
+ g_assert_nonnull(chr1);
+
+ chr2 = qemu_chr_new_from_opts(opts, NULL, &local_err);
+ g_assert_null(chr2);
+ error_free_or_abort(&local_err);
+
+ object_unref(OBJECT(ioc));
+ qemu_opts_del(opts);
+ object_unparent(OBJECT(chr1));
+ qapi_free_SocketAddress(addr);
+ g_free(optstr);
+}
+
+
static void char_socket_client_test(gconstpointer opaque)
{
const CharSocketClientTestConfig *config = opaque;
@@ -1425,6 +1472,8 @@ int main(int argc, char **argv)
{ addr, NULL, false, true }; \
CharSocketClientTestConfig client6 ## name = \
{ addr, NULL, true, true }; \
+ CharSocketClientTestConfig client7 ## name = \
+ { addr, ",reconnect=1", false, false }; \
g_test_add_data_func("/char/socket/client/mainloop/" # name, \
&client1 ##name, char_socket_client_test); \
g_test_add_data_func("/char/socket/client/wait-conn/" # name, \
@@ -1436,7 +1485,9 @@ int main(int argc, char **argv)
g_test_add_data_func("/char/socket/client/mainloop-fdpass/" # name, \
&client5 ##name, char_socket_client_test); \
g_test_add_data_func("/char/socket/client/wait-conn-fdpass/" # name, \
- &client6 ##name, char_socket_client_test)
+ &client6 ##name, char_socket_client_test); \
+ g_test_add_data_func("/char/socket/client/dupid-reconnect/" # name, \
+ &client7 ##name, char_socket_client_dupid_test)
SOCKET_SERVER_TEST(tcp, &tcpaddr);
SOCKET_CLIENT_TEST(tcp, &tcpaddr);
--
2.22.0.windows.1

View File

@ -1,43 +0,0 @@
From 4488ab4700d344b049ddef808a64eda4b5867902 Mon Sep 17 00:00:00 2001
From: lichun <lichun@ruijie.com.cn>
Date: Mon, 22 Jun 2020 05:30:17 +0800
Subject: [PATCH 06/11] chardev/tcp: Fix error message double free error
Errors are already freed by error_report_err, so we only need to call
error_free when that function is not called.
Cc: qemu-stable@nongnu.org
Signed-off-by: lichun <lichun@ruijie.com.cn>
Message-Id: <20200621213017.17978-1-lichun@ruijie.com.cn>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
[Commit message improved, cc: qemu-stable]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: BiaoXiang Ye <yebiaoxiang@huawei.com>
---
chardev/char-socket.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/chardev/char-socket.c b/chardev/char-socket.c
index 701b62f9..9b06c8aa 100644
--- a/chardev/char-socket.c
+++ b/chardev/char-socket.c
@@ -141,6 +141,8 @@ static void check_report_connect_error(Chardev *chr,
error_report("Unable to connect character device %s: %s",
chr->label, error_get_pretty(err));
s->connect_err_reported = true;
+ } else {
+ error_free(err);
}
qemu_chr_socket_restart_timer(chr);
}
@@ -1074,7 +1076,6 @@ static void qemu_chr_socket_connected(QIOTask *task, void *opaque)
if (qio_task_propagate_error(task, &err)) {
tcp_chr_change_state(s, TCP_CHARDEV_STATE_DISCONNECTED);
check_report_connect_error(chr, err);
- error_free(err);
goto cleanup;
}
--
2.27.0.dirty

View File

@ -1,90 +0,0 @@
From 19afb1431bd730a1e4e09e3c0835c35572517268 Mon Sep 17 00:00:00 2001
From: Derek Su <dereksu@qnap.com>
Date: Fri, 22 May 2020 15:53:57 +0800
Subject: [PATCH 07/11] colo-compare: Fix memory leak in packet_enqueue()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The patch is to fix the "pkt" memory leak in packet_enqueue().
The allocated "pkt" needs to be freed if the colo compare
primary or secondary queue is too big.
Replace the error_report of full queue with a trace event.
Signed-off-by: Derek Su <dereksu@qnap.com>
Reviewed-by: Zhang Chen <chen.zhang@intel.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Signed-off-by: Zhang Chen <chen.zhang@intel.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: BiaoXiang Ye <yebiaoxiang@huawei.com>
---
net/colo-compare.c | 23 +++++++++++++++--------
net/trace-events | 1 +
2 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/net/colo-compare.c b/net/colo-compare.c
index 7ee17f2c..3168407e 100644
--- a/net/colo-compare.c
+++ b/net/colo-compare.c
@@ -120,6 +120,10 @@ enum {
SECONDARY_IN,
};
+static const char *colo_mode[] = {
+ [PRIMARY_IN] = "primary",
+ [SECONDARY_IN] = "secondary",
+};
static int compare_chr_send(CompareState *s,
const uint8_t *buf,
@@ -215,6 +219,7 @@ static int packet_enqueue(CompareState *s, int mode, Connection **con)
ConnectionKey key;
Packet *pkt = NULL;
Connection *conn;
+ int ret;
if (mode == PRIMARY_IN) {
pkt = packet_new(s->pri_rs.buf,
@@ -243,16 +248,18 @@ static int packet_enqueue(CompareState *s, int mode, Connection **con)
}
if (mode == PRIMARY_IN) {
- if (!colo_insert_packet(&conn->primary_list, pkt, &conn->pack)) {
- error_report("colo compare primary queue size too big,"
- "drop packet");
- }
+ ret = colo_insert_packet(&conn->primary_list, pkt, &conn->pack);
} else {
- if (!colo_insert_packet(&conn->secondary_list, pkt, &conn->sack)) {
- error_report("colo compare secondary queue size too big,"
- "drop packet");
- }
+ ret = colo_insert_packet(&conn->secondary_list, pkt, &conn->sack);
}
+
+ if (!ret) {
+ trace_colo_compare_drop_packet(colo_mode[mode],
+ "queue size too big, drop packet");
+ packet_destroy(pkt, NULL);
+ pkt = NULL;
+ }
+
*con = conn;
return 0;
diff --git a/net/trace-events b/net/trace-events
index ac570564..a9995387 100644
--- a/net/trace-events
+++ b/net/trace-events
@@ -12,6 +12,7 @@ colo_proxy_main(const char *chr) ": %s"
# colo-compare.c
colo_compare_main(const char *chr) ": %s"
+colo_compare_drop_packet(const char *queue, const char *chr) ": %s: %s"
colo_compare_udp_miscompare(const char *sta, int size) ": %s = %d"
colo_compare_icmp_miscompare(const char *sta, int size) ": %s = %d"
colo_compare_ip_info(int psize, const char *sta, const char *stb, int ssize, const char *stc, const char *std) "ppkt size = %d, ip_src = %s, ip_dst = %s, spkt size = %d, ip_src = %s, ip_dst = %s"
--
2.27.0.dirty

View File

@ -1,121 +0,0 @@
From 5a79ccd388ee09dc1db93d26791d1e4a6b2ced47 Mon Sep 17 00:00:00 2001
From: Juan Quintela <quintela@redhat.com>
Date: Wed, 3 Feb 2021 17:33:44 +0800
Subject: [PATCH] configure: Enable test and libs for zstd
configure: Enable test and libs for zstd
Add it to several build systems to make testing good.
Signed-off-by: Juan Quintela <quintela@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Signed-off-by: Jiajie Li <lijiajie11@huawei.com>
---
.gitlab-ci.yml | 1 +
.travis.yml | 1 +
configure | 30 ++++++++++++++++++++++++++++++
3 files changed, 32 insertions(+)
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index c63bf2f822..3d9b7f9262 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -16,6 +16,7 @@ build-system2:
script:
- apt-get install -y -qq libsdl2-dev libgcrypt-dev libbrlapi-dev libaio-dev
libfdt-dev liblzo2-dev librdmacm-dev libibverbs-dev libibumad-dev
+ libzstd-dev
- ./configure --enable-werror --target-list="tricore-softmmu unicore32-softmmu
microblaze-softmmu mips-softmmu riscv32-softmmu s390x-softmmu sh4-softmmu
sparc64-softmmu x86_64-softmmu xtensa-softmmu nios2-softmmu or1k-softmmu"
diff --git a/.travis.yml b/.travis.yml
index caf0a1f8fa..f3fe04fba9 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -35,6 +35,7 @@ addons:
- liburcu-dev
- libusb-1.0-0-dev
- libvte-2.91-dev
+ - libzstd-dev
- sparse
- uuid-dev
- gcovr
diff --git a/configure b/configure
index 714e7fb6a1..577533e9ed 100755
--- a/configure
+++ b/configure
@@ -446,6 +446,7 @@ lzo=""
snappy=""
bzip2=""
lzfse=""
+zstd=""
guest_agent=""
guest_agent_with_vss="no"
guest_agent_ntddscsi="no"
@@ -1358,6 +1359,10 @@ for opt do
;;
--disable-lzfse) lzfse="no"
;;
+ --disable-zstd) zstd="no"
+ ;;
+ --enable-zstd) zstd="yes"
+ ;;
--enable-guest-agent) guest_agent="yes"
;;
--disable-guest-agent) guest_agent="no"
@@ -1812,6 +1817,8 @@ disabled with --disable-FEATURE, default is enabled if available:
(for reading bzip2-compressed dmg images)
lzfse support of lzfse compression library
(for reading lzfse-compressed dmg images)
+ zstd support for zstd compression library
+ (for migration compression)
seccomp seccomp support
coroutine-pool coroutine freelist (better performance)
glusterfs GlusterFS backend
@@ -2407,6 +2414,24 @@ EOF
fi
fi
+##########################################
+# zstd check
+
+if test "$zstd" != "no" ; then
+ if $pkg_config --exist libzstd ; then
+ zstd_cflags="$($pkg_config --cflags libzstd)"
+ zstd_libs="$($pkg_config --libs libzstd)"
+ LIBS="$zstd_libs $LIBS"
+ QEMU_CFLAGS="$QEMU_CFLAGS $zstd_cflags"
+ zstd="yes"
+ else
+ if test "$zstd" = "yes" ; then
+ feature_not_found "libzstd" "Install libzstd devel"
+ fi
+ zstd="no"
+ fi
+fi
+
##########################################
# libseccomp check
@@ -6460,6 +6485,7 @@ echo "lzo support $lzo"
echo "snappy support $snappy"
echo "bzip2 support $bzip2"
echo "lzfse support $lzfse"
+echo "zstd support $zstd"
echo "NUMA host support $numa"
echo "libxml2 $libxml2"
echo "tcmalloc support $tcmalloc"
@@ -7024,6 +7050,10 @@ if test "$lzfse" = "yes" ; then
echo "LZFSE_LIBS=-llzfse" >> $config_host_mak
fi
+if test "$zstd" = "yes" ; then
+ echo "CONFIG_ZSTD=y" >> $config_host_mak
+fi
+
if test "$libiscsi" = "yes" ; then
echo "CONFIG_LIBISCSI=m" >> $config_host_mak
echo "LIBISCSI_CFLAGS=$libiscsi_cflags" >> $config_host_mak
--
2.27.0

Some files were not shown because too many files have changed in this diff Show More