aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/mm
diff options
context:
space:
mode:
authorJohn Dykstra <jdykstra@cray.com>2012-05-25 17:12:46 -0400
committerIngo Molnar <mingo@kernel.org>2012-05-30 04:57:11 -0400
commitfa83523f45fbb403eba4ebc5704bf98aa4da0163 (patch)
tree35466e5e2e9e5ed8171ef596d63690ed42621fca /arch/x86/mm
parent1b38a3a10f2ad96a3c0130f63b7f3610bab7090d (diff)
x86/mm/pat: Improve scaling of pat_pagerange_is_ram()
Function pat_pagerange_is_ram() scales poorly to large address ranges, because it probes the resource tree for each page. On a 2.6 GHz Opteron, this function consumes 34 ms for a 1 GB range. It is called twice during untrack_pfn_vma(), slowing process cleanup and handicapping the OOM killer. This replacement consumes less than 1ms, under the same conditions. Signed-off-by: John Dykstra <jdykstra@cray.com> on behalf of Cray Inc. Acked-by: Suresh Siddha <suresh.b.siddha@intel.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1337980366.1979.6.camel@redwood [ Small stylistic cleanups and renames ] Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch/x86/mm')
-rw-r--r--arch/x86/mm/pat.c56
1 files changed, 36 insertions, 20 deletions
diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c
index f6ff57b7efa5..bea6e573e02b 100644
--- a/arch/x86/mm/pat.c
+++ b/arch/x86/mm/pat.c
@@ -158,31 +158,47 @@ static unsigned long pat_x_mtrr_type(u64 start, u64 end, unsigned long req_type)
158 return req_type; 158 return req_type;
159} 159}
160 160
161struct pagerange_state {
162 unsigned long cur_pfn;
163 int ram;
164 int not_ram;
165};
166
167static int
168pagerange_is_ram_callback(unsigned long initial_pfn, unsigned long total_nr_pages, void *arg)
169{
170 struct pagerange_state *state = arg;
171
172 state->not_ram |= initial_pfn > state->cur_pfn;
173 state->ram |= total_nr_pages > 0;
174 state->cur_pfn = initial_pfn + total_nr_pages;
175
176 return state->ram && state->not_ram;
177}
178
161static int pat_pagerange_is_ram(resource_size_t start, resource_size_t end) 179static int pat_pagerange_is_ram(resource_size_t start, resource_size_t end)
162{ 180{
163 int ram_page = 0, not_rampage = 0; 181 int ret = 0;
164 unsigned long page_nr; 182 unsigned long start_pfn = start >> PAGE_SHIFT;
183 unsigned long end_pfn = (end + PAGE_SIZE - 1) >> PAGE_SHIFT;
184 struct pagerange_state state = {start_pfn, 0, 0};
165 185
166 for (page_nr = (start >> PAGE_SHIFT); page_nr < (end >> PAGE_SHIFT); 186 /*
167 ++page_nr) { 187 * For legacy reasons, physical address range in the legacy ISA
168 /* 188 * region is tracked as non-RAM. This will allow users of
169 * For legacy reasons, physical address range in the legacy ISA 189 * /dev/mem to map portions of legacy ISA region, even when
170 * region is tracked as non-RAM. This will allow users of 190 * some of those portions are listed(or not even listed) with
171 * /dev/mem to map portions of legacy ISA region, even when 191 * different e820 types(RAM/reserved/..)
172 * some of those portions are listed(or not even listed) with 192 */
173 * different e820 types(RAM/reserved/..) 193 if (start_pfn < ISA_END_ADDRESS >> PAGE_SHIFT)
174 */ 194 start_pfn = ISA_END_ADDRESS >> PAGE_SHIFT;
175 if (page_nr >= (ISA_END_ADDRESS >> PAGE_SHIFT) && 195
176 page_is_ram(page_nr)) 196 if (start_pfn < end_pfn) {
177 ram_page = 1; 197 ret = walk_system_ram_range(start_pfn, end_pfn - start_pfn,
178 else 198 &state, pagerange_is_ram_callback);
179 not_rampage = 1;
180
181 if (ram_page == not_rampage)
182 return -1;
183 } 199 }
184 200
185 return ram_page; 201 return (ret > 0) ? -1 : (state.ram ? 1 : 0);
186} 202}
187 203
188/* 204/*