aboutsummaryrefslogtreecommitdiffstats
path: root/mm/bootmem.c
diff options
context:
space:
mode:
authorYinghai Lu <yhlu.kernel@gmail.com>2008-03-18 15:49:12 -0400
committerIngo Molnar <mingo@elte.hu>2008-04-26 16:51:08 -0400
commita5645a61b3b7e7d7de15e1a642ead600150ce94d (patch)
tree76fad06bc64a00b71821a9df63c474ea5341eab2 /mm/bootmem.c
parent9a2dc04cf070ee98e014a172695782ff42015fc4 (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/bootmem.c')
-rw-r--r--mm/bootmem.c92
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 */
114static int __init reserve_bootmem_core(bootmem_data_t *bdata, 114static 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
150static 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
146err:
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
154static void __init free_bootmem_core(bootmem_data_t *bdata, unsigned long addr, 184static 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,
415void __init reserve_bootmem_node(pg_data_t *pgdat, unsigned long physaddr, 445void __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)
440int __init reserve_bootmem(unsigned long addr, unsigned long size, 475int __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