diff options
author | Xishi Qiu <qiuxishi@huawei.com> | 2014-02-13 21:33:35 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-02-20 14:06:12 -0500 |
commit | 6843d9254c8cd2decb30edaf7deffaad4d244c51 (patch) | |
tree | dffc1779a7aef3aeb8128d2daa0ec5cd40527e32 /mm | |
parent | 2d9258e499abbbe55fb60a26995e378f2b51d513 (diff) |
mm: fix process accidentally killed by mce because of huge page migration
Based on c8721bbbdd36382de51cd6b7a56322e0acca2414 upstream, but only the
bugfix portion pulled out.
Hi Naoya or Greg,
We found a bug in 3.10.x.
The problem is that we accidentally have a hwpoisoned hugepage in free
hugepage list. It could happend in the the following scenario:
process A process B
migrate_huge_page
put_page (old hugepage)
linked to free hugepage list
hugetlb_fault
hugetlb_no_page
alloc_huge_page
dequeue_huge_page_vma
dequeue_huge_page_node
(steal hwpoisoned hugepage)
set_page_hwpoison_huge_page
dequeue_hwpoisoned_huge_page
(fail to dequeue)
I tested this bug, one process keeps allocating huge page, and I
use sysfs interface to soft offline a huge page, then received:
"MCE: Killing UCP:2717 due to hardware memory corruption fault at 8200034"
Upstream kernel is free from this bug because of these two commits:
f15bdfa802bfa5eb6b4b5a241b97ec9fa1204a35
mm/memory-failure.c: fix memory leak in successful soft offlining
c8721bbbdd36382de51cd6b7a56322e0acca2414
mm: memory-hotplug: enable memory hotplug to handle hugepage
The first one, although the problem is about memory leak, this patch
moves unset_migratetype_isolate(), which is important to avoid the race.
The latter is not a bug fix and it's too big, so I rewrite a small one.
The following patch can fix this bug.(please apply f15bdfa802bf first)
Signed-off-by: Xishi Qiu <qiuxishi@huawei.com>
Reviewed-by: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'mm')
-rw-r--r-- | mm/hugetlb.c | 11 |
1 files changed, 9 insertions, 2 deletions
diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 40ad2c6e0ca9..aa3b9a63394b 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/rmap.h> | 21 | #include <linux/rmap.h> |
22 | #include <linux/swap.h> | 22 | #include <linux/swap.h> |
23 | #include <linux/swapops.h> | 23 | #include <linux/swapops.h> |
24 | #include <linux/page-isolation.h> | ||
24 | 25 | ||
25 | #include <asm/page.h> | 26 | #include <asm/page.h> |
26 | #include <asm/pgtable.h> | 27 | #include <asm/pgtable.h> |
@@ -517,9 +518,15 @@ static struct page *dequeue_huge_page_node(struct hstate *h, int nid) | |||
517 | { | 518 | { |
518 | struct page *page; | 519 | struct page *page; |
519 | 520 | ||
520 | if (list_empty(&h->hugepage_freelists[nid])) | 521 | list_for_each_entry(page, &h->hugepage_freelists[nid], lru) |
522 | if (!is_migrate_isolate_page(page)) | ||
523 | break; | ||
524 | /* | ||
525 | * if 'non-isolated free hugepage' not found on the list, | ||
526 | * the allocation fails. | ||
527 | */ | ||
528 | if (&h->hugepage_freelists[nid] == &page->lru) | ||
521 | return NULL; | 529 | return NULL; |
522 | page = list_entry(h->hugepage_freelists[nid].next, struct page, lru); | ||
523 | list_move(&page->lru, &h->hugepage_activelist); | 530 | list_move(&page->lru, &h->hugepage_activelist); |
524 | set_page_refcounted(page); | 531 | set_page_refcounted(page); |
525 | h->free_huge_pages--; | 532 | h->free_huge_pages--; |