Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 340e01248478ba8b78a6d4d1809b1eff > files > 271

kvm-83-270.el5_11.src.rpm

From d8cc8d7c2e6ba00cb91bb988281a62c330e49cf5 Mon Sep 17 00:00:00 2001
From: Andrea Arcangeli <aarcange@redhat.com>
Date: Thu, 25 Mar 2010 17:04:18 -0300
Subject: [PATCH] avoid leaving orphaned swapcache in ksm

RH-Author: Andrea Arcangeli <aarcange@redhat.com>
Message-id: <20100325170418.GU10659@random.random>
Patchwork-id: 8132
O-Subject: [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>

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.h      |    2 ++
 kernel/ksm/ksm_main.c |   40 ++++++++++++++++++++++++++++++++++++----
 2 files changed, 38 insertions(+), 4 deletions(-)

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);
+
 #endif
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