From a06deabd2fb3b2993de884449430012355add4fd Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli <aarcange@redhat.com> Date: Wed, 7 Apr 2010 22:15:49 -0300 Subject: [PATCH 2/2] avoid leaving orphaned swapcache in ksm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RH-Author: Andrea Arcangeli <aarcange@redhat.com> Message-id: <20100407221549.GO5706@random.random> Patchwork-id: 8456 O-Subject: Re: [PATCH KVM RHEL5 KSM] avoid leaving orphaned swapcache in ksm Bugzilla: 575585 RH-Acked-by: Rik van Riel <riel@redhat.com> RH-Acked-by: Izik Eidus <ieidus@redhat.com> RH-Acked-by: Marcelo Tosatti <mtosatti@redhat.com> On Wed, Apr 07, 2010 at 07:08:05PM -0300, Eduardo Habkost wrote: > On Thu, Mar 25, 2010 at 06:04:18PM +0100, Andrea Arcangeli wrote: > > Subject: release swap cache from merged pages > > > > From: Andrea Arcangeli <aarcange@redhat.com> > > > > Remove the old page from swapcache if it was the last mapping. > > > > Signed-off-by: Andrea Arcangeli <aarcange@redhat.com> > > --- > > > > https://bugzilla.redhat.com/show_bug.cgi?id=575585 > > > > diff --git a/kernel/ksm/ksm.h b/kernel/ksm/ksm.h > > index 91ca286..ad68c2f 100644 > > --- a/kernel/ksm/ksm.h > > +++ b/kernel/ksm/ksm.h > > @@ -81,4 +81,6 @@ struct ksm_kthread_info { > > #define KSM_SCAN _IOW(KSMIO, 0x40,\ > > struct ksm_user_scan) > > > > +static void (*free_page_and_swap_cache_p)(struct page *page); > > + > > NACK. This breaks the userspace build when using --enable-werror: > > make -C x86_64-softmmu all > make[2]: Entering directory `/var/lib/builder/rhevh/source-root/kvm/qemu/x86_64-softmmu' > CC vl.o > cc1: warnings being treated as errors > In file included from /var/lib/builder/rhevh/source-root/kvm/qemu/vl.c:25: > /var/lib/builder/rhevh/source-root/kvm/qemu/../kernel/ksm/ksm.h:84: warning: ‘struct page’ declared inside parameter list > /var/lib/builder/rhevh/source-root/kvm/qemu/../kernel/ksm/ksm.h:84: warning: its scope is only this definition or declaration, which is probably not what you want > make[2]: *** [vl.o] Error 1 > make[2]: Leaving directory `/var/lib/builder/rhevh/source-root/kvm/qemu/x86_64-softmmu' > make[1]: *** [subdir-x86_64-softmmu] Error 2 > make[1]: Leaving directory `/var/lib/builder/rhevh/source-root/kvm/qemu' > make: *** [qemu] Error 2 > > > --enable-werror was supposed to be enabled on the spec file, but it looks like > I forgot to do it back in August (sorry). > > http://post-office.corp.redhat.com/archives/virtualist/2009-August/msg00622.html The ksm.h part is not needed. ------------- Subject: release swap cache from merged pages From: Andrea Arcangeli <aarcange@redhat.com> Remove the old page from swapcache if it was the last mapping. Signed-off-by: Andrea Arcangeli <aarcange@redhat.com> --- https://bugzilla.redhat.com/show_bug.cgi?id=575585 Signed-off-by: Eduardo Habkost <ehabkost@redhat.com> --- kernel/ksm/ksm_main.c | 40 ++++++++++++++++++++++++++++++++++++---- 1 files changed, 36 insertions(+), 4 deletions(-) diff --git a/kernel/ksm/ksm_main.c b/kernel/ksm/ksm_main.c index 7032b4f..ddb977a 100644 --- a/kernel/ksm/ksm_main.c +++ b/kernel/ksm/ksm_main.c @@ -37,6 +37,7 @@ #include <linux/swap.h> #include <linux/rbtree.h> #include <linux/anon_inodes.h> +#include <linux/kprobes.h> #include <asm/tlbflush.h> @@ -148,6 +149,8 @@ static struct task_struct *kthread; static DECLARE_WAIT_QUEUE_HEAD(kthread_wait); static DECLARE_RWSEM(kthread_lock); +static void (*free_page_and_swap_cache_p)(struct page *page) = put_page; + static int ksm_slab_init(void) { int ret = -ENOMEM; @@ -1019,8 +1022,9 @@ static int cmp_and_merge_page(struct ksm_scan *ksm_scan, struct page *page) tmp_rmap_item->tree_item; } } - } - put_page(page2[0]); + free_page_and_swap_cache_p(page2[0]); + } else + put_page(page2[0]); return !ret; } if (!wait && !rmap_item) { @@ -1129,9 +1133,14 @@ static int ksm_scan_start(struct ksm_scan *ksm_scan, int scan_npages) 1, 0, 0, page, NULL); up_read(&slot->mm->mmap_sem); if (val == 1) { - if (!PageKsm(page[0])) + if (!PageKsm(page[0])) { cmp_and_merge_page(ksm_scan, page[0]); - put_page(page[0]); + if (!page_mapped(page[0])) + free_page_and_swap_cache_p(page[0]); + else + put_page(page[0]); + } else + put_page(page[0]); } } else { up_read(&slot->mm->mmap_sem); @@ -1373,10 +1382,33 @@ int kthread_ksm_scan_thread(void *nothing) return 0; } +static void __init init_free_page_and_swap_cache_p(void) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) && defined(CONFIG_KALLSYMS) && !defined(RHEL_RELEASE_CODE) + free_page_and_swap_cache_p = (void (*)(struct page *)) + kallsyms_lookup_name("free_page_and_swap_cache"); + BUG_ON(!free_page_and_swap_cache_p); +#else + struct kprobe tmp; + + memset(&tmp, 0, sizeof(struct kprobe)); + tmp.symbol_name = "free_page_and_swap_cache"; + + if (register_kprobe(&tmp)) + printk(KERN_WARNING "free_page_and_swap_cache as put_page"); + else { + free_page_and_swap_cache_p = (void (*)(struct page *)) tmp.addr; + unregister_kprobe(&tmp); + } +#endif +} + static int __init ksm_init(void) { int r; + init_free_page_and_swap_cache_p(); + r = ksm_slab_init(); if (r) goto out; -- 1.7.0.3