From: Nitesh Narayan Lal <nilal@xxxxxxxxxx> This patch enables the guest page hinting support to enable or disable based on the STATIC key which could be set via sysctl. Signed-off-by: Nitesh Narayan Lal <nilal@xxxxxxxxxx> --- drivers/virtio/virtio_balloon.c | 16 +++++++++++----- include/linux/gfp.h | 16 ++++++++++++++-- include/linux/page_hinting.h | 7 +++++++ kernel/sysctl.c | 9 +++++++++ virt/kvm/page_hinting.c | 29 +++++++++++++++++++++++++---- 5 files changed, 66 insertions(+), 11 deletions(-) diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index 7aef032..e6457de 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -32,7 +32,6 @@ #include <linux/mm.h> #include <linux/mount.h> #include <linux/magic.h> -#include <linux/page_hinting.h> /* * Balloon device works in 4K page units. So each page is pointed to by @@ -124,6 +123,14 @@ static void hinting_ack(struct virtqueue *vq) wake_up(&vb->acked); } + +static void enable_hinting(struct virtio_balloon *vb) +{ + guest_page_hinting_flag = 1; + static_branch_enable(&guest_page_hinting_key); + request_hypercall = (void *)&virtballoon_page_hinting; + balloon_ptr = vb; +} #endif static u32 page_to_balloon_pfn(struct page *page) @@ -524,6 +531,7 @@ static int init_vqs(struct virtio_balloon *vb) if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ)) { struct scatterlist sg; unsigned int num_stats; + vb->stats_vq = vqs[2]; /* @@ -685,10 +693,8 @@ static int virtballoon_probe(struct virtio_device *vdev) virtio_device_ready(vdev); #ifdef CONFIG_KVM_FREE_PAGE_HINTING - if (virtio_has_feature(vb->vdev, VIRTIO_GUEST_PAGE_HINTING_VQ)) { - request_hypercall = (void *)&virtballoon_page_hinting; - balloon_ptr = vb; - } + if (virtio_has_feature(vb->vdev, VIRTIO_GUEST_PAGE_HINTING_VQ)) + enable_hinting(vb); #endif if (towards_target(vb)) diff --git a/include/linux/gfp.h b/include/linux/gfp.h index e02369b..2212e08 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -7,6 +7,7 @@ #include <linux/stddef.h> #include <linux/linkage.h> #include <linux/topology.h> +#include <linux/page_hinting.h> struct vm_area_struct; @@ -442,8 +443,19 @@ static inline struct zonelist *node_zonelist(int nid, gfp_t flags) #ifdef CONFIG_KVM_FREE_PAGE_HINTING #define HAVE_ARCH_ALLOC_PAGE #define HAVE_ARCH_FREE_PAGE -void arch_free_page(struct page *page, int order); -void arch_alloc_page(struct page *page, int order); +static inline void arch_alloc_page(struct page *page, int order) +{ + if (!static_branch_unlikely(&guest_page_hinting_key)) + return; + guest_alloc_page(page, order); +} + +static inline void arch_free_page(struct page *page, int order) +{ + if (!static_branch_unlikely(&guest_page_hinting_key)) + return; + guest_free_page(page, order); +} #endif #ifndef HAVE_ARCH_FREE_PAGE diff --git a/include/linux/page_hinting.h b/include/linux/page_hinting.h index 0bfb646..dd30644 100644 --- a/include/linux/page_hinting.h +++ b/include/linux/page_hinting.h @@ -14,3 +14,10 @@ struct hypervisor_pages { extern struct hypervisor_pages hypervisor_pagelist[MAX_FGPT_ENTRIES]; extern void (*request_hypercall)(void *, int); extern void *balloon_ptr; + +extern struct static_key_false guest_page_hinting_key; +int guest_page_hinting_sysctl(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos); +extern int guest_page_hinting_flag; +void guest_alloc_page(struct page *page, int order); +void guest_free_page(struct page *page, int order); diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 557d467..2717ceb 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1655,6 +1655,15 @@ static struct ctl_table vm_table[] = { .extra2 = (void *)&mmap_rnd_compat_bits_max, }, #endif +#ifdef CONFIG_KVM_FREE_PAGE_HINTING + { + .procname = "guest-page-hinting", + .data = &guest_page_hinting_flag, + .maxlen = sizeof(guest_page_hinting_flag), + .mode = 0644, + .proc_handler = guest_page_hinting_sysctl, + }, +#endif { } }; diff --git a/virt/kvm/page_hinting.c b/virt/kvm/page_hinting.c index 22c892b..f66ad63 100644 --- a/virt/kvm/page_hinting.c +++ b/virt/kvm/page_hinting.c @@ -5,7 +5,6 @@ #include <linux/sort.h> #include <linux/kernel.h> #include <trace/events/kmem.h> -#include <linux/page_hinting.h> #define HYPERLIST_THRESHOLD 500 /* @@ -30,6 +29,29 @@ void (*request_hypercall)(void *, int); EXPORT_SYMBOL(request_hypercall); void *balloon_ptr; EXPORT_SYMBOL(balloon_ptr); +struct static_key_false guest_page_hinting_key = STATIC_KEY_FALSE_INIT; +EXPORT_SYMBOL(guest_page_hinting_key); +static DEFINE_MUTEX(hinting_mutex); +int guest_page_hinting_flag; +EXPORT_SYMBOL(guest_page_hinting_flag); + +int guest_page_hinting_sysctl(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, + loff_t *ppos) +{ + int ret; + + mutex_lock(&hinting_mutex); + + ret = proc_dointvec(table, write, buffer, lenp, ppos); + + if (guest_page_hinting_flag) + static_key_enable(&guest_page_hinting_key.key); + else + static_key_disable(&guest_page_hinting_key.key); + mutex_unlock(&hinting_mutex); + return ret; +} static void empty_hyperlist(void) { @@ -254,7 +276,7 @@ void arch_free_page_slowpath(void) write_sequnlock(&guest_page_lock); } -void arch_alloc_page(struct page *page, int order) +void guest_alloc_page(struct page *page, int order) { unsigned int seq; @@ -270,12 +292,11 @@ void arch_alloc_page(struct page *page, int order) trace_guest_alloc_page(page, order); } -void arch_free_page(struct page *page, int order) +void guest_free_page(struct page *page, int order) { int *free_page_idx = &get_cpu_var(kvm_pt_idx); struct kvm_free_pages *free_page_obj; unsigned long flags; - /* * use of global variables may trigger a race condition between irq and * process context causing unwanted overwrites. This will be replaced -- 2.9.4