[PATCH] mm: add a new command-line kmemcheck value

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add a new command-line kmemcheck value: kmemcheck=3 (disable the feature),
this is the same effect as CONFIG_KMEMCHECK disabled.
After doing this, we can enable/disable kmemcheck feature in one vmlinux.

Signed-off-by: Xishi Qiu <qiuxishi@xxxxxxxxxx>
---
 arch/x86/mm/init.c                |   11 ++++++
 arch/x86/mm/kmemcheck/kmemcheck.c |   62 ++++++++++++++++++++++++++-----------
 arch/x86/mm/kmemcheck/shadow.c    |   13 +++++---
 include/linux/kmemcheck.h         |    2 +
 mm/kmemcheck.c                    |   12 +++++--
 mm/page_alloc.c                   |    2 +
 6 files changed, 76 insertions(+), 26 deletions(-)

diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index f971306..cd7d75f 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -135,6 +135,15 @@ static void __init probe_page_size_mask(void)
 		page_size_mask |= 1 << PG_LEVEL_2M;
 #endif
 
+#if defined(CONFIG_KMEMCHECK)
+	if (!kmemcheck_on) {
+		if (direct_gbpages)
+			page_size_mask |= 1 << PG_LEVEL_1G;
+		if (cpu_has_pse)
+			page_size_mask |= 1 << PG_LEVEL_2M;
+	}
+#endif
+
 	/* Enable PSE if available */
 	if (cpu_has_pse)
 		set_in_cr4(X86_CR4_PSE);
@@ -331,6 +340,8 @@ bool pfn_range_is_mapped(unsigned long start_pfn, unsigned long end_pfn)
 	return false;
 }
 
+extern int kmemcheck_on;
+
 /*
  * Setup the direct mapping of the physical memory at PAGE_OFFSET.
  * This runs before bootmem is initialized and gets pages directly from
diff --git a/arch/x86/mm/kmemcheck/kmemcheck.c b/arch/x86/mm/kmemcheck/kmemcheck.c
index d87dd6d..d686ee0 100644
--- a/arch/x86/mm/kmemcheck/kmemcheck.c
+++ b/arch/x86/mm/kmemcheck/kmemcheck.c
@@ -44,30 +44,35 @@
 #ifdef CONFIG_KMEMCHECK_ONESHOT_BY_DEFAULT
 #  define KMEMCHECK_ENABLED 2
 #endif
+#define KMEMCHECK_CLOSED 3
 
-int kmemcheck_enabled = KMEMCHECK_ENABLED;
+int kmemcheck_enabled = KMEMCHECK_CLOSED;
+int kmemcheck_on = 0;
 
 int __init kmemcheck_init(void)
 {
+	if (kmemcheck_on) {
 #ifdef CONFIG_SMP
-	/*
-	 * Limit SMP to use a single CPU. We rely on the fact that this code
-	 * runs before SMP is set up.
-	 */
-	if (setup_max_cpus > 1) {
-		printk(KERN_INFO
-			"kmemcheck: Limiting number of CPUs to 1.\n");
-		setup_max_cpus = 1;
-	}
+		/*
+		 * Limit SMP to use a single CPU. We rely on the fact that this code
+		 * runs before SMP is set up.
+		 */
+		if (setup_max_cpus > 1) {
+			printk(KERN_INFO
+				"kmemcheck: Limiting number of CPUs to 1.\n");
+			setup_max_cpus = 1;
+		}
 #endif
 
-	if (!kmemcheck_selftest()) {
-		printk(KERN_INFO "kmemcheck: self-tests failed; disabling\n");
-		kmemcheck_enabled = 0;
-		return -EINVAL;
+		if (!kmemcheck_selftest()) {
+			printk(KERN_INFO "kmemcheck: self-tests failed; disabling\n");
+			kmemcheck_enabled = 0;
+			return -EINVAL;
+		}
+
+		printk(KERN_INFO "kmemcheck: Initialized\n");
 	}
 
-	printk(KERN_INFO "kmemcheck: Initialized\n");
 	return 0;
 }
 
