kpatch-build: Allow function to have multiple child functions

A symbol associated to a function can be split into multiple
sub-functions. Currently, kpatch only supports one child per function.

Extend this to support an arbitrary number of sub-function per function.

Signed-off-by: Julien Thierry <jthierry@redhat.com>
This commit is contained in:
Julien Thierry 2019-09-16 11:57:05 +01:00
parent af1fe267c5
commit b502e5b1cc
3 changed files with 42 additions and 9 deletions

View File

@ -221,6 +221,7 @@ static void kpatch_detect_child_functions(struct kpatch_elf *kelf)
list_for_each_entry(sym, &kelf->symbols, list) {
char *coldstr;
struct symbol *parent;
coldstr = strstr(sym->name, ".cold.");
if (coldstr != NULL) {
@ -230,13 +231,14 @@ static void kpatch_detect_child_functions(struct kpatch_elf *kelf)
if (!pname)
ERROR("strndup");
sym->parent = find_symbol_by_name(&kelf->symbols, pname);
parent = find_symbol_by_name(&kelf->symbols, pname);
free(pname);
if (!sym->parent)
if (!parent)
ERROR("failed to find parent function for %s", sym->name);
sym->parent->child = sym;
list_add_tail(&sym->subfunction_node, &parent->children);
sym->parent = parent;
}
}
}
@ -659,6 +661,26 @@ static int kpatch_line_macro_change_only(struct section *sec)
}
#endif
/*
* Child functions with "*.cold" names don't have _fentry_ calls, but "*.part",
* often do. In the later case, it is not necessary to include the parent
* in the output object when the child function has changed.
*/
static bool kpatch_changed_child_needs_parent_profiling(struct symbol *sym)
{
struct symbol *child;
list_for_each_entry(child, &sym->children, subfunction_node) {
if (child->has_func_profiling)
continue;
if (child->sec->status == CHANGED ||
kpatch_changed_child_needs_parent_profiling(child))
return true;
}
return false;
}
static void kpatch_compare_sections(struct list_head *seclist)
{
struct section *sec;
@ -691,9 +713,8 @@ static void kpatch_compare_sections(struct list_head *seclist)
if (sym && sym->status != CHANGED)
sym->status = sec->status;
if (sym && sym->child && sym->status == SAME &&
sym->child->sec->status == CHANGED &&
!sym->child->has_func_profiling)
if (sym && sym->status == SAME &&
kpatch_changed_child_needs_parent_profiling(sym))
sym->status = CHANGED;
}
}
@ -2364,6 +2385,16 @@ static void kpatch_mark_ignored_sections_same(struct kpatch_elf *kelf)
sym->status = SAME;
}
static void kpatch_mark_ignored_children_same(struct symbol *sym)
{
struct symbol *child;
list_for_each_entry(child, &sym->children, subfunction_node) {
child->status = SAME;
kpatch_mark_ignored_children_same(child);
}
}
static void kpatch_mark_ignored_functions_same(struct kpatch_elf *kelf)
{
struct section *sec;
@ -2385,8 +2416,7 @@ static void kpatch_mark_ignored_functions_same(struct kpatch_elf *kelf)
rela->sym->status = SAME;
rela->sym->sec->status = SAME;
if (rela->sym->child)
rela->sym->child->status = SAME;
kpatch_mark_ignored_children_same(rela->sym);
if (rela->sym->sec->secsym)
rela->sym->sec->secsym->status = SAME;

View File

@ -277,6 +277,8 @@ void kpatch_create_symbol_list(struct kpatch_elf *kelf)
while (symbols_nr--) {
ALLOC_LINK(sym, &kelf->symbols);
INIT_LIST_HEAD(&sym->children);
sym->index = index;
if (!gelf_getsym(symtab->data, index, &sym->sym))
ERROR("gelf_getsym");

View File

@ -71,7 +71,8 @@ struct symbol {
struct list_head list;
struct symbol *twin;
struct symbol *parent;
struct symbol *child;
struct list_head children;
struct list_head subfunction_node;
struct section *sec;
GElf_Sym sym;
char *name;