sparse-vmemmap: specify vmemmap population range in bytes
authorJohannes Weiner <hannes@cmpxchg.org>
Mon, 29 Apr 2013 22:07:50 +0000 (15:07 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 29 Apr 2013 22:54:35 +0000 (15:54 -0700)
The sparse code, when asking the architecture to populate the vmemmap,
specifies the section range as a starting page and a number of pages.

This is an awkward interface, because none of the arch-specific code
actually thinks of the range in terms of 'struct page' units and always
translates it to bytes first.

In addition, later patches mix huge page and regular page backing for
the vmemmap.  For this, they need to call vmemmap_populate_basepages()
on sub-section ranges with PAGE_SIZE and PMD_SIZE in mind.  But these
are not necessarily multiples of the 'struct page' size and so this unit
is too coarse.

Just translate the section range into bytes once in the generic sparse
code, then pass byte ranges down the stack.

Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Cc: Ben Hutchings <ben@decadent.org.uk>
Cc: Bernhard Schmidt <Bernhard.Schmidt@lrz.de>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Russell King <rmk@arm.linux.org.uk>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: "Luck, Tony" <tony.luck@intel.com>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Acked-by: David S. Miller <davem@davemloft.net>
Tested-by: David S. Miller <davem@davemloft.net>
Cc: Wu Fengguang <fengguang.wu@intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
arch/arm64/mm/mmu.c
arch/ia64/mm/discontig.c
arch/powerpc/mm/init_64.c
arch/s390/mm/vmem.c
arch/sparc/mm/init_64.c
arch/x86/mm/init_64.c
include/linux/mm.h
mm/sparse-vmemmap.c
mm/sparse.c

index 70b8cd4021c46cb800cbf76bd21a001e2e73e86c..eeecc9c8ed6860accacc36bb5f5aa0e6c7db7e58 100644 (file)
@@ -391,17 +391,14 @@ int kern_addr_valid(unsigned long addr)
 }
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
 #ifdef CONFIG_ARM64_64K_PAGES
-int __meminit vmemmap_populate(struct page *start_page,
-                              unsigned long size, int node)
+int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
 {
-       return vmemmap_populate_basepages(start_page, size, node);
+       return vmemmap_populate_basepages(start, end, node);
 }
 #else  /* !CONFIG_ARM64_64K_PAGES */
-int __meminit vmemmap_populate(struct page *start_page,
-                              unsigned long size, int node)
+int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
 {
-       unsigned long addr = (unsigned long)start_page;
-       unsigned long end = (unsigned long)(start_page + size);
+       unsigned long addr = start;
        unsigned long next;
        pgd_t *pgd;
        pud_t *pud;
@@ -434,7 +431,7 @@ int __meminit vmemmap_populate(struct page *start_page,
        return 0;
 }
 #endif /* CONFIG_ARM64_64K_PAGES */
-void vmemmap_free(struct page *memmap, unsigned long nr_pages)
+void vmemmap_free(unsigned long start, unsigned long end)
 {
 }
 #endif /* CONFIG_SPARSEMEM_VMEMMAP */
index a57436e5d4057e3840188c68e2db6306e0a72d6d..ae4db4bd6d97d77aebae5c7677e6803500770904 100644 (file)
@@ -819,13 +819,12 @@ void arch_refresh_nodedata(int update_node, pg_data_t *update_pgdat)
 #endif
 
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
-int __meminit vmemmap_populate(struct page *start_page,
-                                               unsigned long size, int node)
+int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
 {
-       return vmemmap_populate_basepages(start_page, size, node);
+       return vmemmap_populate_basepages(start, end, node);
 }
 
-void vmemmap_free(struct page *memmap, unsigned long nr_pages)
+void vmemmap_free(unsigned long start, unsigned long end)
 {
 }
 #endif
index 7e2246fb2f31b72512720d0a0db1808f26942f38..5a535b73ea1833ef18ef0144374420302e62edf1 100644 (file)
@@ -263,19 +263,14 @@ static __meminit void vmemmap_list_populate(unsigned long phys,
        vmemmap_list = vmem_back;
 }
 
-int __meminit vmemmap_populate(struct page *start_page,
-                              unsigned long nr_pages, int node)
+int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
 {
-       unsigned long start = (unsigned long)start_page;
-       unsigned long end = (unsigned long)(start_page + nr_pages);
        unsigned long page_size = 1 << mmu_psize_defs[mmu_vmemmap_psize].shift;
 
        /* Align to the page size of the linear mapping. */
        start = _ALIGN_DOWN(start, page_size);
 
-       pr_debug("vmemmap_populate page %p, %ld pages, node %d\n",
-                start_page, nr_pages, node);
-       pr_debug(" -> map %lx..%lx\n", start, end);
+       pr_debug("vmemmap_populate %lx..%lx, node %d\n", start, end, node);
 
        for (; start < end; start += page_size) {
                void *p;
@@ -298,7 +293,7 @@ int __meminit vmemmap_populate(struct page *start_page,
        return 0;
 }
 
-void vmemmap_free(struct page *memmap, unsigned long nr_pages)
+void vmemmap_free(unsigned long start, unsigned long end)
 {
 }
 
index ffab84db69071f3ea24e0a446889bcc2036414f2..35837054f73461f371f0a2e2ff311093f4e7e846 100644 (file)
@@ -191,19 +191,16 @@ static void vmem_remove_range(unsigned long start, unsigned long size)
 /*
  * Add a backed mem_map array to the virtual mem_map array.
  */
-int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node)
+int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
 {
-       unsigned long address, start_addr, end_addr;
+       unsigned long address = start;
        pgd_t *pg_dir;
        pud_t *pu_dir;
        pmd_t *pm_dir;
        pte_t *pt_dir;
        int ret = -ENOMEM;
 
-       start_addr = (unsigned long) start;
-       end_addr = (unsigned long) (start + nr);
-
-       for (address = start_addr; address < end_addr;) {
+       for (address = start; address < end;) {
                pg_dir = pgd_offset_k(address);
                if (pgd_none(*pg_dir)) {
                        pu_dir = vmem_pud_alloc();
@@ -262,14 +259,14 @@ int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node)
                }
                address += PAGE_SIZE;
        }
-       memset(start, 0, nr * sizeof(struct page));
+       memset((void *)start, 0, end - start);
        ret = 0;
 out:
-       flush_tlb_kernel_range(start_addr, end_addr);
+       flush_tlb_kernel_range(start, end);
        return ret;
 }
 
-void vmemmap_free(struct page *memmap, unsigned long nr_pages)
+void vmemmap_free(unsigned long start, unsigned long end)
 {
 }
 
index 1588d33d549235aa67756e7e27e0321e85164514..6ac99d64a13c019bd6e6c4c2e7b1d739c68d191d 100644 (file)
@@ -2181,10 +2181,9 @@ unsigned long vmemmap_table[VMEMMAP_SIZE];
 static long __meminitdata addr_start, addr_end;
 static int __meminitdata node_start;
 
-int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node)
+int __meminit vmemmap_populate(unsigned long vstart, unsigned long vend,
+                              int node)
 {
-       unsigned long vstart = (unsigned long) start;
-       unsigned long vend = (unsigned long) (start + nr);
        unsigned long phys_start = (vstart - VMEMMAP_BASE);
        unsigned long phys_end = (vend - VMEMMAP_BASE);
        unsigned long addr = phys_start & VMEMMAP_CHUNK_MASK;
@@ -2236,7 +2235,7 @@ void __meminit vmemmap_populate_print_last(void)
        }
 }
 
-void vmemmap_free(struct page *memmap, unsigned long nr_pages)
+void vmemmap_free(unsigned long start, unsigned long end)
 {
 }
 
index 2ef81f19bd6c63d11f444a35bd803d6795300744..528c143f467cbeea5cfe6436210482f140672fde 100644 (file)
@@ -1011,11 +1011,8 @@ remove_pagetable(unsigned long start, unsigned long end, bool direct)
        flush_tlb_all();
 }
 
-void __ref vmemmap_free(struct page *memmap, unsigned long nr_pages)
+void __ref vmemmap_free(unsigned long start, unsigned long end)
 {
-       unsigned long start = (unsigned long)memmap;
-       unsigned long end = (unsigned long)(memmap + nr_pages);
-
        remove_pagetable(start, end, false);
 }
 
@@ -1284,17 +1281,15 @@ static long __meminitdata addr_start, addr_end;
 static void __meminitdata *p_start, *p_end;
 static int __meminitdata node_start;
 
