| From stable-bounces@linux.kernel.org Wed May 9 02:36:13 2007 |
| Message-Id: <200705090933.l499X98T019451@shell0.pdx.osdl.net> |
| To: torvalds@linux-foundation.org |
| From: akpm@linux-foundation.org |
| Date: Wed, 09 May 2007 02:33:09 -0700 |
| Cc: dwg@au1.ibm.com, kenchen@google.com, mbligh@google.com, agl@us.ibm.com, akpm@linux-foundation.org, stable@kernel.org, david@gibson.dropbear.id.au |
| Subject: fix leaky resv_huge_pages when cpuset is in use |
| |
| From: "Ken Chen" <kenchen@google.com> |
| |
| The internal hugetlb resv_huge_pages variable can permanently leak nonzero |
| value in the error path of hugetlb page fault handler when hugetlb page is |
| used in combination of cpuset. The leaked count can permanently trap N |
| number of hugetlb pages in unusable "reserved" state. |
| |
| Steps to reproduce the bug: |
| |
| (1) create two cpuset, user1 and user2 |
| (2) reserve 50 htlb pages in cpuset user1 |
| (3) attempt to shmget/shmat 50 htlb page inside cpuset user2 |
| (4) kernel oom the user process in step 3 |
| (5) ipcrm the shm segment |
| |
| At this point resv_huge_pages will have a count of 49, even though |
| there are no active hugetlbfs file nor hugetlb shared memory segment |
| in the system. The leak is permanent and there is no recovery method |
| other than system reboot. The leaked count will hold up all future use |
| of that many htlb pages in all cpusets. |
| |
| The culprit is that the error path of alloc_huge_page() did not |
| properly undo the change it made to resv_huge_page, causing |
| inconsistent state. |
| |
| Signed-off-by: Ken Chen <kenchen@google.com> |
| Cc: David Gibson <david@gibson.dropbear.id.au> |
| Cc: Adam Litke <agl@us.ibm.com> |
| Cc: Martin Bligh <mbligh@google.com> |
| Acked-by: David Gibson <dwg@au1.ibm.com> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| Signed-off-by: Chris Wright <chrisw@sous-sol.org> |
| --- |
| |
| mm/hugetlb.c | 2 ++ |
| 1 file changed, 2 insertions(+) |
| |
| --- linux-2.6.21.1.orig/mm/hugetlb.c |
| +++ linux-2.6.21.1/mm/hugetlb.c |
| @@ -140,6 +140,8 @@ static struct page *alloc_huge_page(stru |
| return page; |
| |
| fail: |
| + if (vma->vm_flags & VM_MAYSHARE) |
| + resv_huge_pages++; |
| spin_unlock(&hugetlb_lock); |
| return NULL; |
| } |