Merge remote-tracking branch 'remotes/qmp-unstable/queue/qmp' into staging
* remotes/qmp-unstable/queue/qmp: docs: add memory-hotplug.txt qemu-options.hx: improve -m description virtio-balloon: Add some trace events virtio-balloon: Fix balloon not working correctly when hotplug memory pc-dimm: add a function to calculate VM's current RAM size Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
		
						commit
						9c31a8219a
					
				
							
								
								
									
										76
									
								
								docs/memory-hotplug.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								docs/memory-hotplug.txt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,76 @@
 | 
				
			|||||||
 | 
					QEMU memory hotplug
 | 
				
			||||||
 | 
					===================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This document explains how to use the memory hotplug feature in QEMU,
 | 
				
			||||||
 | 
					which is present since v2.1.0.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Please, note that memory hotunplug is not supported yet. This means
 | 
				
			||||||
 | 
					that you're able to add memory, but you're not able to remove it.
 | 
				
			||||||
 | 
					Also, proper guest support is required for memory hotplug to work.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Basic RAM hotplug
 | 
				
			||||||
 | 
					-----------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In order to be able to hotplug memory, QEMU has to be told how many
 | 
				
			||||||
 | 
					hotpluggable memory slots to create and what is the maximum amount of
 | 
				
			||||||
 | 
					memory the guest can grow. This is done at startup time by means of
 | 
				
			||||||
 | 
					the -m command-line option, which has the following format:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -m [size=]megs[,slots=n,maxmem=size]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Where,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 - "megs" is the startup RAM. It is the RAM the guest will boot with
 | 
				
			||||||
 | 
					 - "slots" is the number of hotpluggable memory slots
 | 
				
			||||||
 | 
					 - "maxmem" is the maximum RAM size the guest can have
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For example, the following command-line:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 qemu [...] 1G,slots=3,maxmem=4G
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Creates a guest with 1GB of memory and three hotpluggable memory slots.
 | 
				
			||||||
 | 
					The hotpluggable memory slots are empty when the guest is booted, so all
 | 
				
			||||||
 | 
					memory the guest will see after boot is 1GB. The maximum memory the
 | 
				
			||||||
 | 
					guest can reach is 4GB. This means that three additional gigabytes can be
 | 
				
			||||||
 | 
					hotplugged by using any combination of the available memory slots.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Two monitor commands are used to hotplug memory:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 - "object_add": creates a memory backend object
 | 
				
			||||||
 | 
					 - "device_add": creates a front-end pc-dimm device and inserts it
 | 
				
			||||||
 | 
					                 into the first empty slot
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For example, the following commands add another 1GB to the guest
 | 
				
			||||||
 | 
					discussed earlier:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  (qemu) object_add memory-backend-ram,id=mem1,size=1G
 | 
				
			||||||
 | 
					  (qemu) device_add pc-dimm,id=dimm1,memdev=mem1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Using the file backend
 | 
				
			||||||
 | 
					----------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Besides basic RAM hotplug, QEMU also supports using files as a memory
 | 
				
			||||||
 | 
					backend. This is useful for using hugetlbfs in Linux, which provides
 | 
				
			||||||
 | 
					access to bigger page sizes.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For example, assuming that the host has 1GB hugepages available in
 | 
				
			||||||
 | 
					the /mnt/hugepages-1GB directory, a 1GB hugepage could be hotplugged
 | 
				
			||||||
 | 
					into the guest from the previous section with the following commands:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  (qemu) object_add memory-backend-file,id=mem1,size=1G,mem-path=/mnt/hugepages-1GB
 | 
				
			||||||
 | 
					  (qemu) device_add pc-dimm,id=dimm1,memdev=mem1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					It's also possible to start a guest with memory cold-plugged into the
 | 
				
			||||||
 | 
					hotpluggable memory slots. This might seem counterintuitive at first,
 | 
				
			||||||
 | 
					but this allows for a lot of flexibility when using the file backend.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In the following command-line example, a 8GB guest is created where 6GB
 | 
				
			||||||
 | 
					comes from regular RAM, 1GB is a 1GB hugepage page and 256MB is from
 | 
				
			||||||
 | 
					2MB pages. Also, the guest has additional memory slots to hotplug more
 | 
				
			||||||
 | 
					2GB if needed:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 qemu [...] -m 6GB,slots=4,maxmem=10G \
 | 
				
			||||||
 | 
					   -object memory-backend-file,id=mem1,size=1G,mem-path=/mnt/hugepages-1G \
 | 
				
			||||||
 | 
					   -device pc-dimm,id=dimm1,memdev=mem1 \
 | 
				
			||||||
 | 
					   -object memory-backend-file,id=mem2,size=256M,mem-path=/mnt/hugepages-2MB \
 | 
				
			||||||
 | 
					   -device pc-dimm,id=dimm2,memdev=mem2
 | 
				
			||||||
