Older QEMU versions did fixup the ram size to match what can be reported
via sclp. We need to mimic this behaviour for machine types 4.2 and
older to not fail on inbound migration for memory sizes that do not fit.
Old machines with proper aligned memory sizes are not affected.
Alignment table:
VM size (<=) | Alignment
--------------------------
1020M | 1M
2040M | 2M
4080M | 4M
8160M | 8M
16320M | 16M
32640M | 32M
65280M | 64M
130560M | 128M
261120M | 256M
522240M | 512M
1044480M | 1G
2088960M | 2G
4177920M | 4G
8355840M | 8G
Suggested action is to replace unaligned -m value with a suitable
aligned one or if a change to a newer machine type is possible, use a
machine version >= 5.0.
A future version might remove the compatibility handling.
For machine types >= 5.0 we can simply use an increment size of 1M and
use the full range of increment number which allows for all possible
memory sizes. The old limitation of having a maximum of 1020 increments
was added for standby memory, which we no longer support. With that we
can now support even weird memory sizes like
10001234 MB.
As we no longer fixup maxram_size as well, make other users use ram_size
instead. Keep using maxram_size when setting the maximum ram size in KVM,
as that will come in handy in the future when supporting memory hotplug
(in contrast, storage keys and storage attributes for hotplugged memory
will have to be migrated per RAM block in the future).
Fixes: 3a12fc61af5c ("390x/s390-virtio-ccw: use memdev for RAM")
Reported-by: Lukáš Doktor <ldoktor@redhat.com>
Signed-off-by: David Hildenbrand <david@redhat.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Reviewed-by: David Hildenbrand <david@redhat.com>
Acked-by: Igor Mammedov <imammedo@redhat.com>
Cc: Igor Mammedov <imammedo@redhat.com>
Cc: Dr. David Alan Gilbert <dgilbert@redhat.com>
Message-Id: <
20200401123754.109602-1-borntraeger@de.ibm.com>
[CH: fixed up message on memory size fixup]
Signed-off-by: Cornelia Huck <cohuck@redhat.com>
QEMUS390SKeysState *skeys = QEMU_S390_SKEYS(obj);
MachineState *machine = MACHINE(qdev_get_machine());
- skeys->key_count = machine->maxram_size / TARGET_PAGE_SIZE;
+ skeys->key_count = machine->ram_size / TARGET_PAGE_SIZE;
skeys->keydata = g_malloc0(skeys->key_count);
}
{
KVMS390StAttribState *sas = KVM_S390_STATTRIB(sa);
MachineState *machine = MACHINE(qdev_get_machine());
- unsigned long max = machine->maxram_size / TARGET_PAGE_SIZE;
+ unsigned long max = machine->ram_size / TARGET_PAGE_SIZE;
if (start_gfn + count > max) {
error_report("Out of memory bounds when setting storage attributes");
{
KVMS390StAttribState *sas = KVM_S390_STATTRIB(sa);
MachineState *machine = MACHINE(qdev_get_machine());
- unsigned long max = machine->maxram_size / TARGET_PAGE_SIZE;
+ unsigned long max = machine->ram_size / TARGET_PAGE_SIZE;
/* We do not need to reach the maximum buffer size allowed */
unsigned long cx, len = KVM_S390_SKEYS_MAX / 2;
int r;
#include "qemu/ctype.h"
#include "qemu/error-report.h"
#include "qemu/option.h"
+#include "qemu/qemu-print.h"
#include "s390-pci-bus.h"
#include "sysemu/reset.h"
#include "hw/s390x/storage-keys.h"
s390_cpu_restart(S390_CPU(cs));
}
+static ram_addr_t s390_fixup_ram_size(ram_addr_t sz)
+{
+ /* same logic as in sclp.c */
+ int increment_size = 20;
+ ram_addr_t newsz;
+
+ while ((sz >> increment_size) > MAX_STORAGE_INCREMENTS) {
+ increment_size++;
+ }
+ newsz = sz >> increment_size << increment_size;
+
+ if (sz != newsz) {
+ qemu_printf("Ram size %" PRIu64 "MB was fixed up to %" PRIu64
+ "MB to match machine restrictions. Consider updating "
+ "the guest definition.\n", (uint64_t) (sz / MiB),
+ (uint64_t) (newsz / MiB));
+ }
+ return newsz;
+}
+
static void ccw_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
static void ccw_machine_4_2_class_options(MachineClass *mc)
{
ccw_machine_5_0_class_options(mc);
+ mc->fixup_ram_size = s390_fixup_ram_size;
compat_props_add(mc->compat_props, hw_compat_4_2, hw_compat_4_2_len);
}
DEFINE_CCW_MACHINE(4_2, "4.2", false);
static void sclp_memory_init(SCLPDevice *sclp)
{
MachineState *machine = MACHINE(qdev_get_machine());
+ MachineClass *machine_class = MACHINE_GET_CLASS(qdev_get_machine());
ram_addr_t initial_mem = machine->ram_size;
int increment_size = 20;
/* The storage increment size is a multiple of 1M and is a power of 2.
- * The number of storage increments must be MAX_STORAGE_INCREMENTS or fewer.
+ * For some machine types, the number of storage increments must be
+ * MAX_STORAGE_INCREMENTS or fewer.
* The variable 'increment_size' is an exponent of 2 that can be
* used to calculate the size (in bytes) of an increment. */
- while ((initial_mem >> increment_size) > MAX_STORAGE_INCREMENTS) {
+ while (machine_class->fixup_ram_size != NULL &&
+ (initial_mem >> increment_size) > MAX_STORAGE_INCREMENTS) {
increment_size++;
}
sclp->increment_size = increment_size;
-
- /* The core memory area needs to be aligned with the increment size.
- * In effect, this can cause the user-specified memory size to be rounded
- * down to align with the nearest increment boundary. */
- initial_mem = initial_mem >> increment_size << increment_size;
-
- machine->ram_size = initial_mem;
- machine->maxram_size = initial_mem;
- /* let's propagate the changed ram size into the global variable. */
- ram_size = initial_mem;
}
static void sclp_init(Object *obj)
* It also will be used as a way to optin into "-m" option support.
* If it's not set by board, '-m' will be ignored and generic code will
* not create default RAM MemoryRegion.
+ * @fixup_ram_size:
+ * Amends user provided ram size (with -m option) using machine
+ * specific algorithm. To be used by old machine types for compat
+ * purposes only.
+ * Applies only to default memory backend, i.e., explicit memory backend
+ * wasn't used.
*/
struct MachineClass {
/*< private >*/
unsigned cpu_index);
const CPUArchIdList *(*possible_cpu_arch_ids)(MachineState *machine);
int64_t (*get_default_cpu_node_id)(const MachineState *ms, int idx);
+ ram_addr_t (*fixup_ram_size)(ram_addr_t size);
};
/**
}
sz = QEMU_ALIGN_UP(sz, 8192);
+ if (mc->fixup_ram_size) {
+ sz = mc->fixup_ram_size(sz);
+ }
ram_size = sz;
if (ram_size != sz) {
error_report("ram size too large");