Commit 0aad818b authored by Johannes Weiner's avatar Johannes Weiner Committed by Linus Torvalds

sparse-vmemmap: specify vmemmap population range in bytes

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: default avatarJohannes 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: default avatarDavid S. Miller <davem@davemloft.net>
Tested-by: default avatarDavid S. Miller <davem@davemloft.net>
Cc: Wu Fengguang <fengguang.wu@intel.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 055e4fd9
...@@ -391,17 +391,14 @@ int kern_addr_valid(unsigned long addr) ...@@ -391,17 +391,14 @@ int kern_addr_valid(unsigned long addr)
} }
#ifdef CONFIG_SPARSEMEM_VMEMMAP #ifdef CONFIG_SPARSEMEM_VMEMMAP
#ifdef CONFIG_ARM64_64K_PAGES #ifdef CONFIG_ARM64_64K_PAGES
int __meminit vmemmap_populate(struct page *start_page, int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
unsigned long size, int node)
{ {
return vmemmap_populate_basepages(start_page, size, node); return vmemmap_populate_basepages(start, end, node);
} }
#else /* !CONFIG_ARM64_64K_PAGES */ #else /* !CONFIG_ARM64_64K_PAGES */
int __meminit vmemmap_populate(struct page *start_page, int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
unsigned long size, int node)
{ {
unsigned long addr = (unsigned long)start_page; unsigned long addr = start;
unsigned long end = (unsigned long)(start_page + size);
unsigned long next; unsigned long next;
pgd_t *pgd; pgd_t *pgd;
pud_t *pud; pud_t *pud;
...@@ -434,7 +431,7 @@ int __meminit vmemmap_populate(struct page *start_page, ...@@ -434,7 +431,7 @@ int __meminit vmemmap_populate(struct page *start_page,
return 0; return 0;
} }
#endif /* CONFIG_ARM64_64K_PAGES */ #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 */ #endif /* CONFIG_SPARSEMEM_VMEMMAP */
...@@ -819,13 +819,12 @@ void arch_refresh_nodedata(int update_node, pg_data_t *update_pgdat) ...@@ -819,13 +819,12 @@ void arch_refresh_nodedata(int update_node, pg_data_t *update_pgdat)
#endif #endif
#ifdef CONFIG_SPARSEMEM_VMEMMAP #ifdef CONFIG_SPARSEMEM_VMEMMAP
int __meminit vmemmap_populate(struct page *start_page, int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
unsigned long size, 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 #endif
...@@ -263,19 +263,14 @@ static __meminit void vmemmap_list_populate(unsigned long phys, ...@@ -263,19 +263,14 @@ static __meminit void vmemmap_list_populate(unsigned long phys,
vmemmap_list = vmem_back; vmemmap_list = vmem_back;
} }
int __meminit vmemmap_populate(struct page *start_page, int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
unsigned long nr_pages, 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; unsigned long page_size = 1 << mmu_psize_defs[mmu_vmemmap_psize].shift;
/* Align to the page size of the linear mapping. */ /* Align to the page size of the linear mapping. */
start = _ALIGN_DOWN(start, page_size); start = _ALIGN_DOWN(start, page_size);
pr_debug("vmemmap_populate page %p, %ld pages, node %d\n", pr_debug("vmemmap_populate %lx..%lx, node %d\n", start, end, node);
start_page, nr_pages, node);
pr_debug(" -> map %lx..%lx\n", start, end);
for (; start < end; start += page_size) { for (; start < end; start += page_size) {
void *p; void *p;
...@@ -298,7 +293,7 @@ int __meminit vmemmap_populate(struct page *start_page, ...@@ -298,7 +293,7 @@ int __meminit vmemmap_populate(struct page *start_page,
return 0; return 0;
} }
void vmemmap_free(struct page *memmap, unsigned long nr_pages) void vmemmap_free(unsigned long start, unsigned long end)
{ {
} }
......
...@@ -191,19 +191,16 @@ static void vmem_remove_range(unsigned long start, unsigned long size) ...@@ -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. * 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; pgd_t *pg_dir;
pud_t *pu_dir; pud_t *pu_dir;
pmd_t *pm_dir; pmd_t *pm_dir;
pte_t *pt_dir; pte_t *pt_dir;
int ret = -ENOMEM; int ret = -ENOMEM;
start_addr = (unsigned long) start; for (address = start; address < end;) {
end_addr = (unsigned long) (start + nr);
for (address = start_addr; address < end_addr;) {
pg_dir = pgd_offset_k(address); pg_dir = pgd_offset_k(address);
if (pgd_none(*pg_dir)) { if (pgd_none(*pg_dir)) {
pu_dir = vmem_pud_alloc(); pu_dir = vmem_pud_alloc();
...@@ -262,14 +259,14 @@ int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node) ...@@ -262,14 +259,14 @@ int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node)
} }
address += PAGE_SIZE; address += PAGE_SIZE;
} }
memset(start, 0, nr * sizeof(struct page)); memset((void *)start, 0, end - start);
ret = 0; ret = 0;
out: out:
flush_tlb_kernel_range(start_addr, end_addr); flush_tlb_kernel_range(start, end);
return ret; return ret;
} }
void vmemmap_free(struct page *memmap, unsigned long nr_pages) void vmemmap_free(unsigned long start, unsigned long end)
{ {
} }
......
...@@ -2181,10 +2181,9 @@ unsigned long vmemmap_table[VMEMMAP_SIZE]; ...@@ -2181,10 +2181,9 @@ unsigned long vmemmap_table[VMEMMAP_SIZE];
static long __meminitdata addr_start, addr_end; static long __meminitdata addr_start, addr_end;
static int __meminitdata node_start; 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_start = (vstart - VMEMMAP_BASE);
unsigned long phys_end = (vend - VMEMMAP_BASE); unsigned long phys_end = (vend - VMEMMAP_BASE);
unsigned long addr = phys_start & VMEMMAP_CHUNK_MASK; unsigned long addr = phys_start & VMEMMAP_CHUNK_MASK;
...@@ -2236,7 +2235,7 @@ void __meminit vmemmap_populate_print_last(void) ...@@ -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)
{ {
} }
......
...@@ -1011,11 +1011,8 @@ remove_pagetable(unsigned long start, unsigned long end, bool direct) ...@@ -1011,11 +1011,8 @@ remove_pagetable(unsigned long start, unsigned long end, bool direct)
flush_tlb_all(); 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); remove_pagetable(start, end, false);
} }
...@@ -1284,17 +1281,15 @@ static long __meminitdata addr_start, addr_end; ...@@ -1284,17 +1281,15 @@ static long __meminitdata addr_start, addr_end;
static void __meminitdata *p_start, *p_end; static void __meminitdata *p_start, *p_end;
static int __meminitdata node_start; static int __meminitdata node_start;
int __meminit int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
vmemmap_populate(struct page *start_page, unsigned long size, int node)
{ {
unsigned long addr = (unsigned long)start_page; unsigned long addr;
unsigned long end = (unsigned long)(start_page + size);
unsigned long next; unsigned long next;
pgd_t *pgd; pgd_t *pgd;
pud_t *pud; pud_t *pud;
pmd_t *pmd; pmd_t *pmd;
for (; addr < end; addr = next) { for (addr = start; addr < end; addr = next) {
void *p = NULL; void *p = NULL;
pgd = vmemmap_pgd_populate(addr, node); pgd = vmemmap_pgd_populate(addr, node);
...@@ -1351,7 +1346,7 @@ vmemmap_populate(struct page *start_page, unsigned long size, int 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; return 0;
} }
......
...@@ -1764,12 +1764,12 @@ pte_t *vmemmap_pte_populate(pmd_t *pmd, unsigned long addr, int node); ...@@ -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(unsigned long size, int node);
void *vmemmap_alloc_block_buf(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); void vmemmap_verify(pte_t *, int, unsigned long, unsigned long);
int vmemmap_populate_basepages(struct page *start_page, int vmemmap_populate_basepages(unsigned long start, unsigned long end,
unsigned long pages, int node); int node);
int vmemmap_populate(struct page *start_page, unsigned long pages, int node); int vmemmap_populate(unsigned long start, unsigned long end, int node);
void vmemmap_populate_print_last(void); void vmemmap_populate_print_last(void);
#ifdef CONFIG_MEMORY_HOTPLUG #ifdef CONFIG_MEMORY_HOTPLUG
void vmemmap_free(struct page *memmap, unsigned long nr_pages); void vmemmap_free(unsigned long start, unsigned long end);
#endif #endif
void register_page_bootmem_memmap(unsigned long section_nr, struct page *map, void register_page_bootmem_memmap(unsigned long section_nr, struct page *map,
unsigned long size); unsigned long size);
......
...@@ -147,11 +147,10 @@ pgd_t * __meminit vmemmap_pgd_populate(unsigned long addr, int node) ...@@ -147,11 +147,10 @@ pgd_t * __meminit vmemmap_pgd_populate(unsigned long addr, int node)
return pgd; return pgd;
} }
int __meminit vmemmap_populate_basepages(struct page *start_page, int __meminit vmemmap_populate_basepages(unsigned long start,
unsigned long size, int node) unsigned long end, int node)
{ {
unsigned long addr = (unsigned long)start_page; unsigned long addr = start;
unsigned long end = (unsigned long)(start_page + size);
pgd_t *pgd; pgd_t *pgd;
pud_t *pud; pud_t *pud;
pmd_t *pmd; pmd_t *pmd;
...@@ -178,9 +177,15 @@ int __meminit vmemmap_populate_basepages(struct page *start_page, ...@@ -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 * __meminit sparse_mem_map_populate(unsigned long pnum, int nid)
{ {
struct page *map = pfn_to_page(pnum * PAGES_PER_SECTION); unsigned long start;
int error = vmemmap_populate(map, PAGES_PER_SECTION, nid); unsigned long end;
if (error) 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 NULL;
return map; return map;
......
...@@ -615,11 +615,17 @@ static inline struct page *kmalloc_section_memmap(unsigned long pnum, int nid, ...@@ -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) 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) 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 #else
static struct page *__kmalloc_section_memmap(unsigned long nr_pages) static struct page *__kmalloc_section_memmap(unsigned long nr_pages)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment