aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNick Piggin <npiggin@suse.de>2006-03-22 03:08:08 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-03-22 10:53:58 -0500
commita482289d46587ffcda4c85aab109fb74910d7a48 (patch)
tree351dc5d9c09a4fe3d122c2157a298852ac8a821c
parent545b1ea9bfa5a8ca9af33d63144bd4f2faaea8dd (diff)
[PATCH] hugepage allocator cleanup
Insert "fresh" huge pages into the hugepage allocator by the same means as they are freed back into it. This reduces code size and allows enqueue_huge_page to be inlined into the hugepage free fastpath. Eliminate occurances of hugepages on the free list with non-zero refcount. This can allow stricter refcount checks in future. Also required for lockless pagecache. Signed-off-by: Nick Piggin <npiggin@suse.de> "This patch also eliminates a leak "cleaned up" by re-clobbering the refcount on every allocation from the hugepage freelists. With respect to the lockless pagecache, the crucial aspect is to eliminate unconditional set_page_count() to 0 on pages with potentially nonzero refcounts, though closer inspection suggests the assignments removed are entirely spurious." Acked-by: William Irwin <wli@holomorphy.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--mm/hugetlb.c24
1 files changed, 8 insertions, 16 deletions
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 508707704d2c..39d49ecea8e8 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -64,7 +64,7 @@ static struct page *dequeue_huge_page(struct vm_area_struct *vma,
64 return page; 64 return page;
65} 65}
66 66
67static struct page *alloc_fresh_huge_page(void) 67static int alloc_fresh_huge_page(void)
68{ 68{
69 static int nid = 0; 69 static int nid = 0;
70 struct page *page; 70 struct page *page;
@@ -72,12 +72,15 @@ static struct page *alloc_fresh_huge_page(void)
72 HUGETLB_PAGE_ORDER); 72 HUGETLB_PAGE_ORDER);
73 nid = (nid + 1) % num_online_nodes(); 73 nid = (nid + 1) % num_online_nodes();
74 if (page) { 74 if (page) {
75 page[1].lru.next = (void *)free_huge_page; /* dtor */
75 spin_lock(&hugetlb_lock); 76 spin_lock(&hugetlb_lock);
76 nr_huge_pages++; 77 nr_huge_pages++;
77 nr_huge_pages_node[page_to_nid(page)]++; 78 nr_huge_pages_node[page_to_nid(page)]++;
78 spin_unlock(&hugetlb_lock); 79 spin_unlock(&hugetlb_lock);
80 put_page(page); /* free it into the hugepage allocator */
81 return 1;
79 } 82 }
80 return page; 83 return 0;
81} 84}
82 85
83void free_huge_page(struct page *page) 86void free_huge_page(struct page *page)
@@ -85,7 +88,6 @@ void free_huge_page(struct page *page)
85 BUG_ON(page_count(page)); 88 BUG_ON(page_count(page));
86 89
87 INIT_LIST_HEAD(&page->lru); 90 INIT_LIST_HEAD(&page->lru);
88 page[1].lru.next = NULL; /* reset dtor */
89 91
90 spin_lock(&hugetlb_lock); 92 spin_lock(&hugetlb_lock);
91 enqueue_huge_page(page); 93 enqueue_huge_page(page);
@@ -105,7 +107,6 @@ struct page *alloc_huge_page(struct vm_area_struct *vma, unsigned long addr)
105 } 107 }
106 spin_unlock(&hugetlb_lock); 108 spin_unlock(&hugetlb_lock);
107 set_page_count(page, 1); 109 set_page_count(page, 1);
108 page[1].lru.next = (void *)free_huge_page; /* set dtor */
109 for (i = 0; i < (HPAGE_SIZE/PAGE_SIZE); ++i) 110 for (i = 0; i < (HPAGE_SIZE/PAGE_SIZE); ++i)
110 clear_user_highpage(&page[i], addr); 111 clear_user_highpage(&page[i], addr);
111 return page; 112 return page;
@@ -114,7 +115,6 @@ struct page *alloc_huge_page(struct vm_area_struct *vma, unsigned long addr)
114static int __init hugetlb_init(void) 115static int __init hugetlb_init(void)
115{ 116{
116 unsigned long i; 117 unsigned long i;
117 struct page *page;
118 118
119 if (HPAGE_SHIFT == 0) 119 if (HPAGE_SHIFT == 0)
120 return 0; 120 return 0;
@@ -123,12 +123,8 @@ static int __init hugetlb_init(void)
123 INIT_LIST_HEAD(&hugepage_freelists[i]); 123 INIT_LIST_HEAD(&hugepage_freelists[i]);
124 124
125 for (i = 0; i < max_huge_pages; ++i) { 125 for (i = 0; i < max_huge_pages; ++i) {
126 page = alloc_fresh_huge_page(); 126 if (!alloc_fresh_huge_page())
127 if (!page)
128 break; 127 break;
129 spin_lock(&hugetlb_lock);
130 enqueue_huge_page(page);
131 spin_unlock(&hugetlb_lock);
132 } 128 }
133 max_huge_pages = free_huge_pages = nr_huge_pages = i; 129 max_huge_pages = free_huge_pages = nr_huge_pages = i;
134 printk("Total HugeTLB memory allocated, %ld\n", free_huge_pages); 130 printk("Total HugeTLB memory allocated, %ld\n", free_huge_pages);
@@ -154,8 +150,8 @@ static void update_and_free_page(struct page *page)
154 page[i].flags &= ~(1 << PG_locked | 1 << PG_error | 1 << PG_referenced | 150 page[i].flags &= ~(1 << PG_locked | 1 << PG_error | 1 << PG_referenced |
155 1 << PG_dirty | 1 << PG_active | 1 << PG_reserved | 151 1 << PG_dirty | 1 << PG_active | 1 << PG_reserved |
156 1 << PG_private | 1<< PG_writeback); 152 1 << PG_private | 1<< PG_writeback);
157 set_page_count(&page[i], 0);
158 } 153 }
154 page[1].lru.next = NULL;
159 set_page_count(page, 1); 155 set_page_count(page, 1);
160 __free_pages(page, HUGETLB_PAGE_ORDER); 156 __free_pages(page, HUGETLB_PAGE_ORDER);
161} 157}
@@ -188,12 +184,8 @@ static inline void try_to_free_low(unsigned long count)
188static unsigned long set_max_huge_pages(unsigned long count) 184static unsigned long set_max_huge_pages(unsigned long count)
189{ 185{
190 while (count > nr_huge_pages) { 186 while (count > nr_huge_pages) {
191 struct page *page = alloc_fresh_huge_page(); 187 if (!alloc_fresh_huge_page())
192 if (!page)
193 return nr_huge_pages; 188 return nr_huge_pages;
194 spin_lock(&hugetlb_lock);
195 enqueue_huge_page(page);
196 spin_unlock(&hugetlb_lock);
197 } 189 }
198 if (count >= nr_huge_pages) 190 if (count >= nr_huge_pages)
199 return nr_huge_pages; 191 return nr_huge_pages;