diff options
author | Yinghai Lu <yhlu.kernel@gmail.com> | 2008-03-18 15:49:12 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-04-26 16:51:08 -0400 |
commit | a5645a61b3b7e7d7de15e1a642ead600150ce94d (patch) | |
tree | 76fad06bc64a00b71821a9df63c474ea5341eab2 /mm | |
parent | 9a2dc04cf070ee98e014a172695782ff42015fc4 (diff) |
mm: allow reserve_bootmem() cross nodes
split reserve_bootmem_core() into two functions, one which checks
conflicts, and one which sets the bits.
and make reserve_bootmem to loop bdata_list to cross the nodes.
user could be crashkernel and ramdisk..., in case the range provided
by those externalities crosses the nodes.
Signed-off-by: Yinghai Lu <yhlu.kernel@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'mm')
-rw-r--r-- | mm/bootmem.c | 92 |
1 files changed, 69 insertions, 23 deletions
diff --git a/mm/bootmem.c b/mm/bootmem.c index 0f30bc873ecc..b6791646143e 100644 --- a/mm/bootmem.c +++ b/mm/bootmem.c | |||
@@ -111,44 +111,74 @@ static unsigned long __init init_bootmem_core(pg_data_t *pgdat, | |||
111 | * might be used for boot-time allocations - or it might get added | 111 | * might be used for boot-time allocations - or it might get added |
112 | * to the free page pool later on. | 112 | * to the free page pool later on. |
113 | */ | 113 | */ |
114 | static int __init reserve_bootmem_core(bootmem_data_t *bdata, | 114 | static int __init can_reserve_bootmem_core(bootmem_data_t *bdata, |
115 | unsigned long addr, unsigned long size, int flags) | 115 | unsigned long addr, unsigned long size, int flags) |
116 | { | 116 | { |
117 | unsigned long sidx, eidx; | 117 | unsigned long sidx, eidx; |
118 | unsigned long i; | 118 | unsigned long i; |
119 | int ret; | 119 | |
120 | BUG_ON(!size); | ||
121 | |||
122 | /* out of range, don't hold other */ | ||
123 | if (addr + size < bdata->node_boot_start || | ||
124 | PFN_DOWN(addr) > bdata->node_low_pfn) | ||
125 | return 0; | ||
120 | 126 | ||
121 | /* | 127 | /* |
122 | * round up, partially reserved pages are considered | 128 | * Round up to index to the range. |
123 | * fully reserved. | ||
124 | */ | 129 | */ |
130 | if (addr > bdata->node_boot_start) | ||
131 | sidx= PFN_DOWN(addr - bdata->node_boot_start); | ||
132 | else | ||
133 | sidx = 0; | ||
134 | |||
135 | eidx = PFN_UP(addr + size - bdata->node_boot_start); | ||
136 | if (eidx > bdata->node_low_pfn - PFN_DOWN(bdata->node_boot_start)) | ||
137 | eidx = bdata->node_low_pfn - PFN_DOWN(bdata->node_boot_start); | ||
138 | |||
139 | for (i = sidx; i < eidx; i++) { | ||
140 | if (test_bit(i, bdata->node_bootmem_map)) { | ||
141 | if (flags & BOOTMEM_EXCLUSIVE) | ||
142 | return -EBUSY; | ||
143 | } | ||
144 | } | ||
145 | |||
146 | return 0; | ||
147 | |||
148 | } | ||
149 | |||
150 | static void __init reserve_bootmem_core(bootmem_data_t *bdata, | ||
151 | unsigned long addr, unsigned long size, int flags) | ||
152 | { | ||
153 | unsigned long sidx, eidx; | ||
154 | unsigned long i; | ||
155 | |||
125 | BUG_ON(!size); | 156 | BUG_ON(!size); |
126 | BUG_ON(PFN_DOWN(addr) >= bdata->node_low_pfn); | ||
127 | BUG_ON(PFN_UP(addr + size) > bdata->node_low_pfn); | ||
128 | BUG_ON(addr < bdata->node_boot_start); | ||
129 | 157 | ||
130 | sidx = PFN_DOWN(addr - bdata->node_boot_start); | 158 | /* out of range */ |
159 | if (addr + size < bdata->node_boot_start || | ||
160 | PFN_DOWN(addr) > bdata->node_low_pfn) | ||
161 | return; | ||
162 | |||
163 | /* | ||
164 | * Round up to index to the range. | ||
165 | */ | ||
166 | if (addr > bdata->node_boot_start) | ||
167 | sidx= PFN_DOWN(addr - bdata->node_boot_start); | ||
168 | else | ||
169 | sidx = 0; | ||
170 | |||
131 | eidx = PFN_UP(addr + size - bdata->node_boot_start); | 171 | eidx = PFN_UP(addr + size - bdata->node_boot_start); |
172 | if (eidx > bdata->node_low_pfn - PFN_DOWN(bdata->node_boot_start)) | ||
173 | eidx = bdata->node_low_pfn - PFN_DOWN(bdata->node_boot_start); | ||
132 | 174 | ||
133 | for (i = sidx; i < eidx; i++) | 175 | for (i = sidx; i < eidx; i++) { |
134 | if (test_and_set_bit(i, bdata->node_bootmem_map)) { | 176 | if (test_and_set_bit(i, bdata->node_bootmem_map)) { |
135 | #ifdef CONFIG_DEBUG_BOOTMEM | 177 | #ifdef CONFIG_DEBUG_BOOTMEM |
136 | printk("hm, page %08lx reserved twice.\n", i*PAGE_SIZE); | 178 | printk("hm, page %08lx reserved twice.\n", i*PAGE_SIZE); |
137 | #endif | 179 | #endif |
138 | if (flags & BOOTMEM_EXCLUSIVE) { | ||
139 | ret = -EBUSY; | ||
140 | goto err; | ||
141 | } | ||
142 | } | 180 | } |
143 | 181 | } | |
144 | return 0; | ||
145 | |||
146 | err: | ||
147 | /* unreserve memory we accidentally reserved */ | ||
148 | for (i--; i >= sidx; i--) | ||
149 | clear_bit(i, bdata->node_bootmem_map); | ||
150 | |||
151 | return ret; | ||
152 | } | 182 | } |
153 | 183 | ||
154 | static void __init free_bootmem_core(bootmem_data_t *bdata, unsigned long addr, | 184 | static void __init free_bootmem_core(bootmem_data_t *bdata, unsigned long addr, |
@@ -415,6 +445,11 @@ unsigned long __init init_bootmem_node(pg_data_t *pgdat, unsigned long freepfn, | |||
415 | void __init reserve_bootmem_node(pg_data_t *pgdat, unsigned long physaddr, | 445 | void __init reserve_bootmem_node(pg_data_t *pgdat, unsigned long physaddr, |
416 | unsigned long size, int flags) | 446 | unsigned long size, int flags) |
417 | { | 447 | { |
448 | int ret; | ||
449 | |||
450 | ret = can_reserve_bootmem_core(pgdat->bdata, physaddr, size, flags); | ||
451 | if (ret < 0) | ||
452 | return; | ||
418 | reserve_bootmem_core(pgdat->bdata, physaddr, size, flags); | 453 | reserve_bootmem_core(pgdat->bdata, physaddr, size, flags); |
419 | } | 454 | } |
420 | 455 | ||
@@ -440,7 +475,18 @@ unsigned long __init init_bootmem(unsigned long start, unsigned long pages) | |||
440 | int __init reserve_bootmem(unsigned long addr, unsigned long size, | 475 | int __init reserve_bootmem(unsigned long addr, unsigned long size, |
441 | int flags) | 476 | int flags) |
442 | { | 477 | { |
443 | return reserve_bootmem_core(NODE_DATA(0)->bdata, addr, size, flags); | 478 | bootmem_data_t *bdata; |
479 | int ret; | ||
480 | |||
481 | list_for_each_entry(bdata, &bdata_list, list) { | ||
482 | ret = can_reserve_bootmem_core(bdata, addr, size, flags); | ||
483 | if (ret < 0) | ||
484 | return ret; | ||
485 | } | ||
486 | list_for_each_entry(bdata, &bdata_list, list) | ||
487 | reserve_bootmem_core(bdata, addr, size, flags); | ||
488 | |||
489 | return 0; | ||
444 | } | 490 | } |
445 | #endif /* !CONFIG_HAVE_ARCH_BOOTMEM_NODE */ | 491 | #endif /* !CONFIG_HAVE_ARCH_BOOTMEM_NODE */ |
446 | 492 | ||