* [PATCH v3 1/5] of: reserved_mem: release dynamically allocated no-map region on init failure
2026-09-20 9:28 [PATCH v3 0/5] of: reserved_mem: several fixes about reserved memory Wandun Chen
@ 2026-09-20 9:28 ` Wandun Chen
2026-09-20 9:28 ` [PATCH v3 2/5] of: reserved_mem: retain static no-map memory " Wandun Chen
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Wandun Chen @ 2026-09-20 9:28 UTC (permalink / raw)
To: robh, saravanak, rppt, m.szyprowski, devicetree, linux-kernel, linux-mm
Cc: akpm
From: Wandun Chen <chenwandun@lixiang.com>
Dynamically reserved-memory regions are added to memblock.reserved by
memblock_phys_alloc_range() during __reserved_mem_alloc_size(). When a
reserved-memory region's driver initialization fails,
fdt_init_reserved_mem_node() cleans up the reservation. For no-map
regions it only calls memblock_clear_nomap(), leaving the range in
memblock.reserved and unavailable for normal memory use.
Fix it by freeing the region on init failure when it was dynamically
allocated.
Sashiko found this issue in [1].
Fixes: 7b25995f5319 ("of: of_reserved_mem: mark nomap memory instead of removing")
Acked-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Wandun Chen <chenwandun@lixiang.com>
Link: https://sashiko.dev/#/message/20260806100605.2C2C01F000E9%40smtp.kernel.org [1]
---
drivers/of/of_reserved_mem.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
index 8c9d6395d6a3..f55ed3b5aaa4 100644
--- a/drivers/of/of_reserved_mem.c
+++ b/drivers/of/of_reserved_mem.c
@@ -112,7 +112,8 @@ static int __init alloc_reserved_mem_array(void)
}
static void fdt_init_reserved_mem_node(unsigned long node, const char *uname,
- phys_addr_t base, phys_addr_t size);
+ phys_addr_t base, phys_addr_t size,
+ bool dynamic);
static int fdt_validate_reserved_mem_node(unsigned long node,
phys_addr_t *align);
static int fdt_fixup_reserved_mem_node(unsigned long node,
@@ -308,7 +309,7 @@ void __init fdt_scan_reserved_mem_late(void)
if (size) {
uname = fdt_get_name(fdt, child, NULL);
- fdt_init_reserved_mem_node(child, uname, base, size);
+ fdt_init_reserved_mem_node(child, uname, base, size, false);
}
}
@@ -518,7 +519,7 @@ static int __init __reserved_mem_alloc_size(unsigned long node, const char *unam
}
fdt_fixup_reserved_mem_node(node, base, size);
- fdt_init_reserved_mem_node(node, uname, base, size);
+ fdt_init_reserved_mem_node(node, uname, base, size, true);
return 0;
}
@@ -627,13 +628,15 @@ static int __init __reserved_mem_init_node(struct reserved_mem *rmem,
* @uname: name of the reserved memory node
* @base: base address of the reserved memory region
* @size: size of the reserved memory region
+ * @dynamic: whether the region was dynamically allocated
*
* This function calls the region-specific initialization function for a
* reserved memory region and saves all region-specific data to the
* reserved_mem array to allow of_reserved_mem_lookup() to find it.
*/
static void __init fdt_init_reserved_mem_node(unsigned long node, const char *uname,
- phys_addr_t base, phys_addr_t size)
+ phys_addr_t base, phys_addr_t size,
+ bool dynamic)
{
int err = 0;
bool nomap;
@@ -659,7 +662,7 @@ static void __init fdt_init_reserved_mem_node(unsigned long node, const char *un
if (nomap)
memblock_clear_nomap(rmem->base, rmem->size);
- else
+ if (dynamic || !nomap)
memblock_phys_free(rmem->base, rmem->size);
return;
} else {
--
2.43.0
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH v3 2/5] of: reserved_mem: retain static no-map memory on init failure
2026-09-20 9:28 [PATCH v3 0/5] of: reserved_mem: several fixes about reserved memory Wandun Chen
2026-09-20 9:28 ` [PATCH v3 1/5] of: reserved_mem: release dynamically allocated no-map region on init failure Wandun Chen
@ 2026-09-20 9:28 ` Wandun Chen
2026-09-20 9:28 ` [PATCH v3 3/5] of: reserved_mem: skip init for regions whose early reservation failed Wandun Chen
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Wandun Chen @ 2026-09-20 9:28 UTC (permalink / raw)
To: robh, saravanak, rppt, m.szyprowski, devicetree, linux-kernel, linux-mm
Cc: akpm
From: Wandun Chen <chenwandun@lixiang.com>
Static no-map reserved-memory regions are initialized after paging_init().
If initialization fails, MEMBLOCK_NOMAP would be cleared, and the memory
is available to the buddy allocator even though it was excluded from the
kernel linear mapping.
Clear MEMBLOCK_NOMAP only for dynamically allocated regions, which are
initialized before paging_init() and can safely be made available to the
kernel linear mapping.
Sashiko found this issue in [1].
Fixes: 8a6e02d0c00e ("of: reserved_mem: Restructure how the reserved memory regions are processed")
Acked-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Wandun Chen <chenwandun@lixiang.com>
Link: https://sashiko.dev/#/message/20260814090305.4C8741F00A3D%40smtp.kernel.org [1]
---
drivers/of/of_reserved_mem.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
index f55ed3b5aaa4..2c64d85cabc6 100644
--- a/drivers/of/of_reserved_mem.c
+++ b/drivers/of/of_reserved_mem.c
@@ -660,7 +660,7 @@ static void __init fdt_init_reserved_mem_node(unsigned long node, const char *un
pr_info("node %s compatible matching fail\n", rmem->name);
rmem->name = NULL;
- if (nomap)
+ if (dynamic && nomap)
memblock_clear_nomap(rmem->base, rmem->size);
if (dynamic || !nomap)
memblock_phys_free(rmem->base, rmem->size);
--
2.43.0
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH v3 3/5] of: reserved_mem: skip init for regions whose early reservation failed
2026-09-20 9:28 [PATCH v3 0/5] of: reserved_mem: several fixes about reserved memory Wandun Chen
2026-09-20 9:28 ` [PATCH v3 1/5] of: reserved_mem: release dynamically allocated no-map region on init failure Wandun Chen
2026-09-20 9:28 ` [PATCH v3 2/5] of: reserved_mem: retain static no-map memory " Wandun Chen
@ 2026-09-20 9:28 ` Wandun Chen
2026-09-20 9:28 ` [PATCH v3 4/5] of: reserved_mem: reject static regions overlapping no-map memory Wandun Chen
2026-09-20 9:28 ` [PATCH v3 5/5] of: reserved_mem: reject static mapped regions overlapping existing reservations Wandun Chen
4 siblings, 0 replies; 6+ messages in thread
From: Wandun Chen @ 2026-09-20 9:28 UTC (permalink / raw)
To: robh, saravanak, rppt, m.szyprowski, devicetree, linux-kernel, linux-mm
Cc: akpm
From: Wandun Chen <chenwandun@lixiang.com>
__reserved_mem_reserve_reg() discards the error from
early_init_dt_reserve_memory() and returns 0 unconditionally, so the
caller counts the node in total_reserved_mem_cnt and the late scan
initializes it without checking whether the early reservation actually
succeeded. A region whose reservation failed is then handed to a
device assuming the memory is protected.
Tag each region in memblock with MEMBLOCK_RSRV_RMEM when its early
reservation succeeds, so the late scan can check whether the node's own
reservation succeeded and skip those that failed.
Fixes: 8a6e02d0c00e ("of: reserved_mem: Restructure how the reserved memory regions are processed")
Suggested-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Wandun Chen <chenwandun@lixiang.com>
---
drivers/of/of_reserved_mem.c | 46 ++++++++++++++++++------
include/linux/memblock.h | 6 ++++
mm/memblock.c | 69 ++++++++++++++++++++++++++++++++++++
3 files changed, 110 insertions(+), 11 deletions(-)
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
index 2c64d85cabc6..3a6c6dbfd7b1 100644
--- a/drivers/of/of_reserved_mem.c
+++ b/drivers/of/of_reserved_mem.c
@@ -122,6 +122,8 @@ static int fdt_fixup_reserved_mem_node(unsigned long node,
static int __init early_init_dt_reserve_memory(phys_addr_t base,
phys_addr_t size, bool nomap)
{
+ int ret;
+
if (nomap) {
/*
* If the memory is already reserved (by another region), we
@@ -132,9 +134,16 @@ static int __init early_init_dt_reserve_memory(phys_addr_t base,
memblock_is_region_reserved(base, size))
return -EBUSY;
- return memblock_mark_nomap(base, size);
+ ret = memblock_mark_nomap(base, size);
+ if (!ret)
+ memblock_mark_rsrv_rmem(base, size);
+ return ret;
}
- return memblock_reserve(base, size);
+
+ ret = memblock_reserve(base, size);
+ if (!ret)
+ memblock_mark_rsrv_rmem(base, size);
+ return ret;
}
/*
@@ -168,14 +177,19 @@ static int __init __reserved_mem_reserve_reg(unsigned long node,
base = b;
size = s;
- if (size && early_init_dt_reserve_memory(base, size, nomap) == 0) {
- fdt_fixup_reserved_mem_node(node, base, size);
- pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %lu MiB\n",
- uname, &base, (unsigned long)(size / SZ_1M));
- } else {
+ if (!size)
+ return -EINVAL;
+
+ err = early_init_dt_reserve_memory(base, size, nomap);
+ if (err) {
pr_err("Reserved memory: failed to reserve memory for node '%s': base %pa, size %lu MiB\n",
uname, &base, (unsigned long)(size / SZ_1M));
+ return err;
}
+
+ fdt_fixup_reserved_mem_node(node, base, size);
+ pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %lu MiB\n",
+ uname, &base, (unsigned long)(size / SZ_1M));
return 0;
}
@@ -288,6 +302,7 @@ void __init fdt_scan_reserved_mem_late(void)
fdt_for_each_subnode(child, fdt, node) {
const __be32 *prop;
const char *uname;
+ bool nomap;
u64 b, s;
int ret;
int len;
@@ -307,10 +322,15 @@ void __init fdt_scan_reserved_mem_late(void)
base = b;
size = s;
- if (size) {
- uname = fdt_get_name(fdt, child, NULL);
- fdt_init_reserved_mem_node(child, uname, base, size, false);
- }
+ if (!size)
+ continue;
+
+ nomap = of_get_flat_dt_prop(child, "no-map", NULL) != NULL;
+ if (!memblock_is_region_rsrv_rmem(base, size, nomap))
+ continue;
+
+ uname = fdt_get_name(fdt, child, NULL);
+ fdt_init_reserved_mem_node(child, uname, base, size, false);
}
/* check for overlapping reserved regions */
@@ -662,8 +682,12 @@ static void __init fdt_init_reserved_mem_node(unsigned long node, const char *un
if (dynamic && nomap)
memblock_clear_nomap(rmem->base, rmem->size);
+
if (dynamic || !nomap)
memblock_phys_free(rmem->base, rmem->size);
+
+ if (!dynamic)
+ memblock_clear_rsrv_rmem(rmem->base, rmem->size);
return;
} else {
phys_addr_t end = rmem->base + rmem->size - 1;
diff --git a/include/linux/memblock.h b/include/linux/memblock.h
index aa845f488327..03613fa0c894 100644
--- a/include/linux/memblock.h
+++ b/include/linux/memblock.h
@@ -52,6 +52,7 @@ extern unsigned long long max_possible_pfn;
* kernel that we know is good to use. It is the only memory that
* allocations may happen from in this phase.
* @MEMBLOCK_RSRV_HUGETLB: memory is reserved for hugetlb pages
+ * @MEMBLOCK_RSRV_RMEM: memory reserved by a static /reserved-memory node
*/
enum memblock_flags {
MEMBLOCK_NONE = 0x0, /* No special request */
@@ -63,6 +64,7 @@ enum memblock_flags {
MEMBLOCK_RSRV_KERN = 0x20, /* memory reserved for kernel use */
MEMBLOCK_KHO_SCRATCH = 0x40, /* scratch memory for kexec handover */
MEMBLOCK_RSRV_HUGETLB = 0x80, /* memory reserved for hugetlb pages */
+ MEMBLOCK_RSRV_RMEM = 0x100, /* static /reserved-memory node */
};
/**
@@ -160,6 +162,10 @@ int memblock_reserved_mark_noinit(phys_addr_t base, phys_addr_t size);
int memblock_reserved_mark_kern(phys_addr_t base, phys_addr_t size);
int memblock_mark_kho_scratch(phys_addr_t base, phys_addr_t size);
int memblock_clear_kho_scratch(phys_addr_t base, phys_addr_t size);
+int memblock_mark_rsrv_rmem(phys_addr_t base, phys_addr_t size);
+int memblock_clear_rsrv_rmem(phys_addr_t base, phys_addr_t size);
+bool memblock_is_region_rsrv_rmem(phys_addr_t base, phys_addr_t size,
+ bool nomap);
void memblock_free(void *ptr, size_t size);
diff --git a/mm/memblock.c b/mm/memblock.c
index ea0de4b5f356..d88e926e2ea5 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -1204,6 +1204,39 @@ __init int memblock_clear_kho_scratch(phys_addr_t base, phys_addr_t size)
MEMBLOCK_KHO_SCRATCH);
}
+/**
+ * memblock_mark_rsrv_rmem - Mark a region reserved by a static /reserved-memory node
+ * @base: the base phys addr of the region
+ * @size: the size of the region
+ *
+ * Only called for statically placed reserved-memory regions (those defined
+ * by a "reg" property), so the late scan can later tell such a region apart
+ * from one reserved by unrelated code.
+ *
+ * Return: 0 on success, -errno on failure.
+ */
+int __init_memblock memblock_mark_rsrv_rmem(phys_addr_t base, phys_addr_t size)
+{
+ return memblock_setclr_flag(&memblock.memory, base, size, 1,
+ MEMBLOCK_RSRV_RMEM);
+}
+
+/**
+ * memblock_clear_rsrv_rmem - Clear the static /reserved-memory node tag
+ * @base: the base phys addr of the region
+ * @size: the size of the region
+ *
+ * Only called for statically placed reserved-memory regions whose late
+ * initialization failed, to undo the tag set by memblock_mark_rsrv_rmem().
+ *
+ * Return: 0 on success, -errno on failure.
+ */
+int __init_memblock memblock_clear_rsrv_rmem(phys_addr_t base, phys_addr_t size)
+{
+ return memblock_setclr_flag(&memblock.memory, base, size, 0,
+ MEMBLOCK_RSRV_RMEM);
+}
+
static bool should_skip_region(struct memblock_type *type,
struct memblock_region *m,
int nid, int flags)
@@ -2154,6 +2187,41 @@ bool __init_memblock memblock_is_region_reserved(phys_addr_t base, phys_addr_t s
return memblock_overlaps_region(&memblock.reserved, base, size);
}
+/**
+ * memblock_is_region_rsrv_rmem - check if a range is tagged by MEMBLOCK_RSRV_RMEM
+ * @base: the base phys addr of the range
+ * @size: the size of the range
+ * @nomap: the expected no-map state of the range
+ *
+ * A range with no overlap in memblock.memory lies entirely outside
+ * declared system memory, where the tag could never be applied, so it is
+ * treated as reserved. Otherwise, every overlapping region must carry the
+ * %MEMBLOCK_RSRV_RMEM tag and match @nomap.
+ *
+ * Return: true if the range is reserved, false otherwise.
+ */
+bool __init_memblock memblock_is_region_rsrv_rmem(phys_addr_t base,
+ phys_addr_t size, bool nomap)
+{
+ phys_addr_t end = base + memblock_cap_size(base, &size);
+ unsigned long i;
+
+ for (i = 0; i < memblock.memory.cnt; i++) {
+ struct memblock_region *r = &memblock.memory.regions[i];
+
+ if (r->base >= end)
+ break;
+ if (!memblock_addrs_overlap(base, size, r->base, r->size))
+ continue;
+ if (!(r->flags & MEMBLOCK_RSRV_RMEM))
+ return false;
+ if (memblock_is_nomap(r) != nomap)
+ return false;
+ }
+
+ return true;
+}
+
void __init_memblock memblock_trim_memory(phys_addr_t align)
{
phys_addr_t start, end, orig_start, orig_end;
@@ -2880,6 +2948,7 @@ static const char * const flagname[] = {
[ilog2(MEMBLOCK_RSRV_KERN)] = "RSV_KERN",
[ilog2(MEMBLOCK_KHO_SCRATCH)] = "KHO_SCRATCH",
[ilog2(MEMBLOCK_RSRV_HUGETLB)] = "RSV_HUGETLB",
+ [ilog2(MEMBLOCK_RSRV_RMEM)] = "RSV_RMEM",
};
static int memblock_debug_show(struct seq_file *m, void *private)
--
2.43.0
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH v3 4/5] of: reserved_mem: reject static regions overlapping no-map memory
2026-09-20 9:28 [PATCH v3 0/5] of: reserved_mem: several fixes about reserved memory Wandun Chen
` (2 preceding siblings ...)
2026-09-20 9:28 ` [PATCH v3 3/5] of: reserved_mem: skip init for regions whose early reservation failed Wandun Chen
@ 2026-09-20 9:28 ` Wandun Chen
2026-09-20 9:28 ` [PATCH v3 5/5] of: reserved_mem: reject static mapped regions overlapping existing reservations Wandun Chen
4 siblings, 0 replies; 6+ messages in thread
From: Wandun Chen @ 2026-09-20 9:28 UTC (permalink / raw)
To: robh, saravanak, rppt, m.szyprowski, devicetree, linux-kernel, linux-mm
Cc: akpm
From: Wandun Chen <chenwandun@lixiang.com>
Static no-map reserved-memory regions are marked in memblock.memory rather
than memblock.reserved. So the reservation overlap check does not reject a
static region that overlaps existing no-map memory.
Both regions can then be initialized and hand the same physical memory to
different reserved-memory drivers. So reject a static no-map region that
overlaps existing reserved no-map memory, and skip a no-map region in
the late scan that overlaps one already reserved.
Sashiko found this issue in [1].
Fixes: 86588296acbf ("fdt: Properly handle "no-map" field in the memory region")
Suggested-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Wandun Chen <chenwandun@lixiang.com>
Link: https://sashiko.dev/#/message/20260814084718.29C341F000E9%40smtp.kernel.org [1]
---
drivers/of/of_reserved_mem.c | 23 +++++++++++++++++++++--
include/linux/memblock.h | 1 +
mm/memblock.c | 26 ++++++++++++++++++++++++++
3 files changed, 48 insertions(+), 2 deletions(-)
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
index 3a6c6dbfd7b1..8d2057f2ac12 100644
--- a/drivers/of/of_reserved_mem.c
+++ b/drivers/of/of_reserved_mem.c
@@ -131,7 +131,8 @@ static int __init early_init_dt_reserve_memory(phys_addr_t base,
* if the region isn't memory as it won't be mapped.
*/
if (memblock_overlaps_region(&memblock.memory, base, size) &&
- memblock_is_region_reserved(base, size))
+ (memblock_is_region_reserved(base, size) ||
+ memblock_overlaps_nomap_region(base, size)))
return -EBUSY;
ret = memblock_mark_nomap(base, size);
@@ -266,6 +267,20 @@ static void __init __rmem_check_for_overlap(void)
}
}
+static bool __init rmem_overlaps_check(phys_addr_t base, phys_addr_t size,
+ int start)
+{
+ int i;
+
+ for (i = start; i < reserved_mem_count; i++) {
+ struct reserved_mem *r = &reserved_mem[i];
+
+ if (memblock_addrs_overlap(base, size, r->base, r->size))
+ return true;
+ }
+ return false;
+}
+
/**
* fdt_scan_reserved_mem_late() - Scan FDT and initialize remaining reserved
* memory regions.
@@ -279,7 +294,7 @@ void __init fdt_scan_reserved_mem_late(void)
{
const void *fdt = initial_boot_params;
phys_addr_t base, size;
- int node, child;
+ int node, child, static_reserved_start;
if (!fdt)
return;
@@ -299,6 +314,8 @@ void __init fdt_scan_reserved_mem_late(void)
return;
}
+ static_reserved_start = reserved_mem_count;
+
fdt_for_each_subnode(child, fdt, node) {
const __be32 *prop;
const char *uname;
@@ -326,6 +343,8 @@ void __init fdt_scan_reserved_mem_late(void)
continue;
nomap = of_get_flat_dt_prop(child, "no-map", NULL) != NULL;
+ if (nomap && rmem_overlaps_check(base, size, static_reserved_start))
+ continue;
if (!memblock_is_region_rsrv_rmem(base, size, nomap))
continue;
diff --git a/include/linux/memblock.h b/include/linux/memblock.h
index 03613fa0c894..34a695542ab1 100644
--- a/include/linux/memblock.h
+++ b/include/linux/memblock.h
@@ -504,6 +504,7 @@ bool memblock_is_map_memory(phys_addr_t addr);
bool memblock_is_region_memory(phys_addr_t base, phys_addr_t size);
bool memblock_is_reserved(phys_addr_t addr);
bool memblock_is_region_reserved(phys_addr_t base, phys_addr_t size);
+bool memblock_overlaps_nomap_region(phys_addr_t base, phys_addr_t size);
void memblock_dump_all(void);
diff --git a/mm/memblock.c b/mm/memblock.c
index d88e926e2ea5..58c9281e729e 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -2222,6 +2222,32 @@ bool __init_memblock memblock_is_region_rsrv_rmem(phys_addr_t base,
return true;
}
+/**
+ * memblock_overlaps_nomap_region - check if a region intersects no-map memory
+ * @base: base of region to check
+ * @size: size of region to check
+ *
+ * Check if the region [@base, @base + @size) intersects a memory block
+ * marked %MEMBLOCK_NOMAP.
+ *
+ * Return:
+ * True if they intersect, false if not.
+ */
+bool __init_memblock memblock_overlaps_nomap_region(phys_addr_t base,
+ phys_addr_t size)
+{
+ struct memblock_region *region;
+
+ memblock_cap_size(base, &size);
+ for_each_mem_region(region) {
+ if (memblock_is_nomap(region) &&
+ memblock_addrs_overlap(base, size, region->base, region->size))
+ return true;
+ }
+
+ return false;
+}
+
void __init_memblock memblock_trim_memory(phys_addr_t align)
{
phys_addr_t start, end, orig_start, orig_end;
--
2.43.0
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH v3 5/5] of: reserved_mem: reject static mapped regions overlapping existing reservations
2026-09-20 9:28 [PATCH v3 0/5] of: reserved_mem: several fixes about reserved memory Wandun Chen
` (3 preceding siblings ...)
2026-09-20 9:28 ` [PATCH v3 4/5] of: reserved_mem: reject static regions overlapping no-map memory Wandun Chen
@ 2026-09-20 9:28 ` Wandun Chen
4 siblings, 0 replies; 6+ messages in thread
From: Wandun Chen @ 2026-09-20 9:28 UTC (permalink / raw)
To: robh, saravanak, rppt, m.szyprowski, devicetree, linux-kernel, linux-mm
Cc: akpm
From: Wandun Chen <chenwandun@lixiang.com>
memblock_reserve() permits overlapping reservations, so a statically
placed region whose 'reg' overlaps an existing one is accepted. When
initialization of a statically placed reserved-memory region
overlapping an existing reservation fails, memblock_phys_free()
returns the overlap to the buddy allocator, corrupting that memory.
Reject the overlap up front. Dynamically allocated regions are
unaffected, as they are allocated from free memory and so cannot
overlap an existing reservation.
Sashiko found this issue in [1].
Fixes: d0b8ed47e83a ("of: reserved_mem: fix reserve memory leak")
Suggested-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Wandun Chen <chenwandun@lixiang.com>
Link: https://sashiko.dev/#/message/20260806100605.2C2C01F000E9%40smtp.kernel.org [1]
---
drivers/of/of_reserved_mem.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
index 8d2057f2ac12..2d1e01c0f886 100644
--- a/drivers/of/of_reserved_mem.c
+++ b/drivers/of/of_reserved_mem.c
@@ -141,6 +141,10 @@ static int __init early_init_dt_reserve_memory(phys_addr_t base,
return ret;
}
+ if (memblock_is_region_reserved(base, size) ||
+ memblock_overlaps_nomap_region(base, size))
+ return -EBUSY;
+
ret = memblock_reserve(base, size);
if (!ret)
memblock_mark_rsrv_rmem(base, size);
@@ -343,7 +347,7 @@ void __init fdt_scan_reserved_mem_late(void)
continue;
nomap = of_get_flat_dt_prop(child, "no-map", NULL) != NULL;
- if (nomap && rmem_overlaps_check(base, size, static_reserved_start))
+ if (rmem_overlaps_check(base, size, static_reserved_start))
continue;
if (!memblock_is_region_rsrv_rmem(base, size, nomap))
continue;
--
2.43.0
^ permalink raw reply [flat|nested] 6+ messages in thread