From: sashiko-bot@kernel.org
To: "Liao Xuan" <liaoxuan@open-hieco.net>
Cc: linux-pci@vger.kernel.org
Subject: Re: [PATCH 2/3] nvme: Add hysteresis and idle detection to link rate switching
Date: Thu, 24 Sep 2026 06:27:29 +0000 [thread overview]
Message-ID: <20260924062729.860BF1F000FF@smtp.kernel.org> (raw)
In-Reply-To: <de23e8b9699b5a7a77e7ee215e8e4c9f530ce5da.1790222172.git.liaoxuan@hygon.cn>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] nvme: data race between timer and worker causes stuck link rate
--
commit 281ed4a8d51a45615fb54b154554270a5683089c
Author: Liao Xuan <liaoxuan@open-hieco.net>
nvme: Add hysteresis and idle detection to link rate switching
This patch adds counters to avoid excessive rate switching when the
workload fluctuates, requiring consecutive windows above or below a
threshold to trigger an upgrade or downgrade. It also stops monitoring
after 10 seconds of inactivity.
> diff --git a/drivers/nvme/host/speed_switch.c b/drivers/nvme/host/speed_switch.c
> index 88c046fcdde89..22f180c8119b2 100644
> --- a/drivers/nvme/host/speed_switch.c
> +++ b/drivers/nvme/host/speed_switch.c
[ ... ]
> @@ -247,31 +252,62 @@ static int nvme_check_io_and_decide_speed(struct nvme_speed_switch *sw)
> stat->write_bytes = 0;
> }
>
> + if (read_bytes || write_bytes) {
> + *io_activity = true;
> + sw->idle_cnt = 0;
> + } else {
> + sw->idle_cnt++;
> + }
> +
> + /* Stop monitoring after 10 seconds of inactivity (100 windows of 100ms). */
> + if (sw->idle_cnt >= 100)
> + *io_activity = false;
> +
> read_kb = read_bytes / 1024;
> write_kb = write_bytes / 1024;
> dev_dbg(ctrl->device,
> "I/O in window: read=%lu KB, write=%lu KB, threshold=%u KB\n",
> read_kb, write_kb, READ_ONCE(sw->threshold));
>
> - if (read_kb >= sw->threshold || write_kb >= sw->threshold)
> + if (read_kb >= sw->threshold || write_kb >= sw->threshold) {
> + sw->up_cnt++;
> + sw->down_cnt = 0;
> + } else {
> + sw->down_cnt++;
> + sw->up_cnt = 0;
> + }
> +
> + if (sw->up_cnt > READ_ONCE(sw->up_threshold)) {
> + sw->up_cnt = 0;
> return sw->max_speed;
> + }
> +
> + if (sw->down_cnt > READ_ONCE(sw->down_threshold) || !*io_activity) {
> + sw->down_cnt = 0;
> + return sw->min_speed;
> + }
>
> - return sw->min_speed;
> + return READ_ONCE(sw->cur_speed);
[Severity: High]
Does returning cur_speed here cause a data race between the timer and the
worker that leaves the hardware link rate permanently throttled?
If the timer previously returned min_speed and scheduled
nvme_speed_switch_work(), the worker will freeze the queues and begin a slow
hardware transition via pcie_set_target_speed().
While the worker is blocked on the hardware transition, I/O is 0 because the
queues are frozen. The concurrent timer will increment down_cnt, but since it
is below down_threshold, it will fall through and return
READ_ONCE(sw->cur_speed).
Because the worker hasn't updated sw->cur_speed yet, it's still max_speed.
The timer then updates sw->target_speed to max_speed:
drivers/nvme/host/speed_switch.c:nvme_speed_switch_timer_fn() {
...
sw->target_speed = nvme_check_io_and_decide_speed(sw, &io_activity);
...
}
When the worker finishes setting the hardware to min_speed, it double-reads
sw->target_speed:
drivers/nvme/host/speed_switch.c:nvme_speed_switch_work() {
...
ret = pcie_set_target_speed(bridge, nvme_speed_to_bus_speed(sw->target_speed),
true);
if (ret) {
...
} else {
WRITE_ONCE(sw->cur_speed, sw->target_speed);
}
...
}
This overwrites cur_speed with the timer-corrupted value (max_speed).
The hardware is now throttled at min_speed, but software thinks it is at
max_speed.
When high I/O resumes, the timer will decide the target is max_speed, but
since cur_speed is already max_speed, it won't schedule the worker to restore
the link rate, causing a severe performance regression.
--
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1790222172.git.liaoxuan@hygon.cn?part=2
next prev parent reply other threads:[~2026-09-24 6:27 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-24 6:15 [PATCH 0/3] Add adaptive NVMe link rate switching function Liao Xuan
2026-09-24 6:15 ` [PATCH 1/3] nvme: Add adaptive PCIe " Liao Xuan
2026-09-24 6:29 ` sashiko-bot
2026-09-24 6:15 ` [PATCH 2/3] nvme: Add hysteresis and idle detection to link rate switching Liao Xuan
2026-09-24 6:27 ` sashiko-bot [this message]
2026-09-24 6:15 ` [PATCH 3/3] nvme: Expose link rate switching tunables via sysfs Liao Xuan
2026-09-24 6:29 ` 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=20260924062729.860BF1F000FF@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=liaoxuan@open-hieco.net \
--cc=linux-pci@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.