aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/vm/hwpoison.txt16
-rw-r--r--mm/hwpoison-inject.c7
-rw-r--r--mm/internal.h1
-rw-r--r--mm/memory-failure.c46
4 files changed, 70 insertions, 0 deletions
diff --git a/Documentation/vm/hwpoison.txt b/Documentation/vm/hwpoison.txt
index f454d3cd4d60..989e5afe740f 100644
--- a/Documentation/vm/hwpoison.txt
+++ b/Documentation/vm/hwpoison.txt
@@ -123,6 +123,22 @@ Only handle memory failures to pages associated with the file system defined
123by block device major/minor. -1U is the wildcard value. 123by block device major/minor. -1U is the wildcard value.
124This should be only used for testing with artificial injection. 124This should be only used for testing with artificial injection.
125 125
126corrupt-filter-memcg
127
128Limit injection to pages owned by memgroup. Specified by inode number
129of the memcg.
130
131Example:
132 mkdir /cgroup/hwpoison
133
134 usemem -m 100 -s 1000 &
135 echo `jobs -p` > /cgroup/hwpoison/tasks
136
137 memcg_ino=$(ls -id /cgroup/hwpoison | cut -f1 -d' ')
138 echo $memcg_ino > /debug/hwpoison/corrupt-filter-memcg
139
140 page-types -p `pidof init` --hwpoison # shall do nothing
141 page-types -p `pidof usemem` --hwpoison # poison its pages
126 142
127corrupt-filter-flags-mask 143corrupt-filter-flags-mask
128corrupt-filter-flags-value 144corrupt-filter-flags-value
diff --git a/mm/hwpoison-inject.c b/mm/hwpoison-inject.c
index c4dfd89f654a..c838735ac31d 100644
--- a/mm/hwpoison-inject.c
+++ b/mm/hwpoison-inject.c
@@ -112,6 +112,13 @@ static int pfn_inject_init(void)
112 if (!dentry) 112 if (!dentry)
113 goto fail; 113 goto fail;
114 114
115#ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
116 dentry = debugfs_create_u64("corrupt-filter-memcg", 0600,
117 hwpoison_dir, &hwpoison_filter_memcg);
118 if (!dentry)
119 goto fail;
120#endif
121
115 return 0; 122 return 0;
116fail: 123fail:
117 pfn_inject_exit(); 124 pfn_inject_exit();
diff --git a/mm/internal.h b/mm/internal.h
index b2027c73119b..5a6761bea6a6 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -257,3 +257,4 @@ extern u32 hwpoison_filter_dev_major;
257extern u32 hwpoison_filter_dev_minor; 257extern u32 hwpoison_filter_dev_minor;
258extern u64 hwpoison_filter_flags_mask; 258extern u64 hwpoison_filter_flags_mask;
259extern u64 hwpoison_filter_flags_value; 259extern u64 hwpoison_filter_flags_value;
260extern u64 hwpoison_filter_memcg;
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 22d2b2028e54..117ef1598469 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -100,6 +100,49 @@ static int hwpoison_filter_flags(struct page *p)
100 return -EINVAL; 100 return -EINVAL;
101} 101}
102 102
103/*
104 * This allows stress tests to limit test scope to a collection of tasks
105 * by putting them under some memcg. This prevents killing unrelated/important
106 * processes such as /sbin/init. Note that the target task may share clean
107 * pages with init (eg. libc text), which is harmless. If the target task
108 * share _dirty_ pages with another task B, the test scheme must make sure B
109 * is also included in the memcg. At last, due to race conditions this filter
110 * can only guarantee that the page either belongs to the memcg tasks, or is
111 * a freed page.
112 */
113#ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
114u64 hwpoison_filter_memcg;
115EXPORT_SYMBOL_GPL(hwpoison_filter_memcg);
116static int hwpoison_filter_task(struct page *p)
117{
118 struct mem_cgroup *mem;
119 struct cgroup_subsys_state *css;
120 unsigned long ino;
121
122 if (!hwpoison_filter_memcg)
123 return 0;
124
125 mem = try_get_mem_cgroup_from_page(p);
126 if (!mem)
127 return -EINVAL;
128
129 css = mem_cgroup_css(mem);
130 /* root_mem_cgroup has NULL dentries */
131 if (!css->cgroup->dentry)
132 return -EINVAL;
133
134 ino = css->cgroup->dentry->d_inode->i_ino;
135 css_put(css);
136
137 if (ino != hwpoison_filter_memcg)
138 return -EINVAL;
139
140 return 0;
141}
142#else
143static int hwpoison_filter_task(struct page *p) { return 0; }
144#endif
145
103int hwpoison_filter(struct page *p) 146int hwpoison_filter(struct page *p)
104{ 147{
105 if (hwpoison_filter_dev(p)) 148 if (hwpoison_filter_dev(p))
@@ -108,6 +151,9 @@ int hwpoison_filter(struct page *p)
108 if (hwpoison_filter_flags(p)) 151 if (hwpoison_filter_flags(p))
109 return -EINVAL; 152 return -EINVAL;
110 153
154 if (hwpoison_filter_task(p))
155 return -EINVAL;
156
111 return 0; 157 return 0;
112} 158}
113EXPORT_SYMBOL_GPL(hwpoison_filter); 159EXPORT_SYMBOL_GPL(hwpoison_filter);