Add option to use file backed guest memory
Port qemu-kvm's -mem-path and -mem-prealloc options. These are useful for backing guest memory with huge pages via hugetlbfs. Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> CC: john cooper <john.cooper@redhat.com>
This commit is contained in:
		
							parent
							
								
									60e4c6317b
								
							
						
					
					
						commit
						c902760fb2
					
				@ -847,6 +847,9 @@ extern uint8_t *phys_ram_dirty;
 | 
				
			|||||||
extern ram_addr_t ram_size;
 | 
					extern ram_addr_t ram_size;
 | 
				
			||||||
extern ram_addr_t last_ram_offset;
 | 
					extern ram_addr_t last_ram_offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern const char *mem_path;
 | 
				
			||||||
 | 
					extern int mem_prealloc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* physical memory access */
 | 
					/* physical memory access */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* MMIO pages are identified by a combination of an IO device index and
 | 
					/* MMIO pages are identified by a combination of an IO device index and
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										117
									
								
								exec.c
									
									
									
									
									
								
							
							
						
						
									
										117
									
								
								exec.c
									
									
									
									
									
								
							@ -2529,6 +2529,99 @@ void qemu_flush_coalesced_mmio_buffer(void)
 | 
				
			|||||||
        kvm_flush_coalesced_mmio_buffer();
 | 
					        kvm_flush_coalesced_mmio_buffer();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(__linux__) && !defined(TARGET_S390X)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <sys/vfs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define HUGETLBFS_MAGIC       0x958458f6
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static long gethugepagesize(const char *path)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct statfs fs;
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    do {
 | 
				
			||||||
 | 
						    ret = statfs(path, &fs);
 | 
				
			||||||
 | 
					    } while (ret != 0 && errno == EINTR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ret != 0) {
 | 
				
			||||||
 | 
						    perror("statfs");
 | 
				
			||||||
 | 
						    return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (fs.f_type != HUGETLBFS_MAGIC)
 | 
				
			||||||
 | 
						    fprintf(stderr, "Warning: path not on HugeTLBFS: %s\n", path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return fs.f_bsize;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void *file_ram_alloc(ram_addr_t memory, const char *path)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    char *filename;
 | 
				
			||||||
 | 
					    void *area;
 | 
				
			||||||
 | 
					    int fd;
 | 
				
			||||||
 | 
					#ifdef MAP_POPULATE
 | 
				
			||||||
 | 
					    int flags;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    unsigned long hpagesize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    hpagesize = gethugepagesize(path);
 | 
				
			||||||
 | 
					    if (!hpagesize) {
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (memory < hpagesize) {
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (kvm_enabled() && !kvm_has_sync_mmu()) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "host lacks kvm mmu notifiers, -mem-path unsupported\n");
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (asprintf(&filename, "%s/qemu_back_mem.XXXXXX", path) == -1) {
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fd = mkstemp(filename);
 | 
				
			||||||
 | 
					    if (fd < 0) {
 | 
				
			||||||
 | 
						perror("mkstemp");
 | 
				
			||||||
 | 
						free(filename);
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    unlink(filename);
 | 
				
			||||||
 | 
					    free(filename);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memory = (memory+hpagesize-1) & ~(hpagesize-1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * ftruncate is not supported by hugetlbfs in older
 | 
				
			||||||
 | 
					     * hosts, so don't bother bailing out on errors.
 | 
				
			||||||
 | 
					     * If anything goes wrong with it under other filesystems,
 | 
				
			||||||
 | 
					     * mmap will fail.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    if (ftruncate(fd, memory))
 | 
				
			||||||
 | 
						perror("ftruncate");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef MAP_POPULATE
 | 
				
			||||||
 | 
					    /* NB: MAP_POPULATE won't exhaustively alloc all phys pages in the case
 | 
				
			||||||
 | 
					     * MAP_PRIVATE is requested.  For mem_prealloc we mmap as MAP_SHARED
 | 
				
			||||||
 | 
					     * to sidestep this quirk.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    flags = mem_prealloc ? MAP_POPULATE | MAP_SHARED : MAP_PRIVATE;
 | 
				
			||||||
 | 
					    area = mmap(0, memory, PROT_READ | PROT_WRITE, flags, fd, 0);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					    area = mmap(0, memory, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    if (area == MAP_FAILED) {
 | 
				
			||||||
 | 
						perror("file_ram_alloc: can't mmap RAM pages");
 | 
				
			||||||
 | 
						close(fd);
 | 
				
			||||||
 | 
						return (NULL);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return area;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ram_addr_t qemu_ram_alloc(ram_addr_t size)
 | 
					ram_addr_t qemu_ram_alloc(ram_addr_t size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    RAMBlock *new_block;
 | 
					    RAMBlock *new_block;
 | 
				
			||||||
@ -2536,16 +2629,28 @@ ram_addr_t qemu_ram_alloc(ram_addr_t size)
 | 
				
			|||||||
    size = TARGET_PAGE_ALIGN(size);
 | 
					    size = TARGET_PAGE_ALIGN(size);
 | 
				
			||||||
    new_block = qemu_malloc(sizeof(*new_block));
 | 
					    new_block = qemu_malloc(sizeof(*new_block));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(TARGET_S390X) && defined(CONFIG_KVM)
 | 
					    if (mem_path) {
 | 
				
			||||||
    /* XXX S390 KVM requires the topmost vma of the RAM to be < 256GB */
 | 
					#if defined (__linux__) && !defined(TARGET_S390X)
 | 
				
			||||||
    new_block->host = mmap((void*)0x1000000, size, PROT_EXEC|PROT_READ|PROT_WRITE,
 | 
					        new_block->host = file_ram_alloc(size, mem_path);
 | 
				
			||||||
                           MAP_SHARED | MAP_ANONYMOUS, -1, 0);
 | 
					        if (!new_block->host)
 | 
				
			||||||
 | 
					            exit(1);
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
    new_block->host = qemu_vmalloc(size);
 | 
					        fprintf(stderr, "-mem-path option unsupported\n");
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					#if defined(TARGET_S390X) && defined(CONFIG_KVM)
 | 
				
			||||||
 | 
					        /* XXX S390 KVM requires the topmost vma of the RAM to be < 256GB */
 | 
				
			||||||
 | 
					        new_block->host = mmap((void*)0x1000000, size,
 | 
				
			||||||
 | 
					                                PROT_EXEC|PROT_READ|PROT_WRITE,
 | 
				
			||||||
 | 
					                                MAP_SHARED | MAP_ANONYMOUS, -1, 0);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					        new_block->host = qemu_vmalloc(size);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#ifdef MADV_MERGEABLE
 | 
					#ifdef MADV_MERGEABLE
 | 
				
			||||||
    madvise(new_block->host, size, MADV_MERGEABLE);
 | 
					        madvise(new_block->host, size, MADV_MERGEABLE);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    new_block->offset = last_ram_offset;
 | 
					    new_block->offset = last_ram_offset;
 | 
				
			||||||
    new_block->length = size;
 | 
					    new_block->length = size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -314,6 +314,22 @@ a suffix of ``M'' or ``G'' can be used to signify a value in megabytes or
 | 
				
			|||||||
