Skip to content

Commit b2fc97c

Browse files
committed
Merge tag 'memblock-v6.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rppt/memblock
Pull memblock updates from Mike Rapoport: - 'reserve_mem' command line parameter to allow creation of named memory reservation at boot time. The driving use-case is to improve the ability of pstore to retain ramoops data across reboots. - cleanups and small improvements in memblock and mm_init - new tests cases in memblock test suite * tag 'memblock-v6.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rppt/memblock: memblock tests: fix implicit declaration of function 'numa_valid_node' memblock: Move late alloc warning down to phys alloc pstore/ramoops: Add ramoops.mem_name= command line option mm/memblock: Add "reserve_mem" to reserved named memory at boot up mm/mm_init.c: don't initialize page->lru again mm/mm_init.c: not always search next deferred_init_pfn from very beginning mm/mm_init.c: use deferred_init_mem_pfn_range_in_zone() to decide loop condition mm/mm_init.c: get the highest zone directly mm/mm_init.c: move nr_initialised reset down a bit mm/memblock: fix a typo in description of for_each_mem_region() mm/mm_init.c: use memblock_region_memory_base_pfn() to get startpfn mm/memblock: use PAGE_ALIGN_DOWN to get pgend in free_memmap mm/memblock: return true directly on finding overlap region memblock tests: add memblock_overlaps_region_checks mm/memblock: fix comment for memblock_isolate_range() memblock tests: add memblock_reserve_many_may_conflict_check() memblock tests: add memblock_reserve_all_locations_check() mm/memblock: remove empty dummy entry
2 parents 68b5973 + 9364a7e commit b2fc97c

File tree

12 files changed

+542
-82
lines changed

12 files changed

+542
-82
lines changed

Documentation/admin-guide/kernel-parameters.txt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5674,6 +5674,28 @@
56745674
them. If <base> is less than 0x10000, the region
56755675
is assumed to be I/O ports; otherwise it is memory.
56765676

5677+
reserve_mem= [RAM]
5678+
Format: nn[KNG]:<align>:<label>
5679+
Reserve physical memory and label it with a name that
5680+
other subsystems can use to access it. This is typically
5681+
used for systems that do not wipe the RAM, and this command
5682+
line will try to reserve the same physical memory on
5683+
soft reboots. Note, it is not guaranteed to be the same
5684+
location. For example, if anything about the system changes
5685+
or if booting a different kernel. It can also fail if KASLR
5686+
places the kernel at the location of where the RAM reservation
5687+
was from a previous boot, the new reservation will be at a
5688+
different location.
5689+
Any subsystem using this feature must add a way to verify
5690+
that the contents of the physical memory is from a previous
5691+
boot, as there may be cases where the memory will not be
5692+
located at the same location.
5693+
5694+
The format is size:align:label for example, to request
5695+
12 megabytes of 4096 alignment for ramoops:
5696+
5697+
reserve_mem=12M:4096:oops ramoops.mem_name=oops
5698+
56775699
reservetop= [X86-32,EARLY]
56785700
Format: nn[KMG]
56795701
Reserves a hole at the top of the kernel virtual

Documentation/admin-guide/ramoops.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ and type of the memory area are set using three variables:
2323
* ``mem_size`` for the size. The memory size will be rounded down to a
2424
power of two.
2525
* ``mem_type`` to specify if the memory type (default is pgprot_writecombine).
26+
* ``mem_name`` to specify a memory region defined by ``reserve_mem`` command
27+
line parameter.
2628

2729
Typically the default value of ``mem_type=0`` should be used as that sets the pstore
2830
mapping to pgprot_writecombine. Setting ``mem_type=1`` attempts to use
@@ -118,6 +120,17 @@ Setting the ramoops parameters can be done in several different manners:
118120
return ret;
119121
}
120122

123+
D. Using a region of memory reserved via ``reserve_mem`` command line
124+
parameter. The address and size will be defined by the ``reserve_mem``
125+
parameter. Note, that ``reserve_mem`` may not always allocate memory
126+
in the same location, and cannot be relied upon. Testing will need
127+
to be done, and it may not work on every machine, nor every kernel.
128+
Consider this a "best effort" approach. The ``reserve_mem`` option
129+
takes a size, alignment and name as arguments. The name is used
130+
to map the memory to a label that can be retrieved by ramoops.
131+
132+
reserver_mem=2M:4096:oops ramoops.mem_name=oops
133+
121134
You can specify either RAM memory or peripheral devices' memory. However, when
122135
specifying RAM, be sure to reserve the memory by issuing memblock_reserve()
123136
very early in the architecture code, e.g.::

