summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKen Chen <kenchen@google.com>2007-05-09 02:33:09 -0700
committerChris Wright <chrisw@sous-sol.org>2007-05-23 14:32:48 -0700
commit8e4a8227450fb3327c244642fca616daa6ca7879 (patch)
treeb5aa9419d8032eb99b01083e428ab3ddedfc3e81
parent76359ee291685b2fe4f88ed0a763e00bee9c3dea (diff)
[PATCH] fix leaky resv_huge_pages when cpuset is in use
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>
-rw-r--r--mm/hugetlb.c2
1 files changed, 2 insertions, 0 deletions
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 36db012b38dd..88e708be1f64 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -140,6 +140,8 @@ static struct page *alloc_huge_page(struct vm_area_struct *vma,
return page;
fail:
+ if (vma->vm_flags & VM_MAYSHARE)
+ resv_huge_pages++;
spin_unlock(&hugetlb_lock);
return NULL;
}