cregit-Linux how code gets into the kernel

Release 4.11 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 Lameter1890.00%133.33%
Andy Whitcroft15.00%133.33%
Ian Campbell15.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()) { 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 Picco3350.77%228.57%
Dave Hansen2030.77%114.29%
Américo Wang913.85%114.29%
Zhang Yanfei11.54%114.29%
Fabian Frederick11.54%114.29%
Yasunori 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 Hansen1694.12%150.00%
Bob 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 Hansen7787.50%133.33%
Gavin Shan77.95%133.33%
Mike 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 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%

/* 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 Whitcroft5149.51%466.67%
Mel Gorman2928.16%116.67%
Bob 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 Whitcroft7489.16%266.67%
Mel 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 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 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) { 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 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 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 = 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 Goto13697.84%150.00%
Joe 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 Goto1553.57%125.00%
Santosh Shilimkar517.86%125.00%
Yinghai Lu414.29%125.00%
Johannes Weiner414.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%
Joe Perches10.78%112.50%
Andrew 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 Whitcroft4657.50%225.00%
Yinghai Lu1721.25%112.50%
Christoph Lameter78.75%112.50%
Yasunori Goto56.25%337.50%
Santosh Shilimkar56.25%112.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 Lu23297.07%250.00%
Santosh Shilimkar52.09%125.00%
Joe 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 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); 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 Lameter4261.76%112.50%
Andy Whitcroft1927.94%225.00%
Bob Picco22.94%112.50%
Joe Perches22.94%112.50%
Yasunori Goto11.47%112.50%
Harvey Harrison11.47%112.50%
Adrian Bunk11.47%112.50%
Total68100.00%8100.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 (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 Lu13264.71%233.33%
Wanpeng Li3617.65%116.67%
Stephen Rothwell3316.18%116.67%
Mel Gorman20.98%116.67%
Andy 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 Lu12147.08%342.86%
Wanpeng Li9637.35%114.29%
Stephen Rothwell197.39%114.29%
Mel Gorman135.06%114.29%
Santosh 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 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 Weiner2661.90%125.00%
Yasunori Goto1126.19%125.00%
Tang Chen49.52%125.00%
Zhang 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 Weiner2661.90%120.00%
Yasunori Goto819.05%120.00%
Tang Chen614.29%120.00%
Zhang Yanfei12.38%120.00%
Jianguo 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 Hansen8695.56%133.33%
Yasunori Goto22.22%133.33%
Zhang Yanfei22.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 Goto1995.00%150.00%
Zhang 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 Hansen4295.45%133.33%
Christoph Lameter12.27%133.33%
Zhang 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->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 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); if (!memmap) return -ENOMEM; usemap = __kmalloc_section_usemap(); if (!usemap) { __kfree_section_memmap(memmap); 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; } memset(memmap, 0, sizeof(struct page) * PAGES_PER_SECTION); ms->section_mem_map |= SECTION_MARKED_PRESENT; 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); } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Dave Hansen8840.00%111.11%
Américo Wang4821.82%111.11%
Andy Whitcroft4018.18%111.11%
Wen Congyang146.36%111.11%
Mel Gorman125.45%111.11%
Mike Kravetz104.55%111.11%
Yasunori Goto62.73%111.11%
Al Viro10.45%111.11%
Zhang Yanfei10.45%111.11%
Total220100.00%9100.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 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); 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 Rientjes74100.00%1100.00%
Total74100.00%1100.00%


void sparse_remove_one_section(struct zone *zone, struct mem_section *ms, unsigned long map_offset) { 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); }

Contributors

PersonTokensPropCommitsCommitProp
Badari Pulavarty7664.41%125.00%
Tang Chen2722.88%125.00%
Dan J Williams86.78%125.00%
Wen Congyang75.93%125.00%
Total118100.00%4100.00%

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

Overall Contributors

PersonTokensPropCommitsCommitProp
Yinghai Lu67820.91%810.39%
Andy Whitcroft44413.69%67.79%
Yasunori Goto38211.78%810.39%
Dave Hansen36411.22%33.90%
Mel Gorman2397.37%22.60%
Wanpeng Li1665.12%11.30%
Christoph Lameter1163.58%33.90%
Wen Congyang1083.33%22.60%
Bob Picco952.93%22.60%
Badari Pulavarty932.87%11.30%
David Rientjes902.78%11.30%
Johannes Weiner712.19%22.60%
Américo Wang571.76%22.60%
Stephen Rothwell551.70%11.30%
Tang Chen371.14%22.60%
Mike Kravetz300.93%33.90%
Zhou Chengming300.93%11.30%
Santosh Shilimkar290.89%11.30%
Zhang Yanfei280.86%45.19%
David Shaohua Li200.62%11.30%
Ingo Molnar180.56%11.30%
Fabian Frederick140.43%11.30%
Jianguo Wu120.37%11.30%
Gavin Shan110.34%22.60%
Nishanth Aravamudan90.28%11.30%
Dan J Williams90.28%11.30%
Joe Perches80.25%11.30%
Andrea Arcangeli60.19%11.30%
Gideon Israel Dsouza60.19%11.30%
Yasuaki Ishimatsu40.12%22.60%
Tejun Heo30.09%11.30%
Ravikiran G. Thirumalai20.06%11.30%
Xishi Qiu10.03%11.30%
Cyrill V. Gorcunov10.03%11.30%
Andrew Morton10.03%11.30%
Harvey Harrison10.03%11.30%
Ian Campbell10.03%11.30%
Paul Gortmaker10.03%11.30%
Al Viro10.03%11.30%
Li Zhong10.03%11.30%
Adrian Bunk10.03%11.30%
Total3243100.00%77100.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.