cregit-Linux how code gets into the kernel

Release 4.18 mm/sparse.c

Directory: mm
// SPDX-License-Identifier: GPL-2.0
/*
 * sparse memory mappings.
 */
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/mmzone.h>
#include <linux/bootmem.h>
#include <linux/compiler.h>
#include <linux/highmem.h>
#include <linux/export.h>
#include <linux/spinlock.h>
#include <linux/vmalloc.h>

#include "internal.h"
#include <asm/dma.h>
#include <asm/pgalloc.h>
#include <asm/pgtable.h>

/*
 * Permanent SPARSEMEM data:
 *
 * 1) mem_section       - memory sections, mem_map's for valid memory
 */
#ifdef CONFIG_SPARSEMEM_EXTREME

struct mem_section **mem_section;
#else

struct mem_section mem_section[NR_SECTION_ROOTS][SECTIONS_PER_ROOT]
	____cacheline_internodealigned_in_smp;
#endif
EXPORT_SYMBOL(mem_section);

#ifdef NODE_NOT_IN_PAGE_FLAGS
/*
 * If we did not store the node number in the page then we have to
 * do a lookup in the section_to_node_table in order to find which
 * node the page belongs to.
 */
#if MAX_NUMNODES <= 256

static u8 section_to_node_table[NR_MEM_SECTIONS] __cacheline_aligned;
#else

static u16 section_to_node_table[NR_MEM_SECTIONS] __cacheline_aligned;
#endif


