Skip to content

Commit

Permalink
HWPOISON: add memory cgroup filter
Browse files Browse the repository at this point in the history
The hwpoison test suite need to inject hwpoison to a collection of
selected task pages, and must not touch pages not owned by them and
thus kill important system processes such as init. (But it's OK to
mis-hwpoison free/unowned pages as well as shared clean pages.
Mis-hwpoison of shared dirty pages will kill all tasks, so the test
suite will target all or non of such tasks in the first place.)

The memory cgroup serves this purpose well. We can put the target
processes under the control of a memory cgroup, and tell the hwpoison
injection code to only kill pages associated with some active memory
cgroup.

The prerequisite for doing hwpoison stress tests with mem_cgroup is,
the mem_cgroup code tracks task pages _accurately_ (unless page is
locked).  Which we believe is/should be true.

The benefits are simplification of hwpoison injector code. Also the
mem_cgroup code will automatically be tested by hwpoison test cases.

The alternative interfaces pin-pfn/unpin-pfn can also delegate the
(process and page flags) filtering functions reliably to user space.
However prototype implementation shows that this scheme adds more
complexity than we wanted.

Example test case:

	mkdir /cgroup/hwpoison

	usemem -m 100 -s 1000 &
	echo `jobs -p` > /cgroup/hwpoison/tasks

	memcg_ino=$(ls -id /cgroup/hwpoison | cut -f1 -d' ')
	echo $memcg_ino > /debug/hwpoison/corrupt-filter-memcg

	page-types -p `pidof init`   --hwpoison  # shall do nothing
	page-types -p `pidof usemem` --hwpoison  # poison its pages

[AK: Fix documentation]
[Add fix for problem noticed by Li Zefan <[email protected]>;
dentry in the css could be NULL]

CC: KOSAKI Motohiro <[email protected]>
CC: Hugh Dickins <[email protected]>
CC: Daisuke Nishimura <[email protected]>
CC: Balbir Singh <[email protected]>
CC: KAMEZAWA Hiroyuki <[email protected]>
CC: Li Zefan <[email protected]>
CC: Paul Menage <[email protected]>
CC: Nick Piggin <[email protected]>
CC: Andi Kleen <[email protected]>
Signed-off-by: Wu Fengguang <[email protected]>
Signed-off-by: Andi Kleen <[email protected]>
  • Loading branch information
Andi Kleen authored and Andi Kleen committed Dec 16, 2009
1 parent d324236 commit 4fd466e
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 0 deletions.
16 changes: 16 additions & 0 deletions Documentation/vm/hwpoison.txt
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,22 @@ Only handle memory failures to pages associated with the file system defined
by block device major/minor. -1U is the wildcard value.
This should be only used for testing with artificial injection.

corrupt-filter-memcg

Limit injection to pages owned by memgroup. Specified by inode number
of the memcg.

Example:
mkdir /cgroup/hwpoison

usemem -m 100 -s 1000 &
echo `jobs -p` > /cgroup/hwpoison/tasks

memcg_ino=$(ls -id /cgroup/hwpoison | cut -f1 -d' ')
echo $memcg_ino > /debug/hwpoison/corrupt-filter-memcg

page-types -p `pidof init` --hwpoison # shall do nothing
page-types -p `pidof usemem` --hwpoison # poison its pages

corrupt-filter-flags-mask
corrupt-filter-flags-value
Expand Down
7 changes: 7 additions & 0 deletions mm/hwpoison-inject.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,13 @@ static int pfn_inject_init(void)
if (!dentry)
goto fail;

#ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
dentry = debugfs_create_u64("corrupt-filter-memcg", 0600,
hwpoison_dir, &hwpoison_filter_memcg);
if (!dentry)
goto fail;
#endif

return 0;
fail:
pfn_inject_exit();
Expand Down
1 change: 1 addition & 0 deletions mm/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -257,3 +257,4 @@ extern u32 hwpoison_filter_dev_major;
extern u32 hwpoison_filter_dev_minor;
extern u64 hwpoison_filter_flags_mask;
extern u64 hwpoison_filter_flags_value;
extern u64 hwpoison_filter_memcg;
46 changes: 46 additions & 0 deletions mm/memory-failure.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,49 @@ static int hwpoison_filter_flags(struct page *p)
return -EINVAL;
}

/*
* This allows stress tests to limit test scope to a collection of tasks
* by putting them under some memcg. This prevents killing unrelated/important
* processes such as /sbin/init. Note that the target task may share clean
* pages with init (eg. libc text), which is harmless. If the target task
* share _dirty_ pages with another task B, the test scheme must make sure B
* is also included in the memcg. At last, due to race conditions this filter
* can only guarantee that the page either belongs to the memcg tasks, or is
* a freed page.
*/
#ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
u64 hwpoison_filter_memcg;
EXPORT_SYMBOL_GPL(hwpoison_filter_memcg);
static int hwpoison_filter_task(struct page *p)
{
struct mem_cgroup *mem;
struct cgroup_subsys_state *css;
unsigned long ino;

if (!hwpoison_filter_memcg)
return 0;

mem = try_get_mem_cgroup_from_page(p);
if (!mem)
return -EINVAL;

css = mem_cgroup_css(mem);
/* root_mem_cgroup has NULL dentries */
if (!css->cgroup->dentry)
return -EINVAL;

ino = css->cgroup->dentry->d_inode->i_ino;
css_put(css);

if (ino != hwpoison_filter_memcg)
return -EINVAL;

return 0;
}
#else
static int hwpoison_filter_task(struct page *p) { return 0; }
#endif

int hwpoison_filter(struct page *p)
{
if (hwpoison_filter_dev(p))
Expand All @@ -108,6 +151,9 @@ int hwpoison_filter(struct page *p)
if (hwpoison_filter_flags(p))
return -EINVAL;

if (hwpoison_filter_task(p))
return -EINVAL;

return 0;
}
EXPORT_SYMBOL_GPL(hwpoison_filter);
Expand Down

0 comments on commit 4fd466e

Please sign in to comment.