Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

kho: update FDT dynamically for subtree addition/removal

Currently, sub-FDTs were tracked in a list (kho_out.sub_fdts) and the
final FDT is constructed entirely from scratch during kho_finalize().

We can maintain the FDT dynamically:
1. Initialize a valid, empty FDT in kho_init().
2. Use fdt_add_subnode and fdt_setprop in kho_add_subtree to
update the FDT immediately when a subsystem registers.
3. Use fdt_del_node in kho_remove_subtree to remove entries.

This removes the need for the intermediate sub_fdts list and the
reconstruction logic in kho_finalize(). kho_finalize() now only needs to
trigger memory map serialization.

Link: https://lkml.kernel.org/r/20251114190002.3311679-11-pasha.tatashin@soleen.com
Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Reviewed-by: Pratyush Yadav <pratyush@kernel.org>
Cc: Alexander Graf <graf@amazon.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Baoquan He <bhe@redhat.com>
Cc: Coiby Xu <coxu@redhat.com>
Cc: Dave Vasilevsky <dave@vasilevsky.ca>
Cc: Eric Biggers <ebiggers@google.com>
Cc: Kees Cook <kees@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Pasha Tatashin and committed by
Andrew Morton
8e068a28 9a4301f7

+69 -75
+69 -75
kernel/liveupdate/kexec_handover.c
··· 104 104 105 105 struct khoser_mem_chunk; 106 106 107 - struct kho_sub_fdt { 108 - struct list_head l; 109 - const char *name; 110 - void *fdt; 111 - }; 112 - 113 107 struct kho_out { 114 108 void *fdt; 115 109 bool finalized; 116 110 struct mutex lock; /* protects KHO FDT finalization */ 117 - 118 - struct list_head sub_fdts; 119 - struct mutex fdts_lock; 120 111 121 112 struct kho_mem_track track; 122 113 struct kho_debugfs dbg; ··· 118 127 .track = { 119 128 .orders = XARRAY_INIT(kho_out.track.orders, 0), 120 129 }, 121 - .sub_fdts = LIST_HEAD_INIT(kho_out.sub_fdts), 122 - .fdts_lock = __MUTEX_INITIALIZER(kho_out.fdts_lock), 123 130 .finalized = false, 124 131 }; 125 132 ··· 714 725 */ 715 726 int kho_add_subtree(const char *name, void *fdt) 716 727 { 717 - struct kho_sub_fdt *sub_fdt; 728 + phys_addr_t phys = virt_to_phys(fdt); 729 + void *root_fdt = kho_out.fdt; 730 + int err = -ENOMEM; 731 + int off, fdt_err; 718 732 719 - sub_fdt = kmalloc(sizeof(*sub_fdt), GFP_KERNEL); 720 - if (!sub_fdt) 721 - return -ENOMEM; 733 + guard(mutex)(&kho_out.lock); 722 734 723 - INIT_LIST_HEAD(&sub_fdt->l); 724 - sub_fdt->name = name; 725 - sub_fdt->fdt = fdt; 735 + fdt_err = fdt_open_into(root_fdt, root_fdt, PAGE_SIZE); 736 + if (fdt_err < 0) 737 + return err; 726 738 727 - guard(mutex)(&kho_out.fdts_lock); 728 - list_add_tail(&sub_fdt->l, &kho_out.sub_fdts); 739 + off = fdt_add_subnode(root_fdt, 0, name); 740 + if (off < 0) { 741 + if (off == -FDT_ERR_EXISTS) 742 + err = -EEXIST; 743 + goto out_pack; 744 + } 745 + 746 + err = fdt_setprop(root_fdt, off, PROP_SUB_FDT, &phys, sizeof(phys)); 747 + if (err < 0) 748 + goto out_pack; 749 + 729 750 WARN_ON_ONCE(kho_debugfs_fdt_add(&kho_out.dbg, name, fdt, false)); 730 751 731 - return 0; 752 + out_pack: 753 + fdt_pack(root_fdt); 754 + 755 + return err; 732 756 } 733 757 EXPORT_SYMBOL_GPL(kho_add_subtree); 734 758 735 759 void kho_remove_subtree(void *fdt) 736 760 { 737 - struct kho_sub_fdt *sub_fdt; 761 + phys_addr_t target_phys = virt_to_phys(fdt); 762 + void *root_fdt = kho_out.fdt; 763 + int off; 764 + int err; 738 765 739 - guard(mutex)(&kho_out.fdts_lock); 740 - list_for_each_entry(sub_fdt, &kho_out.sub_fdts, l) { 741 - if (sub_fdt->fdt == fdt) { 742 - list_del(&sub_fdt->l); 743 - kfree(sub_fdt); 766 + guard(mutex)(&kho_out.lock); 767 + 768 + err = fdt_open_into(root_fdt, root_fdt, PAGE_SIZE); 769 + if (err < 0) 770 + return; 771 + 772 + for (off = fdt_first_subnode(root_fdt, 0); off >= 0; 773 + off = fdt_next_subnode(root_fdt, off)) { 774 + const u64 *val; 775 + int len; 776 + 777 + val = fdt_getprop(root_fdt, off, PROP_SUB_FDT, &len); 778 + if (!val || len != sizeof(phys_addr_t)) 779 + continue; 780 + 781 + if ((phys_addr_t)*val == target_phys) { 782 + fdt_del_node(root_fdt, off); 744 783 kho_debugfs_fdt_remove(&kho_out.dbg, fdt); 745 784 break; 746 785 } 747 786 } 787 + 788 + fdt_pack(root_fdt); 748 789 } 749 790 EXPORT_SYMBOL_GPL(kho_remove_subtree); 750 791 ··· 1251 1232 } 1252 1233 EXPORT_SYMBOL_GPL(kho_restore_free); 1253 1234 1254 - static int __kho_finalize(void) 1255 - { 1256 - void *root = kho_out.fdt; 1257 - struct kho_sub_fdt *fdt; 1258 - u64 empty_mem_map = 0; 1259 - int err; 1260 - 1261 - err = fdt_create(root, PAGE_SIZE); 1262 - err |= fdt_finish_reservemap(root); 1263 - err |= fdt_begin_node(root, ""); 1264 - err |= fdt_property_string(root, "compatible", KHO_FDT_COMPATIBLE); 1265 - err |= fdt_property(root, PROP_PRESERVED_MEMORY_MAP, &empty_mem_map, 1266 - sizeof(empty_mem_map)); 1267 - if (err) 1268 - goto err_exit; 1269 - 1270 - mutex_lock(&kho_out.fdts_lock); 1271 - list_for_each_entry(fdt, &kho_out.sub_fdts, l) { 1272 - phys_addr_t phys = virt_to_phys(fdt->fdt); 1273 - 1274 - err |= fdt_begin_node(root, fdt->name); 1275 - err |= fdt_property(root, PROP_SUB_FDT, &phys, sizeof(phys)); 1276 - err |= fdt_end_node(root); 1277 - } 1278 - mutex_unlock(&kho_out.fdts_lock); 1279 - 1280 - err |= fdt_end_node(root); 1281 - err |= fdt_finish(root); 1282 - if (err) 1283 - goto err_exit; 1284 - 1285 - err = kho_mem_serialize(&kho_out); 1286 - if (err) 1287 - goto err_exit; 1288 - 1289 - return 0; 1290 - 1291 - err_exit: 1292 - pr_err("Failed to convert KHO state tree: %d\n", err); 1293 - return err; 1294 - } 1295 - 1296 1235 int kho_finalize(void) 1297 1236 { 1298 1237 int ret; ··· 1259 1282 return -EOPNOTSUPP; 1260 1283 1261 1284 guard(mutex)(&kho_out.lock); 1262 - if (kho_out.finalized) { 1263 - kho_update_memory_map(NULL); 1264 - kho_out.finalized = false; 1265 - } 1266 - 1267 - ret = __kho_finalize(); 1285 + ret = kho_mem_serialize(&kho_out); 1268 1286 if (ret) 1269 1287 return ret; 1270 1288 ··· 1344 1372 } 1345 1373 EXPORT_SYMBOL_GPL(kho_retrieve_subtree); 1346 1374 1375 + static __init int kho_out_fdt_setup(void) 1376 + { 1377 + void *root = kho_out.fdt; 1378 + u64 empty_mem_map = 0; 1379 + int err; 1380 + 1381 + err = fdt_create(root, PAGE_SIZE); 1382 + err |= fdt_finish_reservemap(root); 1383 + err |= fdt_begin_node(root, ""); 1384 + err |= fdt_property_string(root, "compatible", KHO_FDT_COMPATIBLE); 1385 + err |= fdt_property(root, PROP_PRESERVED_MEMORY_MAP, &empty_mem_map, 1386 + sizeof(empty_mem_map)); 1387 + err |= fdt_end_node(root); 1388 + err |= fdt_finish(root); 1389 + 1390 + return err; 1391 + } 1392 + 1347 1393 static __init int kho_init(void) 1348 1394 { 1349 1395 const void *fdt = kho_get_fdt(); ··· 1381 1391 goto err_free_fdt; 1382 1392 1383 1393 err = kho_out_debugfs_init(&kho_out.dbg); 1394 + if (err) 1395 + goto err_free_fdt; 1396 + 1397 + err = kho_out_fdt_setup(); 1384 1398 if (err) 1385 1399 goto err_free_fdt; 1386 1400