diff options
| author | Yinghai Lu <yinghai@kernel.org> | 2010-02-24 21:36:53 -0500 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2010-02-26 02:25:35 -0500 |
| commit | fb90ef93df654f2678933efbbf864adac0ae490e (patch) | |
| tree | c590e99bc70fbbfa0e1615a29734ca3c1f586729 | |
| parent | 2ee78f7b1d8ada2615ecbcd9fea70580008bd6ce (diff) | |
early_res: Add free_early_partial()
To free partial areas in pcpu_setup...
Reported-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Cc: Tejun Heo <tj@kernel.org>
Cc: Christoph Lameter <cl@linux-foundation.org>
Cc: Stephen Rothwell <sfr@canb.auug.org.au>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Jesse Barnes <jbarnes@virtuousgeek.org>
Cc: Pekka Enberg <penberg@cs.helsinki.fi>
LKML-Reference: <4B85E245.5030001@kernel.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
| -rw-r--r-- | arch/x86/kernel/setup_percpu.c | 6 | ||||
| -rw-r--r-- | include/linux/early_res.h | 1 | ||||
| -rw-r--r-- | kernel/early_res.c | 55 | ||||
| -rw-r--r-- | mm/percpu.c | 3 |
4 files changed, 62 insertions, 3 deletions
diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c index 35abcb8b00e9..ef6370b00e70 100644 --- a/arch/x86/kernel/setup_percpu.c +++ b/arch/x86/kernel/setup_percpu.c | |||
| @@ -137,7 +137,13 @@ static void * __init pcpu_fc_alloc(unsigned int cpu, size_t size, size_t align) | |||
| 137 | 137 | ||
| 138 | static void __init pcpu_fc_free(void *ptr, size_t size) | 138 | static void __init pcpu_fc_free(void *ptr, size_t size) |
| 139 | { | 139 | { |
| 140 | #ifdef CONFIG_NO_BOOTMEM | ||
| 141 | u64 start = __pa(ptr); | ||
| 142 | u64 end = start + size; | ||
| 143 | free_early_partial(start, end); | ||
| 144 | #else | ||
| 140 | free_bootmem(__pa(ptr), size); | 145 | free_bootmem(__pa(ptr), size); |
| 146 | #endif | ||
| 141 | } | 147 | } |
| 142 | 148 | ||
| 143 | static int __init pcpu_cpu_distance(unsigned int from, unsigned int to) | 149 | static int __init pcpu_cpu_distance(unsigned int from, unsigned int to) |
diff --git a/include/linux/early_res.h b/include/linux/early_res.h index 50f7663bb8b1..29c09f57a13c 100644 --- a/include/linux/early_res.h +++ b/include/linux/early_res.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | extern void reserve_early(u64 start, u64 end, char *name); | 5 | extern void reserve_early(u64 start, u64 end, char *name); |
| 6 | extern void reserve_early_overlap_ok(u64 start, u64 end, char *name); | 6 | extern void reserve_early_overlap_ok(u64 start, u64 end, char *name); |
| 7 | extern void free_early(u64 start, u64 end); | 7 | extern void free_early(u64 start, u64 end); |
| 8 | void free_early_partial(u64 start, u64 end); | ||
| 8 | extern void early_res_to_bootmem(u64 start, u64 end); | 9 | extern void early_res_to_bootmem(u64 start, u64 end); |
| 9 | 10 | ||
| 10 | void reserve_early_without_check(u64 start, u64 end, char *name); | 11 | void reserve_early_without_check(u64 start, u64 end, char *name); |
diff --git a/kernel/early_res.c b/kernel/early_res.c index aa5494ac4462..9ab11cd84853 100644 --- a/kernel/early_res.c +++ b/kernel/early_res.c | |||
| @@ -61,6 +61,40 @@ static void __init drop_range(int i) | |||
| 61 | early_res_count--; | 61 | early_res_count--; |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | static void __init drop_range_partial(int i, u64 start, u64 end) | ||
| 65 | { | ||
| 66 | u64 common_start, common_end; | ||
| 67 | u64 old_start, old_end; | ||
| 68 | |||
| 69 | old_start = early_res[i].start; | ||
| 70 | old_end = early_res[i].end; | ||
| 71 | common_start = max(old_start, start); | ||
| 72 | common_end = min(old_end, end); | ||
| 73 | |||
| 74 | /* no overlap ? */ | ||
| 75 | if (common_start >= common_end) | ||
| 76 | return; | ||
| 77 | |||
| 78 | if (old_start < common_start) { | ||
| 79 | /* make head segment */ | ||
| 80 | early_res[i].end = common_start; | ||
| 81 | if (old_end > common_end) { | ||
| 82 | /* add another for left over on tail */ | ||
| 83 | reserve_early_without_check(common_end, old_end, | ||
| 84 | early_res[i].name); | ||
| 85 | } | ||
| 86 | return; | ||
| 87 | } else { | ||
| 88 | if (old_end > common_end) { | ||
| 89 | /* reuse the entry for tail left */ | ||
| 90 | early_res[i].start = common_end; | ||
| 91 | return; | ||
| 92 | } | ||
| 93 | /* all covered */ | ||
| 94 | drop_range(i); | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 64 | /* | 98 | /* |
| 65 | * Split any existing ranges that: | 99 | * Split any existing ranges that: |
| 66 | * 1) are marked 'overlap_ok', and | 100 | * 1) are marked 'overlap_ok', and |
| @@ -284,6 +318,27 @@ void __init free_early(u64 start, u64 end) | |||
| 284 | drop_range(i); | 318 | drop_range(i); |
| 285 | } | 319 | } |
| 286 | 320 | ||
| 321 | void __init free_early_partial(u64 start, u64 end) | ||
| 322 | { | ||
| 323 | struct early_res *r; | ||
| 324 | int i; | ||
| 325 | |||
| 326 | try_next: | ||
| 327 | i = find_overlapped_early(start, end); | ||
| 328 | if (i >= max_early_res) | ||
| 329 | return; | ||
| 330 | |||
| 331 | r = &early_res[i]; | ||
| 332 | /* hole ? */ | ||
| 333 | if (r->end >= end && r->start <= start) { | ||
| 334 | drop_range_partial(i, start, end); | ||
| 335 | return; | ||
| 336 | } | ||
| 337 | |||
| 338 | drop_range_partial(i, start, end); | ||
| 339 | goto try_next; | ||
| 340 | } | ||
| 341 | |||
| 287 | #ifdef CONFIG_NO_BOOTMEM | 342 | #ifdef CONFIG_NO_BOOTMEM |
| 288 | static void __init subtract_early_res(struct range *range, int az) | 343 | static void __init subtract_early_res(struct range *range, int az) |
| 289 | { | 344 | { |
diff --git a/mm/percpu.c b/mm/percpu.c index 841defeeef86..083e7c91e5f6 100644 --- a/mm/percpu.c +++ b/mm/percpu.c | |||
| @@ -1929,10 +1929,7 @@ int __init pcpu_embed_first_chunk(size_t reserved_size, ssize_t dyn_size, | |||
| 1929 | } | 1929 | } |
| 1930 | /* copy and return the unused part */ | 1930 | /* copy and return the unused part */ |
| 1931 | memcpy(ptr, __per_cpu_load, ai->static_size); | 1931 | memcpy(ptr, __per_cpu_load, ai->static_size); |
| 1932 | #ifndef CONFIG_NO_BOOTMEM | ||
| 1933 | /* fix partial free ! */ | ||
| 1934 | free_fn(ptr + size_sum, ai->unit_size - size_sum); | 1932 | free_fn(ptr + size_sum, ai->unit_size - size_sum); |
| 1935 | #endif | ||
| 1936 | } | 1933 | } |
| 1937 | } | 1934 | } |
| 1938 | 1935 | ||
