aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTony Luck <tony.luck@intel.com>2015-06-24 19:58:12 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-06-24 20:49:45 -0400
commita3f5bafcc04aaf62990e0cf3ced1cc6d8dc6fe95 (patch)
treeadb288c0bf2cfbd6f40f0036f16a3a87f4f4ca06
parentfc6daaf93151877748f8096af6b3fddb147f22d6 (diff)
mm/memblock: allocate boot time data structures from mirrored memory
Try to allocate all boot time kernel data structures from mirrored memory. If we run out of mirrored memory print warnings, but fall back to using non-mirrored memory to make sure that we still boot. By number of bytes, most of what we allocate at boot time is the page structures. 64 bytes per 4K page on x86_64 ... or about 1.5% of total system memory. For workloads where the bulk of memory is allocated to applications this may represent a useful improvement to system availability since 1.5% of total memory might be a third of the memory allocated to the kernel. Signed-off-by: Tony Luck <tony.luck@intel.com> Cc: Xishi Qiu <qiuxishi@huawei.com> Cc: Hanjun Guo <guohanjun@huawei.com> Cc: Xiexiuqi <xiexiuqi@huawei.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: Yinghai Lu <yinghai@kernel.org> Cc: Naoya Horiguchi <nao.horiguchi@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--include/linux/memblock.h8
-rw-r--r--mm/memblock.c78
-rw-r--r--mm/nobootmem.c10
3 files changed, 84 insertions, 12 deletions
diff --git a/include/linux/memblock.h b/include/linux/memblock.h
index 7aeec0cb4c27..0215ffd63069 100644
--- a/include/linux/memblock.h
+++ b/include/linux/memblock.h
@@ -24,6 +24,7 @@
24enum { 24enum {
25 MEMBLOCK_NONE = 0x0, /* No special request */ 25 MEMBLOCK_NONE = 0x0, /* No special request */
26 MEMBLOCK_HOTPLUG = 0x1, /* hotpluggable region */ 26 MEMBLOCK_HOTPLUG = 0x1, /* hotpluggable region */
27 MEMBLOCK_MIRROR = 0x2, /* mirrored region */
27}; 28};
28 29
29struct memblock_region { 30struct memblock_region {
@@ -78,6 +79,8 @@ int memblock_reserve(phys_addr_t base, phys_addr_t size);
78void memblock_trim_memory(phys_addr_t align); 79void memblock_trim_memory(phys_addr_t align);
79int memblock_mark_hotplug(phys_addr_t base, phys_addr_t size); 80int memblock_mark_hotplug(phys_addr_t base, phys_addr_t size);
80int memblock_clear_hotplug(phys_addr_t base, phys_addr_t size); 81int memblock_clear_hotplug(phys_addr_t base, phys_addr_t size);
82int memblock_mark_mirror(phys_addr_t base, phys_addr_t size);
83ulong choose_memblock_flags(void);
81 84
82/* Low level functions */ 85/* Low level functions */
83int memblock_add_range(struct memblock_type *type, 86int memblock_add_range(struct memblock_type *type,
@@ -160,6 +163,11 @@ static inline bool movable_node_is_enabled(void)
160} 163}
161#endif 164#endif
162 165
166static inline bool memblock_is_mirror(struct memblock_region *m)
167{
168 return m->flags & MEMBLOCK_MIRROR;
169}
170
163#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP 171#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
164int memblock_search_pfn_nid(unsigned long pfn, unsigned long *start_pfn, 172int memblock_search_pfn_nid(unsigned long pfn, unsigned long *start_pfn,
165 unsigned long *end_pfn); 173 unsigned long *end_pfn);
diff --git a/mm/memblock.c b/mm/memblock.c
index b9ff2f4f0285..1b444c730846 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -54,10 +54,16 @@ int memblock_debug __initdata_memblock;
54#ifdef CONFIG_MOVABLE_NODE 54#ifdef CONFIG_MOVABLE_NODE
55bool movable_node_enabled __initdata_memblock = false; 55bool movable_node_enabled __initdata_memblock = false;
56#endif 56#endif
57static bool system_has_some_mirror __initdata_memblock = false;
57static int memblock_can_resize __initdata_memblock; 58static int memblock_can_resize __initdata_memblock;
58static int memblock_memory_in_slab __initdata_memblock = 0; 59static int memblock_memory_in_slab __initdata_memblock = 0;
59static int memblock_reserved_in_slab __initdata_memblock = 0; 60static int memblock_reserved_in_slab __initdata_memblock = 0;
60 61
62ulong __init_memblock choose_memblock_flags(void)
63{
64 return system_has_some_mirror ? MEMBLOCK_MIRROR : MEMBLOCK_NONE;
65}
66
61/* inline so we don't get a warning when pr_debug is compiled out */ 67/* inline so we don't get a warning when pr_debug is compiled out */
62static __init_memblock const char * 68static __init_memblock const char *
63memblock_type_name(struct memblock_type *type) 69memblock_type_name(struct memblock_type *type)
@@ -259,8 +265,21 @@ phys_addr_t __init_memblock memblock_find_in_range(phys_addr_t start,
259 phys_addr_t end, phys_addr_t size, 265 phys_addr_t end, phys_addr_t size,
260 phys_addr_t align) 266 phys_addr_t align)
261{ 267{
262 return memblock_find_in_range_node(size, align, start, end, 268 phys_addr_t ret;
263 NUMA_NO_NODE, MEMBLOCK_NONE); 269 ulong flags = choose_memblock_flags();
270
271again:
272 ret = memblock_find_in_range_node(size, align, start, end,
273 NUMA_NO_NODE, flags);
274
275 if (!ret && (flags & MEMBLOCK_MIRROR)) {
276 pr_warn("Could not allocate %pap bytes of mirrored memory\n",
277 &size);
278 flags &= ~MEMBLOCK_MIRROR;
279 goto again;
280 }
281
282 return ret;
264} 283}
265 284
266static void __init_memblock memblock_remove_region(struct memblock_type *type, unsigned long r) 285static void __init_memblock memblock_remove_region(struct memblock_type *type, unsigned long r)
@@ -786,6 +805,21 @@ int __init_memblock memblock_clear_hotplug(phys_addr_t base, phys_addr_t size)
786} 805}
787 806
788/** 807/**
808 * memblock_mark_mirror - Mark mirrored memory with flag MEMBLOCK_MIRROR.
809 * @base: the base phys addr of the region
810 * @size: the size of the region
811 *
812 * Return 0 on succees, -errno on failure.
813 */
814int __init_memblock memblock_mark_mirror(phys_addr_t base, phys_addr_t size)
815{
816 system_has_some_mirror = true;
817
818 return memblock_setclr_flag(base, size, 1, MEMBLOCK_MIRROR);
819}
820
821
822/**
789 * __next__mem_range - next function for for_each_free_mem_range() etc. 823 * __next__mem_range - next function for for_each_free_mem_range() etc.
790 * @idx: pointer to u64 loop variable 824 * @idx: pointer to u64 loop variable
791 * @nid: node selector, %NUMA_NO_NODE for all nodes 825 * @nid: node selector, %NUMA_NO_NODE for all nodes
@@ -839,6 +873,10 @@ void __init_memblock __next_mem_range(u64 *idx, int nid, ulong flags,
839 if (movable_node_is_enabled() && memblock_is_hotpluggable(m)) 873 if (movable_node_is_enabled() && memblock_is_hotpluggable(m))
840 continue; 874 continue;
841 875
876 /* if we want mirror memory skip non-mirror memory regions */
877 if ((flags & MEMBLOCK_MIRROR) && !memblock_is_mirror(m))
878 continue;
879
842 if (!type_b) { 880 if (!type_b) {
843 if (out_start) 881 if (out_start)
844 *out_start = m_start; 882 *out_start = m_start;
@@ -944,6 +982,10 @@ void __init_memblock __next_mem_range_rev(u64 *idx, int nid, ulong flags,
944 if (movable_node_is_enabled() && memblock_is_hotpluggable(m)) 982 if (movable_node_is_enabled() && memblock_is_hotpluggable(m))
945 continue; 983 continue;
946 984
985 /* if we want mirror memory skip non-mirror memory regions */
986 if ((flags & MEMBLOCK_MIRROR) && !memblock_is_mirror(m))
987 continue;
988
947 if (!type_b) { 989 if (!type_b) {
948 if (out_start) 990 if (out_start)
949 *out_start = m_start; 991 *out_start = m_start;
@@ -1096,8 +1138,18 @@ static phys_addr_t __init memblock_alloc_base_nid(phys_addr_t size,
1096 1138
1097phys_addr_t __init memblock_alloc_nid(phys_addr_t size, phys_addr_t align, int nid) 1139phys_addr_t __init memblock_alloc_nid(phys_addr_t size, phys_addr_t align, int nid)
1098{ 1140{
1099 return memblock_alloc_base_nid(size, align, MEMBLOCK_ALLOC_ACCESSIBLE, 1141 ulong flags = choose_memblock_flags();
1100 nid, MEMBLOCK_NONE); 1142 phys_addr_t ret;
1143
1144again:
1145 ret = memblock_alloc_base_nid(size, align, MEMBLOCK_ALLOC_ACCESSIBLE,
1146 nid, flags);
1147
1148 if (!ret && (flags & MEMBLOCK_MIRROR)) {
1149 flags &= ~MEMBLOCK_MIRROR;
1150 goto again;
1151 }
1152 return ret;
1101} 1153}
1102 1154
1103phys_addr_t __init __memblock_alloc_base(phys_addr_t size, phys_addr_t align, phys_addr_t max_addr) 1155phys_addr_t __init __memblock_alloc_base(phys_addr_t size, phys_addr_t align, phys_addr_t max_addr)
@@ -1167,6 +1219,7 @@ static void * __init memblock_virt_alloc_internal(
1167{ 1219{
1168 phys_addr_t alloc; 1220 phys_addr_t alloc;
1169 void *ptr; 1221 void *ptr;
1222 ulong flags = choose_memblock_flags();
1170 1223
1171 if (WARN_ONCE(nid == MAX_NUMNODES, "Usage of MAX_NUMNODES is deprecated. Use NUMA_NO_NODE instead\n")) 1224 if (WARN_ONCE(nid == MAX_NUMNODES, "Usage of MAX_NUMNODES is deprecated. Use NUMA_NO_NODE instead\n"))
1172 nid = NUMA_NO_NODE; 1225 nid = NUMA_NO_NODE;
@@ -1187,14 +1240,14 @@ static void * __init memblock_virt_alloc_internal(
1187 1240
1188again: 1241again:
1189 alloc = memblock_find_in_range_node(size, align, min_addr, max_addr, 1242 alloc = memblock_find_in_range_node(size, align, min_addr, max_addr,
1190 nid, MEMBLOCK_NONE); 1243 nid, flags);
1191 if (alloc) 1244 if (alloc)
1192 goto done; 1245 goto done;
1193 1246
1194 if (nid != NUMA_NO_NODE) { 1247 if (nid != NUMA_NO_NODE) {
1195 alloc = memblock_find_in_range_node(size, align, min_addr, 1248 alloc = memblock_find_in_range_node(size, align, min_addr,
1196 max_addr, NUMA_NO_NODE, 1249 max_addr, NUMA_NO_NODE,
1197 MEMBLOCK_NONE); 1250 flags);
1198 if (alloc) 1251 if (alloc)
1199 goto done; 1252 goto done;
1200 } 1253 }
@@ -1202,10 +1255,16 @@ again:
1202 if (min_addr) { 1255 if (min_addr) {
1203 min_addr = 0; 1256 min_addr = 0;
1204 goto again; 1257 goto again;
1205 } else {
1206 goto error;
1207 } 1258 }
1208 1259
1260 if (flags & MEMBLOCK_MIRROR) {
1261 flags &= ~MEMBLOCK_MIRROR;
1262 pr_warn("Could not allocate %pap bytes of mirrored memory\n",
1263 &size);
1264 goto again;
1265 }
1266
1267 return NULL;
1209done: 1268done:
1210 memblock_reserve(alloc, size); 1269 memblock_reserve(alloc, size);
1211 ptr = phys_to_virt(alloc); 1270 ptr = phys_to_virt(alloc);
@@ -1220,9 +1279,6 @@ done:
1220 kmemleak_alloc(ptr, size, 0, 0); 1279 kmemleak_alloc(ptr, size, 0, 0);
1221 1280
1222 return ptr; 1281 return ptr;
1223
1224error:
1225 return NULL;
1226} 1282}
1227 1283
1228/** 1284/**
diff --git a/mm/nobootmem.c b/mm/nobootmem.c
index ad3641dcdbe7..5258386fa1be 100644
--- a/mm/nobootmem.c
+++ b/mm/nobootmem.c
@@ -37,12 +37,20 @@ static void * __init __alloc_memory_core_early(int nid, u64 size, u64 align,
37{ 37{
38 void *ptr; 38 void *ptr;
39 u64 addr; 39 u64 addr;
40 ulong flags = choose_memblock_flags();
40 41
41 if (limit > memblock.current_limit) 42 if (limit > memblock.current_limit)
42 limit = memblock.current_limit; 43 limit = memblock.current_limit;
43 44
45again:
44 addr = memblock_find_in_range_node(size, align, goal, limit, nid, 46 addr = memblock_find_in_range_node(size, align, goal, limit, nid,
45 MEMBLOCK_NONE); 47 flags);
48 if (!addr && (flags & MEMBLOCK_MIRROR)) {
49 flags &= ~MEMBLOCK_MIRROR;
50 pr_warn("Could not allocate %pap bytes of mirrored memory\n",
51 &size);
52 goto again;
53 }
46 if (!addr) 54 if (!addr)
47 return NULL; 55 return NULL;
48 56