Compare commits
No commits in common. 'c9' and 'i9-beta-el9_4' have entirely different histories.
c9
...
i9-beta-el
@ -1,128 +0,0 @@
|
||||
From ef212eb3026a2460f6502a76afa3baedeb74d975 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
|
||||
Date: Tue, 6 Aug 2024 14:14:27 +0400
|
||||
Subject: [PATCH 1/5] Fix scanout version with pc-q35-rhel9.4.0
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
RH-Author: Marc-André Lureau <marcandre.lureau@redhat.com>
|
||||
RH-MergeRequest: 383: Fix scanout version with pc-q35-rhel9.4.0
|
||||
RH-Jira: RHEL-53565
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [1/1] ed2860cfb933654b0046c1b59f78d2e50146bd6c
|
||||
|
||||
Resolves: https://issues.redhat.com/browse/RHEL-52940
|
||||
|
||||
Introduce hw_compat_rhel_9_4_extra so that pc-q35-rhel9.4.0 has
|
||||
x-scanout-vmstate-version=1
|
||||
|
||||
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
|
||||
---
|
||||
hw/arm/virt.c | 1 +
|
||||
hw/core/machine.c | 13 +++++++++++--
|
||||
hw/i386/pc_piix.c | 2 ++
|
||||
hw/i386/pc_q35.c | 3 +++
|
||||
hw/s390x/s390-virtio-ccw.c | 1 +
|
||||
include/hw/boards.h | 3 +++
|
||||
6 files changed, 21 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
|
||||
index e4a66affcb..851eff6b28 100644
|
||||
--- a/hw/arm/virt.c
|
||||
+++ b/hw/arm/virt.c
|
||||
@@ -3670,6 +3670,7 @@ type_init(rhel_machine_init);
|
||||
|
||||
static void rhel940_virt_options(MachineClass *mc)
|
||||
{
|
||||
+ compat_props_add(mc->compat_props, hw_compat_rhel_9_4_extra, hw_compat_rhel_9_4_extra_len);
|
||||
}
|
||||
DEFINE_RHEL_MACHINE_AS_LATEST(9, 4, 0)
|
||||
|
||||
diff --git a/hw/core/machine.c b/hw/core/machine.c
|
||||
index c8c460c916..fe0a28ef3b 100644
|
||||
--- a/hw/core/machine.c
|
||||
+++ b/hw/core/machine.c
|
||||
@@ -64,6 +64,17 @@ const size_t hw_compat_7_2_len = G_N_ELEMENTS(hw_compat_7_2);
|
||||
const char *rhel_old_machine_deprecation =
|
||||
"machine types for previous major releases are deprecated";
|
||||
|
||||
+/*
|
||||
+ * rhel_9_4_extra is used for <= 9.4 machines.
|
||||
+ *
|
||||
+ * (for compatibility and historical reasons, rhel_9_4 is used for <= 9.2 too)
|
||||
+ */
|
||||
+GlobalProperty hw_compat_rhel_9_4_extra[] = {
|
||||
+ /* hw_compat_rhel_9_4_extra from hw_compat_8_2 */
|
||||
+ { "virtio-gpu-device", "x-scanout-vmstate-version", "1" },
|
||||
+};
|
||||
+const size_t hw_compat_rhel_9_4_extra_len = G_N_ELEMENTS(hw_compat_rhel_9_4_extra);
|
||||
+
|
||||
GlobalProperty hw_compat_rhel_9_4[] = {
|
||||
/* hw_compat_rhel_9_4 from hw_compat_8_0 */
|
||||
{ TYPE_VIRTIO_NET, "host_uso", "off"},
|
||||
@@ -81,8 +92,6 @@ GlobalProperty hw_compat_rhel_9_4[] = {
|
||||
{ "igb", "x-pcie-flr-init", "off" },
|
||||
/* hw_compat_rhel_9_4 jira RHEL-24045 */
|
||||
{ "virtio-mem", "dynamic-memslots", "off" },
|
||||
- /* hw_compat_rhel_9_4 from hw_compat_8_1 */
|
||||
- { "virtio-gpu-device", "x-scanout-vmstate-version", "1" },
|
||||
};
|
||||
const size_t hw_compat_rhel_9_4_len = G_N_ELEMENTS(hw_compat_rhel_9_4);
|
||||
|
||||
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
|
||||
index 54d1c58bce..c846673d87 100644
|
||||
--- a/hw/i386/pc_piix.c
|
||||
+++ b/hw/i386/pc_piix.c
|
||||
@@ -1031,6 +1031,8 @@ static void pc_machine_rhel760_options(MachineClass *m)
|
||||
"Use a different south bridge than PIIX3");
|
||||
|
||||
|
||||
+ compat_props_add(m->compat_props, hw_compat_rhel_9_4_extra,
|
||||
+ hw_compat_rhel_9_4_extra_len);
|
||||
compat_props_add(m->compat_props, hw_compat_rhel_9_4,
|
||||
hw_compat_rhel_9_4_len);
|
||||
compat_props_add(m->compat_props, hw_compat_rhel_9_3,
|
||||
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
|
||||
index cd5fb7380e..02bc3d515f 100644
|
||||
--- a/hw/i386/pc_q35.c
|
||||
+++ b/hw/i386/pc_q35.c
|
||||
@@ -731,6 +731,9 @@ static void pc_q35_machine_rhel940_options(MachineClass *m)
|
||||
m->desc = "RHEL-9.4.0 PC (Q35 + ICH9, 2009)";
|
||||
pcmc->smbios_stream_product = "RHEL";
|
||||
pcmc->smbios_stream_version = "9.4.0";
|
||||
+
|
||||
+ compat_props_add(m->compat_props, hw_compat_rhel_9_4_extra,
|
||||
+ hw_compat_rhel_9_4_extra_len);
|
||||
}
|
||||
|
||||
DEFINE_PC_MACHINE(q35_rhel940, "pc-q35-rhel9.4.0", pc_q35_init_rhel940,
|
||||
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
|
||||
index 24f4773179..cc6087c37a 100644
|
||||
--- a/hw/s390x/s390-virtio-ccw.c
|
||||
+++ b/hw/s390x/s390-virtio-ccw.c
|
||||
@@ -1277,6 +1277,7 @@ static void ccw_machine_rhel940_instance_options(MachineState *machine)
|
||||
|
||||
static void ccw_machine_rhel940_class_options(MachineClass *mc)
|
||||
{
|
||||
+ compat_props_add(mc->compat_props, hw_compat_rhel_9_4_extra, hw_compat_rhel_9_4_extra_len);
|
||||
}
|
||||
DEFINE_CCW_MACHINE(rhel940, "rhel9.4.0", true);
|
||||
|
||||
diff --git a/include/hw/boards.h b/include/hw/boards.h
|
||||
index 4edfdb0ddb..e6ae0e61cf 100644
|
||||
--- a/include/hw/boards.h
|
||||
+++ b/include/hw/boards.h
|
||||
@@ -505,6 +505,9 @@ extern const size_t hw_compat_2_2_len;
|
||||
extern GlobalProperty hw_compat_2_1[];
|
||||
extern const size_t hw_compat_2_1_len;
|
||||
|
||||
+extern GlobalProperty hw_compat_rhel_9_4_extra[];
|
||||
+extern const size_t hw_compat_rhel_9_4_extra_len;
|
||||
+
|
||||
extern GlobalProperty hw_compat_rhel_9_4[];
|
||||
extern const size_t hw_compat_rhel_9_4_len;
|
||||
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,155 +0,0 @@
|
||||
From 5c639f8ce65183ce8e44ee8e0230e9d627a440d7 Mon Sep 17 00:00:00 2001
|
||||
From: Igor Mammedov <imammedo@redhat.com>
|
||||
Date: Wed, 21 Feb 2024 17:00:27 +0000
|
||||
Subject: [PATCH 05/20] Implement SMBIOS type 9 v2.6
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 230: Workaround Windows failing to find 64bit SMBIOS entry point with SeaBIOS
|
||||
RH-Jira: RHEL-21705
|
||||
RH-Acked-by: MST <mst@redhat.com>
|
||||
RH-Acked-by: Ani Sinha <None>
|
||||
RH-Commit: [3/18] ead230527d93938907a561cf5b985ee4f54d82b1
|
||||
|
||||
JIRA: https://issues.redhat.com/browse/RHEL-21705
|
||||
Author: Felix Wu <flwu@google.com>
|
||||
|
||||
Signed-off-by: Felix Wu <flwu@google.com>
|
||||
Signed-off-by: Nabih Estefan <nabihestefan@google.com>
|
||||
Message-Id: <20240221170027.1027325-3-nabihestefan@google.com>
|
||||
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
|
||||
(cherry picked from commit 04f143d828845d0fd52dd4a52664d81a4f5431f7)
|
||||
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
|
||||
---
|
||||
hw/smbios/smbios.c | 49 +++++++++++++++++++++++++++++++++---
|
||||
include/hw/firmware/smbios.h | 4 +++
|
||||
qemu-options.hx | 2 +-
|
||||
3 files changed, 51 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c
|
||||
index 4f5637d445..074705fa4c 100644
|
||||
--- a/hw/smbios/smbios.c
|
||||
+++ b/hw/smbios/smbios.c
|
||||
@@ -124,7 +124,7 @@ static QTAILQ_HEAD(, type8_instance) type8 = QTAILQ_HEAD_INITIALIZER(type8);
|
||||
|
||||
/* type 9 instance for parsing */
|
||||
struct type9_instance {
|
||||
- const char *slot_designation;
|
||||
+ const char *slot_designation, *pcidev;
|
||||
uint8_t slot_type, slot_data_bus_width, current_usage, slot_length,
|
||||
slot_characteristics1, slot_characteristics2;
|
||||
uint16_t slot_id;
|
||||
@@ -427,6 +427,11 @@ static const QemuOptDesc qemu_smbios_type9_opts[] = {
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
.help = "slot characteristics2, see the spec",
|
||||
},
|
||||
+ {
|
||||
+ .name = "pci_device",
|
||||
+ .type = QEMU_OPT_STRING,
|
||||
+ .help = "PCI device, if provided."
|
||||
+ }
|
||||
};
|
||||
|
||||
static const QemuOptDesc qemu_smbios_type11_opts[] = {
|
||||
@@ -851,7 +856,7 @@ static void smbios_build_type_8_table(void)
|
||||
}
|
||||
}
|
||||
|
||||
-static void smbios_build_type_9_table(void)
|
||||
+static void smbios_build_type_9_table(Error **errp)
|
||||
{
|
||||
unsigned instance = 0;
|
||||
struct type9_instance *t9;
|
||||
@@ -868,6 +873,43 @@ static void smbios_build_type_9_table(void)
|
||||
t->slot_characteristics1 = t9->slot_characteristics1;
|
||||
t->slot_characteristics2 = t9->slot_characteristics2;
|
||||
|
||||
+ if (t9->pcidev) {
|
||||
+ PCIDevice *pdev = NULL;
|
||||
+ int rc = pci_qdev_find_device(t9->pcidev, &pdev);
|
||||
+ if (rc != 0) {
|
||||
+ error_setg(errp,
|
||||
+ "No PCI device %s for SMBIOS type 9 entry %s",
|
||||
+ t9->pcidev, t9->slot_designation);
|
||||
+ return;
|
||||
+ }
|
||||
+ /*
|
||||
+ * We only handle the case were the device is attached to
|
||||
+ * the PCI root bus. The general case is more complex as
|
||||
+ * bridges are enumerated later and the table would need
|
||||
+ * to be updated at this moment.
|
||||
+ */
|
||||
+ if (!pci_bus_is_root(pci_get_bus(pdev))) {
|
||||
+ error_setg(errp,
|
||||
+ "Cannot create type 9 entry for PCI device %s: "
|
||||
+ "not attached to the root bus",
|
||||
+ t9->pcidev);
|
||||
+ return;
|
||||
+ }
|
||||
+ t->segment_group_number = cpu_to_le16(0);
|
||||
+ t->bus_number = pci_dev_bus_num(pdev);
|
||||
+ t->device_number = pdev->devfn;
|
||||
+ } else {
|
||||
+ /*
|
||||
+ * Per SMBIOS spec, For slots that are not of the PCI, AGP, PCI-X,
|
||||
+ * or PCI-Express type that do not have bus/device/function
|
||||
+ * information, 0FFh should be populated in the fields of Segment
|
||||
+ * Group Number, Bus Number, Device/Function Number.
|
||||
+ */
|
||||
+ t->segment_group_number = 0xff;
|
||||
+ t->bus_number = 0xff;
|
||||
+ t->device_number = 0xff;
|
||||
+ }
|
||||
+
|
||||
SMBIOS_BUILD_TABLE_POST;
|
||||
instance++;
|
||||
}
|
||||
@@ -1222,7 +1264,7 @@ void smbios_get_tables(MachineState *ms,
|
||||
}
|
||||
|
||||
smbios_build_type_8_table();
|
||||
- smbios_build_type_9_table();
|
||||
+ smbios_build_type_9_table(errp);
|
||||
smbios_build_type_11_table();
|
||||
|
||||
#define MAX_DIMM_SZ (16 * GiB)
|
||||
@@ -1568,6 +1610,7 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
|
||||
t->slot_id = qemu_opt_get_number(opts, "slot_id", 0);
|
||||
t->slot_characteristics1 = qemu_opt_get_number(opts, "slot_characteristics1", 0);
|
||||
t->slot_characteristics2 = qemu_opt_get_number(opts, "slot_characteristics2", 0);
|
||||
+ save_opt(&t->pcidev, opts, "pcidev");
|
||||
QTAILQ_INSERT_TAIL(&type9, t, next);
|
||||
return;
|
||||
}
|
||||
diff --git a/include/hw/firmware/smbios.h b/include/hw/firmware/smbios.h
|
||||
index 6bbd5a4c20..f8dd07fe4c 100644
|
||||
--- a/include/hw/firmware/smbios.h
|
||||
+++ b/include/hw/firmware/smbios.h
|
||||
@@ -222,6 +222,10 @@ struct smbios_type_9 {
|
||||
uint16_t slot_id;
|
||||
uint8_t slot_characteristics1;
|
||||
uint8_t slot_characteristics2;
|
||||
+ /* SMBIOS spec v2.6+ */
|
||||
+ uint16_t segment_group_number;
|
||||
+ uint8_t bus_number;
|
||||
+ uint8_t device_number;
|
||||
} QEMU_PACKED;
|
||||
|
||||
/* SMBIOS type 11 - OEM strings */
|
||||
diff --git a/qemu-options.hx b/qemu-options.hx
|
||||
index 94cacc2c63..93364e1765 100644
|
||||
--- a/qemu-options.hx
|
||||
+++ b/qemu-options.hx
|
||||
@@ -2710,7 +2710,7 @@ SRST
|
||||
``-smbios type=4[,sock_pfx=str][,manufacturer=str][,version=str][,serial=str][,asset=str][,part=str][,processor-id=%d]``
|
||||
Specify SMBIOS type 4 fields
|
||||
|
||||
-``-smbios type=9[,slot_designation=str][,slot_type=%d][,slot_data_bus_width=%d][,current_usage=%d][,slot_length=%d][,slot_id=%d][,slot_characteristics1=%d][,slot_characteristics12=%d]``
|
||||
+``-smbios type=9[,slot_designation=str][,slot_type=%d][,slot_data_bus_width=%d][,current_usage=%d][,slot_length=%d][,slot_id=%d][,slot_characteristics1=%d][,slot_characteristics12=%d][,pci_device=str]``
|
||||
Specify SMBIOS type 9 fields
|
||||
|
||||
``-smbios type=11[,value=str][,path=filename]``
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,218 +0,0 @@
|
||||
From 84fc607d678bd72397a41d706e91fa241fd97266 Mon Sep 17 00:00:00 2001
|
||||
From: Igor Mammedov <imammedo@redhat.com>
|
||||
Date: Wed, 21 Feb 2024 17:00:26 +0000
|
||||
Subject: [PATCH 04/20] Implement base of SMBIOS type 9 descriptor.
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 230: Workaround Windows failing to find 64bit SMBIOS entry point with SeaBIOS
|
||||
RH-Jira: RHEL-21705
|
||||
RH-Acked-by: MST <mst@redhat.com>
|
||||
RH-Acked-by: Ani Sinha <None>
|
||||
RH-Commit: [2/18] 2678cc080bfbf3357fa2f94ceaf42fc61b690d32
|
||||
|
||||
JIRA: https://issues.redhat.com/browse/RHEL-21705
|
||||
|
||||
commit: 735eee07d1f963635d3c3bf9f5e4bf1bc000870e
|
||||
Author: Felix Wu <flwu@google.com>
|
||||
|
||||
Version 2.1+.
|
||||
|
||||
Signed-off-by: Felix Wu <flwu@google.com>
|
||||
Signed-off-by: Nabih Estefan <nabihestefan@google.com>
|
||||
Message-Id: <20240221170027.1027325-2-nabihestefan@google.com>
|
||||
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
|
||||
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
|
||||
---
|
||||
hw/smbios/smbios.c | 99 ++++++++++++++++++++++++++++++++++++
|
||||
include/hw/firmware/smbios.h | 13 +++++
|
||||
qemu-options.hx | 3 ++
|
||||
3 files changed, 115 insertions(+)
|
||||
|
||||
diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c
|
||||
index 7bde23e59d..4f5637d445 100644
|
||||
--- a/hw/smbios/smbios.c
|
||||
+++ b/hw/smbios/smbios.c
|
||||
@@ -122,6 +122,16 @@ struct type8_instance {
|
||||
};
|
||||
static QTAILQ_HEAD(, type8_instance) type8 = QTAILQ_HEAD_INITIALIZER(type8);
|
||||
|
||||
+/* type 9 instance for parsing */
|
||||
+struct type9_instance {
|
||||
+ const char *slot_designation;
|
||||
+ uint8_t slot_type, slot_data_bus_width, current_usage, slot_length,
|
||||
+ slot_characteristics1, slot_characteristics2;
|
||||
+ uint16_t slot_id;
|
||||
+ QTAILQ_ENTRY(type9_instance) next;
|
||||
+};
|
||||
+static QTAILQ_HEAD(, type9_instance) type9 = QTAILQ_HEAD_INITIALIZER(type9);
|
||||
+
|
||||
static struct {
|
||||
size_t nvalues;
|
||||
char **values;
|
||||
@@ -371,6 +381,54 @@ static const QemuOptDesc qemu_smbios_type8_opts[] = {
|
||||
},
|
||||
};
|
||||
|
||||
+static const QemuOptDesc qemu_smbios_type9_opts[] = {
|
||||
+ {
|
||||
+ .name = "type",
|
||||
+ .type = QEMU_OPT_NUMBER,
|
||||
+ .help = "SMBIOS element type",
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "slot_designation",
|
||||
+ .type = QEMU_OPT_STRING,
|
||||
+ .help = "string number for reference designation",
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "slot_type",
|
||||
+ .type = QEMU_OPT_NUMBER,
|
||||
+ .help = "connector type",
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "slot_data_bus_width",
|
||||
+ .type = QEMU_OPT_NUMBER,
|
||||
+ .help = "port type",
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "current_usage",
|
||||
+ .type = QEMU_OPT_NUMBER,
|
||||
+ .help = "current usage",
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "slot_length",
|
||||
+ .type = QEMU_OPT_NUMBER,
|
||||
+ .help = "system slot length",
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "slot_id",
|
||||
+ .type = QEMU_OPT_NUMBER,
|
||||
+ .help = "system slot id",
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "slot_characteristics1",
|
||||
+ .type = QEMU_OPT_NUMBER,
|
||||
+ .help = "slot characteristics1, see the spec",
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "slot_characteristics2",
|
||||
+ .type = QEMU_OPT_NUMBER,
|
||||
+ .help = "slot characteristics2, see the spec",
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
static const QemuOptDesc qemu_smbios_type11_opts[] = {
|
||||
{
|
||||
.name = "value",
|
||||
@@ -594,6 +652,7 @@ bool smbios_skip_table(uint8_t type, bool required_table)
|
||||
#define T2_BASE 0x200
|
||||
#define T3_BASE 0x300
|
||||
#define T4_BASE 0x400
|
||||
+#define T9_BASE 0x900
|
||||
#define T11_BASE 0xe00
|
||||
|
||||
#define T16_BASE 0x1000
|
||||
@@ -792,6 +851,28 @@ static void smbios_build_type_8_table(void)
|
||||
}
|
||||
}
|
||||
|
||||
+static void smbios_build_type_9_table(void)
|
||||
+{
|
||||
+ unsigned instance = 0;
|
||||
+ struct type9_instance *t9;
|
||||
+
|
||||
+ QTAILQ_FOREACH(t9, &type9, next) {
|
||||
+ SMBIOS_BUILD_TABLE_PRE(9, T9_BASE + instance, true);
|
||||
+
|
||||
+ SMBIOS_TABLE_SET_STR(9, slot_designation, t9->slot_designation);
|
||||
+ t->slot_type = t9->slot_type;
|
||||
+ t->slot_data_bus_width = t9->slot_data_bus_width;
|
||||
+ t->current_usage = t9->current_usage;
|
||||
+ t->slot_length = t9->slot_length;
|
||||
+ t->slot_id = t9->slot_id;
|
||||
+ t->slot_characteristics1 = t9->slot_characteristics1;
|
||||
+ t->slot_characteristics2 = t9->slot_characteristics2;
|
||||
+
|
||||
+ SMBIOS_BUILD_TABLE_POST;
|
||||
+ instance++;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static void smbios_build_type_11_table(void)
|
||||
{
|
||||
char count_str[128];
|
||||
@@ -1141,6 +1222,7 @@ void smbios_get_tables(MachineState *ms,
|
||||
}
|
||||
|
||||
smbios_build_type_8_table();
|
||||
+ smbios_build_type_9_table();
|
||||
smbios_build_type_11_table();
|
||||
|
||||
#define MAX_DIMM_SZ (16 * GiB)
|
||||
@@ -1472,6 +1554,23 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
|
||||
t8_i->port_type = qemu_opt_get_number(opts, "port_type", 0);
|
||||
QTAILQ_INSERT_TAIL(&type8, t8_i, next);
|
||||
return;
|
||||
+ case 9: {
|
||||
+ if (!qemu_opts_validate(opts, qemu_smbios_type9_opts, errp)) {
|
||||
+ return;
|
||||
+ }
|
||||
+ struct type9_instance *t;
|
||||
+ t = g_new0(struct type9_instance, 1);
|
||||
+ save_opt(&t->slot_designation, opts, "slot_designation");
|
||||
+ t->slot_type = qemu_opt_get_number(opts, "slot_type", 0);
|
||||
+ t->slot_data_bus_width = qemu_opt_get_number(opts, "slot_data_bus_width", 0);
|
||||
+ t->current_usage = qemu_opt_get_number(opts, "current_usage", 0);
|
||||
+ t->slot_length = qemu_opt_get_number(opts, "slot_length", 0);
|
||||
+ t->slot_id = qemu_opt_get_number(opts, "slot_id", 0);
|
||||
+ t->slot_characteristics1 = qemu_opt_get_number(opts, "slot_characteristics1", 0);
|
||||
+ t->slot_characteristics2 = qemu_opt_get_number(opts, "slot_characteristics2", 0);
|
||||
+ QTAILQ_INSERT_TAIL(&type9, t, next);
|
||||
+ return;
|
||||
+ }
|
||||
case 11:
|
||||
if (!qemu_opts_validate(opts, qemu_smbios_type11_opts, errp)) {
|
||||
return;
|
||||
diff --git a/include/hw/firmware/smbios.h b/include/hw/firmware/smbios.h
|
||||
index d24b3ccd32..6bbd5a4c20 100644
|
||||
--- a/include/hw/firmware/smbios.h
|
||||
+++ b/include/hw/firmware/smbios.h
|
||||
@@ -211,6 +211,19 @@ struct smbios_type_8 {
|
||||
uint8_t port_type;
|
||||
} QEMU_PACKED;
|
||||
|
||||
+/* SMBIOS type 9 - System Slots (v2.1+) */
|
||||
+struct smbios_type_9 {
|
||||
+ struct smbios_structure_header header;
|
||||
+ uint8_t slot_designation;
|
||||
+ uint8_t slot_type;
|
||||
+ uint8_t slot_data_bus_width;
|
||||
+ uint8_t current_usage;
|
||||
+ uint8_t slot_length;
|
||||
+ uint16_t slot_id;
|
||||
+ uint8_t slot_characteristics1;
|
||||
+ uint8_t slot_characteristics2;
|
||||
+} QEMU_PACKED;
|
||||
+
|
||||
/* SMBIOS type 11 - OEM strings */
|
||||
struct smbios_type_11 {
|
||||
struct smbios_structure_header header;
|
||||
diff --git a/qemu-options.hx b/qemu-options.hx
|
||||
index 0814f43066..94cacc2c63 100644
|
||||
--- a/qemu-options.hx
|
||||
+++ b/qemu-options.hx
|
||||
@@ -2710,6 +2710,9 @@ SRST
|
||||
``-smbios type=4[,sock_pfx=str][,manufacturer=str][,version=str][,serial=str][,asset=str][,part=str][,processor-id=%d]``
|
||||
Specify SMBIOS type 4 fields
|
||||
|
||||
+``-smbios type=9[,slot_designation=str][,slot_type=%d][,slot_data_bus_width=%d][,current_usage=%d][,slot_length=%d][,slot_id=%d][,slot_characteristics1=%d][,slot_characteristics12=%d]``
|
||||
+ Specify SMBIOS type 9 fields
|
||||
+
|
||||
``-smbios type=11[,value=str][,path=filename]``
|
||||
Specify SMBIOS type 11 fields
|
||||
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,60 +0,0 @@
|
||||
From 2e0e4355b2d4edb66b7d8c198339e17940abd682 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
|
||||
Date: Mon, 18 Mar 2024 13:03:19 +0000
|
||||
Subject: [PATCH 2/3] Revert "chardev/char-socket: Fix TLS io channels sending
|
||||
too much data to the backend"
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
RH-Author: Daniel P. Berrangé <berrange@redhat.com>
|
||||
RH-MergeRequest: 233: Fix handling of TLS sessions in chardevs
|
||||
RH-Jira: RHEL-24614
|
||||
RH-Acked-by: Thomas Huth <thuth@redhat.com>
|
||||
RH-Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com>
|
||||
RH-Commit: [2/3] 1cb3d72b86ced0f70a09dfa0d325ae8a85db1b2b (berrange/centos-src-qemu)
|
||||
|
||||
This commit results in unexpected termination of the TLS connection.
|
||||
When 'fd_can_read' returns 0, the code goes on to pass a zero length
|
||||
buffer to qio_channel_read. The TLS impl calls into gnutls_recv()
|
||||
with this zero length buffer, at which point GNUTLS returns an error
|
||||
GNUTLS_E_INVALID_REQUEST. This is treated as fatal by QEMU's TLS code
|
||||
resulting in the connection being torn down by the chardev.
|
||||
|
||||
Simply skipping the qio_channel_read when the buffer length is zero
|
||||
is also not satisfactory, as it results in a high CPU burn busy loop
|
||||
massively slowing QEMU's functionality.
|
||||
|
||||
The proper solution is to avoid tcp_chr_read being called at all
|
||||
unless the frontend is able to accept more data. This will be done
|
||||
in a followup commit.
|
||||
|
||||
This reverts commit 462945cd22d2bcd233401ed3aa167d83a8e35b05
|
||||
|
||||
Reviewed-by: Thomas Huth <thuth@redhat.com>
|
||||
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
(cherry picked from commit e8ee827ffdb86ebbd5f5213a1f78123c25a90864)
|
||||
---
|
||||
chardev/char-socket.c | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/chardev/char-socket.c b/chardev/char-socket.c
|
||||
index f48d341ebc..51d0943fce 100644
|
||||
--- a/chardev/char-socket.c
|
||||
+++ b/chardev/char-socket.c
|
||||
@@ -492,9 +492,9 @@ static gboolean tcp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
|
||||
s->max_size <= 0) {
|
||||
return TRUE;
|
||||
}
|
||||
- len = tcp_chr_read_poll(opaque);
|
||||
- if (len > sizeof(buf)) {
|
||||
- len = sizeof(buf);
|
||||
+ len = sizeof(buf);
|
||||
+ if (len > s->max_size) {
|
||||
+ len = s->max_size;
|
||||
}
|
||||
size = tcp_chr_recv(chr, (void *)buf, len);
|
||||
if (size == 0 || (size == -1 && errno != EAGAIN)) {
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,216 +0,0 @@
|
||||
From ab5a33d57b48e35388928e388bb6e6479bc77651 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
|
||||
Date: Mon, 18 Mar 2024 17:08:30 +0000
|
||||
Subject: [PATCH 3/3] Revert "chardev: use a child source for qio input source"
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
RH-Author: Daniel P. Berrangé <berrange@redhat.com>
|
||||
RH-MergeRequest: 233: Fix handling of TLS sessions in chardevs
|
||||
RH-Jira: RHEL-24614
|
||||
RH-Acked-by: Thomas Huth <thuth@redhat.com>
|
||||
RH-Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com>
|
||||
RH-Commit: [3/3] b58e6c19c2b11d5d28db31cf1386226fb01d195e (berrange/centos-src-qemu)
|
||||
|
||||
This reverts commit a7077b8e354d90fec26c2921aa2dea85b90dff90,
|
||||
and add comments to explain why child sources cannot be used.
|
||||
|
||||
When a GSource is added as a child of another GSource, if its
|
||||
'prepare' function indicates readiness, then the parent's
|
||||
'prepare' function will never be run. The io_watch_poll_prepare
|
||||
absolutely *must* be run on every iteration of the main loop,
|
||||
to ensure that the chardev backend doesn't feed data to the
|
||||
frontend that it is unable to consume.
|
||||
|
||||
At the time a7077b8e354d90fec26c2921aa2dea85b90dff90 was made,
|
||||
all the child GSource impls were relying on poll'ing an FD,
|
||||
so their 'prepare' functions would never indicate readiness
|
||||
ahead of poll() being invoked. So the buggy behaviour was
|
||||
not noticed and lay dormant.
|
||||
|
||||
Relatively recently the QIOChannelTLS impl introduced a
|
||||
level 2 child GSource, which checks with GNUTLS whether it
|
||||
has cached any data that was decoded but not yet consumed:
|
||||
|
||||
commit ffda5db65aef42266a5053a4be34515106c4c7ee
|
||||
Author: Antoine Damhet <antoine.damhet@shadow.tech>
|
||||
Date: Tue Nov 15 15:23:29 2022 +0100
|
||||
|
||||
io/channel-tls: fix handling of bigger read buffers
|
||||
|
||||
Since the TLS backend can read more data from the underlying QIOChannel
|
||||
we introduce a minimal child GSource to notify if we still have more
|
||||
data available to be read.
|
||||
|
||||
Signed-off-by: Antoine Damhet <antoine.damhet@shadow.tech>
|
||||
Signed-off-by: Charles Frey <charles.frey@shadow.tech>
|
||||
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
|
||||
With this, it is now quite common for the 'prepare' function
|
||||
on a QIOChannelTLS GSource to indicate immediate readiness,
|
||||
bypassing the parent GSource 'prepare' function. IOW, the
|
||||
critical 'io_watch_poll_prepare' is being skipped on some
|
||||
iterations of the main loop. As a result chardev frontend
|
||||
asserts are now being triggered as they are fed data they
|
||||
are not ready to consume.
|
||||
|
||||
A reproducer is as follows:
|
||||
|
||||
* In terminal 1 run a GNUTLS *echo* server
|
||||
|
||||
$ gnutls-serv --echo \
|
||||
--x509cafile ca-cert.pem \
|
||||
--x509keyfile server-key.pem \
|
||||
--x509certfile server-cert.pem \
|
||||
-p 9000
|
||||
|
||||
* In terminal 2 run a QEMU guest
|
||||
|
||||
$ qemu-system-s390x \
|
||||
-nodefaults \
|
||||
-display none \
|
||||
-object tls-creds-x509,id=tls0,dir=$PWD,endpoint=client \
|
||||
-chardev socket,id=con0,host=localhost,port=9000,tls-creds=tls0 \
|
||||
-device sclpconsole,chardev=con0 \
|
||||
-hda Fedora-Cloud-Base-39-1.5.s390x.qcow2
|
||||
|
||||
After the previous patch revert, but before this patch revert,
|
||||
this scenario will crash:
|
||||
|
||||
qemu-system-s390x: ../hw/char/sclpconsole.c:73: chr_read: Assertion
|
||||
`size <= SIZE_BUFFER_VT220 - scon->iov_data_len' failed.
|
||||
|
||||
This assert indicates that 'tcp_chr_read' was called without
|
||||
'tcp_chr_read_poll' having first been checked for ability to
|
||||
receive more data
|
||||
|
||||
QEMU's use of a 'prepare' function to create/delete another
|
||||
GSource is rather a hack and not normally the kind of thing that
|
||||
is expected to be done by a GSource. There is no mechanism to
|
||||
force GLib to always run the 'prepare' function of a parent
|
||||
GSource. The best option is to simply not use the child source
|
||||
concept, and go back to the functional approach previously
|
||||
relied on.
|
||||
|
||||
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
|
||||
Reviewed-by: Thomas Huth <thuth@redhat.com>
|
||||
Tested-by: Thomas Huth <thuth@redhat.com>
|
||||
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
(cherry picked from commit 038b4217884c6f297278bb1ec6f0463c6c8221de)
|
||||
---
|
||||
chardev/char-io.c | 56 ++++++++++++++++++++++++++++++++++++++++++-----
|
||||
1 file changed, 51 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/chardev/char-io.c b/chardev/char-io.c
|
||||
index 4451128cba..dab77b112e 100644
|
||||
--- a/chardev/char-io.c
|
||||
+++ b/chardev/char-io.c
|
||||
@@ -33,6 +33,7 @@ typedef struct IOWatchPoll {
|
||||
IOCanReadHandler *fd_can_read;
|
||||
GSourceFunc fd_read;
|
||||
void *opaque;
|
||||
+ GMainContext *context;
|
||||
} IOWatchPoll;
|
||||
|
||||
static IOWatchPoll *io_watch_poll_from_source(GSource *source)
|
||||
@@ -50,28 +51,59 @@ static gboolean io_watch_poll_prepare(GSource *source,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
+ /*
|
||||
+ * We do not register the QIOChannel watch as a child GSource.
|
||||
+ * The 'prepare' function on the parent GSource will be
|
||||
+ * skipped if a child GSource's 'prepare' function indicates
|
||||
+ * readiness. We need this prepare function be guaranteed
|
||||
+ * to run on *every* iteration of the main loop, because
|
||||
+ * it is critical to ensure we remove the QIOChannel watch
|
||||
+ * if 'fd_can_read' indicates the frontend cannot receive
|
||||
+ * more data.
|
||||
+ */
|
||||
if (now_active) {
|
||||
iwp->src = qio_channel_create_watch(
|
||||
iwp->ioc, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL);
|
||||
g_source_set_callback(iwp->src, iwp->fd_read, iwp->opaque, NULL);
|
||||
- g_source_add_child_source(source, iwp->src);
|
||||
- g_source_unref(iwp->src);
|
||||
+ g_source_attach(iwp->src, iwp->context);
|
||||
} else {
|
||||
- g_source_remove_child_source(source, iwp->src);
|
||||
+ g_source_destroy(iwp->src);
|
||||
+ g_source_unref(iwp->src);
|
||||
iwp->src = NULL;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
+static gboolean io_watch_poll_check(GSource *source)
|
||||
+{
|
||||
+ return FALSE;
|
||||
+}
|
||||
+
|
||||
static gboolean io_watch_poll_dispatch(GSource *source, GSourceFunc callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
- return G_SOURCE_CONTINUE;
|
||||
+ abort();
|
||||
+}
|
||||
+
|
||||
+static void io_watch_poll_finalize(GSource *source)
|
||||
+{
|
||||
+ /*
|
||||
+ * Due to a glib bug, removing the last reference to a source
|
||||
+ * inside a finalize callback causes recursive locking (and a
|
||||
+ * deadlock). This is not a problem inside other callbacks,
|
||||
+ * including dispatch callbacks, so we call io_remove_watch_poll
|
||||
+ * to remove this source. At this point, iwp->src must
|
||||
+ * be NULL, or we would leak it.
|
||||
+ */
|
||||
+ IOWatchPoll *iwp = io_watch_poll_from_source(source);
|
||||
+ assert(iwp->src == NULL);
|
||||
}
|
||||
|
||||
static GSourceFuncs io_watch_poll_funcs = {
|
||||
.prepare = io_watch_poll_prepare,
|
||||
+ .check = io_watch_poll_check,
|
||||
.dispatch = io_watch_poll_dispatch,
|
||||
+ .finalize = io_watch_poll_finalize,
|
||||
};
|
||||
|
||||
GSource *io_add_watch_poll(Chardev *chr,
|
||||
@@ -91,6 +123,7 @@ GSource *io_add_watch_poll(Chardev *chr,
|
||||
iwp->ioc = ioc;
|
||||
iwp->fd_read = (GSourceFunc) fd_read;
|
||||
iwp->src = NULL;
|
||||
+ iwp->context = context;
|
||||
|
||||
name = g_strdup_printf("chardev-iowatch-%s", chr->label);
|
||||
g_source_set_name((GSource *)iwp, name);
|
||||
@@ -101,10 +134,23 @@ GSource *io_add_watch_poll(Chardev *chr,
|
||||
return (GSource *)iwp;
|
||||
}
|
||||
|
||||
+static void io_remove_watch_poll(GSource *source)
|
||||
+{
|
||||
+ IOWatchPoll *iwp;
|
||||
+
|
||||
+ iwp = io_watch_poll_from_source(source);
|
||||
+ if (iwp->src) {
|
||||
+ g_source_destroy(iwp->src);
|
||||
+ g_source_unref(iwp->src);
|
||||
+ iwp->src = NULL;
|
||||
+ }
|
||||
+ g_source_destroy(&iwp->parent);
|
||||
+}
|
||||
+
|
||||
void remove_fd_in_watch(Chardev *chr)
|
||||
{
|
||||
if (chr->gsource) {
|
||||
- g_source_destroy(chr->gsource);
|
||||
+ io_remove_watch_poll(chr->gsource);
|
||||
chr->gsource = NULL;
|
||||
}
|
||||
}
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,260 +0,0 @@
|
||||
From 5c35b7d631e9cdf75512b9e1a0b5d48e8fd768d9 Mon Sep 17 00:00:00 2001
|
||||
From: Jon Maloy <jmaloy@redhat.com>
|
||||
Date: Wed, 5 Jun 2024 19:56:51 -0400
|
||||
Subject: [PATCH 4/4] block: Parse filenames only when explicitly requested
|
||||
|
||||
RH-Author: Jon Maloy <jmaloy@redhat.com>
|
||||
RH-MergeRequest: 2: EMBARGOED CVE-2024-4467 for rhel-9.4.z (PRDSC)
|
||||
RH-Jira: https://issues.redhat.com/browse/RHEL-35610
|
||||
RH-CVE: CVE-2024-4467
|
||||
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
|
||||
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
RH-Acked-by: Hanna Czenczek <hczenczek@redhat.com>
|
||||
RH-Commit: [4/4] 6f71e6a07bd5a9f8352db920f498f5fa5a2cdbfb
|
||||
|
||||
commit f44c2941d4419e60f16dea3e9adca164e75aa78d (origin/cve-2024-4467-hreitz-rhel-9.5.0)
|
||||
Author: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Thu Apr 25 14:56:02 2024 +0200
|
||||
|
||||
block: Parse filenames only when explicitly requested
|
||||
|
||||
When handling image filenames from legacy options such as -drive or from
|
||||
tools, these filenames are parsed for protocol prefixes, including for
|
||||
the json:{} pseudo-protocol.
|
||||
|
||||
This behaviour is intended for filenames that come directly from the
|
||||
command line and for backing files, which may come from the image file
|
||||
itself. Higher level management tools generally take care to verify that
|
||||
untrusted images don't contain a bad (or any) backing file reference;
|
||||
'qemu-img info' is a suitable tool for this.
|
||||
|
||||
However, for other files that can be referenced in images, such as
|
||||
qcow2 data files or VMDK extents, the string from the image file is
|
||||
usually not verified by management tools - and 'qemu-img info' wouldn't
|
||||
be suitable because in contrast to backing files, it already opens these
|
||||
other referenced files. So here the string should be interpreted as a
|
||||
literal local filename. More complex configurations need to be specified
|
||||
explicitly on the command line or in QMP.
|
||||
|
||||
This patch changes bdrv_open_inherit() so that it only parses filenames
|
||||
if a new parameter parse_filename is true. It is set for the top level
|
||||
in bdrv_open(), for the file child and for the backing file child. All
|
||||
other callers pass false and disable filename parsing this way.
|
||||
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Eric Blake <eblake@redhat.com>
|
||||
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
|
||||
Upstream: N/A, embargoed
|
||||
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
|
||||
|
||||
Signed-off-by: Jon Maloy <jmaloy@redhat.com>
|
||||
---
|
||||
block.c | 90 ++++++++++++++++++++++++++++++++++++---------------------
|
||||
1 file changed, 57 insertions(+), 33 deletions(-)
|
||||
|
||||
diff --git a/block.c b/block.c
|
||||
index a097772238..8b6aa4a65c 100644
|
||||
--- a/block.c
|
||||
+++ b/block.c
|
||||
@@ -86,6 +86,7 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
|
||||
BlockDriverState *parent,
|
||||
const BdrvChildClass *child_class,
|
||||
BdrvChildRole child_role,
|
||||
+ bool parse_filename,
|
||||
Error **errp);
|
||||
|
||||
static bool bdrv_recurse_has_child(BlockDriverState *bs,
|
||||
@@ -2035,7 +2036,8 @@ static void parse_json_protocol(QDict *options, const char **pfilename,
|
||||
* block driver has been specified explicitly.
|
||||
*/
|
||||
static int bdrv_fill_options(QDict **options, const char *filename,
|
||||
- int *flags, Error **errp)
|
||||
+ int *flags, bool allow_parse_filename,
|
||||
+ Error **errp)
|
||||
{
|
||||
const char *drvname;
|
||||
bool protocol = *flags & BDRV_O_PROTOCOL;
|
||||
@@ -2077,7 +2079,7 @@ static int bdrv_fill_options(QDict **options, const char *filename,
|
||||
if (protocol && filename) {
|
||||
if (!qdict_haskey(*options, "filename")) {
|
||||
qdict_put_str(*options, "filename", filename);
|
||||
- parse_filename = true;
|
||||
+ parse_filename = allow_parse_filename;
|
||||
} else {
|
||||
error_setg(errp, "Can't specify 'file' and 'filename' options at "
|
||||
"the same time");
|
||||
@@ -3639,7 +3641,8 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
|
||||
}
|
||||
|
||||
backing_hd = bdrv_open_inherit(backing_filename, reference, options, 0, bs,
|
||||
- &child_of_bds, bdrv_backing_role(bs), errp);
|
||||
+ &child_of_bds, bdrv_backing_role(bs), true,
|
||||
+ errp);
|
||||
if (!backing_hd) {
|
||||
bs->open_flags |= BDRV_O_NO_BACKING;
|
||||
error_prepend(errp, "Could not open backing file: ");
|
||||
@@ -3673,7 +3676,8 @@ free_exit:
|
||||
static BlockDriverState *
|
||||
bdrv_open_child_bs(const char *filename, QDict *options, const char *bdref_key,
|
||||
BlockDriverState *parent, const BdrvChildClass *child_class,
|
||||
- BdrvChildRole child_role, bool allow_none, Error **errp)
|
||||
+ BdrvChildRole child_role, bool allow_none,
|
||||
+ bool parse_filename, Error **errp)
|
||||
{
|
||||
BlockDriverState *bs = NULL;
|
||||
QDict *image_options;
|
||||
@@ -3704,7 +3708,8 @@ bdrv_open_child_bs(const char *filename, QDict *options, const char *bdref_key,
|
||||
}
|
||||
|
||||
bs = bdrv_open_inherit(filename, reference, image_options, 0,
|
||||
- parent, child_class, child_role, errp);
|
||||
+ parent, child_class, child_role, parse_filename,
|
||||
+ errp);
|
||||
if (!bs) {
|
||||
goto done;
|
||||
}
|
||||
@@ -3714,6 +3719,33 @@ done:
|
||||
return bs;
|
||||
}
|
||||
|
||||
+static BdrvChild *bdrv_open_child_common(const char *filename,
|
||||
+ QDict *options, const char *bdref_key,
|
||||
+ BlockDriverState *parent,
|
||||
+ const BdrvChildClass *child_class,
|
||||
+ BdrvChildRole child_role,
|
||||
+ bool allow_none, bool parse_filename,
|
||||
+ Error **errp)
|
||||
+{
|
||||
+ BlockDriverState *bs;
|
||||
+ BdrvChild *child;
|
||||
+
|
||||
+ GLOBAL_STATE_CODE();
|
||||
+
|
||||
+ bs = bdrv_open_child_bs(filename, options, bdref_key, parent, child_class,
|
||||
+ child_role, allow_none, parse_filename, errp);
|
||||
+ if (bs == NULL) {
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ bdrv_graph_wrlock();
|
||||
+ child = bdrv_attach_child(parent, bs, bdref_key, child_class, child_role,
|
||||
+ errp);
|
||||
+ bdrv_graph_wrunlock();
|
||||
+
|
||||
+ return child;
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Opens a disk image whose options are given as BlockdevRef in another block
|
||||
* device's options.
|
||||
@@ -3737,27 +3769,15 @@ BdrvChild *bdrv_open_child(const char *filename,
|
||||
BdrvChildRole child_role,
|
||||
bool allow_none, Error **errp)
|
||||
{
|
||||
- BlockDriverState *bs;
|
||||
- BdrvChild *child;
|
||||
-
|
||||
- GLOBAL_STATE_CODE();
|
||||
-
|
||||
- bs = bdrv_open_child_bs(filename, options, bdref_key, parent, child_class,
|
||||
- child_role, allow_none, errp);
|
||||
- if (bs == NULL) {
|
||||
- return NULL;
|
||||
- }
|
||||
-
|
||||
- bdrv_graph_wrlock();
|
||||
- child = bdrv_attach_child(parent, bs, bdref_key, child_class, child_role,
|
||||
- errp);
|
||||
- bdrv_graph_wrunlock();
|
||||
-
|
||||
- return child;
|
||||
+ return bdrv_open_child_common(filename, options, bdref_key, parent,
|
||||
+ child_class, child_role, allow_none, false,
|
||||
+ errp);
|
||||
}
|
||||
|
||||
/*
|
||||
- * Wrapper on bdrv_open_child() for most popular case: open primary child of bs.
|
||||
+ * This does mostly the same as bdrv_open_child(), but for opening the primary
|
||||
+ * child of a node. A notable difference from bdrv_open_child() is that it
|
||||
+ * enables filename parsing for protocol names (including json:).
|
||||
*
|
||||
* @parent can move to a different AioContext in this function.
|
||||
*/
|
||||
@@ -3772,8 +3792,8 @@ int bdrv_open_file_child(const char *filename,
|
||||
role = parent->drv->is_filter ?
|
||||
(BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY) : BDRV_CHILD_IMAGE;
|
||||
|
||||
- if (!bdrv_open_child(filename, options, bdref_key, parent,
|
||||
- &child_of_bds, role, false, errp))
|
||||
+ if (!bdrv_open_child_common(filename, options, bdref_key, parent,
|
||||
+ &child_of_bds, role, false, true, errp))
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -3818,7 +3838,8 @@ BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp)
|
||||
|
||||
}
|
||||
|
||||
- bs = bdrv_open_inherit(NULL, reference, qdict, 0, NULL, NULL, 0, errp);
|
||||
+ bs = bdrv_open_inherit(NULL, reference, qdict, 0, NULL, NULL, 0, false,
|
||||
+ errp);
|
||||
obj = NULL;
|
||||
qobject_unref(obj);
|
||||
visit_free(v);
|
||||
@@ -3907,7 +3928,7 @@ static BlockDriverState * no_coroutine_fn
|
||||
bdrv_open_inherit(const char *filename, const char *reference, QDict *options,
|
||||
int flags, BlockDriverState *parent,
|
||||
const BdrvChildClass *child_class, BdrvChildRole child_role,
|
||||
- Error **errp)
|
||||
+ bool parse_filename, Error **errp)
|
||||
{
|
||||
int ret;
|
||||
BlockBackend *file = NULL;
|
||||
@@ -3955,9 +3976,11 @@ bdrv_open_inherit(const char *filename, const char *reference, QDict *options,
|
||||
}
|
||||
|
||||
/* json: syntax counts as explicit options, as if in the QDict */
|
||||
- parse_json_protocol(options, &filename, &local_err);
|
||||
- if (local_err) {
|
||||
- goto fail;
|
||||
+ if (parse_filename) {
|
||||
+ parse_json_protocol(options, &filename, &local_err);
|
||||
+ if (local_err) {
|
||||
+ goto fail;
|
||||
+ }
|
||||
}
|
||||
|
||||
bs->explicit_options = qdict_clone_shallow(options);
|
||||
@@ -3982,7 +4005,8 @@ bdrv_open_inherit(const char *filename, const char *reference, QDict *options,
|
||||
parent->open_flags, parent->options);
|
||||
}
|
||||
|
||||
- ret = bdrv_fill_options(&options, filename, &flags, &local_err);
|
||||
+ ret = bdrv_fill_options(&options, filename, &flags, parse_filename,
|
||||
+ &local_err);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
@@ -4051,7 +4075,7 @@ bdrv_open_inherit(const char *filename, const char *reference, QDict *options,
|
||||
|
||||
file_bs = bdrv_open_child_bs(filename, options, "file", bs,
|
||||
&child_of_bds, BDRV_CHILD_IMAGE,
|
||||
- true, &local_err);
|
||||
+ true, true, &local_err);
|
||||
if (local_err) {
|
||||
goto fail;
|
||||
}
|
||||
@@ -4200,7 +4224,7 @@ BlockDriverState *bdrv_open(const char *filename, const char *reference,
|
||||
GLOBAL_STATE_CODE();
|
||||
|
||||
return bdrv_open_inherit(filename, reference, options, flags, NULL,
|
||||
- NULL, 0, errp);
|
||||
+ NULL, 0, true, errp);
|
||||
}
|
||||
|
||||
/* Return true if the NULL-terminated @list contains @str */
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,105 +0,0 @@
|
||||
From 95b2ffc5f01dc4309c2e747ed883d22cd1d26347 Mon Sep 17 00:00:00 2001
|
||||
From: Thomas Huth <thuth@redhat.com>
|
||||
Date: Sat, 2 Mar 2024 17:00:23 +0100
|
||||
Subject: [PATCH 2/2] chardev/char-socket: Fix TLS io channels sending too much
|
||||
data to the backend
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
RH-Author: Thomas Huth <thuth@redhat.com>
|
||||
RH-MergeRequest: 227: Fix TLS io channels sending too much data to the backend
|
||||
RH-Jira: RHEL-24614
|
||||
RH-Acked-by: Cédric Le Goater <clg@redhat.com>
|
||||
RH-Acked-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
RH-Commit: [1/1] fce871914e0ce52e16a6edae0e007513f9fec1ae (thuth/qemu-kvm-cs9)
|
||||
|
||||
JIRA: https://issues.redhat.com/browse/RHEL-24614
|
||||
|
||||
commit 462945cd22d2bcd233401ed3aa167d83a8e35b05
|
||||
Author: Thomas Huth <thuth@redhat.com>
|
||||
Date: Thu Feb 29 11:43:37 2024 +0100
|
||||
|
||||
chardev/char-socket: Fix TLS io channels sending too much data to the backend
|
||||
|
||||
Commit ffda5db65a ("io/channel-tls: fix handling of bigger read buffers")
|
||||
changed the behavior of the TLS io channels to schedule a second reading
|
||||
attempt if there is still incoming data pending. This caused a regression
|
||||
with backends like the sclpconsole that check in their read function that
|
||||
the sender does not try to write more bytes to it than the device can
|
||||
currently handle.
|
||||
|
||||
The problem can be reproduced like this:
|
||||
|
||||
1) In one terminal, do this:
|
||||
|
||||
mkdir qemu-pki
|
||||
cd qemu-pki
|
||||
openssl genrsa 2048 > ca-key.pem
|
||||
openssl req -new -x509 -nodes -days 365000 -key ca-key.pem -out ca-cert.pem
|
||||
# enter some dummy value for the cert
|
||||
openssl genrsa 2048 > server-key.pem
|
||||
openssl req -new -x509 -nodes -days 365000 -key server-key.pem \
|
||||
-out server-cert.pem
|
||||
# enter some other dummy values for the cert
|
||||
|
||||
gnutls-serv --echo --x509cafile ca-cert.pem --x509keyfile server-key.pem \
|
||||
--x509certfile server-cert.pem -p 8338
|
||||
|
||||
2) In another terminal, do this:
|
||||
|
||||
wget https://download.fedoraproject.org/pub/fedora-secondary/releases/39/Cloud/s390x/images/Fedora-Cloud-Base-39-1.5.s390x.qcow2
|
||||
|
||||
qemu-system-s390x -nographic -nodefaults \
|
||||
-hda Fedora-Cloud-Base-39-1.5.s390x.qcow2 \
|
||||
-object tls-creds-x509,id=tls0,endpoint=client,verify-peer=false,dir=$PWD/qemu-pki \
|
||||
-chardev socket,id=tls_chardev,host=localhost,port=8338,tls-creds=tls0 \
|
||||
-device sclpconsole,chardev=tls_chardev,id=tls_serial
|
||||
|
||||
QEMU then aborts after a second or two with:
|
||||
|
||||
qemu-system-s390x: ../hw/char/sclpconsole.c:73: chr_read: Assertion
|
||||
`size <= SIZE_BUFFER_VT220 - scon->iov_data_len' failed.
|
||||
Aborted (core dumped)
|
||||
|
||||
It looks like the second read does not trigger the chr_can_read() function
|
||||
to be called before the second read, which should normally always be done
|
||||
before sending bytes to a character device to see how much it can handle,
|
||||
so the s->max_size in tcp_chr_read() still contains the old value from the
|
||||
previous read. Let's make sure that we use the up-to-date value by calling
|
||||
tcp_chr_read_poll() again here.
|
||||
|
||||
Fixes: ffda5db65a ("io/channel-tls: fix handling of bigger read buffers")
|
||||
Buglink: https://issues.redhat.com/browse/RHEL-24614
|
||||
Reviewed-by: "Daniel P. Berrangé" <berrange@redhat.com>
|
||||
Message-ID: <20240229104339.42574-1-thuth@redhat.com>
|
||||
Reviewed-by: Antoine Damhet <antoine.damhet@blade-group.com>
|
||||
Tested-by: Antoine Damhet <antoine.damhet@blade-group.com>
|
||||
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
|
||||
Signed-off-by: Thomas Huth <thuth@redhat.com>
|
||||
|
||||
Signed-off-by: Thomas Huth <thuth@redhat.com>
|
||||
---
|
||||
chardev/char-socket.c | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/chardev/char-socket.c b/chardev/char-socket.c
|
||||
index 73947da188..034840593d 100644
|
||||
--- a/chardev/char-socket.c
|
||||
+++ b/chardev/char-socket.c
|
||||
@@ -492,9 +492,9 @@ static gboolean tcp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
|
||||
s->max_size <= 0) {
|
||||
return TRUE;
|
||||
}
|
||||
- len = sizeof(buf);
|
||||
- if (len > s->max_size) {
|
||||
- len = s->max_size;
|
||||
+ len = tcp_chr_read_poll(opaque);
|
||||
+ if (len > sizeof(buf)) {
|
||||
+ len = sizeof(buf);
|
||||
}
|
||||
size = tcp_chr_recv(chr, (void *)buf, len);
|
||||
if (size == 0 || (size == -1 && errno != EAGAIN)) {
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,78 +0,0 @@
|
||||
From 4d4102f6e2f9afd6182888787ae8b570347df87d Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
|
||||
Date: Mon, 18 Mar 2024 18:06:59 +0000
|
||||
Subject: [PATCH 1/3] chardev: lower priority of the HUP GSource in socket
|
||||
chardev
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
RH-Author: Daniel P. Berrangé <berrange@redhat.com>
|
||||
RH-MergeRequest: 233: Fix handling of TLS sessions in chardevs
|
||||
RH-Jira: RHEL-24614
|
||||
RH-Acked-by: Thomas Huth <thuth@redhat.com>
|
||||
RH-Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com>
|
||||
RH-Commit: [1/3] 842f54349191b0206e68f35a7a80155f5a584942 (berrange/centos-src-qemu)
|
||||
|
||||
The socket chardev often has 2 GSource object registered against the
|
||||
same FD. One is registered all the time and is just intended to handle
|
||||
POLLHUP events, while the other gets registered & unregistered on the
|
||||
fly as the frontend is ready to receive more data or not.
|
||||
|
||||
It is very common for poll() to signal a POLLHUP event at the same time
|
||||
as there is pending incoming data from the disconnected client. It is
|
||||
therefore essential to process incoming data prior to processing HUP.
|
||||
The problem with having 2 GSource on the same FD is that there is no
|
||||
guaranteed ordering of execution between them, so the chardev code may
|
||||
process HUP first and thus discard data.
|
||||
|
||||
This failure scenario is non-deterministic but can be seen fairly
|
||||
reliably by reverting a7077b8e354d90fec26c2921aa2dea85b90dff90, and
|
||||
then running 'tests/unit/test-char', which will sometimes fail with
|
||||
missing data.
|
||||
|
||||
Ideally QEMU would only have 1 GSource, but that's a complex code
|
||||
refactoring job. The next best solution is to try to ensure ordering
|
||||
between the 2 GSource objects. This can be achieved by lowering the
|
||||
priority of the HUP GSource, so that it is never dispatched if the
|
||||
main GSource is also ready to dispatch. Counter-intuitively, lowering
|
||||
the priority of a GSource is done by raising its priority number.
|
||||
|
||||
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
|
||||
Reviewed-by: Thomas Huth <thuth@redhat.com>
|
||||
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
(cherry picked from commit 8bd8b04adc9f18904f323dff085f8b4ec77915c6)
|
||||
---
|
||||
chardev/char-socket.c | 16 ++++++++++++++++
|
||||
1 file changed, 16 insertions(+)
|
||||
|
||||
diff --git a/chardev/char-socket.c b/chardev/char-socket.c
|
||||
index 034840593d..f48d341ebc 100644
|
||||
--- a/chardev/char-socket.c
|
||||
+++ b/chardev/char-socket.c
|
||||
@@ -597,6 +597,22 @@ static void update_ioc_handlers(SocketChardev *s)
|
||||
|
||||
remove_hup_source(s);
|
||||
s->hup_source = qio_channel_create_watch(s->ioc, G_IO_HUP);
|
||||
+ /*
|
||||
+ * poll() is liable to return POLLHUP even when there is
|
||||
+ * still incoming data available to read on the FD. If
|
||||
+ * we have the hup_source at the same priority as the
|
||||
+ * main io_add_watch_poll GSource, then we might end up
|
||||
+ * processing the POLLHUP event first, closing the FD,
|
||||
+ * and as a result silently discard data we should have
|
||||
+ * read.
|
||||
+ *
|
||||
+ * By setting the hup_source to G_PRIORITY_DEFAULT + 1,
|
||||
+ * we ensure that io_add_watch_poll GSource will always
|
||||
+ * be dispatched first, thus guaranteeing we will be
|
||||
+ * able to process all incoming data before closing the
|
||||
+ * FD
|
||||
+ */
|
||||
+ g_source_set_priority(s->hup_source, G_PRIORITY_DEFAULT + 1);
|
||||
g_source_set_callback(s->hup_source, (GSourceFunc)tcp_chr_hup,
|
||||
chr, NULL);
|
||||
g_source_attach(s->hup_source, chr->gcontext);
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,412 +0,0 @@
|
||||
From e99c56752a1c4021a93c92b7be78856ebefaa1b3 Mon Sep 17 00:00:00 2001
|
||||
From: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Date: Mon, 18 Mar 2024 14:34:29 -0400
|
||||
Subject: [PATCH 1/2] coroutine: cap per-thread local pool size
|
||||
|
||||
RH-Author: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
RH-MergeRequest: 234: coroutine: cap per-thread local pool size
|
||||
RH-Jira: RHEL-28947
|
||||
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
|
||||
RH-Acked-by: Hanna Czenczek <hreitz@redhat.com>
|
||||
RH-Commit: [1/2] 5971de1c1e238457925bfb9c4bfc932de857b28d (stefanha/centos-stream-qemu-kvm)
|
||||
|
||||
The coroutine pool implementation can hit the Linux vm.max_map_count
|
||||
limit, causing QEMU to abort with "failed to allocate memory for stack"
|
||||
or "failed to set up stack guard page" during coroutine creation.
|
||||
|
||||
This happens because per-thread pools can grow to tens of thousands of
|
||||
coroutines. Each coroutine causes 2 virtual memory areas to be created.
|
||||
Eventually vm.max_map_count is reached and memory-related syscalls fail.
|
||||
The per-thread pool sizes are non-uniform and depend on past coroutine
|
||||
usage in each thread, so it's possible for one thread to have a large
|
||||
pool while another thread's pool is empty.
|
||||
|
||||
Switch to a new coroutine pool implementation with a global pool that
|
||||
grows to a maximum number of coroutines and per-thread local pools that
|
||||
are capped at hardcoded small number of coroutines.
|
||||
|
||||
This approach does not leave large numbers of coroutines pooled in a
|
||||
thread that may not use them again. In order to perform well it
|
||||
amortizes the cost of global pool accesses by working in batches of
|
||||
coroutines instead of individual coroutines.
|
||||
|
||||
The global pool is a list. Threads donate batches of coroutines to when
|
||||
they have too many and take batches from when they have too few:
|
||||
|
||||
.-----------------------------------.
|
||||
| Batch 1 | Batch 2 | Batch 3 | ... | global_pool
|
||||
`-----------------------------------'
|
||||
|
||||
Each thread has up to 2 batches of coroutines:
|
||||
|
||||
.-------------------.
|
||||
| Batch 1 | Batch 2 | per-thread local_pool (maximum 2 batches)
|
||||
`-------------------'
|
||||
|
||||
The goal of this change is to reduce the excessive number of pooled
|
||||
coroutines that cause QEMU to abort when vm.max_map_count is reached
|
||||
without losing the performance of an adequately sized coroutine pool.
|
||||
|
||||
Here are virtio-blk disk I/O benchmark results:
|
||||
|
||||
RW BLKSIZE IODEPTH OLD NEW CHANGE
|
||||
randread 4k 1 113725 117451 +3.3%
|
||||
randread 4k 8 192968 198510 +2.9%
|
||||
randread 4k 16 207138 209429 +1.1%
|
||||
randread 4k 32 212399 215145 +1.3%
|
||||
randread 4k 64 218319 221277 +1.4%
|
||||
randread 128k 1 17587 17535 -0.3%
|
||||
randread 128k 8 17614 17616 +0.0%
|
||||
randread 128k 16 17608 17609 +0.0%
|
||||
randread 128k 32 17552 17553 +0.0%
|
||||
randread 128k 64 17484 17484 +0.0%
|
||||
|
||||
See files/{fio.sh,test.xml.j2} for the benchmark configuration:
|
||||
https://gitlab.com/stefanha/virt-playbooks/-/tree/coroutine-pool-fix-sizing
|
||||
|
||||
Buglink: https://issues.redhat.com/browse/RHEL-28947
|
||||
Reported-by: Sanjay Rao <srao@redhat.com>
|
||||
Reported-by: Boaz Ben Shabat <bbenshab@redhat.com>
|
||||
Reported-by: Joe Mario <jmario@redhat.com>
|
||||
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Message-ID: <20240318183429.1039340-1-stefanha@redhat.com>
|
||||
(cherry picked from commit 86a637e48104ae74d8be53bed6441ce32be33433)
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
---
|
||||
util/qemu-coroutine.c | 282 +++++++++++++++++++++++++++++++++---------
|
||||
1 file changed, 223 insertions(+), 59 deletions(-)
|
||||
|
||||
diff --git a/util/qemu-coroutine.c b/util/qemu-coroutine.c
|
||||
index 5fd2dbaf8b..2790959eaf 100644
|
||||
--- a/util/qemu-coroutine.c
|
||||
+++ b/util/qemu-coroutine.c
|
||||
@@ -18,39 +18,200 @@
|
||||
#include "qemu/atomic.h"
|
||||
#include "qemu/coroutine_int.h"
|
||||
#include "qemu/coroutine-tls.h"
|
||||
+#include "qemu/cutils.h"
|
||||
#include "block/aio.h"
|
||||
|
||||
-/**
|
||||
- * The minimal batch size is always 64, coroutines from the release_pool are
|
||||
- * reused as soon as there are 64 coroutines in it. The maximum pool size starts
|
||||
- * with 64 and is increased on demand so that coroutines are not deleted even if
|
||||
- * they are not immediately reused.
|
||||
- */
|
||||
enum {
|
||||
- POOL_MIN_BATCH_SIZE = 64,
|
||||
- POOL_INITIAL_MAX_SIZE = 64,
|
||||
+ COROUTINE_POOL_BATCH_MAX_SIZE = 128,
|
||||
};
|
||||
|
||||
-/** Free list to speed up creation */
|
||||
-static QSLIST_HEAD(, Coroutine) release_pool = QSLIST_HEAD_INITIALIZER(pool);
|
||||
-static unsigned int pool_max_size = POOL_INITIAL_MAX_SIZE;
|
||||
-static unsigned int release_pool_size;
|
||||
+/*
|
||||
+ * Coroutine creation and deletion is expensive so a pool of unused coroutines
|
||||
+ * is kept as a cache. When the pool has coroutines available, they are
|
||||
+ * recycled instead of creating new ones from scratch. Coroutines are added to
|
||||
+ * the pool upon termination.
|
||||
+ *
|
||||
+ * The pool is global but each thread maintains a small local pool to avoid
|
||||
+ * global pool contention. Threads fetch and return batches of coroutines from
|
||||
+ * the global pool to maintain their local pool. The local pool holds up to two
|
||||
+ * batches whereas the maximum size of the global pool is controlled by the
|
||||
+ * qemu_coroutine_inc_pool_size() API.
|
||||
+ *
|
||||
+ * .-----------------------------------.
|
||||
+ * | Batch 1 | Batch 2 | Batch 3 | ... | global_pool
|
||||
+ * `-----------------------------------'
|
||||
+ *
|
||||
+ * .-------------------.
|
||||
+ * | Batch 1 | Batch 2 | per-thread local_pool (maximum 2 batches)
|
||||
+ * `-------------------'
|
||||
+ */
|
||||
+typedef struct CoroutinePoolBatch {
|
||||
+ /* Batches are kept in a list */
|
||||
+ QSLIST_ENTRY(CoroutinePoolBatch) next;
|
||||
+
|
||||
+ /* This batch holds up to @COROUTINE_POOL_BATCH_MAX_SIZE coroutines */
|
||||
+ QSLIST_HEAD(, Coroutine) list;
|
||||
+ unsigned int size;
|
||||
+} CoroutinePoolBatch;
|
||||
+
|
||||
+typedef QSLIST_HEAD(, CoroutinePoolBatch) CoroutinePool;
|
||||
+
|
||||
+/* Host operating system limit on number of pooled coroutines */
|
||||
+static unsigned int global_pool_hard_max_size;
|
||||
+
|
||||
+static QemuMutex global_pool_lock; /* protects the following variables */
|
||||
+static CoroutinePool global_pool = QSLIST_HEAD_INITIALIZER(global_pool);
|
||||
+static unsigned int global_pool_size;
|
||||
+static unsigned int global_pool_max_size = COROUTINE_POOL_BATCH_MAX_SIZE;
|
||||
+
|
||||
+QEMU_DEFINE_STATIC_CO_TLS(CoroutinePool, local_pool);
|
||||
+QEMU_DEFINE_STATIC_CO_TLS(Notifier, local_pool_cleanup_notifier);
|
||||
|
||||
-typedef QSLIST_HEAD(, Coroutine) CoroutineQSList;
|
||||
-QEMU_DEFINE_STATIC_CO_TLS(CoroutineQSList, alloc_pool);
|
||||
-QEMU_DEFINE_STATIC_CO_TLS(unsigned int, alloc_pool_size);
|
||||
-QEMU_DEFINE_STATIC_CO_TLS(Notifier, coroutine_pool_cleanup_notifier);
|
||||
+static CoroutinePoolBatch *coroutine_pool_batch_new(void)
|
||||
+{
|
||||
+ CoroutinePoolBatch *batch = g_new(CoroutinePoolBatch, 1);
|
||||
+
|
||||
+ QSLIST_INIT(&batch->list);
|
||||
+ batch->size = 0;
|
||||
+ return batch;
|
||||
+}
|
||||
|
||||
-static void coroutine_pool_cleanup(Notifier *n, void *value)
|
||||
+static void coroutine_pool_batch_delete(CoroutinePoolBatch *batch)
|
||||
{
|
||||
Coroutine *co;
|
||||
Coroutine *tmp;
|
||||
- CoroutineQSList *alloc_pool = get_ptr_alloc_pool();
|
||||
|
||||
- QSLIST_FOREACH_SAFE(co, alloc_pool, pool_next, tmp) {
|
||||
- QSLIST_REMOVE_HEAD(alloc_pool, pool_next);
|
||||
+ QSLIST_FOREACH_SAFE(co, &batch->list, pool_next, tmp) {
|
||||
+ QSLIST_REMOVE_HEAD(&batch->list, pool_next);
|
||||
qemu_coroutine_delete(co);
|
||||
}
|
||||
+ g_free(batch);
|
||||
+}
|
||||
+
|
||||
+static void local_pool_cleanup(Notifier *n, void *value)
|
||||
+{
|
||||
+ CoroutinePool *local_pool = get_ptr_local_pool();
|
||||
+ CoroutinePoolBatch *batch;
|
||||
+ CoroutinePoolBatch *tmp;
|
||||
+
|
||||
+ QSLIST_FOREACH_SAFE(batch, local_pool, next, tmp) {
|
||||
+ QSLIST_REMOVE_HEAD(local_pool, next);
|
||||
+ coroutine_pool_batch_delete(batch);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/* Ensure the atexit notifier is registered */
|
||||
+static void local_pool_cleanup_init_once(void)
|
||||
+{
|
||||
+ Notifier *notifier = get_ptr_local_pool_cleanup_notifier();
|
||||
+ if (!notifier->notify) {
|
||||
+ notifier->notify = local_pool_cleanup;
|
||||
+ qemu_thread_atexit_add(notifier);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/* Helper to get the next unused coroutine from the local pool */
|
||||
+static Coroutine *coroutine_pool_get_local(void)
|
||||
+{
|
||||
+ CoroutinePool *local_pool = get_ptr_local_pool();
|
||||
+ CoroutinePoolBatch *batch = QSLIST_FIRST(local_pool);
|
||||
+ Coroutine *co;
|
||||
+
|
||||
+ if (unlikely(!batch)) {
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ co = QSLIST_FIRST(&batch->list);
|
||||
+ QSLIST_REMOVE_HEAD(&batch->list, pool_next);
|
||||
+ batch->size--;
|
||||
+
|
||||
+ if (batch->size == 0) {
|
||||
+ QSLIST_REMOVE_HEAD(local_pool, next);
|
||||
+ coroutine_pool_batch_delete(batch);
|
||||
+ }
|
||||
+ return co;
|
||||
+}
|
||||
+
|
||||
+/* Get the next batch from the global pool */
|
||||
+static void coroutine_pool_refill_local(void)
|
||||
+{
|
||||
+ CoroutinePool *local_pool = get_ptr_local_pool();
|
||||
+ CoroutinePoolBatch *batch;
|
||||
+
|
||||
+ WITH_QEMU_LOCK_GUARD(&global_pool_lock) {
|
||||
+ batch = QSLIST_FIRST(&global_pool);
|
||||
+
|
||||
+ if (batch) {
|
||||
+ QSLIST_REMOVE_HEAD(&global_pool, next);
|
||||
+ global_pool_size -= batch->size;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (batch) {
|
||||
+ QSLIST_INSERT_HEAD(local_pool, batch, next);
|
||||
+ local_pool_cleanup_init_once();
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/* Add a batch of coroutines to the global pool */
|
||||
+static void coroutine_pool_put_global(CoroutinePoolBatch *batch)
|
||||
+{
|
||||
+ WITH_QEMU_LOCK_GUARD(&global_pool_lock) {
|
||||
+ unsigned int max = MIN(global_pool_max_size,
|
||||
+ global_pool_hard_max_size);
|
||||
+
|
||||
+ if (global_pool_size < max) {
|
||||
+ QSLIST_INSERT_HEAD(&global_pool, batch, next);
|
||||
+
|
||||
+ /* Overshooting the max pool size is allowed */
|
||||
+ global_pool_size += batch->size;
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* The global pool was full, so throw away this batch */
|
||||
+ coroutine_pool_batch_delete(batch);
|
||||
+}
|
||||
+
|
||||
+/* Get the next unused coroutine from the pool or return NULL */
|
||||
+static Coroutine *coroutine_pool_get(void)
|
||||
+{
|
||||
+ Coroutine *co;
|
||||
+
|
||||
+ co = coroutine_pool_get_local();
|
||||
+ if (!co) {
|
||||
+ coroutine_pool_refill_local();
|
||||
+ co = coroutine_pool_get_local();
|
||||
+ }
|
||||
+ return co;
|
||||
+}
|
||||
+
|
||||
+static void coroutine_pool_put(Coroutine *co)
|
||||
+{
|
||||
+ CoroutinePool *local_pool = get_ptr_local_pool();
|
||||
+ CoroutinePoolBatch *batch = QSLIST_FIRST(local_pool);
|
||||
+
|
||||
+ if (unlikely(!batch)) {
|
||||
+ batch = coroutine_pool_batch_new();
|
||||
+ QSLIST_INSERT_HEAD(local_pool, batch, next);
|
||||
+ local_pool_cleanup_init_once();
|
||||
+ }
|
||||
+
|
||||
+ if (unlikely(batch->size >= COROUTINE_POOL_BATCH_MAX_SIZE)) {
|
||||
+ CoroutinePoolBatch *next = QSLIST_NEXT(batch, next);
|
||||
+
|
||||
+ /* Is the local pool full? */
|
||||
+ if (next) {
|
||||
+ QSLIST_REMOVE_HEAD(local_pool, next);
|
||||
+ coroutine_pool_put_global(batch);
|
||||
+ }
|
||||
+
|
||||
+ batch = coroutine_pool_batch_new();
|
||||
+ QSLIST_INSERT_HEAD(local_pool, batch, next);
|
||||
+ }
|
||||
+
|
||||
+ QSLIST_INSERT_HEAD(&batch->list, co, pool_next);
|
||||
+ batch->size++;
|
||||
}
|
||||
|
||||
Coroutine *qemu_coroutine_create(CoroutineEntry *entry, void *opaque)
|
||||
@@ -58,31 +219,7 @@ Coroutine *qemu_coroutine_create(CoroutineEntry *entry, void *opaque)
|
||||
Coroutine *co = NULL;
|
||||
|
||||
if (IS_ENABLED(CONFIG_COROUTINE_POOL)) {
|
||||
- CoroutineQSList *alloc_pool = get_ptr_alloc_pool();
|
||||
-
|
||||
- co = QSLIST_FIRST(alloc_pool);
|
||||
- if (!co) {
|
||||
- if (release_pool_size > POOL_MIN_BATCH_SIZE) {
|
||||
- /* Slow path; a good place to register the destructor, too. */
|
||||
- Notifier *notifier = get_ptr_coroutine_pool_cleanup_notifier();
|
||||
- if (!notifier->notify) {
|
||||
- notifier->notify = coroutine_pool_cleanup;
|
||||
- qemu_thread_atexit_add(notifier);
|
||||
- }
|
||||
-
|
||||
- /* This is not exact; there could be a little skew between
|
||||
- * release_pool_size and the actual size of release_pool. But
|
||||
- * it is just a heuristic, it does not need to be perfect.
|
||||
- */
|
||||
- set_alloc_pool_size(qatomic_xchg(&release_pool_size, 0));
|
||||
- QSLIST_MOVE_ATOMIC(alloc_pool, &release_pool);
|
||||
- co = QSLIST_FIRST(alloc_pool);
|
||||
- }
|
||||
- }
|
||||
- if (co) {
|
||||
- QSLIST_REMOVE_HEAD(alloc_pool, pool_next);
|
||||
- set_alloc_pool_size(get_alloc_pool_size() - 1);
|
||||
- }
|
||||
+ co = coroutine_pool_get();
|
||||
}
|
||||
|
||||
if (!co) {
|
||||
@@ -100,19 +237,10 @@ static void coroutine_delete(Coroutine *co)
|
||||
co->caller = NULL;
|
||||
|
||||
if (IS_ENABLED(CONFIG_COROUTINE_POOL)) {
|
||||
- if (release_pool_size < qatomic_read(&pool_max_size) * 2) {
|
||||
- QSLIST_INSERT_HEAD_ATOMIC(&release_pool, co, pool_next);
|
||||
- qatomic_inc(&release_pool_size);
|
||||
- return;
|
||||
- }
|
||||
- if (get_alloc_pool_size() < qatomic_read(&pool_max_size)) {
|
||||
- QSLIST_INSERT_HEAD(get_ptr_alloc_pool(), co, pool_next);
|
||||
- set_alloc_pool_size(get_alloc_pool_size() + 1);
|
||||
- return;
|
||||
- }
|
||||
+ coroutine_pool_put(co);
|
||||
+ } else {
|
||||
+ qemu_coroutine_delete(co);
|
||||
}
|
||||
-
|
||||
- qemu_coroutine_delete(co);
|
||||
}
|
||||
|
||||
void qemu_aio_coroutine_enter(AioContext *ctx, Coroutine *co)
|
||||
@@ -223,10 +351,46 @@ AioContext *qemu_coroutine_get_aio_context(Coroutine *co)
|
||||
|
||||
void qemu_coroutine_inc_pool_size(unsigned int additional_pool_size)
|
||||
{
|
||||
- qatomic_add(&pool_max_size, additional_pool_size);
|
||||
+ QEMU_LOCK_GUARD(&global_pool_lock);
|
||||
+ global_pool_max_size += additional_pool_size;
|
||||
}
|
||||
|
||||
void qemu_coroutine_dec_pool_size(unsigned int removing_pool_size)
|
||||
{
|
||||
- qatomic_sub(&pool_max_size, removing_pool_size);
|
||||
+ QEMU_LOCK_GUARD(&global_pool_lock);
|
||||
+ global_pool_max_size -= removing_pool_size;
|
||||
+}
|
||||
+
|
||||
+static unsigned int get_global_pool_hard_max_size(void)
|
||||
+{
|
||||
+#ifdef __linux__
|
||||
+ g_autofree char *contents = NULL;
|
||||
+ int max_map_count;
|
||||
+
|
||||
+ /*
|
||||
+ * Linux processes can have up to max_map_count virtual memory areas
|
||||
+ * (VMAs). mmap(2), mprotect(2), etc fail with ENOMEM beyond this limit. We
|
||||
+ * must limit the coroutine pool to a safe size to avoid running out of
|
||||
+ * VMAs.
|
||||
+ */
|
||||
+ if (g_file_get_contents("/proc/sys/vm/max_map_count", &contents, NULL,
|
||||
+ NULL) &&
|
||||
+ qemu_strtoi(contents, NULL, 10, &max_map_count) == 0) {
|
||||
+ /*
|
||||
+ * This is a conservative upper bound that avoids exceeding
|
||||
+ * max_map_count. Leave half for non-coroutine users like library
|
||||
+ * dependencies, vhost-user, etc. Each coroutine takes up 2 VMAs so
|
||||
+ * halve the amount again.
|
||||
+ */
|
||||
+ return max_map_count / 4;
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
+ return UINT_MAX;
|
||||
+}
|
||||
+
|
||||
+static void __attribute__((constructor)) qemu_coroutine_init(void)
|
||||
+{
|
||||
+ qemu_mutex_init(&global_pool_lock);
|
||||
+ global_pool_hard_max_size = get_global_pool_hard_max_size();
|
||||
}
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,61 +0,0 @@
|
||||
From 0aa65dc3acba481f7064df936ab49e3bceb1d5bd Mon Sep 17 00:00:00 2001
|
||||
From: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Date: Wed, 20 Mar 2024 14:12:32 -0400
|
||||
Subject: [PATCH 2/2] coroutine: reserve 5,000 mappings
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
RH-Author: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
RH-MergeRequest: 234: coroutine: cap per-thread local pool size
|
||||
RH-Jira: RHEL-28947
|
||||
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
|
||||
RH-Acked-by: Hanna Czenczek <hreitz@redhat.com>
|
||||
RH-Commit: [2/2] 78560c2b947471111cc16c313d6f38db42860a1c (stefanha/centos-stream-qemu-kvm)
|
||||
|
||||
Daniel P. Berrangé <berrange@redhat.com> pointed out that the coroutine
|
||||
pool size heuristic is very conservative. Instead of halving
|
||||
max_map_count, he suggested reserving 5,000 mappings for non-coroutine
|
||||
users based on observations of guests he has access to.
|
||||
|
||||
Fixes: 86a637e48104 ("coroutine: cap per-thread local pool size")
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
Message-id: 20240320181232.1464819-1-stefanha@redhat.com
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit 9352f80cd926fe2dde7c89b93ee33bb0356ff40e)
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
---
|
||||
util/qemu-coroutine.c | 15 ++++++++++-----
|
||||
1 file changed, 10 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/util/qemu-coroutine.c b/util/qemu-coroutine.c
|
||||
index 2790959eaf..eb4eebefdf 100644
|
||||
--- a/util/qemu-coroutine.c
|
||||
+++ b/util/qemu-coroutine.c
|
||||
@@ -377,12 +377,17 @@ static unsigned int get_global_pool_hard_max_size(void)
|
||||
NULL) &&
|
||||
qemu_strtoi(contents, NULL, 10, &max_map_count) == 0) {
|
||||
/*
|
||||
- * This is a conservative upper bound that avoids exceeding
|
||||
- * max_map_count. Leave half for non-coroutine users like library
|
||||
- * dependencies, vhost-user, etc. Each coroutine takes up 2 VMAs so
|
||||
- * halve the amount again.
|
||||
+ * This is an upper bound that avoids exceeding max_map_count. Leave a
|
||||
+ * fixed amount for non-coroutine users like library dependencies,
|
||||
+ * vhost-user, etc. Each coroutine takes up 2 VMAs so halve the
|
||||
+ * remaining amount.
|
||||
*/
|
||||
- return max_map_count / 4;
|
||||
+ if (max_map_count > 5000) {
|
||||
+ return (max_map_count - 5000) / 2;
|
||||
+ } else {
|
||||
+ /* Disable the global pool but threads still have local pools */
|
||||
+ return 0;
|
||||
+ }
|
||||
}
|
||||
#endif
|
||||
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,186 +0,0 @@
|
||||
From ea2e2368dcf4140be47288472f2c2a094358e0c7 Mon Sep 17 00:00:00 2001
|
||||
From: Igor Mammedov <imammedo@redhat.com>
|
||||
Date: Thu, 8 Feb 2024 23:03:45 +0100
|
||||
Subject: [PATCH 03/20] hw/i386/pc: Defer smbios_set_defaults() to machine_done
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 230: Workaround Windows failing to find 64bit SMBIOS entry point with SeaBIOS
|
||||
RH-Jira: RHEL-21705
|
||||
RH-Acked-by: MST <mst@redhat.com>
|
||||
RH-Acked-by: Ani Sinha <None>
|
||||
RH-Commit: [1/18] 9d4c1d1a910fec7d310429d6fc0b10c798932db7
|
||||
|
||||
JIRA: https://issues.redhat.com/browse/RHEL-21705
|
||||
|
||||
commit: a0204a5ed091dfe79aced7ec8f3ce1931fd25816
|
||||
Author: Bernhard Beschow <shentey@gmail.com>
|
||||
|
||||
Handling most of smbios data generation in the machine_done notifier is similar
|
||||
to how the ARM virt machine handles it which also calls smbios_set_defaults()
|
||||
there. The result is that all pc machines are freed from explicitly worrying
|
||||
about smbios setup.
|
||||
|
||||
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
|
||||
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
|
||||
Message-ID: <20240208220349.4948-6-shentey@gmail.com>
|
||||
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
|
||||
|
||||
Conflicts: hw/i386/pc_q35.c, hw/i386/pc_piix.c
|
||||
due to missing 4d3457fef9 (w/i386/pc: Merge pc_guest_info_init() into pc_machine_initfn())
|
||||
and different signature of smbios_set_defaults() downstream
|
||||
Fixup: hw/i386/fw_cfg.c to account for downstream changes smbios_set_defaults()
|
||||
|
||||
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
|
||||
---
|
||||
hw/i386/fw_cfg.c | 14 +++++++++++++-
|
||||
hw/i386/fw_cfg.h | 3 ++-
|
||||
hw/i386/pc.c | 2 +-
|
||||
hw/i386/pc_piix.c | 12 ------------
|
||||
hw/i386/pc_q35.c | 11 -----------
|
||||
include/hw/i386/pc.h | 1 -
|
||||
6 files changed, 16 insertions(+), 27 deletions(-)
|
||||
|
||||
diff --git a/hw/i386/fw_cfg.c b/hw/i386/fw_cfg.c
|
||||
index 7362daa45a..6a5466faf0 100644
|
||||
--- a/hw/i386/fw_cfg.c
|
||||
+++ b/hw/i386/fw_cfg.c
|
||||
@@ -48,15 +48,27 @@ const char *fw_cfg_arch_key_name(uint16_t key)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
-void fw_cfg_build_smbios(MachineState *ms, FWCfgState *fw_cfg)
|
||||
+void fw_cfg_build_smbios(PCMachineState *pcms, FWCfgState *fw_cfg)
|
||||
{
|
||||
#ifdef CONFIG_SMBIOS
|
||||
uint8_t *smbios_tables, *smbios_anchor;
|
||||
size_t smbios_tables_len, smbios_anchor_len;
|
||||
struct smbios_phys_mem_area *mem_array;
|
||||
unsigned i, array_count;
|
||||
+ MachineState *ms = MACHINE(pcms);
|
||||
+ PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
|
||||
+ MachineClass *mc = MACHINE_GET_CLASS(pcms);
|
||||
X86CPU *cpu = X86_CPU(ms->possible_cpus->cpus[0].cpu);
|
||||
|
||||
+ if (pcmc->smbios_defaults) {
|
||||
+ /* These values are guest ABI, do not change */
|
||||
+ smbios_set_defaults("QEMU", mc->desc, mc->name,
|
||||
+ pcmc->smbios_legacy_mode, pcmc->smbios_uuid_encoded,
|
||||
+ pcmc->smbios_stream_product,
|
||||
+ pcmc->smbios_stream_version,
|
||||
+ pcms->smbios_entry_point_type);
|
||||
+ }
|
||||
+
|
||||
/* tell smbios about cpuid version and features */
|
||||
smbios_set_cpuid(cpu->env.cpuid_version, cpu->env.features[FEAT_1_EDX]);
|
||||
|
||||
diff --git a/hw/i386/fw_cfg.h b/hw/i386/fw_cfg.h
|
||||
index 86ca7c1c0c..1e1de6b4a3 100644
|
||||
--- a/hw/i386/fw_cfg.h
|
||||
+++ b/hw/i386/fw_cfg.h
|
||||
@@ -10,6 +10,7 @@
|
||||
#define HW_I386_FW_CFG_H
|
||||
|
||||
#include "hw/boards.h"
|
||||
+#include "hw/i386/pc.h"
|
||||
#include "hw/nvram/fw_cfg.h"
|
||||
|
||||
#define FW_CFG_IO_BASE 0x510
|
||||
@@ -22,7 +23,7 @@
|
||||
FWCfgState *fw_cfg_arch_create(MachineState *ms,
|
||||
uint16_t boot_cpus,
|
||||
uint16_t apic_id_limit);
|
||||
-void fw_cfg_build_smbios(MachineState *ms, FWCfgState *fw_cfg);
|
||||
+void fw_cfg_build_smbios(PCMachineState *ms, FWCfgState *fw_cfg);
|
||||
void fw_cfg_build_feature_control(MachineState *ms, FWCfgState *fw_cfg);
|
||||
void fw_cfg_add_acpi_dsdt(Aml *scope, FWCfgState *fw_cfg);
|
||||
|
||||
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
|
||||
index a1faa9e92c..16de2a59e8 100644
|
||||
--- a/hw/i386/pc.c
|
||||
+++ b/hw/i386/pc.c
|
||||
@@ -847,7 +847,7 @@ void pc_machine_done(Notifier *notifier, void *data)
|
||||
|
||||
acpi_setup();
|
||||
if (x86ms->fw_cfg) {
|
||||
- fw_cfg_build_smbios(MACHINE(pcms), x86ms->fw_cfg);
|
||||
+ fw_cfg_build_smbios(pcms, x86ms->fw_cfg);
|
||||
fw_cfg_build_feature_control(MACHINE(pcms), x86ms->fw_cfg);
|
||||
/* update FW_CFG_NB_CPUS to account for -device added CPUs */
|
||||
fw_cfg_modify_i16(x86ms->fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus);
|
||||
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
|
||||
index 09d02cc91f..7344b35cf1 100644
|
||||
--- a/hw/i386/pc_piix.c
|
||||
+++ b/hw/i386/pc_piix.c
|
||||
@@ -36,7 +36,6 @@
|
||||
#include "hw/rtc/mc146818rtc.h"
|
||||
#include "hw/southbridge/piix.h"
|
||||
#include "hw/display/ramfb.h"
|
||||
-#include "hw/firmware/smbios.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/pci/pci_ids.h"
|
||||
#include "hw/usb.h"
|
||||
@@ -233,17 +232,6 @@ static void pc_init1(MachineState *machine,
|
||||
|
||||
pc_guest_info_init(pcms);
|
||||
|
||||
- if (pcmc->smbios_defaults) {
|
||||
- MachineClass *mc = MACHINE_GET_CLASS(machine);
|
||||
- /* These values are guest ABI, do not change */
|
||||
- smbios_set_defaults("Red Hat", "KVM",
|
||||
- mc->desc, pcmc->smbios_legacy_mode,
|
||||
- pcmc->smbios_uuid_encoded,
|
||||
- pcmc->smbios_stream_product,
|
||||
- pcmc->smbios_stream_version,
|
||||
- pcms->smbios_entry_point_type);
|
||||
- }
|
||||
-
|
||||
/* allocate ram and load rom/bios */
|
||||
if (!xen_enabled()) {
|
||||
pc_memory_init(pcms, system_memory, rom_memory, hole64_size);
|
||||
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
|
||||
index c6967e1846..9a22ff5dd6 100644
|
||||
--- a/hw/i386/pc_q35.c
|
||||
+++ b/hw/i386/pc_q35.c
|
||||
@@ -45,7 +45,6 @@
|
||||
#include "hw/i386/amd_iommu.h"
|
||||
#include "hw/i386/intel_iommu.h"
|
||||
#include "hw/display/ramfb.h"
|
||||
-#include "hw/firmware/smbios.h"
|
||||
#include "hw/ide/pci.h"
|
||||
#include "hw/ide/ahci.h"
|
||||
#include "hw/intc/ioapic.h"
|
||||
@@ -201,16 +200,6 @@ static void pc_q35_init(MachineState *machine)
|
||||
|
||||
pc_guest_info_init(pcms);
|
||||
|
||||
- if (pcmc->smbios_defaults) {
|
||||
- /* These values are guest ABI, do not change */
|
||||
- smbios_set_defaults("Red Hat", "KVM",
|
||||
- mc->desc, pcmc->smbios_legacy_mode,
|
||||
- pcmc->smbios_uuid_encoded,
|
||||
- pcmc->smbios_stream_product,
|
||||
- pcmc->smbios_stream_version,
|
||||
- pcms->smbios_entry_point_type);
|
||||
- }
|
||||
-
|
||||
/* create pci host bus */
|
||||
phb = OBJECT(qdev_new(TYPE_Q35_HOST_DEVICE));
|
||||
|
||||
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
|
||||
index 37644ede7e..c286c10bc3 100644
|
||||
--- a/include/hw/i386/pc.h
|
||||
+++ b/include/hw/i386/pc.h
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "hw/hotplug.h"
|
||||
#include "qom/object.h"
|
||||
#include "hw/i386/sgx-epc.h"
|
||||
-#include "hw/firmware/smbios.h"
|
||||
#include "hw/cxl/cxl.h"
|
||||
|
||||
#define HPET_INTCAP "hpet-intcap"
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,69 +0,0 @@
|
||||
From c2eafeb32a256cbafb0e65c0380acb478181326e Mon Sep 17 00:00:00 2001
|
||||
From: Jon Maloy <jmaloy@redhat.com>
|
||||
Date: Wed, 5 Jun 2024 19:56:51 -0400
|
||||
Subject: [PATCH 2/4] iotests/244: Don't store data-file with protocol in image
|
||||
|
||||
RH-Author: Jon Maloy <jmaloy@redhat.com>
|
||||
RH-MergeRequest: 2: EMBARGOED CVE-2024-4467 for rhel-9.4.z (PRDSC)
|
||||
RH-Jira: https://issues.redhat.com/browse/RHEL-35610
|
||||
RH-CVE: CVE-2024-4467
|
||||
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
|
||||
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
RH-Acked-by: Hanna Czenczek <hczenczek@redhat.com>
|
||||
RH-Commit: [2/4] ddef095945aa55bb0aacc2a2cb58f9e12ad20d5e
|
||||
|
||||
commit 92e00dab8be1570b13172353d77d2af44cb4e22b
|
||||
Author: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Thu Apr 25 14:49:40 2024 +0200
|
||||
|
||||
iotests/244: Don't store data-file with protocol in image
|
||||
|
||||
We want to disable filename parsing for data files because it's too easy
|
||||
to abuse in malicious image files. Make the test ready for the change by
|
||||
passing the data file explicitly in command line options.
|
||||
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Eric Blake <eblake@redhat.com>
|
||||
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
|
||||
Upstream: N/A, embargoed
|
||||
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
|
||||
|
||||
Signed-off-by: Jon Maloy <jmaloy@redhat.com>
|
||||
---
|
||||
tests/qemu-iotests/244 | 19 ++++++++++++++++---
|
||||
1 file changed, 16 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/tests/qemu-iotests/244 b/tests/qemu-iotests/244
|
||||
index 3e61fa25bb..bb9cc6512f 100755
|
||||
--- a/tests/qemu-iotests/244
|
||||
+++ b/tests/qemu-iotests/244
|
||||
@@ -215,9 +215,22 @@ $QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n -C "$TEST_IMG.src" "$TEST_IMG"
|
||||
$QEMU_IMG compare -f $IMGFMT -F $IMGFMT "$TEST_IMG.src" "$TEST_IMG"
|
||||
|
||||
# blkdebug doesn't support copy offloading, so this tests the error path
|
||||
-$QEMU_IMG amend -f $IMGFMT -o "data_file=blkdebug::$TEST_IMG.data" "$TEST_IMG"
|
||||
-$QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n -C "$TEST_IMG.src" "$TEST_IMG"
|
||||
-$QEMU_IMG compare -f $IMGFMT -F $IMGFMT "$TEST_IMG.src" "$TEST_IMG"
|
||||
+test_img_with_blkdebug="json:{
|
||||
+ 'driver': 'qcow2',
|
||||
+ 'file': {
|
||||
+ 'driver': 'file',
|
||||
+ 'filename': '$TEST_IMG'
|
||||
+ },
|
||||
+ 'data-file': {
|
||||
+ 'driver': 'blkdebug',
|
||||
+ 'image': {
|
||||
+ 'driver': 'file',
|
||||
+ 'filename': '$TEST_IMG.data'
|
||||
+ }
|
||||
+ }
|
||||
+}"
|
||||
+$QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n -C "$TEST_IMG.src" "$test_img_with_blkdebug"
|
||||
+$QEMU_IMG compare -f $IMGFMT -F $IMGFMT "$TEST_IMG.src" "$test_img_with_blkdebug"
|
||||
|
||||
echo
|
||||
echo "=== Flushing should flush the data file ==="
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,72 +0,0 @@
|
||||
From 931ab59f39b5e3551b328fe5b0f872df7a19ba05 Mon Sep 17 00:00:00 2001
|
||||
From: Jon Maloy <jmaloy@redhat.com>
|
||||
Date: Wed, 5 Jun 2024 19:56:51 -0400
|
||||
Subject: [PATCH 3/4] iotests/270: Don't store data-file with json: prefix in
|
||||
image
|
||||
|
||||
RH-Author: Jon Maloy <jmaloy@redhat.com>
|
||||
RH-MergeRequest: 2: EMBARGOED CVE-2024-4467 for rhel-9.4.z (PRDSC)
|
||||
RH-Jira: https://issues.redhat.com/browse/RHEL-35610
|
||||
RH-CVE: CVE-2024-4467
|
||||
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
|
||||
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
RH-Acked-by: Hanna Czenczek <hczenczek@redhat.com>
|
||||
RH-Commit: [3/4] 7a9844fd48e3f3c4d1711ea4fb671c795ca4a1c1
|
||||
|
||||
commit 705bcc2819ce8e0f8b9d660a93bc48de26413aec
|
||||
Author: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Thu Apr 25 14:49:40 2024 +0200
|
||||
|
||||
iotests/270: Don't store data-file with json: prefix in image
|
||||
|
||||
We want to disable filename parsing for data files because it's too easy
|
||||
to abuse in malicious image files. Make the test ready for the change by
|
||||
passing the data file explicitly in command line options.
|
||||
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Eric Blake <eblake@redhat.com>
|
||||
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
|
||||
Upstream: N/A, embargoed
|
||||
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
|
||||
|
||||
Signed-off-by: Jon Maloy <jmaloy@redhat.com>
|
||||
---
|
||||
tests/qemu-iotests/270 | 14 +++++++++++---
|
||||
1 file changed, 11 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/tests/qemu-iotests/270 b/tests/qemu-iotests/270
|
||||
index 74352342db..c37b674aa2 100755
|
||||
--- a/tests/qemu-iotests/270
|
||||
+++ b/tests/qemu-iotests/270
|
||||
@@ -60,8 +60,16 @@ _make_test_img -o cluster_size=2M,data_file="$TEST_IMG.orig" \
|
||||
# "write" 2G of data without using any space.
|
||||
# (qemu-img create does not like it, though, because null-co does not
|
||||
# support image creation.)
|
||||
-$QEMU_IMG amend -o data_file="json:{'driver':'null-co',,'size':'4294967296'}" \
|
||||
- "$TEST_IMG"
|
||||
+test_img_with_null_data="json:{
|
||||
+ 'driver': '$IMGFMT',
|
||||
+ 'file': {
|
||||
+ 'filename': '$TEST_IMG'
|
||||
+ },
|
||||
+ 'data-file': {
|
||||
+ 'driver': 'null-co',
|
||||
+ 'size':'4294967296'
|
||||
+ }
|
||||
+}"
|
||||
|
||||
# This gives us a range of:
|
||||
# 2^31 - 512 + 768 - 1 = 2^31 + 255 > 2^31
|
||||
@@ -74,7 +82,7 @@ $QEMU_IMG amend -o data_file="json:{'driver':'null-co',,'size':'4294967296'}" \
|
||||
# on L2 boundaries, we need large L2 tables; hence the cluster size of
|
||||
# 2 MB. (Anything from 256 kB should work, though, because then one L2
|
||||
# table covers 8 GB.)
|
||||
-$QEMU_IO -c "write 768 $((2 ** 31 - 512))" "$TEST_IMG" | _filter_qemu_io
|
||||
+$QEMU_IO -c "write 768 $((2 ** 31 - 512))" "$test_img_with_null_data" | _filter_qemu_io
|
||||
|
||||
_check_test_img
|
||||
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,133 +0,0 @@
|
||||
From 65d58819ff7b012e43b5f1da1356b559d3f5a962 Mon Sep 17 00:00:00 2001
|
||||
From: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Thu, 14 Mar 2024 17:58:25 +0100
|
||||
Subject: [PATCH 3/4] iotests: Add test for reset/AioContext switches with NBD
|
||||
exports
|
||||
|
||||
RH-Author: Kevin Wolf <kwolf@redhat.com>
|
||||
RH-MergeRequest: 231: Fix deadlock and crash during storage migration
|
||||
RH-Jira: RHEL-28125
|
||||
RH-Acked-by: Hanna Czenczek <hreitz@redhat.com>
|
||||
RH-Acked-by: Eric Blake <eblake@redhat.com>
|
||||
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
RH-Commit: [3/3] 7266acdf85271d157497bfe452aa6eeb58fbe7c6 (kmwolf/centos-qemu-kvm)
|
||||
|
||||
This replicates the scenario in which the bug was reported.
|
||||
Unfortunately this relies on actually executing a guest (so that the
|
||||
firmware initialises the virtio-blk device and moves it to its
|
||||
configured iothread), so this can't make use of the qtest accelerator
|
||||
like most other test cases. I tried to find a different easy way to
|
||||
trigger the bug, but couldn't find one.
|
||||
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Message-ID: <20240314165825.40261-3-kwolf@redhat.com>
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
(cherry picked from commit e8fce34eccf68a32f4ecf2c6f121ff2ac383d6bf)
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
---
|
||||
tests/qemu-iotests/tests/iothreads-nbd-export | 66 +++++++++++++++++++
|
||||
.../tests/iothreads-nbd-export.out | 19 ++++++
|
||||
2 files changed, 85 insertions(+)
|
||||
create mode 100755 tests/qemu-iotests/tests/iothreads-nbd-export
|
||||
create mode 100644 tests/qemu-iotests/tests/iothreads-nbd-export.out
|
||||
|
||||
diff --git a/tests/qemu-iotests/tests/iothreads-nbd-export b/tests/qemu-iotests/tests/iothreads-nbd-export
|
||||
new file mode 100755
|
||||
index 0000000000..037260729c
|
||||
--- /dev/null
|
||||
+++ b/tests/qemu-iotests/tests/iothreads-nbd-export
|
||||
@@ -0,0 +1,66 @@
|
||||
+#!/usr/bin/env python3
|
||||
+# group: rw quick
|
||||
+#
|
||||
+# Copyright (C) 2024 Red Hat, Inc.
|
||||
+#
|
||||
+# 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/>.
|
||||
+#
|
||||
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
|
||||
+
|
||||
+import time
|
||||
+import qemu
|
||||
+import iotests
|
||||
+
|
||||
+iotests.script_initialize(supported_fmts=['qcow2'],
|
||||
+ supported_platforms=['linux'])
|
||||
+
|
||||
+with iotests.FilePath('disk1.img') as path, \
|
||||
+ iotests.FilePath('nbd.sock', base_dir=iotests.sock_dir) as nbd_sock, \
|
||||
+ qemu.machine.QEMUMachine(iotests.qemu_prog) as vm:
|
||||
+
|
||||
+ img_size = '10M'
|
||||
+
|
||||
+ iotests.log('Preparing disk...')
|
||||
+ iotests.qemu_img_create('-f', iotests.imgfmt, path, img_size)
|
||||
+ vm.add_args('-blockdev', f'file,node-name=disk-file,filename={path}')
|
||||
+ vm.add_args('-blockdev', 'qcow2,node-name=disk,file=disk-file')
|
||||
+ vm.add_args('-object', 'iothread,id=iothread0')
|
||||
+ vm.add_args('-device',
|
||||
+ 'virtio-blk,drive=disk,iothread=iothread0,share-rw=on')
|
||||
+
|
||||
+ iotests.log('Launching VM...')
|
||||
+ vm.add_args('-accel', 'kvm', '-accel', 'tcg')
|
||||
+ #vm.add_args('-accel', 'qtest')
|
||||
+ vm.launch()
|
||||
+
|
||||
+ iotests.log('Exporting to NBD...')
|
||||
+ iotests.log(vm.qmp('nbd-server-start',
|
||||
+ addr={'type': 'unix', 'data': {'path': nbd_sock}}))
|
||||
+ iotests.log(vm.qmp('block-export-add', type='nbd', id='exp0',
|
||||
+ node_name='disk', writable=True))
|
||||
+
|
||||
+ iotests.log('Connecting qemu-img...')
|
||||
+ qemu_io = iotests.QemuIoInteractive('-f', 'raw',
|
||||
+ f'nbd+unix:///disk?socket={nbd_sock}')
|
||||
+
|
||||
+ iotests.log('Moving the NBD export to a different iothread...')
|
||||
+ for i in range(0, 10):
|
||||
+ iotests.log(vm.qmp('system_reset'))
|
||||
+ time.sleep(0.1)
|
||||
+
|
||||
+ iotests.log('Checking that it is still alive...')
|
||||
+ iotests.log(vm.qmp('query-status'))
|
||||
+
|
||||
+ qemu_io.close()
|
||||
+ vm.shutdown()
|
||||
diff --git a/tests/qemu-iotests/tests/iothreads-nbd-export.out b/tests/qemu-iotests/tests/iothreads-nbd-export.out
|
||||
new file mode 100644
|
||||
index 0000000000..bc514e35e5
|
||||
--- /dev/null
|
||||
+++ b/tests/qemu-iotests/tests/iothreads-nbd-export.out
|
||||
@@ -0,0 +1,19 @@
|
||||
+Preparing disk...
|
||||
+Launching VM...
|
||||
+Exporting to NBD...
|
||||
+{"return": {}}
|
||||
+{"return": {}}
|
||||
+Connecting qemu-img...
|
||||
+Moving the NBD export to a different iothread...
|
||||
+{"return": {}}
|
||||
+{"return": {}}
|
||||
+{"return": {}}
|
||||
+{"return": {}}
|
||||
+{"return": {}}
|
||||
+{"return": {}}
|
||||
+{"return": {}}
|
||||
+{"return": {}}
|
||||
+{"return": {}}
|
||||
+{"return": {}}
|
||||
+Checking that it is still alive...
|
||||
+{"return": {"running": true, "status": "running"}}
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,275 +0,0 @@
|
||||
From 4296c41178438f9dffa16c538b0c1a2e28944f4c Mon Sep 17 00:00:00 2001
|
||||
From: Eric Blake <eblake@redhat.com>
|
||||
Date: Fri, 17 May 2024 21:50:15 -0500
|
||||
Subject: [PATCH 4/4] iotests: test NBD+TLS+iothread
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
RH-Author: Eric Blake <eblake@redhat.com>
|
||||
RH-MergeRequest: 375: Fix regression on nbd+tls
|
||||
RH-Jira: RHEL-33754
|
||||
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [4/4] 5905c09466f4e65f3ff9973b41f42cbe1d75363c (ebblake/qemu-kvm)
|
||||
|
||||
Prevent regressions when using NBD with TLS in the presence of
|
||||
iothreads, adding coverage the fix to qio channels made in the
|
||||
previous patch.
|
||||
|
||||
The shell function pick_unused_port() was copied from
|
||||
nbdkit.git/tests/functions.sh.in, where it had all authors from Red
|
||||
Hat, agreeing to the resulting relicensing from 2-clause BSD to GPLv2.
|
||||
|
||||
CC: qemu-stable@nongnu.org
|
||||
CC: "Richard W.M. Jones" <rjones@redhat.com>
|
||||
Signed-off-by: Eric Blake <eblake@redhat.com>
|
||||
Message-ID: <20240531180639.1392905-6-eblake@redhat.com>
|
||||
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
(cherry picked from commit a73c99378022ebb785481e84cfe1e81097546268)
|
||||
Jira: https://issues.redhat.com/browse/RHEL-33754
|
||||
Signed-off-by: Eric Blake <eblake@redhat.com>
|
||||
---
|
||||
tests/qemu-iotests/tests/nbd-tls-iothread | 168 ++++++++++++++++++
|
||||
tests/qemu-iotests/tests/nbd-tls-iothread.out | 54 ++++++
|
||||
2 files changed, 222 insertions(+)
|
||||
create mode 100755 tests/qemu-iotests/tests/nbd-tls-iothread
|
||||
create mode 100644 tests/qemu-iotests/tests/nbd-tls-iothread.out
|
||||
|
||||
diff --git a/tests/qemu-iotests/tests/nbd-tls-iothread b/tests/qemu-iotests/tests/nbd-tls-iothread
|
||||
new file mode 100755
|
||||
index 0000000000..a2fb07206e
|
||||
--- /dev/null
|
||||
+++ b/tests/qemu-iotests/tests/nbd-tls-iothread
|
||||
@@ -0,0 +1,168 @@
|
||||
+#!/usr/bin/env bash
|
||||
+# group: rw quick
|
||||
+#
|
||||
+# Test of NBD+TLS+iothread
|
||||
+#
|
||||
+# Copyright (C) 2024 Red Hat, Inc.
|
||||
+#
|
||||
+# 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/>.
|
||||
+#
|
||||
+
|
||||
+# creator
|
||||
+owner=eblake@redhat.com
|
||||
+
|
||||
+seq=`basename $0`
|
||||
+echo "QA output created by $seq"
|
||||
+
|
||||
+status=1 # failure is the default!
|
||||
+
|
||||
+_cleanup()
|
||||
+{
|
||||
+ _cleanup_qemu
|
||||
+ _cleanup_test_img
|
||||
+ rm -f "$dst_image"
|
||||
+ tls_x509_cleanup
|
||||
+}
|
||||
+trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
+
|
||||
+# get standard environment, filters and checks
|
||||
+cd ..
|
||||
+. ./common.rc
|
||||
+. ./common.filter
|
||||
+. ./common.qemu
|
||||
+. ./common.tls
|
||||
+. ./common.nbd
|
||||
+
|
||||
+_supported_fmt qcow2 # Hardcoded to qcow2 command line and QMP below
|
||||
+_supported_proto file
|
||||
+
|
||||
+# pick_unused_port
|
||||
+#
|
||||
+# Picks and returns an "unused" port, setting the global variable
|
||||
+# $port.
|
||||
+#
|
||||
+# This is inherently racy, but we need it because qemu does not currently
|
||||
+# permit NBD+TLS over a Unix domain socket
|
||||
+pick_unused_port ()
|
||||
+{
|
||||
+ if ! (ss --version) >/dev/null 2>&1; then
|
||||
+ _notrun "ss utility required, skipped this test"
|
||||
+ fi
|
||||
+
|
||||
+ # Start at a random port to make it less likely that two parallel
|
||||
+ # tests will conflict.
|
||||
+ port=$(( 50000 + (RANDOM%15000) ))
|
||||
+ while ss -ltn | grep -sqE ":$port\b"; do
|
||||
+ ((port++))
|
||||
+ if [ $port -eq 65000 ]; then port=50000; fi
|
||||
+ done
|
||||
+ echo picked unused port
|
||||
+}
|
||||
+
|
||||
+tls_x509_init
|
||||
+
|
||||
+size=1G
|
||||
+DST_IMG="$TEST_DIR/dst.qcow2"
|
||||
+
|
||||
+echo
|
||||
+echo "== preparing TLS creds and spare port =="
|
||||
+
|
||||
+pick_unused_port
|
||||
+tls_x509_create_root_ca "ca1"
|
||||
+tls_x509_create_server "ca1" "server1"
|
||||
+tls_x509_create_client "ca1" "client1"
|
||||
+tls_obj_base=tls-creds-x509,id=tls0,verify-peer=true,dir="${tls_dir}"
|
||||
+
|
||||
+echo
|
||||
+echo "== preparing image =="
|
||||
+
|
||||
+_make_test_img $size
|
||||
+$QEMU_IMG create -f qcow2 "$DST_IMG" $size | _filter_img_create
|
||||
+
|
||||
+echo
|
||||
+echo === Starting Src QEMU ===
|
||||
+echo
|
||||
+
|
||||
+_launch_qemu -machine q35 \
|
||||
+ -object iothread,id=iothread0 \
|
||||
+ -object "${tls_obj_base}"/client1,endpoint=client \
|
||||
+ -device '{"driver":"pcie-root-port", "id":"root0", "multifunction":true,
|
||||
+ "bus":"pcie.0"}' \
|
||||
+ -device '{"driver":"virtio-scsi-pci", "id":"virtio_scsi_pci0",
|
||||
+ "bus":"root0", "iothread":"iothread0"}' \
|
||||
+ -device '{"driver":"scsi-hd", "id":"image1", "drive":"drive_image1",
|
||||
+ "bus":"virtio_scsi_pci0.0"}' \
|
||||
+ -blockdev '{"driver":"file", "cache":{"direct":true, "no-flush":false},
|
||||
+ "filename":"'"$TEST_IMG"'", "node-name":"drive_sys1"}' \
|
||||
+ -blockdev '{"driver":"qcow2", "node-name":"drive_image1",
|
||||
+ "file":"drive_sys1"}'
|
||||
+h1=$QEMU_HANDLE
|
||||
+_send_qemu_cmd $h1 '{"execute": "qmp_capabilities"}' 'return'
|
||||
+
|
||||
+echo
|
||||
+echo === Starting Dst VM2 ===
|
||||
+echo
|
||||
+
|
||||
+_launch_qemu -machine q35 \
|
||||
+ -object iothread,id=iothread0 \
|
||||
+ -object "${tls_obj_base}"/server1,endpoint=server \
|
||||
+ -device '{"driver":"pcie-root-port", "id":"root0", "multifunction":true,
|
||||
+ "bus":"pcie.0"}' \
|
||||
+ -device '{"driver":"virtio-scsi-pci", "id":"virtio_scsi_pci0",
|
||||
+ "bus":"root0", "iothread":"iothread0"}' \
|
||||
+ -device '{"driver":"scsi-hd", "id":"image1", "drive":"drive_image1",
|
||||
+ "bus":"virtio_scsi_pci0.0"}' \
|
||||
+ -blockdev '{"driver":"file", "cache":{"direct":true, "no-flush":false},
|
||||
+ "filename":"'"$DST_IMG"'", "node-name":"drive_sys1"}' \
|
||||
+ -blockdev '{"driver":"qcow2", "node-name":"drive_image1",
|
||||
+ "file":"drive_sys1"}' \
|
||||
+ -incoming defer
|
||||
+h2=$QEMU_HANDLE
|
||||
+_send_qemu_cmd $h2 '{"execute": "qmp_capabilities"}' 'return'
|
||||
+
|
||||
+echo
|
||||
+echo === Dst VM: Enable NBD server for incoming storage migration ===
|
||||
+echo
|
||||
+
|
||||
+_send_qemu_cmd $h2 '{"execute": "nbd-server-start", "arguments":
|
||||
+ {"addr": {"type": "inet", "data": {"host": "127.0.0.1", "port": "'$port'"}},
|
||||
+ "tls-creds": "tls0"}}' '{"return": {}}' | sed "s/\"$port\"/PORT/g"
|
||||
+_send_qemu_cmd $h2 '{"execute": "block-export-add", "arguments":
|
||||
+ {"node-name": "drive_image1", "type": "nbd", "writable": true,
|
||||
+ "id": "drive_image1"}}' '{"return": {}}'
|
||||
+
|
||||
+echo
|
||||
+echo === Src VM: Mirror to dst NBD for outgoing storage migration ===
|
||||
+echo
|
||||
+
|
||||
+_send_qemu_cmd $h1 '{"execute": "blockdev-add", "arguments":
|
||||
+ {"node-name": "mirror", "driver": "nbd",
|
||||
+ "server": {"type": "inet", "host": "127.0.0.1", "port": "'$port'"},
|
||||
+ "export": "drive_image1", "tls-creds": "tls0",
|
||||
+ "tls-hostname": "127.0.0.1"}}' '{"return": {}}' | sed "s/\"$port\"/PORT/g"
|
||||
+_send_qemu_cmd $h1 '{"execute": "blockdev-mirror", "arguments":
|
||||
+ {"sync": "full", "device": "drive_image1", "target": "mirror",
|
||||
+ "job-id": "drive_image1_53"}}' '{"return": {}}'
|
||||
+_timed_wait_for $h1 '"ready"'
|
||||
+
|
||||
+echo
|
||||
+echo === Cleaning up ===
|
||||
+echo
|
||||
+
|
||||
+_send_qemu_cmd $h1 '{"execute":"quit"}' ''
|
||||
+_send_qemu_cmd $h2 '{"execute":"quit"}' ''
|
||||
+
|
||||
+echo "*** done"
|
||||
+rm -f $seq.full
|
||||
+status=0
|
||||
diff --git a/tests/qemu-iotests/tests/nbd-tls-iothread.out b/tests/qemu-iotests/tests/nbd-tls-iothread.out
|
||||
new file mode 100644
|
||||
index 0000000000..1d83d4f903
|
||||
--- /dev/null
|
||||
+++ b/tests/qemu-iotests/tests/nbd-tls-iothread.out
|
||||
@@ -0,0 +1,54 @@
|
||||
+QA output created by nbd-tls-iothread
|
||||
+
|
||||
+== preparing TLS creds and spare port ==
|
||||
+picked unused port
|
||||
+Generating a self signed certificate...
|
||||
+Generating a signed certificate...
|
||||
+Generating a signed certificate...
|
||||
+
|
||||
+== preparing image ==
|
||||
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
+Formatting 'TEST_DIR/dst.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
+
|
||||
+=== Starting Src QEMU ===
|
||||
+
|
||||
+{"execute": "qmp_capabilities"}
|
||||
+{"return": {}}
|
||||
+
|
||||
+=== Starting Dst VM2 ===
|
||||
+
|
||||
+{"execute": "qmp_capabilities"}
|
||||
+{"return": {}}
|
||||
+
|
||||
+=== Dst VM: Enable NBD server for incoming storage migration ===
|
||||
+
|
||||
+{"execute": "nbd-server-start", "arguments":
|
||||
+ {"addr": {"type": "inet", "data": {"host": "127.0.0.1", "port": PORT}},
|
||||
+ "tls-creds": "tls0"}}
|
||||
+{"return": {}}
|
||||
+{"execute": "block-export-add", "arguments":
|
||||
+ {"node-name": "drive_image1", "type": "nbd", "writable": true,
|
||||
+ "id": "drive_image1"}}
|
||||
+{"return": {}}
|
||||
+
|
||||
+=== Src VM: Mirror to dst NBD for outgoing storage migration ===
|
||||
+
|
||||
+{"execute": "blockdev-add", "arguments":
|
||||
+ {"node-name": "mirror", "driver": "nbd",
|
||||
+ "server": {"type": "inet", "host": "127.0.0.1", "port": PORT},
|
||||
+ "export": "drive_image1", "tls-creds": "tls0",
|
||||
+ "tls-hostname": "127.0.0.1"}}
|
||||
+{"return": {}}
|
||||
+{"execute": "blockdev-mirror", "arguments":
|
||||
+ {"sync": "full", "device": "drive_image1", "target": "mirror",
|
||||
+ "job-id": "drive_image1_53"}}
|
||||
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "drive_image1_53"}}
|
||||
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "drive_image1_53"}}
|
||||
+{"return": {}}
|
||||
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "drive_image1_53"}}
|
||||
+
|
||||
+=== Cleaning up ===
|
||||
+
|
||||
+{"execute":"quit"}
|
||||
+{"execute":"quit"}
|
||||
+*** done
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,76 +0,0 @@
|
||||
From 8a8fa4ab4dc05502550ca207926cd0c93a3341ea Mon Sep 17 00:00:00 2001
|
||||
From: Igor Mammedov <imammedo@redhat.com>
|
||||
Date: Mon, 8 Apr 2024 12:43:49 +0200
|
||||
Subject: [PATCH] kvm: error out of kvm_irqchip_add_msi_route() in case of full
|
||||
route table
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 374: kvm: error out of kvm_irqchip_add_msi_route() in case of full route table
|
||||
RH-Jira: RHEL-32990
|
||||
RH-Acked-by: Ani Sinha <anisinha@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [1/1] df31f2d0cafe10a1ac22a2bebb85dc17c1e891e0
|
||||
|
||||
RH-Jira: RHEL-32990
|
||||
|
||||
subj is calling kvm_add_routing_entry() which simply extends
|
||||
KVMState::irq_routes::entries[]
|
||||
but doesn't check if number of routes goes beyond limit the kernel
|
||||
is willing to accept. Which later leads toi the assert
|
||||
|
||||
qemu-kvm: ../accel/kvm/kvm-all.c:1833: kvm_irqchip_commit_routes: Assertion `ret == 0' failed
|
||||
|
||||
typically it happens during guest boot for large enough guest
|
||||
|
||||
Reproduced with:
|
||||
./qemu --enable-kvm -m 8G -smp 64 -machine pc \
|
||||
`for b in {1..2}; do echo -n "-device pci-bridge,id=pci$b,chassis_nr=$b ";
|
||||
for i in {0..31}; do touch /tmp/vblk$b$i;
|
||||
echo -n "-drive file=/tmp/vblk$b$i,if=none,id=drive$b$i,format=raw
|
||||
-device virtio-blk-pci,drive=drive$b$i,bus=pci$b ";
|
||||
done; done`
|
||||
|
||||
While crash at boot time is bad, the same might happen at hotplug time
|
||||
which is unacceptable.
|
||||
So instead calling kvm_add_routing_entry() unconditionally, check first
|
||||
that number of routes won't exceed KVM_CAP_IRQ_ROUTING. This way virtio
|
||||
device insteads killin qemu, will gracefully fail to initialize device
|
||||
as expected with following warnings on console:
|
||||
virtio-blk failed to set guest notifier (-28), ensure -accel kvm is set.
|
||||
virtio_bus_start_ioeventfd: failed. Fallback to userspace (slower).
|
||||
|
||||
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
|
||||
---
|
||||
accel/kvm/kvm-all.c | 15 ++++++++++-----
|
||||
1 file changed, 10 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
|
||||
index e39a810a4e..f1a4564cbd 100644
|
||||
--- a/accel/kvm/kvm-all.c
|
||||
+++ b/accel/kvm/kvm-all.c
|
||||
@@ -2000,12 +2000,17 @@ int kvm_irqchip_add_msi_route(KVMRouteChange *c, int vector, PCIDevice *dev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
- trace_kvm_irqchip_add_msi_route(dev ? dev->name : (char *)"N/A",
|
||||
- vector, virq);
|
||||
+ if (s->irq_routes->nr < s->gsi_count) {
|
||||
+ trace_kvm_irqchip_add_msi_route(dev ? dev->name : (char *)"N/A",
|
||||
+ vector, virq);
|
||||
|
||||
- kvm_add_routing_entry(s, &kroute);
|
||||
- kvm_arch_add_msi_route_post(&kroute, vector, dev);
|
||||
- c->changes++;
|
||||
+ kvm_add_routing_entry(s, &kroute);
|
||||
+ kvm_arch_add_msi_route_post(&kroute, vector, dev);
|
||||
+ c->changes++;
|
||||
+ } else {
|
||||
+ kvm_irqchip_release_virq(s, virq);
|
||||
+ return -ENOSPC;
|
||||
+ }
|
||||
|
||||
return virq;
|
||||
}
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,126 +0,0 @@
|
||||
From 9d00965910d5a7818ffe55b18d3e9dd4c7210e1b Mon Sep 17 00:00:00 2001
|
||||
From: Prasad Pandit <pjp@fedoraproject.org>
|
||||
Date: Thu, 25 Apr 2024 12:34:12 +0530
|
||||
Subject: [PATCH 4/4] linux-aio: add IO_CMD_FDSYNC command support
|
||||
|
||||
RH-Author: Prasad Pandit <None>
|
||||
RH-MergeRequest: 378: linux-aio: add IO_CMD_FDSYNC command support
|
||||
RH-Jira: RHEL-43261
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [1/1] 3b80d4a162aad1a87322078a7d7b060a9496035b
|
||||
|
||||
Libaio defines IO_CMD_FDSYNC command to sync all outstanding
|
||||
asynchronous I/O operations, by flushing out file data to the
|
||||
disk storage. Enable linux-aio to submit such aio request.
|
||||
|
||||
When using aio=native without fdsync() support, QEMU creates
|
||||
pthreads, and destroying these pthreads results in TLB flushes.
|
||||
In a real-time guest environment, TLB flushes cause a latency
|
||||
spike. This patch helps to avoid such spikes.
|
||||
|
||||
Jira: https://issues.redhat.com/browse/RHEL-43261
|
||||
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Signed-off-by: Prasad Pandit <pjp@fedoraproject.org>
|
||||
Message-ID: <20240425070412.37248-1-ppandit@redhat.com>
|
||||
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
(cherry picked from commit 24687abf237e3c15816d689a8e4b08d7c3190dcb)
|
||||
Signed-off-by: Prasad Pandit <pjp@fedoraproject.org>
|
||||
---
|
||||
block/file-posix.c | 9 +++++++++
|
||||
block/linux-aio.c | 21 ++++++++++++++++++++-
|
||||
include/block/raw-aio.h | 1 +
|
||||
3 files changed, 30 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/block/file-posix.c b/block/file-posix.c
|
||||
index 35684f7e21..9831b08fb6 100644
|
||||
--- a/block/file-posix.c
|
||||
+++ b/block/file-posix.c
|
||||
@@ -159,6 +159,7 @@ typedef struct BDRVRawState {
|
||||
bool has_discard:1;
|
||||
bool has_write_zeroes:1;
|
||||
bool use_linux_aio:1;
|
||||
+ bool has_laio_fdsync:1;
|
||||
bool use_linux_io_uring:1;
|
||||
int page_cache_inconsistent; /* errno from fdatasync failure */
|
||||
bool has_fallocate;
|
||||
@@ -718,6 +719,9 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
+ if (s->use_linux_aio) {
|
||||
+ s->has_laio_fdsync = laio_has_fdsync(s->fd);
|
||||
+ }
|
||||
#else
|
||||
if (s->use_linux_aio) {
|
||||
error_setg(errp, "aio=native was specified, but is not supported "
|
||||
@@ -2599,6 +2603,11 @@ static int coroutine_fn raw_co_flush_to_disk(BlockDriverState *bs)
|
||||
if (raw_check_linux_io_uring(s)) {
|
||||
return luring_co_submit(bs, s->fd, 0, NULL, QEMU_AIO_FLUSH);
|
||||
}
|
||||
+#endif
|
||||
+#ifdef CONFIG_LINUX_AIO
|
||||
+ if (s->has_laio_fdsync && raw_check_linux_aio(s)) {
|
||||
+ return laio_co_submit(s->fd, 0, NULL, QEMU_AIO_FLUSH, 0);
|
||||
+ }
|
||||
#endif
|
||||
return raw_thread_pool_submit(handle_aiocb_flush, &acb);
|
||||
}
|
||||
diff --git a/block/linux-aio.c b/block/linux-aio.c
|
||||
index ec05d946f3..e3b5ec9aba 100644
|
||||
--- a/block/linux-aio.c
|
||||
+++ b/block/linux-aio.c
|
||||
@@ -384,6 +384,9 @@ static int laio_do_submit(int fd, struct qemu_laiocb *laiocb, off_t offset,
|
||||
case QEMU_AIO_READ:
|
||||
io_prep_preadv(iocbs, fd, qiov->iov, qiov->niov, offset);
|
||||
break;
|
||||
+ case QEMU_AIO_FLUSH:
|
||||
+ io_prep_fdsync(iocbs, fd);
|
||||
+ break;
|
||||
/* Currently Linux kernel does not support other operations */
|
||||
default:
|
||||
fprintf(stderr, "%s: invalid AIO request type 0x%x.\n",
|
||||
@@ -412,7 +415,7 @@ int coroutine_fn laio_co_submit(int fd, uint64_t offset, QEMUIOVector *qiov,
|
||||
AioContext *ctx = qemu_get_current_aio_context();
|
||||
struct qemu_laiocb laiocb = {
|
||||
.co = qemu_coroutine_self(),
|
||||
- .nbytes = qiov->size,
|
||||
+ .nbytes = qiov ? qiov->size : 0,
|
||||
.ctx = aio_get_linux_aio(ctx),
|
||||
.ret = -EINPROGRESS,
|
||||
.is_read = (type == QEMU_AIO_READ),
|
||||
@@ -486,3 +489,19 @@ void laio_cleanup(LinuxAioState *s)
|
||||
}
|
||||
g_free(s);
|
||||
}
|
||||
+
|
||||
+bool laio_has_fdsync(int fd)
|
||||
+{
|
||||
+ struct iocb cb;
|
||||
+ struct iocb *cbs[] = {&cb, NULL};
|
||||
+
|
||||
+ io_context_t ctx = 0;
|
||||
+ io_setup(1, &ctx);
|
||||
+
|
||||
+ /* check if host kernel supports IO_CMD_FDSYNC */
|
||||
+ io_prep_fdsync(&cb, fd);
|
||||
+ int ret = io_submit(ctx, 1, cbs);
|
||||
+
|
||||
+ io_destroy(ctx);
|
||||
+ return (ret == -EINVAL) ? false : true;
|
||||
+}
|
||||
diff --git a/include/block/raw-aio.h b/include/block/raw-aio.h
|
||||
index 0f63c2800c..3166903a56 100644
|
||||
--- a/include/block/raw-aio.h
|
||||
+++ b/include/block/raw-aio.h
|
||||
@@ -60,6 +60,7 @@ void laio_cleanup(LinuxAioState *s);
|
||||
int coroutine_fn laio_co_submit(int fd, uint64_t offset, QEMUIOVector *qiov,
|
||||
int type, uint64_t dev_max_batch);
|
||||
|
||||
+bool laio_has_fdsync(int);
|
||||
void laio_detach_aio_context(LinuxAioState *s, AioContext *old_context);
|
||||
void laio_attach_aio_context(LinuxAioState *s, AioContext *new_context);
|
||||
#endif
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,90 +0,0 @@
|
||||
From 21cadc8ed200ad9af13b217b441b9f12cd2163ee Mon Sep 17 00:00:00 2001
|
||||
From: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Wed, 13 Mar 2024 16:30:00 +0100
|
||||
Subject: [PATCH 1/4] mirror: Don't call job_pause_point() under graph lock
|
||||
|
||||
RH-Author: Kevin Wolf <kwolf@redhat.com>
|
||||
RH-MergeRequest: 231: Fix deadlock and crash during storage migration
|
||||
RH-Jira: RHEL-28125
|
||||
RH-Acked-by: Hanna Czenczek <hreitz@redhat.com>
|
||||
RH-Acked-by: Eric Blake <eblake@redhat.com>
|
||||
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
RH-Commit: [1/3] 093910fcd5ea1516d0ed48a9cd73dad6170590f3 (kmwolf/centos-qemu-kvm)
|
||||
|
||||
Calling job_pause_point() while holding the graph reader lock
|
||||
potentially results in a deadlock: bdrv_graph_wrlock() first drains
|
||||
everything, including the mirror job, which pauses it. The job is only
|
||||
unpaused at the end of the drain section, which is when the graph writer
|
||||
lock has been successfully taken. However, if the job happens to be
|
||||
paused at a pause point where it still holds the reader lock, the writer
|
||||
lock can't be taken as long as the job is still paused.
|
||||
|
||||
Mark job_pause_point() as GRAPH_UNLOCKED and fix mirror accordingly.
|
||||
|
||||
Cc: qemu-stable@nongnu.org
|
||||
Buglink: https://issues.redhat.com/browse/RHEL-28125
|
||||
Fixes: 004915a96a7a ("block: Protect bs->backing with graph_lock")
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Message-ID: <20240313153000.33121-1-kwolf@redhat.com>
|
||||
Reviewed-by: Eric Blake <eblake@redhat.com>
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
(cherry picked from commit ae5a40e8581185654a667fbbf7e4adbc2a2a3e45)
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
---
|
||||
block/mirror.c | 10 ++++++----
|
||||
include/qemu/job.h | 2 +-
|
||||
2 files changed, 7 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/block/mirror.c b/block/mirror.c
|
||||
index 5145eb53e1..1bdce3b657 100644
|
||||
--- a/block/mirror.c
|
||||
+++ b/block/mirror.c
|
||||
@@ -479,9 +479,9 @@ static unsigned mirror_perform(MirrorBlockJob *s, int64_t offset,
|
||||
return bytes_handled;
|
||||
}
|
||||
|
||||
-static void coroutine_fn GRAPH_RDLOCK mirror_iteration(MirrorBlockJob *s)
|
||||
+static void coroutine_fn GRAPH_UNLOCKED mirror_iteration(MirrorBlockJob *s)
|
||||
{
|
||||
- BlockDriverState *source = s->mirror_top_bs->backing->bs;
|
||||
+ BlockDriverState *source;
|
||||
MirrorOp *pseudo_op;
|
||||
int64_t offset;
|
||||
/* At least the first dirty chunk is mirrored in one iteration. */
|
||||
@@ -489,6 +489,10 @@ static void coroutine_fn GRAPH_RDLOCK mirror_iteration(MirrorBlockJob *s)
|
||||
bool write_zeroes_ok = bdrv_can_write_zeroes_with_unmap(blk_bs(s->target));
|
||||
int max_io_bytes = MAX(s->buf_size / MAX_IN_FLIGHT, MAX_IO_BYTES);
|
||||
|
||||
+ bdrv_graph_co_rdlock();
|
||||
+ source = s->mirror_top_bs->backing->bs;
|
||||
+ bdrv_graph_co_rdunlock();
|
||||
+
|
||||
bdrv_dirty_bitmap_lock(s->dirty_bitmap);
|
||||
offset = bdrv_dirty_iter_next(s->dbi);
|
||||
if (offset < 0) {
|
||||
@@ -1066,9 +1070,7 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
|
||||
mirror_wait_for_free_in_flight_slot(s);
|
||||
continue;
|
||||
} else if (cnt != 0) {
|
||||
- bdrv_graph_co_rdlock();
|
||||
mirror_iteration(s);
|
||||
- bdrv_graph_co_rdunlock();
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/include/qemu/job.h b/include/qemu/job.h
|
||||
index 9ea98b5927..2b873f2576 100644
|
||||
--- a/include/qemu/job.h
|
||||
+++ b/include/qemu/job.h
|
||||
@@ -483,7 +483,7 @@ void job_enter(Job *job);
|
||||
*
|
||||
* Called with job_mutex *not* held.
|
||||
*/
|
||||
-void coroutine_fn job_pause_point(Job *job);
|
||||
+void coroutine_fn GRAPH_UNLOCKED job_pause_point(Job *job);
|
||||
|
||||
/**
|
||||
* @job: The job that calls the function.
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,184 +0,0 @@
|
||||
From 3311ddaffa78ad8d2c40c86cd69461ebeabe1052 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Blake <eblake@redhat.com>
|
||||
Date: Tue, 6 Aug 2024 13:53:00 -0500
|
||||
Subject: [PATCH 3/5] nbd/server: CVE-2024-7409: Cap default max-connections to
|
||||
100
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
RH-Author: Eric Blake <eblake@redhat.com>
|
||||
RH-MergeRequest: 386: nbd/server: fix CVE-2024-7409 (qemu crash on nbd-server-stop) [rhel-9.4.z]
|
||||
RH-Jira: RHEL-52616
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [2/4] 17c9c81282e180485e2f2d584a3e0c73a6fbd66a (ebblake/qemu-kvm)
|
||||
|
||||
Allowing an unlimited number of clients to any web service is a recipe
|
||||
for a rudimentary denial of service attack: the client merely needs to
|
||||
open lots of sockets without closing them, until qemu no longer has
|
||||
any more fds available to allocate.
|
||||
|
||||
For qemu-nbd, we default to allowing only 1 connection unless more are
|
||||
explicitly asked for (-e or --shared); this was historically picked as
|
||||
a nice default (without an explicit -t, a non-persistent qemu-nbd goes
|
||||
away after a client disconnects, without needing any additional
|
||||
follow-up commands), and we are not going to change that interface now
|
||||
(besides, someday we want to point people towards qemu-storage-daemon
|
||||
instead of qemu-nbd).
|
||||
|
||||
But for qemu proper, and the newer qemu-storage-daemon, the QMP
|
||||
nbd-server-start command has historically had a default of unlimited
|
||||
number of connections, in part because unlike qemu-nbd it is
|
||||
inherently persistent until nbd-server-stop. Allowing multiple client
|
||||
sockets is particularly useful for clients that can take advantage of
|
||||
MULTI_CONN (creating parallel sockets to increase throughput),
|
||||
although known clients that do so (such as libnbd's nbdcopy) typically
|
||||
use only 8 or 16 connections (the benefits of scaling diminish once
|
||||
more sockets are competing for kernel attention). Picking a number
|
||||
large enough for typical use cases, but not unlimited, makes it
|
||||
slightly harder for a malicious client to perform a denial of service
|
||||
merely by opening lots of connections withot progressing through the
|
||||
handshake.
|
||||
|
||||
This change does not eliminate CVE-2024-7409 on its own, but reduces
|
||||
the chance for fd exhaustion or unlimited memory usage as an attack
|
||||
surface. On the other hand, by itself, it makes it more obvious that
|
||||
with a finite limit, we have the problem of an unauthenticated client
|
||||
holding 100 fds opened as a way to block out a legitimate client from
|
||||
being able to connect; thus, later patches will further add timeouts
|
||||
to reject clients that are not making progress.
|
||||
|
||||
This is an INTENTIONAL change in behavior, and will break any client
|
||||
of nbd-server-start that was not passing an explicit max-connections
|
||||
parameter, yet expects more than 100 simultaneous connections. We are
|
||||
not aware of any such client (as stated above, most clients aware of
|
||||
MULTI_CONN get by just fine on 8 or 16 connections, and probably cope
|
||||
with later connections failing by relying on the earlier connections;
|
||||
libvirt has not yet been passing max-connections, but generally
|
||||
creates NBD servers with the intent for a single client for the sake
|
||||
of live storage migration; meanwhile, the KubeSAN project anticipates
|
||||
a large cluster sharing multiple clients [up to 8 per node, and up to
|
||||
100 nodes in a cluster], but it currently uses qemu-nbd with an
|
||||
explicit --shared=0 rather than qemu-storage-daemon with
|
||||
nbd-server-start).
|
||||
|
||||
We considered using a deprecation period (declare that omitting
|
||||
max-parameters is deprecated, and make it mandatory in 3 releases -
|
||||
then we don't need to pick an arbitrary default); that has zero risk
|
||||
of breaking any apps that accidentally depended on more than 100
|
||||
connections, and where such breakage might not be noticed under unit
|
||||
testing but only under the larger loads of production usage. But it
|
||||
does not close the denial-of-service hole until far into the future,
|
||||
and requires all apps to change to add the parameter even if 100 was
|
||||
good enough. It also has a drawback that any app (like libvirt) that
|
||||
is accidentally relying on an unlimited default should seriously
|
||||
consider their own CVE now, at which point they are going to change to
|
||||
pass explicit max-connections sooner than waiting for 3 qemu releases.
|
||||
Finally, if our changed default breaks an app, that app can always
|
||||
pass in an explicit max-parameters with a larger value.
|
||||
|
||||
It is also intentional that the HMP interface to nbd-server-start is
|
||||
not changed to expose max-connections (any client needing to fine-tune
|
||||
things should be using QMP).
|
||||
|
||||
Suggested-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
Signed-off-by: Eric Blake <eblake@redhat.com>
|
||||
Message-ID: <20240807174943.771624-12-eblake@redhat.com>
|
||||
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
[ericb: Expand commit message to summarize Dan's argument for why we
|
||||
break corner-case back-compat behavior without a deprecation period]
|
||||
Signed-off-by: Eric Blake <eblake@redhat.com>
|
||||
|
||||
(cherry picked from commit c8a76dbd90c2f48df89b75bef74917f90a59b623)
|
||||
Jira: https://issues.redhat.com/browse/RHEL-52616
|
||||
Signed-off-by: Eric Blake <eblake@redhat.com>
|
||||
---
|
||||
block/monitor/block-hmp-cmds.c | 3 ++-
|
||||
blockdev-nbd.c | 8 ++++++++
|
||||
include/block/nbd.h | 7 +++++++
|
||||
qapi/block-export.json | 4 ++--
|
||||
4 files changed, 19 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c
|
||||
index bdbb5cb141..2d7b4d80c8 100644
|
||||
--- a/block/monitor/block-hmp-cmds.c
|
||||
+++ b/block/monitor/block-hmp-cmds.c
|
||||
@@ -402,7 +402,8 @@ void hmp_nbd_server_start(Monitor *mon, const QDict *qdict)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
- nbd_server_start(addr, NULL, NULL, 0, &local_err);
|
||||
+ nbd_server_start(addr, NULL, NULL, NBD_DEFAULT_MAX_CONNECTIONS,
|
||||
+ &local_err);
|
||||
qapi_free_SocketAddress(addr);
|
||||
if (local_err != NULL) {
|
||||
goto exit;
|
||||
diff --git a/blockdev-nbd.c b/blockdev-nbd.c
|
||||
index 267a1de903..24ba5382db 100644
|
||||
--- a/blockdev-nbd.c
|
||||
+++ b/blockdev-nbd.c
|
||||
@@ -170,6 +170,10 @@ void nbd_server_start(SocketAddress *addr, const char *tls_creds,
|
||||
|
||||
void nbd_server_start_options(NbdServerOptions *arg, Error **errp)
|
||||
{
|
||||
+ if (!arg->has_max_connections) {
|
||||
+ arg->max_connections = NBD_DEFAULT_MAX_CONNECTIONS;
|
||||
+ }
|
||||
+
|
||||
nbd_server_start(arg->addr, arg->tls_creds, arg->tls_authz,
|
||||
arg->max_connections, errp);
|
||||
}
|
||||
@@ -182,6 +186,10 @@ void qmp_nbd_server_start(SocketAddressLegacy *addr,
|
||||
{
|
||||
SocketAddress *addr_flat = socket_address_flatten(addr);
|
||||
|
||||
+ if (!has_max_connections) {
|
||||
+ max_connections = NBD_DEFAULT_MAX_CONNECTIONS;
|
||||
+ }
|
||||
+
|
||||
nbd_server_start(addr_flat, tls_creds, tls_authz, max_connections, errp);
|
||||
qapi_free_SocketAddress(addr_flat);
|
||||
}
|
||||
diff --git a/include/block/nbd.h b/include/block/nbd.h
|
||||
index 1d4d65922d..d4f8b21aec 100644
|
||||
--- a/include/block/nbd.h
|
||||
+++ b/include/block/nbd.h
|
||||
@@ -39,6 +39,13 @@ extern const BlockExportDriver blk_exp_nbd;
|
||||
*/
|
||||
#define NBD_DEFAULT_HANDSHAKE_MAX_SECS 10
|
||||
|
||||
+/*
|
||||
+ * NBD_DEFAULT_MAX_CONNECTIONS: Number of client sockets to allow at
|
||||
+ * once; must be large enough to allow a MULTI_CONN-aware client like
|
||||
+ * nbdcopy to create its typical number of 8-16 sockets.
|
||||
+ */
|
||||
+#define NBD_DEFAULT_MAX_CONNECTIONS 100
|
||||
+
|
||||
/* Handshake phase structs - this struct is passed on the wire */
|
||||
|
||||
typedef struct NBDOption {
|
||||
diff --git a/qapi/block-export.json b/qapi/block-export.json
|
||||
index 7874a49ba7..1d255d77e3 100644
|
||||
--- a/qapi/block-export.json
|
||||
+++ b/qapi/block-export.json
|
||||
@@ -28,7 +28,7 @@
|
||||
# @max-connections: The maximum number of connections to allow at the
|
||||
# same time, 0 for unlimited. Setting this to 1 also stops the
|
||||
# server from advertising multiple client support (since 5.2;
|
||||
-# default: 0)
|
||||
+# default: 100)
|
||||
#
|
||||
# Since: 4.2
|
||||
##
|
||||
@@ -63,7 +63,7 @@
|
||||
# @max-connections: The maximum number of connections to allow at the
|
||||
# same time, 0 for unlimited. Setting this to 1 also stops the
|
||||
# server from advertising multiple client support (since 5.2;
|
||||
-# default: 0).
|
||||
+# default: 100).
|
||||
#
|
||||
# Returns: error if the server is already running.
|
||||
#
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,173 +0,0 @@
|
||||
From 1c2fe81349a99cf0c28549426c7ad0c06d942ae3 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Blake <eblake@redhat.com>
|
||||
Date: Wed, 7 Aug 2024 12:23:13 -0500
|
||||
Subject: [PATCH 5/5] nbd/server: CVE-2024-7409: Close stray clients at
|
||||
server-stop
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
RH-Author: Eric Blake <eblake@redhat.com>
|
||||
RH-MergeRequest: 386: nbd/server: fix CVE-2024-7409 (qemu crash on nbd-server-stop) [rhel-9.4.z]
|
||||
RH-Jira: RHEL-52616
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [4/4] 54d56c0d92d92b2b6a0f81a01853881286beae0e (ebblake/qemu-kvm)
|
||||
|
||||
A malicious client can attempt to connect to an NBD server, and then
|
||||
intentionally delay progress in the handshake, including if it does
|
||||
not know the TLS secrets. Although the previous two patches reduce
|
||||
this behavior by capping the default max-connections parameter and
|
||||
killing slow clients, they did not eliminate the possibility of a
|
||||
client waiting to close the socket until after the QMP nbd-server-stop
|
||||
command is executed, at which point qemu would SEGV when trying to
|
||||
dereference the NULL nbd_server global which is no longer present.
|
||||
This amounts to a denial of service attack. Worse, if another NBD
|
||||
server is started before the malicious client disconnects, I cannot
|
||||
rule out additional adverse effects when the old client interferes
|
||||
with the connection count of the new server (although the most likely
|
||||
is a crash due to an assertion failure when checking
|
||||
nbd_server->connections > 0).
|
||||
|
||||
For environments without this patch, the CVE can be mitigated by
|
||||
ensuring (such as via a firewall) that only trusted clients can
|
||||
connect to an NBD server. Note that using frameworks like libvirt
|
||||
that ensure that TLS is used and that nbd-server-stop is not executed
|
||||
while any trusted clients are still connected will only help if there
|
||||
is also no possibility for an untrusted client to open a connection
|
||||
but then stall on the NBD handshake.
|
||||
|
||||
Given the previous patches, it would be possible to guarantee that no
|
||||
clients remain connected by having nbd-server-stop sleep for longer
|
||||
than the default handshake deadline before finally freeing the global
|
||||
nbd_server object, but that could make QMP non-responsive for a long
|
||||
time. So intead, this patch fixes the problem by tracking all client
|
||||
sockets opened while the server is running, and forcefully closing any
|
||||
such sockets remaining without a completed handshake at the time of
|
||||
nbd-server-stop, then waiting until the coroutines servicing those
|
||||
sockets notice the state change. nbd-server-stop now has a second
|
||||
AIO_WAIT_WHILE_UNLOCKED (the first is indirectly through the
|
||||
blk_exp_close_all_type() that disconnects all clients that completed
|
||||
handshakes), but forced socket shutdown is enough to progress the
|
||||
coroutines and quickly tear down all clients before the server is
|
||||
freed, thus finally fixing the CVE.
|
||||
|
||||
This patch relies heavily on the fact that nbd/server.c guarantees
|
||||
that it only calls nbd_blockdev_client_closed() from the main loop
|
||||
(see the assertion in nbd_client_put() and the hoops used in
|
||||
nbd_client_put_nonzero() to achieve that); if we did not have that
|
||||
guarantee, we would also need a mutex protecting our accesses of the
|
||||
list of connections to survive re-entrancy from independent iothreads.
|
||||
|
||||
Although I did not actually try to test old builds, it looks like this
|
||||
problem has existed since at least commit 862172f45c (v2.12.0, 2017) -
|
||||
even back when that patch started using a QIONetListener to handle
|
||||
listening on multiple sockets, nbd_server_free() was already unaware
|
||||
that the nbd_blockdev_client_closed callback can be reached later by a
|
||||
client thread that has not completed handshakes (and therefore the
|
||||
client's socket never got added to the list closed in
|
||||
nbd_export_close_all), despite that patch intentionally tearing down
|
||||
the QIONetListener to prevent new clients.
|
||||
|
||||
Reported-by: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
|
||||
Fixes: CVE-2024-7409
|
||||
CC: qemu-stable@nongnu.org
|
||||
Signed-off-by: Eric Blake <eblake@redhat.com>
|
||||
Message-ID: <20240807174943.771624-14-eblake@redhat.com>
|
||||
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
|
||||
(cherry picked from commit 3e7ef738c8462c45043a1d39f702a0990406a3b3)
|
||||
Jira: https://issues.redhat.com/browse/RHEL-52616
|
||||
Signed-off-by: Eric Blake <eblake@redhat.com>
|
||||
---
|
||||
blockdev-nbd.c | 35 ++++++++++++++++++++++++++++++++++-
|
||||
1 file changed, 34 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/blockdev-nbd.c b/blockdev-nbd.c
|
||||
index 24ba5382db..f73409ae49 100644
|
||||
--- a/blockdev-nbd.c
|
||||
+++ b/blockdev-nbd.c
|
||||
@@ -21,12 +21,18 @@
|
||||
#include "io/channel-socket.h"
|
||||
#include "io/net-listener.h"
|
||||
|
||||
+typedef struct NBDConn {
|
||||
+ QIOChannelSocket *cioc;
|
||||
+ QLIST_ENTRY(NBDConn) next;
|
||||
+} NBDConn;
|
||||
+
|
||||
typedef struct NBDServerData {
|
||||
QIONetListener *listener;
|
||||
QCryptoTLSCreds *tlscreds;
|
||||
char *tlsauthz;
|
||||
uint32_t max_connections;
|
||||
uint32_t connections;
|
||||
+ QLIST_HEAD(, NBDConn) conns;
|
||||
} NBDServerData;
|
||||
|
||||
static NBDServerData *nbd_server;
|
||||
@@ -51,6 +57,14 @@ int nbd_server_max_connections(void)
|
||||
|
||||
static void nbd_blockdev_client_closed(NBDClient *client, bool ignored)
|
||||
{
|
||||
+ NBDConn *conn = nbd_client_owner(client);
|
||||
+
|
||||
+ assert(qemu_in_main_thread() && nbd_server);
|
||||
+
|
||||
+ object_unref(OBJECT(conn->cioc));
|
||||
+ QLIST_REMOVE(conn, next);
|
||||
+ g_free(conn);
|
||||
+
|
||||
nbd_client_put(client);
|
||||
assert(nbd_server->connections > 0);
|
||||
nbd_server->connections--;
|
||||
@@ -60,14 +74,20 @@ static void nbd_blockdev_client_closed(NBDClient *client, bool ignored)
|
||||
static void nbd_accept(QIONetListener *listener, QIOChannelSocket *cioc,
|
||||
gpointer opaque)
|
||||
{
|
||||
+ NBDConn *conn = g_new0(NBDConn, 1);
|
||||
+
|
||||
+ assert(qemu_in_main_thread() && nbd_server);
|
||||
nbd_server->connections++;
|
||||
+ object_ref(OBJECT(cioc));
|
||||
+ conn->cioc = cioc;
|
||||
+ QLIST_INSERT_HEAD(&nbd_server->conns, conn, next);
|
||||
nbd_update_server_watch(nbd_server);
|
||||
|
||||
qio_channel_set_name(QIO_CHANNEL(cioc), "nbd-server");
|
||||
/* TODO - expose handshake timeout as QMP option */
|
||||
nbd_client_new(cioc, NBD_DEFAULT_HANDSHAKE_MAX_SECS,
|
||||
nbd_server->tlscreds, nbd_server->tlsauthz,
|
||||
- nbd_blockdev_client_closed, NULL);
|
||||
+ nbd_blockdev_client_closed, conn);
|
||||
}
|
||||
|
||||
static void nbd_update_server_watch(NBDServerData *s)
|
||||
@@ -81,12 +101,25 @@ static void nbd_update_server_watch(NBDServerData *s)
|
||||
|
||||
static void nbd_server_free(NBDServerData *server)
|
||||
{
|
||||
+ NBDConn *conn, *tmp;
|
||||
+
|
||||
if (!server) {
|
||||
return;
|
||||
}
|
||||
|
||||
+ /*
|
||||
+ * Forcefully close the listener socket, and any clients that have
|
||||
+ * not yet disconnected on their own.
|
||||
+ */
|
||||
qio_net_listener_disconnect(server->listener);
|
||||
object_unref(OBJECT(server->listener));
|
||||
+ QLIST_FOREACH_SAFE(conn, &server->conns, next, tmp) {
|
||||
+ qio_channel_shutdown(QIO_CHANNEL(conn->cioc), QIO_CHANNEL_SHUTDOWN_BOTH,
|
||||
+ NULL);
|
||||
+ }
|
||||
+
|
||||
+ AIO_WAIT_WHILE_UNLOCKED(NULL, server->connections > 0);
|
||||
+
|
||||
if (server->tlscreds) {
|
||||
object_unref(OBJECT(server->tlscreds));
|
||||
}
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,134 +0,0 @@
|
||||
From 71c525e45f3f2a421ad651bc50eff94be925b36c Mon Sep 17 00:00:00 2001
|
||||
From: Eric Blake <eblake@redhat.com>
|
||||
Date: Thu, 8 Aug 2024 16:05:08 -0500
|
||||
Subject: [PATCH 4/5] nbd/server: CVE-2024-7409: Drop non-negotiating clients
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
RH-Author: Eric Blake <eblake@redhat.com>
|
||||
RH-MergeRequest: 386: nbd/server: fix CVE-2024-7409 (qemu crash on nbd-server-stop) [rhel-9.4.z]
|
||||
RH-Jira: RHEL-52616
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [3/4] 4394e60a8733cd57ee6c8cb140171c7f61cc13a3 (ebblake/qemu-kvm)
|
||||
|
||||
A client that opens a socket but does not negotiate is merely hogging
|
||||
qemu's resources (an open fd and a small amount of memory); and a
|
||||
malicious client that can access the port where NBD is listening can
|
||||
attempt a denial of service attack by intentionally opening and
|
||||
abandoning lots of unfinished connections. The previous patch put a
|
||||
default bound on the number of such ongoing connections, but once that
|
||||
limit is hit, no more clients can connect (including legitimate ones).
|
||||
The solution is to insist that clients complete handshake within a
|
||||
reasonable time limit, defaulting to 10 seconds. A client that has
|
||||
not successfully completed NBD_OPT_GO by then (including the case of
|
||||
where the client didn't know TLS credentials to even reach the point
|
||||
of NBD_OPT_GO) is wasting our time and does not deserve to stay
|
||||
connected. Later patches will allow fine-tuning the limit away from
|
||||
the default value (including disabling it for doing integration
|
||||
testing of the handshake process itself).
|
||||
|
||||
Note that this patch in isolation actually makes it more likely to see
|
||||
qemu SEGV after nbd-server-stop, as any client socket still connected
|
||||
when the server shuts down will now be closed after 10 seconds rather
|
||||
than at the client's whims. That will be addressed in the next patch.
|
||||
|
||||
For a demo of this patch in action:
|
||||
$ qemu-nbd -f raw -r -t -e 10 file &
|
||||
$ nbdsh --opt-mode -c '
|
||||
H = list()
|
||||
for i in range(20):
|
||||
print(i)
|
||||
H.insert(i, nbd.NBD())
|
||||
H[i].set_opt_mode(True)
|
||||
H[i].connect_uri("nbd://localhost")
|
||||
'
|
||||
$ kill $!
|
||||
|
||||
where later connections get to start progressing once earlier ones are
|
||||
forcefully dropped for taking too long, rather than hanging.
|
||||
|
||||
Suggested-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
Signed-off-by: Eric Blake <eblake@redhat.com>
|
||||
Message-ID: <20240807174943.771624-13-eblake@redhat.com>
|
||||
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
[eblake: rebase to changes earlier in series, reduce scope of timer]
|
||||
Signed-off-by: Eric Blake <eblake@redhat.com>
|
||||
|
||||
(cherry picked from commit b9b72cb3ce15b693148bd09cef7e50110566d8a0)
|
||||
Jira: https://issues.redhat.com/browse/RHEL-52616
|
||||
Signed-off-by: Eric Blake <eblake@redhat.com>
|
||||
---
|
||||
nbd/server.c | 28 +++++++++++++++++++++++++++-
|
||||
nbd/trace-events | 1 +
|
||||
2 files changed, 28 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/nbd/server.c b/nbd/server.c
|
||||
index e50012499f..39285cc971 100644
|
||||
--- a/nbd/server.c
|
||||
+++ b/nbd/server.c
|
||||
@@ -3186,22 +3186,48 @@ static void nbd_client_receive_next_request(NBDClient *client)
|
||||
}
|
||||
}
|
||||
|
||||
+static void nbd_handshake_timer_cb(void *opaque)
|
||||
+{
|
||||
+ QIOChannel *ioc = opaque;
|
||||
+
|
||||
+ trace_nbd_handshake_timer_cb();
|
||||
+ qio_channel_shutdown(ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL);
|
||||
+}
|
||||
+
|
||||
static coroutine_fn void nbd_co_client_start(void *opaque)
|
||||
{
|
||||
NBDClient *client = opaque;
|
||||
Error *local_err = NULL;
|
||||
+ QEMUTimer *handshake_timer = NULL;
|
||||
|
||||
qemu_co_mutex_init(&client->send_lock);
|
||||
|
||||
- /* TODO - utilize client->handshake_max_secs */
|
||||
+ /*
|
||||
+ * Create a timer to bound the time spent in negotiation. If the
|
||||
+ * timer expires, it is likely nbd_negotiate will fail because the
|
||||
+ * socket was shutdown.
|
||||
+ */
|
||||
+ if (client->handshake_max_secs > 0) {
|
||||
+ handshake_timer = aio_timer_new(qemu_get_aio_context(),
|
||||
+ QEMU_CLOCK_REALTIME,
|
||||
+ SCALE_NS,
|
||||
+ nbd_handshake_timer_cb,
|
||||
+ client->sioc);
|
||||
+ timer_mod(handshake_timer,
|
||||
+ qemu_clock_get_ns(QEMU_CLOCK_REALTIME) +
|
||||
+ client->handshake_max_secs * NANOSECONDS_PER_SECOND);
|
||||
+ }
|
||||
+
|
||||
if (nbd_negotiate(client, &local_err)) {
|
||||
if (local_err) {
|
||||
error_report_err(local_err);
|
||||
}
|
||||
+ timer_free(handshake_timer);
|
||||
client_close(client, false);
|
||||
return;
|
||||
}
|
||||
|
||||
+ timer_free(handshake_timer);
|
||||
WITH_QEMU_LOCK_GUARD(&client->lock) {
|
||||
nbd_client_receive_next_request(client);
|
||||
}
|
||||
diff --git a/nbd/trace-events b/nbd/trace-events
|
||||
index 00ae3216a1..cbd0a4ab7e 100644
|
||||
--- a/nbd/trace-events
|
||||
+++ b/nbd/trace-events
|
||||
@@ -76,6 +76,7 @@ nbd_co_receive_request_payload_received(uint64_t cookie, uint64_t len) "Payload
|
||||
nbd_co_receive_ext_payload_compliance(uint64_t from, uint64_t len) "client sent non-compliant write without payload flag: from=0x%" PRIx64 ", len=0x%" PRIx64
|
||||
nbd_co_receive_align_compliance(const char *op, uint64_t from, uint64_t len, uint32_t align) "client sent non-compliant unaligned %s request: from=0x%" PRIx64 ", len=0x%" PRIx64 ", align=0x%" PRIx32
|
||||
nbd_trip(void) "Reading request"
|
||||
+nbd_handshake_timer_cb(void) "client took too long to negotiate"
|
||||
|
||||
# client-connection.c
|
||||
nbd_connect_thread_sleep(uint64_t timeout) "timeout %" PRIu64
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,95 +0,0 @@
|
||||
From dc4dd11233522d8195782a2196aaae44bd924575 Mon Sep 17 00:00:00 2001
|
||||
From: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Thu, 14 Mar 2024 17:58:24 +0100
|
||||
Subject: [PATCH 2/4] nbd/server: Fix race in draining the export
|
||||
|
||||
RH-Author: Kevin Wolf <kwolf@redhat.com>
|
||||
RH-MergeRequest: 231: Fix deadlock and crash during storage migration
|
||||
RH-Jira: RHEL-28125
|
||||
RH-Acked-by: Hanna Czenczek <hreitz@redhat.com>
|
||||
RH-Acked-by: Eric Blake <eblake@redhat.com>
|
||||
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
RH-Commit: [2/3] 036e1b171986099904dee468c59d77437e3d3d61 (kmwolf/centos-qemu-kvm)
|
||||
|
||||
When draining an NBD export, nbd_drained_begin() first sets
|
||||
client->quiescing so that nbd_client_receive_next_request() won't start
|
||||
any new request coroutines. Then nbd_drained_poll() tries to makes sure
|
||||
that we wait for any existing request coroutines by checking that
|
||||
client->nb_requests has become 0.
|
||||
|
||||
However, there is a small window between creating a new request
|
||||
coroutine and increasing client->nb_requests. If a coroutine is in this
|
||||
state, it won't be waited for and drain returns too early.
|
||||
|
||||
In the context of switching to a different AioContext, this means that
|
||||
blk_aio_attached() will see client->recv_coroutine != NULL and fail its
|
||||
assertion.
|
||||
|
||||
Fix this by increasing client->nb_requests immediately when starting the
|
||||
coroutine. Doing this after the checks if we should create a new
|
||||
coroutine is okay because client->lock is held.
|
||||
|
||||
Cc: qemu-stable@nongnu.org
|
||||
Fixes: fd6afc501a01 ("nbd/server: Use drained block ops to quiesce the server")
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Message-ID: <20240314165825.40261-2-kwolf@redhat.com>
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
(cherry picked from commit 9c707525cbb1dd1e56876e45c70c0c08f2876d41)
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
---
|
||||
nbd/server.c | 15 +++++++--------
|
||||
1 file changed, 7 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/nbd/server.c b/nbd/server.c
|
||||
index 941832f178..c3484cc1eb 100644
|
||||
--- a/nbd/server.c
|
||||
+++ b/nbd/server.c
|
||||
@@ -3007,8 +3007,8 @@ static coroutine_fn int nbd_handle_request(NBDClient *client,
|
||||
/* Owns a reference to the NBDClient passed as opaque. */
|
||||
static coroutine_fn void nbd_trip(void *opaque)
|
||||
{
|
||||
- NBDClient *client = opaque;
|
||||
- NBDRequestData *req = NULL;
|
||||
+ NBDRequestData *req = opaque;
|
||||
+ NBDClient *client = req->client;
|
||||
NBDRequest request = { 0 }; /* GCC thinks it can be used uninitialized */
|
||||
int ret;
|
||||
Error *local_err = NULL;
|
||||
@@ -3037,8 +3037,6 @@ static coroutine_fn void nbd_trip(void *opaque)
|
||||
goto done;
|
||||
}
|
||||
|
||||
- req = nbd_request_get(client);
|
||||
-
|
||||
/*
|
||||
* nbd_co_receive_request() returns -EAGAIN when nbd_drained_begin() has
|
||||
* set client->quiescing but by the time we get back nbd_drained_end() may
|
||||
@@ -3112,9 +3110,7 @@ static coroutine_fn void nbd_trip(void *opaque)
|
||||
}
|
||||
|
||||
done:
|
||||
- if (req) {
|
||||
- nbd_request_put(req);
|
||||
- }
|
||||
+ nbd_request_put(req);
|
||||
|
||||
qemu_mutex_unlock(&client->lock);
|
||||
|
||||
@@ -3143,10 +3139,13 @@ disconnect:
|
||||
*/
|
||||
static void nbd_client_receive_next_request(NBDClient *client)
|
||||
{
|
||||
+ NBDRequestData *req;
|
||||
+
|
||||
if (!client->recv_coroutine && client->nb_requests < MAX_NBD_REQUESTS &&
|
||||
!client->quiescing) {
|
||||
nbd_client_get(client);
|
||||
- client->recv_coroutine = qemu_coroutine_create(nbd_trip, client);
|
||||
+ req = nbd_request_get(client);
|
||||
+ client->recv_coroutine = qemu_coroutine_create(nbd_trip, req);
|
||||
aio_co_schedule(client->exp->common.ctx, client->recv_coroutine);
|
||||
}
|
||||
}
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,329 +0,0 @@
|
||||
From d1dd79b558fb9b23ae14165ec8edf0085e927091 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Blake <eblake@redhat.com>
|
||||
Date: Mon, 8 Apr 2024 11:00:44 -0500
|
||||
Subject: [PATCH 2/4] nbd/server: Mark negotiation functions as coroutine_fn
|
||||
|
||||
RH-Author: Eric Blake <eblake@redhat.com>
|
||||
RH-MergeRequest: 375: Fix regression on nbd+tls
|
||||
RH-Jira: RHEL-33754
|
||||
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [2/4] 6dc8ecca16df5ae5cc6dc36e7b96f991396fcf24 (ebblake/qemu-kvm)
|
||||
|
||||
nbd_negotiate() is already marked coroutine_fn. And given the fix in
|
||||
the previous patch to have nbd_negotiate_handle_starttls not create
|
||||
and wait on a g_main_loop (as that would violate coroutine
|
||||
constraints), it is worth marking the rest of the related static
|
||||
functions reachable only during option negotiation as also being
|
||||
coroutine_fn.
|
||||
|
||||
Suggested-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
|
||||
Signed-off-by: Eric Blake <eblake@redhat.com>
|
||||
Message-ID: <20240408160214.1200629-6-eblake@redhat.com>
|
||||
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
|
||||
[eblake: drop one spurious coroutine_fn marking]
|
||||
Signed-off-by: Eric Blake <eblake@redhat.com>
|
||||
(cherry picked from commit 4fa333e08dd96395a99ea8dd9e4c73a29dd23344)
|
||||
Jira: https://issues.redhat.com/browse/RHEL-33754
|
||||
Signed-off-by: Eric Blake <eblake@redhat.com>
|
||||
---
|
||||
nbd/server.c | 102 +++++++++++++++++++++++++++++----------------------
|
||||
1 file changed, 59 insertions(+), 43 deletions(-)
|
||||
|
||||
diff --git a/nbd/server.c b/nbd/server.c
|
||||
index 98ae0e1632..892797bb11 100644
|
||||
--- a/nbd/server.c
|
||||
+++ b/nbd/server.c
|
||||
@@ -195,8 +195,9 @@ static inline void set_be_option_rep(NBDOptionReply *rep, uint32_t option,
|
||||
|
||||
/* Send a reply header, including length, but no payload.
|
||||
* Return -errno on error, 0 on success. */
|
||||
-static int nbd_negotiate_send_rep_len(NBDClient *client, uint32_t type,
|
||||
- uint32_t len, Error **errp)
|
||||
+static coroutine_fn int
|
||||
+nbd_negotiate_send_rep_len(NBDClient *client, uint32_t type,
|
||||
+ uint32_t len, Error **errp)
|
||||
{
|
||||
NBDOptionReply rep;
|
||||
|
||||
@@ -211,15 +212,15 @@ static int nbd_negotiate_send_rep_len(NBDClient *client, uint32_t type,
|
||||
|
||||
/* Send a reply header with default 0 length.
|
||||
* Return -errno on error, 0 on success. */
|
||||
-static int nbd_negotiate_send_rep(NBDClient *client, uint32_t type,
|
||||
- Error **errp)
|
||||
+static coroutine_fn int
|
||||
+nbd_negotiate_send_rep(NBDClient *client, uint32_t type, Error **errp)
|
||||
{
|
||||
return nbd_negotiate_send_rep_len(client, type, 0, errp);
|
||||
}
|
||||
|
||||
/* Send an error reply.
|
||||
* Return -errno on error, 0 on success. */
|
||||
-static int G_GNUC_PRINTF(4, 0)
|
||||
+static coroutine_fn int G_GNUC_PRINTF(4, 0)
|
||||
nbd_negotiate_send_rep_verr(NBDClient *client, uint32_t type,
|
||||
Error **errp, const char *fmt, va_list va)
|
||||
{
|
||||
@@ -259,7 +260,7 @@ nbd_sanitize_name(const char *name)
|
||||
|
||||
/* Send an error reply.
|
||||
* Return -errno on error, 0 on success. */
|
||||
-static int G_GNUC_PRINTF(4, 5)
|
||||
+static coroutine_fn int G_GNUC_PRINTF(4, 5)
|
||||
nbd_negotiate_send_rep_err(NBDClient *client, uint32_t type,
|
||||
Error **errp, const char *fmt, ...)
|
||||
{
|
||||
@@ -275,7 +276,7 @@ nbd_negotiate_send_rep_err(NBDClient *client, uint32_t type,
|
||||
/* Drop remainder of the current option, and send a reply with the
|
||||
* given error type and message. Return -errno on read or write
|
||||
* failure; or 0 if connection is still live. */
|
||||
-static int G_GNUC_PRINTF(4, 0)
|
||||
+static coroutine_fn int G_GNUC_PRINTF(4, 0)
|
||||
nbd_opt_vdrop(NBDClient *client, uint32_t type, Error **errp,
|
||||
const char *fmt, va_list va)
|
||||
{
|
||||
@@ -288,7 +289,7 @@ nbd_opt_vdrop(NBDClient *client, uint32_t type, Error **errp,
|
||||
return ret;
|
||||
}
|
||||
|
||||
-static int G_GNUC_PRINTF(4, 5)
|
||||
+static coroutine_fn int G_GNUC_PRINTF(4, 5)
|
||||
nbd_opt_drop(NBDClient *client, uint32_t type, Error **errp,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
@@ -302,7 +303,7 @@ nbd_opt_drop(NBDClient *client, uint32_t type, Error **errp,
|
||||
return ret;
|
||||
}
|
||||
|
||||
-static int G_GNUC_PRINTF(3, 4)
|
||||
+static coroutine_fn int G_GNUC_PRINTF(3, 4)
|
||||
nbd_opt_invalid(NBDClient *client, Error **errp, const char *fmt, ...)
|
||||
{
|
||||
int ret;
|
||||
@@ -319,8 +320,9 @@ nbd_opt_invalid(NBDClient *client, Error **errp, const char *fmt, ...)
|
||||
* If @check_nul, require that no NUL bytes appear in buffer.
|
||||
* Return -errno on I/O error, 0 if option was completely handled by
|
||||
* sending a reply about inconsistent lengths, or 1 on success. */
|
||||
-static int nbd_opt_read(NBDClient *client, void *buffer, size_t size,
|
||||
- bool check_nul, Error **errp)
|
||||
+static coroutine_fn int
|
||||
+nbd_opt_read(NBDClient *client, void *buffer, size_t size,
|
||||
+ bool check_nul, Error **errp)
|
||||
{
|
||||
if (size > client->optlen) {
|
||||
return nbd_opt_invalid(client, errp,
|
||||
@@ -343,7 +345,8 @@ static int nbd_opt_read(NBDClient *client, void *buffer, size_t size,
|
||||
/* Drop size bytes from the unparsed payload of the current option.
|
||||
* Return -errno on I/O error, 0 if option was completely handled by
|
||||
* sending a reply about inconsistent lengths, or 1 on success. */
|
||||
-static int nbd_opt_skip(NBDClient *client, size_t size, Error **errp)
|
||||
+static coroutine_fn int
|
||||
+nbd_opt_skip(NBDClient *client, size_t size, Error **errp)
|
||||
{
|
||||
if (size > client->optlen) {
|
||||
return nbd_opt_invalid(client, errp,
|
||||
@@ -366,8 +369,9 @@ static int nbd_opt_skip(NBDClient *client, size_t size, Error **errp)
|
||||
* Return -errno on I/O error, 0 if option was completely handled by
|
||||
* sending a reply about inconsistent lengths, or 1 on success.
|
||||
*/
|
||||
-static int nbd_opt_read_name(NBDClient *client, char **name, uint32_t *length,
|
||||
- Error **errp)
|
||||
+static coroutine_fn int
|
||||
+nbd_opt_read_name(NBDClient *client, char **name, uint32_t *length,
|
||||
+ Error **errp)
|
||||
{
|
||||
int ret;
|
||||
uint32_t len;
|
||||
@@ -402,8 +406,8 @@ static int nbd_opt_read_name(NBDClient *client, char **name, uint32_t *length,
|
||||
|
||||
/* Send a single NBD_REP_SERVER reply to NBD_OPT_LIST, including payload.
|
||||
* Return -errno on error, 0 on success. */
|
||||
-static int nbd_negotiate_send_rep_list(NBDClient *client, NBDExport *exp,
|
||||
- Error **errp)
|
||||
+static coroutine_fn int
|
||||
+nbd_negotiate_send_rep_list(NBDClient *client, NBDExport *exp, Error **errp)
|
||||
{
|
||||
ERRP_GUARD();
|
||||
size_t name_len, desc_len;
|
||||
@@ -444,7 +448,8 @@ static int nbd_negotiate_send_rep_list(NBDClient *client, NBDExport *exp,
|
||||
|
||||
/* Process the NBD_OPT_LIST command, with a potential series of replies.
|
||||
* Return -errno on error, 0 on success. */
|
||||
-static int nbd_negotiate_handle_list(NBDClient *client, Error **errp)
|
||||
+static coroutine_fn int
|
||||
+nbd_negotiate_handle_list(NBDClient *client, Error **errp)
|
||||
{
|
||||
NBDExport *exp;
|
||||
assert(client->opt == NBD_OPT_LIST);
|
||||
@@ -459,7 +464,8 @@ static int nbd_negotiate_handle_list(NBDClient *client, Error **errp)
|
||||
return nbd_negotiate_send_rep(client, NBD_REP_ACK, errp);
|
||||
}
|
||||
|
||||
-static void nbd_check_meta_export(NBDClient *client, NBDExport *exp)
|
||||
+static coroutine_fn void
|
||||
+nbd_check_meta_export(NBDClient *client, NBDExport *exp)
|
||||
{
|
||||
if (exp != client->contexts.exp) {
|
||||
client->contexts.count = 0;
|
||||
@@ -468,8 +474,9 @@ static void nbd_check_meta_export(NBDClient *client, NBDExport *exp)
|
||||
|
||||
/* Send a reply to NBD_OPT_EXPORT_NAME.
|
||||
* Return -errno on error, 0 on success. */
|
||||
-static int nbd_negotiate_handle_export_name(NBDClient *client, bool no_zeroes,
|
||||
- Error **errp)
|
||||
+static coroutine_fn int
|
||||
+nbd_negotiate_handle_export_name(NBDClient *client, bool no_zeroes,
|
||||
+ Error **errp)
|
||||
{
|
||||
ERRP_GUARD();
|
||||
g_autofree char *name = NULL;
|
||||
@@ -536,9 +543,9 @@ static int nbd_negotiate_handle_export_name(NBDClient *client, bool no_zeroes,
|
||||
/* Send a single NBD_REP_INFO, with a buffer @buf of @length bytes.
|
||||
* The buffer does NOT include the info type prefix.
|
||||
* Return -errno on error, 0 if ready to send more. */
|
||||
-static int nbd_negotiate_send_info(NBDClient *client,
|
||||
- uint16_t info, uint32_t length, void *buf,
|
||||
- Error **errp)
|
||||
+static coroutine_fn int
|
||||
+nbd_negotiate_send_info(NBDClient *client, uint16_t info, uint32_t length,
|
||||
+ void *buf, Error **errp)
|
||||
{
|
||||
int rc;
|
||||
|
||||
@@ -565,7 +572,8 @@ static int nbd_negotiate_send_info(NBDClient *client,
|
||||
* -errno transmission error occurred or @fatal was requested, errp is set
|
||||
* 0 error message successfully sent to client, errp is not set
|
||||
*/
|
||||
-static int nbd_reject_length(NBDClient *client, bool fatal, Error **errp)
|
||||
+static coroutine_fn int
|
||||
+nbd_reject_length(NBDClient *client, bool fatal, Error **errp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -583,7 +591,8 @@ static int nbd_reject_length(NBDClient *client, bool fatal, Error **errp)
|
||||
/* Handle NBD_OPT_INFO and NBD_OPT_GO.
|
||||
* Return -errno on error, 0 if ready for next option, and 1 to move
|
||||
* into transmission phase. */
|
||||
-static int nbd_negotiate_handle_info(NBDClient *client, Error **errp)
|
||||
+static coroutine_fn int
|
||||
+nbd_negotiate_handle_info(NBDClient *client, Error **errp)
|
||||
{
|
||||
int rc;
|
||||
g_autofree char *name = NULL;
|
||||
@@ -755,7 +764,8 @@ struct NBDTLSServerHandshakeData {
|
||||
Coroutine *co;
|
||||
};
|
||||
|
||||
-static void nbd_server_tls_handshake(QIOTask *task, void *opaque)
|
||||
+static void
|
||||
+nbd_server_tls_handshake(QIOTask *task, void *opaque)
|
||||
{
|
||||
struct NBDTLSServerHandshakeData *data = opaque;
|
||||
|
||||
@@ -768,8 +778,8 @@ static void nbd_server_tls_handshake(QIOTask *task, void *opaque)
|
||||
|
||||
/* Handle NBD_OPT_STARTTLS. Return NULL to drop connection, or else the
|
||||
* new channel for all further (now-encrypted) communication. */
|
||||
-static QIOChannel *nbd_negotiate_handle_starttls(NBDClient *client,
|
||||
- Error **errp)
|
||||
+static coroutine_fn QIOChannel *
|
||||
+nbd_negotiate_handle_starttls(NBDClient *client, Error **errp)
|
||||
{
|
||||
QIOChannel *ioc;
|
||||
QIOChannelTLS *tioc;
|
||||
@@ -821,10 +831,9 @@ static QIOChannel *nbd_negotiate_handle_starttls(NBDClient *client,
|
||||
*
|
||||
* For NBD_OPT_LIST_META_CONTEXT @context_id is ignored, 0 is used instead.
|
||||
*/
|
||||
-static int nbd_negotiate_send_meta_context(NBDClient *client,
|
||||
- const char *context,
|
||||
- uint32_t context_id,
|
||||
- Error **errp)
|
||||
+static coroutine_fn int
|
||||
+nbd_negotiate_send_meta_context(NBDClient *client, const char *context,
|
||||
+ uint32_t context_id, Error **errp)
|
||||
{
|
||||
NBDOptionReplyMetaContext opt;
|
||||
struct iovec iov[] = {
|
||||
@@ -849,8 +858,9 @@ static int nbd_negotiate_send_meta_context(NBDClient *client,
|
||||
* Return true if @query matches @pattern, or if @query is empty when
|
||||
* the @client is performing _LIST_.
|
||||
*/
|
||||
-static bool nbd_meta_empty_or_pattern(NBDClient *client, const char *pattern,
|
||||
- const char *query)
|
||||
+static coroutine_fn bool
|
||||
+nbd_meta_empty_or_pattern(NBDClient *client, const char *pattern,
|
||||
+ const char *query)
|
||||
{
|
||||
if (!*query) {
|
||||
trace_nbd_negotiate_meta_query_parse("empty");
|
||||
@@ -867,7 +877,8 @@ static bool nbd_meta_empty_or_pattern(NBDClient *client, const char *pattern,
|
||||
/*
|
||||
* Return true and adjust @str in place if it begins with @prefix.
|
||||
*/
|
||||
-static bool nbd_strshift(const char **str, const char *prefix)
|
||||
+static coroutine_fn bool
|
||||
+nbd_strshift(const char **str, const char *prefix)
|
||||
{
|
||||
size_t len = strlen(prefix);
|
||||
|
||||
@@ -883,8 +894,9 @@ static bool nbd_strshift(const char **str, const char *prefix)
|
||||
* Handle queries to 'base' namespace. For now, only the base:allocation
|
||||
* context is available. Return true if @query has been handled.
|
||||
*/
|
||||
-static bool nbd_meta_base_query(NBDClient *client, NBDMetaContexts *meta,
|
||||
- const char *query)
|
||||
+static coroutine_fn bool
|
||||
+nbd_meta_base_query(NBDClient *client, NBDMetaContexts *meta,
|
||||
+ const char *query)
|
||||
{
|
||||
if (!nbd_strshift(&query, "base:")) {
|
||||
return false;
|
||||
@@ -903,8 +915,9 @@ static bool nbd_meta_base_query(NBDClient *client, NBDMetaContexts *meta,
|
||||
* and qemu:allocation-depth contexts are available. Return true if @query
|
||||
* has been handled.
|
||||
*/
|
||||
-static bool nbd_meta_qemu_query(NBDClient *client, NBDMetaContexts *meta,
|
||||
- const char *query)
|
||||
+static coroutine_fn bool
|
||||
+nbd_meta_qemu_query(NBDClient *client, NBDMetaContexts *meta,
|
||||
+ const char *query)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
@@ -968,8 +981,9 @@ static bool nbd_meta_qemu_query(NBDClient *client, NBDMetaContexts *meta,
|
||||
*
|
||||
* Return -errno on I/O error, 0 if option was completely handled by
|
||||
* sending a reply about inconsistent lengths, or 1 on success. */
|
||||
-static int nbd_negotiate_meta_query(NBDClient *client,
|
||||
- NBDMetaContexts *meta, Error **errp)
|
||||
+static coroutine_fn int
|
||||
+nbd_negotiate_meta_query(NBDClient *client,
|
||||
+ NBDMetaContexts *meta, Error **errp)
|
||||
{
|
||||
int ret;
|
||||
g_autofree char *query = NULL;
|
||||
@@ -1008,7 +1022,8 @@ static int nbd_negotiate_meta_query(NBDClient *client,
|
||||
* Handle NBD_OPT_LIST_META_CONTEXT and NBD_OPT_SET_META_CONTEXT
|
||||
*
|
||||
* Return -errno on I/O error, or 0 if option was completely handled. */
|
||||
-static int nbd_negotiate_meta_queries(NBDClient *client, Error **errp)
|
||||
+static coroutine_fn int
|
||||
+nbd_negotiate_meta_queries(NBDClient *client, Error **errp)
|
||||
{
|
||||
int ret;
|
||||
g_autofree char *export_name = NULL;
|
||||
@@ -1136,7 +1151,8 @@ static int nbd_negotiate_meta_queries(NBDClient *client, Error **errp)
|
||||
* 1 if client sent NBD_OPT_ABORT, i.e. on valid disconnect,
|
||||
* errp is not set
|
||||
*/
|
||||
-static int nbd_negotiate_options(NBDClient *client, Error **errp)
|
||||
+static coroutine_fn int
|
||||
+nbd_negotiate_options(NBDClient *client, Error **errp)
|
||||
{
|
||||
uint32_t flags;
|
||||
bool fixedNewstyle = false;
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,175 +0,0 @@
|
||||
From c8c7dc7a445892a820223be2e7617a790e0400f5 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Blake <eblake@redhat.com>
|
||||
Date: Wed, 7 Aug 2024 08:50:01 -0500
|
||||
Subject: [PATCH 2/5] nbd/server: Plumb in new args to nbd_client_add()
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
RH-Author: Eric Blake <eblake@redhat.com>
|
||||
RH-MergeRequest: 386: nbd/server: fix CVE-2024-7409 (qemu crash on nbd-server-stop) [rhel-9.4.z]
|
||||
RH-Jira: RHEL-52616
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [1/4] 658d80c80a1163fcad456a34ec20d7828273a36c (ebblake/qemu-kvm)
|
||||
|
||||
Upcoming patches to fix a CVE need to track an opaque pointer passed
|
||||
in by the owner of a client object, as well as request for a time
|
||||
limit on how fast negotiation must complete. Prepare for that by
|
||||
changing the signature of nbd_client_new() and adding an accessor to
|
||||
get at the opaque pointer, although for now the two servers
|
||||
(qemu-nbd.c and blockdev-nbd.c) do not change behavior even though
|
||||
they pass in a new default timeout value.
|
||||
|
||||
Suggested-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
|
||||
Signed-off-by: Eric Blake <eblake@redhat.com>
|
||||
Message-ID: <20240807174943.771624-11-eblake@redhat.com>
|
||||
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
[eblake: s/LIMIT/MAX_SECS/ as suggested by Dan]
|
||||
Signed-off-by: Eric Blake <eblake@redhat.com>
|
||||
|
||||
(cherry picked from commit fb1c2aaa981e0a2fa6362c9985f1296b74f055ac)
|
||||
Jira: https://issues.redhat.com/browse/RHEL-52616
|
||||
Signed-off-by: Eric Blake <eblake@redhat.com>
|
||||
---
|
||||
blockdev-nbd.c | 6 ++++--
|
||||
include/block/nbd.h | 11 ++++++++++-
|
||||
nbd/server.c | 20 +++++++++++++++++---
|
||||
qemu-nbd.c | 4 +++-
|
||||
4 files changed, 34 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/blockdev-nbd.c b/blockdev-nbd.c
|
||||
index 213012435f..267a1de903 100644
|
||||
--- a/blockdev-nbd.c
|
||||
+++ b/blockdev-nbd.c
|
||||
@@ -64,8 +64,10 @@ static void nbd_accept(QIONetListener *listener, QIOChannelSocket *cioc,
|
||||
nbd_update_server_watch(nbd_server);
|
||||
|
||||
qio_channel_set_name(QIO_CHANNEL(cioc), "nbd-server");
|
||||
- nbd_client_new(cioc, nbd_server->tlscreds, nbd_server->tlsauthz,
|
||||
- nbd_blockdev_client_closed);
|
||||
+ /* TODO - expose handshake timeout as QMP option */
|
||||
+ nbd_client_new(cioc, NBD_DEFAULT_HANDSHAKE_MAX_SECS,
|
||||
+ nbd_server->tlscreds, nbd_server->tlsauthz,
|
||||
+ nbd_blockdev_client_closed, NULL);
|
||||
}
|
||||
|
||||
static void nbd_update_server_watch(NBDServerData *s)
|
||||
diff --git a/include/block/nbd.h b/include/block/nbd.h
|
||||
index 4e7bd6342f..1d4d65922d 100644
|
||||
--- a/include/block/nbd.h
|
||||
+++ b/include/block/nbd.h
|
||||
@@ -33,6 +33,12 @@ typedef struct NBDMetaContexts NBDMetaContexts;
|
||||
|
||||
extern const BlockExportDriver blk_exp_nbd;
|
||||
|
||||
+/*
|
||||
+ * NBD_DEFAULT_HANDSHAKE_MAX_SECS: Number of seconds in which client must
|
||||
+ * succeed at NBD_OPT_GO before being forcefully dropped as too slow.
|
||||
+ */
|
||||
+#define NBD_DEFAULT_HANDSHAKE_MAX_SECS 10
|
||||
+
|
||||
/* Handshake phase structs - this struct is passed on the wire */
|
||||
|
||||
typedef struct NBDOption {
|
||||
@@ -403,9 +409,12 @@ AioContext *nbd_export_aio_context(NBDExport *exp);
|
||||
NBDExport *nbd_export_find(const char *name);
|
||||
|
||||
void nbd_client_new(QIOChannelSocket *sioc,
|
||||
+ uint32_t handshake_max_secs,
|
||||
QCryptoTLSCreds *tlscreds,
|
||||
const char *tlsauthz,
|
||||
- void (*close_fn)(NBDClient *, bool));
|
||||
+ void (*close_fn)(NBDClient *, bool),
|
||||
+ void *owner);
|
||||
+void *nbd_client_owner(NBDClient *client);
|
||||
void nbd_client_get(NBDClient *client);
|
||||
void nbd_client_put(NBDClient *client);
|
||||
|
||||
diff --git a/nbd/server.c b/nbd/server.c
|
||||
index 892797bb11..e50012499f 100644
|
||||
--- a/nbd/server.c
|
||||
+++ b/nbd/server.c
|
||||
@@ -124,12 +124,14 @@ struct NBDMetaContexts {
|
||||
struct NBDClient {
|
||||
int refcount; /* atomic */
|
||||
void (*close_fn)(NBDClient *client, bool negotiated);
|
||||
+ void *owner;
|
||||
|
||||
QemuMutex lock;
|
||||
|
||||
NBDExport *exp;
|
||||
QCryptoTLSCreds *tlscreds;
|
||||
char *tlsauthz;
|
||||
+ uint32_t handshake_max_secs;
|
||||
QIOChannelSocket *sioc; /* The underlying data channel */
|
||||
QIOChannel *ioc; /* The current I/O channel which may differ (eg TLS) */
|
||||
|
||||
@@ -3191,6 +3193,7 @@ static coroutine_fn void nbd_co_client_start(void *opaque)
|
||||
|
||||
qemu_co_mutex_init(&client->send_lock);
|
||||
|
||||
+ /* TODO - utilize client->handshake_max_secs */
|
||||
if (nbd_negotiate(client, &local_err)) {
|
||||
if (local_err) {
|
||||
error_report_err(local_err);
|
||||
@@ -3205,14 +3208,17 @@ static coroutine_fn void nbd_co_client_start(void *opaque)
|
||||
}
|
||||
|
||||
/*
|
||||
- * Create a new client listener using the given channel @sioc.
|
||||
+ * Create a new client listener using the given channel @sioc and @owner.
|
||||
* Begin servicing it in a coroutine. When the connection closes, call
|
||||
- * @close_fn with an indication of whether the client completed negotiation.
|
||||
+ * @close_fn with an indication of whether the client completed negotiation
|
||||
+ * within @handshake_max_secs seconds (0 for unbounded).
|
||||
*/
|
||||
void nbd_client_new(QIOChannelSocket *sioc,
|
||||
+ uint32_t handshake_max_secs,
|
||||
QCryptoTLSCreds *tlscreds,
|
||||
const char *tlsauthz,
|
||||
- void (*close_fn)(NBDClient *, bool))
|
||||
+ void (*close_fn)(NBDClient *, bool),
|
||||
+ void *owner)
|
||||
{
|
||||
NBDClient *client;
|
||||
Coroutine *co;
|
||||
@@ -3225,13 +3231,21 @@ void nbd_client_new(QIOChannelSocket *sioc,
|
||||
object_ref(OBJECT(client->tlscreds));
|
||||
}
|
||||
client->tlsauthz = g_strdup(tlsauthz);
|
||||
+ client->handshake_max_secs = handshake_max_secs;
|
||||
client->sioc = sioc;
|
||||
qio_channel_set_delay(QIO_CHANNEL(sioc), false);
|
||||
object_ref(OBJECT(client->sioc));
|
||||
client->ioc = QIO_CHANNEL(sioc);
|
||||
object_ref(OBJECT(client->ioc));
|
||||
client->close_fn = close_fn;
|
||||
+ client->owner = owner;
|
||||
|
||||
co = qemu_coroutine_create(nbd_co_client_start, client);
|
||||
qemu_coroutine_enter(co);
|
||||
}
|
||||
+
|
||||
+void *
|
||||
+nbd_client_owner(NBDClient *client)
|
||||
+{
|
||||
+ return client->owner;
|
||||
+}
|
||||
diff --git a/qemu-nbd.c b/qemu-nbd.c
|
||||
index bac0b5e3ec..01b4a63c31 100644
|
||||
--- a/qemu-nbd.c
|
||||
+++ b/qemu-nbd.c
|
||||
@@ -389,7 +389,9 @@ static void nbd_accept(QIONetListener *listener, QIOChannelSocket *cioc,
|
||||
|
||||
nb_fds++;
|
||||
nbd_update_server_watch();
|
||||
- nbd_client_new(cioc, tlscreds, tlsauthz, nbd_client_closed);
|
||||
+ /* TODO - expose handshake timeout as command line option */
|
||||
+ nbd_client_new(cioc, NBD_DEFAULT_HANDSHAKE_MAX_SECS,
|
||||
+ tlscreds, tlsauthz, nbd_client_closed, NULL);
|
||||
}
|
||||
|
||||
static void nbd_update_server_watch(void)
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,207 +0,0 @@
|
||||
From ef01aeba9f6c4c886719261333a04bc32484f0d0 Mon Sep 17 00:00:00 2001
|
||||
From: Zhu Yangyang <zhuyangyang14@huawei.com>
|
||||
Date: Mon, 8 Apr 2024 11:00:43 -0500
|
||||
Subject: [PATCH 1/4] nbd/server: do not poll within a coroutine context
|
||||
|
||||
RH-Author: Eric Blake <eblake@redhat.com>
|
||||
RH-MergeRequest: 375: Fix regression on nbd+tls
|
||||
RH-Jira: RHEL-33754
|
||||
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [1/4] 88ca2c90e0c412ba8c1cfd7ea91e01ec58220e9b (ebblake/qemu-kvm)
|
||||
|
||||
Coroutines are not supposed to block. Instead, they should yield.
|
||||
|
||||
The client performs TLS upgrade outside of an AIOContext, during
|
||||
synchronous handshake; this still requires g_main_loop. But the
|
||||
server responds to TLS upgrade inside a coroutine, so a nested
|
||||
g_main_loop is wrong. Since the two callbacks no longer share more
|
||||
than the setting of data.complete and data.error, it's just as easy to
|
||||
use static helpers instead of trying to share a common code path. It
|
||||
is also possible to add assertions that no other code is interfering
|
||||
with the eventual path to qio reaching the callback, whether or not it
|
||||
required a yield or main loop.
|
||||
|
||||
Fixes: f95910f ("nbd: implement TLS support in the protocol negotiation")
|
||||
Signed-off-by: Zhu Yangyang <zhuyangyang14@huawei.com>
|
||||
[eblake: move callbacks to their use point, add assertions]
|
||||
Signed-off-by: Eric Blake <eblake@redhat.com>
|
||||
Message-ID: <20240408160214.1200629-5-eblake@redhat.com>
|
||||
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
|
||||
(cherry picked from commit ae6d91a7e9b77abb029ed3fa9fad461422286942)
|
||||
Jira: https://issues.redhat.com/browse/RHEL-33754
|
||||
Signed-off-by: Eric Blake <eblake@redhat.com>
|
||||
---
|
||||
nbd/client.c | 28 ++++++++++++++++++++++++----
|
||||
nbd/common.c | 11 -----------
|
||||
nbd/nbd-internal.h | 10 ----------
|
||||
nbd/server.c | 28 +++++++++++++++++++++++-----
|
||||
4 files changed, 47 insertions(+), 30 deletions(-)
|
||||
|
||||
diff --git a/nbd/client.c b/nbd/client.c
|
||||
index 29ffc609a4..c89c750467 100644
|
||||
--- a/nbd/client.c
|
||||
+++ b/nbd/client.c
|
||||
@@ -596,13 +596,31 @@ static int nbd_request_simple_option(QIOChannel *ioc, int opt, bool strict,
|
||||
return 1;
|
||||
}
|
||||
|
||||
+/* Callback to learn when QIO TLS upgrade is complete */
|
||||
+struct NBDTLSClientHandshakeData {
|
||||
+ bool complete;
|
||||
+ Error *error;
|
||||
+ GMainLoop *loop;
|
||||
+};
|
||||
+
|
||||
+static void nbd_client_tls_handshake(QIOTask *task, void *opaque)
|
||||
+{
|
||||
+ struct NBDTLSClientHandshakeData *data = opaque;
|
||||
+
|
||||
+ qio_task_propagate_error(task, &data->error);
|
||||
+ data->complete = true;
|
||||
+ if (data->loop) {
|
||||
+ g_main_loop_quit(data->loop);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static QIOChannel *nbd_receive_starttls(QIOChannel *ioc,
|
||||
QCryptoTLSCreds *tlscreds,
|
||||
const char *hostname, Error **errp)
|
||||
{
|
||||
int ret;
|
||||
QIOChannelTLS *tioc;
|
||||
- struct NBDTLSHandshakeData data = { 0 };
|
||||
+ struct NBDTLSClientHandshakeData data = { 0 };
|
||||
|
||||
ret = nbd_request_simple_option(ioc, NBD_OPT_STARTTLS, true, errp);
|
||||
if (ret <= 0) {
|
||||
@@ -619,18 +637,20 @@ static QIOChannel *nbd_receive_starttls(QIOChannel *ioc,
|
||||
return NULL;
|
||||
}
|
||||
qio_channel_set_name(QIO_CHANNEL(tioc), "nbd-client-tls");
|
||||
- data.loop = g_main_loop_new(g_main_context_default(), FALSE);
|
||||
trace_nbd_receive_starttls_tls_handshake();
|
||||
qio_channel_tls_handshake(tioc,
|
||||
- nbd_tls_handshake,
|
||||
+ nbd_client_tls_handshake,
|
||||
&data,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
if (!data.complete) {
|
||||
+ data.loop = g_main_loop_new(g_main_context_default(), FALSE);
|
||||
g_main_loop_run(data.loop);
|
||||
+ assert(data.complete);
|
||||
+ g_main_loop_unref(data.loop);
|
||||
}
|
||||
- g_main_loop_unref(data.loop);
|
||||
+
|
||||
if (data.error) {
|
||||
error_propagate(errp, data.error);
|
||||
object_unref(OBJECT(tioc));
|
||||
diff --git a/nbd/common.c b/nbd/common.c
|
||||
index 3247c1d618..589a748cfe 100644
|
||||
--- a/nbd/common.c
|
||||
+++ b/nbd/common.c
|
||||
@@ -47,17 +47,6 @@ int nbd_drop(QIOChannel *ioc, size_t size, Error **errp)
|
||||
}
|
||||
|
||||
|
||||
-void nbd_tls_handshake(QIOTask *task,
|
||||
- void *opaque)
|
||||
-{
|
||||
- struct NBDTLSHandshakeData *data = opaque;
|
||||
-
|
||||
- qio_task_propagate_error(task, &data->error);
|
||||
- data->complete = true;
|
||||
- g_main_loop_quit(data->loop);
|
||||
-}
|
||||
-
|
||||
-
|
||||
const char *nbd_opt_lookup(uint32_t opt)
|
||||
{
|
||||
switch (opt) {
|
||||
diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h
|
||||
index dfa02f77ee..91895106a9 100644
|
||||
--- a/nbd/nbd-internal.h
|
||||
+++ b/nbd/nbd-internal.h
|
||||
@@ -72,16 +72,6 @@ static inline int nbd_write(QIOChannel *ioc, const void *buffer, size_t size,
|
||||
return qio_channel_write_all(ioc, buffer, size, errp) < 0 ? -EIO : 0;
|
||||
}
|
||||
|
||||
-struct NBDTLSHandshakeData {
|
||||
- GMainLoop *loop;
|
||||
- bool complete;
|
||||
- Error *error;
|
||||
-};
|
||||
-
|
||||
-
|
||||
-void nbd_tls_handshake(QIOTask *task,
|
||||
- void *opaque);
|
||||
-
|
||||
int nbd_drop(QIOChannel *ioc, size_t size, Error **errp);
|
||||
|
||||
#endif
|
||||
diff --git a/nbd/server.c b/nbd/server.c
|
||||
index c3484cc1eb..98ae0e1632 100644
|
||||
--- a/nbd/server.c
|
||||
+++ b/nbd/server.c
|
||||
@@ -748,6 +748,23 @@ static int nbd_negotiate_handle_info(NBDClient *client, Error **errp)
|
||||
return rc;
|
||||
}
|
||||
|
||||
+/* Callback to learn when QIO TLS upgrade is complete */
|
||||
+struct NBDTLSServerHandshakeData {
|
||||
+ bool complete;
|
||||
+ Error *error;
|
||||
+ Coroutine *co;
|
||||
+};
|
||||
+
|
||||
+static void nbd_server_tls_handshake(QIOTask *task, void *opaque)
|
||||
+{
|
||||
+ struct NBDTLSServerHandshakeData *data = opaque;
|
||||
+
|
||||
+ qio_task_propagate_error(task, &data->error);
|
||||
+ data->complete = true;
|
||||
+ if (!qemu_coroutine_entered(data->co)) {
|
||||
+ aio_co_wake(data->co);
|
||||
+ }
|
||||
+}
|
||||
|
||||
/* Handle NBD_OPT_STARTTLS. Return NULL to drop connection, or else the
|
||||
* new channel for all further (now-encrypted) communication. */
|
||||
@@ -756,7 +773,7 @@ static QIOChannel *nbd_negotiate_handle_starttls(NBDClient *client,
|
||||
{
|
||||
QIOChannel *ioc;
|
||||
QIOChannelTLS *tioc;
|
||||
- struct NBDTLSHandshakeData data = { 0 };
|
||||
+ struct NBDTLSServerHandshakeData data = { 0 };
|
||||
|
||||
assert(client->opt == NBD_OPT_STARTTLS);
|
||||
|
||||
@@ -777,17 +794,18 @@ static QIOChannel *nbd_negotiate_handle_starttls(NBDClient *client,
|
||||
|
||||
qio_channel_set_name(QIO_CHANNEL(tioc), "nbd-server-tls");
|
||||
trace_nbd_negotiate_handle_starttls_handshake();
|
||||
- data.loop = g_main_loop_new(g_main_context_default(), FALSE);
|
||||
+ data.co = qemu_coroutine_self();
|
||||
qio_channel_tls_handshake(tioc,
|
||||
- nbd_tls_handshake,
|
||||
+ nbd_server_tls_handshake,
|
||||
&data,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
if (!data.complete) {
|
||||
- g_main_loop_run(data.loop);
|
||||
+ qemu_coroutine_yield();
|
||||
+ assert(data.complete);
|
||||
}
|
||||
- g_main_loop_unref(data.loop);
|
||||
+
|
||||
if (data.error) {
|
||||
object_unref(OBJECT(tioc));
|
||||
error_propagate(errp, data.error);
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,115 +0,0 @@
|
||||
From 9ca64f73238d9f1b9f13d8e941ba42771a992afb Mon Sep 17 00:00:00 2001
|
||||
From: Igor Mammedov <imammedo@redhat.com>
|
||||
Date: Fri, 29 Dec 2023 14:06:05 +0100
|
||||
Subject: [PATCH 20/20] pc/q35: set SMBIOS entry point type to 'auto' by
|
||||
default
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 230: Workaround Windows failing to find 64bit SMBIOS entry point with SeaBIOS
|
||||
RH-Jira: RHEL-21705
|
||||
RH-Acked-by: MST <mst@redhat.com>
|
||||
RH-Acked-by: Ani Sinha <None>
|
||||
RH-Commit: [18/18] c7fc6ac7350bca3ff99e58620710a86218385781
|
||||
|
||||
JIRA: https://issues.redhat.com/browse/RHEL-21705
|
||||
|
||||
Use smbios-entry-point-type='auto' for newer machine types as a workaround
|
||||
for Windows not detecting SMBIOS tables. Which makes QEMU pick SMBIOS tables
|
||||
based on configuration (with 2.x preferred and fallback to 3.x if the former
|
||||
isn't compatible with configuration)
|
||||
|
||||
Default compat setting of smbios-entry-point-type after series
|
||||
for pc/q35 machines:
|
||||
* 9.0-newer: 'auto'
|
||||
* 8.1-8.2: '64'
|
||||
* 8.0-older: '32'
|
||||
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2008
|
||||
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
|
||||
Reviewed-by: Ani Sinha <anisinha@redhat.com>
|
||||
Tested-by: Fiona Ebner <f.ebner@proxmox.com>
|
||||
|
||||
Conflicts: hw/i386/pc_piix.c hw/i386/pc_q35.c
|
||||
due to RHEL machine types
|
||||
|
||||
REHL only parts:
|
||||
Fix RHEL 'pc' machine types at SMBIOS 2.X
|
||||
for the latest RHEL 'q35' machine type use version autoselect
|
||||
which propagates to RHEL 9.4 q35 macine type while RHEL 9.2 q35 and older
|
||||
are kept at SMBIOS_ENTRY_POINT_TYPE_32 (see: pc_q35_machine_rhel920_options)
|
||||
|
||||
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
|
||||
---
|
||||
hw/i386/pc.c | 2 +-
|
||||
hw/i386/pc_piix.c | 7 +++++++
|
||||
hw/i386/pc_q35.c | 5 +++++
|
||||
3 files changed, 13 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
|
||||
index ae6777fc1a..d6f267b220 100644
|
||||
--- a/hw/i386/pc.c
|
||||
+++ b/hw/i386/pc.c
|
||||
@@ -2004,7 +2004,7 @@ static void pc_machine_class_init(ObjectClass *oc, void *data)
|
||||
mc->nvdimm_supported = true;
|
||||
mc->smp_props.dies_supported = true;
|
||||
mc->default_ram_id = "pc.ram";
|
||||
- pcmc->default_smbios_ep_type = SMBIOS_ENTRY_POINT_TYPE_64;
|
||||
+ pcmc->default_smbios_ep_type = SMBIOS_ENTRY_POINT_TYPE_AUTO;
|
||||
|
||||
object_class_property_add(oc, PC_MACHINE_MAX_RAM_BELOW_4G, "size",
|
||||
pc_machine_get_max_ram_below_4g, pc_machine_set_max_ram_below_4g,
|
||||
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
|
||||
index 7344b35cf1..54d1c58bce 100644
|
||||
--- a/hw/i386/pc_piix.c
|
||||
+++ b/hw/i386/pc_piix.c
|
||||
@@ -539,9 +539,14 @@ static void pc_i440fx_machine_options(MachineClass *m)
|
||||
|
||||
static void pc_i440fx_8_2_machine_options(MachineClass *m)
|
||||
{
|
||||
+ PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
|
||||
+
|
||||
pc_i440fx_machine_options(m);
|
||||
m->alias = "pc";
|
||||
m->is_default = true;
|
||||
+
|
||||
+ /* For pc-i44fx-8.2 and 8.1, use SMBIOS 3.X by default */
|
||||
+ pcmc->default_smbios_ep_type = SMBIOS_ENTRY_POINT_TYPE_64;
|
||||
}
|
||||
|
||||
DEFINE_I440FX_MACHINE(v8_2, "pc-i440fx-8.2", NULL,
|
||||
@@ -982,6 +987,8 @@ static void pc_machine_rhel7_options(MachineClass *m)
|
||||
m->alias = "pc";
|
||||
m->is_default = 1;
|
||||
m->smp_props.prefer_sockets = true;
|
||||
+ /* there aren't ne PC macine types in RHEL9, keep it at SMBIOS 2.X */
|
||||
+ pcmc->default_smbios_ep_type = SMBIOS_ENTRY_POINT_TYPE_32;
|
||||
}
|
||||
|
||||
static void pc_init_rhel760(MachineState *machine)
|
||||
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
|
||||
index 9a22ff5dd6..cd5fb7380e 100644
|
||||
--- a/hw/i386/pc_q35.c
|
||||
+++ b/hw/i386/pc_q35.c
|
||||
@@ -377,8 +377,11 @@ static void pc_q35_machine_options(MachineClass *m)
|
||||
|
||||
static void pc_q35_8_2_machine_options(MachineClass *m)
|
||||
{
|
||||
+ PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
|
||||
pc_q35_machine_options(m);
|
||||
m->alias = "q35";
|
||||
+ /* For pc-q35-8.2 and 8.1, use SMBIOS 3.X by default */
|
||||
+ pcmc->default_smbios_ep_type = SMBIOS_ENTRY_POINT_TYPE_64;
|
||||
}
|
||||
|
||||
DEFINE_Q35_MACHINE(v8_2, "pc-q35-8.2", NULL,
|
||||
@@ -712,6 +715,8 @@ static void pc_q35_machine_rhel_options(MachineClass *m)
|
||||
m->alias = "q35";
|
||||
m->max_cpus = 710;
|
||||
compat_props_add(m->compat_props, pc_rhel_compat, pc_rhel_compat_len);
|
||||
+ /* use SMBIOS version autoselect by default for the latest RHEL machine */
|
||||
+ pcmc->default_smbios_ep_type = SMBIOS_ENTRY_POINT_TYPE_AUTO;
|
||||
}
|
||||
|
||||
static void pc_q35_init_rhel940(MachineState *machine)
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,44 +0,0 @@
|
||||
From 03cad16743d9a4d377af66611d030eca9eda326d Mon Sep 17 00:00:00 2001
|
||||
From: Igor Mammedov <imammedo@redhat.com>
|
||||
Date: Tue, 19 Mar 2024 11:42:04 +0100
|
||||
Subject: [PATCH 4/4] pc: smbios: fixup manufacturer/product/version to match
|
||||
downstream
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 232: pc: smbios: fixup manufacturer/product/version to match downstream
|
||||
RH-Jira: RHEL-21705
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Acked-by: Ani Sinha <anisinha@redhat.com>
|
||||
RH-Commit: [1/1] 9235f64acb5ff46360282e889d0aedcb13374ac1
|
||||
|
||||
JIRA: https://issues.redhat.com/browse/RHEL-21705
|
||||
|
||||
commit [1] discarded RHEL only change that customizes
|
||||
SMBIOS values for manufacturer/product/version for pc/q35
|
||||
machine types.
|
||||
Fix it up by reverting back to ("Red Hat", "KVM", mc->desc)
|
||||
tuple.
|
||||
|
||||
1)
|
||||
Fixes: 208239eb2 (hw/i386/pc: Defer smbios_set_defaults() to machine_done)
|
||||
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
|
||||
---
|
||||
hw/i386/fw_cfg.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/hw/i386/fw_cfg.c b/hw/i386/fw_cfg.c
|
||||
index 58429bb78d..d6a24177e2 100644
|
||||
--- a/hw/i386/fw_cfg.c
|
||||
+++ b/hw/i386/fw_cfg.c
|
||||
@@ -63,7 +63,7 @@ void fw_cfg_build_smbios(PCMachineState *pcms, FWCfgState *fw_cfg,
|
||||
|
||||
if (pcmc->smbios_defaults) {
|
||||
/* These values are guest ABI, do not change */
|
||||
- smbios_set_defaults("QEMU", mc->desc, mc->name,
|
||||
+ smbios_set_defaults("Red Hat", "KVM", mc->desc,
|
||||
pcmc->smbios_uuid_encoded,
|
||||
pcmc->smbios_stream_product,
|
||||
pcmc->smbios_stream_version);
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,125 +0,0 @@
|
||||
From 6e39b4c13c0eacb35e81874b09e6b6411266c631 Mon Sep 17 00:00:00 2001
|
||||
From: Jon Maloy <jmaloy@redhat.com>
|
||||
Date: Wed, 5 Jun 2024 19:56:51 -0400
|
||||
Subject: [PATCH 1/4] qcow2: Don't open data_file with BDRV_O_NO_IO
|
||||
|
||||
RH-Author: Jon Maloy <jmaloy@redhat.com>
|
||||
RH-MergeRequest: 2: EMBARGOED CVE-2024-4467 for rhel-9.4.z (PRDSC)
|
||||
RH-Jira: https://issues.redhat.com/browse/RHEL-35610
|
||||
RH-CVE: CVE-2024-4467
|
||||
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
|
||||
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
RH-Acked-by: Hanna Czenczek <hczenczek@redhat.com>
|
||||
RH-Commit: [1/4] 1000359b05c706f3c5155a9481692352be333129
|
||||
|
||||
commit f9843ce5c519901654a7d8ba43ee95ce25ca13c2
|
||||
Author: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Thu Apr 11 15:06:01 2024 +0200
|
||||
|
||||
qcow2: Don't open data_file with BDRV_O_NO_IO
|
||||
|
||||
One use case for 'qemu-img info' is verifying that untrusted images
|
||||
don't reference an unwanted external file, be it as a backing file or an
|
||||
external data file. To make sure that calling 'qemu-img info' can't
|
||||
already have undesired side effects with a malicious image, just don't
|
||||
open the data file at all with BDRV_O_NO_IO. If nothing ever tries to do
|
||||
I/O, we don't need to have it open.
|
||||
|
||||
This changes the output of iotests case 061, which used 'qemu-img info'
|
||||
to show that opening an image with an invalid data file fails. After
|
||||
this patch, it succeeds. Replace this part of the test with a qemu-io
|
||||
call, but keep the final 'qemu-img info' to show that the invalid data
|
||||
file is correctly displayed in the output.
|
||||
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Eric Blake <eblake@redhat.com>
|
||||
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
|
||||
Upstream: N/A, embargoed
|
||||
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
|
||||
|
||||
Signed-off-by: Jon Maloy <jmaloy@redhat.com>
|
||||
---
|
||||
block/qcow2.c | 17 ++++++++++++++++-
|
||||
tests/qemu-iotests/061 | 6 ++++--
|
||||
tests/qemu-iotests/061.out | 8 ++++++--
|
||||
3 files changed, 26 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/block/qcow2.c b/block/qcow2.c
|
||||
index d91b7b91d3..b269cfc78f 100644
|
||||
--- a/block/qcow2.c
|
||||
+++ b/block/qcow2.c
|
||||
@@ -1642,7 +1642,22 @@ qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
- if (open_data_file) {
|
||||
+ if (open_data_file && (flags & BDRV_O_NO_IO)) {
|
||||
+ /*
|
||||
+ * Don't open the data file for 'qemu-img info' so that it can be used
|
||||
+ * to verify that an untrusted qcow2 image doesn't refer to external
|
||||
+ * files.
|
||||
+ *
|
||||
+ * Note: This still makes has_data_file() return true.
|
||||
+ */
|
||||
+ if (s->incompatible_features & QCOW2_INCOMPAT_DATA_FILE) {
|
||||
+ s->data_file = NULL;
|
||||
+ } else {
|
||||
+ s->data_file = bs->file;
|
||||
+ }
|
||||
+ qdict_extract_subqdict(options, NULL, "data-file.");
|
||||
+ qdict_del(options, "data-file");
|
||||
+ } else if (open_data_file) {
|
||||
/* Open external data file */
|
||||
bdrv_graph_co_rdunlock();
|
||||
s->data_file = bdrv_co_open_child(NULL, options, "data-file", bs,
|
||||
diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061
|
||||
index 53c7d428e3..b71ac097d1 100755
|
||||
--- a/tests/qemu-iotests/061
|
||||
+++ b/tests/qemu-iotests/061
|
||||
@@ -326,12 +326,14 @@ $QEMU_IMG amend -o "data_file=foo" "$TEST_IMG"
|
||||
echo
|
||||
_make_test_img -o "compat=1.1,data_file=$TEST_IMG.data" 64M
|
||||
$QEMU_IMG amend -o "data_file=foo" "$TEST_IMG"
|
||||
-_img_info --format-specific
|
||||
+$QEMU_IO -c "read 0 4k" "$TEST_IMG" 2>&1 | _filter_testdir | _filter_imgfmt
|
||||
+$QEMU_IO -c "open -o data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG" -c "read 0 4k" | _filter_qemu_io
|
||||
TEST_IMG="data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG" _img_info --format-specific --image-opts
|
||||
|
||||
echo
|
||||
$QEMU_IMG amend -o "data_file=" --image-opts "data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG"
|
||||
-_img_info --format-specific
|
||||
+$QEMU_IO -c "read 0 4k" "$TEST_IMG" 2>&1 | _filter_testdir | _filter_imgfmt
|
||||
+$QEMU_IO -c "open -o data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG" -c "read 0 4k" | _filter_qemu_io
|
||||
TEST_IMG="data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG" _img_info --format-specific --image-opts
|
||||
|
||||
echo
|
||||
diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out
|
||||
index 139fc68177..24c33add7c 100644
|
||||
--- a/tests/qemu-iotests/061.out
|
||||
+++ b/tests/qemu-iotests/061.out
|
||||
@@ -545,7 +545,9 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
qemu-img: data-file can only be set for images that use an external data file
|
||||
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data
|
||||
-qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Could not open 'foo': No such file or directory
|
||||
+qemu-io: can't open device TEST_DIR/t.IMGFMT: Could not open 'foo': No such file or directory
|
||||
+read 4096/4096 bytes at offset 0
|
||||
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
image: TEST_DIR/t.IMGFMT
|
||||
file format: IMGFMT
|
||||
virtual size: 64 MiB (67108864 bytes)
|
||||
@@ -560,7 +562,9 @@ Format specific information:
|
||||
corrupt: false
|
||||
extended l2: false
|
||||
|
||||
-qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'data-file' is required for this image
|
||||
+qemu-io: can't open device TEST_DIR/t.IMGFMT: 'data-file' is required for this image
|
||||
+read 4096/4096 bytes at offset 0
|
||||
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
image: TEST_DIR/t.IMGFMT
|
||||
file format: IMGFMT
|
||||
virtual size: 64 MiB (67108864 bytes)
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,135 +0,0 @@
|
||||
From f2fe6c7a2def488633cbb67e28ac00279d6e8de4 Mon Sep 17 00:00:00 2001
|
||||
From: Cornelia Huck <cohuck@redhat.com>
|
||||
Date: Tue, 27 Feb 2024 11:17:39 +0100
|
||||
Subject: [PATCH 1/2] qemu_init: increase NOFILE soft limit on POSIX
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
RH-Author: Cornelia Huck <cohuck@redhat.com>
|
||||
RH-MergeRequest: 226: qemu_init: increase NOFILE soft limit on POSIX
|
||||
RH-Jira: RHEL-26049
|
||||
RH-Acked-by: Gavin Shan <gshan@redhat.com>
|
||||
RH-Acked-by: Ani Sinha <None>
|
||||
RH-Acked-by: Shaoqin Huang <None>
|
||||
RH-Commit: [1/1] cee5404aef3f6437d45a1c43bdee73a57a528bee (cohuck/qemu-kvm-c9s)
|
||||
|
||||
Jira: https://issues.redhat.com/browse/RHEL-26049
|
||||
|
||||
In many configurations, e.g. multiple vNICs with multiple queues or
|
||||
with many Ceph OSDs, the default soft limit of 1024 is not enough.
|
||||
QEMU is supposed to work fine with file descriptors >= 1024 and does
|
||||
not use select() on POSIX. Bump the soft limit to the allowed hard
|
||||
limit to avoid issues with the aforementioned configurations.
|
||||
|
||||
Of course the limit could be raised from the outside, but the man page
|
||||
of systemd.exec states about 'LimitNOFILE=':
|
||||
|
||||
> Don't use.
|
||||
> [...]
|
||||
> Typically applications should increase their soft limit to the hard
|
||||
> limit on their own, if they are OK with working with file
|
||||
> descriptors above 1023,
|
||||
|
||||
If the soft limit is already the same as the hard limit, avoid the
|
||||
superfluous setrlimit call. This can avoid a warning with a strict
|
||||
seccomp filter blocking setrlimit if NOFILE was already raised before
|
||||
executing QEMU.
|
||||
|
||||
Buglink: https://bugzilla.proxmox.com/show_bug.cgi?id=4507
|
||||
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
|
||||
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
(cherry picked from commit 03e471c41d8b1b6eb16c9714f387449f52fe5c1d)
|
||||
Signed-off-by: Cornelia Huck <cohuck@redhat.com>
|
||||
---
|
||||
include/sysemu/os-posix.h | 1 +
|
||||
include/sysemu/os-win32.h | 5 +++++
|
||||
os-posix.c | 22 ++++++++++++++++++++++
|
||||
system/vl.c | 2 ++
|
||||
4 files changed, 30 insertions(+)
|
||||
|
||||
diff --git a/include/sysemu/os-posix.h b/include/sysemu/os-posix.h
|
||||
index dff32ae185..b881ac6c6f 100644
|
||||
--- a/include/sysemu/os-posix.h
|
||||
+++ b/include/sysemu/os-posix.h
|
||||
@@ -51,6 +51,7 @@ bool is_daemonized(void);
|
||||
void os_daemonize(void);
|
||||
bool os_set_runas(const char *user_id);
|
||||
void os_set_chroot(const char *path);
|
||||
+void os_setup_limits(void);
|
||||
void os_setup_post(void);
|
||||
int os_mlock(void);
|
||||
|
||||
diff --git a/include/sysemu/os-win32.h b/include/sysemu/os-win32.h
|
||||
index 1047d260cb..b82a5d3ad9 100644
|
||||
--- a/include/sysemu/os-win32.h
|
||||
+++ b/include/sysemu/os-win32.h
|
||||
@@ -128,6 +128,11 @@ static inline int os_mlock(void)
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
+static inline void os_setup_limits(void)
|
||||
+{
|
||||
+ return;
|
||||
+}
|
||||
+
|
||||
#define fsync _commit
|
||||
|
||||
#if !defined(lseek)
|
||||
diff --git a/os-posix.c b/os-posix.c
|
||||
index 52ef6990ff..a4284e2c07 100644
|
||||
--- a/os-posix.c
|
||||
+++ b/os-posix.c
|
||||
@@ -24,6 +24,7 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
+#include <sys/resource.h>
|
||||
#include <sys/wait.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
@@ -256,6 +257,27 @@ void os_daemonize(void)
|
||||
}
|
||||
}
|
||||
|
||||
+void os_setup_limits(void)
|
||||
+{
|
||||
+ struct rlimit nofile;
|
||||
+
|
||||
+ if (getrlimit(RLIMIT_NOFILE, &nofile) < 0) {
|
||||
+ warn_report("unable to query NOFILE limit: %s", strerror(errno));
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (nofile.rlim_cur == nofile.rlim_max) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ nofile.rlim_cur = nofile.rlim_max;
|
||||
+
|
||||
+ if (setrlimit(RLIMIT_NOFILE, &nofile) < 0) {
|
||||
+ warn_report("unable to set NOFILE limit: %s", strerror(errno));
|
||||
+ return;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void os_setup_post(void)
|
||||
{
|
||||
int fd = 0;
|
||||
diff --git a/system/vl.c b/system/vl.c
|
||||
index 93635ffc5b..6443b6e469 100644
|
||||
--- a/system/vl.c
|
||||
+++ b/system/vl.c
|
||||
@@ -2783,6 +2783,8 @@ void qemu_init(int argc, char **argv)
|
||||
error_init(argv[0]);
|
||||
qemu_init_exec_dir(argv[0]);
|
||||
|
||||
+ os_setup_limits();
|
||||
+
|
||||
qemu_init_arch_modules();
|
||||
|
||||
qemu_init_subsystems();
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,129 +0,0 @@
|
||||
From 69d6b5f98d665fbcb86e42df40bcc5e9c79b397f Mon Sep 17 00:00:00 2001
|
||||
From: Eric Blake <eblake@redhat.com>
|
||||
Date: Fri, 17 May 2024 21:50:14 -0500
|
||||
Subject: [PATCH 3/4] qio: Inherit follow_coroutine_ctx across TLS
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
RH-Author: Eric Blake <eblake@redhat.com>
|
||||
RH-MergeRequest: 375: Fix regression on nbd+tls
|
||||
RH-Jira: RHEL-33754
|
||||
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [3/4] 14ddea7e3c81898bb3fe4be51a40749d67a5c0c0 (ebblake/qemu-kvm)
|
||||
|
||||
Since qemu 8.2, the combination of NBD + TLS + iothread crashes on an
|
||||
assertion failure:
|
||||
|
||||
qemu-kvm: ../io/channel.c:534: void qio_channel_restart_read(void *): Assertion `qemu_get_current_aio_context() == qemu_coroutine_get_aio_context(co)' failed.
|
||||
|
||||
It turns out that when we removed AioContext locking, we did so by
|
||||
having NBD tell its qio channels that it wanted to opt in to
|
||||
qio_channel_set_follow_coroutine_ctx(); but while we opted in on the
|
||||
main channel, we did not opt in on the TLS wrapper channel.
|
||||
qemu-iotests has coverage of NBD+iothread and NBD+TLS, but apparently
|
||||
no coverage of NBD+TLS+iothread, or we would have noticed this
|
||||
regression sooner. (I'll add that in the next patch)
|
||||
|
||||
But while we could manually opt in to the TLS channel in nbd/server.c
|
||||
(a one-line change), it is more generic if all qio channels that wrap
|
||||
other channels inherit the follow status, in the same way that they
|
||||
inherit feature bits.
|
||||
|
||||
CC: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
CC: Daniel P. Berrangé <berrange@redhat.com>
|
||||
CC: qemu-stable@nongnu.org
|
||||
Fixes: https://issues.redhat.com/browse/RHEL-34786
|
||||
Fixes: 06e0f098 ("io: follow coroutine AioContext in qio_channel_yield()", v8.2.0)
|
||||
Signed-off-by: Eric Blake <eblake@redhat.com>
|
||||
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
Message-ID: <20240518025246.791593-5-eblake@redhat.com>
|
||||
(cherry picked from commit 199e84de1c903ba5aa1f7256310bbc4a20dd930b)
|
||||
Jira: https://issues.redhat.com/browse/RHEL-33754
|
||||
Signed-off-by: Eric Blake <eblake@redhat.com>
|
||||
---
|
||||
io/channel-tls.c | 26 +++++++++++++++-----------
|
||||
io/channel-websock.c | 1 +
|
||||
2 files changed, 16 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/io/channel-tls.c b/io/channel-tls.c
|
||||
index 58fe1aceee..a8ad89c3d1 100644
|
||||
--- a/io/channel-tls.c
|
||||
+++ b/io/channel-tls.c
|
||||
@@ -69,37 +69,40 @@ qio_channel_tls_new_server(QIOChannel *master,
|
||||
const char *aclname,
|
||||
Error **errp)
|
||||
{
|
||||
- QIOChannelTLS *ioc;
|
||||
+ QIOChannelTLS *tioc;
|
||||
+ QIOChannel *ioc;
|
||||
|
||||
- ioc = QIO_CHANNEL_TLS(object_new(TYPE_QIO_CHANNEL_TLS));
|
||||
+ tioc = QIO_CHANNEL_TLS(object_new(TYPE_QIO_CHANNEL_TLS));
|
||||
+ ioc = QIO_CHANNEL(tioc);
|
||||
|
||||
- ioc->master = master;
|
||||
+ tioc->master = master;
|
||||
+ ioc->follow_coroutine_ctx = master->follow_coroutine_ctx;
|
||||
if (qio_channel_has_feature(master, QIO_CHANNEL_FEATURE_SHUTDOWN)) {
|
||||
- qio_channel_set_feature(QIO_CHANNEL(ioc), QIO_CHANNEL_FEATURE_SHUTDOWN);
|
||||
+ qio_channel_set_feature(ioc, QIO_CHANNEL_FEATURE_SHUTDOWN);
|
||||
}
|
||||
object_ref(OBJECT(master));
|
||||
|
||||
- ioc->session = qcrypto_tls_session_new(
|
||||
+ tioc->session = qcrypto_tls_session_new(
|
||||
creds,
|
||||
NULL,
|
||||
aclname,
|
||||
QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
|
||||
errp);
|
||||
- if (!ioc->session) {
|
||||
+ if (!tioc->session) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
qcrypto_tls_session_set_callbacks(
|
||||
- ioc->session,
|
||||
+ tioc->session,
|
||||
qio_channel_tls_write_handler,
|
||||
qio_channel_tls_read_handler,
|
||||
- ioc);
|
||||
+ tioc);
|
||||
|
||||
- trace_qio_channel_tls_new_server(ioc, master, creds, aclname);
|
||||
- return ioc;
|
||||
+ trace_qio_channel_tls_new_server(tioc, master, creds, aclname);
|
||||
+ return tioc;
|
||||
|
||||
error:
|
||||
- object_unref(OBJECT(ioc));
|
||||
+ object_unref(OBJECT(tioc));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -116,6 +119,7 @@ qio_channel_tls_new_client(QIOChannel *master,
|
||||
ioc = QIO_CHANNEL(tioc);
|
||||
|
||||
tioc->master = master;
|
||||
+ ioc->follow_coroutine_ctx = master->follow_coroutine_ctx;
|
||||
if (qio_channel_has_feature(master, QIO_CHANNEL_FEATURE_SHUTDOWN)) {
|
||||
qio_channel_set_feature(ioc, QIO_CHANNEL_FEATURE_SHUTDOWN);
|
||||
}
|
||||
diff --git a/io/channel-websock.c b/io/channel-websock.c
|
||||
index a12acc27cf..de39f0d182 100644
|
||||
--- a/io/channel-websock.c
|
||||
+++ b/io/channel-websock.c
|
||||
@@ -883,6 +883,7 @@ qio_channel_websock_new_server(QIOChannel *master)
|
||||
ioc = QIO_CHANNEL(wioc);
|
||||
|
||||
wioc->master = master;
|
||||
+ ioc->follow_coroutine_ctx = master->follow_coroutine_ctx;
|
||||
if (qio_channel_has_feature(master, QIO_CHANNEL_FEATURE_SHUTDOWN)) {
|
||||
qio_channel_set_feature(ioc, QIO_CHANNEL_FEATURE_SHUTDOWN);
|
||||
}
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,38 +0,0 @@
|
||||
From aa0ad36a56cbc0528306e47112081b0db124e512 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
|
||||
Date: Wed, 5 Jun 2024 10:28:20 +0400
|
||||
Subject: [PATCH 3/4] rhel 9.4.0 machine type compat for virtio-gpu migration
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
RH-Author: Marc-André Lureau <marcandre.lureau@redhat.com>
|
||||
RH-MergeRequest: 377: virtio-gpu: fix scanout migration post-load
|
||||
RH-Jira: RHEL-36181
|
||||
RH-Acked-by: Peter Xu <peterx@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [3/3] 270e932e04eb2d730550f3a56b53cbb17f5e66f8
|
||||
|
||||
Jira: https://issues.redhat.com/browse/RHEL-36181
|
||||
|
||||
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
|
||||
---
|
||||
hw/core/machine.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/hw/core/machine.c b/hw/core/machine.c
|
||||
index a0843ab93e..c8c460c916 100644
|
||||
--- a/hw/core/machine.c
|
||||
+++ b/hw/core/machine.c
|
||||
@@ -81,6 +81,8 @@ GlobalProperty hw_compat_rhel_9_4[] = {
|
||||
{ "igb", "x-pcie-flr-init", "off" },
|
||||
/* hw_compat_rhel_9_4 jira RHEL-24045 */
|
||||
{ "virtio-mem", "dynamic-memslots", "off" },
|
||||
+ /* hw_compat_rhel_9_4 from hw_compat_8_1 */
|
||||
+ { "virtio-gpu-device", "x-scanout-vmstate-version", "1" },
|
||||
};
|
||||
const size_t hw_compat_rhel_9_4_len = G_N_ELEMENTS(hw_compat_rhel_9_4);
|
||||
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,62 +0,0 @@
|
||||
From 93cf5b82771f1d1e8182be168dae7a45d42069e9 Mon Sep 17 00:00:00 2001
|
||||
From: Igor Mammedov <imammedo@redhat.com>
|
||||
Date: Mon, 4 Mar 2024 15:39:57 +0100
|
||||
Subject: [PATCH 11/20] smbios: add smbios_add_usr_blob_size() helper
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 230: Workaround Windows failing to find 64bit SMBIOS entry point with SeaBIOS
|
||||
RH-Jira: RHEL-21705
|
||||
RH-Acked-by: MST <mst@redhat.com>
|
||||
RH-Acked-by: Ani Sinha <None>
|
||||
RH-Commit: [9/18] 8c698fb9e186d2b1d2b7f75a74305f356450ad68
|
||||
|
||||
JIRA: https://issues.redhat.com/browse/RHEL-21705
|
||||
|
||||
it will be used by follow up patch when legacy handling
|
||||
is moved out into a separate file.
|
||||
|
||||
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
|
||||
Reviewed-by: Ani Sinha <anisinha@redhat.com>
|
||||
---
|
||||
hw/smbios/smbios.c | 18 ++++++++++++++----
|
||||
1 file changed, 14 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c
|
||||
index 441517cf24..c48a290478 100644
|
||||
--- a/hw/smbios/smbios.c
|
||||
+++ b/hw/smbios/smbios.c
|
||||
@@ -1426,6 +1426,14 @@ static bool save_opt_list(size_t *ndest, char ***dest, QemuOpts *opts,
|
||||
return true;
|
||||
}
|
||||
|
||||
+static void smbios_add_usr_blob_size(size_t size)
|
||||
+{
|
||||
+ if (!usr_blobs_sizes) {
|
||||
+ usr_blobs_sizes = g_array_new(false, false, sizeof(size_t));
|
||||
+ }
|
||||
+ g_array_append_val(usr_blobs_sizes, size);
|
||||
+}
|
||||
+
|
||||
void smbios_entry_add(QemuOpts *opts, Error **errp)
|
||||
{
|
||||
const char *val;
|
||||
@@ -1473,10 +1481,12 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
|
||||
smbios_type4_count++;
|
||||
}
|
||||
|
||||
- if (!usr_blobs_sizes) {
|
||||
- usr_blobs_sizes = g_array_new(false, false, sizeof(size_t));
|
||||
- }
|
||||
- g_array_append_val(usr_blobs_sizes, size);
|
||||
+ /*
|
||||
+ * preserve blob size for legacy mode so it could build its
|
||||
+ * blobs flavor from 'usr_blobs'
|
||||
+ */
|
||||
+ smbios_add_usr_blob_size(size);
|
||||
+
|
||||
usr_blobs_len += size;
|
||||
if (size > usr_table_max) {
|
||||
usr_table_max = size;
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,309 +0,0 @@
|
||||
From 15d293b706ca6c9e6ad569becda8da5f70461c30 Mon Sep 17 00:00:00 2001
|
||||
From: Igor Mammedov <imammedo@redhat.com>
|
||||
Date: Tue, 13 Feb 2024 09:25:11 +0100
|
||||
Subject: [PATCH 09/20] smbios: avoid mangling user provided tables
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 230: Workaround Windows failing to find 64bit SMBIOS entry point with SeaBIOS
|
||||
RH-Jira: RHEL-21705
|
||||
RH-Acked-by: MST <mst@redhat.com>
|
||||
RH-Acked-by: Ani Sinha <None>
|
||||
RH-Commit: [7/18] fa2c7372f55f29e5834eee94ba98f19ea02e7a82
|
||||
|
||||
JIRA: https://issues.redhat.com/browse/RHEL-21705
|
||||
|
||||
currently smbios_entry_add() preserves internally '-smbios type='
|
||||
options but tables provided with '-smbios file=' are stored directly
|
||||
into blob that eventually will be exposed to VM. And then later
|
||||
QEMU adds default/'-smbios type' entries on top into the same blob.
|
||||
|
||||
It makes impossible to generate tables more than once, hence
|
||||
'immutable' guard was used.
|
||||
Make it possible to regenerate final blob by storing user provided
|
||||
blobs into a dedicated area (usr_blobs) and then copy it when
|
||||
composing final blob. Which also makes handling of -smbios
|
||||
options consistent.
|
||||
|
||||
As side effect of this and previous commits there is no need to
|
||||
generate legacy smbios_entries at the time options are parsed.
|
||||
Instead compose smbios_entries on demand from usr_blobs like
|
||||
it is done for non-legacy SMBIOS tables.
|
||||
|
||||
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
|
||||
Tested-by: Fiona Ebner <f.ebner@proxmox.com>
|
||||
Reviewed-by: Ani Sinha <anisinha@redhat.com>
|
||||
|
||||
Conflicts: hw/smbios/smbios.c
|
||||
caused by downstream smbios_type2_required
|
||||
|
||||
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
|
||||
---
|
||||
hw/smbios/smbios.c | 181 +++++++++++++++++++++++----------------------
|
||||
1 file changed, 93 insertions(+), 88 deletions(-)
|
||||
|
||||
diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c
|
||||
index 0c8c439859..d8d68716d4 100644
|
||||
--- a/hw/smbios/smbios.c
|
||||
+++ b/hw/smbios/smbios.c
|
||||
@@ -60,6 +60,14 @@ static bool smbios_uuid_encoded = true;
|
||||
/* Set to true for modern Windows 10 HardwareID-6 compat */
|
||||
static bool smbios_type2_required;
|
||||
|
||||
+/*
|
||||
+ * SMBIOS tables provided by user with '-smbios file=<foo>' option
|
||||
+ */
|
||||
+uint8_t *usr_blobs;
|
||||
+size_t usr_blobs_len;
|
||||
+static GArray *usr_blobs_sizes;
|
||||
+static unsigned usr_table_max;
|
||||
+static unsigned usr_table_cnt;
|
||||
|
||||
uint8_t *smbios_tables;
|
||||
size_t smbios_tables_len;
|
||||
@@ -70,7 +78,6 @@ static SmbiosEntryPointType smbios_ep_type = SMBIOS_ENTRY_POINT_TYPE_32;
|
||||
static SmbiosEntryPoint ep;
|
||||
|
||||
static int smbios_type4_count = 0;
|
||||
-static bool smbios_immutable;
|
||||
static bool smbios_have_defaults;
|
||||
static uint32_t smbios_cpuid_version, smbios_cpuid_features;
|
||||
|
||||
@@ -617,9 +624,8 @@ static void smbios_build_type_1_fields(void)
|
||||
|
||||
uint8_t *smbios_get_table_legacy(uint32_t expected_t4_count, size_t *length)
|
||||
{
|
||||
- /* drop unwanted version of command-line file blob(s) */
|
||||
- g_free(smbios_tables);
|
||||
- smbios_tables = NULL;
|
||||
+ int i;
|
||||
+ size_t usr_offset;
|
||||
|
||||
/* also complain if fields were given for types > 1 */
|
||||
if (find_next_bit(have_fields_bitmap,
|
||||
@@ -629,12 +635,33 @@ uint8_t *smbios_get_table_legacy(uint32_t expected_t4_count, size_t *length)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
- if (!smbios_immutable) {
|
||||
- smbios_build_type_0_fields();
|
||||
- smbios_build_type_1_fields();
|
||||
- smbios_validate_table(expected_t4_count);
|
||||
- smbios_immutable = true;
|
||||
+ g_free(smbios_entries);
|
||||
+ smbios_entries_len = sizeof(uint16_t);
|
||||
+ smbios_entries = g_malloc0(smbios_entries_len);
|
||||
+
|
||||
+ for (i = 0, usr_offset = 0; usr_blobs_sizes && i < usr_blobs_sizes->len;
|
||||
+ i++)
|
||||
+ {
|
||||
+ struct smbios_table *table;
|
||||
+ struct smbios_structure_header *header;
|
||||
+ size_t size = g_array_index(usr_blobs_sizes, size_t, i);
|
||||
+
|
||||
+ header = (struct smbios_structure_header *)(usr_blobs + usr_offset);
|
||||
+ smbios_entries = g_realloc(smbios_entries, smbios_entries_len +
|
||||
+ size + sizeof(*table));
|
||||
+ table = (struct smbios_table *)(smbios_entries + smbios_entries_len);
|
||||
+ table->header.type = SMBIOS_TABLE_ENTRY;
|
||||
+ table->header.length = cpu_to_le16(sizeof(*table) + size);
|
||||
+ memcpy(table->data, header, size);
|
||||
+ smbios_entries_len += sizeof(*table) + size;
|
||||
+ (*(uint16_t *)smbios_entries) =
|
||||
+ cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
|
||||
+ usr_offset += size;
|
||||
}
|
||||
+
|
||||
+ smbios_build_type_0_fields();
|
||||
+ smbios_build_type_1_fields();
|
||||
+ smbios_validate_table(expected_t4_count);
|
||||
*length = smbios_entries_len;
|
||||
return smbios_entries;
|
||||
}
|
||||
@@ -1232,68 +1259,68 @@ void smbios_get_tables(MachineState *ms,
|
||||
{
|
||||
unsigned i, dimm_cnt, offset;
|
||||
|
||||
- /* drop unwanted (legacy) version of command-line file blob(s) */
|
||||
- g_free(smbios_entries);
|
||||
- smbios_entries = NULL;
|
||||
+ g_free(smbios_tables);
|
||||
+ smbios_tables = g_memdup2(usr_blobs, usr_blobs_len);
|
||||
+ smbios_tables_len = usr_blobs_len;
|
||||
+ smbios_table_max = usr_table_max;
|
||||
+ smbios_table_cnt = usr_table_cnt;
|
||||
|
||||
- if (!smbios_immutable) {
|
||||
- smbios_build_type_0_table();
|
||||
- smbios_build_type_1_table();
|
||||
- smbios_build_type_2_table();
|
||||
- smbios_build_type_3_table();
|
||||
+ smbios_build_type_0_table();
|
||||
+ smbios_build_type_1_table();
|
||||
+ smbios_build_type_2_table();
|
||||
+ smbios_build_type_3_table();
|
||||
|
||||
- assert(ms->smp.sockets >= 1);
|
||||
+ assert(ms->smp.sockets >= 1);
|
||||
|
||||
- for (i = 0; i < ms->smp.sockets; i++) {
|
||||
- smbios_build_type_4_table(ms, i);
|
||||
- }
|
||||
+ for (i = 0; i < ms->smp.sockets; i++) {
|
||||
+ smbios_build_type_4_table(ms, i);
|
||||
+ }
|
||||
|
||||
- smbios_build_type_8_table();
|
||||
- smbios_build_type_9_table(errp);
|
||||
- smbios_build_type_11_table();
|
||||
+ smbios_build_type_8_table();
|
||||
+ smbios_build_type_9_table(errp);
|
||||
+ smbios_build_type_11_table();
|
||||
|
||||
#define MAX_DIMM_SZ (16 * GiB)
|
||||
#define GET_DIMM_SZ ((i < dimm_cnt - 1) ? MAX_DIMM_SZ \
|
||||
: ((current_machine->ram_size - 1) % MAX_DIMM_SZ) + 1)
|
||||
|
||||
- dimm_cnt = QEMU_ALIGN_UP(current_machine->ram_size, MAX_DIMM_SZ) / MAX_DIMM_SZ;
|
||||
+ dimm_cnt = QEMU_ALIGN_UP(current_machine->ram_size, MAX_DIMM_SZ) /
|
||||
+ MAX_DIMM_SZ;
|
||||
|
||||
- /*
|
||||
- * The offset determines if we need to keep additional space between
|
||||
- * table 17 and table 19 header handle numbers so that they do
|
||||
- * not overlap. For example, for a VM with larger than 8 TB guest
|
||||
- * memory and DIMM like chunks of 16 GiB, the default space between
|
||||
- * the two tables (T19_BASE - T17_BASE = 512) is not enough.
|
||||
- */
|
||||
- offset = (dimm_cnt > (T19_BASE - T17_BASE)) ? \
|
||||
- dimm_cnt - (T19_BASE - T17_BASE) : 0;
|
||||
+ /*
|
||||
+ * The offset determines if we need to keep additional space between
|
||||
+ * table 17 and table 19 header handle numbers so that they do
|
||||
+ * not overlap. For example, for a VM with larger than 8 TB guest
|
||||
+ * memory and DIMM like chunks of 16 GiB, the default space between
|
||||
+ * the two tables (T19_BASE - T17_BASE = 512) is not enough.
|
||||
+ */
|
||||
+ offset = (dimm_cnt > (T19_BASE - T17_BASE)) ? \
|
||||
+ dimm_cnt - (T19_BASE - T17_BASE) : 0;
|
||||
|
||||
- smbios_build_type_16_table(dimm_cnt);
|
||||
+ smbios_build_type_16_table(dimm_cnt);
|
||||
|
||||
- for (i = 0; i < dimm_cnt; i++) {
|
||||
- smbios_build_type_17_table(i, GET_DIMM_SZ);
|
||||
- }
|
||||
+ for (i = 0; i < dimm_cnt; i++) {
|
||||
+ smbios_build_type_17_table(i, GET_DIMM_SZ);
|
||||
+ }
|
||||
|
||||
- for (i = 0; i < mem_array_size; i++) {
|
||||
- smbios_build_type_19_table(i, offset, mem_array[i].address,
|
||||
- mem_array[i].length);
|
||||
- }
|
||||
+ for (i = 0; i < mem_array_size; i++) {
|
||||
+ smbios_build_type_19_table(i, offset, mem_array[i].address,
|
||||
+ mem_array[i].length);
|
||||
+ }
|
||||
|
||||
- /*
|
||||
- * make sure 16 bit handle numbers in the headers of tables 19
|
||||
- * and 32 do not overlap.
|
||||
- */
|
||||
- assert((mem_array_size + offset) < (T32_BASE - T19_BASE));
|
||||
+ /*
|
||||
+ * make sure 16 bit handle numbers in the headers of tables 19
|
||||
+ * and 32 do not overlap.
|
||||
+ */
|
||||
+ assert((mem_array_size + offset) < (T32_BASE - T19_BASE));
|
||||
|
||||
- smbios_build_type_32_table();
|
||||
- smbios_build_type_38_table();
|
||||
- smbios_build_type_41_table(errp);
|
||||
- smbios_build_type_127_table();
|
||||
+ smbios_build_type_32_table();
|
||||
+ smbios_build_type_38_table();
|
||||
+ smbios_build_type_41_table(errp);
|
||||
+ smbios_build_type_127_table();
|
||||
|
||||
- smbios_validate_table(ms->smp.sockets);
|
||||
- smbios_entry_point_setup();
|
||||
- smbios_immutable = true;
|
||||
- }
|
||||
+ smbios_validate_table(ms->smp.sockets);
|
||||
+ smbios_entry_point_setup();
|
||||
|
||||
/* return tables blob and entry point (anchor), and their sizes */
|
||||
*tables = smbios_tables;
|
||||
@@ -1393,13 +1420,10 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
|
||||
{
|
||||
const char *val;
|
||||
|
||||
- assert(!smbios_immutable);
|
||||
-
|
||||
val = qemu_opt_get(opts, "file");
|
||||
if (val) {
|
||||
struct smbios_structure_header *header;
|
||||
- int size;
|
||||
- struct smbios_table *table; /* legacy mode only */
|
||||
+ size_t size;
|
||||
|
||||
if (!qemu_opts_validate(opts, qemu_smbios_file_opts, errp)) {
|
||||
return;
|
||||
@@ -1416,9 +1440,9 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
|
||||
* (except in legacy mode, where the second '\0' is implicit and
|
||||
* will be inserted by the BIOS).
|
||||
*/
|
||||
- smbios_tables = g_realloc(smbios_tables, smbios_tables_len + size);
|
||||
- header = (struct smbios_structure_header *)(smbios_tables +
|
||||
- smbios_tables_len);
|
||||
+ usr_blobs = g_realloc(usr_blobs, usr_blobs_len + size);
|
||||
+ header = (struct smbios_structure_header *)(usr_blobs +
|
||||
+ usr_blobs_len);
|
||||
|
||||
if (load_image_size(val, (uint8_t *)header, size) != size) {
|
||||
error_setg(errp, "Failed to load SMBIOS file %s", val);
|
||||
@@ -1439,34 +1463,15 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
|
||||
smbios_type4_count++;
|
||||
}
|
||||
|
||||
- smbios_tables_len += size;
|
||||
- if (size > smbios_table_max) {
|
||||
- smbios_table_max = size;
|
||||
+ if (!usr_blobs_sizes) {
|
||||
+ usr_blobs_sizes = g_array_new(false, false, sizeof(size_t));
|
||||
}
|
||||
- smbios_table_cnt++;
|
||||
-
|
||||
- /* add a copy of the newly loaded blob to legacy smbios_entries */
|
||||
- /* NOTE: This code runs before smbios_set_defaults(), so we don't
|
||||
- * yet know which mode (legacy vs. aggregate-table) will be
|
||||
- * required. We therefore add the binary blob to both legacy
|
||||
- * (smbios_entries) and aggregate (smbios_tables) tables, and
|
||||
- * delete the one we don't need from smbios_set_defaults(),
|
||||
- * once we know which machine version has been requested.
|
||||
- */
|
||||
- if (!smbios_entries) {
|
||||
- smbios_entries_len = sizeof(uint16_t);
|
||||
- smbios_entries = g_malloc0(smbios_entries_len);
|
||||
+ g_array_append_val(usr_blobs_sizes, size);
|
||||
+ usr_blobs_len += size;
|
||||
+ if (size > usr_table_max) {
|
||||
+ usr_table_max = size;
|
||||
}
|
||||
- smbios_entries = g_realloc(smbios_entries, smbios_entries_len +
|
||||
- size + sizeof(*table));
|
||||
- table = (struct smbios_table *)(smbios_entries + smbios_entries_len);
|
||||
- table->header.type = SMBIOS_TABLE_ENTRY;
|
||||
- table->header.length = cpu_to_le16(sizeof(*table) + size);
|
||||
- memcpy(table->data, header, size);
|
||||
- smbios_entries_len += sizeof(*table) + size;
|
||||
- (*(uint16_t *)smbios_entries) =
|
||||
- cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
|
||||
- /* end: add a copy of the newly loaded blob to legacy smbios_entries */
|
||||
+ usr_table_cnt++;
|
||||
|
||||
return;
|
||||
}
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,517 +0,0 @@
|
||||
From 7ebb314a4f81d6d1a7dd4980b757fb5e556f5837 Mon Sep 17 00:00:00 2001
|
||||
From: Igor Mammedov <imammedo@redhat.com>
|
||||
Date: Tue, 13 Feb 2024 16:45:18 +0100
|
||||
Subject: [PATCH 13/20] smbios: build legacy mode code only for 'pc' machine
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 230: Workaround Windows failing to find 64bit SMBIOS entry point with SeaBIOS
|
||||
RH-Jira: RHEL-21705
|
||||
RH-Acked-by: MST <mst@redhat.com>
|
||||
RH-Acked-by: Ani Sinha <None>
|
||||
RH-Commit: [11/18] 06e639be03e0d151fb9bcf5f728388edcb84219a
|
||||
|
||||
JIRA: https://issues.redhat.com/browse/RHEL-21705
|
||||
|
||||
basically moving code around without functional change.
|
||||
And exposing some symbols so that they could be shared
|
||||
between smbbios.c and new smbios_legacy.c
|
||||
|
||||
plus some meson magic to build smbios_legacy.c only
|
||||
for 'pc' machine and otherwise replace it with stub
|
||||
if not selected.
|
||||
|
||||
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
|
||||
Reviewed-by: Ani Sinha <anisinha@redhat.com>
|
||||
|
||||
Conflicts: hw/smbios/smbios.c
|
||||
context change due to downstream smbios_type2_required
|
||||
|
||||
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
|
||||
---
|
||||
hw/i386/Kconfig | 1 +
|
||||
hw/smbios/Kconfig | 2 +
|
||||
hw/smbios/meson.build | 5 +
|
||||
hw/smbios/smbios.c | 163 +-----------------------------
|
||||
hw/smbios/smbios_legacy.c | 179 +++++++++++++++++++++++++++++++++
|
||||
hw/smbios/smbios_legacy_stub.c | 15 +++
|
||||
include/hw/firmware/smbios.h | 5 +
|
||||
7 files changed, 208 insertions(+), 162 deletions(-)
|
||||
create mode 100644 hw/smbios/smbios_legacy.c
|
||||
create mode 100644 hw/smbios/smbios_legacy_stub.c
|
||||
|
||||
diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig
|
||||
index a1846be6f7..a6ee052f9a 100644
|
||||
--- a/hw/i386/Kconfig
|
||||
+++ b/hw/i386/Kconfig
|
||||
@@ -76,6 +76,7 @@ config I440FX
|
||||
select PIIX
|
||||
select DIMM
|
||||
select SMBIOS
|
||||
+ select SMBIOS_LEGACY
|
||||
select FW_CFG_DMA
|
||||
|
||||
config ISAPC
|
||||
diff --git a/hw/smbios/Kconfig b/hw/smbios/Kconfig
|
||||
index 553adf4bfc..8d989a2f1b 100644
|
||||
--- a/hw/smbios/Kconfig
|
||||
+++ b/hw/smbios/Kconfig
|
||||
@@ -1,2 +1,4 @@
|
||||
config SMBIOS
|
||||
bool
|
||||
+config SMBIOS_LEGACY
|
||||
+ bool
|
||||
diff --git a/hw/smbios/meson.build b/hw/smbios/meson.build
|
||||
index 6eeae4b35c..fcac1d7490 100644
|
||||
--- a/hw/smbios/meson.build
|
||||
+++ b/hw/smbios/meson.build
|
||||
@@ -4,10 +4,15 @@ smbios_ss.add(when: 'CONFIG_IPMI',
|
||||
if_true: files('smbios_type_38.c'),
|
||||
if_false: files('smbios_type_38-stub.c'))
|
||||
|
||||
+smbios_ss.add(when: 'CONFIG_SMBIOS_LEGACY',
|
||||
+ if_true: files('smbios_legacy.c'),
|
||||
+ if_false: files('smbios_legacy_stub.c'))
|
||||
+
|
||||
system_ss.add_all(when: 'CONFIG_SMBIOS', if_true: smbios_ss)
|
||||
system_ss.add(when: 'CONFIG_SMBIOS', if_false: files('smbios-stub.c'))
|
||||
|
||||
system_ss.add(when: 'CONFIG_ALL', if_true: files(
|
||||
'smbios-stub.c',
|
||||
'smbios_type_38-stub.c',
|
||||
+ 'smbios_legacy_stub.c',
|
||||
))
|
||||
diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c
|
||||
index eb9927335d..e40204550e 100644
|
||||
--- a/hw/smbios/smbios.c
|
||||
+++ b/hw/smbios/smbios.c
|
||||
@@ -31,31 +31,7 @@
|
||||
#include "hw/pci/pci_device.h"
|
||||
#include "smbios_build.h"
|
||||
|
||||
-/* legacy structures and constants for <= 2.0 machines */
|
||||
-struct smbios_header {
|
||||
- uint16_t length;
|
||||
- uint8_t type;
|
||||
-} QEMU_PACKED;
|
||||
-
|
||||
-struct smbios_field {
|
||||
- struct smbios_header header;
|
||||
- uint8_t type;
|
||||
- uint16_t offset;
|
||||
- uint8_t data[];
|
||||
-} QEMU_PACKED;
|
||||
-
|
||||
-struct smbios_table {
|
||||
- struct smbios_header header;
|
||||
- uint8_t data[];
|
||||
-} QEMU_PACKED;
|
||||
-
|
||||
-#define SMBIOS_FIELD_ENTRY 0
|
||||
-#define SMBIOS_TABLE_ENTRY 1
|
||||
-
|
||||
-static uint8_t *smbios_entries;
|
||||
-static size_t smbios_entries_len;
|
||||
static bool smbios_uuid_encoded = true;
|
||||
-/* end: legacy structures & constants for <= 2.0 machines */
|
||||
|
||||
/* Set to true for modern Windows 10 HardwareID-6 compat */
|
||||
static bool smbios_type2_required;
|
||||
@@ -65,7 +41,6 @@ static bool smbios_type2_required;
|
||||
*/
|
||||
uint8_t *usr_blobs;
|
||||
size_t usr_blobs_len;
|
||||
-static GArray *usr_blobs_sizes;
|
||||
static unsigned usr_table_max;
|
||||
static unsigned usr_table_cnt;
|
||||
|
||||
@@ -531,7 +506,7 @@ static void smbios_check_type4_count(uint32_t expected_t4_count)
|
||||
}
|
||||
}
|
||||
|
||||
-static void smbios_validate_table(void)
|
||||
+void smbios_validate_table(void)
|
||||
{
|
||||
if (smbios_ep_type == SMBIOS_ENTRY_POINT_TYPE_32 &&
|
||||
smbios_tables_len > SMBIOS_21_MAX_TABLES_LEN) {
|
||||
@@ -541,134 +516,6 @@ static void smbios_validate_table(void)
|
||||
}
|
||||
}
|
||||
|
||||
-
|
||||
-/* legacy setup functions for <= 2.0 machines */
|
||||
-static void smbios_add_field(int type, int offset, const void *data, size_t len)
|
||||
-{
|
||||
- struct smbios_field *field;
|
||||
-
|
||||
- if (!smbios_entries) {
|
||||
- smbios_entries_len = sizeof(uint16_t);
|
||||
- smbios_entries = g_malloc0(smbios_entries_len);
|
||||
- }
|
||||
- smbios_entries = g_realloc(smbios_entries, smbios_entries_len +
|
||||
- sizeof(*field) + len);
|
||||
- field = (struct smbios_field *)(smbios_entries + smbios_entries_len);
|
||||
- field->header.type = SMBIOS_FIELD_ENTRY;
|
||||
- field->header.length = cpu_to_le16(sizeof(*field) + len);
|
||||
-
|
||||
- field->type = type;
|
||||
- field->offset = cpu_to_le16(offset);
|
||||
- memcpy(field->data, data, len);
|
||||
-
|
||||
- smbios_entries_len += sizeof(*field) + len;
|
||||
- (*(uint16_t *)smbios_entries) =
|
||||
- cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
|
||||
-}
|
||||
-
|
||||
-static void smbios_maybe_add_str(int type, int offset, const char *data)
|
||||
-{
|
||||
- if (data) {
|
||||
- smbios_add_field(type, offset, data, strlen(data) + 1);
|
||||
- }
|
||||
-}
|
||||
-
|
||||
-static void smbios_build_type_0_fields(void)
|
||||
-{
|
||||
- smbios_maybe_add_str(0, offsetof(struct smbios_type_0, vendor_str),
|
||||
- smbios_type0.vendor);
|
||||
- smbios_maybe_add_str(0, offsetof(struct smbios_type_0, bios_version_str),
|
||||
- smbios_type0.version);
|
||||
- smbios_maybe_add_str(0, offsetof(struct smbios_type_0,
|
||||
- bios_release_date_str),
|
||||
- smbios_type0.date);
|
||||
- if (smbios_type0.have_major_minor) {
|
||||
- smbios_add_field(0, offsetof(struct smbios_type_0,
|
||||
- system_bios_major_release),
|
||||
- &smbios_type0.major, 1);
|
||||
- smbios_add_field(0, offsetof(struct smbios_type_0,
|
||||
- system_bios_minor_release),
|
||||
- &smbios_type0.minor, 1);
|
||||
- }
|
||||
-}
|
||||
-
|
||||
-static void smbios_build_type_1_fields(void)
|
||||
-{
|
||||
- smbios_maybe_add_str(1, offsetof(struct smbios_type_1, manufacturer_str),
|
||||
- smbios_type1.manufacturer);
|
||||
- smbios_maybe_add_str(1, offsetof(struct smbios_type_1, product_name_str),
|
||||
- smbios_type1.product);
|
||||
- smbios_maybe_add_str(1, offsetof(struct smbios_type_1, version_str),
|
||||
- smbios_type1.version);
|
||||
- smbios_maybe_add_str(1, offsetof(struct smbios_type_1, serial_number_str),
|
||||
- smbios_type1.serial);
|
||||
- smbios_maybe_add_str(1, offsetof(struct smbios_type_1, sku_number_str),
|
||||
- smbios_type1.sku);
|
||||
- smbios_maybe_add_str(1, offsetof(struct smbios_type_1, family_str),
|
||||
- smbios_type1.family);
|
||||
- if (qemu_uuid_set) {
|
||||
- /* We don't encode the UUID in the "wire format" here because this
|
||||
- * function is for legacy mode and needs to keep the guest ABI, and
|
||||
- * because we don't know what's the SMBIOS version advertised by the
|
||||
- * BIOS.
|
||||
- */
|
||||
- smbios_add_field(1, offsetof(struct smbios_type_1, uuid),
|
||||
- &qemu_uuid, 16);
|
||||
- }
|
||||
-}
|
||||
-
|
||||
-uint8_t *smbios_get_table_legacy(size_t *length)
|
||||
-{
|
||||
- int i;
|
||||
- size_t usr_offset;
|
||||
-
|
||||
- /* also complain if fields were given for types > 1 */
|
||||
- if (find_next_bit(smbios_have_fields_bitmap,
|
||||
- SMBIOS_MAX_TYPE + 1, 2) < SMBIOS_MAX_TYPE + 1) {
|
||||
- error_report("can't process fields for smbios "
|
||||
- "types > 1 on machine versions < 2.1!");
|
||||
- exit(1);
|
||||
- }
|
||||
-
|
||||
- if (test_bit(4, smbios_have_binfile_bitmap)) {
|
||||
- error_report("can't process table for smbios "
|
||||
- "type 4 on machine versions < 2.1!");
|
||||
- exit(1);
|
||||
- }
|
||||
-
|
||||
- g_free(smbios_entries);
|
||||
- smbios_entries_len = sizeof(uint16_t);
|
||||
- smbios_entries = g_malloc0(smbios_entries_len);
|
||||
-
|
||||
- for (i = 0, usr_offset = 0; usr_blobs_sizes && i < usr_blobs_sizes->len;
|
||||
- i++)
|
||||
- {
|
||||
- struct smbios_table *table;
|
||||
- struct smbios_structure_header *header;
|
||||
- size_t size = g_array_index(usr_blobs_sizes, size_t, i);
|
||||
-
|
||||
- header = (struct smbios_structure_header *)(usr_blobs + usr_offset);
|
||||
- smbios_entries = g_realloc(smbios_entries, smbios_entries_len +
|
||||
- size + sizeof(*table));
|
||||
- table = (struct smbios_table *)(smbios_entries + smbios_entries_len);
|
||||
- table->header.type = SMBIOS_TABLE_ENTRY;
|
||||
- table->header.length = cpu_to_le16(sizeof(*table) + size);
|
||||
- memcpy(table->data, header, size);
|
||||
- smbios_entries_len += sizeof(*table) + size;
|
||||
- (*(uint16_t *)smbios_entries) =
|
||||
- cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
|
||||
- usr_offset += size;
|
||||
- }
|
||||
-
|
||||
- smbios_build_type_0_fields();
|
||||
- smbios_build_type_1_fields();
|
||||
- smbios_validate_table();
|
||||
- *length = smbios_entries_len;
|
||||
- return smbios_entries;
|
||||
-}
|
||||
-/* end: legacy setup functions for <= 2.0 machines */
|
||||
-
|
||||
-
|
||||
bool smbios_skip_table(uint8_t type, bool required_table)
|
||||
{
|
||||
if (test_bit(type, smbios_have_binfile_bitmap)) {
|
||||
@@ -1418,14 +1265,6 @@ static bool save_opt_list(size_t *ndest, char ***dest, QemuOpts *opts,
|
||||
return true;
|
||||
}
|
||||
|
||||
-static void smbios_add_usr_blob_size(size_t size)
|
||||
-{
|
||||
- if (!usr_blobs_sizes) {
|
||||
- usr_blobs_sizes = g_array_new(false, false, sizeof(size_t));
|
||||
- }
|
||||
- g_array_append_val(usr_blobs_sizes, size);
|
||||
-}
|
||||
-
|
||||
void smbios_entry_add(QemuOpts *opts, Error **errp)
|
||||
{
|
||||
const char *val;
|
||||
diff --git a/hw/smbios/smbios_legacy.c b/hw/smbios/smbios_legacy.c
|
||||
new file mode 100644
|
||||
index 0000000000..21f143e738
|
||||
--- /dev/null
|
||||
+++ b/hw/smbios/smbios_legacy.c
|
||||
@@ -0,0 +1,179 @@
|
||||
+/*
|
||||
+ * SMBIOS legacy support
|
||||
+ *
|
||||
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
|
||||
+ * Copyright (C) 2013 Red Hat, Inc.
|
||||
+ *
|
||||
+ * Authors:
|
||||
+ * Alex Williamson <alex.williamson@hp.com>
|
||||
+ * Markus Armbruster <armbru@redhat.com>
|
||||
+ *
|
||||
+ * This work is licensed under the terms of the GNU GPL, version 2. See
|
||||
+ * the COPYING file in the top-level directory.
|
||||
+ *
|
||||
+ * Contributions after 2012-01-13 are licensed under the terms of the
|
||||
+ * GNU GPL, version 2 or (at your option) any later version.
|
||||
+ */
|
||||
+
|
||||
+#include "qemu/osdep.h"
|
||||
+#include "qemu/bswap.h"
|
||||
+#include "hw/firmware/smbios.h"
|
||||
+#include "sysemu/sysemu.h"
|
||||
+#include "qemu/error-report.h"
|
||||
+
|
||||
+struct smbios_header {
|
||||
+ uint16_t length;
|
||||
+ uint8_t type;
|
||||
+} QEMU_PACKED;
|
||||
+
|
||||
+struct smbios_field {
|
||||
+ struct smbios_header header;
|
||||
+ uint8_t type;
|
||||
+ uint16_t offset;
|
||||
+ uint8_t data[];
|
||||
+} QEMU_PACKED;
|
||||
+
|
||||
+struct smbios_table {
|
||||
+ struct smbios_header header;
|
||||
+ uint8_t data[];
|
||||
+} QEMU_PACKED;
|
||||
+
|
||||
+#define SMBIOS_FIELD_ENTRY 0
|
||||
+#define SMBIOS_TABLE_ENTRY 1
|
||||
+
|
||||
+static uint8_t *smbios_entries;
|
||||
+static size_t smbios_entries_len;
|
||||
+GArray *usr_blobs_sizes;
|
||||
+
|
||||
+void smbios_add_usr_blob_size(size_t size)
|
||||
+{
|
||||
+ if (!usr_blobs_sizes) {
|
||||
+ usr_blobs_sizes = g_array_new(false, false, sizeof(size_t));
|
||||
+ }
|
||||
+ g_array_append_val(usr_blobs_sizes, size);
|
||||
+}
|
||||
+
|
||||
+static void smbios_add_field(int type, int offset, const void *data, size_t len)
|
||||
+{
|
||||
+ struct smbios_field *field;
|
||||
+
|
||||
+ if (!smbios_entries) {
|
||||
+ smbios_entries_len = sizeof(uint16_t);
|
||||
+ smbios_entries = g_malloc0(smbios_entries_len);
|
||||
+ }
|
||||
+ smbios_entries = g_realloc(smbios_entries, smbios_entries_len +
|
||||
+ sizeof(*field) + len);
|
||||
+ field = (struct smbios_field *)(smbios_entries + smbios_entries_len);
|
||||
+ field->header.type = SMBIOS_FIELD_ENTRY;
|
||||
+ field->header.length = cpu_to_le16(sizeof(*field) + len);
|
||||
+
|
||||
+ field->type = type;
|
||||
+ field->offset = cpu_to_le16(offset);
|
||||
+ memcpy(field->data, data, len);
|
||||
+
|
||||
+ smbios_entries_len += sizeof(*field) + len;
|
||||
+ (*(uint16_t *)smbios_entries) =
|
||||
+ cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
|
||||
+}
|
||||
+
|
||||
+static void smbios_maybe_add_str(int type, int offset, const char *data)
|
||||
+{
|
||||
+ if (data) {
|
||||
+ smbios_add_field(type, offset, data, strlen(data) + 1);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void smbios_build_type_0_fields(void)
|
||||
+{
|
||||
+ smbios_maybe_add_str(0, offsetof(struct smbios_type_0, vendor_str),
|
||||
+ smbios_type0.vendor);
|
||||
+ smbios_maybe_add_str(0, offsetof(struct smbios_type_0, bios_version_str),
|
||||
+ smbios_type0.version);
|
||||
+ smbios_maybe_add_str(0, offsetof(struct smbios_type_0,
|
||||
+ bios_release_date_str),
|
||||
+ smbios_type0.date);
|
||||
+ if (smbios_type0.have_major_minor) {
|
||||
+ smbios_add_field(0, offsetof(struct smbios_type_0,
|
||||
+ system_bios_major_release),
|
||||
+ &smbios_type0.major, 1);
|
||||
+ smbios_add_field(0, offsetof(struct smbios_type_0,
|
||||
+ system_bios_minor_release),
|
||||
+ &smbios_type0.minor, 1);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void smbios_build_type_1_fields(void)
|
||||
+{
|
||||
+ smbios_maybe_add_str(1, offsetof(struct smbios_type_1, manufacturer_str),
|
||||
+ smbios_type1.manufacturer);
|
||||
+ smbios_maybe_add_str(1, offsetof(struct smbios_type_1, product_name_str),
|
||||
+ smbios_type1.product);
|
||||
+ smbios_maybe_add_str(1, offsetof(struct smbios_type_1, version_str),
|
||||
+ smbios_type1.version);
|
||||
+ smbios_maybe_add_str(1, offsetof(struct smbios_type_1, serial_number_str),
|
||||
+ smbios_type1.serial);
|
||||
+ smbios_maybe_add_str(1, offsetof(struct smbios_type_1, sku_number_str),
|
||||
+ smbios_type1.sku);
|
||||
+ smbios_maybe_add_str(1, offsetof(struct smbios_type_1, family_str),
|
||||
+ smbios_type1.family);
|
||||
+ if (qemu_uuid_set) {
|
||||
+ /*
|
||||
+ * We don't encode the UUID in the "wire format" here because this
|
||||
+ * function is for legacy mode and needs to keep the guest ABI, and
|
||||
+ * because we don't know what's the SMBIOS version advertised by the
|
||||
+ * BIOS.
|
||||
+ */
|
||||
+ smbios_add_field(1, offsetof(struct smbios_type_1, uuid),
|
||||
+ &qemu_uuid, 16);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+uint8_t *smbios_get_table_legacy(size_t *length)
|
||||
+{
|
||||
+ int i;
|
||||
+ size_t usr_offset;
|
||||
+
|
||||
+ /* complain if fields were given for types > 1 */
|
||||
+ if (find_next_bit(smbios_have_fields_bitmap,
|
||||
+ SMBIOS_MAX_TYPE + 1, 2) < SMBIOS_MAX_TYPE + 1) {
|
||||
+ error_report("can't process fields for smbios "
|
||||
+ "types > 1 on machine versions < 2.1!");
|
||||
+ exit(1);
|
||||
+ }
|
||||
+
|
||||
+ if (test_bit(4, smbios_have_binfile_bitmap)) {
|
||||
+ error_report("can't process table for smbios "
|
||||
+ "type 4 on machine versions < 2.1!");
|
||||
+ exit(1);
|
||||
+ }
|
||||
+
|
||||
+ g_free(smbios_entries);
|
||||
+ smbios_entries_len = sizeof(uint16_t);
|
||||
+ smbios_entries = g_malloc0(smbios_entries_len);
|
||||
+
|
||||
+ for (i = 0, usr_offset = 0; usr_blobs_sizes && i < usr_blobs_sizes->len;
|
||||
+ i++)
|
||||
+ {
|
||||
+ struct smbios_table *table;
|
||||
+ struct smbios_structure_header *header;
|
||||
+ size_t size = g_array_index(usr_blobs_sizes, size_t, i);
|
||||
+
|
||||
+ header = (struct smbios_structure_header *)(usr_blobs + usr_offset);
|
||||
+ smbios_entries = g_realloc(smbios_entries, smbios_entries_len +
|
||||
+ size + sizeof(*table));
|
||||
+ table = (struct smbios_table *)(smbios_entries + smbios_entries_len);
|
||||
+ table->header.type = SMBIOS_TABLE_ENTRY;
|
||||
+ table->header.length = cpu_to_le16(sizeof(*table) + size);
|
||||
+ memcpy(table->data, header, size);
|
||||
+ smbios_entries_len += sizeof(*table) + size;
|
||||
+ (*(uint16_t *)smbios_entries) =
|
||||
+ cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
|
||||
+ usr_offset += size;
|
||||
+ }
|
||||
+
|
||||
+ smbios_build_type_0_fields();
|
||||
+ smbios_build_type_1_fields();
|
||||
+ smbios_validate_table();
|
||||
+ *length = smbios_entries_len;
|
||||
+ return smbios_entries;
|
||||
+}
|
||||
diff --git a/hw/smbios/smbios_legacy_stub.c b/hw/smbios/smbios_legacy_stub.c
|
||||
new file mode 100644
|
||||
index 0000000000..f29b15316c
|
||||
--- /dev/null
|
||||
+++ b/hw/smbios/smbios_legacy_stub.c
|
||||
@@ -0,0 +1,15 @@
|
||||
+/*
|
||||
+ * IPMI SMBIOS firmware handling
|
||||
+ *
|
||||
+ * Copyright (c) 2024 Igor Mammedov, Red Hat, Inc.
|
||||
+ *
|
||||
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
+ * See the COPYING file in the top-level directory.
|
||||
+ */
|
||||
+
|
||||
+#include "qemu/osdep.h"
|
||||
+#include "hw/firmware/smbios.h"
|
||||
+
|
||||
+void smbios_add_usr_blob_size(size_t size)
|
||||
+{
|
||||
+}
|
||||
diff --git a/include/hw/firmware/smbios.h b/include/hw/firmware/smbios.h
|
||||
index 333de0d5fc..92e9aba415 100644
|
||||
--- a/include/hw/firmware/smbios.h
|
||||
+++ b/include/hw/firmware/smbios.h
|
||||
@@ -17,6 +17,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
+extern uint8_t *usr_blobs;
|
||||
+extern GArray *usr_blobs_sizes;
|
||||
+
|
||||
typedef struct {
|
||||
const char *vendor, *version, *date;
|
||||
bool have_major_minor, uefi;
|
||||
@@ -323,6 +326,8 @@ struct smbios_type_127 {
|
||||
struct smbios_structure_header header;
|
||||
} QEMU_PACKED;
|
||||
|
||||
+void smbios_validate_table(void);
|
||||
+void smbios_add_usr_blob_size(size_t size);
|
||||
void smbios_entry_add(QemuOpts *opts, Error **errp);
|
||||
void smbios_set_cpuid(uint32_t version, uint32_t features);
|
||||
void smbios_set_defaults(const char *manufacturer, const char *product,
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,65 +0,0 @@
|
||||
From 07f6ef2d032cda3e746ac2477c0a9bc1ac636f45 Mon Sep 17 00:00:00 2001
|
||||
From: Igor Mammedov <imammedo@redhat.com>
|
||||
Date: Fri, 29 Dec 2023 14:08:13 +0100
|
||||
Subject: [PATCH 06/20] smbios: cleanup smbios_get_tables() from legacy
|
||||
handling
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 230: Workaround Windows failing to find 64bit SMBIOS entry point with SeaBIOS
|
||||
RH-Jira: RHEL-21705
|
||||
RH-Acked-by: MST <mst@redhat.com>
|
||||
RH-Acked-by: Ani Sinha <None>
|
||||
RH-Commit: [4/18] a5e09ce1df72293fecad863edd146a8c4b1a734f
|
||||
|
||||
JIRA: https://issues.redhat.com/browse/RHEL-21705
|
||||
|
||||
smbios_get_tables() bails out right away if leagacy mode is enabled
|
||||
and won't generate any SMBIOS tables. At the same time x86 specific
|
||||
fw_cfg_build_smbios() will genarate legacy tables and then proceed
|
||||
to preparing temporary mem_array for useless call to
|
||||
smbios_get_tables() and then discard it.
|
||||
|
||||
Drop legacy related check in smbios_get_tables() and return from
|
||||
fw_cfg_build_smbios() early if legacy tables where built without
|
||||
proceeding to non legacy part of the function.
|
||||
|
||||
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
|
||||
Reviewed-by: Ani Sinha <anisinha@redhat.com>
|
||||
Tested-by: Fiona Ebner <f.ebner@proxmox.com>
|
||||
---
|
||||
hw/i386/fw_cfg.c | 1 +
|
||||
hw/smbios/smbios.c | 6 ------
|
||||
2 files changed, 1 insertion(+), 6 deletions(-)
|
||||
|
||||
diff --git a/hw/i386/fw_cfg.c b/hw/i386/fw_cfg.c
|
||||
index 6a5466faf0..ed72b1442d 100644
|
||||
--- a/hw/i386/fw_cfg.c
|
||||
+++ b/hw/i386/fw_cfg.c
|
||||
@@ -76,6 +76,7 @@ void fw_cfg_build_smbios(PCMachineState *pcms, FWCfgState *fw_cfg)
|
||||
if (smbios_tables) {
|
||||
fw_cfg_add_bytes(fw_cfg, FW_CFG_SMBIOS_ENTRIES,
|
||||
smbios_tables, smbios_tables_len);
|
||||
+ return;
|
||||
}
|
||||
|
||||
/* build the array of physical mem area from e820 table */
|
||||
diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c
|
||||
index 074705fa4c..b13e40bae2 100644
|
||||
--- a/hw/smbios/smbios.c
|
||||
+++ b/hw/smbios/smbios.c
|
||||
@@ -1244,12 +1244,6 @@ void smbios_get_tables(MachineState *ms,
|
||||
{
|
||||
unsigned i, dimm_cnt, offset;
|
||||
|
||||
- if (smbios_legacy) {
|
||||
- *tables = *anchor = NULL;
|
||||
- *tables_len = *anchor_len = 0;
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
if (!smbios_immutable) {
|
||||
smbios_build_type_0_table();
|
||||
smbios_build_type_1_table();
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,38 +0,0 @@
|
||||
From c0282a842a912aacac28a6ae229de5854c3fb5df Mon Sep 17 00:00:00 2001
|
||||
From: Igor Mammedov <imammedo@redhat.com>
|
||||
Date: Mon, 26 Feb 2024 13:20:22 +0100
|
||||
Subject: [PATCH 16/20] smbios: clear smbios_type4_count before building tables
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 230: Workaround Windows failing to find 64bit SMBIOS entry point with SeaBIOS
|
||||
RH-Jira: RHEL-21705
|
||||
RH-Acked-by: MST <mst@redhat.com>
|
||||
RH-Acked-by: Ani Sinha <None>
|
||||
RH-Commit: [14/18] f809595d2934ae975c0b7d17a4a79645e062ba42
|
||||
|
||||
JIRA: https://issues.redhat.com/browse/RHEL-21705
|
||||
|
||||
it will help to keep type 4 tables accounting correct in case
|
||||
SMBIOS tables are built multiple times.
|
||||
|
||||
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
|
||||
Tested-by: Fiona Ebner <f.ebner@proxmox.com>
|
||||
---
|
||||
hw/smbios/smbios.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c
|
||||
index 7e32430b85..4521ea386c 100644
|
||||
--- a/hw/smbios/smbios.c
|
||||
+++ b/hw/smbios/smbios.c
|
||||
@@ -1111,6 +1111,7 @@ void smbios_get_tables(MachineState *ms,
|
||||
ep_type == SMBIOS_ENTRY_POINT_TYPE_64);
|
||||
|
||||
g_free(smbios_tables);
|
||||
+ smbios_type4_count = 0;
|
||||
smbios_tables = g_memdup2(usr_blobs, usr_blobs_len);
|
||||
smbios_tables_len = usr_blobs_len;
|
||||
smbios_table_max = usr_table_max;
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,133 +0,0 @@
|
||||
From 2b76d95ec07aba6d96070ee90c5015c1676be091 Mon Sep 17 00:00:00 2001
|
||||
From: Igor Mammedov <imammedo@redhat.com>
|
||||
Date: Tue, 13 Feb 2024 16:25:54 +0100
|
||||
Subject: [PATCH 10/20] smbios: don't check type4 structures in legacy mode
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 230: Workaround Windows failing to find 64bit SMBIOS entry point with SeaBIOS
|
||||
RH-Jira: RHEL-21705
|
||||
RH-Acked-by: MST <mst@redhat.com>
|
||||
RH-Acked-by: Ani Sinha <None>
|
||||
RH-Commit: [8/18] c1f8409ea0d916f333c9373535bf21b521c62855
|
||||
|
||||
JIRA: https://issues.redhat.com/browse/RHEL-21705
|
||||
|
||||
legacy mode doesn't support structures of type 2 and more,
|
||||
and CLI has a check for '-smbios type' option, however it's
|
||||
still possible to sneak in type4 as a blob with '-smbios file'
|
||||
option. However doing the later makes SMBIOS tables broken
|
||||
since SeaBIOS doesn't expect that.
|
||||
|
||||
Rather than trying to add support for type4 to legacy code
|
||||
(both QEMU and SeaBIOS), simplify smbios_get_table_legacy()
|
||||
by dropping not relevant check in legacy code and error out
|
||||
on type4 blob.
|
||||
|
||||
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
|
||||
Reviewed-by: Ani Sinha <anisinha@redhat.com>
|
||||
Tested-by: Fiona Ebner <f.ebner@proxmox.com>
|
||||
|
||||
Conflicts: include/hw/firmware/smbios.h
|
||||
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
|
||||
|
||||
Please enter the commit message for your changes. Lines starting
|
||||
---
|
||||
hw/i386/fw_cfg.c | 3 +--
|
||||
hw/smbios/smbios.c | 18 ++++++++++++++----
|
||||
include/hw/firmware/smbios.h | 2 +-
|
||||
3 files changed, 16 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/hw/i386/fw_cfg.c b/hw/i386/fw_cfg.c
|
||||
index bb7149c4c3..a25793a68f 100644
|
||||
--- a/hw/i386/fw_cfg.c
|
||||
+++ b/hw/i386/fw_cfg.c
|
||||
@@ -73,8 +73,7 @@ void fw_cfg_build_smbios(PCMachineState *pcms, FWCfgState *fw_cfg)
|
||||
smbios_set_cpuid(cpu->env.cpuid_version, cpu->env.features[FEAT_1_EDX]);
|
||||
|
||||
if (pcmc->smbios_legacy_mode) {
|
||||
- smbios_tables = smbios_get_table_legacy(ms->smp.cpus,
|
||||
- &smbios_tables_len);
|
||||
+ smbios_tables = smbios_get_table_legacy(&smbios_tables_len);
|
||||
fw_cfg_add_bytes(fw_cfg, FW_CFG_SMBIOS_ENTRIES,
|
||||
smbios_tables, smbios_tables_len);
|
||||
return;
|
||||
diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c
|
||||
index d8d68716d4..441517cf24 100644
|
||||
--- a/hw/smbios/smbios.c
|
||||
+++ b/hw/smbios/smbios.c
|
||||
@@ -530,14 +530,17 @@ opts_init(smbios_register_config);
|
||||
*/
|
||||
#define SMBIOS_21_MAX_TABLES_LEN 0xffff
|
||||
|
||||
-static void smbios_validate_table(uint32_t expected_t4_count)
|
||||
+static void smbios_check_type4_count(uint32_t expected_t4_count)
|
||||
{
|
||||
if (smbios_type4_count && smbios_type4_count != expected_t4_count) {
|
||||
error_report("Expected %d SMBIOS Type 4 tables, got %d instead",
|
||||
expected_t4_count, smbios_type4_count);
|
||||
exit(1);
|
||||
}
|
||||
+}
|
||||
|
||||
+static void smbios_validate_table(void)
|
||||
+{
|
||||
if (smbios_ep_type == SMBIOS_ENTRY_POINT_TYPE_32 &&
|
||||
smbios_tables_len > SMBIOS_21_MAX_TABLES_LEN) {
|
||||
error_report("SMBIOS 2.1 table length %zu exceeds %d",
|
||||
@@ -622,7 +625,7 @@ static void smbios_build_type_1_fields(void)
|
||||
}
|
||||
}
|
||||
|
||||
-uint8_t *smbios_get_table_legacy(uint32_t expected_t4_count, size_t *length)
|
||||
+uint8_t *smbios_get_table_legacy(size_t *length)
|
||||
{
|
||||
int i;
|
||||
size_t usr_offset;
|
||||
@@ -635,6 +638,12 @@ uint8_t *smbios_get_table_legacy(uint32_t expected_t4_count, size_t *length)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
+ if (test_bit(4, have_binfile_bitmap)) {
|
||||
+ error_report("can't process table for smbios "
|
||||
+ "type 4 on machine versions < 2.1!");
|
||||
+ exit(1);
|
||||
+ }
|
||||
+
|
||||
g_free(smbios_entries);
|
||||
smbios_entries_len = sizeof(uint16_t);
|
||||
smbios_entries = g_malloc0(smbios_entries_len);
|
||||
@@ -661,7 +670,7 @@ uint8_t *smbios_get_table_legacy(uint32_t expected_t4_count, size_t *length)
|
||||
|
||||
smbios_build_type_0_fields();
|
||||
smbios_build_type_1_fields();
|
||||
- smbios_validate_table(expected_t4_count);
|
||||
+ smbios_validate_table();
|
||||
*length = smbios_entries_len;
|
||||
return smbios_entries;
|
||||
}
|
||||
@@ -1319,7 +1328,8 @@ void smbios_get_tables(MachineState *ms,
|
||||
smbios_build_type_41_table(errp);
|
||||
smbios_build_type_127_table();
|
||||
|
||||
- smbios_validate_table(ms->smp.sockets);
|
||||
+ smbios_check_type4_count(ms->smp.sockets);
|
||||
+ smbios_validate_table();
|
||||
smbios_entry_point_setup();
|
||||
|
||||
/* return tables blob and entry point (anchor), and their sizes */
|
||||
diff --git a/include/hw/firmware/smbios.h b/include/hw/firmware/smbios.h
|
||||
index b9fc9a0f42..d55018e5e3 100644
|
||||
--- a/include/hw/firmware/smbios.h
|
||||
+++ b/include/hw/firmware/smbios.h
|
||||
@@ -315,7 +315,7 @@ void smbios_set_defaults(const char *manufacturer, const char *product,
|
||||
SmbiosEntryPointType ep_type,
|
||||
const char *stream_product,
|
||||
const char *stream_version);
|
||||
-uint8_t *smbios_get_table_legacy(uint32_t expected_t4_count, size_t *length);
|
||||
+uint8_t *smbios_get_table_legacy(size_t *length);
|
||||
void smbios_get_tables(MachineState *ms,
|
||||
const struct smbios_phys_mem_area *mem_array,
|
||||
const unsigned int mem_array_size,
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,72 +0,0 @@
|
||||
From bbb2d260e6f33380b9df28c74421055bd8dccda5 Mon Sep 17 00:00:00 2001
|
||||
From: Igor Mammedov <imammedo@redhat.com>
|
||||
Date: Mon, 26 Feb 2024 12:59:33 +0100
|
||||
Subject: [PATCH 19/20] smbios: error out when building type 4 table is not
|
||||
possible
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 230: Workaround Windows failing to find 64bit SMBIOS entry point with SeaBIOS
|
||||
RH-Jira: RHEL-21705
|
||||
RH-Acked-by: MST <mst@redhat.com>
|
||||
RH-Acked-by: Ani Sinha <None>
|
||||
RH-Commit: [17/18] 86b1c67bfbe9c0c14a190cd1204b6ccd1de1630f
|
||||
|
||||
JIRA: https://issues.redhat.com/browse/RHEL-21705
|
||||
|
||||
If SMBIOS v2 version is requested but number of cores/threads
|
||||
are more than it's possible to describe with v2, error out
|
||||
instead of silently ignoring the fact and filling core/thread
|
||||
count with bogus values.
|
||||
|
||||
This will help caller to decide if it should fallback to
|
||||
SMBIOSv3 when smbios-entry-point-type='auto'
|
||||
|
||||
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
|
||||
Reviewed-by: Ani Sinha <anisinha@redhat.com>
|
||||
Tested-by: Fiona Ebner <f.ebner@proxmox.com>
|
||||
---
|
||||
hw/smbios/smbios.c | 14 ++++++++++++--
|
||||
1 file changed, 12 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c
|
||||
index 3d9dcb0d31..637aa952f5 100644
|
||||
--- a/hw/smbios/smbios.c
|
||||
+++ b/hw/smbios/smbios.c
|
||||
@@ -655,7 +655,8 @@ static void smbios_build_type_3_table(void)
|
||||
}
|
||||
|
||||
static void smbios_build_type_4_table(MachineState *ms, unsigned instance,
|
||||
- SmbiosEntryPointType ep_type)
|
||||
+ SmbiosEntryPointType ep_type,
|
||||
+ Error **errp)
|
||||
{
|
||||
char sock_str[128];
|
||||
size_t tbl_len = SMBIOS_TYPE_4_LEN_V28;
|
||||
@@ -709,6 +710,12 @@ static void smbios_build_type_4_table(MachineState *ms, unsigned instance,
|
||||
if (tbl_len == SMBIOS_TYPE_4_LEN_V30) {
|
||||
t->core_count2 = t->core_enabled2 = cpu_to_le16(cores_per_socket);
|
||||
t->thread_count2 = cpu_to_le16(threads_per_socket);
|
||||
+ } else if (t->core_count == 0xFF || t->thread_count == 0xFF) {
|
||||
+ error_setg(errp, "SMBIOS 2.0 doesn't support number of processor "
|
||||
+ "cores/threads more than 255, use "
|
||||
+ "-machine smbios-entry-point-type=64 option to enable "
|
||||
+ "SMBIOS 3.0 support");
|
||||
+ return;
|
||||
}
|
||||
|
||||
SMBIOS_BUILD_TABLE_POST;
|
||||
@@ -1126,7 +1133,10 @@ static bool smbios_get_tables_ep(MachineState *ms,
|
||||
assert(ms->smp.sockets >= 1);
|
||||
|
||||
for (i = 0; i < ms->smp.sockets; i++) {
|
||||
- smbios_build_type_4_table(ms, i, ep_type);
|
||||
+ smbios_build_type_4_table(ms, i, ep_type, errp);
|
||||
+ if (*errp) {
|
||||
+ goto err_exit;
|
||||
+ }
|
||||
}
|
||||
|
||||
smbios_build_type_8_table();
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,48 +0,0 @@
|
||||
From c083959c963fde33f4769fd4c6e122dd16ce6d3c Mon Sep 17 00:00:00 2001
|
||||
From: Igor Mammedov <imammedo@redhat.com>
|
||||
Date: Wed, 21 Feb 2024 16:04:36 +0100
|
||||
Subject: [PATCH 17/20] smbios: extend smbios-entry-point-type with 'auto'
|
||||
value
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 230: Workaround Windows failing to find 64bit SMBIOS entry point with SeaBIOS
|
||||
RH-Jira: RHEL-21705
|
||||
RH-Acked-by: MST <mst@redhat.com>
|
||||
RH-Acked-by: Ani Sinha <None>
|
||||
RH-Commit: [15/18] 202563dcf77e062a238aa2a10ec14c25d3f5a7d0
|
||||
|
||||
JIRA: https://issues.redhat.com/browse/RHEL-21705
|
||||
|
||||
later patches will use it to pick SMBIOS version at runtime
|
||||
depending on configuration.
|
||||
|
||||
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
|
||||
Acked-by: Markus Armbruster <armbru@redhat.com>
|
||||
Reviewed-by: Ani Sinha <anisinha@redhat.com>
|
||||
Tested-by: Fiona Ebner <f.ebner@proxmox.com>
|
||||
---
|
||||
qapi/machine.json | 5 ++++-
|
||||
1 file changed, 4 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/qapi/machine.json b/qapi/machine.json
|
||||
index b6d634b30d..99f6368fa6 100644
|
||||
--- a/qapi/machine.json
|
||||
+++ b/qapi/machine.json
|
||||
@@ -1788,10 +1788,13 @@
|
||||
#
|
||||
# @64: SMBIOS version 3.0 (64-bit) Entry Point
|
||||
#
|
||||
+# @auto: Either 2.x or 3.x SMBIOS version, 2.x if configuration can be
|
||||
+# described by it and 3.x otherwise (since: 9.0)
|
||||
+#
|
||||
# Since: 7.0
|
||||
##
|
||||
{ 'enum': 'SmbiosEntryPointType',
|
||||
- 'data': [ '32', '64' ] }
|
||||
+ 'data': [ '32', '64', 'auto' ] }
|
||||
|
||||
##
|
||||
# @MemorySizeConfiguration:
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,281 +0,0 @@
|
||||
From be0abbf3f7845847b46486704c46c5de5a2b2323 Mon Sep 17 00:00:00 2001
|
||||
From: Igor Mammedov <imammedo@redhat.com>
|
||||
Date: Mon, 26 Feb 2024 13:49:14 +0100
|
||||
Subject: [PATCH 15/20] smbios: get rid of global smbios_ep_type
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 230: Workaround Windows failing to find 64bit SMBIOS entry point with SeaBIOS
|
||||
RH-Jira: RHEL-21705
|
||||
RH-Acked-by: MST <mst@redhat.com>
|
||||
RH-Acked-by: Ani Sinha <None>
|
||||
RH-Commit: [13/18] 2e838ed0d03989e2e4ee08041b5ba64d5d7f5820
|
||||
|
||||
JIRA: https://issues.redhat.com/browse/RHEL-21705
|
||||
|
||||
Conflicts: hw/arm/virt.c, hw/i386/fw_cfg.c, hw/riscv/virt.c, hw/smbios/smbios.c,
|
||||
include/hw/firmware/smbios.h
|
||||
due to downstream specific smbios_set_defaults()
|
||||
|
||||
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
|
||||
Acked-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
|
||||
Reviewed-by: Ani Sinha <anisinha@redhat.com>
|
||||
Tested-by: Fiona Ebner <f.ebner@proxmox.com>
|
||||
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
|
||||
---
|
||||
hw/arm/virt.c | 4 ++--
|
||||
hw/i386/fw_cfg.c | 6 +++---
|
||||
hw/i386/fw_cfg.h | 3 ++-
|
||||
hw/i386/pc.c | 2 +-
|
||||
hw/loongarch/virt.c | 7 ++++---
|
||||
hw/smbios/smbios.c | 26 ++++++++++++++------------
|
||||
hw/smbios/smbios_legacy.c | 2 +-
|
||||
include/hw/firmware/smbios.h | 4 ++--
|
||||
8 files changed, 29 insertions(+), 25 deletions(-)
|
||||
|
||||
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
|
||||
index e5cfc19c08..e4a66affcb 100644
|
||||
--- a/hw/arm/virt.c
|
||||
+++ b/hw/arm/virt.c
|
||||
@@ -1695,14 +1695,14 @@ static void virt_build_smbios(VirtMachineState *vms)
|
||||
|
||||
smbios_set_defaults("QEMU", product,
|
||||
vmc->smbios_old_sys_ver ? "1.0" : mc->name,
|
||||
- true, SMBIOS_ENTRY_POINT_TYPE_64,
|
||||
+ true,
|
||||
NULL, NULL);
|
||||
|
||||
/* build the array of physical mem area from base_memmap */
|
||||
mem_array.address = vms->memmap[VIRT_MEM].base;
|
||||
mem_array.length = ms->ram_size;
|
||||
|
||||
- smbios_get_tables(ms, &mem_array, 1,
|
||||
+ smbios_get_tables(ms, SMBIOS_ENTRY_POINT_TYPE_64, &mem_array, 1,
|
||||
&smbios_tables, &smbios_tables_len,
|
||||
&smbios_anchor, &smbios_anchor_len,
|
||||
&error_fatal);
|
||||
diff --git a/hw/i386/fw_cfg.c b/hw/i386/fw_cfg.c
|
||||
index bdc3cc4556..58429bb78d 100644
|
||||
--- a/hw/i386/fw_cfg.c
|
||||
+++ b/hw/i386/fw_cfg.c
|
||||
@@ -48,7 +48,8 @@ const char *fw_cfg_arch_key_name(uint16_t key)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
-void fw_cfg_build_smbios(PCMachineState *pcms, FWCfgState *fw_cfg)
|
||||
+void fw_cfg_build_smbios(PCMachineState *pcms, FWCfgState *fw_cfg,
|
||||
+ SmbiosEntryPointType ep_type)
|
||||
{
|
||||
#ifdef CONFIG_SMBIOS
|
||||
uint8_t *smbios_tables, *smbios_anchor;
|
||||
@@ -64,7 +65,6 @@ void fw_cfg_build_smbios(PCMachineState *pcms, FWCfgState *fw_cfg)
|
||||
/* These values are guest ABI, do not change */
|
||||
smbios_set_defaults("QEMU", mc->desc, mc->name,
|
||||
pcmc->smbios_uuid_encoded,
|
||||
- pcms->smbios_entry_point_type,
|
||||
pcmc->smbios_stream_product,
|
||||
pcmc->smbios_stream_version);
|
||||
}
|
||||
@@ -91,7 +91,7 @@ void fw_cfg_build_smbios(PCMachineState *pcms, FWCfgState *fw_cfg)
|
||||
array_count++;
|
||||
}
|
||||
}
|
||||
- smbios_get_tables(ms, mem_array, array_count,
|
||||
+ smbios_get_tables(ms, ep_type, mem_array, array_count,
|
||||
&smbios_tables, &smbios_tables_len,
|
||||
&smbios_anchor, &smbios_anchor_len,
|
||||
&error_fatal);
|
||||
diff --git a/hw/i386/fw_cfg.h b/hw/i386/fw_cfg.h
|
||||
index 1e1de6b4a3..92e310f5fd 100644
|
||||
--- a/hw/i386/fw_cfg.h
|
||||
+++ b/hw/i386/fw_cfg.h
|
||||
@@ -23,7 +23,8 @@
|
||||
FWCfgState *fw_cfg_arch_create(MachineState *ms,
|
||||
uint16_t boot_cpus,
|
||||
uint16_t apic_id_limit);
|
||||
-void fw_cfg_build_smbios(PCMachineState *ms, FWCfgState *fw_cfg);
|
||||
+void fw_cfg_build_smbios(PCMachineState *pcms, FWCfgState *fw_cfg,
|
||||
+ SmbiosEntryPointType ep_type);
|
||||
void fw_cfg_build_feature_control(MachineState *ms, FWCfgState *fw_cfg);
|
||||
void fw_cfg_add_acpi_dsdt(Aml *scope, FWCfgState *fw_cfg);
|
||||
|
||||
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
|
||||
index 16de2a59e8..ae6777fc1a 100644
|
||||
--- a/hw/i386/pc.c
|
||||
+++ b/hw/i386/pc.c
|
||||
@@ -847,7 +847,7 @@ void pc_machine_done(Notifier *notifier, void *data)
|
||||
|
||||
acpi_setup();
|
||||
if (x86ms->fw_cfg) {
|
||||
- fw_cfg_build_smbios(pcms, x86ms->fw_cfg);
|
||||
+ fw_cfg_build_smbios(pcms, x86ms->fw_cfg, pcms->smbios_entry_point_type);
|
||||
fw_cfg_build_feature_control(MACHINE(pcms), x86ms->fw_cfg);
|
||||
/* update FW_CFG_NB_CPUS to account for -device added CPUs */
|
||||
fw_cfg_modify_i16(x86ms->fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus);
|
||||
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
|
||||
index 7358a023d3..77956b5ada 100644
|
||||
--- a/hw/loongarch/virt.c
|
||||
+++ b/hw/loongarch/virt.c
|
||||
@@ -320,10 +320,11 @@ static void virt_build_smbios(LoongArchMachineState *lams)
|
||||
return;
|
||||
}
|
||||
|
||||
- smbios_set_defaults("QEMU", product, mc->name,
|
||||
- true, SMBIOS_ENTRY_POINT_TYPE_64);
|
||||
+ smbios_set_defaults("QEMU", product, mc->name, true);
|
||||
|
||||
- smbios_get_tables(ms, NULL, 0, &smbios_tables, &smbios_tables_len,
|
||||
+ smbios_get_tables(ms, SMBIOS_ENTRY_POINT_TYPE_64,
|
||||
+ NULL, 0,
|
||||
+ &smbios_tables, &smbios_tables_len,
|
||||
&smbios_anchor, &smbios_anchor_len, &error_fatal);
|
||||
|
||||
if (smbios_anchor) {
|
||||
diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c
|
||||
index b5745c6c2d..7e32430b85 100644
|
||||
--- a/hw/smbios/smbios.c
|
||||
+++ b/hw/smbios/smbios.c
|
||||
@@ -47,7 +47,6 @@ uint8_t *smbios_tables;
|
||||
size_t smbios_tables_len;
|
||||
unsigned smbios_table_max;
|
||||
unsigned smbios_table_cnt;
|
||||
-static SmbiosEntryPointType smbios_ep_type = SMBIOS_ENTRY_POINT_TYPE_32;
|
||||
|
||||
static SmbiosEntryPoint ep;
|
||||
|
||||
@@ -506,9 +505,9 @@ static bool smbios_check_type4_count(uint32_t expected_t4_count, Error **errp)
|
||||
return true;
|
||||
}
|
||||
|
||||
-bool smbios_validate_table(Error **errp)
|
||||
+bool smbios_validate_table(SmbiosEntryPointType ep_type, Error **errp)
|
||||
{
|
||||
- if (smbios_ep_type == SMBIOS_ENTRY_POINT_TYPE_32 &&
|
||||
+ if (ep_type == SMBIOS_ENTRY_POINT_TYPE_32 &&
|
||||
smbios_tables_len > SMBIOS_21_MAX_TABLES_LEN) {
|
||||
error_setg(errp, "SMBIOS 2.1 table length %zu exceeds %d",
|
||||
smbios_tables_len, SMBIOS_21_MAX_TABLES_LEN);
|
||||
@@ -655,14 +654,15 @@ static void smbios_build_type_3_table(void)
|
||||
SMBIOS_BUILD_TABLE_POST;
|
||||
}
|
||||
|
||||
-static void smbios_build_type_4_table(MachineState *ms, unsigned instance)
|
||||
+static void smbios_build_type_4_table(MachineState *ms, unsigned instance,
|
||||
+ SmbiosEntryPointType ep_type)
|
||||
{
|
||||
char sock_str[128];
|
||||
size_t tbl_len = SMBIOS_TYPE_4_LEN_V28;
|
||||
unsigned threads_per_socket;
|
||||
unsigned cores_per_socket;
|
||||
|
||||
- if (smbios_ep_type == SMBIOS_ENTRY_POINT_TYPE_64) {
|
||||
+ if (ep_type == SMBIOS_ENTRY_POINT_TYPE_64) {
|
||||
tbl_len = SMBIOS_TYPE_4_LEN_V30;
|
||||
}
|
||||
|
||||
@@ -991,13 +991,11 @@ void smbios_set_cpuid(uint32_t version, uint32_t features)
|
||||
void smbios_set_defaults(const char *manufacturer, const char *product,
|
||||
const char *version,
|
||||
bool uuid_encoded,
|
||||
- SmbiosEntryPointType ep_type,
|
||||
const char *stream_product,
|
||||
const char *stream_version)
|
||||
{
|
||||
smbios_have_defaults = true;
|
||||
smbios_uuid_encoded = uuid_encoded;
|
||||
- smbios_ep_type = ep_type;
|
||||
|
||||
/*
|
||||
* If @stream_product & @stream_version are non-NULL, then
|
||||
@@ -1048,9 +1046,9 @@ void smbios_set_defaults(const char *manufacturer, const char *product,
|
||||
SMBIOS_SET_DEFAULT(type17.manufacturer, manufacturer);
|
||||
}
|
||||
|
||||
-static void smbios_entry_point_setup(void)
|
||||
+static void smbios_entry_point_setup(SmbiosEntryPointType ep_type)
|
||||
{
|
||||
- switch (smbios_ep_type) {
|
||||
+ switch (ep_type) {
|
||||
case SMBIOS_ENTRY_POINT_TYPE_32:
|
||||
memcpy(ep.ep21.anchor_string, "_SM_", 4);
|
||||
memcpy(ep.ep21.intermediate_anchor_string, "_DMI_", 5);
|
||||
@@ -1100,6 +1098,7 @@ static void smbios_entry_point_setup(void)
|
||||
}
|
||||
|
||||
void smbios_get_tables(MachineState *ms,
|
||||
+ SmbiosEntryPointType ep_type,
|
||||
const struct smbios_phys_mem_area *mem_array,
|
||||
const unsigned int mem_array_size,
|
||||
uint8_t **tables, size_t *tables_len,
|
||||
@@ -1108,6 +1107,9 @@ void smbios_get_tables(MachineState *ms,
|
||||
{
|
||||
unsigned i, dimm_cnt, offset;
|
||||
|
||||
+ assert(ep_type == SMBIOS_ENTRY_POINT_TYPE_32 ||
|
||||
+ ep_type == SMBIOS_ENTRY_POINT_TYPE_64);
|
||||
+
|
||||
g_free(smbios_tables);
|
||||
smbios_tables = g_memdup2(usr_blobs, usr_blobs_len);
|
||||
smbios_tables_len = usr_blobs_len;
|
||||
@@ -1122,7 +1124,7 @@ void smbios_get_tables(MachineState *ms,
|
||||
assert(ms->smp.sockets >= 1);
|
||||
|
||||
for (i = 0; i < ms->smp.sockets; i++) {
|
||||
- smbios_build_type_4_table(ms, i);
|
||||
+ smbios_build_type_4_table(ms, i, ep_type);
|
||||
}
|
||||
|
||||
smbios_build_type_8_table();
|
||||
@@ -1171,10 +1173,10 @@ void smbios_get_tables(MachineState *ms,
|
||||
if (!smbios_check_type4_count(ms->smp.sockets, errp)) {
|
||||
goto err_exit;
|
||||
}
|
||||
- if (!smbios_validate_table(errp)) {
|
||||
+ if (!smbios_validate_table(ep_type, errp)) {
|
||||
goto err_exit;
|
||||
}
|
||||
- smbios_entry_point_setup();
|
||||
+ smbios_entry_point_setup(ep_type);
|
||||
|
||||
/* return tables blob and entry point (anchor), and their sizes */
|
||||
*tables = smbios_tables;
|
||||
diff --git a/hw/smbios/smbios_legacy.c b/hw/smbios/smbios_legacy.c
|
||||
index a6544bf55a..06907cd16c 100644
|
||||
--- a/hw/smbios/smbios_legacy.c
|
||||
+++ b/hw/smbios/smbios_legacy.c
|
||||
@@ -173,7 +173,7 @@ uint8_t *smbios_get_table_legacy(size_t *length, Error **errp)
|
||||
|
||||
smbios_build_type_0_fields();
|
||||
smbios_build_type_1_fields();
|
||||
- if (!smbios_validate_table(errp)) {
|
||||
+ if (!smbios_validate_table(SMBIOS_ENTRY_POINT_TYPE_32, errp)) {
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
diff --git a/include/hw/firmware/smbios.h b/include/hw/firmware/smbios.h
|
||||
index 44af3a0d82..781298f594 100644
|
||||
--- a/include/hw/firmware/smbios.h
|
||||
+++ b/include/hw/firmware/smbios.h
|
||||
@@ -326,18 +326,18 @@ struct smbios_type_127 {
|
||||
struct smbios_structure_header header;
|
||||
} QEMU_PACKED;
|
||||
|
||||
-bool smbios_validate_table(Error **errp);
|
||||
+bool smbios_validate_table(SmbiosEntryPointType ep_type, Error **errp);
|
||||
void smbios_add_usr_blob_size(size_t size);
|
||||
void smbios_entry_add(QemuOpts *opts, Error **errp);
|
||||
void smbios_set_cpuid(uint32_t version, uint32_t features);
|
||||
void smbios_set_defaults(const char *manufacturer, const char *product,
|
||||
const char *version,
|
||||
bool uuid_encoded,
|
||||
- SmbiosEntryPointType ep_type,
|
||||
const char *stream_product,
|
||||
const char *stream_version);
|
||||
uint8_t *smbios_get_table_legacy(size_t *length, Error **errp);
|
||||
void smbios_get_tables(MachineState *ms,
|
||||
+ SmbiosEntryPointType ep_type,
|
||||
const struct smbios_phys_mem_area *mem_array,
|
||||
const unsigned int mem_array_size,
|
||||
uint8_t **tables, size_t *tables_len,
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,198 +0,0 @@
|
||||
From 0802fa7199c8085d018fc38dd4beaa5062d383d1 Mon Sep 17 00:00:00 2001
|
||||
From: Igor Mammedov <imammedo@redhat.com>
|
||||
Date: Fri, 29 Dec 2023 15:37:29 +0100
|
||||
Subject: [PATCH 08/20] smbios: get rid of smbios_legacy global
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 230: Workaround Windows failing to find 64bit SMBIOS entry point with SeaBIOS
|
||||
RH-Jira: RHEL-21705
|
||||
RH-Acked-by: MST <mst@redhat.com>
|
||||
RH-Acked-by: Ani Sinha <None>
|
||||
RH-Commit: [6/18] 684dd1dca8d611c6de97b26ef8c1cda6ca509d54
|
||||
|
||||
JIRA: https://issues.redhat.com/browse/RHEL-21705
|
||||
|
||||
clean up smbios_set_defaults() which is reused by legacy
|
||||
and non legacy machines from being aware of 'legacy' notion
|
||||
and need to turn it off. And push legacy handling up to
|
||||
PC machine code where it's relevant.
|
||||
|
||||
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
|
||||
Reviewed-by: Ani Sinha <anisinha@redhat.com>
|
||||
Acked-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
|
||||
Tested-by: Fiona Ebner <f.ebner@proxmox.com>
|
||||
|
||||
Conflicts: hw/arm/virt.c, hw/i386/fw_cfg.c, hw/loongarch/virt.c,
|
||||
hw/smbios/smbios.c, include/hw/firmware/smbios.h
|
||||
due to downstream specifc signature of smbios_set_defaults()
|
||||
PS:
|
||||
while fixing conflicts move RHEL specific
|
||||
smbios_stream_product/smbios_stream_version
|
||||
at the end of arguments list
|
||||
|
||||
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
|
||||
---
|
||||
hw/arm/virt.c | 5 +++--
|
||||
hw/i386/fw_cfg.c | 11 +++++-----
|
||||
hw/loongarch/virt.c | 2 +-
|
||||
hw/smbios/smbios.c | 39 ++++++++++++++++--------------------
|
||||
include/hw/firmware/smbios.h | 6 +++---
|
||||
5 files changed, 30 insertions(+), 33 deletions(-)
|
||||
|
||||
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
|
||||
index 943c563391..e5cfc19c08 100644
|
||||
--- a/hw/arm/virt.c
|
||||
+++ b/hw/arm/virt.c
|
||||
@@ -1694,8 +1694,9 @@ static void virt_build_smbios(VirtMachineState *vms)
|
||||
}
|
||||
|
||||
smbios_set_defaults("QEMU", product,
|
||||
- vmc->smbios_old_sys_ver ? "1.0" : mc->name, false,
|
||||
- true, NULL, NULL, SMBIOS_ENTRY_POINT_TYPE_64);
|
||||
+ vmc->smbios_old_sys_ver ? "1.0" : mc->name,
|
||||
+ true, SMBIOS_ENTRY_POINT_TYPE_64,
|
||||
+ NULL, NULL);
|
||||
|
||||
/* build the array of physical mem area from base_memmap */
|
||||
mem_array.address = vms->memmap[VIRT_MEM].base;
|
||||
diff --git a/hw/i386/fw_cfg.c b/hw/i386/fw_cfg.c
|
||||
index 79ff7f7225..bb7149c4c3 100644
|
||||
--- a/hw/i386/fw_cfg.c
|
||||
+++ b/hw/i386/fw_cfg.c
|
||||
@@ -63,17 +63,18 @@ void fw_cfg_build_smbios(PCMachineState *pcms, FWCfgState *fw_cfg)
|
||||
if (pcmc->smbios_defaults) {
|
||||
/* These values are guest ABI, do not change */
|
||||
smbios_set_defaults("QEMU", mc->desc, mc->name,
|
||||
- pcmc->smbios_legacy_mode, pcmc->smbios_uuid_encoded,
|
||||
+ pcmc->smbios_uuid_encoded,
|
||||
+ pcms->smbios_entry_point_type,
|
||||
pcmc->smbios_stream_product,
|
||||
- pcmc->smbios_stream_version,
|
||||
- pcms->smbios_entry_point_type);
|
||||
+ pcmc->smbios_stream_version);
|
||||
}
|
||||
|
||||
/* tell smbios about cpuid version and features */
|
||||
smbios_set_cpuid(cpu->env.cpuid_version, cpu->env.features[FEAT_1_EDX]);
|
||||
|
||||
- smbios_tables = smbios_get_table_legacy(ms->smp.cpus, &smbios_tables_len);
|
||||
- if (smbios_tables) {
|
||||
+ if (pcmc->smbios_legacy_mode) {
|
||||
+ smbios_tables = smbios_get_table_legacy(ms->smp.cpus,
|
||||
+ &smbios_tables_len);
|
||||
fw_cfg_add_bytes(fw_cfg, FW_CFG_SMBIOS_ENTRIES,
|
||||
smbios_tables, smbios_tables_len);
|
||||
return;
|
||||
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
|
||||
index 4b7dc67a2d..7358a023d3 100644
|
||||
--- a/hw/loongarch/virt.c
|
||||
+++ b/hw/loongarch/virt.c
|
||||
@@ -320,7 +320,7 @@ static void virt_build_smbios(LoongArchMachineState *lams)
|
||||
return;
|
||||
}
|
||||
|
||||
- smbios_set_defaults("QEMU", product, mc->name, false,
|
||||
+ smbios_set_defaults("QEMU", product, mc->name,
|
||||
true, SMBIOS_ENTRY_POINT_TYPE_64);
|
||||
|
||||
smbios_get_tables(ms, NULL, 0, &smbios_tables, &smbios_tables_len,
|
||||
diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c
|
||||
index 8129d396d1..0c8c439859 100644
|
||||
--- a/hw/smbios/smbios.c
|
||||
+++ b/hw/smbios/smbios.c
|
||||
@@ -54,7 +54,6 @@ struct smbios_table {
|
||||
|
||||
static uint8_t *smbios_entries;
|
||||
static size_t smbios_entries_len;
|
||||
-static bool smbios_legacy = true;
|
||||
static bool smbios_uuid_encoded = true;
|
||||
/* end: legacy structures & constants for <= 2.0 machines */
|
||||
|
||||
@@ -618,9 +617,16 @@ static void smbios_build_type_1_fields(void)
|
||||
|
||||
uint8_t *smbios_get_table_legacy(uint32_t expected_t4_count, size_t *length)
|
||||
{
|
||||
- if (!smbios_legacy) {
|
||||
- *length = 0;
|
||||
- return NULL;
|
||||
+ /* drop unwanted version of command-line file blob(s) */
|
||||
+ g_free(smbios_tables);
|
||||
+ smbios_tables = NULL;
|
||||
+
|
||||
+ /* also complain if fields were given for types > 1 */
|
||||
+ if (find_next_bit(have_fields_bitmap,
|
||||
+ SMBIOS_MAX_TYPE + 1, 2) < SMBIOS_MAX_TYPE + 1) {
|
||||
+ error_report("can't process fields for smbios "
|
||||
+ "types > 1 on machine versions < 2.1!");
|
||||
+ exit(1);
|
||||
}
|
||||
|
||||
if (!smbios_immutable) {
|
||||
@@ -1107,31 +1113,16 @@ void smbios_set_cpuid(uint32_t version, uint32_t features)
|
||||
}
|
||||
|
||||
void smbios_set_defaults(const char *manufacturer, const char *product,
|
||||
- const char *version, bool legacy_mode,
|
||||
+ const char *version,
|
||||
bool uuid_encoded,
|
||||
+ SmbiosEntryPointType ep_type,
|
||||
const char *stream_product,
|
||||
- const char *stream_version,
|
||||
- SmbiosEntryPointType ep_type)
|
||||
+ const char *stream_version)
|
||||
{
|
||||
smbios_have_defaults = true;
|
||||
- smbios_legacy = legacy_mode;
|
||||
smbios_uuid_encoded = uuid_encoded;
|
||||
smbios_ep_type = ep_type;
|
||||
|
||||
- /* drop unwanted version of command-line file blob(s) */
|
||||
- if (smbios_legacy) {
|
||||
- g_free(smbios_tables);
|
||||
- /* in legacy mode, also complain if fields were given for types > 1 */
|
||||
- if (find_next_bit(have_fields_bitmap,
|
||||
- SMBIOS_MAX_TYPE+1, 2) < SMBIOS_MAX_TYPE+1) {
|
||||
- error_report("can't process fields for smbios "
|
||||
- "types > 1 on machine versions < 2.1!");
|
||||
- exit(1);
|
||||
- }
|
||||
- } else {
|
||||
- g_free(smbios_entries);
|
||||
- }
|
||||
-
|
||||
/*
|
||||
* If @stream_product & @stream_version are non-NULL, then
|
||||
* we're following rules for new Windows driver support.
|
||||
@@ -1241,6 +1232,10 @@ void smbios_get_tables(MachineState *ms,
|
||||
{
|
||||
unsigned i, dimm_cnt, offset;
|
||||
|
||||
+ /* drop unwanted (legacy) version of command-line file blob(s) */
|
||||
+ g_free(smbios_entries);
|
||||
+ smbios_entries = NULL;
|
||||
+
|
||||
if (!smbios_immutable) {
|
||||
smbios_build_type_0_table();
|
||||
smbios_build_type_1_table();
|
||||
diff --git a/include/hw/firmware/smbios.h b/include/hw/firmware/smbios.h
|
||||
index 95ec64ce2c..b9fc9a0f42 100644
|
||||
--- a/include/hw/firmware/smbios.h
|
||||
+++ b/include/hw/firmware/smbios.h
|
||||
@@ -310,11 +310,11 @@ struct smbios_type_127 {
|
||||
void smbios_entry_add(QemuOpts *opts, Error **errp);
|
||||
void smbios_set_cpuid(uint32_t version, uint32_t features);
|
||||
void smbios_set_defaults(const char *manufacturer, const char *product,
|
||||
- const char *version, bool legacy_mode,
|
||||
+ const char *version,
|
||||
bool uuid_encoded,
|
||||
+ SmbiosEntryPointType ep_type,
|
||||
const char *stream_product,
|
||||
- const char *stream_version,
|
||||
- SmbiosEntryPointType ep_type);
|
||||
+ const char *stream_version);
|
||||
uint8_t *smbios_get_table_legacy(uint32_t expected_t4_count, size_t *length);
|
||||
void smbios_get_tables(MachineState *ms,
|
||||
const struct smbios_phys_mem_area *mem_array,
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,134 +0,0 @@
|
||||
From 1536f1ec00ddc1729854b381cc0d54814bb6c19f Mon Sep 17 00:00:00 2001
|
||||
From: Igor Mammedov <imammedo@redhat.com>
|
||||
Date: Fri, 29 Dec 2023 15:04:55 +0100
|
||||
Subject: [PATCH 07/20] smbios: get rid of smbios_smp_sockets global
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 230: Workaround Windows failing to find 64bit SMBIOS entry point with SeaBIOS
|
||||
RH-Jira: RHEL-21705
|
||||
RH-Acked-by: MST <mst@redhat.com>
|
||||
RH-Acked-by: Ani Sinha <None>
|
||||
RH-Commit: [5/18] f59bfeb547b7febcf1de2b6179af006e7fa0bccd
|
||||
|
||||
JIRA: https://issues.redhat.com/browse/RHEL-21705
|
||||
|
||||
it makes smbios_validate_table() independent from
|
||||
smbios_smp_sockets global, which in turn lets
|
||||
smbios_get_tables() avoid using not related legacy code.
|
||||
|
||||
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
|
||||
Reviewed-by: Ani Sinha <anisinha@redhat.com>
|
||||
Tested-by: Fiona Ebner <f.ebner@proxmox.com>
|
||||
|
||||
Conflicts:
|
||||
include/hw/firmware/smbios.h due to down-stream
|
||||
(d9ff466c980d Machine type related general changes)
|
||||
adding custom stream_product/stream_version
|
||||
|
||||
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
|
||||
---
|
||||
hw/i386/fw_cfg.c | 2 +-
|
||||
hw/smbios/smbios.c | 22 +++++++++-------------
|
||||
include/hw/firmware/smbios.h | 2 +-
|
||||
3 files changed, 11 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/hw/i386/fw_cfg.c b/hw/i386/fw_cfg.c
|
||||
index ed72b1442d..79ff7f7225 100644
|
||||
--- a/hw/i386/fw_cfg.c
|
||||
+++ b/hw/i386/fw_cfg.c
|
||||
@@ -72,7 +72,7 @@ void fw_cfg_build_smbios(PCMachineState *pcms, FWCfgState *fw_cfg)
|
||||
/* tell smbios about cpuid version and features */
|
||||
smbios_set_cpuid(cpu->env.cpuid_version, cpu->env.features[FEAT_1_EDX]);
|
||||
|
||||
- smbios_tables = smbios_get_table_legacy(ms, &smbios_tables_len);
|
||||
+ smbios_tables = smbios_get_table_legacy(ms->smp.cpus, &smbios_tables_len);
|
||||
if (smbios_tables) {
|
||||
fw_cfg_add_bytes(fw_cfg, FW_CFG_SMBIOS_ENTRIES,
|
||||
smbios_tables, smbios_tables_len);
|
||||
diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c
|
||||
index b13e40bae2..8129d396d1 100644
|
||||
--- a/hw/smbios/smbios.c
|
||||
+++ b/hw/smbios/smbios.c
|
||||
@@ -73,7 +73,7 @@ static SmbiosEntryPoint ep;
|
||||
static int smbios_type4_count = 0;
|
||||
static bool smbios_immutable;
|
||||
static bool smbios_have_defaults;
|
||||
-static uint32_t smbios_cpuid_version, smbios_cpuid_features, smbios_smp_sockets;
|
||||
+static uint32_t smbios_cpuid_version, smbios_cpuid_features;
|
||||
|
||||
static DECLARE_BITMAP(have_binfile_bitmap, SMBIOS_MAX_TYPE+1);
|
||||
static DECLARE_BITMAP(have_fields_bitmap, SMBIOS_MAX_TYPE+1);
|
||||
@@ -524,14 +524,11 @@ opts_init(smbios_register_config);
|
||||
*/
|
||||
#define SMBIOS_21_MAX_TABLES_LEN 0xffff
|
||||
|
||||
-static void smbios_validate_table(MachineState *ms)
|
||||
+static void smbios_validate_table(uint32_t expected_t4_count)
|
||||
{
|
||||
- uint32_t expect_t4_count = smbios_legacy ?
|
||||
- ms->smp.cpus : smbios_smp_sockets;
|
||||
-
|
||||
- if (smbios_type4_count && smbios_type4_count != expect_t4_count) {
|
||||
+ if (smbios_type4_count && smbios_type4_count != expected_t4_count) {
|
||||
error_report("Expected %d SMBIOS Type 4 tables, got %d instead",
|
||||
- expect_t4_count, smbios_type4_count);
|
||||
+ expected_t4_count, smbios_type4_count);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -619,7 +616,7 @@ static void smbios_build_type_1_fields(void)
|
||||
}
|
||||
}
|
||||
|
||||
-uint8_t *smbios_get_table_legacy(MachineState *ms, size_t *length)
|
||||
+uint8_t *smbios_get_table_legacy(uint32_t expected_t4_count, size_t *length)
|
||||
{
|
||||
if (!smbios_legacy) {
|
||||
*length = 0;
|
||||
@@ -629,7 +626,7 @@ uint8_t *smbios_get_table_legacy(MachineState *ms, size_t *length)
|
||||
if (!smbios_immutable) {
|
||||
smbios_build_type_0_fields();
|
||||
smbios_build_type_1_fields();
|
||||
- smbios_validate_table(ms);
|
||||
+ smbios_validate_table(expected_t4_count);
|
||||
smbios_immutable = true;
|
||||
}
|
||||
*length = smbios_entries_len;
|
||||
@@ -1250,10 +1247,9 @@ void smbios_get_tables(MachineState *ms,
|
||||
smbios_build_type_2_table();
|
||||
smbios_build_type_3_table();
|
||||
|
||||
- smbios_smp_sockets = ms->smp.sockets;
|
||||
- assert(smbios_smp_sockets >= 1);
|
||||
+ assert(ms->smp.sockets >= 1);
|
||||
|
||||
- for (i = 0; i < smbios_smp_sockets; i++) {
|
||||
+ for (i = 0; i < ms->smp.sockets; i++) {
|
||||
smbios_build_type_4_table(ms, i);
|
||||
}
|
||||
|
||||
@@ -1299,7 +1295,7 @@ void smbios_get_tables(MachineState *ms,
|
||||
smbios_build_type_41_table(errp);
|
||||
smbios_build_type_127_table();
|
||||
|
||||
- smbios_validate_table(ms);
|
||||
+ smbios_validate_table(ms->smp.sockets);
|
||||
smbios_entry_point_setup();
|
||||
smbios_immutable = true;
|
||||
}
|
||||
diff --git a/include/hw/firmware/smbios.h b/include/hw/firmware/smbios.h
|
||||
index f8dd07fe4c..95ec64ce2c 100644
|
||||
--- a/include/hw/firmware/smbios.h
|
||||
+++ b/include/hw/firmware/smbios.h
|
||||
@@ -315,7 +315,7 @@ void smbios_set_defaults(const char *manufacturer, const char *product,
|
||||
const char *stream_product,
|
||||
const char *stream_version,
|
||||
SmbiosEntryPointType ep_type);
|
||||
-uint8_t *smbios_get_table_legacy(MachineState *ms, size_t *length);
|
||||
+uint8_t *smbios_get_table_legacy(uint32_t expected_t4_count, size_t *length);
|
||||
void smbios_get_tables(MachineState *ms,
|
||||
const struct smbios_phys_mem_area *mem_array,
|
||||
const unsigned int mem_array_size,
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,217 +0,0 @@
|
||||
From 7271c4424c6d90f0bb34f8090eb4e192eb2b2537 Mon Sep 17 00:00:00 2001
|
||||
From: Igor Mammedov <imammedo@redhat.com>
|
||||
Date: Tue, 20 Feb 2024 10:30:28 +0100
|
||||
Subject: [PATCH 14/20] smbios: handle errors consistently
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 230: Workaround Windows failing to find 64bit SMBIOS entry point with SeaBIOS
|
||||
RH-Jira: RHEL-21705
|
||||
RH-Acked-by: MST <mst@redhat.com>
|
||||
RH-Acked-by: Ani Sinha <None>
|
||||
RH-Commit: [12/18] d8a5a70602ae0665ce35e5bf87b2d8420f9189bc
|
||||
|
||||
JIRA: https://issues.redhat.com/browse/RHEL-21705
|
||||
|
||||
Current code uses mix of error_report()+exit(1)
|
||||
and error_setg() to handle errors.
|
||||
Use newer error_setg() everywhere, beside consistency
|
||||
it will allow to detect error condition without killing
|
||||
QEMU and attempt switch-over to SMBIOS3.x tables/entrypoint
|
||||
in follow up patch.
|
||||
|
||||
while at it, clear smbios_tables pointer after freeing.
|
||||
that will avoid double free if smbios_get_tables() is called
|
||||
multiple times.
|
||||
|
||||
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
|
||||
Reviewed-by: Ani Sinha <anisinha@redhat.com>
|
||||
|
||||
Conflicts: include/hw/firmware/smbios.h
|
||||
due to downstream specific smbios_set_defaults()
|
||||
|
||||
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
|
||||
---
|
||||
hw/i386/fw_cfg.c | 3 ++-
|
||||
hw/smbios/smbios.c | 34 ++++++++++++++++++++++------------
|
||||
hw/smbios/smbios_legacy.c | 22 ++++++++++++++--------
|
||||
include/hw/firmware/smbios.h | 4 ++--
|
||||
4 files changed, 40 insertions(+), 23 deletions(-)
|
||||
|
||||
diff --git a/hw/i386/fw_cfg.c b/hw/i386/fw_cfg.c
|
||||
index a25793a68f..bdc3cc4556 100644
|
||||
--- a/hw/i386/fw_cfg.c
|
||||
+++ b/hw/i386/fw_cfg.c
|
||||
@@ -73,7 +73,8 @@ void fw_cfg_build_smbios(PCMachineState *pcms, FWCfgState *fw_cfg)
|
||||
smbios_set_cpuid(cpu->env.cpuid_version, cpu->env.features[FEAT_1_EDX]);
|
||||
|
||||
if (pcmc->smbios_legacy_mode) {
|
||||
- smbios_tables = smbios_get_table_legacy(&smbios_tables_len);
|
||||
+ smbios_tables = smbios_get_table_legacy(&smbios_tables_len,
|
||||
+ &error_fatal);
|
||||
fw_cfg_add_bytes(fw_cfg, FW_CFG_SMBIOS_ENTRIES,
|
||||
smbios_tables, smbios_tables_len);
|
||||
return;
|
||||
diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c
|
||||
index e40204550e..b5745c6c2d 100644
|
||||
--- a/hw/smbios/smbios.c
|
||||
+++ b/hw/smbios/smbios.c
|
||||
@@ -19,7 +19,6 @@
|
||||
#include "qemu/units.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/config-file.h"
|
||||
-#include "qemu/error-report.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/option.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
@@ -497,23 +496,25 @@ opts_init(smbios_register_config);
|
||||
*/
|
||||
#define SMBIOS_21_MAX_TABLES_LEN 0xffff
|
||||
|
||||
-static void smbios_check_type4_count(uint32_t expected_t4_count)
|
||||
+static bool smbios_check_type4_count(uint32_t expected_t4_count, Error **errp)
|
||||
{
|
||||
if (smbios_type4_count && smbios_type4_count != expected_t4_count) {
|
||||
- error_report("Expected %d SMBIOS Type 4 tables, got %d instead",
|
||||
- expected_t4_count, smbios_type4_count);
|
||||
- exit(1);
|
||||
+ error_setg(errp, "Expected %d SMBIOS Type 4 tables, got %d instead",
|
||||
+ expected_t4_count, smbios_type4_count);
|
||||
+ return false;
|
||||
}
|
||||
+ return true;
|
||||
}
|
||||
|
||||
-void smbios_validate_table(void)
|
||||
+bool smbios_validate_table(Error **errp)
|
||||
{
|
||||
if (smbios_ep_type == SMBIOS_ENTRY_POINT_TYPE_32 &&
|
||||
smbios_tables_len > SMBIOS_21_MAX_TABLES_LEN) {
|
||||
- error_report("SMBIOS 2.1 table length %zu exceeds %d",
|
||||
- smbios_tables_len, SMBIOS_21_MAX_TABLES_LEN);
|
||||
- exit(1);
|
||||
+ error_setg(errp, "SMBIOS 2.1 table length %zu exceeds %d",
|
||||
+ smbios_tables_len, SMBIOS_21_MAX_TABLES_LEN);
|
||||
+ return false;
|
||||
}
|
||||
+ return true;
|
||||
}
|
||||
|
||||
bool smbios_skip_table(uint8_t type, bool required_table)
|
||||
@@ -1167,15 +1168,18 @@ void smbios_get_tables(MachineState *ms,
|
||||
smbios_build_type_41_table(errp);
|
||||
smbios_build_type_127_table();
|
||||
|
||||
- smbios_check_type4_count(ms->smp.sockets);
|
||||
- smbios_validate_table();
|
||||
+ if (!smbios_check_type4_count(ms->smp.sockets, errp)) {
|
||||
+ goto err_exit;
|
||||
+ }
|
||||
+ if (!smbios_validate_table(errp)) {
|
||||
+ goto err_exit;
|
||||
+ }
|
||||
smbios_entry_point_setup();
|
||||
|
||||
/* return tables blob and entry point (anchor), and their sizes */
|
||||
*tables = smbios_tables;
|
||||
*tables_len = smbios_tables_len;
|
||||
*anchor = (uint8_t *)&ep;
|
||||
-
|
||||
/* calculate length based on anchor string */
|
||||
if (!strncmp((char *)&ep, "_SM_", 4)) {
|
||||
*anchor_len = sizeof(struct smbios_21_entry_point);
|
||||
@@ -1184,6 +1188,12 @@ void smbios_get_tables(MachineState *ms,
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
+
|
||||
+ return;
|
||||
+err_exit:
|
||||
+ g_free(smbios_tables);
|
||||
+ smbios_tables = NULL;
|
||||
+ return;
|
||||
}
|
||||
|
||||
static void save_opt(const char **dest, QemuOpts *opts, const char *name)
|
||||
diff --git a/hw/smbios/smbios_legacy.c b/hw/smbios/smbios_legacy.c
|
||||
index 21f143e738..a6544bf55a 100644
|
||||
--- a/hw/smbios/smbios_legacy.c
|
||||
+++ b/hw/smbios/smbios_legacy.c
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "qemu/bswap.h"
|
||||
#include "hw/firmware/smbios.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
-#include "qemu/error-report.h"
|
||||
+#include "qapi/error.h"
|
||||
|
||||
struct smbios_header {
|
||||
uint16_t length;
|
||||
@@ -128,7 +128,7 @@ static void smbios_build_type_1_fields(void)
|
||||
}
|
||||
}
|
||||
|
||||
-uint8_t *smbios_get_table_legacy(size_t *length)
|
||||
+uint8_t *smbios_get_table_legacy(size_t *length, Error **errp)
|
||||
{
|
||||
int i;
|
||||
size_t usr_offset;
|
||||
@@ -136,15 +136,15 @@ uint8_t *smbios_get_table_legacy(size_t *length)
|
||||
/* complain if fields were given for types > 1 */
|
||||
if (find_next_bit(smbios_have_fields_bitmap,
|
||||
SMBIOS_MAX_TYPE + 1, 2) < SMBIOS_MAX_TYPE + 1) {
|
||||
- error_report("can't process fields for smbios "
|
||||
+ error_setg(errp, "can't process fields for smbios "
|
||||
"types > 1 on machine versions < 2.1!");
|
||||
- exit(1);
|
||||
+ goto err_exit;
|
||||
}
|
||||
|
||||
if (test_bit(4, smbios_have_binfile_bitmap)) {
|
||||
- error_report("can't process table for smbios "
|
||||
- "type 4 on machine versions < 2.1!");
|
||||
- exit(1);
|
||||
+ error_setg(errp, "can't process table for smbios "
|
||||
+ "type 4 on machine versions < 2.1!");
|
||||
+ goto err_exit;
|
||||
}
|
||||
|
||||
g_free(smbios_entries);
|
||||
@@ -173,7 +173,13 @@ uint8_t *smbios_get_table_legacy(size_t *length)
|
||||
|
||||
smbios_build_type_0_fields();
|
||||
smbios_build_type_1_fields();
|
||||
- smbios_validate_table();
|
||||
+ if (!smbios_validate_table(errp)) {
|
||||
+ goto err_exit;
|
||||
+ }
|
||||
+
|
||||
*length = smbios_entries_len;
|
||||
return smbios_entries;
|
||||
+err_exit:
|
||||
+ g_free(smbios_entries);
|
||||
+ return NULL;
|
||||
}
|
||||
diff --git a/include/hw/firmware/smbios.h b/include/hw/firmware/smbios.h
|
||||
index 92e9aba415..44af3a0d82 100644
|
||||
--- a/include/hw/firmware/smbios.h
|
||||
+++ b/include/hw/firmware/smbios.h
|
||||
@@ -326,7 +326,7 @@ struct smbios_type_127 {
|
||||
struct smbios_structure_header header;
|
||||
} QEMU_PACKED;
|
||||
|
||||
-void smbios_validate_table(void);
|
||||
+bool smbios_validate_table(Error **errp);
|
||||
void smbios_add_usr_blob_size(size_t size);
|
||||
void smbios_entry_add(QemuOpts *opts, Error **errp);
|
||||
void smbios_set_cpuid(uint32_t version, uint32_t features);
|
||||
@@ -336,7 +336,7 @@ void smbios_set_defaults(const char *manufacturer, const char *product,
|
||||
SmbiosEntryPointType ep_type,
|
||||
const char *stream_product,
|
||||
const char *stream_version);
|
||||
-uint8_t *smbios_get_table_legacy(size_t *length);
|
||||
+uint8_t *smbios_get_table_legacy(size_t *length, Error **errp);
|
||||
void smbios_get_tables(MachineState *ms,
|
||||
const struct smbios_phys_mem_area *mem_array,
|
||||
const unsigned int mem_array_size,
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,131 +0,0 @@
|
||||
From 38220bc61bdb1614f34a53481f7604720c9e9e5a Mon Sep 17 00:00:00 2001
|
||||
From: Igor Mammedov <imammedo@redhat.com>
|
||||
Date: Tue, 20 Feb 2024 10:41:06 +0100
|
||||
Subject: [PATCH 18/20] smbios: in case of entry point is 'auto' try to build
|
||||
v2 tables 1st
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 230: Workaround Windows failing to find 64bit SMBIOS entry point with SeaBIOS
|
||||
RH-Jira: RHEL-21705
|
||||
RH-Acked-by: MST <mst@redhat.com>
|
||||
RH-Acked-by: Ani Sinha <None>
|
||||
RH-Commit: [16/18] becbcb3d8dad4842e5939bb75e21f4e737a4a325
|
||||
|
||||
JIRA: https://issues.redhat.com/browse/RHEL-21705
|
||||
|
||||
QEMU for some time now uses SMBIOS 3.0 for PC/Q35 machines by
|
||||
default, however Windows has a bug in locating SMBIOS 3.0
|
||||
entrypoint and fails to find tables when booted on SeaBIOS
|
||||
(on UEFI SMBIOS 3.0 tables work fine since firmware hands
|
||||
over tables in another way)
|
||||
|
||||
Missing SMBIOS tables may lead to some issues for guest
|
||||
though (worst are: possible reactiveation, inability to
|
||||
get virtio drivers from 'Windows Update')
|
||||
|
||||
It's unclear at this point if MS will fix the issue on their
|
||||
side. So instead of it (or rather in addition) this patch
|
||||
will try to workaround the issue.
|
||||
|
||||
aka, use smbios-entry-point-type=auto to make QEMU try
|
||||
generating conservative SMBIOS 2.0 tables and if that
|
||||
fails (due to limits/requested configuration) fallback
|
||||
to SMBIOS 3.0 tables.
|
||||
|
||||
With this in place majority of users will use SMBIOS 2.0
|
||||
tables which work fine with (Windows + legacy BIOS).
|
||||
The configurations that is not to possible to describe
|
||||
with SMBIOS 2.0 will switch automatically to SMBIOS 3.0
|
||||
(which will trigger Windows bug but there is nothing
|
||||
QEMU can do here, so go and aks Microsoft to real fix).
|
||||
|
||||
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
|
||||
Reviewed-by: Ani Sinha <anisinha@redhat.com>
|
||||
Tested-by: Fiona Ebner <f.ebner@proxmox.com>
|
||||
---
|
||||
hw/smbios/smbios.c | 52 +++++++++++++++++++++++++++++++++++++++++++---
|
||||
1 file changed, 49 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c
|
||||
index 4521ea386c..3d9dcb0d31 100644
|
||||
--- a/hw/smbios/smbios.c
|
||||
+++ b/hw/smbios/smbios.c
|
||||
@@ -1097,7 +1097,7 @@ static void smbios_entry_point_setup(SmbiosEntryPointType ep_type)
|
||||
}
|
||||
}
|
||||
|
||||
-void smbios_get_tables(MachineState *ms,
|
||||
+static bool smbios_get_tables_ep(MachineState *ms,
|
||||
SmbiosEntryPointType ep_type,
|
||||
const struct smbios_phys_mem_area *mem_array,
|
||||
const unsigned int mem_array_size,
|
||||
@@ -1106,6 +1106,7 @@ void smbios_get_tables(MachineState *ms,
|
||||
Error **errp)
|
||||
{
|
||||
unsigned i, dimm_cnt, offset;
|
||||
+ ERRP_GUARD();
|
||||
|
||||
assert(ep_type == SMBIOS_ENTRY_POINT_TYPE_32 ||
|
||||
ep_type == SMBIOS_ENTRY_POINT_TYPE_64);
|
||||
@@ -1192,11 +1193,56 @@ void smbios_get_tables(MachineState *ms,
|
||||
abort();
|
||||
}
|
||||
|
||||
- return;
|
||||
+ return true;
|
||||
err_exit:
|
||||
g_free(smbios_tables);
|
||||
smbios_tables = NULL;
|
||||
- return;
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
+void smbios_get_tables(MachineState *ms,
|
||||
+ SmbiosEntryPointType ep_type,
|
||||
+ const struct smbios_phys_mem_area *mem_array,
|
||||
+ const unsigned int mem_array_size,
|
||||
+ uint8_t **tables, size_t *tables_len,
|
||||
+ uint8_t **anchor, size_t *anchor_len,
|
||||
+ Error **errp)
|
||||
+{
|
||||
+ Error *local_err = NULL;
|
||||
+ bool is_valid;
|
||||
+ ERRP_GUARD();
|
||||
+
|
||||
+ switch (ep_type) {
|
||||
+ case SMBIOS_ENTRY_POINT_TYPE_AUTO:
|
||||
+ case SMBIOS_ENTRY_POINT_TYPE_32:
|
||||
+ is_valid = smbios_get_tables_ep(ms, SMBIOS_ENTRY_POINT_TYPE_32,
|
||||
+ mem_array, mem_array_size,
|
||||
+ tables, tables_len,
|
||||
+ anchor, anchor_len,
|
||||
+ &local_err);
|
||||
+ if (is_valid || ep_type != SMBIOS_ENTRY_POINT_TYPE_AUTO) {
|
||||
+ break;
|
||||
+ }
|
||||
+ /*
|
||||
+ * fall through in case AUTO endpoint is selected and
|
||||
+ * SMBIOS 2.x tables can't be generated, to try if SMBIOS 3.x
|
||||
+ * tables would work
|
||||
+ */
|
||||
+ case SMBIOS_ENTRY_POINT_TYPE_64:
|
||||
+ error_free(local_err);
|
||||
+ local_err = NULL;
|
||||
+ is_valid = smbios_get_tables_ep(ms, SMBIOS_ENTRY_POINT_TYPE_64,
|
||||
+ mem_array, mem_array_size,
|
||||
+ tables, tables_len,
|
||||
+ anchor, anchor_len,
|
||||
+ &local_err);
|
||||
+ break;
|
||||
+ default:
|
||||
+ abort();
|
||||
+ }
|
||||
+ if (!is_valid) {
|
||||
+ error_propagate(errp, local_err);
|
||||
+ }
|
||||
}
|
||||
|
||||
static void save_opt(const char **dest, QemuOpts *opts, const char *name)
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,330 +0,0 @@
|
||||
From 36b0256e27f9d5268c5413891b4a7322819ae9db Mon Sep 17 00:00:00 2001
|
||||
From: Igor Mammedov <imammedo@redhat.com>
|
||||
Date: Mon, 4 Mar 2024 15:56:19 +0100
|
||||
Subject: [PATCH 12/20] smbios: rename/expose structures/bitmaps used by both
|
||||
legacy and modern code
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 230: Workaround Windows failing to find 64bit SMBIOS entry point with SeaBIOS
|
||||
RH-Jira: RHEL-21705
|
||||
RH-Acked-by: MST <mst@redhat.com>
|
||||
RH-Acked-by: Ani Sinha <None>
|
||||
RH-Commit: [10/18] 59fe438d5b7f6e584a6bb02597e4d4724fe2cece
|
||||
|
||||
JIRA: https://issues.redhat.com/browse/RHEL-21705
|
||||
|
||||
As a preparation to move legacy handling into a separate file,
|
||||
add prefix 'smbios_' to type0/type1/have_binfile_bitmap/have_fields_bitmap
|
||||
and expose them in smbios.h so that they can be reused in
|
||||
legacy and modern code.
|
||||
|
||||
Doing it as a separate patch to avoid rename cluttering follow-up
|
||||
patch which will move legacy code into a separate file.
|
||||
|
||||
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
|
||||
Reviewed-by: Ani Sinha <anisinha@redhat.com>
|
||||
|
||||
Conflicts: hw/smbios/smbios.c
|
||||
due to setting downstream type1.family/type1.sku defaults
|
||||
|
||||
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
|
||||
---
|
||||
hw/smbios/smbios.c | 117 ++++++++++++++++-------------------
|
||||
include/hw/firmware/smbios.h | 16 +++++
|
||||
2 files changed, 71 insertions(+), 62 deletions(-)
|
||||
|
||||
diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c
|
||||
index c48a290478..eb9927335d 100644
|
||||
--- a/hw/smbios/smbios.c
|
||||
+++ b/hw/smbios/smbios.c
|
||||
@@ -81,19 +81,11 @@ static int smbios_type4_count = 0;
|
||||
static bool smbios_have_defaults;
|
||||
static uint32_t smbios_cpuid_version, smbios_cpuid_features;
|
||||
|
||||
-static DECLARE_BITMAP(have_binfile_bitmap, SMBIOS_MAX_TYPE+1);
|
||||
-static DECLARE_BITMAP(have_fields_bitmap, SMBIOS_MAX_TYPE+1);
|
||||
+DECLARE_BITMAP(smbios_have_binfile_bitmap, SMBIOS_MAX_TYPE + 1);
|
||||
+DECLARE_BITMAP(smbios_have_fields_bitmap, SMBIOS_MAX_TYPE + 1);
|
||||
|
||||
-static struct {
|
||||
- const char *vendor, *version, *date;
|
||||
- bool have_major_minor, uefi;
|
||||
- uint8_t major, minor;
|
||||
-} type0;
|
||||
-
|
||||
-static struct {
|
||||
- const char *manufacturer, *product, *version, *serial, *sku, *family;
|
||||
- /* uuid is in qemu_uuid */
|
||||
-} type1;
|
||||
+smbios_type0_t smbios_type0;
|
||||
+smbios_type1_t smbios_type1;
|
||||
|
||||
static struct {
|
||||
const char *manufacturer, *product, *version, *serial, *asset, *location;
|
||||
@@ -584,36 +576,36 @@ static void smbios_maybe_add_str(int type, int offset, const char *data)
|
||||
static void smbios_build_type_0_fields(void)
|
||||
{
|
||||
smbios_maybe_add_str(0, offsetof(struct smbios_type_0, vendor_str),
|
||||
- type0.vendor);
|
||||
+ smbios_type0.vendor);
|
||||
smbios_maybe_add_str(0, offsetof(struct smbios_type_0, bios_version_str),
|
||||
- type0.version);
|
||||
+ smbios_type0.version);
|
||||
smbios_maybe_add_str(0, offsetof(struct smbios_type_0,
|
||||
bios_release_date_str),
|
||||
- type0.date);
|
||||
- if (type0.have_major_minor) {
|
||||
+ smbios_type0.date);
|
||||
+ if (smbios_type0.have_major_minor) {
|
||||
smbios_add_field(0, offsetof(struct smbios_type_0,
|
||||
system_bios_major_release),
|
||||
- &type0.major, 1);
|
||||
+ &smbios_type0.major, 1);
|
||||
smbios_add_field(0, offsetof(struct smbios_type_0,
|
||||
system_bios_minor_release),
|
||||
- &type0.minor, 1);
|
||||
+ &smbios_type0.minor, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void smbios_build_type_1_fields(void)
|
||||
{
|
||||
smbios_maybe_add_str(1, offsetof(struct smbios_type_1, manufacturer_str),
|
||||
- type1.manufacturer);
|
||||
+ smbios_type1.manufacturer);
|
||||
smbios_maybe_add_str(1, offsetof(struct smbios_type_1, product_name_str),
|
||||
- type1.product);
|
||||
+ smbios_type1.product);
|
||||
smbios_maybe_add_str(1, offsetof(struct smbios_type_1, version_str),
|
||||
- type1.version);
|
||||
+ smbios_type1.version);
|
||||
smbios_maybe_add_str(1, offsetof(struct smbios_type_1, serial_number_str),
|
||||
- type1.serial);
|
||||
+ smbios_type1.serial);
|
||||
smbios_maybe_add_str(1, offsetof(struct smbios_type_1, sku_number_str),
|
||||
- type1.sku);
|
||||
+ smbios_type1.sku);
|
||||
smbios_maybe_add_str(1, offsetof(struct smbios_type_1, family_str),
|
||||
- type1.family);
|
||||
+ smbios_type1.family);
|
||||
if (qemu_uuid_set) {
|
||||
/* We don't encode the UUID in the "wire format" here because this
|
||||
* function is for legacy mode and needs to keep the guest ABI, and
|
||||
@@ -631,14 +623,14 @@ uint8_t *smbios_get_table_legacy(size_t *length)
|
||||
size_t usr_offset;
|
||||
|
||||
/* also complain if fields were given for types > 1 */
|
||||
- if (find_next_bit(have_fields_bitmap,
|
||||
+ if (find_next_bit(smbios_have_fields_bitmap,
|
||||
SMBIOS_MAX_TYPE + 1, 2) < SMBIOS_MAX_TYPE + 1) {
|
||||
error_report("can't process fields for smbios "
|
||||
"types > 1 on machine versions < 2.1!");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
- if (test_bit(4, have_binfile_bitmap)) {
|
||||
+ if (test_bit(4, smbios_have_binfile_bitmap)) {
|
||||
error_report("can't process table for smbios "
|
||||
"type 4 on machine versions < 2.1!");
|
||||
exit(1);
|
||||
@@ -679,10 +671,10 @@ uint8_t *smbios_get_table_legacy(size_t *length)
|
||||
|
||||
bool smbios_skip_table(uint8_t type, bool required_table)
|
||||
{
|
||||
- if (test_bit(type, have_binfile_bitmap)) {
|
||||
+ if (test_bit(type, smbios_have_binfile_bitmap)) {
|
||||
return true; /* user provided their own binary blob(s) */
|
||||
}
|
||||
- if (test_bit(type, have_fields_bitmap)) {
|
||||
+ if (test_bit(type, smbios_have_fields_bitmap)) {
|
||||
return false; /* user provided fields via command line */
|
||||
}
|
||||
if (smbios_have_defaults && required_table) {
|
||||
@@ -710,25 +702,25 @@ static void smbios_build_type_0_table(void)
|
||||
{
|
||||
SMBIOS_BUILD_TABLE_PRE(0, T0_BASE, false); /* optional, leave up to BIOS */
|
||||
|
||||
- SMBIOS_TABLE_SET_STR(0, vendor_str, type0.vendor);
|
||||
- SMBIOS_TABLE_SET_STR(0, bios_version_str, type0.version);
|
||||
+ SMBIOS_TABLE_SET_STR(0, vendor_str, smbios_type0.vendor);
|
||||
+ SMBIOS_TABLE_SET_STR(0, bios_version_str, smbios_type0.version);
|
||||
|
||||
t->bios_starting_address_segment = cpu_to_le16(0xE800); /* from SeaBIOS */
|
||||
|
||||
- SMBIOS_TABLE_SET_STR(0, bios_release_date_str, type0.date);
|
||||
+ SMBIOS_TABLE_SET_STR(0, bios_release_date_str, smbios_type0.date);
|
||||
|
||||
t->bios_rom_size = 0; /* hardcoded in SeaBIOS with FIXME comment */
|
||||
|
||||
t->bios_characteristics = cpu_to_le64(0x08); /* Not supported */
|
||||
t->bios_characteristics_extension_bytes[0] = 0;
|
||||
t->bios_characteristics_extension_bytes[1] = 0x14; /* TCD/SVVP | VM */
|
||||
- if (type0.uefi) {
|
||||
+ if (smbios_type0.uefi) {
|
||||
t->bios_characteristics_extension_bytes[1] |= 0x08; /* |= UEFI */
|
||||
}
|
||||
|
||||
- if (type0.have_major_minor) {
|
||||
- t->system_bios_major_release = type0.major;
|
||||
- t->system_bios_minor_release = type0.minor;
|
||||
+ if (smbios_type0.have_major_minor) {
|
||||
+ t->system_bios_major_release = smbios_type0.major;
|
||||
+ t->system_bios_minor_release = smbios_type0.minor;
|
||||
} else {
|
||||
t->system_bios_major_release = 0;
|
||||
t->system_bios_minor_release = 0;
|
||||
@@ -758,18 +750,18 @@ static void smbios_build_type_1_table(void)
|
||||
{
|
||||
SMBIOS_BUILD_TABLE_PRE(1, T1_BASE, true); /* required */
|
||||
|
||||
- SMBIOS_TABLE_SET_STR(1, manufacturer_str, type1.manufacturer);
|
||||
- SMBIOS_TABLE_SET_STR(1, product_name_str, type1.product);
|
||||
- SMBIOS_TABLE_SET_STR(1, version_str, type1.version);
|
||||
- SMBIOS_TABLE_SET_STR(1, serial_number_str, type1.serial);
|
||||
+ SMBIOS_TABLE_SET_STR(1, manufacturer_str, smbios_type1.manufacturer);
|
||||
+ SMBIOS_TABLE_SET_STR(1, product_name_str, smbios_type1.product);
|
||||
+ SMBIOS_TABLE_SET_STR(1, version_str, smbios_type1.version);
|
||||
+ SMBIOS_TABLE_SET_STR(1, serial_number_str, smbios_type1.serial);
|
||||
if (qemu_uuid_set) {
|
||||
smbios_encode_uuid(&t->uuid, &qemu_uuid);
|
||||
} else {
|
||||
memset(&t->uuid, 0, 16);
|
||||
}
|
||||
t->wake_up_type = 0x06; /* power switch */
|
||||
- SMBIOS_TABLE_SET_STR(1, sku_number_str, type1.sku);
|
||||
- SMBIOS_TABLE_SET_STR(1, family_str, type1.family);
|
||||
+ SMBIOS_TABLE_SET_STR(1, sku_number_str, smbios_type1.sku);
|
||||
+ SMBIOS_TABLE_SET_STR(1, family_str, smbios_type1.family);
|
||||
|
||||
SMBIOS_BUILD_TABLE_POST;
|
||||
}
|
||||
@@ -1184,12 +1176,12 @@ void smbios_set_defaults(const char *manufacturer, const char *product,
|
||||
*
|
||||
* We get 'System Manufacturer' and 'Baseboard Manufacturer'
|
||||
*/
|
||||
- SMBIOS_SET_DEFAULT(type1.manufacturer, manufacturer);
|
||||
- SMBIOS_SET_DEFAULT(type1.product, product);
|
||||
- SMBIOS_SET_DEFAULT(type1.version, version);
|
||||
- SMBIOS_SET_DEFAULT(type1.family, "Red Hat Enterprise Linux");
|
||||
+ SMBIOS_SET_DEFAULT(smbios_type1.manufacturer, manufacturer);
|
||||
+ SMBIOS_SET_DEFAULT(smbios_type1.product, product);
|
||||
+ SMBIOS_SET_DEFAULT(smbios_type1.version, version);
|
||||
+ SMBIOS_SET_DEFAULT(smbios_type1.family, "Red Hat Enterprise Linux");
|
||||
if (stream_version != NULL) {
|
||||
- SMBIOS_SET_DEFAULT(type1.sku, stream_version);
|
||||
+ SMBIOS_SET_DEFAULT(smbios_type1.sku, stream_version);
|
||||
}
|
||||
SMBIOS_SET_DEFAULT(type2.manufacturer, manufacturer);
|
||||
if (stream_product != NULL) {
|
||||
@@ -1468,13 +1460,13 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
|
||||
}
|
||||
|
||||
if (header->type <= SMBIOS_MAX_TYPE) {
|
||||
- if (test_bit(header->type, have_fields_bitmap)) {
|
||||
+ if (test_bit(header->type, smbios_have_fields_bitmap)) {
|
||||
error_setg(errp,
|
||||
"can't load type %d struct, fields already specified!",
|
||||
header->type);
|
||||
return;
|
||||
}
|
||||
- set_bit(header->type, have_binfile_bitmap);
|
||||
+ set_bit(header->type, smbios_have_binfile_bitmap);
|
||||
}
|
||||
|
||||
if (header->type == 4) {
|
||||
@@ -1505,41 +1497,42 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
- if (test_bit(type, have_binfile_bitmap)) {
|
||||
+ if (test_bit(type, smbios_have_binfile_bitmap)) {
|
||||
error_setg(errp, "can't add fields, binary file already loaded!");
|
||||
return;
|
||||
}
|
||||
- set_bit(type, have_fields_bitmap);
|
||||
+ set_bit(type, smbios_have_fields_bitmap);
|
||||
|
||||
switch (type) {
|
||||
case 0:
|
||||
if (!qemu_opts_validate(opts, qemu_smbios_type0_opts, errp)) {
|
||||
return;
|
||||
}
|
||||
- save_opt(&type0.vendor, opts, "vendor");
|
||||
- save_opt(&type0.version, opts, "version");
|
||||
- save_opt(&type0.date, opts, "date");
|
||||
- type0.uefi = qemu_opt_get_bool(opts, "uefi", false);
|
||||
+ save_opt(&smbios_type0.vendor, opts, "vendor");
|
||||
+ save_opt(&smbios_type0.version, opts, "version");
|
||||
+ save_opt(&smbios_type0.date, opts, "date");
|
||||
+ smbios_type0.uefi = qemu_opt_get_bool(opts, "uefi", false);
|
||||
|
||||
val = qemu_opt_get(opts, "release");
|
||||
if (val) {
|
||||
- if (sscanf(val, "%hhu.%hhu", &type0.major, &type0.minor) != 2) {
|
||||
+ if (sscanf(val, "%hhu.%hhu", &smbios_type0.major,
|
||||
+ &smbios_type0.minor) != 2) {
|
||||
error_setg(errp, "Invalid release");
|
||||
return;
|
||||
}
|
||||
- type0.have_major_minor = true;
|
||||
+ smbios_type0.have_major_minor = true;
|
||||
}
|
||||
return;
|
||||
case 1:
|
||||
if (!qemu_opts_validate(opts, qemu_smbios_type1_opts, errp)) {
|
||||
return;
|
||||
}
|
||||
- save_opt(&type1.manufacturer, opts, "manufacturer");
|
||||
- save_opt(&type1.product, opts, "product");
|
||||
- save_opt(&type1.version, opts, "version");
|
||||
- save_opt(&type1.serial, opts, "serial");
|
||||
- save_opt(&type1.sku, opts, "sku");
|
||||
- save_opt(&type1.family, opts, "family");
|
||||
+ save_opt(&smbios_type1.manufacturer, opts, "manufacturer");
|
||||
+ save_opt(&smbios_type1.product, opts, "product");
|
||||
+ save_opt(&smbios_type1.version, opts, "version");
|
||||
+ save_opt(&smbios_type1.serial, opts, "serial");
|
||||
+ save_opt(&smbios_type1.sku, opts, "sku");
|
||||
+ save_opt(&smbios_type1.family, opts, "family");
|
||||
|
||||
val = qemu_opt_get(opts, "uuid");
|
||||
if (val) {
|
||||
diff --git a/include/hw/firmware/smbios.h b/include/hw/firmware/smbios.h
|
||||
index d55018e5e3..333de0d5fc 100644
|
||||
--- a/include/hw/firmware/smbios.h
|
||||
+++ b/include/hw/firmware/smbios.h
|
||||
@@ -2,6 +2,7 @@
|
||||
#define QEMU_SMBIOS_H
|
||||
|
||||
#include "qapi/qapi-types-machine.h"
|
||||
+#include "qemu/bitmap.h"
|
||||
|
||||
/*
|
||||
* SMBIOS Support
|
||||
@@ -16,8 +17,23 @@
|
||||
*
|
||||
*/
|
||||
|
||||
+typedef struct {
|
||||
+ const char *vendor, *version, *date;
|
||||
+ bool have_major_minor, uefi;
|
||||
+ uint8_t major, minor;
|
||||
+} smbios_type0_t;
|
||||
+extern smbios_type0_t smbios_type0;
|
||||
+
|
||||
+typedef struct {
|
||||
+ const char *manufacturer, *product, *version, *serial, *sku, *family;
|
||||
+ /* uuid is in qemu_uuid */
|
||||
+} smbios_type1_t;
|
||||
+extern smbios_type1_t smbios_type1;
|
||||
|
||||
#define SMBIOS_MAX_TYPE 127
|
||||
+extern DECLARE_BITMAP(smbios_have_binfile_bitmap, SMBIOS_MAX_TYPE + 1);
|
||||
+extern DECLARE_BITMAP(smbios_have_fields_bitmap, SMBIOS_MAX_TYPE + 1);
|
||||
+
|
||||
#define offsetofend(TYPE, MEMBER) \
|
||||
(offsetof(TYPE, MEMBER) + sizeof_field(TYPE, MEMBER))
|
||||
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,81 +0,0 @@
|
||||
From 6e4f68e9ba3fe75ca6f200f189f96bb402f0ee8e Mon Sep 17 00:00:00 2001
|
||||
From: Fiona Ebner <f.ebner@proxmox.com>
|
||||
Date: Wed, 24 Jan 2024 11:57:49 +0100
|
||||
Subject: [PATCH 02/20] ui/clipboard: add asserts for update and request
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
RH-Author: Jon Maloy <jmaloy@redhat.com>
|
||||
RH-MergeRequest: 228: ui/clipboard: mark type as not available when there is no data
|
||||
RH-Jira: RHEL-19629
|
||||
RH-Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com>
|
||||
RH-Acked-by: Gerd Hoffmann <None>
|
||||
RH-Commit: [2/2] 176b4b835fd8aa226f2fa93fd334b9384080cf21 (jmaloy/jmaloy-qemu-kvm-2)
|
||||
|
||||
JIRA: https://issues.redhat.com/browse/RHEL-19629
|
||||
CVE: CVE-2023-6683
|
||||
Upstream: Merged
|
||||
|
||||
ui/clipboard: add asserts for update and request
|
||||
|
||||
commit 9c416582611b7495bdddb4c5456c7acb64b78938
|
||||
Author: Fiona Ebner <f.ebner@proxmox.com>
|
||||
Date: Wed Jan 24 11:57:49 2024 +0100
|
||||
|
||||
ui/clipboard: add asserts for update and request
|
||||
|
||||
Should an issue like CVE-2023-6683 ever appear again in the future,
|
||||
it will be more obvious which assumption was violated.
|
||||
|
||||
Suggested-by: Marc-André Lureau <marcandre.lureau@redhat.com>
|
||||
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
|
||||
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
|
||||
Message-ID: <20240124105749.204610-2-f.ebner@proxmox.com>
|
||||
|
||||
Signed-off-by: Jon Maloy <jmaloy@redhat.com>
|
||||
---
|
||||
ui/clipboard.c | 14 ++++++++++++++
|
||||
1 file changed, 14 insertions(+)
|
||||
|
||||
diff --git a/ui/clipboard.c b/ui/clipboard.c
|
||||
index b3f6fa3c9e..4264884a6c 100644
|
||||
--- a/ui/clipboard.c
|
||||
+++ b/ui/clipboard.c
|
||||
@@ -65,12 +65,24 @@ bool qemu_clipboard_check_serial(QemuClipboardInfo *info, bool client)
|
||||
|
||||
void qemu_clipboard_update(QemuClipboardInfo *info)
|
||||
{
|
||||
+ uint32_t type;
|
||||
QemuClipboardNotify notify = {
|
||||
.type = QEMU_CLIPBOARD_UPDATE_INFO,
|
||||
.info = info,
|
||||
};
|
||||
assert(info->selection < QEMU_CLIPBOARD_SELECTION__COUNT);
|
||||
|
||||
+ for (type = 0; type < QEMU_CLIPBOARD_TYPE__COUNT; type++) {
|
||||
+ /*
|
||||
+ * If data is missing, the clipboard owner's 'request' callback needs to
|
||||
+ * be set. Otherwise, there is no way to get the clipboard data and
|
||||
+ * qemu_clipboard_request() cannot be called.
|
||||
+ */
|
||||
+ if (info->types[type].available && !info->types[type].data) {
|
||||
+ assert(info->owner && info->owner->request);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
notifier_list_notify(&clipboard_notifiers, ¬ify);
|
||||
|
||||
if (cbinfo[info->selection] != info) {
|
||||
@@ -132,6 +144,8 @@ void qemu_clipboard_request(QemuClipboardInfo *info,
|
||||
!info->owner)
|
||||
return;
|
||||
|
||||
+ assert(info->owner->request);
|
||||
+
|
||||
info->types[type].requested = true;
|
||||
info->owner->request(info, type);
|
||||
}
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,107 +0,0 @@
|
||||
From 097516bef2993d917e76d92066ca2eb067e45394 Mon Sep 17 00:00:00 2001
|
||||
From: Fiona Ebner <f.ebner@proxmox.com>
|
||||
Date: Wed, 24 Jan 2024 11:57:48 +0100
|
||||
Subject: [PATCH 01/20] ui/clipboard: mark type as not available when there is
|
||||
no data
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
RH-Author: Jon Maloy <jmaloy@redhat.com>
|
||||
RH-MergeRequest: 228: ui/clipboard: mark type as not available when there is no data
|
||||
RH-Jira: RHEL-19629
|
||||
RH-Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com>
|
||||
RH-Acked-by: Gerd Hoffmann <None>
|
||||
RH-Commit: [1/2] 74ded03d6376f9693733d673502219f76eab7099 (jmaloy/jmaloy-qemu-kvm-2)
|
||||
|
||||
JIRA: https://issues.redhat.com/browse/RHEL-19629
|
||||
CVE: CVE-2023-6683
|
||||
Upstream: Merged
|
||||
|
||||
commit 405484b29f6548c7b86549b0f961b906337aa68a
|
||||
Author: Fiona Ebner <f.ebner@proxmox.com>
|
||||
Date: Wed Jan 24 11:57:48 2024 +0100
|
||||
|
||||
ui/clipboard: mark type as not available when there is no data
|
||||
|
||||
With VNC, a client can send a non-extended VNC_MSG_CLIENT_CUT_TEXT
|
||||
message with len=0. In qemu_clipboard_set_data(), the clipboard info
|
||||
will be updated setting data to NULL (because g_memdup(data, size)
|
||||
returns NULL when size is 0). If the client does not set the
|
||||
VNC_ENCODING_CLIPBOARD_EXT feature when setting up the encodings, then
|
||||
the 'request' callback for the clipboard peer is not initialized.
|
||||
Later, because data is NULL, qemu_clipboard_request() can be reached
|
||||
via vdagent_chr_write() and vdagent_clipboard_recv_request() and
|
||||
there, the clipboard owner's 'request' callback will be attempted to
|
||||
be called, but that is a NULL pointer.
|
||||
|
||||
In particular, this can happen when using the KRDC (22.12.3) VNC
|
||||
client.
|
||||
|
||||
Another scenario leading to the same issue is with two clients (say
|
||||
noVNC and KRDC):
|
||||
|
||||
The noVNC client sets the extension VNC_FEATURE_CLIPBOARD_EXT and
|
||||
initializes its cbpeer.
|
||||
|
||||
The KRDC client does not, but triggers a vnc_client_cut_text() (note
|
||||
it's not the _ext variant)). There, a new clipboard info with it as
|
||||
the 'owner' is created and via qemu_clipboard_set_data() is called,
|
||||
which in turn calls qemu_clipboard_update() with that info.
|
||||
|
||||
In qemu_clipboard_update(), the notifier for the noVNC client will be
|
||||
called, i.e. vnc_clipboard_notify() and also set vs->cbinfo for the
|
||||
noVNC client. The 'owner' in that clipboard info is the clipboard peer
|
||||
for the KRDC client, which did not initialize the 'request' function.
|
||||
That sounds correct to me, it is the owner of that clipboard info.
|
||||
|
||||
Then when noVNC sends a VNC_MSG_CLIENT_CUT_TEXT message (it did set
|
||||
the VNC_FEATURE_CLIPBOARD_EXT feature correctly, so a check for it
|
||||
passes), that clipboard info is passed to qemu_clipboard_request() and
|
||||
the original segfault still happens.
|
||||
|
||||
Fix the issue by handling updates with size 0 differently. In
|
||||
particular, mark in the clipboard info that the type is not available.
|
||||
|
||||
While at it, switch to g_memdup2(), because g_memdup() is deprecated.
|
||||
|
||||
Cc: qemu-stable@nongnu.org
|
||||
Fixes: CVE-2023-6683
|
||||
Reported-by: Markus Frank <m.frank@proxmox.com>
|
||||
Suggested-by: Marc-André Lureau <marcandre.lureau@redhat.com>
|
||||
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
|
||||
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
|
||||
Tested-by: Markus Frank <m.frank@proxmox.com>
|
||||
Message-ID: <20240124105749.204610-1-f.ebner@proxmox.com>
|
||||
|
||||
Signed-off-by: Jon Maloy <jmaloy@redhat.com>
|
||||
---
|
||||
ui/clipboard.c | 12 +++++++++---
|
||||
1 file changed, 9 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/ui/clipboard.c b/ui/clipboard.c
|
||||
index 3d14bffaf8..b3f6fa3c9e 100644
|
||||
--- a/ui/clipboard.c
|
||||
+++ b/ui/clipboard.c
|
||||
@@ -163,9 +163,15 @@ void qemu_clipboard_set_data(QemuClipboardPeer *peer,
|
||||
}
|
||||
|
||||
g_free(info->types[type].data);
|
||||
- info->types[type].data = g_memdup(data, size);
|
||||
- info->types[type].size = size;
|
||||
- info->types[type].available = true;
|
||||
+ if (size) {
|
||||
+ info->types[type].data = g_memdup2(data, size);
|
||||
+ info->types[type].size = size;
|
||||
+ info->types[type].available = true;
|
||||
+ } else {
|
||||
+ info->types[type].data = NULL;
|
||||
+ info->types[type].size = 0;
|
||||
+ info->types[type].available = false;
|
||||
+ }
|
||||
|
||||
if (update) {
|
||||
qemu_clipboard_update(info);
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,196 +0,0 @@
|
||||
From 523423436e83b01a83c60bc44bd08471992aaff4 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
|
||||
Date: Mon, 15 Jan 2024 16:34:33 +0400
|
||||
Subject: [PATCH 1/4] virtio-gpu: fix scanout migration post-load
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
RH-Author: Marc-André Lureau <marcandre.lureau@redhat.com>
|
||||
RH-MergeRequest: 377: virtio-gpu: fix scanout migration post-load
|
||||
RH-Jira: RHEL-36181
|
||||
RH-Acked-by: Peter Xu <peterx@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [1/3] 05e9dbf7f602d62ec2f336a855daf57e6ee8f3f3
|
||||
|
||||
The current post-loading code for scanout has a FIXME: it doesn't take
|
||||
the resource region/rect into account. But there is more, when adding
|
||||
blob migration support in commit f66767f75c9, I didn't realize that blob
|
||||
resources could be used for scanouts. This situationn leads to a crash
|
||||
during post-load, as they don't have an associated res->image.
|
||||
|
||||
virtio_gpu_do_set_scanout() handle all cases, but requires the
|
||||
associated virtio_gpu_framebuffer, which is currently not saved during
|
||||
migration.
|
||||
|
||||
Add a v2 of "virtio-gpu-one-scanout" with the framebuffer fields, so we
|
||||
can restore blob scanouts, as well as fixing the existing FIXME.
|
||||
|
||||
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
|
||||
Reviewed-by: Sebastian Ott <sebott@redhat.com>
|
||||
(cherry picked from commit dfcf74fa68c88233209aafc5f82728d0b9a1af5c)
|
||||
---
|
||||
hw/display/virtio-gpu.c | 55 +++++++++++++++++++++++++++-------
|
||||
include/hw/virtio/virtio-gpu.h | 1 +
|
||||
2 files changed, 46 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
|
||||
index 1702190ead..bc485d60ea 100644
|
||||
--- a/hw/display/virtio-gpu.c
|
||||
+++ b/hw/display/virtio-gpu.c
|
||||
@@ -598,6 +598,7 @@ static void virtio_unref_resource(pixman_image_t *image, void *data)
|
||||
static void virtio_gpu_update_scanout(VirtIOGPU *g,
|
||||
uint32_t scanout_id,
|
||||
struct virtio_gpu_simple_resource *res,
|
||||
+ struct virtio_gpu_framebuffer *fb,
|
||||
struct virtio_gpu_rect *r)
|
||||
{
|
||||
struct virtio_gpu_simple_resource *ores;
|
||||
@@ -615,9 +616,10 @@ static void virtio_gpu_update_scanout(VirtIOGPU *g,
|
||||
scanout->y = r->y;
|
||||
scanout->width = r->width;
|
||||
scanout->height = r->height;
|
||||
+ scanout->fb = *fb;
|
||||
}
|
||||
|
||||
-static void virtio_gpu_do_set_scanout(VirtIOGPU *g,
|
||||
+static bool virtio_gpu_do_set_scanout(VirtIOGPU *g,
|
||||
uint32_t scanout_id,
|
||||
struct virtio_gpu_framebuffer *fb,
|
||||
struct virtio_gpu_simple_resource *res,
|
||||
@@ -643,7 +645,7 @@ static void virtio_gpu_do_set_scanout(VirtIOGPU *g,
|
||||
r->x, r->y, r->width, r->height,
|
||||
fb->width, fb->height);
|
||||
*error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
|
||||
- return;
|
||||
+ return false;
|
||||
}
|
||||
|
||||
g->parent_obj.enable = 1;
|
||||
@@ -651,11 +653,12 @@ static void virtio_gpu_do_set_scanout(VirtIOGPU *g,
|
||||
if (res->blob) {
|
||||
if (console_has_gl(scanout->con)) {
|
||||
if (!virtio_gpu_update_dmabuf(g, scanout_id, res, fb, r)) {
|
||||
- virtio_gpu_update_scanout(g, scanout_id, res, r);
|
||||
+ virtio_gpu_update_scanout(g, scanout_id, res, fb, r);
|
||||
} else {
|
||||
*error = VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY;
|
||||
+ return false;
|
||||
}
|
||||
- return;
|
||||
+ return true;
|
||||
}
|
||||
|
||||
data = res->blob;
|
||||
@@ -684,7 +687,7 @@ static void virtio_gpu_do_set_scanout(VirtIOGPU *g,
|
||||
scanout->ds = qemu_create_displaysurface_pixman(rect);
|
||||
if (!scanout->ds) {
|
||||
*error = VIRTIO_GPU_RESP_ERR_UNSPEC;
|
||||
- return;
|
||||
+ return false;
|
||||
}
|
||||
#ifdef WIN32
|
||||
qemu_displaysurface_win32_set_handle(scanout->ds, res->handle, fb->offset);
|
||||
@@ -695,7 +698,8 @@ static void virtio_gpu_do_set_scanout(VirtIOGPU *g,
|
||||
scanout->ds);
|
||||
}
|
||||
|
||||
- virtio_gpu_update_scanout(g, scanout_id, res, r);
|
||||
+ virtio_gpu_update_scanout(g, scanout_id, res, fb, r);
|
||||
+ return true;
|
||||
}
|
||||
|
||||
static void virtio_gpu_set_scanout(VirtIOGPU *g,
|
||||
@@ -1166,8 +1170,9 @@ static void virtio_gpu_cursor_bh(void *opaque)
|
||||
|
||||
static const VMStateDescription vmstate_virtio_gpu_scanout = {
|
||||
.name = "virtio-gpu-one-scanout",
|
||||
- .version_id = 1,
|
||||
- .fields = (VMStateField[]) {
|
||||
+ .version_id = 2,
|
||||
+ .minimum_version_id = 1,
|
||||
+ .fields = (const VMStateField[]) {
|
||||
VMSTATE_UINT32(resource_id, struct virtio_gpu_scanout),
|
||||
VMSTATE_UINT32(width, struct virtio_gpu_scanout),
|
||||
VMSTATE_UINT32(height, struct virtio_gpu_scanout),
|
||||
@@ -1178,6 +1183,12 @@ static const VMStateDescription vmstate_virtio_gpu_scanout = {
|
||||
VMSTATE_UINT32(cursor.hot_y, struct virtio_gpu_scanout),
|
||||
VMSTATE_UINT32(cursor.pos.x, struct virtio_gpu_scanout),
|
||||
VMSTATE_UINT32(cursor.pos.y, struct virtio_gpu_scanout),
|
||||
+ VMSTATE_UINT32_V(fb.format, struct virtio_gpu_scanout, 2),
|
||||
+ VMSTATE_UINT32_V(fb.bytes_pp, struct virtio_gpu_scanout, 2),
|
||||
+ VMSTATE_UINT32_V(fb.width, struct virtio_gpu_scanout, 2),
|
||||
+ VMSTATE_UINT32_V(fb.height, struct virtio_gpu_scanout, 2),
|
||||
+ VMSTATE_UINT32_V(fb.stride, struct virtio_gpu_scanout, 2),
|
||||
+ VMSTATE_UINT32_V(fb.offset, struct virtio_gpu_scanout, 2),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
};
|
||||
@@ -1349,6 +1360,7 @@ static int virtio_gpu_blob_save(QEMUFile *f, void *opaque, size_t size,
|
||||
if (!res->blob_size) {
|
||||
continue;
|
||||
}
|
||||
+ assert(!res->image);
|
||||
qemu_put_be32(f, res->resource_id);
|
||||
qemu_put_be32(f, res->blob_size);
|
||||
qemu_put_be32(f, res->iov_cnt);
|
||||
@@ -1411,11 +1423,11 @@ static int virtio_gpu_post_load(void *opaque, int version_id)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < g->parent_obj.conf.max_outputs; i++) {
|
||||
- /* FIXME: should take scanout.r.{x,y} into account */
|
||||
scanout = &g->parent_obj.scanout[i];
|
||||
if (!scanout->resource_id) {
|
||||
continue;
|
||||
}
|
||||
+
|
||||
res = virtio_gpu_find_resource(g, scanout->resource_id);
|
||||
if (!res) {
|
||||
return -EINVAL;
|
||||
@@ -1428,7 +1440,30 @@ static int virtio_gpu_post_load(void *opaque, int version_id)
|
||||
qemu_displaysurface_win32_set_handle(scanout->ds, res->handle, 0);
|
||||
#endif
|
||||
|
||||
- dpy_gfx_replace_surface(scanout->con, scanout->ds);
|
||||
+ if (scanout->fb.format != 0) {
|
||||
+ uint32_t error = 0;
|
||||
+ struct virtio_gpu_rect r = {
|
||||
+ .x = scanout->x,
|
||||
+ .y = scanout->y,
|
||||
+ .width = scanout->width,
|
||||
+ .height = scanout->height
|
||||
+ };
|
||||
+
|
||||
+ if (!virtio_gpu_do_set_scanout(g, i, &scanout->fb, res, &r, &error)) {
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ } else {
|
||||
+ /* legacy v1 migration support */
|
||||
+ if (!res->image) {
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ scanout->ds = qemu_create_displaysurface_pixman(res->image);
|
||||
+#ifdef WIN32
|
||||
+ qemu_displaysurface_win32_set_handle(scanout->ds, res->handle, 0);
|
||||
+#endif
|
||||
+ dpy_gfx_replace_surface(scanout->con, scanout->ds);
|
||||
+ }
|
||||
+
|
||||
dpy_gfx_update_full(scanout->con);
|
||||
if (scanout->cursor.resource_id) {
|
||||
update_cursor(g, &scanout->cursor);
|
||||
diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h
|
||||
index 584ba2ed73..9a13afb34e 100644
|
||||
--- a/include/hw/virtio/virtio-gpu.h
|
||||
+++ b/include/hw/virtio/virtio-gpu.h
|
||||
@@ -81,6 +81,7 @@ struct virtio_gpu_scanout {
|
||||
uint32_t resource_id;
|
||||
struct virtio_gpu_update_cursor cursor;
|
||||
QEMUCursor *current_cursor;
|
||||
+ struct virtio_gpu_framebuffer fb;
|
||||
};
|
||||
|
||||
struct virtio_gpu_requested_state {
|
||||
--
|
||||
2.39.3
|
||||
|
@ -1,122 +0,0 @@
|
||||
From 7741a7d1c1d719ff681f73a023f27d5951b98882 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
|
||||
Date: Thu, 16 May 2024 12:40:22 +0400
|
||||
Subject: [PATCH 2/4] virtio-gpu: fix v2 migration
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
RH-Author: Marc-André Lureau <marcandre.lureau@redhat.com>
|
||||
RH-MergeRequest: 377: virtio-gpu: fix scanout migration post-load
|
||||
RH-Jira: RHEL-36181
|
||||
RH-Acked-by: Peter Xu <peterx@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [2/3] 482c37c10ac7e5e8a6c36ac2eb806ac02beeefdc
|
||||
|
||||
Commit dfcf74fa ("virtio-gpu: fix scanout migration post-load") broke
|
||||
forward/backward version migration. Versioning of nested VMSD structures
|
||||
is not straightforward, as the wire format doesn't have nested
|
||||
structures versions. Introduce x-scanout-vmstate-version and a field
|
||||
test to save/load appropriately according to the machine version.
|
||||
|
||||
Fixes: dfcf74fa ("virtio-gpu: fix scanout migration post-load")
|
||||
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
|
||||
Signed-off-by: Peter Xu <peterx@redhat.com>
|
||||
Reviewed-by: Fiona Ebner <f.ebner@proxmox.com>
|
||||
Tested-by: Fiona Ebner <f.ebner@proxmox.com>
|
||||
[fixed long lines]
|
||||
Signed-off-by: Fabiano Rosas <farosas@suse.de>
|
||||
|
||||
[ Move the hw-compat from 8.2 to 8.1 ]
|
||||
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
|
||||
(cherry picked from commit 40a23ef643664b5c1021a9789f9d680b6294fb50)
|
||||
---
|
||||
hw/core/machine.c | 1 +
|
||||
hw/display/virtio-gpu.c | 30 ++++++++++++++++++++++--------
|
||||
include/hw/virtio/virtio-gpu.h | 1 +
|
||||
3 files changed, 24 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/hw/core/machine.c b/hw/core/machine.c
|
||||
index 309f6ba685..a0843ab93e 100644
|
||||
--- a/hw/core/machine.c
|
||||
+++ b/hw/core/machine.c
|
||||
@@ -37,6 +37,7 @@ GlobalProperty hw_compat_8_1[] = {
|
||||
{ "ramfb", "x-migrate", "off" },
|
||||
{ "vfio-pci-nohotplug", "x-ramfb-migrate", "off" },
|
||||
{ "igb", "x-pcie-flr-init", "off" },
|
||||
+ { "virtio-gpu-device", "x-scanout-vmstate-version", "1" },
|
||||
};
|
||||
const size_t hw_compat_8_1_len = G_N_ELEMENTS(hw_compat_8_1);
|
||||
|
||||
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
|
||||
index bc485d60ea..9d35a016ae 100644
|
||||
--- a/hw/display/virtio-gpu.c
|
||||
+++ b/hw/display/virtio-gpu.c
|
||||
@@ -1168,10 +1168,17 @@ static void virtio_gpu_cursor_bh(void *opaque)
|
||||
virtio_gpu_handle_cursor(&g->parent_obj.parent_obj, g->cursor_vq);
|
||||
}
|
||||
|
||||
+static bool scanout_vmstate_after_v2(void *opaque, int version)
|
||||
+{
|
||||
+ struct VirtIOGPUBase *base = container_of(opaque, VirtIOGPUBase, scanout);
|
||||
+ struct VirtIOGPU *gpu = container_of(base, VirtIOGPU, parent_obj);
|
||||
+
|
||||
+ return gpu->scanout_vmstate_version >= 2;
|
||||
+}
|
||||
+
|
||||
static const VMStateDescription vmstate_virtio_gpu_scanout = {
|
||||
.name = "virtio-gpu-one-scanout",
|
||||
- .version_id = 2,
|
||||
- .minimum_version_id = 1,
|
||||
+ .version_id = 1,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_UINT32(resource_id, struct virtio_gpu_scanout),
|
||||
VMSTATE_UINT32(width, struct virtio_gpu_scanout),
|
||||
@@ -1183,12 +1190,18 @@ static const VMStateDescription vmstate_virtio_gpu_scanout = {
|
||||
VMSTATE_UINT32(cursor.hot_y, struct virtio_gpu_scanout),
|
||||
VMSTATE_UINT32(cursor.pos.x, struct virtio_gpu_scanout),
|
||||
VMSTATE_UINT32(cursor.pos.y, struct virtio_gpu_scanout),
|
||||
- VMSTATE_UINT32_V(fb.format, struct virtio_gpu_scanout, 2),
|
||||
- VMSTATE_UINT32_V(fb.bytes_pp, struct virtio_gpu_scanout, 2),
|
||||
- VMSTATE_UINT32_V(fb.width, struct virtio_gpu_scanout, 2),
|
||||
- VMSTATE_UINT32_V(fb.height, struct virtio_gpu_scanout, 2),
|
||||
- VMSTATE_UINT32_V(fb.stride, struct virtio_gpu_scanout, 2),
|
||||
- VMSTATE_UINT32_V(fb.offset, struct virtio_gpu_scanout, 2),
|
||||
+ VMSTATE_UINT32_TEST(fb.format, struct virtio_gpu_scanout,
|
||||
+ scanout_vmstate_after_v2),
|
||||
+ VMSTATE_UINT32_TEST(fb.bytes_pp, struct virtio_gpu_scanout,
|
||||
+ scanout_vmstate_after_v2),
|
||||
+ VMSTATE_UINT32_TEST(fb.width, struct virtio_gpu_scanout,
|
||||
+ scanout_vmstate_after_v2),
|
||||
+ VMSTATE_UINT32_TEST(fb.height, struct virtio_gpu_scanout,
|
||||
+ scanout_vmstate_after_v2),
|
||||
+ VMSTATE_UINT32_TEST(fb.stride, struct virtio_gpu_scanout,
|
||||
+ scanout_vmstate_after_v2),
|
||||
+ VMSTATE_UINT32_TEST(fb.offset, struct virtio_gpu_scanout,
|
||||
+ scanout_vmstate_after_v2),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
};
|
||||
@@ -1668,6 +1681,7 @@ static Property virtio_gpu_properties[] = {
|
||||
DEFINE_PROP_BIT("blob", VirtIOGPU, parent_obj.conf.flags,
|
||||
VIRTIO_GPU_FLAG_BLOB_ENABLED, false),
|
||||
DEFINE_PROP_SIZE("hostmem", VirtIOGPU, parent_obj.conf.hostmem, 0),
|
||||
+ DEFINE_PROP_UINT8("x-scanout-vmstate-version", VirtIOGPU, scanout_vmstate_version, 2),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h
|
||||
index 9a13afb34e..18500432c6 100644
|
||||
--- a/include/hw/virtio/virtio-gpu.h
|
||||
+++ b/include/hw/virtio/virtio-gpu.h
|
||||
@@ -177,6 +177,7 @@ typedef struct VGPUDMABuf {
|
||||
struct VirtIOGPU {
|
||||
VirtIOGPUBase parent_obj;
|
||||
|
||||
+ uint8_t scanout_vmstate_version;
|
||||
uint64_t conf_max_hostmem;
|
||||
|
||||
VirtQueue *ctrl_vq;
|
||||
--
|
||||
2.39.3
|
||||
|
Loading…
Reference in new issue