Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/mm: Track backing pages allocated by vmemmap_populate()

We need to keep track of the backing pages that get allocated by
vmemmap_populate() so that when we use kdump, the dump-capture kernel knows
where these pages are.

We use a simple linked list of structures that contain the physical address
of the backing page and corresponding virtual address to track the backing
pages.
To save space, we just use a pointer to the next struct vmemmap_backing. We
can also do this because we never remove nodes. We call the pointer "list"
to be compatible with changes made to the crash utility.

vmemmap_populate() is called either at boot-time or on a memory hotplug
operation. We don't have to worry about the boot-time calls because they
will be inherently single-threaded, and for a memory hotplug operation
vmemmap_populate() is called through:
sparse_add_one_section()
|
V
kmalloc_section_memmap()
|
V
sparse_mem_map_populate()
|
V
vmemmap_populate()
and in sparse_add_one_section() we're protected by pgdat_resize_lock().
So, we don't need a spinlock to protect the vmemmap_list.

We allocate space for the vmemmap_backing structs by allocating whole pages
in vmemmap_list_alloc() and then handing out chunks of this to
vmemmap_list_populate().

This means that we waste at most just under one page, but this keeps the code
is simple.

Signed-off-by: Mark Nelson <markn@au1.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

authored by

Mark Nelson and committed by
Benjamin Herrenschmidt
91eea67c 13bb5339

+49
+6
arch/powerpc/include/asm/pgalloc-64.h
··· 11 11 #include <linux/cpumask.h> 12 12 #include <linux/percpu.h> 13 13 14 + struct vmemmap_backing { 15 + struct vmemmap_backing *list; 16 + unsigned long phys; 17 + unsigned long virt_addr; 18 + }; 19 + 14 20 /* 15 21 * Functions that deal with pagetables that could be at any level of 16 22 * the table need to be passed an "index_size" so they know how to
+43
arch/powerpc/mm/init_64.c
··· 252 252 } 253 253 #endif /* CONFIG_PPC_BOOK3E */ 254 254 255 + struct vmemmap_backing *vmemmap_list; 256 + 257 + static __meminit struct vmemmap_backing * vmemmap_list_alloc(int node) 258 + { 259 + static struct vmemmap_backing *next; 260 + static int num_left; 261 + 262 + /* allocate a page when required and hand out chunks */ 263 + if (!next || !num_left) { 264 + next = vmemmap_alloc_block(PAGE_SIZE, node); 265 + if (unlikely(!next)) { 266 + WARN_ON(1); 267 + return NULL; 268 + } 269 + num_left = PAGE_SIZE / sizeof(struct vmemmap_backing); 270 + } 271 + 272 + num_left--; 273 + 274 + return next++; 275 + } 276 + 277 + static __meminit void vmemmap_list_populate(unsigned long phys, 278 + unsigned long start, 279 + int node) 280 + { 281 + struct vmemmap_backing *vmem_back; 282 + 283 + vmem_back = vmemmap_list_alloc(node); 284 + if (unlikely(!vmem_back)) { 285 + WARN_ON(1); 286 + return; 287 + } 288 + 289 + vmem_back->phys = phys; 290 + vmem_back->virt_addr = start; 291 + vmem_back->list = vmemmap_list; 292 + 293 + vmemmap_list = vmem_back; 294 + } 295 + 255 296 int __meminit vmemmap_populate(struct page *start_page, 256 297 unsigned long nr_pages, int node) 257 298 { ··· 316 275 p = vmemmap_alloc_block(page_size, node); 317 276 if (!p) 318 277 return -ENOMEM; 278 + 279 + vmemmap_list_populate(__pa(p), start, node); 319 280 320 281 pr_debug(" * %016lx..%016lx allocated at %p\n", 321 282 start, start + page_size, p);