From 378ee7e6dd301347c6bf2c740cb1fb40174bcb8b Mon Sep 17 00:00:00 2001 From: Matt Evans Date: Tue, 13 Dec 2011 17:21:46 +1100 Subject: [PATCH] kvm tools: Add ability to map guest RAM from hugetlbfs Add a --hugetlbfs commandline option to give a path to hugetlbfs-map guest memory (down in kvm__arch_init()). For x86, guest memory is a normal ANON mmap() if this option is not provided, otherwise a hugetlbfs mmap. This maps directly from a hugetlbfs temp file rather than using something like MADV_HUGEPAGES so that, if the user asks for hugepages, we definitely are using hugepages. (This is particularly useful for architectures that don't yet support KVM without hugepages, so we definitely need to use them for the whole of guest RAM.) Signed-off-by: Matt Evans Signed-off-by: Pekka Enberg --- tools/kvm/builtin-run.c | 4 +++- tools/kvm/include/kvm/kvm.h | 4 ++-- tools/kvm/include/kvm/util.h | 4 ++++ tools/kvm/kvm.c | 4 ++-- tools/kvm/util/util.c | 38 ++++++++++++++++++++++++++++++++++++ tools/kvm/x86/kvm.c | 20 ++++++++++++++++--- 6 files changed, 66 insertions(+), 8 deletions(-) diff --git a/tools/kvm/builtin-run.c b/tools/kvm/builtin-run.c index 35245ff98182..76f1a8caf19e 100644 --- a/tools/kvm/builtin-run.c +++ b/tools/kvm/builtin-run.c @@ -86,6 +86,7 @@ static const char *host_mac; static const char *script; static const char *guest_name; static const char *sandbox; +static const char *hugetlbfs_path; static struct virtio_net_params *net_params; static bool single_step; static bool readonly_image[MAX_DISK_IMAGES]; @@ -438,6 +439,7 @@ static const struct option options[] = { tty_parser), OPT_STRING('\0', "sandbox", &sandbox, "script", "Run this script when booting into custom rootfs"), + OPT_STRING('\0', "hugetlbfs", &hugetlbfs_path, "path", "Hugetlbfs path"), OPT_GROUP("Kernel options:"), OPT_STRING('k', "kernel", &kernel_filename, "kernel", @@ -926,7 +928,7 @@ int kvm_cmd_run(int argc, const char **argv, const char *prefix) guest_name = default_name; } - kvm = kvm__init(dev, ram_size, guest_name); + kvm = kvm__init(dev, hugetlbfs_path, ram_size, guest_name); kvm->single_step = single_step; diff --git a/tools/kvm/include/kvm/kvm.h b/tools/kvm/include/kvm/kvm.h index 5fe6e75fe5dc..71599522481c 100644 --- a/tools/kvm/include/kvm/kvm.h +++ b/tools/kvm/include/kvm/kvm.h @@ -30,7 +30,7 @@ struct kvm_ext { void kvm__set_dir(const char *fmt, ...); const char *kvm__get_dir(void); -struct kvm *kvm__init(const char *kvm_dev, u64 ram_size, const char *name); +struct kvm *kvm__init(const char *kvm_dev, const char *hugetlbfs_path, u64 ram_size, const char *name); int kvm__recommended_cpus(struct kvm *kvm); int kvm__max_cpus(struct kvm *kvm); void kvm__init_ram(struct kvm *kvm); @@ -54,7 +54,7 @@ int kvm__enumerate_instances(int (*callback)(const char *name, int pid)); void kvm__remove_socket(const char *name); void kvm__arch_set_cmdline(char *cmdline, bool video); -void kvm__arch_init(struct kvm *kvm, const char *kvm_dev, u64 ram_size, const char *name); +void kvm__arch_init(struct kvm *kvm, const char *kvm_dev, const char *hugetlbfs_path, u64 ram_size, const char *name); void kvm__arch_setup_firmware(struct kvm *kvm); bool kvm__arch_cpu_supports_vm(void); void kvm__arch_periodic_poll(struct kvm *kvm); diff --git a/tools/kvm/include/kvm/util.h b/tools/kvm/include/kvm/util.h index 3e382fc76649..83088afe89a2 100644 --- a/tools/kvm/include/kvm/util.h +++ b/tools/kvm/include/kvm/util.h @@ -20,6 +20,7 @@ #include #include #include +#include #ifdef __GNUC__ #define NORETURN __attribute__((__noreturn__)) @@ -65,4 +66,7 @@ static inline void msleep(unsigned int msecs) { usleep(MSECS_TO_USECS(msecs)); } + +void *mmap_hugetlbfs(const char *htlbfs_path, u64 size); + #endif /* KVM__UTIL_H */ diff --git a/tools/kvm/kvm.c b/tools/kvm/kvm.c index c54f8866caac..35ca2c5cb2ca 100644 --- a/tools/kvm/kvm.c +++ b/tools/kvm/kvm.c @@ -306,7 +306,7 @@ int kvm__max_cpus(struct kvm *kvm) return ret; } -struct kvm *kvm__init(const char *kvm_dev, u64 ram_size, const char *name) +struct kvm *kvm__init(const char *kvm_dev, const char *hugetlbfs_path, u64 ram_size, const char *name) { struct kvm *kvm; int ret; @@ -339,7 +339,7 @@ struct kvm *kvm__init(const char *kvm_dev, u64 ram_size, const char *name) if (kvm__check_extensions(kvm)) die("A required KVM extention is not supported by OS"); - kvm__arch_init(kvm, kvm_dev, ram_size, name); + kvm__arch_init(kvm, kvm_dev, hugetlbfs_path, ram_size, name); kvm->name = name; diff --git a/tools/kvm/util/util.c b/tools/kvm/util/util.c index 682ed6c2337a..ad5418e0387f 100644 --- a/tools/kvm/util/util.c +++ b/tools/kvm/util/util.c @@ -4,6 +4,11 @@ #include "kvm/util.h" +#include /* For HUGETLBFS_MAGIC */ +#include +#include +#include + static void report(const char *prefix, const char *err, va_list params) { char msg[1024]; @@ -74,3 +79,36 @@ void die_perror(const char *s) perror(s); exit(1); } + +void *mmap_hugetlbfs(const char *htlbfs_path, u64 size) +{ + char mpath[PATH_MAX]; + int fd; + struct statfs sfs; + void *addr; + + if (statfs(htlbfs_path, &sfs) < 0) + die("Can't stat %s\n", htlbfs_path); + + if (sfs.f_type != HUGETLBFS_MAGIC) { + die("%s is not hugetlbfs!\n", htlbfs_path); + } + + if (sfs.f_bsize == 0 || (unsigned long)sfs.f_bsize > size) { + die("Can't use hugetlbfs pagesize %ld for mem size %lld\n", + sfs.f_bsize, size); + } + + snprintf(mpath, PATH_MAX, "%s/kvmtoolXXXXXX", htlbfs_path); + fd = mkstemp(mpath); + if (fd < 0) + die("Can't open %s for hugetlbfs map\n", mpath); + unlink(mpath); + if (ftruncate(fd, size) < 0) + die("Can't ftruncate for mem mapping size %lld\n", + size); + addr = mmap(NULL, size, PROT_RW, MAP_PRIVATE, fd, 0); + close(fd); + + return addr; +} diff --git a/tools/kvm/x86/kvm.c b/tools/kvm/x86/kvm.c index da4a6b6c9d86..bc52ef399846 100644 --- a/tools/kvm/x86/kvm.c +++ b/tools/kvm/x86/kvm.c @@ -130,8 +130,22 @@ void kvm__arch_set_cmdline(char *cmdline, bool video) strcat(cmdline, " console=ttyS0 earlyprintk=serial i8042.noaux=1"); } +/* This function wraps the decision between hugetlbfs map (if requested) or normal mmap */ +static void *mmap_anon_or_hugetlbfs(const char *hugetlbfs_path, u64 size) +{ + if (hugetlbfs_path) { + /* + * We don't /need/ to map guest RAM from hugetlbfs, but we do so + * if the user specifies a hugetlbfs path. + */ + return mmap_hugetlbfs(hugetlbfs_path, size); + } else { + return mmap(NULL, size, PROT_RW, MAP_ANON_NORESERVE, -1, 0); + } +} + /* Architecture-specific KVM init */ -void kvm__arch_init(struct kvm *kvm, const char *kvm_dev, u64 ram_size, const char *name) +void kvm__arch_init(struct kvm *kvm, const char *kvm_dev, const char *hugetlbfs_path, u64 ram_size, const char *name) { struct kvm_pit_config pit_config = { .flags = 0, }; int ret; @@ -147,9 +161,9 @@ void kvm__arch_init(struct kvm *kvm, const char *kvm_dev, u64 ram_size, const ch kvm->ram_size = ram_size; if (kvm->ram_size < KVM_32BIT_GAP_START) { - kvm->ram_start = mmap(NULL, ram_size, PROT_RW, MAP_ANON_NORESERVE, -1, 0); + kvm->ram_start = mmap_anon_or_hugetlbfs(hugetlbfs_path, ram_size); } else { - kvm->ram_start = mmap(NULL, ram_size + KVM_32BIT_GAP_SIZE, PROT_RW, MAP_ANON_NORESERVE, -1, 0); + kvm->ram_start = mmap_anon_or_hugetlbfs(hugetlbfs_path, ram_size + KVM_32BIT_GAP_SIZE); if (kvm->ram_start != MAP_FAILED) { /* * We mprotect the gap (see kvm__init_ram() for details) PROT_NONE so that -- 2.39.5