]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
kvm tools: Add ability to map guest RAM from hugetlbfs
authorMatt Evans <matt@ozlabs.org>
Tue, 13 Dec 2011 06:21:46 +0000 (17:21 +1100)
committerPekka Enberg <penberg@kernel.org>
Tue, 13 Dec 2011 15:16:23 +0000 (17:16 +0200)
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 <matt@ozlabs.org>
Signed-off-by: Pekka Enberg <penberg@kernel.org>
tools/kvm/builtin-run.c
tools/kvm/include/kvm/kvm.h
tools/kvm/include/kvm/util.h
tools/kvm/kvm.c
tools/kvm/util/util.c
tools/kvm/x86/kvm.c

index 35245ff98182e6f03a48f2b1eadd18ca1779b143..76f1a8caf19e35320bff42388be8c71666379f9e 100644 (file)
@@ -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;
 
index 5fe6e75fe5dccac15ac76468c418a0e9827f3cdc..71599522481ca5490eb3993581aca0eb55efba9d 100644 (file)
@@ -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);
index 3e382fc766494a33fac576a389bcd91b8c19a735..83088afe89a2a45059aaf9468a185e70fc8311e7 100644 (file)
@@ -20,6 +20,7 @@
 #include <limits.h>
 #include <sys/param.h>
 #include <sys/types.h>
+#include <linux/types.h>
 
 #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 */
index c54f8866caac86a102e8f8b2ac836cb37bbe01f9..35ca2c5cb2cadfb213e8be362d3f436470494121 100644 (file)
@@ -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;
 
index 682ed6c2337a1d870ac5e0644e327ee72c94574f..ad5418e0387f6de4ef86f1209d3016cd5899e81f 100644 (file)
@@ -4,6 +4,11 @@
 
 #include "kvm/util.h"
 
+#include <linux/magic.h>       /* For HUGETLBFS_MAGIC */
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+
 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;
+}
index da4a6b6c9d8634350a85bee1f74a7089ad59021b..bc52ef3998462d3a8ea3a2e04f94fe57ff93ab82 100644 (file)
@@ -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