This renames the global list which tracks all the virtual to physical
mapping and also the global list which tracks all the available unused
vmemmap_hw_map node structures. It also attempts to explain the purpose
of these global linked lists and points out a possible race condition.

Signed-off-by: Anshuman Khandual <khand...@linux.vnet.ibm.com>
---
 arch/powerpc/include/asm/pgalloc-64.h |  2 +-
 arch/powerpc/kernel/machine_kexec.c   |  2 +-
 arch/powerpc/mm/init_64.c             | 82 +++++++++++++++++++++--------------
 3 files changed, 52 insertions(+), 34 deletions(-)

diff --git a/arch/powerpc/include/asm/pgalloc-64.h 
b/arch/powerpc/include/asm/pgalloc-64.h
index e03b41c..6e21a2a 100644
--- a/arch/powerpc/include/asm/pgalloc-64.h
+++ b/arch/powerpc/include/asm/pgalloc-64.h
@@ -22,7 +22,7 @@ struct vmemmap_hw_map {
        unsigned long paddr;
        unsigned long vaddr;
 };
-extern struct vmemmap_hw_map *vmemmap_list;
+extern struct vmemmap_hw_map *vmemmap_global;
 
 /*
  * Functions that deal with pagetables that could be at any level of
diff --git a/arch/powerpc/kernel/machine_kexec.c 
b/arch/powerpc/kernel/machine_kexec.c
index 0d90798..eb6876c 100644
--- a/arch/powerpc/kernel/machine_kexec.c
+++ b/arch/powerpc/kernel/machine_kexec.c
@@ -77,7 +77,7 @@ void arch_crash_save_vmcoreinfo(void)
        VMCOREINFO_SYMBOL(contig_page_data);
 #endif
 #if defined(CONFIG_PPC64) && defined(CONFIG_SPARSEMEM_VMEMMAP)
-       VMCOREINFO_SYMBOL(vmemmap_list);
+       VMCOREINFO_SYMBOL(vmemmap_global);
        VMCOREINFO_SYMBOL(mmu_vmemmap_psize);
        VMCOREINFO_SYMBOL(mmu_psize_defs);
        VMCOREINFO_STRUCT_SIZE(vmemmap_hw_map);
diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c
index 9b5dea3..d998f3f 100644
--- a/arch/powerpc/mm/init_64.c
+++ b/arch/powerpc/mm/init_64.c
@@ -245,45 +245,63 @@ static void vmemmap_remove_mapping(unsigned long start,
 
 #endif /* CONFIG_PPC_BOOK3E */
 
-struct vmemmap_hw_map *vmemmap_list;
-static struct vmemmap_hw_map *next;
-static int num_left;
-static int num_freed;
+/*
+ * vmemmap virtual address space does not have a page table to track
+ * existing physical mapping. The vmemmap_global list maintains the
+ * physical mapping at all times where as the vmemmap_avail list
+ * maintains the available vmemmap_hw_map structures which got deleted
+ * from the vmemmap_global list during system runtime (memory hotplug
+ * remove operation for example). They freed structures are reused later
+ * when new requests come in without allocating new fresh memory. This
+ * pointer also tracks the allocated vmemmap_hw_map structures as we
+ * allocate one full page memory at a time when we dont have any.
+ */
+struct vmemmap_hw_map *vmemmap_global;
+static struct vmemmap_hw_map *vmemmap_avail;
+
+/* XXX: The same pointer vmemmap_avail tracks individual chunks inside
+ * the allocated full page during the boot time and again tracks the
+ * freeed nodes during runtime. It is racy but it does not happen as
+ * both they are separated by the boot process. Will create problem if
+ * some how we have memory hotplug operation during boot !!
+ */
+static int free_chunk;         /* Allocated chunks available */
+static int free_node;          /* Freeed nodes available */
 
