From: Wandun Chen <chenwandun1@gmail.com>
To: robh@kernel.org, saravanak@kernel.org, rppt@kernel.org,
m.szyprowski@samsung.com, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-mm@kvack.org
Cc: akpm@linux-foundation.org
Subject: [PATCH v3 3/5] of: reserved_mem: skip init for regions whose early reservation failed
Date: Sun, 20 Sep 2026 17:28:50 +0800 [thread overview]
Message-ID: <20260920092852.614973-4-chenwandun1@gmail.com> (raw)
In-Reply-To: <20260920092852.614973-1-chenwandun1@gmail.com>
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
next prev parent reply other threads:[~2026-09-20 9:29 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
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 [this message]
2026-09-20 9:28 ` [PATCH v3 4/5] of: reserved_mem: reject static regions overlapping no-map memory Wandun Chen
2026-09-20 10:03 ` sashiko-bot
2026-09-20 9:28 ` [PATCH v3 5/5] of: reserved_mem: reject static mapped regions overlapping existing reservations Wandun Chen
2026-09-20 10:13 ` sashiko-bot
2026-09-22 8:48 ` [PATCH v3 0/5] of: reserved_mem: several fixes about reserved memory Mike Rapoport
2026-09-22 9:24 ` Wandun
2026-10-03 8:04 ` Mike Rapoport
2026-10-06 13:26 ` Marek Szyprowski
2026-10-08 6:38 ` Mike Rapoport
2026-10-08 9:43 ` Marek Szyprowski
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260920092852.614973-4-chenwandun1@gmail.com \
--to=chenwandun1@gmail.com \
--cc=akpm@linux-foundation.org \
--cc=devicetree@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=m.szyprowski@samsung.com \
--cc=robh@kernel.org \
--cc=rppt@kernel.org \
--cc=saravanak@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.