ANDROID: memblock: track memblock changed at early param

In addition to reserved-memory in device tree, an option in cmdline may
result in memblock allocation. This patch tries to distinguish memblock
changes done at early param.

A region in memsize will be created with name as the param string. And
the region size will be updated during the param function.

Bug: 340432773
Signed-off-by: Jaewon Kim <jaewon31.kim@samsung.com>
Link: https://lore.kernel.org/linux-mm/20240521023957.2587005-6-jaewon31.kim@samsung.com/
Change-Id: Ib01e88b303be4ab958db46f1e369d15042a5d9fd
This commit is contained in:
Jaewon Kim
2020-06-29 02:28:44 +09:00
committed by Suren Baghdasaryan
parent f3f83a6edf
commit 7227090784
3 changed files with 107 additions and 4 deletions
+4
View File
@@ -597,10 +597,14 @@ static inline void memtest_report_meminfo(struct seq_file *m) { }
extern void __init_memblock memblock_memsize_record(const char *name,
phys_addr_t base, phys_addr_t size, bool nomap, bool reusable);
extern void __init memblock_memsize_detect_hole(void);
extern void __init memblock_memsize_set_name(const char *name);
extern void __init memblock_memsize_unset_name(void);
#else
static inline void __init_memblock memblock_memsize_record(const char *name,
phys_addr_t base, phys_addr_t size, bool nomap, bool reusable) { }
static inline void __init memblock_memsize_detect_hole(void) { }
static inline void __init memblock_memsize_set_name(const char *name) { }
static inline void __init memblock_memsize_unset_name(void) { }
#endif
#endif /* _LINUX_MEMBLOCK_H */
+11 -2
View File
@@ -212,8 +212,15 @@ static bool __init obsolete_checksetup(char *line)
pr_warn("Parameter %s is obsolete, ignored\n",
p->str);
return true;
} else if (p->setup_func(line + n))
return true;
} else {
int ret;
memblock_memsize_set_name(p->str);
ret = p->setup_func(line + n);
memblock_memsize_unset_name();
if (ret)
return true;
}
}
p++;
} while (p < __setup_end);
@@ -758,8 +765,10 @@ static int __init do_early_param(char *param, char *val,
(strcmp(param, "console") == 0 &&
strcmp(p->str, "earlycon") == 0)
) {
memblock_memsize_set_name(p->str);
if (p->setup_func(val) != 0)
pr_warn("Malformed early option '%s'\n", param);
memblock_memsize_unset_name();
}
}
/* We accept everything at this stage. */
+92 -2
View File
@@ -175,6 +175,18 @@ static inline phys_addr_t memblock_cap_size(phys_addr_t base, phys_addr_t *size)
return *size = min(*size, PHYS_ADDR_MAX - base);
}
#ifdef CONFIG_MEMBLOCK_MEMSIZE
static void memblock_memsize_record_add(struct memblock_type *type,
phys_addr_t base, phys_addr_t size);
static void memblock_memsize_record_remove(struct memblock_type *type,
phys_addr_t base, phys_addr_t size);
#else
static inline void memblock_memsize_record_add(struct memblock_type *type,
phys_addr_t base, phys_addr_t size) { }
static inline void memblock_memsize_record_remove(struct memblock_type *type,
phys_addr_t base, phys_addr_t size) { }
#endif
/*
* Address comparison utilities
*/
@@ -591,6 +603,7 @@ static int __init_memblock memblock_add_range(struct memblock_type *type,
phys_addr_t end = base + memblock_cap_size(base, &size);
int idx, nr_new, start_rgn = -1, end_rgn;
struct memblock_region *rgn;
phys_addr_t new_size = 0;
if (!size)
return 0;
@@ -604,7 +617,8 @@ static int __init_memblock memblock_add_range(struct memblock_type *type,
memblock_set_region_node(&type->regions[0], nid);
type->total_size = size;
type->cnt = 1;
return 0;
new_size = size;
goto done;
}
/*
@@ -651,6 +665,7 @@ repeat:
memblock_insert_region(type, idx++, base,
rbase - base, nid,
flags);
new_size += rbase - base;
}
}
/* area below @rend is dealt with, forget about it */
@@ -666,6 +681,7 @@ repeat:
end_rgn = idx + 1;
memblock_insert_region(type, idx, base, end - base,
nid, flags);
new_size += end - base;
}
}
@@ -684,8 +700,11 @@ repeat:
goto repeat;
} else {
memblock_merge_regions(type, start_rgn, end_rgn);
return 0;
}
done:
if (new_size == size)
memblock_memsize_record_add(type, obase, size);
return 0;
}
/**
@@ -856,6 +875,7 @@ static int __init_memblock memblock_remove_range(struct memblock_type *type,
for (i = end_rgn - 1; i >= start_rgn; i--)
memblock_remove_region(type, i);
memblock_memsize_record_remove(type, base, size);
return 0;
}
@@ -2049,6 +2069,7 @@ struct memsize_rgn_struct {
static struct memsize_rgn_struct memsize_rgn[CONFIG_MAX_MEMBLOCK_MEMSIZE] __initdata_memblock;
static int memsize_rgn_count __initdata_memblock;
static const char *memblock_memsize_name __initdata_memblock;
static void __init_memblock memsize_get_valid_name(char *valid_name, const char *name)
{
@@ -2245,6 +2266,75 @@ void __init memblock_memsize_detect_hole(void)
}
}
}
/* assume that freeing region is NOT bigger than the previous region */
static void __init_memblock memblock_memsize_free(phys_addr_t free_base,
phys_addr_t free_size)
{
int i;
struct memsize_rgn_struct *rgn;
phys_addr_t free_end, end;
free_end = free_base + free_size - 1;
memblock_dbg("%s %pa..%pa\n",
__func__, &free_base, &free_end);
for (i = 0; i < memsize_rgn_count; i++) {
rgn = &memsize_rgn[i];
end = rgn->base + rgn->size;
if (free_base < rgn->base ||
free_base >= end)
continue;
free_end = free_base + free_size;
if (free_base == rgn->base) {
rgn->size -= free_size;
if (rgn->size != 0)
rgn->base += free_size;
} else if (free_end == end) {
rgn->size -= free_size;
} else {
memblock_memsize_record(rgn->name, free_end,
end - free_end, rgn->nomap, rgn->reusable);
rgn->size = free_base - rgn->base;
}
}
}
void __init memblock_memsize_set_name(const char *name)
{
memblock_memsize_name = name;
}
void __init memblock_memsize_unset_name(void)
{
memblock_memsize_name = NULL;
}
static void __init_memblock memblock_memsize_record_add(struct memblock_type *type,
phys_addr_t base, phys_addr_t size)
{
if (memblock_memsize_name) {
if (type == &memblock.reserved)
memblock_memsize_record(memblock_memsize_name,
base, size, false, false);
else if (type == &memblock.memory)
memblock_memsize_free(base, size);
}
}
static void __init_memblock memblock_memsize_record_remove(struct memblock_type *type,
phys_addr_t base, phys_addr_t size)
{
if (memblock_memsize_name) {
if (type == &memblock.reserved)
memblock_memsize_free(base, size);
else if (type == &memblock.memory)
memblock_memsize_record(memblock_memsize_name,
base, size, true, false);
}
}
#endif /* MEMBLOCK_MEMSIZE */
static void __init free_memmap(unsigned long start_pfn, unsigned long end_pfn)