-int __meminit
-vmemmap_populate(struct page *start_page, unsigned long size, int node)
+int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
 {
-       unsigned long addr = (unsigned long)start_page;
-       unsigned long end = (unsigned long)(start_page + size);
+       unsigned long addr;
        unsigned long next;
        pgd_t *pgd;
        pud_t *pud;
        pmd_t *pmd;
 
-       for (; addr < end; addr = next) {
+       for (addr = start; addr < end; addr = next) {
                void *p = NULL;
 
                pgd = vmemmap_pgd_populate(addr, node);
@@ -1351,7 +1346,7 @@ vmemmap_populate(struct page *start_page, unsigned long size, int node)
                }
 
        }
-       sync_global_pgds((unsigned long)start_page, end - 1);
+       sync_global_pgds(start, end - 1);
        return 0;
 }
 
index 98a44376e4f3a0e6cae77d844929ad51d02006ed..6d7266842abd3b8e7e6d923da54ec4a7b703c649 100644 (file)
@@ -1764,12 +1764,12 @@ pte_t *vmemmap_pte_populate(pmd_t *pmd, unsigned long addr, int node);
 void *vmemmap_alloc_block(unsigned long size, int node);
 void *vmemmap_alloc_block_buf(unsigned long size, int node);
 void vmemmap_verify(pte_t *, int, unsigned long, unsigned long);
-int vmemmap_populate_basepages(struct page *start_page,
-                                               unsigned long pages, int node);
-int vmemmap_populate(struct page *start_page, unsigned long pages, int node);
+int vmemmap_populate_basepages(unsigned long start, unsigned long end,
+                              int node);
+int vmemmap_populate(unsigned long start, unsigned long end, int node);
 void vmemmap_populate_print_last(void);
 #ifdef CONFIG_MEMORY_HOTPLUG
-void vmemmap_free(struct page *memmap, unsigned long nr_pages);
+void vmemmap_free(unsigned long start, unsigned long end);
 #endif
 void register_page_bootmem_memmap(unsigned long section_nr, struct page *map,
                                  unsigned long size);
index 22b7e18e9dea5953a59b6aafd4f9bbb804c428db..27eeab3be757e8c9bf04a18dba9dfd7f7aaa5ab1 100644 (file)
@@ -147,11 +147,10 @@ pgd_t * __meminit vmemmap_pgd_populate(unsigned long addr, int node)
        return pgd;
 }
 
-int __meminit vmemmap_populate_basepages(struct page *start_page,
-                                               unsigned long size, int node)
+int __meminit vmemmap_populate_basepages(unsigned long start,
+                                        unsigned long end, int node)
 {
-       unsigned long addr = (unsigned long)start_page;
-       unsigned long end = (unsigned long)(start_page + size);
+       unsigned long addr = start;
        pgd_t *pgd;
        pud_t *pud;
        pmd_t *pmd;
@@ -178,9 +177,15 @@ int __meminit vmemmap_populate_basepages(struct page *start_page,
 
 struct page * __meminit sparse_mem_map_populate(unsigned long pnum, int nid)
 {
-       struct page *map = pfn_to_page(pnum * PAGES_PER_SECTION);
-       int error = vmemmap_populate(map, PAGES_PER_SECTION, nid);
-       if (error)
+       unsigned long start;
+       unsigned long end;
+       struct page *map;
+
+       map = pfn_to_page(pnum * PAGES_PER_SECTION);
+       start = (unsigned long)map;
+       end = (unsigned long)(map + PAGES_PER_SECTION);
+
+       if (vmemmap_populate(start, end, nid))
                return NULL;
 
        return map;
index 7ca6dc8479475cf982c607193b501371d94abf07..a37be5f9050d62c54588b19fdeb9941b73d0b460 100644 (file)
@@ -615,11 +615,17 @@ static inline struct page *kmalloc_section_memmap(unsigned long pnum, int nid,
 }
 static void __kfree_section_memmap(struct page *memmap, unsigned long nr_pages)
 {
-       vmemmap_free(memmap, nr_pages);
+       unsigned long start = (unsigned long)memmap;
+       unsigned long end = (unsigned long)(memmap + nr_pages);
+
+       vmemmap_free(start, end);
 }
 static void free_map_bootmem(struct page *memmap, unsigned long nr_pages)
 {
-       vmemmap_free(memmap, nr_pages);
+       unsigned long start = (unsigned long)memmap;
+       unsigned long end = (unsigned long)(memmap + nr_pages);
+
+       vmemmap_free(start, end);
 }
 #else
 static struct page *__kmalloc_section_memmap(unsigned long nr_pages)