fs/pstore/ram.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ module_param_hw(mem_address, ullong, other, 0400);
5050
MODULE_PARM_DESC(mem_address,
5151
"start of reserved RAM used to store oops/panic logs");
5252

53+
static char *mem_name;
54+
module_param_named(mem_name, mem_name, charp, 0400);
55+
MODULE_PARM_DESC(mem_name, "name of kernel param that holds addr");
56+
5357
static ulong mem_size;
5458
module_param(mem_size, ulong, 0400);
5559
MODULE_PARM_DESC(mem_size,
@@ -914,6 +918,16 @@ static void __init ramoops_register_dummy(void)
914918
{
915919
struct ramoops_platform_data pdata;
916920

921+
if (mem_name) {
922+
phys_addr_t start;
923+
phys_addr_t size;
924+
925+
if (reserve_mem_find_by_name(mem_name, &start, &size)) {
926+
mem_address = start;
927+
mem_size = size;
928+
}
929+
}
930+
917931
/*
918932
* Prepare a dummy platform data structure to carry the module
919933
* parameters. If mem_size isn't set, then there are no module

include/linux/memblock.h

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -299,25 +299,6 @@ void __next_mem_pfn_range(int *idx, int nid, unsigned long *out_start_pfn,
299299
void __next_mem_pfn_range_in_zone(u64 *idx, struct zone *zone,
300300
unsigned long *out_spfn,
301301
unsigned long *out_epfn);
302-
/**
303-
* for_each_free_mem_pfn_range_in_zone - iterate through zone specific free
304-
* memblock areas
305-
* @i: u64 used as loop variable
306-
* @zone: zone in which all of the memory blocks reside
307-
* @p_start: ptr to phys_addr_t for start address of the range, can be %NULL
308-
* @p_end: ptr to phys_addr_t for end address of the range, can be %NULL
309-
*
310-
* Walks over free (memory && !reserved) areas of memblock in a specific
311-
* zone. Available once memblock and an empty zone is initialized. The main
312-
* assumption is that the zone start, end, and pgdat have been associated.
313-
* This way we can use the zone to determine NUMA node, and if a given part
314-
* of the memblock is valid for the zone.
315-
*/
316-
#define for_each_free_mem_pfn_range_in_zone(i, zone, p_start, p_end) \
317-
for (i = 0, \
318-
__next_mem_pfn_range_in_zone(&i, zone, p_start, p_end); \
319-
i != U64_MAX; \
320-
__next_mem_pfn_range_in_zone(&i, zone, p_start, p_end))
321302

322303
/**
323304
* for_each_free_mem_pfn_range_in_zone_from - iterate through zone specific
@@ -565,7 +546,7 @@ static inline unsigned long memblock_region_reserved_end_pfn(const struct memblo
565546
}
566547

567548
/**
568-
* for_each_mem_region - itereate over memory regions
549+
* for_each_mem_region - iterate over memory regions
569550
* @region: loop variable
570551
*/
571552
#define for_each_mem_region(region) \

include/linux/mm.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4261,4 +4261,6 @@ static inline bool pfn_is_unaccepted_memory(unsigned long pfn)
42614261
void vma_pgtable_walk_begin(struct vm_area_struct *vma);
42624262
void vma_pgtable_walk_end(struct vm_area_struct *vma);
42634263

4264+
int reserve_mem_find_by_name(const char *name, phys_addr_t *start, phys_addr_t *size);
4265+
42644266
#endif /* _LINUX_MM_H */

mm/memblock.c

Lines changed: 135 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,10 @@ static struct memblock_region memblock_physmem_init_regions[INIT_PHYSMEM_REGIONS
114114

115115
struct memblock memblock __initdata_memblock = {
116116
.memory.regions = memblock_memory_init_regions,
117-
.memory.cnt = 1, /* empty dummy entry */
118117
.memory.max = INIT_MEMBLOCK_MEMORY_REGIONS,
119118
.memory.name = "memory",
120119

121120
.reserved.regions = memblock_reserved_init_regions,
122-
.reserved.cnt = 1, /* empty dummy entry */
123121
.reserved.max = INIT_MEMBLOCK_RESERVED_REGIONS,
124122
.reserved.name = "reserved",
125123

@@ -130,7 +128,6 @@ struct memblock memblock __initdata_memblock = {
130128
#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP
131129
struct memblock_type physmem = {
132130
.regions = memblock_physmem_init_regions,
133-
.cnt = 1, /* empty dummy entry */
134131
.max = INIT_PHYSMEM_REGIONS,
135132
.name = "physmem",
136133
};
@@ -197,8 +194,8 @@ bool __init_memblock memblock_overlaps_region(struct memblock_type *type,
197194
for (i = 0; i < type->cnt; i++)
198195
if (memblock_addrs_overlap(base, size, type->regions[i].base,
199196
type->regions[i].size))
200-
break;
201-
return i < type->cnt;
197+
return true;
198+
return false;
202199
}
203200

204201
/**
@@ -356,7 +353,6 @@ static void __init_memblock memblock_remove_region(struct memblock_type *type, u
356353
/* Special case for empty arrays */
357354
if (type->cnt == 0) {
358355
WARN_ON(type->total_size != 0);
359-
type->cnt = 1;
360356
type->regions[0].base = 0;
361357
type->regions[0].size = 0;
362358
type->regions[0].flags = 0;
@@ -600,12 +596,13 @@ static int __init_memblock memblock_add_range(struct memblock_type *type,
600596

601597
/* special case for empty array */
602598
if (type->regions[0].size == 0) {
603-
WARN_ON(type->cnt != 1 || type->total_size);
599+
WARN_ON(type->cnt != 0 || type->total_size);
604600
type->regions[0].base = base;
605601
type->regions[0].size = size;
606602
type->regions[0].flags = flags;
607603
memblock_set_region_node(&type->regions[0], nid);
608604
type->total_size = size;
605+
type->cnt = 1;
609606
return 0;
610607
}
611608

@@ -780,7 +777,8 @@ bool __init_memblock memblock_validate_numa_coverage(unsigned long threshold_byt
780777
* Walk @type and ensure that regions don't cross the boundaries defined by
781778
* [@base, @base + @size). Crossing regions are split at the boundaries,
782779
* which may create at most two more regions. The index of the first
783-
* region inside the range is returned in *@start_rgn and end in *@end_rgn.
780+
* region inside the range is returned in *@start_rgn and the index of the
781+
* first region after the range is returned in *@end_rgn.
784782
*
785783
* Return:
786784
* 0 on success, -errno on failure.
@@ -1441,6 +1439,17 @@ phys_addr_t __init memblock_alloc_range_nid(phys_addr_t size,
14411439
enum memblock_flags flags = choose_memblock_flags();
14421440
phys_addr_t found;
14431441

1442+
/*
1443+
* Detect any accidental use of these APIs after slab is ready, as at
1444+
* this moment memblock may be deinitialized already and its
1445+
* internal data may be destroyed (after execution of memblock_free_all)
1446+
*/
1447+
if (WARN_ON_ONCE(slab_is_available())) {
1448+
void *vaddr = kzalloc_node(size, GFP_NOWAIT, nid);
1449+
1450+
return vaddr ? virt_to_phys(vaddr) : 0;
1451+
}
1452+
14441453
if (!align) {
14451454
/* Can't use WARNs this early in boot on powerpc */
14461455
dump_stack();
@@ -1566,13 +1575,6 @@ static void * __init memblock_alloc_internal(
15661575
{
15671576
phys_addr_t alloc;
15681577

1569-
/*
1570-
* Detect any accidental use of these APIs after slab is ready, as at
1571-
* this moment memblock may be deinitialized already and its
1572-
* internal data may be destroyed (after execution of memblock_free_all)
1573-
*/
1574-
if (WARN_ON_ONCE(slab_is_available()))
1575-
return kzalloc_node(size, GFP_NOWAIT, nid);
15761578

15771579
if (max_addr > memblock.current_limit)
15781580
max_addr = memblock.current_limit;
@@ -2031,7 +2033,7 @@ static void __init free_memmap(unsigned long start_pfn, unsigned long end_pfn)
20312033
* downwards.
20322034
*/
20332035
pg = PAGE_ALIGN(__pa(start_pg));
2034-
pgend = __pa(end_pg) & PAGE_MASK;
2036+
pgend = PAGE_ALIGN_DOWN(__pa(end_pg));
20352037

20362038
/*
20372039
* If there are free pages between these, free the section of the
@@ -2234,6 +2236,123 @@ void __init memblock_free_all(void)
22342236
totalram_pages_add(pages);
22352237
}
22362238

2239+
/* Keep a table to reserve named memory */
2240+
#define RESERVE_MEM_MAX_ENTRIES 8
2241+
#define RESERVE_MEM_NAME_SIZE 16
2242+
struct reserve_mem_table {
2243+
char name[RESERVE_MEM_NAME_SIZE];
2244+
phys_addr_t start;
2245+
phys_addr_t size;
2246+
};
2247+
static struct reserve_mem_table reserved_mem_table[RESERVE_MEM_MAX_ENTRIES];
2248+
static int reserved_mem_count;
2249+
2250+
/* Add wildcard region with a lookup name */
2251+
static void __init reserved_mem_add(phys_addr_t start, phys_addr_t size,
2252+
const char *name)
2253+
{
2254+
struct reserve_mem_table *map;
2255+
2256+
map = &reserved_mem_table[reserved_mem_count++];
2257+
map->start = start;
2258+
map->size = size;
2259+
strscpy(map->name, name);
2260+
}
2261+
2262+
/**
2263+
* reserve_mem_find_by_name - Find reserved memory region with a given name
2264+
* @name: The name that is attached to a reserved memory region
2265+
* @start: If found, holds the start address
2266+
* @size: If found, holds the size of the address.
2267+
*
2268+
* @start and @size are only updated if @name is found.
2269+
*
2270+
* Returns: 1 if found or 0 if not found.
2271+
*/
2272+
int reserve_mem_find_by_name(const char *name, phys_addr_t *start, phys_addr_t *size)
2273+
{
2274+
struct reserve_mem_table *map;
2275+
int i;
2276+
2277+
for (i = 0; i < reserved_mem_count; i++) {
2278+
map = &reserved_mem_table[i];
2279+
if (!map->size)
2280+
continue;
2281+
if (strcmp(name, map->name) == 0) {
2282+
*start = map->start;
2283+
*size = map->size;
2284+
return 1;
2285+
}
2286+
}
2287+
return 0;
2288+
}
2289+
EXPORT_SYMBOL_GPL(reserve_mem_find_by_name);
2290+
2291+
/*
2292+
* Parse reserve_mem=nn:align:name
2293+
*/
2294+
static int __init reserve_mem(char *p)
2295+
{
2296+
phys_addr_t start, size, align, tmp;
2297+
char *name;
2298+
char *oldp;
2299+
int len;
2300+
2301+
if (!p)
2302+
return -EINVAL;
2303+
2304+
/* Check if there's room for more reserved memory */
2305+
if (reserved_mem_count >= RESERVE_MEM_MAX_ENTRIES)
2306+
return -EBUSY;
2307+
2308+
oldp = p;
2309+
size = memparse(p, &p);
2310+
if (!size || p == oldp)
2311+
return -EINVAL;
2312+
2313+
if (*p != ':')
2314+
return -EINVAL;
2315+
2316+
align = memparse(p+1, &p);
2317+
if (*p != ':')
2318+
return -EINVAL;
2319+
2320+
/*
2321+
* memblock_phys_alloc() doesn't like a zero size align,
2322+
* but it is OK for this command to have it.
2323+
*/
2324+
if (align < SMP_CACHE_BYTES)
2325+
align = SMP_CACHE_BYTES;
2326+
2327+
name = p + 1;
2328+
len = strlen(name);
2329+
2330+
/* name needs to have length but not too big */
2331+
if (!len || len >= RESERVE_MEM_NAME_SIZE)
2332+
return -EINVAL;
2333+
2334+
/* Make sure that name has text */
2335+
for (p = name; *p; p++) {
2336+
if (!isspace(*p))
2337+
break;
2338+
}
2339+
if (!*p)
2340+
return -EINVAL;
2341+
2342+
/* Make sure the name is not already used */
2343+
if (reserve_mem_find_by_name(name, &start, &tmp))
2344+
return -EBUSY;
2345+
2346+
start = memblock_phys_alloc(size, align);
2347+
if (!start)
2348+
return -ENOMEM;
2349+
2350+
reserved_mem_add(start, size, name);
2351+
2352+
return 1;
2353+
}
2354+
__setup("reserve_mem=", reserve_mem);
2355+
22372356
#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_ARCH_KEEP_MEMBLOCK)
22382357
static const char * const flagname[] = {
22392358
[ilog2(MEMBLOCK_HOTPLUG)] = "HOTPLUG",

0 commit comments

Comments
 (0)