cregit-Linux how code gets into the kernel

Release 4.8 mm/sparse.c

Directory: mm
/*
 * 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[NR_SECTION_ROOTS]
	
____cacheline_internodealigned_in_smp;
#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 lameterchristoph lameter1890.00%133.33%
ian campbellian campbell15.00%133.33%
andy whitcroftandy 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 whitcroftandy 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 whitcroftandy 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()) { if (node_state(nid, N_HIGH_MEMORY)) section = kzalloc_node(array_size, GFP_KERNEL, nid); else section = kzalloc(array_size, GFP_KERNEL); } 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 piccobob picco3350.77%228.57%
dave hansendave hansen2030.77%114.29%
americo wangamerico wang913.85%114.29%
fabian frederickfabian frederick11.54%114.29%
zhang yanfeizhang yanfei11.54%114.29%
yasunori gotoyasunori goto11.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 hansendave hansen1694.12%150.00%
bob piccobob picco15.88%150.00%
Total17100.00%2100.00%

#endif #ifdef CONFIG_SPARSEMEM_EXTREME
int __section_nr(struct mem_section* ms) { unsigned long root_nr; struct mem_section* root; 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_nr == NR_SECTION_ROOTS); return (root_nr * SECTIONS_PER_ROOT) + (ms - root); }

Contributors

PersonTokensPropCommitsCommitProp
dave hansendave hansen7787.50%133.33%
gavin shangavin shan77.95%133.33%
mike kravetzmike kravetz44.55%133.33%
Total88100.00%3100.00%

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

Contributors

PersonTokensPropCommitsCommitProp
zhou chengmingzhou 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 whitcroftandy 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 whitcroftandy 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 gormanmel gorman7771.96%125.00%
ingo molnaringo molnar1816.82%125.00%
andy whitcroftandy whitcroft1110.28%125.00%
cyrill gorcunovcyrill gorcunov10.93%125.00%
Total107100.00%4100.00%

/* Record a memory area against a node. */
void __init memory_present(int nid, unsigned long start, unsigned long end) { unsigned long pfn; 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_MARKED_PRESENT; } }

Contributors

PersonTokensPropCommitsCommitProp
andy whitcroftandy whitcroft5149.51%466.67%
mel gormanmel gorman2928.16%116.67%
bob piccobob picco2322.33%116.67%
Total103100.00%6100.00%

/* * Only used by the i386 NUMA architecures, but relatively * generic code. */
unsigned long __init node_memmap_size_bytes(int nid, unsigned long start_pfn, unsigned long end_pfn) { unsigned long pfn; unsigned long nr_pages = 0; mminit_validate_memmodel_limits(&start_pfn, &end_pfn); for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) { if (nid != early_pfn_to_nid(pfn)) continue; if (pfn_present(pfn)) nr_pages += PAGES_PER_SECTION; } return nr_pages * sizeof(struct page); }

Contributors

PersonTokensPropCommitsCommitProp
andy whitcroftandy whitcroft7489.16%266.67%
mel gormanmel gorman910.84%133.33%
Total83100.00%3100.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) { return (unsigned long)(mem_map - (section_nr_to_pfn(pnum))); }

Contributors

PersonTokensPropCommitsCommitProp
andy whitcroftandy whitcroft32100.00%2100.00%
Total32100.00%2100.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 whitcroftandy whitcroft1954.29%266.67%
badari pulavartybadari 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 whitcroftandy whitcroft5582.09%466.67%
mel gormanmel gorman1116.42%116.67%
yasunori gotoyasunori goto11.49%116.67%
Total67100.00%6100.00%


unsigned long usemap_size(void) { unsigned long size_bytes; size_bytes = roundup(SECTION_BLOCKFLAGS_BITS, 8) / 8; size_bytes = roundup(size_bytes, sizeof(unsigned long)); return size_bytes; }

Contributors

PersonTokensPropCommitsCommitProp
mel gormanmel gorman39100.00%1100.00%
Total39100.00%1100.00%

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

Contributors

PersonTokensPropCommitsCommitProp
mel gormanmel 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 luyinghai lu5453.47%342.86%
yasunori gotoyasunori goto2827.72%114.29%
johannes weinerjohannes weiner1514.85%114.29%
santosh shilimkarsantosh shilimkar32.97%114.29%
li zhongli 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 = NR_MEM_SECTIONS; static unsigned long old_pgdat_snr = NR_MEM_SECTIONS; struct pglist_data *pgdat = NODE_DATA(nid); int usemap_nid; 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 gotoyasunori goto13697.84%150.00%
joe perchesjoe perches32.16%150.00%
Total139100.00%2100.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 gotoyasunori goto1553.57%125.00%
santosh shilimkarsantosh shilimkar517.86%125.00%
yinghai luyinghai lu414.29%125.00%
johannes weinerjohannes weiner414.29%125.00%
Total28100.00%4100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
yasunori gotoyasunori 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 luyinghai lu6953.91%112.50%
mel gormanmel gorman2015.62%112.50%
wanpeng liwanpeng li1612.50%112.50%
yasunori gotoyasunori goto129.38%225.00%
nishanth aravamudannishanth aravamudan97.03%112.50%
joe perchesjoe perches10.78%112.50%
andrew mortonandrew morton10.78%112.50%
Total128100.00%8100.00%

