Commit f96efd585b8d847181f81bf16721f96ded18d9fe
Committed by
Linus Torvalds
1 parent
2706a1b89b
Exists in
master
and in
4 other branches
hugetlb: fix race in alloc_fresh_huge_page()
That static `nid' index needs locking. Without it we can end up calling alloc_pages_node() with an illegal node ID and the kernel crashes. Acked-by: gurudas pai <gurudas.pai@oracle.com> Cc: <stable@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 1 changed file with 11 additions and 4 deletions Side-by-side Diff
mm/hugetlb.c
... | ... | @@ -101,13 +101,20 @@ |
101 | 101 | |
102 | 102 | static int alloc_fresh_huge_page(void) |
103 | 103 | { |
104 | - static int nid = 0; | |
104 | + static int prev_nid; | |
105 | 105 | struct page *page; |
106 | - page = alloc_pages_node(nid, GFP_HIGHUSER|__GFP_COMP|__GFP_NOWARN, | |
107 | - HUGETLB_PAGE_ORDER); | |
108 | - nid = next_node(nid, node_online_map); | |
106 | + static DEFINE_SPINLOCK(nid_lock); | |
107 | + int nid; | |
108 | + | |
109 | + spin_lock(&nid_lock); | |
110 | + nid = next_node(prev_nid, node_online_map); | |
109 | 111 | if (nid == MAX_NUMNODES) |
110 | 112 | nid = first_node(node_online_map); |
113 | + prev_nid = nid; | |
114 | + spin_unlock(&nid_lock); | |
115 | + | |
116 | + page = alloc_pages_node(nid, GFP_HIGHUSER|__GFP_COMP|__GFP_NOWARN, | |
117 | + HUGETLB_PAGE_ORDER); | |
111 | 118 | if (page) { |
112 | 119 | set_compound_page_dtor(page, free_huge_page); |
113 | 120 | spin_lock(&hugetlb_lock); |