This patch adds support for guest-side frontswap. This is the part which communicates with the host regarding frontswap TMEM actions. Signed-off-by: Sasha Levin <levinsasha928@xxxxxxxxx> --- arch/x86/kvm/tmem/Kconfig | 9 +++ arch/x86/kvm/tmem/Makefile | 1 + arch/x86/kvm/tmem/frontswap.c | 139 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 149 insertions(+), 0 deletions(-) create mode 100644 arch/x86/kvm/tmem/frontswap.c diff --git a/arch/x86/kvm/tmem/Kconfig b/arch/x86/kvm/tmem/Kconfig index 4734db2..ae46299 100644 --- a/arch/x86/kvm/tmem/Kconfig +++ b/arch/x86/kvm/tmem/Kconfig @@ -31,4 +31,13 @@ config KVM_TMEM_GUEST_CLEANCACHE as the TMEM target, which means that cleanswap may be used across VMs (and even hosts). +config KVM_TMEM_GUEST_FRONTSWAP + bool "Guest-side frontswap support + depends on FRONTSWAP + select KVM_TMEM_GUEST + ---help--- + This option enables guest to use frontswap with the KVM host acting + as the TMEM target, which means that frontswap may be used across + VMs (and even hosts). + endif # KVM_TMEM diff --git a/arch/x86/kvm/tmem/Makefile b/arch/x86/kvm/tmem/Makefile index b972c2b..40c0561 100644 --- a/arch/x86/kvm/tmem/Makefile +++ b/arch/x86/kvm/tmem/Makefile @@ -3,3 +3,4 @@ ccflags-y += -Idrivers/staging/zcache/ obj-$(CONFIG_KVM_TMEM_HOST) += host.o obj-$(CONFIG_KVM_TMEM_GUEST) += guest.o obj-$(CONFIG_KVM_TMEM_GUEST_CLEANCACHE) += cleancache.o +obj-$(CONFIG_KVM_TMEM_GUEST_FRONTSWAP) += frontswap.o diff --git a/arch/x86/kvm/tmem/frontswap.c b/arch/x86/kvm/tmem/frontswap.c new file mode 100644 index 0000000..b63ac83 --- /dev/null +++ b/arch/x86/kvm/tmem/frontswap.c @@ -0,0 +1,139 @@ +/* + * KVM TMEM frontswap guest side interface + * + * Copyright (c) 2012 Sasha Levin + * + * Based on the equivalent Xen code. + * + */ + +#include <linux/kvm_types.h> +#include <linux/mm.h> +#include <linux/frontswap.h> +#include <linux/kvm_para.h> + +#include "tmem.h" +#include "guest.h" + +#include <zcache.h> + +/* a single tmem poolid is used for all frontswap "types" (swapfiles) */ +static int tmem_frontswap_poolid; + +/* + * Swizzling increases objects per swaptype, increasing tmem concurrency + * for heavy swaploads. Later, larger nr_cpus -> larger SWIZ_BITS + */ +#define SWIZ_BITS 4 +#define SWIZ_MASK ((1 << SWIZ_BITS) - 1) +#define _oswiz(_type, _ind) ((_type << SWIZ_BITS) | (_ind & SWIZ_MASK)) +#define iswiz(_ind) (_ind >> SWIZ_BITS) + +static inline struct tmem_oid oswiz(unsigned type, __u32 ind) +{ + struct tmem_oid oid = { .oid = { 0 } }; + + oid.oid[0] = _oswiz(type, ind); + + return oid; +} + +/* returns 0 if the page was successfully put into frontswap, -1 if not */ +static int tmem_frontswap_store(unsigned type, pgoff_t offset, + struct page *page) +{ + __u32 ind = (__u32)offset; + unsigned long pfn = page_to_pfn(page); + int pool = tmem_frontswap_poolid; + + if (pool < 0) + return -1; + + return kvm_tmem_put_page(pool, oswiz(type, ind), iswiz(ind), pfn); +} + +/* + * returns 0 if the page was successfully gotten from frontswap, -1 if + * was not present (should never happen!) + */ +static int tmem_frontswap_load(unsigned type, pgoff_t offset, + struct page *page) +{ + __u32 ind = (__u32)offset; + unsigned long pfn = page_to_pfn(page); + int pool = tmem_frontswap_poolid; + + if (pool < 0) + return -1; + + return kvm_tmem_get_page(pool, oswiz(type, ind), iswiz(ind), pfn); +} + +/* flush a single page from frontswap */ +static void tmem_frontswap_invalidate_page(unsigned type, pgoff_t offset) +{ + __u64 ind64 = (__u64)offset; + __u32 ind = (__u32)offset; + int pool = tmem_frontswap_poolid; + + if (pool < 0) + return; + + kvm_tmem_flush_page(pool, oswiz(type, ind), iswiz(ind64)); +} + +/* flush all pages from the passed swaptype */ +static void tmem_frontswap_invalidate_area(unsigned type) +{ + int pool = tmem_frontswap_poolid; + int ind; + + if (pool < 0) + return; + for (ind = SWIZ_MASK; ind >= 0; ind--) + kvm_tmem_flush_object(pool, oswiz(type, ind)); + kvm_tmem_destroy_pool((u32)pool); +} + +static void tmem_frontswap_init(unsigned ignored) +{ + /* a single tmem poolid is used for all frontswap "types" (swapfiles) */ + if (tmem_frontswap_poolid < 0) + tmem_frontswap_poolid = + kvm_tmem_new_pool(KVM_CLIENT, TMEM_POOL_PERSIST, PAGE_SIZE); +} + +static int use_kvmfrontswap = 1; + +static int __init no_kvmfrontswap(char *s) +{ + use_kvmfrontswap = 0; + return 1; +} + +__setup("nokvmfrontswap", no_kvmfrontswap); + +static struct frontswap_ops tmem_frontswap_ops = { + .store = tmem_frontswap_store, + .load = tmem_frontswap_load, + .invalidate_page = tmem_frontswap_invalidate_page, + .invalidate_area = tmem_frontswap_invalidate_area, + .init = tmem_frontswap_init +}; + +static int kvm_tmem_frontswap_init(void) +{ + struct frontswap_ops old_ops; + + if (!use_kvmfrontswap || !kvm_para_available()) + return 0; + + old_ops = frontswap_register_ops(&tmem_frontswap_ops); + + tmem_frontswap_poolid = -1; + printk(KERN_INFO "frontswap enabled, RAM provided by KVM TMEM %s\n", + old_ops.init?"(WARNING: frontswap_ops overridden)":""); + return 0; +} + +module_init(kvm_tmem_frontswap_init); -- 1.7.8.6 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html