aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/x86_64/mm.c
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2010-02-04 13:09:30 +0000
committerKeir Fraser <keir.fraser@citrix.com>2010-02-04 13:09:30 +0000
commit47f441d6b6a23f223edf27951189ea0828d121d0 (patch)
tree26132a9d4de7964452d7832ec34a508d4b39e199 /xen/arch/x86/x86_64/mm.c
parent8973872b3401a4948670008b28e77d597259877c (diff)
downloadxen-47f441d6b6a23f223edf27951189ea0828d121d0.tar.gz
xen-47f441d6b6a23f223edf27951189ea0828d121d0.tar.bz2
xen-47f441d6b6a23f223edf27951189ea0828d121d0.zip
mem hotplug: Fix an incorrect sanity check in memory add
Current, memory hot-add will fail if the new added memory is bigger than current max_pages. This is really a stupid checking, considering user may hot-add the biggest address riser card firstly. This patch fix this issue. It check if all new added memory is unpopulated, if yes, then it is ok. Signed-off-by: Jiang, Yunhong <yunhong.jiang@intel.com>
Diffstat (limited to 'xen/arch/x86/x86_64/mm.c')
-rw-r--r--xen/arch/x86/x86_64/mm.c30
1 files changed, 25 insertions, 5 deletions
diff --git a/xen/arch/x86/x86_64/mm.c b/xen/arch/x86/x86_64/mm.c
index 03b61cc34f..caccc0b1e5 100644
--- a/xen/arch/x86/x86_64/mm.c
+++ b/xen/arch/x86/x86_64/mm.c
@@ -1332,9 +1332,12 @@ int transfer_pages_to_heap(struct mem_hotadd_info *info)
int mem_hotadd_check(unsigned long spfn, unsigned long epfn)
{
- unsigned long s, e, length;
+ unsigned long s, e, length, sidx, eidx;
- if ( (spfn >= epfn) || (spfn < max_page) )
+ if ( (spfn >= epfn) )
+ return 0;
+
+ if (pfn_to_pdx(epfn) > (FRAMETABLE_SIZE / sizeof(*frame_table)))
return 0;
if ( (spfn | epfn) & ((1UL << PAGETABLE_ORDER) - 1) )
@@ -1343,6 +1346,20 @@ int mem_hotadd_check(unsigned long spfn, unsigned long epfn)
if ( (spfn | epfn) & pfn_hole_mask )
return 0;
+ /* Make sure the new range is not present now */
+ sidx = ((pfn_to_pdx(spfn) + PDX_GROUP_COUNT - 1) & ~(PDX_GROUP_COUNT - 1))
+ / PDX_GROUP_COUNT;
+ eidx = (pfn_to_pdx(epfn - 1) & ~(PDX_GROUP_COUNT - 1)) / PDX_GROUP_COUNT;
+ if (sidx >= eidx)
+ return 0;
+
+ s = find_next_zero_bit(pdx_group_valid, eidx, sidx);
+ if ( s > eidx )
+ return 0;
+ e = find_next_bit(pdx_group_valid, eidx, s);
+ if ( e < eidx )
+ return 0;
+
/* Caculate at most required m2p/compat m2p/frametable pages */
s = (spfn & ~((1UL << (L2_PAGETABLE_SHIFT - 3)) - 1));
e = (epfn + (1UL << (L2_PAGETABLE_SHIFT - 3)) - 1) &
@@ -1433,8 +1450,11 @@ int memory_add(unsigned long spfn, unsigned long epfn, unsigned int pxm)
goto destroy_frametable;
/* Set max_page as setup_m2p_table will use it*/
- max_page = epfn;
- max_pdx = pfn_to_pdx(max_page - 1) + 1;
+ if (max_page < epfn)
+ {
+ max_page = epfn;
+ max_pdx = pfn_to_pdx(max_page - 1) + 1;
+ }
total_pages += epfn - spfn;
set_pdx_range(spfn, epfn);
@@ -1443,7 +1463,7 @@ int memory_add(unsigned long spfn, unsigned long epfn, unsigned int pxm)
if ( ret )
goto destroy_m2p;
- for ( i = old_max; i < epfn; i++ )
+ for ( i = spfn; i < epfn; i++ )
if ( iommu_map_page(dom0, i, i) )
break;