Thread (1 message) 1 message, 1 author, 2025-10-07

Re: [PATCH v4 03/30] kho: drop notifiers

From: Pratyush Yadav <pratyush@kernel.org>
Date: 2025-10-07 13:30:24
Also in: linux-doc, linux-fsdevel, linux-mm, lkml

On Tue, Oct 07 2025, Pasha Tatashin wrote:
On Tue, Oct 7, 2025 at 8:10 AM Pratyush Yadav [off-list ref] wrote:
quoted
On Mon, Oct 06 2025, Pasha Tatashin wrote:
quoted
On Mon, Oct 6, 2025 at 1:01 PM Pratyush Yadav [off-list ref] wrote:
quoted
On Mon, Sep 29 2025, Pasha Tatashin wrote:
quoted
From: "Mike Rapoport (Microsoft)" <rppt@kernel.org>

The KHO framework uses a notifier chain as the mechanism for clients to
participate in the finalization process. While this works for a single,
central state machine, it is too restrictive for kernel-internal
components like pstore/reserve_mem or IMA. These components need a
simpler, direct way to register their state for preservation (e.g.,
during their initcall) without being part of a complex,
shutdown-time notifier sequence. The notifier model forces all
participants into a single finalization flow and makes direct
preservation from an arbitrary context difficult.
This patch refactors the client participation model by removing the
notifier chain and introducing a direct API for managing FDT subtrees.

The core kho_finalize() and kho_abort() state machine remains, but
clients now register their data with KHO beforehand.

Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
[...]
quoted
diff --git a/mm/memblock.c b/mm/memblock.c
index e23e16618e9b..c4b2d4e4c715 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -2444,53 +2444,18 @@ int reserve_mem_release_by_name(const char *name)
 #define MEMBLOCK_KHO_FDT "memblock"
 #define MEMBLOCK_KHO_NODE_COMPATIBLE "memblock-v1"
 #define RESERVE_MEM_KHO_NODE_COMPATIBLE "reserve-mem-v1"
-static struct page *kho_fdt;
-
-static int reserve_mem_kho_finalize(struct kho_serialization *ser)
-{
-     int err = 0, i;
-
-     for (i = 0; i < reserved_mem_count; i++) {
-             struct reserve_mem_table *map = &reserved_mem_table[i];
-             struct page *page = phys_to_page(map->start);
-             unsigned int nr_pages = map->size >> PAGE_SHIFT;
-
-             err |= kho_preserve_pages(page, nr_pages);
-     }
-
-     err |= kho_preserve_folio(page_folio(kho_fdt));
-     err |= kho_add_subtree(ser, MEMBLOCK_KHO_FDT, page_to_virt(kho_fdt));
-
-     return notifier_from_errno(err);
-}
-
-static int reserve_mem_kho_notifier(struct notifier_block *self,
-                                 unsigned long cmd, void *v)
-{
-     switch (cmd) {
-     case KEXEC_KHO_FINALIZE:
-             return reserve_mem_kho_finalize((struct kho_serialization *)v);
-     case KEXEC_KHO_ABORT:
-             return NOTIFY_DONE;
-     default:
-             return NOTIFY_BAD;
-     }
-}
-
-static struct notifier_block reserve_mem_kho_nb = {
-     .notifier_call = reserve_mem_kho_notifier,
-};

 static int __init prepare_kho_fdt(void)
 {
      int err = 0, i;
+     struct page *fdt_page;
      void *fdt;

-     kho_fdt = alloc_page(GFP_KERNEL);
-     if (!kho_fdt)
+     fdt_page = alloc_page(GFP_KERNEL);
+     if (!fdt_page)
              return -ENOMEM;

-     fdt = page_to_virt(kho_fdt);
+     fdt = page_to_virt(fdt_page);

      err |= fdt_create(fdt, PAGE_SIZE);
      err |= fdt_finish_reservemap(fdt);
@@ -2499,7 +2464,10 @@ static int __init prepare_kho_fdt(void)
      err |= fdt_property_string(fdt, "compatible", MEMBLOCK_KHO_NODE_COMPATIBLE);
      for (i = 0; i < reserved_mem_count; i++) {
              struct reserve_mem_table *map = &reserved_mem_table[i];
+             struct page *page = phys_to_page(map->start);
+             unsigned int nr_pages = map->size >> PAGE_SHIFT;

+             err |= kho_preserve_pages(page, nr_pages);
              err |= fdt_begin_node(fdt, map->name);
              err |= fdt_property_string(fdt, "compatible", RESERVE_MEM_KHO_NODE_COMPATIBLE);
              err |= fdt_property(fdt, "start", &map->start, sizeof(map->start));
@@ -2507,13 +2475,14 @@ static int __init prepare_kho_fdt(void)
              err |= fdt_end_node(fdt);
      }
      err |= fdt_end_node(fdt);
-
      err |= fdt_finish(fdt);

+     err |= kho_preserve_folio(page_folio(fdt_page));
+     err |= kho_add_subtree(MEMBLOCK_KHO_FDT, fdt);
+
      if (err) {
              pr_err("failed to prepare memblock FDT for KHO: %d\n", err);
-             put_page(kho_fdt);
-             kho_fdt = NULL;
+             put_page(fdt_page);
This adds subtree to KHO even if the FDT might be invalid. And then
leaves a dangling reference in KHO to the FDT in case of an error. I
think you should either do this check after
kho_preserve_folio(page_folio(fdt_page)) and do a clean error check for
kho_add_subtree(), or call kho_remove_subtree() in the error block.
I agree, I do not like these err |= stuff, we should be checking
errors cleanly, and do proper clean-ups.
Yeah, this is mainly a byproduct of using FDTs. Getting and setting
simple properties also needs error checking and that can get tedious
real quick. Which is why this pattern has shown up I suppose.
Exactly. This is also why it's important to replace FDT with something
more sensible for general-purpose live update purposes.

By the way, I forgot to address this comment in the v5 of the KHO
series I sent out yesterday. Could you please take another look? If
everything else is good, I will refresh that series so we can ask
Andrew to take in the KHO patches. That would simplify the LUO series.
Good idea. Will take a look.

[...]

-- 
Regards,
Pratyush Yadav
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help