From: sashiko-bot@kernel.org
To: "Ian Rogers" <irogers@google.com>
Cc: linux-perf-users@vger.kernel.org
Subject: Re: [PATCH v11 15/20] perf intel-tpebs: Fix race in tpebs_stop() and tpebs_cmd.out fd handling
Date: Mon, 09 Nov 2026 21:50:07 +0000 [thread overview]
Message-ID: <sashiko-outbox-205695@kernel.org> (raw)
In-Reply-To: <20261107044102.1506626-16-irogers@google.com>
Thank you for your contribution! Sashiko AI review found 2 potential
issues to consider:
- [Medium] perf intel-tpebs: control pipe command coalescing deadlock in
tpebs_stop()
- [Low] perf intel-tpebs: race in process_sample_event() during
tpebs_stop()
--
commit e2203763a4bf43ed152a64f29917746045712cad
Author: Ian Rogers <irogers@google.com>
perf intel-tpebs: Fix race in tpebs_stop() and tpebs_cmd.out fd handling
This commit serializes control command writes with teardown, transfers
ownership of tpebs_cmd.out to __sample_reader(), and guards
evsel__tpebs_open() against a concurrent tpebs_stop().
> diff --git a/tools/perf/util/intel-tpebs.c b/tools/perf/util/intel-tpebs.c
> index 7c0b8b15bd10e..4b7464cfa0eb3 100644
> --- a/tools/perf/util/intel-tpebs.c
> +++ b/tools/perf/util/intel-tpebs.c
[ ... ]
> @@ -262,20 +291,20 @@ static int tpebs_send_record_cmd(const char *msg) __must_hold(tpebs_mtx_get())
>
> /* Send perf record command.*/
> len = strlen(msg);
> - ret = write(control_fd[1], msg, len);
> + ret = write(ctrl_fd, msg, len);
> if (ret != len) {
> pr_err("perf record control write control message '%s' failed\n", msg);
> ret = -EPIPE;
> goto out;
> }
>
> - if (!strcmp(msg, EVLIST_CTL_CMD_STOP_TAG)) {
> + if (is_stop) {
> ret = 0;
> goto out;
> }
>
> /* Wait for an ack. */
> - pollfd.fd = ack_fd[0];
> + pollfd.fd = resp_fd;
>
> /*
> * We need this poll to ensure the ack_fd PIPE will not hang
> @@ -284,7 +313,17 @@ static int tpebs_send_record_cmd(const char *msg) __must_hold(tpebs_mtx_get())
> */
> again:
> if (!poll(&pollfd, 1, 500)) {
> - if (check_if_command_finished(&tpebs_cmd)) {
> + bool stopping, finished;
> +
> + mutex_lock(tpebs_mtx_get());
> + stopping = tpebs_stopping;
> + finished = !stopping && check_if_command_finished(&tpebs_cmd);
> + mutex_unlock(tpebs_mtx_get());
> + if (stopping) {
> + ret = -EBUSY;
> + goto out;
> + }
[Severity: Medium]
Can aborting the poll() wait on tpebs_stopping coalesce the in-flight
command with EVLIST_CTL_CMD_STOP_TAG in control_fd and hang tpebs_stop()
in pthread_join()?
tpebs_send_record_cmd() writes msg without a trailing newline or NUL
delimiter:
Thread 1 Thread 2
evsel__tpebs_open()
tpebs_send_record_cmd("enable")
write(ctrl_fd, "enable", 6)
poll(&pollfd, 1, 500)
evsel__tpebs_close()
tpebs_stop()
tpebs_stopping = true
tpebs_gen++
tpebs_send_record_cmd("stop")
cond_wait(&tpebs_cmd_cond, ...)
/* poll() times out */
stopping == true -> goto out
tpebs_cmd_in_flight = false
cond_broadcast(&tpebs_cmd_cond)
/* tpebs_gen != open_gen, skips SIGTERM */
write(ctrl_fd, "stop", 4)
pthread_join(reader_thread, NULL)
<-- hangs forever
When perf record reads from the control pipe, evlist__ctlfd_recv() reads
all available bytes until '\n', '\0', or EAGAIN into a single command
buffer:
tools/perf/util/evlist.c:evlist__ctlfd_recv() {
do {
err = read(evlist__ctl_fd_fd(evlist), &c, 1);
if (err > 0) {
if (c == '\n' || c == '\0')
break;
cmd_data[bytes_read++] = c;
...
}
If perf record has not consumed "enable" (or "ping") before "stop" is
written, it reads "enablestop" (or "pingstop") as one command and drops
the stop request. Because evsel__tpebs_open() skips kill(..., SIGTERM)
once tpebs_gen has changed and tpebs_stop() waits in pthread_join()
before closing the pipes or killing the child, perf record never exits
and pthread_join() blocks forever.
[ ... ]
> @@ -331,12 +382,21 @@ static int tpebs_stop(void) __must_hold(tpebs_mtx_get())
> /* Like tpebs_start, we should only run tpebs_end once. */
> if (tpebs_cmd.pid != 0) {
> pid_t actual_pid = tpebs_cmd.pid;
> + pthread_t reader_thread;
>
> tpebs_stopping = true;
> + tpebs_gen++;
> + cond_broadcast(&tpebs_cmd_cond);
> tpebs_send_record_cmd(EVLIST_CTL_CMD_STOP_TAG);
> + /*
> + * tpebs_results is empty when stopping; clear pid so
> + * process_sample_event() ignores any late samples while
> + * draining the pipe.
> + */
> tpebs_cmd.pid = 0;
[Severity: Low]
Can process_sample_event() still see a non-zero tpebs_cmd.pid and return
-EINVAL while tpebs_send_record_cmd(EVLIST_CTL_CMD_STOP_TAG) drops
tpebs_mtx?
evsel__tpebs_close() empties tpebs_results before calling tpebs_stop(),
and tpebs_send_record_cmd() releases tpebs_mtx in cond_wait() and around
write(). Because tpebs_cmd.pid is only cleared after
tpebs_send_record_cmd() returns and process_sample_event() does not check
tpebs_stopping:
tools/perf/util/intel-tpebs.c:process_sample_event() {
mutex_lock(tpebs_mtx_get());
if (tpebs_cmd.pid == 0) {
/* Record has terminated. */
mutex_unlock(tpebs_mtx_get());
return 0;
}
t = tpebs_retire_lat__find(sample->evsel);
if (!t) {
mutex_unlock(tpebs_mtx_get());
return -EINVAL;
}
...
}
Any sample processed by tpebs_reader_thread during that window fails the
lookup in the empty tpebs_results list and returns -EINVAL, causing
__perf_session__process_pipe_events() to log an error and abort draining
the pipe early. Checking tpebs_stopping in process_sample_event() would
avoid this race.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261107044102.1506626-1-irogers@google.com?part=15
next prev parent reply other threads:[~2026-11-09 21:50 UTC|newest]
Thread overview: 43+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-07 4:40 [PATCH v11 00/20] tools/perf: Adopt kernel compiler-context-analysis.h annotations Ian Rogers
2026-11-07 4:40 ` [PATCH v11 01/20] compiler-context-analysis: Avoid unused parameter warning in _context_unsafe_alias() Ian Rogers
2026-11-09 19:55 ` sashiko-bot
2026-11-07 4:40 ` [PATCH v11 02/20] tools headers compiler: Synchronize compiler_types.h with the kernel sources Ian Rogers
2026-11-09 20:01 ` sashiko-bot
2026-11-07 4:40 ` [PATCH v11 03/20] tools headers: Synchronize linux/compiler-context-analysis.h " Ian Rogers
2026-11-09 20:04 ` sashiko-bot
2026-11-07 4:40 ` [PATCH v11 04/20] perf mutex: Use kernel style compiler-context-analysis.h annotations Ian Rogers
2026-11-09 20:11 ` sashiko-bot
2026-11-07 4:40 ` [PATCH v11 05/20] perf build: Enable additional Clang thread-safety flags Ian Rogers
2026-11-09 20:23 ` sashiko-bot
2026-11-07 4:40 ` [PATCH v11 06/20] perf comm: Add __guarded_by annotations to struct comm_strs Ian Rogers
2026-11-09 20:37 ` sashiko-bot
2026-11-07 4:40 ` [PATCH v11 07/20] perf vdso: Fix unlocked __dsos__add() and race in __machine__addnew_vdso() Ian Rogers
2026-11-09 20:41 ` sashiko-bot
2026-11-07 4:40 ` [PATCH v11 08/20] perf dsos: Skip BPF and OOL DSOs in dsos__find_kernel_dso() Ian Rogers
2026-11-09 20:59 ` sashiko-bot
2026-11-07 4:40 ` [PATCH v11 09/20] perf dsos: Ensure DSOs in auxtrace, machine, and symbol are in dsos Ian Rogers
2026-11-09 21:08 ` sashiko-bot
2026-11-07 4:40 ` [PATCH v11 10/20] perf dso: Pass dso_data to close_data_fd() and dso__list_del() Ian Rogers
2026-11-09 21:13 ` sashiko-bot
2026-11-07 4:40 ` [PATCH v11 11/20] perf dso: Use DEFINE_MUTEX for dso__data_open_lock Ian Rogers
2026-11-09 21:14 ` sashiko-bot
2026-11-07 4:40 ` [PATCH v11 12/20] perf dsos: Use read lock fast path in dsos__findnew_id() Ian Rogers
2026-11-09 21:19 ` sashiko-bot
2026-11-07 4:40 ` [PATCH v11 13/20] perf dso: Expand context analysis annotations Ian Rogers
2026-11-09 21:21 ` sashiko-bot
2026-11-07 4:40 ` [PATCH v11 14/20] perf thread: Expand context analysis annotations to threads and namespaces_lock Ian Rogers
2026-11-09 21:25 ` sashiko-bot
2026-11-07 4:40 ` [PATCH v11 15/20] perf intel-tpebs: Fix race in tpebs_stop() and tpebs_cmd.out fd handling Ian Rogers
2026-11-09 21:50 ` sashiko-bot [this message]
2026-11-07 4:40 ` [PATCH v11 16/20] perf intel-tpebs: Use DEFINE_MUTEX for tpebs_mtx Ian Rogers
2026-11-09 21:58 ` sashiko-bot
2026-11-07 4:40 ` [PATCH v11 17/20] perf config, intel-tpebs, env: Add __guarded_by and __must_hold annotations Ian Rogers
2026-11-09 22:06 ` sashiko-bot
2026-11-07 4:40 ` [PATCH v11 18/20] perf maps: Fix lock inversion in maps__load_first() Ian Rogers
2026-11-09 22:10 ` sashiko-bot
2026-11-07 4:41 ` [PATCH v11 19/20] perf maps: Fix map index lookup fallback and removal Ian Rogers
2026-11-09 22:17 ` sashiko-bot
2026-11-07 4:41 ` [PATCH v11 20/20] perf maps: Add context analysis annotations Ian Rogers
2026-11-09 22:24 ` sashiko-bot
2026-11-10 22:58 ` [PATCH v11 00/20] tools/perf: Adopt kernel compiler-context-analysis.h annotations Namhyung Kim
2026-11-10 23:14 ` Ian Rogers
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=sashiko-outbox-205695@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=irogers@google.com \
--cc=linux-perf-users@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox