From 979057c339d2db56d445cce9c0490bca2436a453 Mon Sep 17 00:00:00 2001 From: Benjamin Donnachie Date: Sat, 15 Aug 2026 23:49:51 +0100 Subject: [PATCH] lookup: defer, don't fail closed, when a file's locals can't be matched against the reference symbol table gcc's inlining decisions for a handful of functions per translation unit are not always reproducible between a local kpatch-build rebuild and the officially published kernel build it's diffing against -- most plausibly because the published build applies profile-guided optimization data the local rebuild has no access to. A function can end up split into a .part.N cold-path clone, or fully inlined away, in one build but not the other, with no actual source change at all. find_local_syms() previously failed the whole build the moment this happened for *any* file, including files kpatch-build only recompiled as a side effect of Kbuild dependency tracking (an unrelated header changed) and that have no bearing on the actual patch. That makes an otherwise-successful build fail on files nowhere near the real diff. Since lookup_local_symbol() already handles a NULL lookup_table_file_sym cleanly (it just reports "not found" instead of crashing -- the in_file flag never sets because nothing will equal NULL in the symbol walk), leaving a file's locals uncorrelated here is safe: this only becomes a real, later failure at the point something in the actual patch tries and fails to resolve one of this file's local symbols, which is exactly where a genuine problem should be caught. Reproduced and fixed while building a real cumulative EL9 5.14 kernel livepatch: this took the failure count on that build from 40 files down to functions actually relevant to the patch. Co-authored-by: Claude --- kpatch-build/lookup.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/kpatch-build/lookup.c b/kpatch-build/lookup.c index 1530cfb3..33f9c756 100644 --- a/kpatch-build/lookup.c +++ b/kpatch-build/lookup.c @@ -215,9 +215,33 @@ static void find_local_syms(struct lookup_table *table, struct symbol *file_sym, } } - if (!lookup_table_file_sym) - ERROR("couldn't find matching %s local symbols in %s symbol table", - file_sym->name, table->objname); + if (!lookup_table_file_sym) { + /* + * gcc's inlining decisions for a handful of functions per + * file are not always reproducible between this local build + * and the officially published kernel build (most likely + * because the published build applies profile-guided + * optimization data this build doesn't have access to): a + * function may be split into a .part.N cold-path clone, or + * fully inlined away, in one build but not the other. That + * shows up here as an apparent local-symbol mismatch for + * files that have no actual source change at all. + * + * Failing closed here would kill every file kpatch-build + * decided to recompile as a side effect of an unrelated + * header changing, even when the file being processed has + * no bearing on the patch. Instead, leave this file's + * locals uncorrelated (lookup_table_file_sym stays NULL) + * and defer: lookup_local_symbol() already handles a NULL + * lookup_table_file_sym by cleanly reporting "not found" + * rather than crashing, so this only becomes a hard failure + * later, at the point something in the actual patch tries + * and fails to resolve one of this file's local symbols -- + * exactly where a real problem would need to be caught. + */ + log_error("couldn't find matching %s local symbols in %s symbol table, deferring\n", + file_sym->name, table->objname); + } list_for_each_entry_continue(file_sym, sym_list, list) { if (file_sym->type == STT_FILE)