23ad8dec8d
With VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE, we signal the VM that reading unplugged memory is not supported. We have to fail feature negotiation in case the guest does not support VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE. First, VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE is required to properly handle memory backends (or architectures) without support for the shared zeropage in the hypervisor cleanly. Without the shared zeropage, even reading an unpopulated virtual memory location can populate real memory and consequently consume memory in the hypervisor. We have a guaranteed shared zeropage only on MAP_PRIVATE anonymous memory. Second, we want VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE to be the default long-term as even populating the shared zeropage can be problematic: for example, without THP support (possible) or without support for the shared huge zeropage with THP (unlikely), the PTE page tables to hold the shared zeropage entries can consume quite some memory that cannot be reclaimed easily. Third, there are other optimizations+features (e.g., protection of unplugged memory, reducing the total memory slot size and bitmap sizes) that will require VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE. We really only support x86 targets with virtio-mem for now (and Linux similarly only support x86), but that might change soon, so prepare for different targets already. Add a new "unplugged-inaccessible" tristate property for x86 targets: - "off" will keep VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE unset and legacy guests working. - "on" will set VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE and stop legacy guests from using the device. - "auto" selects the default based on support for the shared zeropage. Warn in case the property is set to "off" and we don't have support for the shared zeropage. For existing compat machines, the property will default to "off", to not change the behavior but eventually warn about a problematic setup. Short-term, we'll set the property default to "auto" for new QEMU machines. Mid-term, we'll set the property default to "on" for new QEMU machines. Long-term, we'll deprecate the parameter and disallow legacy guests completely. The property has to match on the migration source and destination. "auto" will result in the same VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE setting as long as the qemu command line (esp. memdev) match -- so "auto" is good enough for migration purposes and the parameter doesn't have to be migrated explicitly. Reviewed-by: Michal Privoznik <mprivozn@redhat.com> Signed-off-by: David Hildenbrand <david@redhat.com> Message-Id: <20211217134039.29670-3-david@redhat.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
96 lines
2.5 KiB
C
96 lines
2.5 KiB
C
/*
|
|
* Virtio MEM device
|
|
*
|
|
* Copyright (C) 2020 Red Hat, Inc.
|
|
*
|
|
* Authors:
|
|
* David Hildenbrand <david@redhat.com>
|
|
*
|
|
* This work is licensed under the terms of the GNU GPL, version 2.
|
|
* See the COPYING file in the top-level directory.
|
|
*/
|
|
|
|
#ifndef HW_VIRTIO_MEM_H
|
|
#define HW_VIRTIO_MEM_H
|
|
|
|
#include "standard-headers/linux/virtio_mem.h"
|
|
#include "hw/virtio/virtio.h"
|
|
#include "qapi/qapi-types-misc.h"
|
|
#include "sysemu/hostmem.h"
|
|
#include "qom/object.h"
|
|
|
|
#define TYPE_VIRTIO_MEM "virtio-mem"
|
|
|
|
OBJECT_DECLARE_TYPE(VirtIOMEM, VirtIOMEMClass,
|
|
VIRTIO_MEM)
|
|
|
|
#define VIRTIO_MEM_MEMDEV_PROP "memdev"
|
|
#define VIRTIO_MEM_NODE_PROP "node"
|
|
#define VIRTIO_MEM_SIZE_PROP "size"
|
|
#define VIRTIO_MEM_REQUESTED_SIZE_PROP "requested-size"
|
|
#define VIRTIO_MEM_BLOCK_SIZE_PROP "block-size"
|
|
#define VIRTIO_MEM_ADDR_PROP "memaddr"
|
|
#define VIRTIO_MEM_UNPLUGGED_INACCESSIBLE_PROP "unplugged-inaccessible"
|
|
#define VIRTIO_MEM_PREALLOC_PROP "prealloc"
|
|
|
|
struct VirtIOMEM {
|
|
VirtIODevice parent_obj;
|
|
|
|
/* guest -> host request queue */
|
|
VirtQueue *vq;
|
|
|
|
/* bitmap used to track unplugged memory */
|
|
int32_t bitmap_size;
|
|
unsigned long *bitmap;
|
|
|
|
/* assigned memory backend and memory region */
|
|
HostMemoryBackend *memdev;
|
|
|
|
/* NUMA node */
|
|
uint32_t node;
|
|
|
|
/* assigned address of the region in guest physical memory */
|
|
uint64_t addr;
|
|
|
|
/* usable region size (<= region_size) */
|
|
uint64_t usable_region_size;
|
|
|
|
/* actual size (how much the guest plugged) */
|
|
uint64_t size;
|
|
|
|
/* requested size */
|
|
uint64_t requested_size;
|
|
|
|
/* block size and alignment */
|
|
uint64_t block_size;
|
|
|
|
/*
|
|
* Whether we indicate VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE to the guest.
|
|
* For !x86 targets this will always be "on" and consequently indicate
|
|
* VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE.
|
|
*/
|
|
OnOffAuto unplugged_inaccessible;
|
|
|
|
/* whether to prealloc memory when plugging new blocks */
|
|
bool prealloc;
|
|
|
|
/* notifiers to notify when "size" changes */
|
|
NotifierList size_change_notifiers;
|
|
|
|
/* listeners to notify on plug/unplug activity. */
|
|
QLIST_HEAD(, RamDiscardListener) rdl_list;
|
|
};
|
|
|
|
struct VirtIOMEMClass {
|
|
/* private */
|
|
VirtIODevice parent;
|
|
|
|
/* public */
|
|
void (*fill_device_info)(const VirtIOMEM *vmen, VirtioMEMDeviceInfo *vi);
|
|
MemoryRegion *(*get_memory_region)(VirtIOMEM *vmem, Error **errp);
|
|
void (*add_size_change_notifier)(VirtIOMEM *vmem, Notifier *notifier);
|
|
void (*remove_size_change_notifier)(VirtIOMEM *vmem, Notifier *notifier);
|
|
};
|
|
|
|
#endif
|