[PATCH v7 3/4] perf symbol: Add setters for bitfields sharing a byte to avoid concurrent update issues

Ian Rogers
2026-05-01T18:20:33Z

A problem with putting bitfields into struct symbol is that other bits in
the symbol could be updated concurrently and only one update to the
underlying storage unit happen, leading to lost updates.

To avoid this, introduce a global lock `symbol_bits_lock` in `symbol.c`
and helper functions to update the bits sharing a byte:
`symbol__set_ignore` and `symbol__set_annotate2`.

`inlined` is not given a setter as it is only initialized in
`new_inline_sym` when the symbol is under construction and not shared.

Assisted-by: Gemini:gemini-3.1-pro-preview
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/builtin-kwork.c | 2 +-
tools/perf/builtin-sched.c | 2 +-
tools/perf/util/annotate.c | 2 +-
tools/perf/util/symbol.c | 22 ++++++++++++++++++++++
tools/perf/util/symbol.h | 3 +++
5 files changed, 28 insertions(+), 3 deletions(-)

diff --git a/tools/perf/builtin-kwork.c b/tools/perf/builtin-kwork.c
index 9d3a4c779a41..7337ee956dc9 100644
--- a/tools/perf/builtin-kwork.c
+++ b/tools/perf/builtin-kwork.c
@@ -725,7 +725,7 @@ static void timehist_save_callchain(struct perf_kwork *kwork,
if (sym) {
if (!strcmp(sym->name, "__softirqentry_text_start") ||
!strcmp(sym->name, "__do_softirq"))
- sym->ignore = 1;
+ symbol__set_ignore(sym, true);
}

callchain_cursor_advance(cursor);
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 555247568e7a..655e95f660c2 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -2371,7 +2371,7 @@ static void save_task_callchain(struct perf_sched *sched,
if (!strcmp(sym->name, "schedule") ||
!strcmp(sym->name, "__schedule") ||
!strcmp(sym->name, "preempt_schedule"))
- sym->ignore = 1;
+ symbol__set_ignore(sym, true);
}

callchain_cursor_advance(cursor);
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index e745f3034a0e..d550a0061159 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -2224,7 +2224,7 @@ int symbol__annotate2(struct map_symbol *ms, struct evsel *evsel,

annotation__init_column_widths(notes, sym);
annotation__update_column_widths(notes);
- sym->annotate2 = 1;
+ symbol__set_annotate2(sym, true);

return 0;
}
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index fd332db56157..e6a1f23634ec 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -31,6 +31,7 @@
#include "map.h"
#include "symbol.h"
#include "map_symbol.h"
+#include "mutex.h"
#include "mem-events.h"
#include "mem-info.h"
#include "symsrc.h"
@@ -52,6 +53,8 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map);
static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map);
static bool symbol__is_idle(const char *name);

+static struct mutex symbol_bits_lock;
+
int vmlinux_path__nr_entries;
char **vmlinux_path;

@@ -345,6 +348,20 @@ void symbol__delete(struct symbol *sym)
free(((void *)sym) - symbol_conf.priv_size);
}

+void symbol__set_ignore(struct symbol *sym, bool ignore)
+{
+ mutex_lock(&symbol_bits_lock);
+ sym->ignore = ignore;
+ mutex_unlock(&symbol_bits_lock);
+}
+
+void symbol__set_annotate2(struct symbol *sym, bool annotate2)
+{
+ mutex_lock(&symbol_bits_lock);
+ sym->annotate2 = annotate2;
+ mutex_unlock(&symbol_bits_lock);
+}
+
void symbols__delete(struct rb_root_cached *symbols)
{
struct symbol *pos;
@@ -2398,6 +2415,8 @@ int symbol__init(struct perf_env *env)
if (symbol_conf.initialized)
return 0;

+ mutex_init(&symbol_bits_lock);
+
symbol_conf.priv_size = PERF_ALIGN(symbol_conf.priv_size, sizeof(u64));

symbol__elf_init();
@@ -2476,6 +2495,9 @@ void symbol__exit(void)
{
if (!symbol_conf.initialized)
return;
+
+ mutex_destroy(&symbol_bits_lock);
+
strlist__delete(symbol_conf.bt_stop_list);
strlist__delete(symbol_conf.sym_list);
strlist__delete(symbol_conf.dso_list);
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index bd6eb90c8668..5d98d7e84d57 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -77,6 +77,9 @@ struct symbol {
void symbol__delete(struct symbol *sym);
void symbols__delete(struct rb_root_cached *symbols);

+void symbol__set_ignore(struct symbol *sym, bool ignore);
+void symbol__set_annotate2(struct symbol *sym, bool annotate2);
+
/* symbols__for_each_entry - iterate over symbols (rb_root)
*
* @symbols: the rb_root of symbols
--
2.54.0.545.g6539524ca2-goog