gigabytes respectively.
 | 
					gigabytes respectively.
 | 
				
			||||||
ETEXI
 | 
					ETEXI
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEF("mem-path", HAS_ARG, QEMU_OPTION_mempath,
 | 
				
			||||||
 | 
					    "-mem-path FILE  provide backing storage for guest RAM\n")
 | 
				
			||||||
 | 
					STEXI
 | 
				
			||||||
 | 
					@item -mem-path @var{path}
 | 
				
			||||||
 | 
					Allocate guest RAM from a temporarily created file in @var{path}.
 | 
				
			||||||
 | 
					ETEXI
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef MAP_POPULATE
 | 
				
			||||||
 | 
					DEF("mem-prealloc", 0, QEMU_OPTION_mem_prealloc,
 | 
				
			||||||
 | 
					    "-mem-prealloc   preallocate guest memory (use with -mem-path)\n")
 | 
				
			||||||
 | 
					STEXI
 | 
				
			||||||
 | 
					@item -mem-prealloc
 | 
				
			||||||
 | 
					Preallocate memory when using -mem-path.
 | 
				
			||||||
 | 
					ETEXI
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEF("k", HAS_ARG, QEMU_OPTION_k,
 | 
					DEF("k", HAS_ARG, QEMU_OPTION_k,
 | 
				
			||||||
    "-k language     use keyboard layout (for example 'fr' for French)\n")
 | 
					    "-k language     use keyboard layout (for example 'fr' for French)\n")
 | 
				
			||||||
STEXI
 | 
					STEXI
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										12
									
								
								vl.c
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								vl.c
									
									
									
									
									
								
							@ -185,6 +185,10 @@ enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB;
 | 
				
			|||||||
DisplayType display_type = DT_DEFAULT;
 | 
					DisplayType display_type = DT_DEFAULT;
 | 
				
			||||||
const char* keyboard_layout = NULL;
 | 
					const char* keyboard_layout = NULL;
 | 
				
			||||||
ram_addr_t ram_size;
 | 
					ram_addr_t ram_size;
 | 
				
			||||||
 | 
					const char *mem_path = NULL;
 | 
				
			||||||
 | 
					#ifdef MAP_POPULATE
 | 
				
			||||||
 | 
					int mem_prealloc = 0; /* force preallocation of physical target memory */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
int nb_nics;
 | 
					int nb_nics;
 | 
				
			||||||
NICInfo nd_table[MAX_NICS];
 | 
					NICInfo nd_table[MAX_NICS];
 | 
				
			||||||
int vm_running;
 | 
					int vm_running;
 | 
				
			||||||
@ -5216,6 +5220,14 @@ int main(int argc, char **argv, char **envp)
 | 
				
			|||||||
                ram_size = value;
 | 
					                ram_size = value;
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            case QEMU_OPTION_mempath:
 | 
				
			||||||
 | 
					                mem_path = optarg;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					#ifdef MAP_POPULATE
 | 
				
			||||||
 | 
					            case QEMU_OPTION_mem_prealloc:
 | 
				
			||||||
 | 
					                mem_prealloc = 1;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
            case QEMU_OPTION_d:
 | 
					            case QEMU_OPTION_d:
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    int mask;
 | 
					                    int mask;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user