Linux Perf Users
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Ian Rogers" <irogers@google.com>
Cc: linux-perf-users@vger.kernel.org, linux-nvme@lists.infradead.org
Subject: Re: [PATCH v3 2/3] perf pmu: Implement tool-provided NVMe PMU
Date: Fri, 13 Nov 2026 19:40:54 +0000	[thread overview]
Message-ID: <sashiko-outbox-213562@kernel.org> (raw)
In-Reply-To: <20261113191234.2509964-3-irogers@google.com>

Thank you for your contribution! Sashiko AI review found 2 potential
issues to consider:
- [Medium] perf pmu: missing errno and err_thread handling in
  evsel__nvme_pmu_open()
- [Medium] perf evsel: PERF_EVENT_IOC_ENABLE/DISABLE ioctls issued on
  NVMe device fds
--

commit 1cca3c688611b8ef7867f412d383cb3ae7a315e1
Author: Ian Rogers <irogers@google.com>

perf pmu: Implement tool-provided NVMe PMU

This commit adds a tool-provided PMU for NVMe controllers using libnvme,
exposing metrics from standard NVMe log pages under nvme_<ctrl> PMUs.

> diff --git a/tools/perf/util/nvme_pmu.c b/tools/perf/util/nvme_pmu.c
> new file mode 100644
> index 0000000000000..3ee967505dec6
> --- /dev/null
> +++ b/tools/perf/util/nvme_pmu.c

[ ... ]

> +static int nvme_pmu__read_val(int fd, uint64_t config, uint64_t *val)
> +{

[ ... ]

> +	if (ret < 0)
> +		return -errno ?: -EIO;
> +	if (ret > 0)
> +		return -EOPNOTSUPP;

[ ... ]

> +int evsel__nvme_pmu_open(struct evsel *evsel,
> +			 struct perf_thread_map *threads,
> +			 int start_cpu_map_idx, int end_cpu_map_idx)
> +{
> +	struct nvme_pmu *nvm = container_of(evsel->pmu, struct nvme_pmu, pmu);
> +	int idx = start_cpu_map_idx, thread = 0, nthreads, err = 0;
> +	int max_cpus, max_threads;
> +	char path[PATH_MAX];
> +
> +	if (evsel->core.attr.sample_period || !evsel->core.fd)
> +		return -EINVAL;
> +
> +	snprintf(path, sizeof(path), "/dev/%s", nvm->dev_name);

[ ... ]

> +	for (idx = start_cpu_map_idx; idx < end_cpu_map_idx; idx++) {
> +		for (thread = 0; thread < nthreads; thread++) {
> +			uint64_t *initial_val;
> +			int fd = open(path, O_RDONLY | O_CLOEXEC);
> +
> +			FD(evsel, idx, thread) = fd;

[Severity: Medium]
Does storing a /dev/nvmeX file descriptor in evsel->core.fd cause
evsel__enable_cpu(), evsel__enable(), evsel__disable_cpu() and
evsel__disable() to fail with -ENOTTY?

Those functions only special-case evsel__is_tool(evsel) and otherwise call
 into libperf:

tools/perf/util/evsel.c:evsel__enable_cpu() {
	if (evsel__is_tool(evsel))
		err = evsel__tool_pmu_enable_cpu(evsel, cpu_map_idx);
	else
		err = perf_evsel__enable_cpu(&evsel->core, cpu_map_idx);

	if (!err && evsel__is_group_leader(evsel)) {
    ...
}

perf_evsel__enable_cpu() and its enable/disable counterparts issue
PERF_EVENT_IOC_ENABLE and PERF_EVENT_IOC_DISABLE on every fd in
evsel->core.fd, which the NVMe character device rejects with -ENOTTY.
That leaves evsel->disabled stale and aborts the group loop before
userspace members such as duration_time, user_time or system_time are
enabled or disabled in mixed groups.

> +			if (fd < 0) {
> +				err = -errno;
> +				goto out_close;
> +			}
> +			initial_val = xyarray__entry(evsel->nvme.initial_values, idx, thread);
> +			err = nvme_pmu__read_val(fd, evsel->core.attr.config, initial_val);
> +			if (err) {
> +				close(fd);
> +				FD(evsel, idx, thread) = -1;
> +				goto out_close;
> +			}
> +		}
> +	}
> +	return 0;
> +out_close:
> +	if (err)
> +		threads->err_thread = thread;
> +
> +	do {
> +		while (--thread >= 0) {
> +			if (FD(evsel, idx, thread) >= 0)
> +				close(FD(evsel, idx, thread));
> +			FD(evsel, idx, thread) = -1;
> +		}
> +		thread = nthreads;
> +	} while (--idx >= start_cpu_map_idx);
> +	return err;
> +}

[Severity: Medium]
Does evsel__nvme_pmu_open() leave errno unset or clobbered on failure while
also setting threads->err_thread for a controller-wide device?

Callers of evsel__open() and evsel__open_per_cpu_and_thread() such as
__run_perf_stat(), record__open() and __cmd_top() read errno after a
negative return.  When a controller does not support an optional log page
(such as FDP, ZNS or Endurance Group), libnvme returns a positive NVMe
status code without setting errno, and nvme_pmu__read_val() returns
-EOPNOTSUPP with errno still 0 (or clobbered by close()).  The -EINVAL and
!HAVE_LIBNVME_SUPPORT error returns likewise do not set errno.

In addition, setting threads->err_thread = thread causes
stat_handle_error() in perf stat --per-thread mode to treat a controller
open or log error as a dead thread, removing every thread from the thread
map in a retry loop until nthreads reaches 0 and evsel__nvme_pmu_open()
returns 0 with no descriptors opened.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261113191234.2509964-1-irogers@google.com?part=2

  reply	other threads:[~2026-11-13 19:40 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-13 19:12 [PATCH v3 0/3] perf pmu: Add tool-provided NVMe PMU Ian Rogers
2026-11-13 19:12 ` [PATCH v3 1/3] perf build: Add libnvme feature detection Ian Rogers
2026-11-13 19:22   ` sashiko-bot
2026-11-13 19:12 ` [PATCH v3 2/3] perf pmu: Implement tool-provided NVMe PMU Ian Rogers
2026-11-13 19:40   ` sashiko-bot [this message]
2026-11-13 19:12 ` [PATCH v3 3/3] perf tests: Add NVMe PMU event parsing test Ian Rogers
2026-11-13 19:28   ` sashiko-bot

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-213562@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=irogers@google.com \
    --cc=linux-nvme@lists.infradead.org \
    --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