diff options
Diffstat (limited to 'mm/sparse.c')
-rw-r--r-- | mm/sparse.c | 75 |
1 files changed, 69 insertions, 6 deletions
diff --git a/mm/sparse.c b/mm/sparse.c index b54e304df4a7..347249a4917a 100644 --- a/mm/sparse.c +++ b/mm/sparse.c | |||
@@ -6,6 +6,7 @@ | |||
6 | #include <linux/mmzone.h> | 6 | #include <linux/mmzone.h> |
7 | #include <linux/bootmem.h> | 7 | #include <linux/bootmem.h> |
8 | #include <linux/module.h> | 8 | #include <linux/module.h> |
9 | #include <linux/spinlock.h> | ||
9 | #include <asm/dma.h> | 10 | #include <asm/dma.h> |
10 | 11 | ||
11 | /* | 12 | /* |
@@ -13,9 +14,64 @@ | |||
13 | * | 14 | * |
14 | * 1) mem_section - memory sections, mem_map's for valid memory | 15 | * 1) mem_section - memory sections, mem_map's for valid memory |
15 | */ | 16 | */ |
16 | struct mem_section mem_section[NR_MEM_SECTIONS]; | 17 | #ifdef CONFIG_SPARSEMEM_EXTREME |
18 | struct mem_section *mem_section[NR_SECTION_ROOTS] | ||
19 | ____cacheline_maxaligned_in_smp; | ||
20 | #else | ||
21 | struct mem_section mem_section[NR_SECTION_ROOTS][SECTIONS_PER_ROOT] | ||
22 | ____cacheline_maxaligned_in_smp; | ||
23 | #endif | ||
17 | EXPORT_SYMBOL(mem_section); | 24 | EXPORT_SYMBOL(mem_section); |
18 | 25 | ||
26 | #ifdef CONFIG_SPARSEMEM_EXTREME | ||
27 | static struct mem_section *sparse_index_alloc(int nid) | ||
28 | { | ||
29 | struct mem_section *section = NULL; | ||
30 | unsigned long array_size = SECTIONS_PER_ROOT * | ||
31 | sizeof(struct mem_section); | ||
32 | |||
33 | section = alloc_bootmem_node(NODE_DATA(nid), array_size); | ||
34 | |||
35 | if (section) | ||
36 | memset(section, 0, array_size); | ||
37 | |||
38 | return section; | ||
39 | } | ||
40 | |||
41 | static int sparse_index_init(unsigned long section_nr, int nid) | ||
42 | { | ||
43 | static spinlock_t index_init_lock = SPIN_LOCK_UNLOCKED; | ||
44 | unsigned long root = SECTION_NR_TO_ROOT(section_nr); | ||
45 | struct mem_section *section; | ||
46 | int ret = 0; | ||
47 | |||
48 | if (mem_section[root]) | ||
49 | return -EEXIST; | ||
50 | |||
51 | section = sparse_index_alloc(nid); | ||
52 | /* | ||
53 | * This lock keeps two different sections from | ||
54 | * reallocating for the same index | ||
55 | */ | ||
56 | spin_lock(&index_init_lock); | ||
57 | |||
58 | if (mem_section[root]) { | ||
59 | ret = -EEXIST; | ||
60 | goto out; | ||
61 | } | ||
62 | |||
63 | mem_section[root] = section; | ||
64 | out: | ||
65 | spin_unlock(&index_init_lock); | ||
66 | return ret; | ||
67 | } | ||
68 | #else /* !SPARSEMEM_EXTREME */ | ||
69 | static inline int sparse_index_init(unsigned long section_nr, int nid) | ||
70 | { | ||
71 | return 0; | ||
72 | } | ||
73 | #endif | ||
74 | |||
19 | /* Record a memory area against a node. */ | 75 | /* Record a memory area against a node. */ |
20 | void memory_present(int nid, unsigned long start, unsigned long end) | 76 | void memory_present(int nid, unsigned long start, unsigned long end) |
21 | { | 77 | { |
@@ -24,8 +80,13 @@ void memory_present(int nid, unsigned long start, unsigned long end) | |||
24 | start &= PAGE_SECTION_MASK; | 80 | start &= PAGE_SECTION_MASK; |
25 | for (pfn = start; pfn < end; pfn += PAGES_PER_SECTION) { | 81 | for (pfn = start; pfn < end; pfn += PAGES_PER_SECTION) { |
26 | unsigned long section = pfn_to_section_nr(pfn); | 82 | unsigned long section = pfn_to_section_nr(pfn); |
27 | if (!mem_section[section].section_mem_map) | 83 | struct mem_section *ms; |
28 | mem_section[section].section_mem_map = SECTION_MARKED_PRESENT; | 84 | |
85 | sparse_index_init(section, nid); | ||
86 | |||
87 | ms = __nr_to_section(section); | ||
88 | if (!ms->section_mem_map) | ||
89 | ms->section_mem_map = SECTION_MARKED_PRESENT; | ||
29 | } | 90 | } |
30 | } | 91 | } |
31 | 92 | ||
@@ -85,6 +146,7 @@ static struct page *sparse_early_mem_map_alloc(unsigned long pnum) | |||
85 | { | 146 | { |
86 | struct page *map; | 147 | struct page *map; |
87 | int nid = early_pfn_to_nid(section_nr_to_pfn(pnum)); | 148 | int nid = early_pfn_to_nid(section_nr_to_pfn(pnum)); |
149 | struct mem_section *ms = __nr_to_section(pnum); | ||
88 | 150 | ||
89 | map = alloc_remap(nid, sizeof(struct page) * PAGES_PER_SECTION); | 151 | map = alloc_remap(nid, sizeof(struct page) * PAGES_PER_SECTION); |
90 | if (map) | 152 | if (map) |
@@ -96,7 +158,7 @@ static struct page *sparse_early_mem_map_alloc(unsigned long pnum) | |||
96 | return map; | 158 | return map; |
97 | 159 | ||
98 | printk(KERN_WARNING "%s: allocation failed\n", __FUNCTION__); | 160 | printk(KERN_WARNING "%s: allocation failed\n", __FUNCTION__); |
99 | mem_section[pnum].section_mem_map = 0; | 161 | ms->section_mem_map = 0; |
100 | return NULL; | 162 | return NULL; |
101 | } | 163 | } |
102 | 164 | ||
@@ -114,8 +176,9 @@ void sparse_init(void) | |||
114 | continue; | 176 | continue; |
115 | 177 | ||
116 | map = sparse_early_mem_map_alloc(pnum); | 178 | map = sparse_early_mem_map_alloc(pnum); |
117 | if (map) | 179 | if (!map) |
118 | sparse_init_one_section(&mem_section[pnum], pnum, map); | 180 | continue; |
181 | sparse_init_one_section(__nr_to_section(pnum), pnum, map); | ||
119 | } | 182 | } |
120 | } | 183 | } |
121 | 184 | ||