diff options
author | Lee Schermerhorn <Lee.Schermerhorn@hp.com> | 2007-09-19 01:46:47 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-09-19 14:24:18 -0400 |
commit | 480eccf9ae1073b87bb4fe118971fbf134a5bc61 (patch) | |
tree | b66cd85cd6ad9dc7c141d34837a848111d036584 /mm/hugetlb.c | |
parent | 28f300d23674fa01ae747c66ce861d4ee6aebe8c (diff) |
Fix NUMA Memory Policy Reference Counting
This patch proposes fixes to the reference counting of memory policy in the
page allocation paths and in show_numa_map(). Extracted from my "Memory
Policy Cleanups and Enhancements" series as stand-alone.
Shared policy lookup [shmem] has always added a reference to the policy,
but this was never unrefed after page allocation or after formatting the
numa map data.
Default system policy should not require additional ref counting, nor
should the current task's task policy. However, show_numa_map() calls
get_vma_policy() to examine what may be [likely is] another task's policy.
The latter case needs protection against freeing of the policy.
This patch adds a reference count to a mempolicy returned by
get_vma_policy() when the policy is a vma policy or another task's
mempolicy. Again, shared policy is already reference counted on lookup. A
matching "unref" [__mpol_free()] is performed in alloc_page_vma() for
shared and vma policies, and in show_numa_map() for shared and another
task's mempolicy. We can call __mpol_free() directly, saving an admittedly
inexpensive inline NULL test, because we know we have a non-NULL policy.
Handling policy ref counts for hugepages is a bit trickier.
huge_zonelist() returns a zone list that might come from a shared or vma
'BIND policy. In this case, we should hold the reference until after the
huge page allocation in dequeue_hugepage(). The patch modifies
huge_zonelist() to return a pointer to the mempolicy if it needs to be
unref'd after allocation.
Kernel Build [16cpu, 32GB, ia64] - average of 10 runs:
w/o patch w/ refcount patch
Avg Std Devn Avg Std Devn
Real: 100.59 0.38 100.63 0.43
User: 1209.60 0.37 1209.91 0.31
System: 81.52 0.42 81.64 0.34
Signed-off-by: Lee Schermerhorn <lee.schermerhorn@hp.com>
Acked-by: Andi Kleen <ak@suse.de>
Cc: Christoph Lameter <clameter@sgi.com>
Acked-by: Mel Gorman <mel@csn.ul.ie>
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 | 4 |
1 files changed, 3 insertions, 1 deletions
diff --git a/mm/hugetlb.c b/mm/hugetlb.c index de4cf458d6e1..84c795ee2d65 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c | |||
@@ -71,8 +71,9 @@ static struct page *dequeue_huge_page(struct vm_area_struct *vma, | |||
71 | { | 71 | { |
72 | int nid; | 72 | int nid; |
73 | struct page *page = NULL; | 73 | struct page *page = NULL; |
74 | struct mempolicy *mpol; | ||
74 | struct zonelist *zonelist = huge_zonelist(vma, address, | 75 | struct zonelist *zonelist = huge_zonelist(vma, address, |
75 | htlb_alloc_mask); | 76 | htlb_alloc_mask, &mpol); |
76 | struct zone **z; | 77 | struct zone **z; |
77 | 78 | ||
78 | for (z = zonelist->zones; *z; z++) { | 79 | for (z = zonelist->zones; *z; z++) { |
@@ -87,6 +88,7 @@ static struct page *dequeue_huge_page(struct vm_area_struct *vma, | |||
87 | break; | 88 | break; |
88 | } | 89 | } |
89 | } | 90 | } |
91 | mpol_free(mpol); /* unref if mpol !NULL */ | ||
90 | return page; | 92 | return page; |
91 | } | 93 | } |
92 | 94 | ||