int page_to_nid(const struct page *page) { return section_to_node_table[page_to_section(page)]; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Lameter1890.00%133.33%
Ian Campbell15.00%133.33%
Andy Whitcroft15.00%133.33%
Total20100.00%3100.00%

EXPORT_SYMBOL(page_to_nid);
static void set_section_nid(unsigned long section_nr, int nid) { section_to_node_table[section_nr] = nid; }

Contributors

PersonTokensPropCommitsCommitProp
Andy Whitcroft20100.00%1100.00%
Total20100.00%1100.00%

#else /* !NODE_NOT_IN_PAGE_FLAGS */
static inline void set_section_nid(unsigned long section_nr, int nid) { }

Contributors

PersonTokensPropCommitsCommitProp
Andy Whitcroft13100.00%1100.00%
Total13100.00%1100.00%

#endif #ifdef CONFIG_SPARSEMEM_EXTREME static noinline struct mem_section __ref *sparse_index_alloc(int nid) { struct mem_section *section = NULL; unsigned long array_size = SECTIONS_PER_ROOT * sizeof(struct mem_section); if (slab_is_available()) section = kzalloc_node(array_size, GFP_KERNEL, nid); else section = memblock_virt_alloc_node(array_size, nid); return section;
} static int __meminit sparse_index_init(unsigned long section_nr, int nid) { unsigned long root = SECTION_NR_TO_ROOT(section_nr); struct mem_section *section; if (mem_section[root]) return -EEXIST; section = sparse_index_alloc(nid); if (!section) return -ENOMEM; mem_section[root] = section; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Bob Picco3452.31%228.57%
Dave Hansen1929.23%114.29%
Américo Wang913.85%114.29%
Yasunori Goto11.54%114.29%
Fabian Frederick11.54%114.29%
Zhang Yanfei11.54%114.29%
Total65100.00%7100.00%

#else /* !SPARSEMEM_EXTREME */
static inline int sparse_index_init(unsigned long section_nr, int nid) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Dave Hansen17100.00%1100.00%
Total17100.00%1100.00%

#endif #ifdef CONFIG_SPARSEMEM_EXTREME
int __section_nr(struct mem_section* ms) { unsigned long root_nr; struct mem_section *root = NULL; for (root_nr = 0; root_nr < NR_SECTION_ROOTS; root_nr++) { root = __nr_to_section(root_nr * SECTIONS_PER_ROOT); if (!root) continue; if ((ms >= root) && (ms < (root + SECTIONS_PER_ROOT))) break; } VM_BUG_ON(!root); return (root_nr * SECTIONS_PER_ROOT) + (ms - root); }

Contributors

PersonTokensPropCommitsCommitProp
Dave Hansen7786.52%125.00%
Mike Kravetz44.49%125.00%
Gavin Shan44.49%125.00%
Kirill A. Shutemov44.49%125.00%
Total89100.00%4100.00%

#else
int __section_nr(struct mem_section* ms) { return (int)(ms - mem_section[0]); }

Contributors

PersonTokensPropCommitsCommitProp
Zhou Chengming23100.00%1100.00%
Total23100.00%1100.00%

#endif /* * During early boot, before section_mem_map is used for an actual * mem_map, we use section_mem_map to store the section's NUMA * node. This keeps us from having to use another data structure. The * node information is cleared just before we store the real mem_map. */
static inline unsigned long sparse_encode_early_nid(int nid) { return (nid << SECTION_NID_SHIFT); }

Contributors

PersonTokensPropCommitsCommitProp
Andy Whitcroft18100.00%1100.00%
Total18100.00%1100.00%


static inline int sparse_early_nid(struct mem_section *section) { return (section->section_mem_map >> SECTION_NID_SHIFT); }

Contributors

PersonTokensPropCommitsCommitProp
Andy Whitcroft21100.00%1100.00%
Total21100.00%1100.00%

/* Validate the physical addressing limitations of the model */
void __meminit mminit_validate_memmodel_limits(unsigned long *start_pfn, unsigned long *end_pfn) { unsigned long max_sparsemem_pfn = 1UL << (MAX_PHYSMEM_BITS-PAGE_SHIFT); /* * Sanity checks - do not allow an architecture to pass * in larger pfns than the maximum scope of sparsemem: */ if (*start_pfn > max_sparsemem_pfn) { mminit_dprintk(MMINIT_WARNING, "pfnvalidation", "Start of range %lu -> %lu exceeds SPARSEMEM max %lu\n", *start_pfn, *end_pfn, max_sparsemem_pfn); WARN_ON_ONCE(1); *start_pfn = max_sparsemem_pfn; *end_pfn = max_sparsemem_pfn; } else if (*end_pfn > max_sparsemem_pfn) { mminit_dprintk(MMINIT_WARNING, "pfnvalidation", "End of range %lu -> %lu exceeds SPARSEMEM max %lu\n", *start_pfn, *end_pfn, max_sparsemem_pfn); WARN_ON_ONCE(1); *end_pfn = max_sparsemem_pfn; } }

Contributors

PersonTokensPropCommitsCommitProp
Mel Gorman7771.96%125.00%
Ingo Molnar1816.82%125.00%
Andy Whitcroft1110.28%125.00%
Cyrill V. Gorcunov10.93%125.00%
Total107100.00%4100.00%

/* * There are a number of times that we loop over NR_MEM_SECTIONS, * looking for section_present() on each. But, when we have very * large physical address spaces, NR_MEM_SECTIONS can also be * very large which makes the loops quite long. * * Keeping track of this gives us an easy way to break out of * those loops early. */ int __highest_present_section_nr;
static void section_mark_present(struct mem_section *ms) { int section_nr = __section_nr(ms); if (section_nr > __highest_present_section_nr) __highest_present_section_nr = section_nr; ms->section_mem_map |= SECTION_MARKED_PRESENT; }

Contributors

PersonTokensPropCommitsCommitProp
Dave Hansen35100.00%1100.00%
Total35100.00%1100.00%


static inline int next_present_section_nr(int section_nr) { do { section_nr++; if (present_section_nr(section_nr)) return section_nr; } while ((section_nr <= __highest_present_section_nr)); return -1; }

Contributors

PersonTokensPropCommitsCommitProp
Dave Hansen39100.00%1100.00%
Total39100.00%1100.00%

#define for_each_present_section_nr(start, section_nr) \ for (section_nr = next_present_section_nr(start-1); \ ((section_nr >= 0) && \ (section_nr <= __highest_present_section_nr)); \ section_nr = next_present_section_nr(section_nr)) /* Record a memory area against a node. */
void __init memory_present(int nid, unsigned long start, unsigned long end) { unsigned long pfn; #ifdef CONFIG_SPARSEMEM_EXTREME if (unlikely(!mem_section)) { unsigned long size, align; size = sizeof(struct mem_section*) * NR_SECTION_ROOTS; align = 1 << (INTERNODE_CACHE_SHIFT); mem_section = memblock_virt_alloc(size, align); } #endif start &= PAGE_SECTION_MASK; mminit_validate_memmodel_limits(&start, &end); for (pfn = start; pfn < end; pfn += PAGES_PER_SECTION) { unsigned long section = pfn_to_section_nr(pfn); struct mem_section *ms; sparse_index_init(section, nid); set_section_nid(section, nid); ms = __nr_to_section(section); if (!ms->section_mem_map) { ms->section_mem_map = sparse_encode_early_nid(nid) | SECTION_IS_ONLINE; section_mark_present(ms); } } }

Contributors

PersonTokensPropCommitsCommitProp
Andy Whitcroft4930.82%333.33%
Kirill A. Shutemov4830.19%111.11%
Mel Gorman2918.24%111.11%
Bob Picco2314.47%111.11%
Dave Hansen74.40%111.11%
Michal Hocko21.26%111.11%
Baoquan He10.63%111.11%
Total159100.00%9100.00%

/* * Subtle, we encode the real pfn into the mem_map such that * the identity pfn - section_mem_map will return the actual * physical page frame number. */
static unsigned long sparse_encode_mem_map(struct page *mem_map, unsigned long pnum) { unsigned long coded_mem_map = (unsigned long)(mem_map - (section_nr_to_pfn(pnum))); BUILD_BUG_ON(SECTION_MAP_LAST_BIT > (1UL<<PFN_SECTION_SHIFT)); BUG_ON(coded_mem_map & ~SECTION_MAP_MASK); return coded_mem_map; }

Contributors

PersonTokensPropCommitsCommitProp
Andy Whitcroft3154.39%266.67%
Petr Tesarik2645.61%133.33%
Total57100.00%3100.00%

/* * Decode mem_map from the coded memmap */
struct page *sparse_decode_mem_map(unsigned long coded_mem_map, unsigned long pnum) { /* mask off the extra low bits of information */ coded_mem_map &= SECTION_MAP_MASK; return ((struct page *)coded_mem_map) + section_nr_to_pfn(pnum); }

Contributors

PersonTokensPropCommitsCommitProp
Andy Whitcroft1954.29%266.67%
Badari Pulavarty1645.71%133.33%
Total35100.00%3100.00%


static int __meminit sparse_init_one_section(struct mem_section *ms, unsigned long pnum, struct page *mem_map, unsigned long *pageblock_bitmap) { if (!present_section(ms)) return -EINVAL; ms->section_mem_map &= ~SECTION_MAP_MASK; ms->section_mem_map |= sparse_encode_mem_map(mem_map, pnum) | SECTION_HAS_MEM_MAP; ms->pageblock_flags = pageblock_bitmap; return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Andy Whitcroft5582.09%466.67%
Mel Gorman1116.42%116.67%
Yasunori Goto11.49%116.67%
Total67100.00%6100.00%


unsigned long usemap_size(void) { return BITS_TO_LONGS(SECTION_BLOCKFLAGS_BITS) * sizeof(unsigned long); }

Contributors

PersonTokensPropCommitsCommitProp
Mel Gorman1785.00%150.00%
Wei Yang315.00%150.00%
Total20100.00%2100.00%

#ifdef CONFIG_MEMORY_HOTPLUG
static unsigned long *__kmalloc_section_usemap(void) { return kmalloc(usemap_size(), GFP_KERNEL); }

Contributors

PersonTokensPropCommitsCommitProp
Mel Gorman19100.00%1100.00%
Total19100.00%1100.00%

#endif /* CONFIG_MEMORY_HOTPLUG */ #ifdef CONFIG_MEMORY_HOTREMOVE
static unsigned long * __init sparse_early_usemaps_alloc_pgdat_section(struct pglist_data *pgdat, unsigned long size) { unsigned long goal, limit; unsigned long *p; int nid; /* * A page may contain usemaps for other sections preventing the * page being freed and making a section unremovable while * other sections referencing the usemap remain active. Similarly, * a pgdat can prevent a section being removed. If section A * contains a pgdat and section B contains the usemap, both * sections become inter-dependent. This allocates usemaps * from the same section as the pgdat where possible to avoid * this problem. */ goal = __pa(pgdat) & (PAGE_SECTION_MASK << PAGE_SHIFT); limit = goal + (1UL << PA_SECTION_SHIFT); nid = early_pfn_to_nid(goal >> PAGE_SHIFT); again: p = memblock_virt_alloc_try_nid_nopanic(size, SMP_CACHE_BYTES, goal, limit, nid); if (!p && limit) { limit = 0; goto again; } return p; }

Contributors

PersonTokensPropCommitsCommitProp
Yinghai Lu5453.47%342.86%
Yasunori Goto2827.72%114.29%
Johannes Weiner1514.85%114.29%
Santosh Shilimkar32.97%114.29%
Li Zhong10.99%114.29%
Total101100.00%7100.00%


static void __init check_usemap_section_nr(int nid, unsigned long *usemap) { unsigned long usemap_snr, pgdat_snr; static unsigned long old_usemap_snr; static unsigned long old_pgdat_snr; struct pglist_data *pgdat = NODE_DATA(nid); int usemap_nid; /* First call */ if (!old_usemap_snr) { old_usemap_snr = NR_MEM_SECTIONS; old_pgdat_snr = NR_MEM_SECTIONS; } usemap_snr = pfn_to_section_nr(__pa(usemap) >> PAGE_SHIFT); pgdat_snr = pfn_to_section_nr(__pa(pgdat) >> PAGE_SHIFT); if (usemap_snr == pgdat_snr) return; if (old_usemap_snr == usemap_snr && old_pgdat_snr == pgdat_snr) /* skip redundant message */ return; old_usemap_snr = usemap_snr; old_pgdat_snr = pgdat_snr; usemap_nid = sparse_early_nid(__nr_to_section(usemap_snr)); if (usemap_nid != nid) { pr_info("node %d must be removed before remove section %ld\n", nid, usemap_snr); return; } /* * There is a circular dependency. * Some platforms allow un-removable section because they will just * gather other removable sections for dynamic partitioning. * Just notify un-removable section's number here. */ pr_info("Section %ld and %ld (node %d) have a circular dependency on usemap and pgdat allocations\n", usemap_snr, pgdat_snr, nid); }

Contributors

PersonTokensPropCommitsCommitProp
Yasunori Goto13287.42%133.33%
Kirill A. Shutemov1610.60%133.33%
Joe Perches31.99%133.33%
Total151100.00%3100.00%

#else
static unsigned long * __init sparse_early_usemaps_alloc_pgdat_section(struct pglist_data *pgdat, unsigned long size) { return memblock_virt_alloc_node_nopanic(size, pgdat->node_id); }

Contributors

PersonTokensPropCommitsCommitProp
Yasunori Goto1553.57%125.00%
Santosh Shilimkar517.86%125.00%
Johannes Weiner414.29%125.00%
Yinghai Lu414.29%125.00%
Total28100.00%4100.00%


static void __init check_usemap_section_nr(int nid, unsigned long *usemap) { }

Contributors

PersonTokensPropCommitsCommitProp
Yasunori Goto14100.00%1100.00%
Total14100.00%1100.00%

#endif /* CONFIG_MEMORY_HOTREMOVE */
static void __init sparse_early_usemaps_alloc_node(void *data, unsigned long pnum_begin, unsigned long pnum_end, unsigned long usemap_count, int nodeid) { void *usemap; unsigned long pnum; unsigned long **usemap_map = (unsigned long **)data; int size = usemap_size(); usemap = sparse_early_usemaps_alloc_pgdat_section(NODE_DATA(nodeid), size * usemap_count); if (!usemap) { pr_warn("%s: allocation failed\n", __func__); return; } for (pnum = pnum_begin; pnum < pnum_end; pnum++) { if (!present_section_nr(pnum)) continue; usemap_map[pnum] = usemap; usemap += size; check_usemap_section_nr(nodeid, usemap_map[pnum]); } }

Contributors

PersonTokensPropCommitsCommitProp
Yinghai Lu6953.91%112.50%
Mel Gorman2015.62%112.50%
Wanpeng Li1612.50%112.50%
Yasunori Goto129.38%225.00%
Nishanth Aravamudan97.03%112.50%
Andrew Morton10.78%112.50%
Joe Perches10.78%112.50%
Total128100.00%8100.00%

#ifndef CONFIG_SPARSEMEM_VMEMMAP
struct page __init *sparse_mem_map_populate(unsigned long pnum, int nid, struct vmem_altmap *altmap) { struct page *map; unsigned long size; size = PAGE_ALIGN(sizeof(struct page) * PAGES_PER_SECTION); map = memblock_virt_alloc_try_nid(size, PAGE_SIZE, __pa(MAX_DMA_ADDRESS), BOOTMEM_ALLOC_ACCESSIBLE, nid); return map; }

Contributors

PersonTokensPropCommitsCommitProp
Andy Whitcroft2438.10%222.22%
Yinghai Lu1726.98%111.11%
Christoph Lameter711.11%111.11%
Santosh Shilimkar57.94%111.11%
Yasunori Goto57.94%333.33%
Christoph Hellwig57.94%111.11%
Total63100.00%9100.00%


void __init sparse_mem_maps_populate_node(struct page **map_map, unsigned long pnum_begin, unsigned long pnum_end, unsigned long map_count, int nodeid) { void *map; unsigned long pnum; unsigned long size = sizeof(struct page) * PAGES_PER_SECTION; size = PAGE_ALIGN(size); map = memblock_virt_alloc_try_nid_raw(size * map_count, PAGE_SIZE, __pa(MAX_DMA_ADDRESS), BOOTMEM_ALLOC_ACCESSIBLE, nodeid); if (map) { for (pnum = pnum_begin; pnum < pnum_end; pnum++) { if (!present_section_nr(pnum)) continue; map_map[pnum] = map; map += size; } return; } /* fallback */ for (pnum = pnum_begin; pnum < pnum_end; pnum++) { struct mem_section *ms; if (!present_section_nr(pnum)) continue; map_map[pnum] = sparse_mem_map_populate(pnum, nodeid, NULL); if (map_map[pnum]) continue; ms = __nr_to_section(pnum); pr_err("%s: sparsemem memory map backing failed some memory will not be available\n", __func__); ms->section_mem_map = 0; } }

Contributors

PersonTokensPropCommitsCommitProp
Yinghai Lu17995.21%233.33%
Santosh Shilimkar42.13%116.67%
Christoph Hellwig21.06%116.67%
Joe Perches21.06%116.67%
Pavel Tatashin10.53%116.67%
Total188100.00%6100.00%

#endif /* !CONFIG_SPARSEMEM_VMEMMAP */ #ifdef CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER
static void __init sparse_early_mem_maps_alloc_node(void *data, unsigned long pnum_begin, unsigned long pnum_end, unsigned long map_count, int nodeid) { struct page **map_map = (struct page **)data; sparse_mem_maps_populate_node(map_map, pnum_begin, pnum_end, map_count, nodeid); }

Contributors

PersonTokensPropCommitsCommitProp
Yinghai Lu3769.81%150.00%
Wanpeng Li1630.19%150.00%
Total53100.00%2100.00%

#else
static struct page __init *sparse_early_mem_map_alloc(unsigned long pnum) { struct page *map; struct mem_section *ms = __nr_to_section(pnum); int nid = sparse_early_nid(ms); map = sparse_mem_map_populate(pnum, nid, NULL); if (map) return map; pr_err("%s: sparsemem memory map backing failed some memory will not be available\n", __func__); ms->section_mem_map = 0; return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Lameter4260.00%111.11%
Andy Whitcroft1927.14%222.22%
Christoph Hellwig22.86%111.11%
Bob Picco22.86%111.11%
Joe Perches22.86%111.11%
Yasunori Goto11.43%111.11%
Adrian Bunk11.43%111.11%
Harvey Harrison11.43%111.11%
Total70100.00%9100.00%

#endif
void __weak __meminit vmemmap_populate_print_last(void) { }

Contributors

PersonTokensPropCommitsCommitProp
Yinghai Lu562.50%150.00%
Gideon Israel Dsouza337.50%150.00%
Total8100.00%2100.00%

/** * alloc_usemap_and_memmap - memory alloction for pageblock flags and vmemmap * @map: usemap_map for pageblock flags or mmap_map for vmemmap */
static void __init alloc_usemap_and_memmap(void (*alloc_func) (void *, unsigned long, unsigned long, unsigned long, int), void *data) { unsigned long pnum; unsigned long map_count; int nodeid_begin = 0; unsigned long pnum_begin = 0; for_each_present_section_nr(0, pnum) { struct mem_section *ms; ms = __nr_to_section(pnum); nodeid_begin = sparse_early_nid(ms); pnum_begin = pnum; break; } map_count = 1; for_each_present_section_nr(pnum_begin + 1, pnum) { struct mem_section *ms; int nodeid; ms = __nr_to_section(pnum); nodeid = sparse_early_nid(ms); if (nodeid == nodeid_begin) { map_count++; continue; } /* ok, we need to take cake of from pnum_begin to pnum - 1*/ alloc_func(data, pnum_begin, pnum, map_count, nodeid_begin); /* new start, update count etc*/ nodeid_begin = nodeid; pnum_begin = pnum; map_count = 1; } /* ok, last chunk */ alloc_func(data, pnum_begin, __highest_present_section_nr+1, map_count, nodeid_begin); }

Contributors

PersonTokensPropCommitsCommitProp
Yinghai Lu10862.43%228.57%
Wanpeng Li3620.81%114.29%
Stephen Rothwell137.51%114.29%
Dave Hansen116.36%114.29%
Wei Yang31.73%114.29%
Mel Gorman21.16%114.29%
Total173100.00%7100.00%

/* * Allocate the accumulated non-linear sections, allocate a mem_map * for each and record the physical to section mapping. */
void __init sparse_init(void) { unsigned long pnum; struct page *map; unsigned long *usemap; unsigned long **usemap_map; int size; #ifdef CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER int size2; struct page **map_map; #endif /* see include/linux/mmzone.h 'struct mem_section' definition */ BUILD_BUG_ON(!is_power_of_2(sizeof(struct mem_section))); /* Setup pageblock_order for HUGETLB_PAGE_SIZE_VARIABLE */ set_pageblock_order(); /* * map is using big page (aka 2M in x86 64 bit) * usemap is less one page (aka 24 bytes) * so alloc 2M (with 2M align) and 24 bytes in turn will * make next 2M slip to one more 2M later. * then in big system, the memory will have a lot of holes... * here try to allocate 2M pages continuously. * * powerpc need to call sparse_init_one_section right after each * sparse_early_mem_map_alloc, so allocate usemap_map at first. */ size = sizeof(unsigned long *) * NR_MEM_SECTIONS; usemap_map = memblock_virt_alloc(size, 0); if (!usemap_map) panic("can not allocate usemap_map\n"); alloc_usemap_and_memmap(sparse_early_usemaps_alloc_node, (void *)usemap_map); #ifdef CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER size2 = sizeof(struct page *) * NR_MEM_SECTIONS; map_map = memblock_virt_alloc(size2, 0); if (!map_map) panic("can not allocate map_map\n"); alloc_usemap_and_memmap(sparse_early_mem_maps_alloc_node, (void *)map_map); #endif for_each_present_section_nr(0, pnum) { usemap = usemap_map[pnum]; if (!usemap) continue; #ifdef CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER map = map_map[pnum]; #else map = sparse_early_mem_map_alloc(pnum); #endif if (!map) continue; sparse_init_one_section(__nr_to_section(pnum), pnum, map, usemap); } vmemmap_populate_print_last(); #ifdef CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER memblock_free_early(__pa(map_map), size2); #endif memblock_free_early(__pa(usemap_map), size); }

Contributors

PersonTokensPropCommitsCommitProp
Yinghai Lu10543.57%337.50%
Wanpeng Li9639.83%112.50%
Stephen Rothwell145.81%112.50%
Mel Gorman135.39%112.50%
Santosh Shilimkar83.32%112.50%
Dave Hansen52.07%112.50%
Total241100.00%8100.00%

#ifdef CONFIG_MEMORY_HOTPLUG /* Mark all memory sections within the pfn range as online */
void online_mem_sections(unsigned long start_pfn, unsigned long end_pfn) { unsigned long pfn; for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) { unsigned long section_nr = pfn_to_section_nr(pfn); struct mem_section *ms; /* onlining code should never touch invalid ranges */ if (WARN_ON(!valid_section_nr(section_nr))) continue; ms = __nr_to_section(section_nr); ms->section_mem_map |= SECTION_IS_ONLINE; } }

Contributors

PersonTokensPropCommitsCommitProp
Michal Hocko73100.00%2100.00%
Total73100.00%2100.00%

#ifdef CONFIG_MEMORY_HOTREMOVE /* Mark all memory sections within the pfn range as online */
void offline_mem_sections(unsigned long start_pfn, unsigned long end_pfn) { unsigned long pfn; for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) { unsigned long section_nr = pfn_to_section_nr(pfn); struct mem_section *ms; /* * TODO this needs some double checking. Offlining code makes * sure to check pfn_valid but those checks might be just bogus */ if (WARN_ON(!valid_section_nr(section_nr))) continue; ms = __nr_to_section(section_nr); ms->section_mem_map &= ~SECTION_IS_ONLINE; } }

Contributors

PersonTokensPropCommitsCommitProp
Michal Hocko7398.65%150.00%
Pavel Tatashin11.35%150.00%
Total74100.00%2100.00%

#endif #ifdef CONFIG_SPARSEMEM_VMEMMAP
static inline struct page *kmalloc_section_memmap(unsigned long pnum, int nid, struct vmem_altmap *altmap) { /* This will make the necessary allocations eventually. */ return sparse_mem_map_populate(pnum, nid, altmap); }

Contributors

PersonTokensPropCommitsCommitProp
Yasunori Goto2578.12%150.00%
Christoph Hellwig721.88%150.00%
Total32100.00%2100.00%


static void __kfree_section_memmap(struct page *memmap, struct vmem_altmap *altmap) { unsigned long start = (unsigned long)memmap; unsigned long end = (unsigned long)(memmap + PAGES_PER_SECTION); vmemmap_free(start, end, altmap); }

Contributors

PersonTokensPropCommitsCommitProp
Johannes Weiner2653.06%120.00%
Yasunori Goto1122.45%120.00%
Christoph Hellwig714.29%120.00%
Tang Chen48.16%120.00%
Zhang Yanfei12.04%120.00%
Total49100.00%5100.00%

#ifdef CONFIG_MEMORY_HOTREMOVE
static void free_map_bootmem(struct page *memmap) { unsigned long start = (unsigned long)memmap; unsigned long end = (unsigned long)(memmap + PAGES_PER_SECTION); vmemmap_free(start, end, NULL); }

Contributors

PersonTokensPropCommitsCommitProp
Johannes Weiner2659.09%116.67%
Yasunori Goto818.18%116.67%
Tang Chen613.64%116.67%
Christoph Hellwig24.55%116.67%
Zhang Yanfei12.27%116.67%
Jianguo Wu12.27%116.67%
Total44100.00%6100.00%

#endif /* CONFIG_MEMORY_HOTREMOVE */ #else
static struct page *__kmalloc_section_memmap(void) { struct page *page, *ret; unsigned long memmap_size = sizeof(struct page) * PAGES_PER_SECTION; page = alloc_pages(GFP_KERNEL|__GFP_NOWARN, get_order(memmap_size)); if (page) goto got_map_page; ret = vmalloc(memmap_size); if (ret) goto got_map_ptr; return NULL; got_map_page: ret = (struct page *)pfn_to_kaddr(page_to_pfn(page)); got_map_ptr: return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Dave Hansen8695.56%133.33%
Zhang Yanfei22.22%133.33%
Yasunori Goto22.22%133.33%
Total90100.00%3100.00%


static inline struct page *kmalloc_section_memmap(unsigned long pnum, int nid, struct vmem_altmap *altmap) { return __kmalloc_section_memmap(); }

Contributors

PersonTokensPropCommitsCommitProp
Yasunori Goto1976.00%133.33%
Christoph Hellwig520.00%133.33%
Zhang Yanfei14.00%133.33%
Total25100.00%3100.00%


static void __kfree_section_memmap(struct page *memmap, struct vmem_altmap *altmap) { if (is_vmalloc_addr(memmap)) vfree(memmap); else free_pages((unsigned long)memmap, get_order(sizeof(struct page) * PAGES_PER_SECTION)); }

Contributors

PersonTokensPropCommitsCommitProp
Dave Hansen4285.71%125.00%
Christoph Hellwig510.20%125.00%
Zhang Yanfei12.04%125.00%
Christoph Lameter12.04%125.00%
Total49100.00%4100.00%

#ifdef CONFIG_MEMORY_HOTREMOVE
static void free_map_bootmem(struct page *memmap) { unsigned long maps_section_nr, removing_section_nr, i; unsigned long magic, nr_pages; struct page *page = virt_to_page(memmap); nr_pages = PAGE_ALIGN(PAGES_PER_SECTION * sizeof(struct page)) >> PAGE_SHIFT; for (i = 0; i < nr_pages; i++, page++) { magic = (unsigned long) page->freelist; BUG_ON(magic == NODE_INFO); maps_section_nr = pfn_to_section_nr(page_to_pfn(page)); removing_section_nr = page_private(page); /* * When this function is called, the removing section is * logical offlined state. This means all pages are isolated * from page allocator. If removing section's memmap is placed * on the same section, it must not be freed. * If it is freed, page allocator may allocate it which will * be removed physically soon. */ if (maps_section_nr != removing_section_nr) put_page_bootmem(page); } }

Contributors

PersonTokensPropCommitsCommitProp
Yasunori Goto7666.67%116.67%
Zhang Yanfei1714.91%116.67%
Jianguo Wu119.65%116.67%
Andrea Arcangeli65.26%116.67%
Yasuaki Ishimatsu43.51%233.33%
Total114100.00%6100.00%

#endif /* CONFIG_MEMORY_HOTREMOVE */ #endif /* CONFIG_SPARSEMEM_VMEMMAP */ /* * returns the number of sections whose mem_maps were properly * set. If this is <=0, then that means that the passed-in * map was not consumed and must be freed. */
int __meminit sparse_add_one_section(struct pglist_data *pgdat, unsigned long start_pfn, struct vmem_altmap *altmap) { unsigned long section_nr = pfn_to_section_nr(start_pfn); struct mem_section *ms; struct page *memmap; unsigned long *usemap; unsigned long flags; int ret; /* * no locking for this, because it does its own * plus, it does a kmalloc */ ret = sparse_index_init(section_nr, pgdat->node_id); if (ret < 0 && ret != -EEXIST) return ret; memmap = kmalloc_section_memmap(section_nr, pgdat->node_id, altmap); if (!memmap) return -ENOMEM; usemap = __kmalloc_section_usemap(); if (!usemap) { __kfree_section_memmap(memmap, altmap); return -ENOMEM; } pgdat_resize_lock(pgdat, &flags); ms = __pfn_to_section(start_pfn); if (ms->section_mem_map & SECTION_MARKED_PRESENT) { ret = -EEXIST; goto out; } #ifdef CONFIG_DEBUG_VM /* * Poison uninitialized struct pages in order to catch invalid flags * combinations. */ memset(memmap, PAGE_POISON_PATTERN, sizeof(struct page) * PAGES_PER_SECTION); #endif section_mark_present(ms); ret = sparse_init_one_section(ms, section_nr, memmap, usemap); out: pgdat_resize_unlock(pgdat, &flags); if (ret <= 0) { kfree(usemap); __kfree_section_memmap(memmap, altmap); } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Dave Hansen8135.68%214.29%
Américo Wang4821.15%17.14%
Andy Whitcroft3515.42%17.14%
Wen Congyang135.73%17.14%
Mel Gorman125.29%17.14%
Christoph Hellwig114.85%214.29%
Mike Kravetz104.41%17.14%
Pavel Tatashin73.08%17.14%
Yasunori Goto62.64%17.14%
Michal Hocko20.88%17.14%
Zhang Yanfei10.44%17.14%
Al Viro10.44%17.14%
Total227100.00%14100.00%

#ifdef CONFIG_MEMORY_HOTREMOVE #ifdef CONFIG_MEMORY_FAILURE
static void clear_hwpoisoned_pages(struct page *memmap, int nr_pages) { int i; if (!memmap) return; for (i = 0; i < nr_pages; i++) { if (PageHWPoison(&memmap[i])) { atomic_long_sub(1, &num_poisoned_pages); ClearPageHWPoison(&memmap[i]); } } }

Contributors

PersonTokensPropCommitsCommitProp
Wen Congyang6697.06%133.33%
Xishi Qiu11.47%133.33%
Dan J Williams11.47%133.33%
Total68100.00%3100.00%

#else
static inline void clear_hwpoisoned_pages(struct page *memmap, int nr_pages) { }

Contributors

PersonTokensPropCommitsCommitProp
Wen Congyang14100.00%1100.00%
Total14100.00%1100.00%

#endif
static void free_section_usemap(struct page *memmap, unsigned long *usemap, struct vmem_altmap *altmap) { struct page *usemap_page; if (!usemap) return; usemap_page = virt_to_page(usemap); /* * Check to see if allocation came from hot-plug-add */ if (PageSlab(usemap_page) || PageCompound(usemap_page)) { kfree(usemap); if (memmap) __kfree_section_memmap(memmap, altmap); return; } /* * The usemap came from bootmem. This is packed with other usemaps * on the section which has pgdat at boot time. Just keep it as is now. */ if (memmap) free_map_bootmem(memmap); }

Contributors

PersonTokensPropCommitsCommitProp
David Rientjes7491.36%150.00%
Christoph Hellwig78.64%150.00%
Total81100.00%2100.00%


void sparse_remove_one_section(struct zone *zone, struct mem_section *ms, unsigned long map_offset, struct vmem_altmap *altmap) { struct page *memmap = NULL; unsigned long *usemap = NULL, flags; struct pglist_data *pgdat = zone->zone_pgdat; pgdat_resize_lock(pgdat, &flags); if (ms->section_mem_map) { usemap = ms->pageblock_flags; memmap = sparse_decode_mem_map(ms->section_mem_map, __section_nr(ms)); ms->section_mem_map = 0; ms->pageblock_flags = NULL; } pgdat_resize_unlock(pgdat, &flags); clear_hwpoisoned_pages(memmap + map_offset, PAGES_PER_SECTION - map_offset); free_section_usemap(memmap, usemap, altmap); }

Contributors

PersonTokensPropCommitsCommitProp
Badari Pulavarty7660.80%120.00%
Tang Chen2721.60%120.00%
Dan J Williams86.40%120.00%
Christoph Hellwig75.60%120.00%
Wen Congyang75.60%120.00%
Total125100.00%5100.00%

#endif /* CONFIG_MEMORY_HOTREMOVE */ #endif /* CONFIG_MEMORY_HOTPLUG */

Overall Contributors

PersonTokensPropCommitsCommitProp
Yinghai Lu58517.28%88.60%
Dave Hansen46713.80%44.30%
Yasunori Goto37711.14%88.60%
Andy Whitcroft3389.99%66.45%
Mel Gorman2086.14%22.15%
Wanpeng Li1664.90%11.08%
Michal Hocko1574.64%33.23%
Christoph Lameter1163.43%33.23%
Wen Congyang1073.16%22.15%
Badari Pulavarty932.75%11.08%
Bob Picco922.72%22.15%
David Rientjes912.69%11.08%
Johannes Weiner712.10%22.15%
Kirill A. Shutemov692.04%22.15%
Christoph Hellwig601.77%22.15%
Américo Wang571.68%22.15%
Tang Chen371.09%22.15%
Mike Kravetz300.89%33.23%
Stephen Rothwell300.89%11.08%
Zhou Chengming300.89%11.08%
Zhang Yanfei280.83%44.30%
Santosh Shilimkar280.83%11.08%
Petr Tesarik260.77%11.08%
Ingo Molnar180.53%11.08%
Fabian Frederick140.41%11.08%
Jianguo Wu120.35%11.08%
Dan J Williams90.27%11.08%
Pavel Tatashin90.27%33.23%
Nishanth Aravamudan90.27%11.08%
Joe Perches80.24%11.08%
Wei Yang70.21%33.23%
Andrea Arcangeli60.18%11.08%
Gideon Israel Dsouza60.18%11.08%
Gavin Shan50.15%22.15%
Yasuaki Ishimatsu40.12%22.15%
Tejun Heo30.09%11.08%
Harvey Harrison10.03%11.08%
Ravikiran G. Thirumalai10.03%11.08%
Xishi Qiu10.03%11.08%
Baoquan He10.03%11.08%
Li Zhong10.03%11.08%
Andrew Morton10.03%11.08%
Al Viro10.03%11.08%
Ian Campbell10.03%11.08%
Greg Kroah-Hartman10.03%11.08%
Cyrill V. Gorcunov10.03%11.08%
Adrian Bunk10.03%11.08%
Paul Gortmaker10.03%11.08%
Total3385100.00%93100.00%
Directory: mm
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.