-static __meminit struct vmemmap_hw_map * vmemmap_list_alloc(int node)
+static __meminit struct vmemmap_hw_map * vmemmap_global_alloc(int node)
 {
        struct vmemmap_hw_map *vmem_back;
        /* get from freed entries first */
-       if (num_freed) {
-               num_freed--;
-               vmem_back = next;
-               next = next->link;
+       if (free_node) {
+               free_node--;
+               vmem_back = vmemmap_avail;
+               vmemmap_avail = vmemmap_avail->link;
 
                return vmem_back;
        }
 
        /* allocate a page when required and hand out chunks */
-       if (!num_left) {
-               next = vmemmap_alloc_block(PAGE_SIZE, node);
-               if (unlikely(!next)) {
+       if (!free_chunk) {
+               vmemmap_avail = vmemmap_alloc_block(PAGE_SIZE, node);
+               if (unlikely(!vmemmap_avail)) {
                        WARN_ON(1);
                        return NULL;
                }
-               num_left = PAGE_SIZE / sizeof(struct vmemmap_hw_map);
+               free_chunk = PAGE_SIZE / sizeof(struct vmemmap_hw_map);
        }
 
-       num_left--;
+       free_chunk--;
 
-       return next++;
+       return vmemmap_avail++;
 }
 
-static __meminit void vmemmap_list_populate(unsigned long paddr,
+static __meminit void vmemmap_global_populate(unsigned long paddr,
                                            unsigned long start,
                                            int node)
 {
        struct vmemmap_hw_map *vmem_back;
 
-       vmem_back = vmemmap_list_alloc(node);
+       vmem_back = vmemmap_global_alloc(node);
        if (unlikely(!vmem_back)) {
                WARN_ON(1);
                return;
@@ -291,9 +309,9 @@ static __meminit void vmemmap_list_populate(unsigned long 
paddr,
 
        vmem_back->paddr = paddr;
        vmem_back->vaddr = start;
-       vmem_back->link = vmemmap_list;
+       vmem_back->link = vmemmap_global;
 
-       vmemmap_list = vmem_back;
+       vmemmap_global = vmem_back;
 }
 
 int __meminit vmemmap_populate(unsigned long start, unsigned long end, int 
node)
@@ -315,7 +333,7 @@ int __meminit vmemmap_populate(unsigned long start, 
unsigned long end, int node)
                if (!p)
                        return -ENOMEM;
 
-               vmemmap_list_populate(__pa(p), start, node);
+               vmemmap_global_populate(__pa(p), start, node);
 
                pr_debug("      * %016lx..%016lx allocated at %p\n",
                         start, start + page_size, p);
@@ -327,11 +345,11 @@ int __meminit vmemmap_populate(unsigned long start, 
unsigned long end, int node)
 }
 
 #ifdef CONFIG_MEMORY_HOTPLUG
-static unsigned long vmemmap_list_free(unsigned long start)
+static unsigned long vmemmap_global_free(unsigned long start)
 {
        struct vmemmap_hw_map *vmem_back, *vmem_back_prev;
 
-       vmem_back_prev = vmem_back = vmemmap_list;
+       vmem_back_prev = vmem_back = vmemmap_global;
 
        /* look for it with prev pointer recorded */
        for (; vmem_back; vmem_back = vmem_back->link) {
@@ -345,16 +363,16 @@ static unsigned long vmemmap_list_free(unsigned long 
start)
                return 0;
        }
 
-       /* remove it from vmemmap_list */
-       if (vmem_back == vmemmap_list) /* remove head */
-               vmemmap_list = vmem_back->link;
+       /* remove it from vmemmap_global */
+       if (vmem_back == vmemmap_global) /* remove head */
+               vmemmap_global = vmem_back->link;
        else
                vmem_back_prev->link = vmem_back->link;
 
-       /* next point to this freed entry */
-       vmem_back->link = next;
-       next = vmem_back;
-       num_freed++;
+       /* vmemmap_avail point to this freed entry */
+       vmem_back->link = vmemmap_avail;
+       vmemmap_avail = vmem_back;
+       free_node++;
 
        return vmem_back->paddr;
 }
@@ -378,7 +396,7 @@ void __ref vmemmap_free(unsigned long start, unsigned long 
end)
                if (vmemmap_populated(start, page_size))
                        continue;
 
-               addr = vmemmap_list_free(start);
+               addr = vmemmap_global_free(start);
                if (addr) {
                        struct page *page = pfn_to_page(addr >> PAGE_SHIFT);
 
@@ -432,11 +450,11 @@ struct page *realmode_pfn_to_page(unsigned long pfn)
        unsigned long page_size = 1 << mmu_psize_defs[mmu_vmemmap_psize].shift;
        unsigned long pg_va = (unsigned long) pfn_to_page(pfn);
 
-       for (vmem_back = vmemmap_list; vmem_back; vmem_back = vmem_back->link) {
+       for (vmem_back = vmemmap_global; vmem_back; vmem_back = 
vmem_back->link) {
                if (pg_va < vmem_back->vaddr)
                        continue;
 
-               /* After vmemmap_list entry free is possible, need check all */
+               /* After vmemmap_global entry free is possible, need check all 
*/
                if ((pg_va + sizeof(struct page)) <=
                                (vmem_back->vaddr + page_size)) {
                        page = (struct page *) (vmem_back->paddr + pg_va -
-- 
2.1.0

_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Reply via email to