@ -100,6 +100,32 @@ int qmp_pc_dimm_device_list(Object *obj, void *opaque)
 | 
				
			|||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ram_addr_t get_current_ram_size(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    MemoryDeviceInfoList *info_list = NULL;
 | 
				
			||||||
 | 
					    MemoryDeviceInfoList **prev = &info_list;
 | 
				
			||||||
 | 
					    MemoryDeviceInfoList *info;
 | 
				
			||||||
 | 
					    ram_addr_t size = ram_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qmp_pc_dimm_device_list(qdev_get_machine(), &prev);
 | 
				
			||||||
 | 
					    for (info = info_list; info; info = info->next) {
 | 
				
			||||||
 | 
					        MemoryDeviceInfo *value = info->value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (value) {
 | 
				
			||||||
 | 
					            switch (value->kind) {
 | 
				
			||||||
 | 
					            case MEMORY_DEVICE_INFO_KIND_DIMM:
 | 
				
			||||||
 | 
					                size += value->dimm->size;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    qapi_free_MemoryDeviceInfoList(info_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return size;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int pc_dimm_slot2bitmap(Object *obj, void *opaque)
 | 
					static int pc_dimm_slot2bitmap(Object *obj, void *opaque)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    unsigned long *bitmap = opaque;
 | 
					    unsigned long *bitmap = opaque;
 | 
				
			||||||
 | 
				
			|||||||
@ -25,6 +25,7 @@
 | 
				
			|||||||
#include "exec/address-spaces.h"
 | 
					#include "exec/address-spaces.h"
 | 
				
			||||||
#include "qapi/visitor.h"
 | 
					#include "qapi/visitor.h"
 | 
				
			||||||
#include "qapi-event.h"
 | 
					#include "qapi-event.h"
 | 
				
			||||||
 | 
					#include "trace.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(__linux__)
 | 
					#if defined(__linux__)
 | 
				
			||||||
#include <sys/mman.h>
 | 
					#include <sys/mman.h>
 | 
				
			||||||
@ -222,6 +223,8 @@ static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
 | 
				
			|||||||
            if (!int128_nz(section.size) || !memory_region_is_ram(section.mr))
 | 
					            if (!int128_nz(section.size) || !memory_region_is_ram(section.mr))
 | 
				
			||||||
                continue;
 | 
					                continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            trace_virtio_balloon_handle_output(memory_region_name(section.mr),
 | 
				
			||||||
 | 
					                                               pa);
 | 
				
			||||||
            /* Using memory_region_get_ram_ptr is bending the rules a bit, but
 | 
					            /* Using memory_region_get_ram_ptr is bending the rules a bit, but
 | 
				
			||||||
               should be OK because we only want a single page.  */
 | 
					               should be OK because we only want a single page.  */
 | 
				
			||||||
            addr = section.offset_within_region;
 | 
					            addr = section.offset_within_region;
 | 
				
			||||||
@ -285,6 +288,7 @@ static void virtio_balloon_get_config(VirtIODevice *vdev, uint8_t *config_data)
 | 
				
			|||||||
    config.num_pages = cpu_to_le32(dev->num_pages);
 | 
					    config.num_pages = cpu_to_le32(dev->num_pages);
 | 
				
			||||||
    config.actual = cpu_to_le32(dev->actual);
 | 
					    config.actual = cpu_to_le32(dev->actual);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    trace_virtio_balloon_get_config(config.num_pages, config.actual);
 | 
				
			||||||
    memcpy(config_data, &config, sizeof(struct virtio_balloon_config));
 | 
					    memcpy(config_data, &config, sizeof(struct virtio_balloon_config));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -294,13 +298,16 @@ static void virtio_balloon_set_config(VirtIODevice *vdev,
 | 
				
			|||||||
    VirtIOBalloon *dev = VIRTIO_BALLOON(vdev);
 | 
					    VirtIOBalloon *dev = VIRTIO_BALLOON(vdev);
 | 
				
			||||||
    struct virtio_balloon_config config;
 | 
					    struct virtio_balloon_config config;
 | 
				
			||||||
    uint32_t oldactual = dev->actual;
 | 
					    uint32_t oldactual = dev->actual;
 | 
				
			||||||
 | 
					    ram_addr_t vm_ram_size = get_current_ram_size();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    memcpy(&config, config_data, sizeof(struct virtio_balloon_config));
 | 
					    memcpy(&config, config_data, sizeof(struct virtio_balloon_config));
 | 
				
			||||||
    dev->actual = le32_to_cpu(config.actual);
 | 
					    dev->actual = le32_to_cpu(config.actual);
 | 
				
			||||||
    if (dev->actual != oldactual) {
 | 
					    if (dev->actual != oldactual) {
 | 
				
			||||||
        qapi_event_send_balloon_change(ram_size -
 | 
					        qapi_event_send_balloon_change(vm_ram_size -
 | 
				
			||||||
                        ((ram_addr_t) dev->actual << VIRTIO_BALLOON_PFN_SHIFT),
 | 
					                        ((ram_addr_t) dev->actual << VIRTIO_BALLOON_PFN_SHIFT),
 | 
				
			||||||
                        &error_abort);
 | 
					                        &error_abort);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    trace_virtio_balloon_set_config(dev->actual, oldactual);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f)
 | 
					static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f)
 | 
				
			||||||
@ -312,7 +319,7 @@ static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f)
 | 
				
			|||||||
static void virtio_balloon_stat(void *opaque, BalloonInfo *info)
 | 
					static void virtio_balloon_stat(void *opaque, BalloonInfo *info)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    VirtIOBalloon *dev = opaque;
 | 
					    VirtIOBalloon *dev = opaque;
 | 
				
			||||||
    info->actual = ram_size - ((uint64_t) dev->actual <<
 | 
					    info->actual = get_current_ram_size() - ((uint64_t) dev->actual <<
 | 
				
			||||||
                                             VIRTIO_BALLOON_PFN_SHIFT);
 | 
					                                             VIRTIO_BALLOON_PFN_SHIFT);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -320,14 +327,16 @@ static void virtio_balloon_to_target(void *opaque, ram_addr_t target)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    VirtIOBalloon *dev = VIRTIO_BALLOON(opaque);
 | 
					    VirtIOBalloon *dev = VIRTIO_BALLOON(opaque);
 | 
				
			||||||
    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
 | 
					    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
 | 
				
			||||||
 | 
					    ram_addr_t vm_ram_size = get_current_ram_size();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (target > ram_size) {
 | 
					    if (target > vm_ram_size) {
 | 
				
			||||||
        target = ram_size;
 | 
					        target = vm_ram_size;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (target) {
 | 
					    if (target) {
 | 
				
			||||||
        dev->num_pages = (ram_size - target) >> VIRTIO_BALLOON_PFN_SHIFT;
 | 
					        dev->num_pages = (vm_ram_size - target) >> VIRTIO_BALLOON_PFN_SHIFT;
 | 
				
			||||||
        virtio_notify_config(vdev);
 | 
					        virtio_notify_config(vdev);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    trace_virtio_balloon_to_target(target, dev->num_pages);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void virtio_balloon_save(QEMUFile *f, void *opaque)
 | 
					static void virtio_balloon_save(QEMUFile *f, void *opaque)
 | 
				
			||||||
 | 
				
			|||||||
@ -52,6 +52,7 @@ typedef uintptr_t ram_addr_t;
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern ram_addr_t ram_size;
 | 
					extern ram_addr_t ram_size;
 | 
				
			||||||
 | 
					ram_addr_t get_current_ram_size(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* memory API */
 | 
					/* memory API */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -237,12 +237,24 @@ DEF("m", HAS_ARG, QEMU_OPTION_m,
 | 
				
			|||||||
    "NOTE: Some architectures might enforce a specific granularity\n",
 | 
					    "NOTE: Some architectures might enforce a specific granularity\n",
 | 
				
			||||||
    QEMU_ARCH_ALL)
 | 
					    QEMU_ARCH_ALL)
 | 
				
			||||||
STEXI
 | 
					STEXI
 | 
				
			||||||
@item -m [size=]@var{megs}
 | 
					@item -m [size=]@var{megs}[,slots=n,maxmem=size]
 | 
				
			||||||
@findex -m
 | 
					@findex -m
 | 
				
			||||||
Set virtual RAM size to @var{megs} megabytes. Default is 128 MiB.  Optionally,
 | 
					Sets guest startup RAM size to @var{megs} megabytes. Default is 128 MiB.
 | 
				
			||||||
a suffix of ``M'' or ``G'' can be used to signify a value in megabytes or
 | 
					Optionally, a suffix of ``M'' or ``G'' can be used to signify a value in
 | 
				
			||||||
gigabytes respectively. Optional pair @var{slots}, @var{maxmem} could be used
 | 
					megabytes or gigabytes respectively. Optional pair @var{slots}, @var{maxmem}
 | 
				
			||||||
to set amount of hotluggable memory slots and possible maximum amount of memory.
 | 
					could be used to set amount of hotpluggable memory slots and maximum amount of
 | 
				
			||||||
 | 
					memory. Note that @var{maxmem} must be aligned to the page size.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For example, the following command-line sets the guest startup RAM size to
 | 
				
			||||||
 | 
					1GB, creates 3 slots to hotplug additional memory and sets the maximum
 | 
				
			||||||
 | 
					memory the guest can reach to 4GB:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@example
 | 
				
			||||||
 | 
					qemu-system-x86_64 -m 1G,slots=3,maxmem=4G
 | 
				
			||||||
 | 
					@end example
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If @var{slots} and @var{maxmem} are not specified, memory hotplug won't
 | 
				
			||||||
 | 
					be enabled and the guest startup RAM will never increase.
 | 
				
			||||||
ETEXI
 | 
					ETEXI
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEF("mem-path", HAS_ARG, QEMU_OPTION_mempath,
 | 
					DEF("mem-path", HAS_ARG, QEMU_OPTION_mempath,
 | 
				
			||||||
 | 
				
			|||||||
@ -5,3 +5,8 @@ int qmp_pc_dimm_device_list(Object *obj, void *opaque)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
   return 0;
 | 
					   return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ram_addr_t get_current_ram_size(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return ram_size;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -143,6 +143,10 @@ cpu_out(unsigned int addr, unsigned int val) "addr %#x value %u"
 | 
				
			|||||||
# balloon.c
 | 
					# balloon.c
 | 
				
			||||||
# Since requests are raised via monitor, not many tracepoints are needed.
 | 
					# Since requests are raised via monitor, not many tracepoints are needed.
 | 
				
			||||||
balloon_event(void *opaque, unsigned long addr) "opaque %p addr %lu"
 | 
					balloon_event(void *opaque, unsigned long addr) "opaque %p addr %lu"
 | 
				
			||||||
 | 
					virtio_balloon_handle_output(const char *name, uint64_t gpa) "setion name: %s gpa: %"PRIx64""
 | 
				
			||||||
 | 
					virtio_balloon_get_config(uint32_t num_pages, uint32_t acutal) "num_pages: %d acutal: %d"
 | 
				
			||||||
 | 
					virtio_balloon_set_config(uint32_t acutal, uint32_t oldacutal) "acutal: %d oldacutal: %d"
 | 
				
			||||||
 | 
					virtio_balloon_to_target(uint64_t target, uint32_t num_pages) "balloon target: %"PRIx64" num_pages: %d"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# hw/intc/apic_common.c
 | 
					# hw/intc/apic_common.c
 | 
				
			||||||
cpu_set_apic_base(uint64_t val) "%016"PRIx64
 | 
					cpu_set_apic_base(uint64_t val) "%016"PRIx64
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user