diff options
author | Joe Jin <joe.jin@oracle.com> | 2007-07-16 02:38:12 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-16 12:05:35 -0400 |
commit | f96efd585b8d847181f81bf16721f96ded18d9fe (patch) | |
tree | 10821321b4f501e3126606ef2b54eb356ec8ef77 /mm/hugetlb.c | |
parent | 2706a1b89b1a3e7434a668d4a9d15f616da96685 (diff) |
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>
Diffstat (limited to 'mm/hugetlb.c')
-rw-r--r-- | mm/hugetlb.c | 15 |
1 files changed, 11 insertions, 4 deletions
diff --git a/mm/hugetlb.c b/mm/hugetlb.c index eaba7d6b25a..acc0fb3cf06 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c | |||
@@ -101,13 +101,20 @@ static void free_huge_page(struct page *page) | |||
101 | 101 | ||
102 | static int alloc_fresh_huge_page(void) | 102 | static int alloc_fresh_huge_page(void) |
103 | { | 103 | { |
104 | static int nid = 0; | 104 | static int prev_nid; |
105 | struct page *page; | 105 | struct page *page; |
106 | page = alloc_pages_node(nid, GFP_HIGHUSER|__GFP_COMP|__GFP_NOWARN, | 106 | static DEFINE_SPINLOCK(nid_lock); |
107 | HUGETLB_PAGE_ORDER); | 107 | int nid; |
108 | nid = next_node(nid, node_online_map); | 108 | |
109 | spin_lock(&nid_lock); | ||
110 | nid = next_node(prev_nid, node_online_map); | ||
109 | if (nid == MAX_NUMNODES) | 111 | if (nid == MAX_NUMNODES) |
110 | nid = first_node(node_online_map); | 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 | if (page) { | 118 | if (page) { |
112 | set_compound_page_dtor(page, free_huge_page); | 119 | set_compound_page_dtor(page, free_huge_page); |
113 | spin_lock(&hugetlb_lock); | 120 | spin_lock(&hugetlb_lock); |