Mirrored memory support for boot time allocations
Subsystems (7)
cover Mirrored memory support for boot time allocations
Platforms that support a mix of mirrored and regular memory are coming.
We'd like to use the mirrored memory for kernel code, data and dynamically allocated data because our machine check recovery code cannot fix problems there. This series modifies the memblock allocator to comprehend mirrored memory and use it for all boot time allocations. Later I'll dig into page_alloc.c to put the leftover mirrored memory into a zone to be used for kernel allocation by slab/slob/slub and others.
You'll see why this is just RFC when you get to part 3.
Tony Luck (3):
mm/memblock: Add extra "flag" to memblock to allow selection of memory
based on attribute
mm/memblock: Allocate boot time data structures from mirrored memory x86, mirror: x86 enabling - find mirrored memory ranges and tell
memblock
arch/s390/kernel/crash_dump.c | 4 +- arch/sparc/mm/init_64.c | 4 +- arch/x86/kernel/check.c | 2 +- arch/x86/kernel/e820.c | 2 +- arch/x86/mm/init_32.c | 2 +- arch/x86/mm/memtest.c | 2 +- include/linux/memblock.h | 43 ++++++++++------ mm/cma.c | 4 +- mm/memblock.c | 113 ++++++++++++++++++++++++++++++++---------- mm/nobootmem.c | 12 ++++- 10 files changed, 135 insertions(+), 53 deletions(-)
Signature · 1 line
2.1.0
RFC 1/3 mm/memblock: Add extra "flag" to memblock to allow selection of memory based on attribute
No functional changes
--- arch/s390/kernel/crash_dump.c | 4 ++-- arch/sparc/mm/init_64.c | 4 ++-- arch/x86/kernel/check.c | 2 +- arch/x86/kernel/e820.c | 2 +- arch/x86/mm/init_32.c | 2 +- arch/x86/mm/memtest.c | 2 +- include/linux/memblock.h | 35 ++++++++++++++++++------------- mm/cma.c | 4 ++-- mm/memblock.c | 49 +++++++++++++++++++++++++------------------ mm/nobootmem.c | 4 ++-- 10 files changed, 61 insertions(+), 47 deletions(-)
arch/s390/kernel/crash_dump.c +2 -2
@@ -33,11 +33,11 @@ static struct memblock_type oldmem_type = { };#define for_each_dump_mem_range (i, nid, p_start, p_end, p_nid) \ - for (i = 0, __next_mem_range(&i, nid, &memblock.physmem, \ + for (i = 0, __next_mem_range(&i, nid, 0, &memblock.physmem, \ &oldmem_type, p_start, \ p_end, p_nid); \ i != (u64)ULLONG_MAX; \ - __next_mem_range(&i, nid, &memblock.physmem, \ + __next_mem_range(&i, nid, 0, &memblock.physmem, \ &oldmem_type, \ p_start, p_end, p_nid))
arch/sparc/mm/init_64.c +2 -2
@@ -1952,7 +1952,7 @@ static phys_addr_t __init available_memory(void)phys_addr_t pa_start, pa_end;u64 i; -for_each_free_mem_range (i,NUMA_NO_NODE , &pa_start, &pa_end,NULL ) +for_each_free_mem_range (i,NUMA_NO_NODE ,0 , &pa_start, &pa_end,NULL ) available = available + (pa_end - pa_start);return available;
@@ -1971,7 +1971,7 @@ static void __init reduce_memory(phys_addr_t limit_ram)if (limit_ram >= avail_ram)return ; -for_each_free_mem_range (i,NUMA_NO_NODE , &pa_start, &pa_end,NULL ) { +for_each_free_mem_range (i,NUMA_NO_NODE ,0 , &pa_start, &pa_end,NULL ) {phys_addr_t region_size = pa_end - pa_start;phys_addr_t clip_start = pa_start;
arch/x86/kernel/check.c +1 -1
@@ -91,7 +91,7 @@ void __init setup_bios_corruption_check(void) corruption_check_size =round_up (corruption_check_size,PAGE_SIZE ); -for_each_free_mem_range (i,NUMA_NO_NODE , &start, &end,NULL ) { +for_each_free_mem_range (i,NUMA_NO_NODE ,0 , &start, &end,NULL ) { start =clamp_t (phys_addr_t,round_up (start,PAGE_SIZE ),PAGE_SIZE , corruption_check_size); end = clamp_t(phys_addr_t, round_down(end, PAGE_SIZE),
arch/x86/kernel/e820.c +1 -1
@@ -1119,7 +1119,7 @@ void __init memblock_find_dma_reserve(void) nr_pages += end_pfn - start_pfn; } -for_each_free_mem_range (u,NUMA_NO_NODE , &start, &end,NULL ) { +for_each_free_mem_range (u,NUMA_NO_NODE ,0 , &start, &end,NULL ) { start_pfn = min_t(unsigned long, PFN_UP(start), MAX_DMA_PFN); end_pfn = min_t(unsigned long, PFN_DOWN(end), MAX_DMA_PFN);if (start_pfn < end_pfn)
arch/x86/mm/init_32.c +1 -1
@@ -433,7 +433,7 @@ void __init add_highpages_with_active_regions(int nid,phys_addr_t start, end;u64 i; -for_each_free_mem_range (i, nid, &start, &end,NULL ) { +for_each_free_mem_range (i, nid,0 , &start, &end,NULL ) { unsigned long pfn = clamp_t(unsigned long, PFN_UP(start), start_pfn, end_pfn); unsigned long e_pfn = clamp_t(unsigned long, PFN_DOWN(end),
arch/x86/mm/memtest.c +1 -1
@@ -74,7 +74,7 @@ static void __init do_one_pass(u64 pattern, u64 start, u64 end)u64 i;phys_addr_t this_start, this_end; -for_each_free_mem_range (i,NUMA_NO_NODE , &this_start, &this_end,NULL ) { +for_each_free_mem_range (i,NUMA_NO_NODE ,0 , &this_start, &this_end,NULL ) { this_start =clamp_t (phys_addr_t, this_start, start, end); this_end =clamp_t (phys_addr_t, this_end, start, end);if (this_start < this_end) {
include/linux/memblock.h +20 -15
@@ -61,7 +61,7 @@ extern bool movable_node_enabled;phys_addr_t memblock_find_in_range_node (phys_addr_t size,phys_addr_t align,phys_addr_t start,phys_addr_t end, -int nid); +int nid,u32 flag);phys_addr_t memblock_find_in_range (phys_addr_t start,phys_addr_t end,phys_addr_t size,phys_addr_t align);phys_addr_t get_allocated_memblock_reserved_regions_info (phys_addr_t *addr);
@@ -85,11 +85,11 @@ int memblock_remove_range(struct memblock_type *type,phys_addr_t base, phys_addr_t size); -void __next_mem_range (u64 *idx,int nid,struct memblock_type *type_a, +void __next_mem_range (u64 *idx,int nid,u32 flags,struct memblock_type *type_a,struct memblock_type *type_b,phys_addr_t *out_start,phys_addr_t *out_end,int *out_nid); -void __next_mem_range_rev (u64 *idx,int nid,struct memblock_type *type_a, +void __next_mem_range_rev (u64 *idx,int nid,u32 flags,struct memblock_type *type_a,struct memblock_type *type_b,phys_addr_t *out_start,phys_addr_t *out_end,int *out_nid);
@@ -100,16 +100,17 @@ void __next_mem_range_rev(u64 *idx, int nid, struct memblock_type *type_a,* @type_a: ptr to memblock_type to iterate * @type_b: ptr to memblock_type which excludes from the iteration * @nid: node selector, %NUMA_NO_NODE for all nodes +* @flag: pick from blocks based on memory attributes * @p_start: ptr to phys_addr_t for start address of the range, can be %NULL * @p_end: ptr to phys_addr_t for end address of the range, can be %NULL * @p_nid: ptr to int for nid of the range, can be %NULL */ -#define for_each_mem_range (i, type_a, type_b, nid, \ +#define for_each_mem_range (i, type_a, type_b, nid, flag, \ p_start, p_end, p_nid) \ - for (i = 0, __next_mem_range(&i, nid, type_a, type_b, \ + for (i = 0, __next_mem_range(&i, nid, flag, type_a, type_b, \ p_start, p_end, p_nid); \ i != (u64)ULLONG_MAX; \ - __next_mem_range(&i, nid, type_a, type_b, \ + __next_mem_range(&i, nid, flag, type_a, type_b, \ p_start, p_end, p_nid))/**
@@ -119,17 +120,18 @@ void __next_mem_range_rev(u64 *idx, int nid, struct memblock_type *type_a,* @type_a: ptr to memblock_type to iterate * @type_b: ptr to memblock_type which excludes from the iteration * @nid: node selector, %NUMA_NO_NODE for all nodes +* @flag: pick from blocks based on memory attributes * @p_start: ptr to phys_addr_t for start address of the range, can be %NULL * @p_end: ptr to phys_addr_t for end address of the range, can be %NULL * @p_nid: ptr to int for nid of the range, can be %NULL */ -#define for_each_mem_range_rev (i, type_a, type_b, nid, \ +#define for_each_mem_range_rev (i, type_a, type_b, nid, flag, \ p_start, p_end, p_nid) \ for (i = (u64)ULLONG_MAX, \ - __next_mem_range_rev(&i, nid, type_a, type_b, \ + __next_mem_range_rev(&i, nid, flag, type_a, type_b,\ p_start, p_end, p_nid); \ i != (u64)ULLONG_MAX; \ - __next_mem_range_rev(&i, nid, type_a, type_b, \ + __next_mem_range_rev(&i, nid, flag, type_a, type_b, \ p_start, p_end, p_nid))#ifdef CONFIG_MOVABLE_NODE
@@ -181,13 +183,14 @@ void __next_mem_pfn_range(int *idx, int nid, unsigned long *out_start_pfn,* @p_start: ptr to phys_addr_t for start address of the range, can be %NULL * @p_end: ptr to phys_addr_t for end address of the range, can be %NULL * @p_nid: ptr to int for nid of the range, can be %NULL +* @flag: pick from blocks based on memory attributes * * Walks over free (memory && !reserved) areas of memblock. Available as * soon as memblock is initialized. */ -#define for_each_free_mem_range (i, nid, p_start, p_end, p_nid) \ +#define for_each_free_mem_range (i, nid, flag, p_start, p_end, p_nid) \ for_each_mem_range(i, &memblock.memory, &memblock.reserved, \ - nid, p_start, p_end, p_nid) + nid, flag, p_start, p_end, p_nid)/** * for_each_free_mem_range_reverse - rev-iterate through free memblock areas
@@ -196,13 +199,14 @@ void __next_mem_pfn_range(int *idx, int nid, unsigned long *out_start_pfn,* @p_start: ptr to phys_addr_t for start address of the range, can be %NULL * @p_end: ptr to phys_addr_t for end address of the range, can be %NULL * @p_nid: ptr to int for nid of the range, can be %NULL +* @flag: pick from blocks based on memory attributes * * Walks over free (memory && !reserved) areas of memblock in reverse * order. Available as soon as memblock is initialized. */ -#define for_each_free_mem_range_reverse (i, nid, p_start, p_end, p_nid) \ - for_each_mem_range_rev(i, &memblock.memory, &memblock.reserved, \ - nid, p_start, p_end, p_nid) +#define for_each_free_mem_range_reverse (i, nid, flag, p_start, p_end, p_nid) \ + for_each_mem_range_rev(i, &memblock.memory, &memblock.reserved, \ + nid, flag, p_start, p_end, p_nid)static inline void memblock_set_region_flags (struct memblock_region *r,unsigned long flags)
@@ -273,7 +277,8 @@ static inline bool memblock_bottom_up(void) { return false; }#define MEMBLOCK_ALLOC_ACCESSIBLE 0phys_addr_t __init memblock_alloc_range (phys_addr_t size,phys_addr_t align, -phys_addr_t start,phys_addr_t end); +phys_addr_t start,phys_addr_t end, +u32 flag);phys_addr_t memblock_alloc_base (phys_addr_t size,phys_addr_t align,phys_addr_t max_addr); phys_addr_t __memblock_alloc_base(phys_addr_t size, phys_addr_t align,
mm/cma.c +2 -2
@@ -312,13 +312,13 @@ int __init cma_declare_contiguous(phys_addr_t base,*/ if (base < highmem_start && limit > highmem_start) { addr =memblock_alloc_range (size, alignment, - highmem_start, limit); + highmem_start, limit,0 ); limit = highmem_start; }if (!addr) { addr =memblock_alloc_range (size, alignment, base, - limit); + limit,0 );if (!addr) { ret = -ENOMEM ; goto err;
mm/memblock.c +29 -20
184 lines not on this page · raw message
mm/nobootmem.c +2 -2
@@ -41,7 +41,7 @@ static void * __init __alloc_memory_core_early(int nid, u64 size, u64 align,if (limit > memblock.current_limit) limit = memblock.current_limit; - addr =memblock_find_in_range_node (size, align, goal, limit, nid); + addr =memblock_find_in_range_node (size, align, goal, limit, nid,0 );if (!addr)return NULL ;
@@ -121,7 +121,7 @@ static unsigned long __init free_low_memory_core_early(void)memblock_clear_hotplug (0 ,-1 ); -for_each_free_mem_range (i,NUMA_NO_NODE , &start, &end,NULL ) +for_each_free_mem_range (i,NUMA_NO_NODE ,0 , &start, &end,NULL ) count +=__free_memory_core (start, end);#ifdef CONFIG_ARCH_DISCARD_MEMBLOCK
Signature · 1 line
2.1.0
RFC 2/3 mm/memblock: Allocate boot time data structures from mirrored memory
In reply to Tony LuckTry 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.
--- include/linux/memblock.h | 8 ++++++ mm/memblock.c | 72 +++++++++++++++++++++++++++++++++++++++++------- mm/nobootmem.c | 10 ++++++- 3 files changed, 79 insertions(+), 11 deletions(-)
include/linux/memblock.h +8 -0
@@ -22,6 +22,7 @@/* Definition of memblock flags. */ #define MEMBLOCK_HOTPLUG 0x1/* hotpluggable region */ +#define MEMBLOCK_MIRROR 0x2/* mirrored region */ struct memblock_region {phys_addr_t base;
@@ -75,6 +76,8 @@ int memblock_reserve(phys_addr_t base, phys_addr_t size);void memblock_trim_memory (phys_addr_t align);int memblock_mark_hotplug (phys_addr_t base,phys_addr_t size);int memblock_clear_hotplug (phys_addr_t base,phys_addr_t size); +int memblock_mark_mirror (phys_addr_t base,phys_addr_t size); +u32 memblock_has_mirror (void );/* Low level functions */ int memblock_add_range(struct memblock_type *type,
@@ -155,6 +158,11 @@ static inline bool movable_node_is_enabled(void) }#endif +static inline bool memblock_is_mirror (struct memblock_region *m) +{ +return m->flags &MEMBLOCK_MIRROR ; +} +#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP int memblock_search_pfn_nid (unsigned long pfn,unsigned long *start_pfn,unsigned long *end_pfn);
mm/memblock.c +62 -10
150 lines not on this page · raw message
mm/nobootmem.c +9 -1
@@ -37,11 +37,19 @@ static void * __init __alloc_memory_core_early(int nid, u64 size, u64 align, {void *ptr;u64 addr; +u32 flag =memblock_has_mirror ();if (limit > memblock.current_limit) limit = memblock.current_limit; - addr =memblock_find_in_range_node (size, align, goal, limit, nid,0 ); +again: + addr =memblock_find_in_range_node (size, align, goal, limit, nid, flag); + +if (flag && !addr) { + flag =0 ; +pr_warn ("Could not allocate %lld bytes of mirrored memory\n" , size); + goto again; + }if (!addr)return NULL ;
Signature · 1 line
2.1.0
RFC 3/3 x86, mirror: x86 enabling - find mirrored memory ranges and tell memblock
In reply to Tony LuckCan't post this part yet because it uses things in an upcoming[*] ACPI, UEFI, or some other four-letter-ending-in-I standard. So just imagine a call someplace early in startup that reads information about mirrored address ranges and does:
+ for (...) {
+ start = ...;
+ size = ...;
+ if (it looks mirrored)
+ memblock_mark_mirror(start, size);
+ }
Whole patch is pretty tiny:
3 files changed, 19 insertions(+)
How much damage could I possibly do in just 19 lines?
-Tony
[*] very soon, I'm told
Re: [RFC 3/3] x86, mirror: x86 enabling - find mirrored memory ranges and tell memblock
Quoted 4 lines · Tony Luck
Can't post this part yet because it uses things in an upcoming[*] ACPI, UEFI, or some other four-letter-ending-in-I standard. So just imagine a call someplace early in startup that reads information about mirrored address ranges and does:
Hi Tony,
Does the upcoming[*] ACPI will add a new flag in SRAT tables? just like memory hotplug.
#define ACPI_SRAT_MEM_HOT_PLUGGABLE (1<<1) /* 01: Memory region is hot pluggable */
+#define ACPI_SRAT_MEM_MIRROR (1<<3) /* 03: Memory region is mirrored */
acpi_numa_memory_affinity_init()
... hotpluggable = ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE; + mirrorable = ma->flags & ACPI_SRAT_MEM_MIRROR; ... + if (mirrorable) + memblock_mark_mirror(start, size); ...
Thanks,
Xishi Qiu
Quoted 23 lines
(quoted diff) +6
-0+ for (...) { + start = ...; + size = ...; + if (it looks mirrored) + memblock_mark_mirror(start, size); + }Whole patch is pretty tiny:
3 files changed, 19 insertions(+)How much damage could I possibly do in just 19 lines?
-Tony
[*] very soon, I'm told
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
RE: [RFC 3/3] x86, mirror: x86 enabling - find mirrored memory ranges and tell memblock
Quoted 9 lines · Tony Luck
Quoted 4 lines
Can't post this part yet because it uses things in an upcoming[*] ACPI, UEFI, or some other four-letter-ending-in-I standard. So just imagine a call someplace early in startup that reads information about mirrored address ranges and does:
Does the upcoming[*] ACPI will add a new flag in SRAT tables? just like memory hotplug.
#define
ACPI_SRAT_MEM_HOT_PLUGGABLE(1<<1) /* 01: Memory region is hot pluggable */
+#defineACPI_SRAT_MEM_MIRROR(1<<3) /* 03: Memory region is mirrored */
The choice for this was UEFI - new attribute bit in the GetMemoryMap() return value.
UEFI 2.5 has been published with this change and I posted a newer patch 10 days ago:
https://lkml.org/lkml/2015/5/8/521
-Tony
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 1 line · Tony Luck
Platforms that support a mix of mirrored and regular memory are coming.
Obviously I don't do enough -mm work to remember where linux-mm mailing list is hosted :-(
Let's see who finds this on the linux-kernel list (that I did spell right). When v2
happens I'll get it to the right places.
-Tony
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 8 lines · Tony Luck
Platforms that support a mix of mirrored and regular memory are coming.
We'd like to use the mirrored memory for kernel code, data and dynamically allocated data because our machine check recovery code cannot fix problems there. This series modifies the memblock allocator to comprehend mirrored memory and use it for all boot time allocations. Later I'll dig into
page_alloc.cto put the leftover mirrored memory into a zone to be used for kernel allocation by slab/slob/slub and others.
Hi Tony,
Is it means that you will create a new zone to fill mirrored memory, like the movable zone, right?
I think this will change a lot of code, why not create a new migrate type? such as CMA, e.g. MIGRATE_MIRROR
Thanks,
Xishi Qiu
Quoted 22 lines
You'll see why this is just RFC when you get to part 3.
Tony Luck (3):
mm/memblock: Add extra "flag" to memblock to allow selection of memory
based on attribute
mm/memblock: Allocate boot time data structures from mirrored memory x86, mirror: x86 enabling - find mirrored memory ranges and tell
memblockarch/s390/kernel/crash_dump.c | 4 +- arch/sparc/mm/init_64.c | 4 +- arch/x86/kernel/check.c | 2 +- arch/x86/kernel/e820.c | 2 +- arch/x86/mm/init_32.c | 2 +- arch/x86/mm/memtest.c | 2 +- include/linux/memblock.h | 43 ++++++++++------ mm/cma.c | 4 +- mm/memblock.c | 113 ++++++++++++++++++++++++++++++++---------- mm/nobootmem.c | 12 ++++- 10 files changed, 135 insertions(+), 53 deletions(-)
Quoted 54 lines · Xishi Qiu
Quoted 8 lines · Tony Luck
Platforms that support a mix of mirrored and regular memory are coming.
We'd like to use the mirrored memory for kernel code, data and dynamically allocated data because our machine check recovery code cannot fix problems there. This series modifies the memblock allocator to comprehend mirrored memory and use it for all boot time allocations. Later I'll dig into
page_alloc.cto put the leftover mirrored memory into a zone to be used for kernel allocation by slab/slob/slub and others.Hi Tony,
Is it means that you will create a new zone to fill mirrored memory, like the movable zone, right?
I think this will change a lot of code, why not create a new migrate type? such as CMA, e.g.MIGRATE_MIRRORThanks,
Xishi QiuQuoted 10 lines
You'll see why this is just RFC when you get to part 3.
Tony Luck (3):
mm/memblock: Add extra "flag" to memblock to allow selection of memory
based on attribute
mm/memblock: Allocate boot time data structures from mirrored memory x86, mirror: x86 enabling - find mirrored memory ranges and tell
memblockQuoted 12 lines
arch/s390/kernel/crash_dump.c | 4 +- arch/sparc/mm/init_64.c | 4 +- arch/x86/kernel/check.c | 2 +- arch/x86/kernel/e820.c | 2 +- arch/x86/mm/init_32.c | 2 +- arch/x86/mm/memtest.c | 2 +- include/linux/memblock.h | 43 ++++++++++------ mm/cma.c | 4 +- mm/memblock.c | 113 ++++++++++++++++++++++++++++++++---------- mm/nobootmem.c | 12 ++++- 10 files changed, 135 insertions(+), 53 deletions(-)--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/.
Quoted 2 lines
Is it means that you will create a new zone to fill mirrored memory, like the movable zone, right?
That's my general plan.
Quoted 2 lines
I think this will change a lot of code, why not create a new migrate type? such as CMA, e.g.
MIGRATE_MIRROR
I'm still exploring options ... the idea is to use mirrored memory for kernel allocations (because our machine check recovery code will always crash the system for errors in kernel memory - while we can avoid the crash for errors in application memory). I'm not familiar with CMA ... can you explain a bit how it might let me direct kernel allocations to specific areas of memory?
-Tony
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>