diff options
Diffstat (limited to 'mm/sparse.c')
-rw-r--r-- | mm/sparse.c | 53 |
1 files changed, 41 insertions, 12 deletions
diff --git a/mm/sparse.c b/mm/sparse.c index fa01292157a9..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 | /* |
@@ -22,27 +23,55 @@ struct mem_section mem_section[NR_SECTION_ROOTS][SECTIONS_PER_ROOT] | |||
22 | #endif | 23 | #endif |
23 | EXPORT_SYMBOL(mem_section); | 24 | EXPORT_SYMBOL(mem_section); |
24 | 25 | ||
25 | static void sparse_alloc_root(unsigned long root, int nid) | ||
26 | { | ||
27 | #ifdef CONFIG_SPARSEMEM_EXTREME | 26 | #ifdef CONFIG_SPARSEMEM_EXTREME |
28 | mem_section[root] = alloc_bootmem_node(NODE_DATA(nid), PAGE_SIZE); | 27 | static struct mem_section *sparse_index_alloc(int nid) |
29 | #endif | 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; | ||
30 | } | 39 | } |
31 | 40 | ||
32 | static void sparse_index_init(unsigned long section, int nid) | 41 | static int sparse_index_init(unsigned long section_nr, int nid) |
33 | { | 42 | { |
34 | unsigned long root = SECTION_NR_TO_ROOT(section); | 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; | ||
35 | 47 | ||
36 | if (mem_section[root]) | 48 | if (mem_section[root]) |
37 | return; | 49 | return -EEXIST; |
38 | 50 | ||
39 | sparse_alloc_root(root, nid); | 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); | ||
40 | 57 | ||
41 | if (mem_section[root]) | 58 | if (mem_section[root]) { |
42 | memset(mem_section[root], 0, PAGE_SIZE); | 59 | ret = -EEXIST; |
43 | else | 60 | goto out; |
44 | panic("memory_present: NO MEMORY\n"); | 61 | } |
62 | |||
63 | mem_section[root] = section; | ||
64 | out: | ||
65 | spin_unlock(&index_init_lock); | ||
66 | return ret; | ||
45 | } | 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 | |||
46 | /* Record a memory area against a node. */ | 75 | /* Record a memory area against a node. */ |
47 | void memory_present(int nid, unsigned long start, unsigned long end) | 76 | void memory_present(int nid, unsigned long start, unsigned long end) |
48 | { | 77 | { |