@@ -82,6 +87,12 @@ static int __init param_kmemcheck(char *str)
 		return -EINVAL;
 
 	sscanf(str, "%d", &kmemcheck_enabled);
+
+	if ((kmemcheck_enabled >= KMEMCHECK_CLOSED) || (kmemcheck_enabled < 0))
+		kmemcheck_on = 0;
+	else
+		kmemcheck_on = 1;
+
 	return 0;
 }
 
@@ -134,9 +145,12 @@ static DEFINE_PER_CPU(struct kmemcheck_context, kmemcheck_context);
 
 bool kmemcheck_active(struct pt_regs *regs)
 {
-	struct kmemcheck_context *data = &__get_cpu_var(kmemcheck_context);
+	if (kmemcheck_on) {
+		struct kmemcheck_context *data = &__get_cpu_var(kmemcheck_context);
+		return data->balance > 0;
+	}
 
-	return data->balance > 0;
+	return false;
 }
 
 /* Save an address that needs to be shown/hidden */
@@ -223,6 +237,9 @@ void kmemcheck_hide(struct pt_regs *regs)
 	struct kmemcheck_context *data = &__get_cpu_var(kmemcheck_context);
 	int n;
 
+	if (!kmemcheck_on)
+		return;
+
 	BUG_ON(!irqs_disabled());
 
 	if (unlikely(data->balance != 1)) {
@@ -278,6 +295,9 @@ void kmemcheck_show_pages(struct page *p, unsigned int n)
 
 bool kmemcheck_page_is_tracked(struct page *p)
 {
+	if (!kmemcheck_on)
+		return false;
+
 	/* This will also check the "hidden" flag of the PTE. */
 	return kmemcheck_pte_lookup((unsigned long) page_address(p));
 }
@@ -333,6 +353,9 @@ bool kmemcheck_is_obj_initialized(unsigned long addr, size_t size)
 	enum kmemcheck_shadow status;
 	void *shadow;
 
+	if (!kmemcheck_on)
+		return true;
+
 	shadow = kmemcheck_shadow_lookup(addr);
 	if (!shadow)
 		return true;
@@ -616,6 +639,9 @@ bool kmemcheck_fault(struct pt_regs *regs, unsigned long address,
 {
 	pte_t *pte;
 
+	if (!kmemcheck_on)
+		return false;
+
 	/*
 	 * XXX: Is it safe to assume that memory accesses from virtual 86
 	 * mode or non-kernel code segments will _never_ access kernel
@@ -644,7 +670,7 @@ bool kmemcheck_fault(struct pt_regs *regs, unsigned long address,
 
 bool kmemcheck_trap(struct pt_regs *regs)
 {
-	if (!kmemcheck_active(regs))
+	if (!kmemcheck_on || !kmemcheck_active(regs))
 		return false;
 
 	/* We're done. */
diff --git a/arch/x86/mm/kmemcheck/shadow.c b/arch/x86/mm/kmemcheck/shadow.c
index aec1242..26e461d 100644
--- a/arch/x86/mm/kmemcheck/shadow.c
+++ b/arch/x86/mm/kmemcheck/shadow.c
@@ -90,7 +90,8 @@ void kmemcheck_mark_uninitialized(void *address, unsigned int n)
  */
 void kmemcheck_mark_initialized(void *address, unsigned int n)
 {
-	mark_shadow(address, n, KMEMCHECK_SHADOW_INITIALIZED);
+	if (kmemcheck_on)
+		mark_shadow(address, n, KMEMCHECK_SHADOW_INITIALIZED);
 }
 EXPORT_SYMBOL_GPL(kmemcheck_mark_initialized);
 
@@ -103,16 +104,18 @@ void kmemcheck_mark_unallocated_pages(struct page *p, unsigned int n)
 {
 	unsigned int i;
 
-	for (i = 0; i < n; ++i)
-		kmemcheck_mark_unallocated(page_address(&p[i]), PAGE_SIZE);
+	if (kmemcheck_on)
+		for (i = 0; i < n; ++i)
+			kmemcheck_mark_unallocated(page_address(&p[i]), PAGE_SIZE);
 }
 
 void kmemcheck_mark_uninitialized_pages(struct page *p, unsigned int n)
 {
 	unsigned int i;
 
-	for (i = 0; i < n; ++i)
-		kmemcheck_mark_uninitialized(page_address(&p[i]), PAGE_SIZE);
+	if (kmemcheck_on)
+		for (i = 0; i < n; ++i)
+			kmemcheck_mark_uninitialized(page_address(&p[i]), PAGE_SIZE);
 }
 
 void kmemcheck_mark_initialized_pages(struct page *p, unsigned int n)
diff --git a/include/linux/kmemcheck.h b/include/linux/kmemcheck.h
index 39f8453..13d15e1 100644
--- a/include/linux/kmemcheck.h
+++ b/include/linux/kmemcheck.h
@@ -6,6 +6,7 @@
 
 #ifdef CONFIG_KMEMCHECK
 extern int kmemcheck_enabled;
+extern int kmemcheck_on;
 
 /* The slab-related functions. */
 void kmemcheck_alloc_shadow(struct page *page, int order, gfp_t flags, int node);
@@ -88,6 +89,7 @@ bool kmemcheck_is_obj_initialized(unsigned long addr, size_t size);
 
 #else
 #define kmemcheck_enabled 0
+#define kmemcheck_on 0
 
 static inline void
 kmemcheck_alloc_shadow(struct page *page, int order, gfp_t flags, int node)
diff --git a/mm/kmemcheck.c b/mm/kmemcheck.c
index fd814fd..fd89146 100644
--- a/mm/kmemcheck.c
+++ b/mm/kmemcheck.c
@@ -10,6 +10,9 @@ void kmemcheck_alloc_shadow(struct page *page, int order, gfp_t flags, int node)
 	int pages;
 	int i;
 
+	if (!kmemcheck_on)
+		return;
+
 	pages = 1 << order;
 
 	/*
@@ -41,6 +44,9 @@ void kmemcheck_free_shadow(struct page *page, int order)
 	int pages;
 	int i;
 
+	if (!kmemcheck_on)
+		return;
+
 	if (!kmemcheck_page_is_tracked(page))
 		return;
 
@@ -63,7 +69,7 @@ void kmemcheck_slab_alloc(struct kmem_cache *s, gfp_t gfpflags, void *object,
 	 * Has already been memset(), which initializes the shadow for us
 	 * as well.
 	 */
-	if (gfpflags & __GFP_ZERO)
+	if (!kmemcheck_on || gfpflags & __GFP_ZERO)
 		return;
 
 	/* No need to initialize the shadow of a non-tracked slab. */
@@ -92,7 +98,7 @@ void kmemcheck_slab_alloc(struct kmem_cache *s, gfp_t gfpflags, void *object,
 void kmemcheck_slab_free(struct kmem_cache *s, void *object, size_t size)
 {
 	/* TODO: RCU freeing is unsupported for now; hide false positives. */
-	if (!s->ctor && !(s->flags & SLAB_DESTROY_BY_RCU))
+	if (kmemcheck_on && !s->ctor && !(s->flags & SLAB_DESTROY_BY_RCU))
 		kmemcheck_mark_freed(object, size);
 }
 
@@ -101,7 +107,7 @@ void kmemcheck_pagealloc_alloc(struct page *page, unsigned int order,
 {
 	int pages;
 
-	if (gfpflags & (__GFP_HIGHMEM | __GFP_NOTRACK))
+	if (!kmemcheck_on || (gfpflags & (__GFP_HIGHMEM | __GFP_NOTRACK)))
 		return;
 
 	pages = 1 << order;
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index f861d02..0b2bbf2 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -2716,6 +2716,8 @@ retry_cpuset:
 	page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, nodemask, order,
 			zonelist, high_zoneidx, alloc_flags,
 			preferred_zone, migratetype);
+	if (kmemcheck_on && kmemcheck_enabled && page)
+		kmemcheck_pagealloc_alloc(page, order, gfp_mask);
 	if (unlikely(!page)) {
 		/*
 		 * Runtime PM, block IO and its error handling path
-- 
1.7.1



--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@xxxxxxxxx.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@xxxxxxxxx";> email@xxxxxxxxx </a>




[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]