From 76fef140a395cfceb7d6595249f77333a4b0c0af Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 16 Dec 2009 12:19:59 +0100 Subject: [PATCH] --- yaml --- r: 177627 b: refs/heads/master c: 31d3d3484f9bd263925ecaa341500ac2df3a5d9b h: refs/heads/master i: 177625: cac2a114419c02583ababfe53d1078c9cc9085be 177623: 2ec5357f2241e9378ceb17a983a97da7c2a12611 v: v3 --- [refs] | 2 +- trunk/Documentation/vm/hwpoison.txt | 3 ++- trunk/mm/hwpoison-inject.c | 41 +++++++++++++++++++++++++++-- trunk/mm/internal.h | 2 ++ 4 files changed, 44 insertions(+), 4 deletions(-) diff --git a/[refs] b/[refs] index 9d02c849a199..13b28db28423 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 7c116f2b0dbac4a1dd051c7a5e8cef37701cafd4 +refs/heads/master: 31d3d3484f9bd263925ecaa341500ac2df3a5d9b diff --git a/trunk/Documentation/vm/hwpoison.txt b/trunk/Documentation/vm/hwpoison.txt index fdf580464324..4ef7bb30d15c 100644 --- a/trunk/Documentation/vm/hwpoison.txt +++ b/trunk/Documentation/vm/hwpoison.txt @@ -103,7 +103,8 @@ hwpoison-inject module through debugfs corrupt-pfn -Inject hwpoison fault at PFN echoed into this file. +Inject hwpoison fault at PFN echoed into this file. This does +some early filtering to avoid corrupted unintended pages in test suites. unpoison-pfn diff --git a/trunk/mm/hwpoison-inject.c b/trunk/mm/hwpoison-inject.c index ac692a9b766c..2b6b3200fa65 100644 --- a/trunk/mm/hwpoison-inject.c +++ b/trunk/mm/hwpoison-inject.c @@ -3,16 +3,53 @@ #include #include #include +#include +#include #include "internal.h" static struct dentry *hwpoison_dir; static int hwpoison_inject(void *data, u64 val) { + unsigned long pfn = val; + struct page *p; + int err; + if (!capable(CAP_SYS_ADMIN)) return -EPERM; - printk(KERN_INFO "Injecting memory failure at pfn %Lx\n", val); - return __memory_failure(val, 18, 0); + + if (!pfn_valid(pfn)) + return -ENXIO; + + p = pfn_to_page(pfn); + /* + * This implies unable to support free buddy pages. + */ + if (!get_page_unless_zero(p)) + return 0; + + if (!PageLRU(p)) + shake_page(p); + /* + * This implies unable to support non-LRU pages. + */ + if (!PageLRU(p)) + return 0; + + /* + * do a racy check with elevated page count, to make sure PG_hwpoison + * will only be set for the targeted owner (or on a free page). + * We temporarily take page lock for try_get_mem_cgroup_from_page(). + * __memory_failure() will redo the check reliably inside page lock. + */ + lock_page(p); + err = hwpoison_filter(p); + unlock_page(p); + if (err) + return 0; + + printk(KERN_INFO "Injecting memory failure at pfn %lx\n", pfn); + return __memory_failure(pfn, 18, MF_COUNT_INCREASED); } static int hwpoison_unpoison(void *data, u64 val) diff --git a/trunk/mm/internal.h b/trunk/mm/internal.h index 814da335f050..04bbce8b8ba6 100644 --- a/trunk/mm/internal.h +++ b/trunk/mm/internal.h @@ -251,5 +251,7 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, #define ZONE_RECLAIM_SUCCESS 1 #endif +extern int hwpoison_filter(struct page *p); + extern u32 hwpoison_filter_dev_major; extern u32 hwpoison_filter_dev_minor;