#ifndef CONFIG_SPARSEMEM_VMEMMAP
struct page __init *sparse_mem_map_populate(unsigned long pnum, int nid) { struct page *map; unsigned long size; map = alloc_remap(nid, sizeof(struct page) * PAGES_PER_SECTION); if (map) return map; 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 whitcroftandy whitcroft4657.50%225.00%
yinghai luyinghai lu1721.25%112.50%
christoph lameterchristoph lameter78.75%112.50%
santosh shilimkarsantosh shilimkar56.25%112.50%
yasunori gotoyasunori goto56.25%337.50%
Total80100.00%8100.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; map = alloc_remap(nodeid, size * map_count); if (map) { for (pnum = pnum_begin; pnum < pnum_end; pnum++) { if (!present_section_nr(pnum)) continue; map_map[pnum] = map; map += size; } return; } size = PAGE_ALIGN(size); map = memblock_virt_alloc_try_nid(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); 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 luyinghai lu23297.07%250.00%
santosh shilimkarsantosh shilimkar52.09%125.00%
joe perchesjoe perches20.84%125.00%
Total239100.00%4100.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 luyinghai lu3769.81%150.00%
wanpeng liwanpeng 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); 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 lameterchristoph lameter4261.76%112.50%
andy whitcroftandy whitcroft1927.94%225.00%
joe perchesjoe perches22.94%112.50%
bob piccobob picco22.94%112.50%
harvey harrisonharvey harrison11.47%112.50%
yasunori gotoyasunori goto11.47%112.50%
adrian bunkadrian bunk11.47%112.50%
Total68100.00%8100.00%

#endif
void __weak __meminit vmemmap_populate_print_last(void) { }

Contributors

PersonTokensPropCommitsCommitProp
yinghai luyinghai lu562.50%150.00%
gideon israel dsouzagideon 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 (pnum = 0; pnum < NR_MEM_SECTIONS; pnum++) { struct mem_section *ms; if (!present_section_nr(pnum)) continue; ms = __nr_to_section(pnum); nodeid_begin = sparse_early_nid(ms); pnum_begin = pnum; break; } map_count = 1; for (pnum = pnum_begin + 1; pnum < NR_MEM_SECTIONS; pnum++) { struct mem_section *ms; int nodeid; if (!present_section_nr(pnum)) continue; 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, NR_MEM_SECTIONS, map_count, nodeid_begin); }

Contributors

PersonTokensPropCommitsCommitProp
yinghai luyinghai lu13264.71%233.33%
wanpeng liwanpeng li3617.65%116.67%
stephen rothwellstephen rothwell3316.18%116.67%
mel gormanmel gorman20.98%116.67%
andy whitcroftandy whitcroft10.49%116.67%
Total204100.00%6100.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 (pnum = 0; pnum < NR_MEM_SECTIONS; pnum++) { if (!present_section_nr(pnum)) continue; 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 luyinghai lu12147.08%342.86%
wanpeng liwanpeng li9637.35%114.29%
stephen rothwellstephen rothwell197.39%114.29%
mel gormanmel gorman135.06%114.29%
santosh shilimkarsantosh shilimkar83.11%114.29%
Total257100.00%7100.00%

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

Contributors

PersonTokensPropCommitsCommitProp
yasunori gotoyasunori goto25100.00%1100.00%
Total25100.00%1100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
johannes weinerjohannes weiner2661.90%125.00%
yasunori gotoyasunori goto1126.19%125.00%
tang chentang chen49.52%125.00%
zhang yanfeizhang yanfei12.38%125.00%
Total42100.00%4100.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); }

Contributors

PersonTokensPropCommitsCommitProp
johannes weinerjohannes weiner2661.90%120.00%
yasunori gotoyasunori goto819.05%120.00%
tang chentang chen614.29%120.00%
zhang yanfeizhang yanfei12.38%120.00%
jianguo wujianguo wu12.38%120.00%
Total42100.00%5100.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 hansendave hansen8695.56%133.33%
zhang yanfeizhang yanfei22.22%133.33%
yasunori gotoyasunori goto22.22%133.33%
Total90100.00%3100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
yasunori gotoyasunori goto1995.00%150.00%
zhang yanfeizhang yanfei15.00%150.00%
Total20100.00%2100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
dave hansendave hansen4295.45%133.33%
christoph lameterchristoph lameter12.27%133.33%
zhang yanfeizhang yanfei12.27%133.33%
Total44100.00%3100.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->lru.next; BUG_ON(magic == NODE_INFO); maps_section_nr = pfn_to_section_nr(page_to_pfn(page)); removing_section_nr = page->private; /* * 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 gotoyasunori goto7867.83%125.00%
zhang yanfeizhang yanfei1714.78%125.00%
jianguo wujianguo wu119.57%125.00%
andrea arcangeliandrea arcangeli97.83%125.00%
Total115100.00%4100.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 zone *zone, unsigned long start_pfn) { unsigned long section_nr = pfn_to_section_nr(start_pfn); struct pglist_data *pgdat = zone->zone_pgdat; 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