xen: switch extra memory accounting to use pfns
authorJuergen Gross <jgross@suse.com>
Fri, 4 Sep 2015 12:05:51 +0000 (14:05 +0200)
committerDavid Vrabel <david.vrabel@citrix.com>
Tue, 8 Sep 2015 15:28:06 +0000 (16:28 +0100)
Instead of using physical addresses for accounting of extra memory
areas available for ballooning switch to pfns as this is much less
error prone regarding partial pages.

Reported-by: Roger Pau Monné <roger.pau@citrix.com>
Tested-by: Roger Pau Monné <roger.pau@citrix.com>
Signed-off-by: Juergen Gross <jgross@suse.com>
Signed-off-by: David Vrabel <david.vrabel@citrix.com>
arch/x86/xen/setup.c
drivers/xen/balloon.c
include/xen/page.h

index 70de4c8b8f271dbfeeb9f593455b08d2550f6e16..f5ef6746d47a0ee36f6b0a11edd0c49cbcf3590a 100644 (file)
@@ -90,62 +90,69 @@ static void __init xen_parse_512gb(void)
        xen_512gb_limit = val;
 }
 
-static void __init xen_add_extra_mem(phys_addr_t start, phys_addr_t size)
+static void __init xen_add_extra_mem(unsigned long start_pfn,
+                                    unsigned long n_pfns)
 {
        int i;
 
+       /*
+        * No need to check for zero size, should happen rarely and will only
+        * write a new entry regarded to be unused due to zero size.
+        */
        for (i = 0; i < XEN_EXTRA_MEM_MAX_REGIONS; i++) {
                /* Add new region. */
-               if (xen_extra_mem[i].size == 0) {
-                       xen_extra_mem[i].start = start;
-                       xen_extra_mem[i].size  = size;
+               if (xen_extra_mem[i].n_pfns == 0) {
+                       xen_extra_mem[i].start_pfn = start_pfn;
+                       xen_extra_mem[i].n_pfns = n_pfns;
                        break;
                }
                /* Append to existing region. */
-               if (xen_extra_mem[i].start + xen_extra_mem[i].size == start) {
-                       xen_extra_mem[i].size += size;
+               if (xen_extra_mem[i].start_pfn + xen_extra_mem[i].n_pfns ==
+                   start_pfn) {
+                       xen_extra_mem[i].n_pfns += n_pfns;
                        break;
                }
        }
        if (i == XEN_EXTRA_MEM_MAX_REGIONS)
                printk(KERN_WARNING "Warning: not enough extra memory regions\n");
 
-       memblock_reserve(start, size);
+       memblock_reserve(PFN_PHYS(start_pfn), PFN_PHYS(n_pfns));
 }
 
-static void __init xen_del_extra_mem(phys_addr_t start, phys_addr_t size)
+static void __init xen_del_extra_mem(unsigned long start_pfn,
+                                    unsigned long n_pfns)
 {
        int i;
-       phys_addr_t start_r, size_r;
+       unsigned long start_r, size_r;
 
        for (i = 0; i < XEN_EXTRA_MEM_MAX_REGIONS; i++) {
-               start_r = xen_extra_mem[i].start;
-               size_r = xen_extra_mem[i].size;
+               start_r = xen_extra_mem[i].start_pfn;
+               size_r = xen_extra_mem[i].n_pfns;
 
                /* Start of region. */
-               if (start_r == start) {
-                       BUG_ON(size > size_r);
-                       xen_extra_mem[i].start += size;
-                       xen_extra_mem[i].size -= size;
+               if (start_r == start_pfn) {
+                       BUG_ON(n_pfns > size_r);
+                       xen_extra_mem[i].start_pfn += n_pfns;
+                       xen_extra_mem[i].n_pfns -= n_pfns;
                        break;
                }
                /* End of region. */
-               if (start_r + size_r == start + size) {
-                       BUG_ON(size > size_r);
-                       xen_extra_mem[i].size -= size;
+               if (start_r + size_r == start_pfn + n_pfns) {
+                       BUG_ON(n_pfns > size_r);
+                       xen_extra_mem[i].n_pfns -= n_pfns;
                        break;
                }
                /* Mid of region. */
-               if (start > start_r && start < start_r + size_r) {
-                       BUG_ON(start + size > start_r + size_r);
-                       xen_extra_mem[i].size = start - start_r;
+               if (start_pfn > start_r && start_pfn < start_r + size_r) {
+                       BUG_ON(start_pfn + n_pfns > start_r + size_r);
+                       xen_extra_mem[i].n_pfns = start_pfn - start_r;
                        /* Calling memblock_reserve() again is okay. */
-                       xen_add_extra_mem(start + size, start_r + size_r -
-                                         (start + size));
+                       xen_add_extra_mem(start_pfn + n_pfns, start_r + size_r -
+                                         (start_pfn + n_pfns));
                        break;
                }
        }
-       memblock_free(start, size);
+       memblock_free(PFN_PHYS(start_pfn), PFN_PHYS(n_pfns));
 }
 
 /*
@@ -156,11 +163,10 @@ static void __init xen_del_extra_mem(phys_addr_t start, phys_addr_t size)
 unsigned long __ref xen_chk_extra_mem(unsigned long pfn)
 {
        int i;
-       phys_addr_t addr = PFN_PHYS(pfn);
 
        for (i = 0; i < XEN_EXTRA_MEM_MAX_REGIONS; i++) {
-               if (addr >= xen_extra_mem[i].start &&
-                   addr < xen_extra_mem[i].start + xen_extra_mem[i].size)
+               if (pfn >= xen_extra_mem[i].start_pfn &&
+                   pfn < xen_extra_mem[i].start_pfn + xen_extra_mem[i].n_pfns)
                        return INVALID_P2M_ENTRY;
        }
 
@@ -176,10 +182,10 @@ void __init xen_inv_extra_mem(void)
        int i;
 
        for (i = 0; i < XEN_EXTRA_MEM_MAX_REGIONS; i++) {
-               if (!xen_extra_mem[i].size)
+               if (!xen_extra_mem[i].n_pfns)
                        continue;
-               pfn_s = PFN_DOWN(xen_extra_mem[i].start);
-               pfn_e = PFN_UP(xen_extra_mem[i].start + xen_extra_mem[i].size);
+               pfn_s = xen_extra_mem[i].start_pfn;
+               pfn_e = pfn_s + xen_extra_mem[i].n_pfns;
                for (pfn = pfn_s; pfn < pfn_e; pfn++)
                        set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
        }
@@ -507,7 +513,7 @@ void __init xen_remap_memory(void)
                } else if (pfn_s + len == xen_remap_buf.target_pfn) {
                        len += xen_remap_buf.size;
                } else {
-                       xen_del_extra_mem(PFN_PHYS(pfn_s), PFN_PHYS(len));
+                       xen_del_extra_mem(pfn_s, len);
                        pfn_s = xen_remap_buf.target_pfn;
                        len = xen_remap_buf.size;
                }
@@ -517,7 +523,7 @@ void __init xen_remap_memory(void)
        }
 
        if (pfn_s != ~0UL && len)
-               xen_del_extra_mem(PFN_PHYS(pfn_s), PFN_PHYS(len));
+               xen_del_extra_mem(pfn_s, len);
 
        set_pte_mfn(buf, mfn_save, PAGE_KERNEL);
 
@@ -744,7 +750,7 @@ static void __init xen_reserve_xen_mfnlist(void)
  **/
 char * __init xen_memory_setup(void)
 {
-       unsigned long max_pfn;
+       unsigned long max_pfn, pfn_s, n_pfns;
        phys_addr_t mem_end, addr, size, chunk_size;
        u32 type;
        int rc;
@@ -831,9 +837,11 @@ char * __init xen_memory_setup(void)
                                chunk_size = min(size, mem_end - addr);
                        } else if (extra_pages) {
                                chunk_size = min(size, PFN_PHYS(extra_pages));
-                               extra_pages -= PFN_DOWN(chunk_size);
-                               xen_add_extra_mem(addr, chunk_size);
-                               xen_max_p2m_pfn = PFN_DOWN(addr + chunk_size);
+                               pfn_s = PFN_UP(addr);
+                               n_pfns = PFN_DOWN(addr + chunk_size) - pfn_s;
+                               extra_pages -= n_pfns;
+                               xen_add_extra_mem(pfn_s, n_pfns);
+                               xen_max_p2m_pfn = pfn_s + n_pfns;
                        } else
                                type = E820_UNUSABLE;
                }
index bf4a23c7c5918f6849e764a8376c3608cc591933..1fa633b2d556e6a33a86779fb5d711e19f13839c 100644 (file)
@@ -638,9 +638,9 @@ static int __init balloon_init(void)
         * regions (see arch/x86/xen/setup.c).
         */
        for (i = 0; i < XEN_EXTRA_MEM_MAX_REGIONS; i++)
-               if (xen_extra_mem[i].size)
-                       balloon_add_region(PFN_UP(xen_extra_mem[i].start),
-                                          PFN_DOWN(xen_extra_mem[i].size));
+               if (xen_extra_mem[i].n_pfns)
+                       balloon_add_region(xen_extra_mem[i].start_pfn,
+                                          xen_extra_mem[i].n_pfns);
 
        return 0;
 }
index c5ed20bb3fe96d5f309c5299a55a7ba3b7a140bd..a5983da2f5cd929e8461eb25814c3a26ebc8e15e 100644 (file)
@@ -9,8 +9,8 @@ static inline unsigned long page_to_mfn(struct page *page)
 }
 
 struct xen_memory_region {
-       phys_addr_t start;
-       phys_addr_t size;
+       unsigned long start_pfn;
+       unsigned long n_pfns;
 };
 
 #define XEN_EXTRA_MEM_MAX_REGIONS 128 /* == E820MAX */