Commit dc2a1cbf authored by Wu Fengguang's avatar Wu Fengguang Committed by Andi Kleen

HWPOISON: introduce delete_from_lru_cache()

Introduce delete_from_lru_cache() to
- clear PG_active, PG_unevictable to avoid complains at unpoison time
- move the isolate_lru_page() call back to the handlers instead of the
  entrance of __memory_failure(), this is more hwpoison filter friendly
Signed-off-by: default avatarWu Fengguang <fengguang.wu@intel.com>
Signed-off-by: default avatarAndi Kleen <ak@linux.intel.com>
parent 71f72525
...@@ -349,6 +349,30 @@ static const char *action_name[] = { ...@@ -349,6 +349,30 @@ static const char *action_name[] = {
[RECOVERED] = "Recovered", [RECOVERED] = "Recovered",
}; };
/*
* XXX: It is possible that a page is isolated from LRU cache,
* and then kept in swap cache or failed to remove from page cache.
* The page count will stop it from being freed by unpoison.
* Stress tests should be aware of this memory leak problem.
*/
static int delete_from_lru_cache(struct page *p)
{
if (!isolate_lru_page(p)) {
/*
* Clear sensible page flags, so that the buddy system won't
* complain when the page is unpoison-and-freed.
*/
ClearPageActive(p);
ClearPageUnevictable(p);
/*
* drop the page count elevated by isolate_lru_page()
*/
page_cache_release(p);
return 0;
}
return -EIO;
}
/* /*
* Error hit kernel page. * Error hit kernel page.
* Do nothing, try to be lucky and not touch this instead. For a few cases we * Do nothing, try to be lucky and not touch this instead. For a few cases we
...@@ -393,6 +417,8 @@ static int me_pagecache_clean(struct page *p, unsigned long pfn) ...@@ -393,6 +417,8 @@ static int me_pagecache_clean(struct page *p, unsigned long pfn)
int ret = FAILED; int ret = FAILED;
struct address_space *mapping; struct address_space *mapping;
delete_from_lru_cache(p);
/* /*
* For anonymous pages we're done the only reference left * For anonymous pages we're done the only reference left
* should be the one m_f() holds. * should be the one m_f() holds.
...@@ -522,14 +548,20 @@ static int me_swapcache_dirty(struct page *p, unsigned long pfn) ...@@ -522,14 +548,20 @@ static int me_swapcache_dirty(struct page *p, unsigned long pfn)
/* Trigger EIO in shmem: */ /* Trigger EIO in shmem: */
ClearPageUptodate(p); ClearPageUptodate(p);
return DELAYED; if (!delete_from_lru_cache(p))
return DELAYED;
else
return FAILED;
} }
static int me_swapcache_clean(struct page *p, unsigned long pfn) static int me_swapcache_clean(struct page *p, unsigned long pfn)
{ {
delete_from_swap_cache(p); delete_from_swap_cache(p);
return RECOVERED; if (!delete_from_lru_cache(p))
return RECOVERED;
else
return FAILED;
} }
/* /*
...@@ -746,7 +778,6 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn, ...@@ -746,7 +778,6 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
int __memory_failure(unsigned long pfn, int trapno, int flags) int __memory_failure(unsigned long pfn, int trapno, int flags)
{ {
unsigned long lru_flag;
struct page_state *ps; struct page_state *ps;
struct page *p; struct page *p;
int res; int res;
...@@ -796,13 +827,11 @@ int __memory_failure(unsigned long pfn, int trapno, int flags) ...@@ -796,13 +827,11 @@ int __memory_failure(unsigned long pfn, int trapno, int flags)
*/ */
if (!PageLRU(p)) if (!PageLRU(p))
lru_add_drain_all(); lru_add_drain_all();
lru_flag = p->flags & lru; if (!PageLRU(p)) {
if (isolate_lru_page(p)) {
action_result(pfn, "non LRU", IGNORED); action_result(pfn, "non LRU", IGNORED);
put_page(p); put_page(p);
return -EBUSY; return -EBUSY;
} }
page_cache_release(p);
/* /*
* Lock the page and wait for writeback to finish. * Lock the page and wait for writeback to finish.
...@@ -825,7 +854,7 @@ int __memory_failure(unsigned long pfn, int trapno, int flags) ...@@ -825,7 +854,7 @@ int __memory_failure(unsigned long pfn, int trapno, int flags)
/* /*
* Torn down by someone else? * Torn down by someone else?
*/ */
if ((lru_flag & lru) && !PageSwapCache(p) && p->mapping == NULL) { if (PageLRU(p) && !PageSwapCache(p) && p->mapping == NULL) {
action_result(pfn, "already truncated LRU", IGNORED); action_result(pfn, "already truncated LRU", IGNORED);
res = 0; res = 0;
goto out; goto out;
...@@ -833,7 +862,7 @@ int __memory_failure(unsigned long pfn, int trapno, int flags) ...@@ -833,7 +862,7 @@ int __memory_failure(unsigned long pfn, int trapno, int flags)
res = -EBUSY; res = -EBUSY;
for (ps = error_states;; ps++) { for (ps = error_states;; ps++) {
if (((p->flags | lru_flag)& ps->mask) == ps->res) { if ((p->flags & ps->mask) == ps->res) {
res = page_action(ps, p, pfn); res = page_action(ps, p, pfn);
break; break;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment