* [PATCH AUTOSEL 6.18-6.6] thermal/drivers/qcom/tsens: Atomic temperature read with hardware-guided retries
[not found] <20260831133314.4125787-1-sashal@kernel.org>
@ 2026-08-31 13:20 ` Sasha Levin
2026-08-31 13:22 ` [PATCH AUTOSEL 6.18] cpufreq/amd-pstate: Loosen requirement on lowest nonlinear frequency != min freq Sasha Levin
` (3 subsequent siblings)
4 siblings, 0 replies; 5+ messages in thread
From: Sasha Levin @ 2026-08-31 13:20 UTC (permalink / raw)
To: patches, stable
Cc: Priyansh Jain, Daniel Lezcano, Konrad Dybcio, Sasha Levin, amitk,
thara.gopinath, rafael, linux-pm, linux-arm-msm, linux-kernel
From: Priyansh Jain <priyansh.jain@oss.qualcomm.com>
[ Upstream commit e28ef2f3ccea276436bd0f30c93f99e764ba492b ]
The existing TSENS temperature read logic polls the valid bit and then
reads the temperature register. When temperature reads are triggered
at very short intervals, this can race with hardware updates and allow
the temperature field to be read while it is still being updated.
In this case, the valid bit may already be asserted even though the
temperature value is transitioning, resulting in an incorrect reading.
Hardware programming guidelines require the temperature value and the
valid bit to be sampled atomically in the same read transaction. A
reading is considered valid only if the valid bit is observed set in
that same sample.
The guidelines further specify that software should attempt the
temperature read up to three times to account for transient update
windows. If none of the attempts yields a valid sample, a stable fallback
value must be returned: if the first and second samples match, the second
value is returned;otherwise, if the second and third samples match, the
third value is returned;if neither pair matches, -EAGAIN is returned.
Update the TSENS sensor read logic to implement atomic sampling along
with the recommended retry-and-compare fallback behavior. This removes
the race window and ensures deterministic temperature values in
accordance with hardware requirements.
Signed-off-by: Priyansh Jain <priyansh.jain@oss.qualcomm.com>
Signed-off-by: Daniel Lezcano <daniel.lezcano@kernel.org>
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Link: https://patch.msgid.link/20260514113643.1954111-1-priyansh.jain@oss.qualcomm.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: Qualcomm TSENS Atomic Temperature Read
**Local tree:** `v6.18.44` (Linux 6.18.44)
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: Subject Line
**Record:** `[thermal/drivers/qcom/tsens]` — action:
**update/implement** — **Atomic temperature read with hardware-guided
retries**
### Step 1.2: Commit Message Tags
**Record:**
- **Signed-off-by:** Priyansh Jain `<priyansh.jain@oss.qualcomm.com>`
(author)
- **Signed-off-by:** Daniel Lezcano `<daniel.lezcano@kernel.org>`
(thermal maintainer)
- **Reviewed-by:** Konrad Dybcio `<konrad.dybcio@oss.qualcomm.com>`
(Qualcomm reviewer)
- **Link:** `https://patch.msgid.link/20260514113643.1954111-1-
priyansh.jain@oss.qualcomm.com`
- **No** Fixes:, Reported-by:, Tested-by:, Acked-by:, Cc:
stable@vger.kernel.org
- **Notable:** Reviewed by Qualcomm engineer; signed by thermal
subsystem maintainer. No syzbot or user bug report.
### Step 1.3: Commit Body Analysis
**Record:**
- **Bug:** TSENS reads poll the VALID bit, then separately read the
temperature field. Under rapid read intervals, VALID may be set while
the temperature field is still transitioning, yielding a stale or
corrupt reading.
- **Symptom:** Incorrect temperature values returned to the thermal
subsystem.
- **Root cause:** VALID and temperature are in the same status register
but were sampled via separate `regmap_field_read()` transactions
instead of one atomic register read.
- **Fix:** Single `regmap_read()` of the status register; up to 3
retries per HW guidelines; fallback comparison logic; return `-EAGAIN`
if no stable sample.
- **Version info:** None specified in the message.
### Step 1.4: Hidden Bug Fix Detection
**Record:** Not disguised as cleanup — this is an explicit hardware-
correctness bug fix. The retry/fallback logic implements Qualcomm TSENS
programming guidelines, not a cosmetic refactor.
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: Change Inventory
**Record:**
- **Files:** `drivers/thermal/qcom/tsens.c` (~+100/−50 lines),
`drivers/thermal/qcom/tsens.h` (+1 line: `MAX_READ_RETRY 3`)
- **Functions modified/added:** `tsens_read_temp()` (new),
`tsens_hw_to_mC()` (refactored to convert only),
`tsens_read_irq_state()`, `get_temp_tsens_valid()`
- **Scope:** Single-driver, surgical fix with one internal helper added
### Step 2.2: Code Flow Changes
**Record:**
| Hunk | Before | After |
|------|--------|-------|
| `get_temp_tsens_valid()` | Poll VALID via
`regmap_field_read_poll_timeout()`, then call `tsens_hw_to_mC(s,
temp_idx)` which does a second `regmap_field_read()` | Call new
`tsens_read_temp()` for atomic register read + retries, then convert via
`tsens_hw_to_mC(s, *temp)` |
| `tsens_hw_to_mC()` | Reads hardware field and converts | Accepts pre-
read raw value, converts only |
| `tsens_read_irq_state()` | Threshold reads via `tsens_hw_to_mC(s,
field)` (implicit read) | Explicit `regmap_field_read()` then
`tsens_hw_to_mC(s, value)` |
**Affected paths:** Normal thermal zone temperature polling and IRQ
handler temperature reads during threshold violations.
### Step 2.3: Bug Mechanism
**Record:** **Logic / hardware correctness fix (race on non-atomic
register sampling).**
Verified in field definitions — both v1 and v2 place LAST_TEMP and VALID
in the same `TM_Sn_STATUS_OFF` register:
```135:136:drivers/thermal/qcom/tsens-v1.c
REG_FIELD_FOR_EACH_SENSOR11(LAST_TEMP, TM_Sn_STATUS_OFF, 0,
9),
REG_FIELD_FOR_EACH_SENSOR11(VALID, TM_Sn_STATUS_OFF, 14,
14),
```
```128:129:drivers/thermal/qcom/tsens-v2.c
REG_FIELD_FOR_EACH_SENSOR16(LAST_TEMP, TM_Sn_STATUS_OFF,
0, 11),
REG_FIELD_FOR_EACH_SENSOR16(VALID, TM_Sn_STATUS_OFF,
21, 21),
```
The old code performed two independent field reads; hardware can update
the register between them.
### Step 2.4: Fix Quality
**Record:**
- **Quality:** High — matches documented HW requirements; minimal API
surface change (all internal).
- **Regression risk:** Low. VER_0 path preserved (no VALID bit).
Threshold reads in `tsens_read_irq_state()` are separated correctly
since thresholds are not subject to the same race.
- **New behavior:** `-EAGAIN` when no stable sample after 3 attempts —
safer than returning a corrupt value.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: Blame
**Record:**
- `get_temp_tsens_valid()` introduced in `a7ff82976122e` (Amit Kucheria,
2020-04-29): *"Merge tsens-common.c into tsens.c"*
- VALID-bit polling added in `d012f9189fda0f` (Christian Marangi,
2021-10-07): *"Add timeout to get_temp_tsens_valid"* — fixed infinite
loop, not the atomic-read race
- Bug present since ~2020 in this tree; the separate-read pattern
predates 6.18 branching
### Step 3.2: Fixes: Tag
**Record:** N/A — no Fixes: tag in the commit message.
### Step 3.3: Related File History
**Record:** Recent tsens changes in this tree are device-support
additions (IPQ5018, MSM8937, v1 without RPM). No prior fix for atomic
sampling. Standalone patch, not part of a series.
### Step 3.4: Author Context
**Record:** Priyansh Jain (Qualcomm). Daniel Lezcano is the thermal
maintainer (Signed-off-by). No other commits from this author in the
local tsens history.
### Step 3.5: Dependencies
**Record:** No prerequisites. Uses existing `priv->tm_map`,
`priv->fields[]`, `priv->rf[]` — all present in 6.18.44. Applies
standalone.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: Original Discussion
**Record:** UNVERIFIED — `b4 dig` requires a commit hash (commit not in
this tree). Lore.kernel.org fetch blocked by bot protection. Link tag
points to `20260514113643.1954111-1-priyansh.jain@oss.qualcomm.com`.
### Step 4.2: Reviewers
**Record:** UNVERIFIED via b4 dig -w. Commit message lists Reviewed-by:
Konrad Dybcio and Signed-off-by: Daniel Lezcano.
### Step 4.3: Bug Report
**Record:** No Reported-by: or bugzilla/syzbot links. Bug identified
from HW programming guidelines, not a user crash report.
### Step 4.4: Related Patches
**Record:** Standalone single patch; not part of a multi-patch series.
### Step 4.5: Stable List History
**Record:** UNVERIFIED — could not search lore stable list due to access
restrictions.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: Key Functions
**Record:** `tsens_read_temp()` (new), `get_temp_tsens_valid()`,
`tsens_hw_to_mC()`, `tsens_get_temp()`, IRQ handler path at line 605
### Step 5.2: Callers
**Record:**
- `get_temp_tsens_valid` is `.get_temp` for 6 tsens v1/v2 platform
variants (`tsens-v1.c`, `tsens-v2.c`)
- Called from IRQ handler when threshold violated (`tsens.c:605`)
- `tsens_get_temp()` → `priv->ops->get_temp()` → thermal framework
polling, hwmon sysfs, cooling decisions
### Step 5.3: Callees
**Record:** `regmap_read()`, `regmap_field_read()`, `code_to_degc()`,
`sign_extend32()`
### Step 5.4: Reachability
**Record:** Userspace can trigger via thermal sysfs/hwmon reads. Kernel
thermal governor polls regularly. IRQ path fires during overheating —
exactly when rapid successive reads are most likely and accuracy is most
critical.
### Step 5.5: Similar Patterns
**Record:** `get_temp_common()` (VER_0/v0.1 paths) uses a different read
model and is unchanged. Only `get_temp_tsens_valid` platforms (v1, v2)
are affected.
---
## PHASE 6: CROSS-REFERENCE WITH LOCAL TREE (6.18.44)
### Step 6.1: Buggy Code Present?
**Record:** **YES.** Current `get_temp_tsens_valid()` at lines 751–779
still uses separate VALID poll + `tsens_hw_to_mC()` field read:
```751:779:drivers/thermal/qcom/tsens.c
int get_temp_tsens_valid(const struct tsens_sensor *s, int *temp)
{
// ...
ret = regmap_field_read_poll_timeout(priv->rf[valid_idx], valid,
valid, 1, 20 *
USEC_PER_MSEC);
// ...
*temp = tsens_hw_to_mC(s, temp_idx);
return 0;
}
```
The candidate commit is **not** in this tree.
### Step 6.2: Backport Complications
**Record:** **Clean apply expected.** File structure, enums (`VALID_0`,
`LAST_TEMP_0`), and `tm_map` match what the patch expects. No
conflicting refactors in recent 6.18 tsens history.
### Step 6.3: Related Fixes Already Present?
**Record:** **No.** `git log --grep` found only `d012f9189fda0f`
(timeout fix), which addressed a different bug (infinite poll loop on
disabled sensors).
---
## PHASE 7: SUBSYSTEM CONTEXT
### Step 7.1: Subsystem Criticality
**Record:** `drivers/thermal/qcom/tsens` — **IMPORTANT** (Qualcomm SoC
thermal management on phones, routers, embedded). Not core-kernel-wide,
but safety-relevant on affected hardware.
### Step 7.2: Activity Level
**Record:** Moderately active — recent commits add IPQ5018, MSM8937,
v1-without-RPM support. Driver is mature but still receiving platform
additions.
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
### Step 8.1: Who Is Affected
**Record:** Users of Qualcomm SoCs with TSENS v1 or v2 (SDM845,
MSM8996/8998, IPQ routers, many Android devices). Config:
`CONFIG_QCOM_TSENS` (or module equivalent). Not universal, but large
embedded/mobile population.
### Step 8.2: Trigger Conditions
**Record:** Temperature reads at short intervals — thermal framework
polling, hwmon reads, and especially IRQ-handler reads during threshold
violations. Plausible in production, not merely theoretical.
### Step 8.3: Failure Mode Severity
**Record:** **Incorrect temperature readings** → wrong thermal
throttling decisions. Could under-throttle during overheating (hardware
stress) or over-throttle (performance loss). Not a kernel oops/UAF, but
affects thermal protection. **Severity: MEDIUM-HIGH** for affected
platforms.
### Step 8.4: Risk-Benefit
**Record:**
- **Benefit:** Correct thermal readings per HW spec; safer `-EAGAIN`
instead of corrupt values; fixes race on safety-critical overheating
path
- **Risk:** Low — contained driver change, reviewed, follows HW
guidelines
- **Ratio:** Favorable for Qualcomm TSENS users
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: Evidence Summary
**FOR backport:**
- Real, verifiable bug: non-atomic VALID/temp sampling from same
register
- Bug present in 6.18.44 since ~2020
- Affects thermal protection on widely deployed Qualcomm hardware
- IRQ path during threshold violations is a concrete high-risk trigger
- Fix is reviewed, maintainer-signed, follows HW programming guidelines
- Small, self-contained, no new public APIs
- Returns `-EAGAIN` instead of corrupt data when sampling fails
**AGAINST backport:**
- No user crash reports, syzbot, or CVE
- Not oops/UAF/corruption — incorrect sensor data
- Stable rules discourage unproven "theoretical" races (though this has
a concrete HW mechanism)
- Patch may approach the ~100-line stable size guideline
- Mailing list discussion unverified
### Step 9.2: Stable Rules Checklist
1. Obviously correct and tested? **PASS** — HW spec compliance;
Reviewed-by + maintainer SOB (runtime testing not independently
verified)
2. Fixes a real bug? **PASS** — verified separate-read race on shared
status register
3. Important issue? **PASS (borderline)** — incorrect thermal readings
on overheating path; hardware quirk / HW-requirement compliance
category
4. Small and contained? **PASS** — single driver, ~50 net lines; diff
may be near 100-line guideline
5. No new features/APIs? **PASS** — internal refactor only
6. Can apply to local tree? **PASS** — buggy code present, no
dependencies
### Step 9.3: Exception Categories
**Record:** **Hardware quirk/workaround** — implements mandatory HW
atomic-sampling and retry protocol for TSENS status registers.
### Step 9.4: Decision Rationale
For Linux **6.18.44**, this commit fixes a longstanding hardware-read
race in the Qualcomm TSENS driver that can return incorrect temperatures
during rapid reads — including in the IRQ handler when sensors report
threshold violations. While it does not cause kernel crashes, thermal
sensor correctness on the overheating path is safety-relevant for a
large class of production devices. The fix is small, reviewed, follows
documented HW requirements, and applies cleanly to this tree.
---
## Verification
- **[Phase 1]** Parsed subject, tags (SOB, Reviewed-by, Link); no
Fixes/Reported-by/syzbot
- **[Phase 2]** Diff analysis: new `tsens_read_temp()`, refactored
`tsens_hw_to_mC()`, updated `get_temp_tsens_valid()` and
`tsens_read_irq_state()`
- **[Phase 2]** Verified LAST_TEMP and VALID share `TM_Sn_STATUS_OFF` in
`tsens-v1.c:135-136` and `tsens-v2.c:128-129`
- **[Phase 3]** `git blame -L 751,779`: core logic from `a7ff82976122e`
(2020), polling from `d012f9189fda0f` (2021)
- **[Phase 3]** `git show d012f9189fda0f`: prior fix addressed infinite
poll, not atomic read
- **[Phase 3]** `git log --oneline -20 -- drivers/thermal/qcom/tsens.c`:
no duplicate fix present
- **[Phase 3]** `git log --grep="Atomic temperature"`: no match in tree
(commit not present)
- **[Phase 4]** UNVERIFIED: `b4 dig -c` failed (no commit hash in tree);
lore fetch blocked
- **[Phase 4]** UNVERIFIED: stable list discussion, reviewer stable
nominations
- **[Phase 5]** `grep get_temp_tsens_valid`: 6 `.get_temp` assignments
in v1/v2 + IRQ call at `tsens.c:605`
- **[Phase 5]** `grep tsens_get_temp`: thermal zone ops at
`tsens.c:1170`
- **[Phase 6]** `git describe HEAD`: v6.18.44
- **[Phase 6]** Read `get_temp_tsens_valid()` at `tsens.c:751-779`:
buggy separate-read pattern confirmed
- **[Phase 6]** `grep tsens_read_temp|MAX_READ_RETRY`: not in tree — fix
not yet applied
- **[Phase 7]** `git log --oneline -20 -- drivers/thermal/qcom/`:
subsystem active with platform additions
- **[Phase 8]** Failure mode: incorrect temperature → thermal mis-
management; severity MEDIUM-HIGH on affected platforms
**YES**The background searches finished and match the earlier analysis:
- **Subject search:** No commit matching “Atomic temperature read with
hardware-guided retries” (or `tsens_read_temp`) is in this **6.18.44**
tree — the fix is still a backport candidate, not something already
applied.
- **Related history:** The only closely related prior change is
`d012f9189fda0f` (“Add timeout to get_temp_tsens_valid”), which fixed
an infinite-poll loop on disabled sensors, not the atomic VALID/temp
sampling race this patch addresses.
**Verdict for 6.18.44:** **YES** — real HW-read race on Qualcomm TSENS
v1/v2, affects thermal readings (including the IRQ/overheat path), and
the fix is small, reviewed, and should apply cleanly.
drivers/thermal/qcom/tsens.c | 111 ++++++++++++++++++++++++-----------
drivers/thermal/qcom/tsens.h | 1 +
2 files changed, 78 insertions(+), 34 deletions(-)
diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index a2422ebee8169..40f27c1a1cd59 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -316,9 +316,66 @@ static inline int code_to_degc(u32 adc_code, const struct tsens_sensor *s)
}
/**
- * tsens_hw_to_mC - Return sign-extended temperature in mCelsius.
+ * tsens_read_temp - Retrieve temperature readings from the hardware.
* @s: Pointer to sensor struct
* @field: Index into regmap_field array pointing to temperature data
+ * @temp: temperature in deciCelsius to be read from hardware
+ *
+ * This function handles temperature returned in ADC code or deciCelsius
+ * depending on IP version.
+ *
+ * Return: 0 on success, a negative errno will be returned in error cases
+ */
+static int tsens_read_temp(const struct tsens_sensor *s, int field, int *temp)
+{
+ struct tsens_priv *priv = s->priv;
+ int temp_val[MAX_READ_RETRY] = {0};
+ u32 status;
+ int ret;
+ u32 last_temp_mask = GENMASK(priv->fields[LAST_TEMP_0].msb,
+ priv->fields[LAST_TEMP_0].lsb);
+ u32 valid_bit = priv->rf[VALID_0] ? BIT(priv->fields[VALID_0].lsb) : 0;
+
+ for (int i = 0; i < MAX_READ_RETRY; i++) {
+ ret = regmap_read(priv->tm_map, priv->fields[field].reg, &status);
+ if (ret)
+ return ret;
+
+ /* VER_0 doesn't have a VALID bit */
+ if (!valid_bit) {
+ *temp = status & last_temp_mask;
+ return 0;
+ }
+
+ temp_val[i] = status & last_temp_mask;
+
+ if (status & valid_bit) {
+ *temp = temp_val[i];
+ return 0;
+ }
+ }
+
+ /*
+ * As per the HW guidelines, if none of the attempts observe a
+ * valid sample, a stable fallback value must be returned. If the
+ * first and second samples match, the second value is returned;
+ * otherwise, if the second and third samples match, the third
+ * value is returned.
+ */
+ if (temp_val[0] == temp_val[1])
+ *temp = temp_val[1];
+ else if (temp_val[1] == temp_val[2])
+ *temp = temp_val[2];
+ else
+ return -EAGAIN;
+
+ return 0;
+}
+
+/**
+ * tsens_hw_to_mC - Return sign-extended temperature in mCelsius.
+ * @s: Pointer to sensor struct
+ * @temp: temperature in milliCelsius to be read from hardware
*
* This function handles temperature returned in ADC code or deciCelsius
* depending on IP version.
@@ -326,20 +383,14 @@ static inline int code_to_degc(u32 adc_code, const struct tsens_sensor *s)
* Return: Temperature in milliCelsius on success, a negative errno will
* be returned in error cases
*/
-static int tsens_hw_to_mC(const struct tsens_sensor *s, int field)
+static int tsens_hw_to_mC(const struct tsens_sensor *s, int temp)
{
struct tsens_priv *priv = s->priv;
u32 resolution;
- u32 temp = 0;
- int ret;
resolution = priv->fields[LAST_TEMP_0].msb -
priv->fields[LAST_TEMP_0].lsb;
- ret = regmap_field_read(priv->rf[field], &temp);
- if (ret)
- return ret;
-
/* Convert temperature from ADC code to milliCelsius */
if (priv->feat->adc)
return code_to_degc(temp, s) * 1000;
@@ -514,8 +565,10 @@ static int tsens_read_irq_state(struct tsens_priv *priv, u32 hw_id,
&d->crit_irq_mask);
if (ret)
return ret;
-
- d->crit_thresh = tsens_hw_to_mC(s, CRIT_THRESH_0 + hw_id);
+ ret = regmap_field_read(priv->rf[CRIT_THRESH_0 + hw_id], &d->crit_thresh);
+ if (ret)
+ return ret;
+ d->crit_thresh = tsens_hw_to_mC(s, d->crit_thresh);
} else {
/* No mask register on older TSENS */
d->up_irq_mask = 0;
@@ -525,8 +578,16 @@ static int tsens_read_irq_state(struct tsens_priv *priv, u32 hw_id,
d->crit_thresh = 0;
}
- d->up_thresh = tsens_hw_to_mC(s, UP_THRESH_0 + hw_id);
- d->low_thresh = tsens_hw_to_mC(s, LOW_THRESH_0 + hw_id);
+ ret = regmap_field_read(priv->rf[UP_THRESH_0 + hw_id], &d->up_thresh);
+ if (ret)
+ return ret;
+
+ d->up_thresh = tsens_hw_to_mC(s, d->up_thresh);
+ ret = regmap_field_read(priv->rf[LOW_THRESH_0 + hw_id], &d->low_thresh);
+ if (ret)
+ return ret;
+
+ d->low_thresh = tsens_hw_to_mC(s, d->low_thresh);
dev_dbg(priv->dev, "[%u] %s%s: status(%u|%u|%u) | clr(%u|%u|%u) | mask(%u|%u|%u)\n",
hw_id, __func__,
@@ -750,33 +811,15 @@ static void tsens_disable_irq(struct tsens_priv *priv)
int get_temp_tsens_valid(const struct tsens_sensor *s, int *temp)
{
- struct tsens_priv *priv = s->priv;
int hw_id = s->hw_id;
u32 temp_idx = LAST_TEMP_0 + hw_id;
- u32 valid_idx = VALID_0 + hw_id;
- u32 valid;
int ret;
- /* VER_0 doesn't have VALID bit */
- if (tsens_version(priv) == VER_0)
- goto get_temp;
-
- /* Valid bit is 0 for 6 AHB clock cycles.
- * At 19.2MHz, 1 AHB clock is ~60ns.
- * We should enter this loop very, very rarely.
- * Wait 1 us since it's the min of poll_timeout macro.
- * Old value was 400 ns.
- */
- ret = regmap_field_read_poll_timeout(priv->rf[valid_idx], valid,
- valid, 1, 20 * USEC_PER_MSEC);
- if (ret)
- return ret;
-
-get_temp:
- /* Valid bit is set, OK to read the temperature */
- *temp = tsens_hw_to_mC(s, temp_idx);
+ ret = tsens_read_temp(s, temp_idx, temp);
+ if (!ret)
+ *temp = tsens_hw_to_mC(s, *temp);
- return 0;
+ return ret;
}
int get_temp_common(const struct tsens_sensor *s, int *temp)
diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
index 2a7afa4c899b9..ab57ad88c3f7c 100644
--- a/drivers/thermal/qcom/tsens.h
+++ b/drivers/thermal/qcom/tsens.h
@@ -21,6 +21,7 @@
#define THRESHOLD_MIN_ADC_CODE 0x0
#define MAX_SENSORS 16
+#define MAX_READ_RETRY 3
#include <linux/interrupt.h>
#include <linux/thermal.h>
--
2.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH AUTOSEL 6.18] cpufreq/amd-pstate: Loosen requirement on lowest nonlinear frequency != min freq
[not found] <20260831133314.4125787-1-sashal@kernel.org>
2026-08-31 13:20 ` [PATCH AUTOSEL 6.18-6.6] thermal/drivers/qcom/tsens: Atomic temperature read with hardware-guided retries Sasha Levin
@ 2026-08-31 13:22 ` Sasha Levin
2026-08-31 13:22 ` [PATCH AUTOSEL 6.18-5.10] thermal/drivers/tegra/soctherma: Switch to devm cooling device registration Sasha Levin
` (2 subsequent siblings)
4 siblings, 0 replies; 5+ messages in thread
From: Sasha Levin @ 2026-08-31 13:22 UTC (permalink / raw)
To: patches, stable
Cc: Mario Limonciello, K Prateek Nayak, Mario Limonciello,
Sasha Levin, ray.huang, rafael, viresh.kumar, linux-pm,
linux-kernel
From: Mario Limonciello <mario.limonciello@amd.com>
[ Upstream commit 6842427bf2990271c771081f11fd8fab17f86c82 ]
This requirement was introduced by commit 8f8b42c1fcc93 ("cpufreq:
amd-pstate: optimize the initial frequency values verification")
specifically to aid in debugging BIOS issues with invalid _CPC tables
on some older systems.
This requirement is too tight for new systems though as some systems
actually have lowest nonlinear frequency identical to minimum
frequency. Allow that combo to work.
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
Reviewed-by: K Prateek Nayak <kprateek.nayak@amd.com>
Tested-by: K Prateek Nayak <kprateek.nayak@amd.com>
Link: https://lore.kernel.org/r/20260715174318.18235-1-mario.limonciello@amd.com
Signed-off-by: Mario Limonciello <superm1@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
**Verdict for Linux 6.18.y: YES**
The amd-pstate patch is a one-line fix (`<=` → `<`) in
`amd_pstate_init_freq()`. The strict check from `8f8b42c1fcc93` (June
2024, present since v6.11) rejects valid ACPI `_CPC` tables where
`lowest_nonlinear_freq == min_freq`, so the driver fails to probe on
some newer AMD systems. The fix matches the existing comment that
documents the inclusive range `[min_freq, nominal_freq]`, is
reviewed/tested by AMD, and should apply cleanly to 6.18.44.
drivers/cpufreq/amd-pstate.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
index ce6d6b3ff58a3..46086a9053044 100644
--- a/drivers/cpufreq/amd-pstate.c
+++ b/drivers/cpufreq/amd-pstate.c
@@ -951,7 +951,7 @@ static int amd_pstate_init_freq(struct amd_cpudata *cpudata)
return -EINVAL;
}
- if (lowest_nonlinear_freq <= min_freq || lowest_nonlinear_freq > nominal_freq) {
+ if (lowest_nonlinear_freq < min_freq || lowest_nonlinear_freq > nominal_freq) {
pr_err("lowest_nonlinear_freq(%d) value is out of range [min_freq(%d), nominal_freq(%d)]\n",
lowest_nonlinear_freq, min_freq, nominal_freq);
return -EINVAL;
--
2.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH AUTOSEL 6.18-5.10] thermal/drivers/tegra/soctherma: Switch to devm cooling device registration
[not found] <20260831133314.4125787-1-sashal@kernel.org>
2026-08-31 13:20 ` [PATCH AUTOSEL 6.18-6.6] thermal/drivers/qcom/tsens: Atomic temperature read with hardware-guided retries Sasha Levin
2026-08-31 13:22 ` [PATCH AUTOSEL 6.18] cpufreq/amd-pstate: Loosen requirement on lowest nonlinear frequency != min freq Sasha Levin
@ 2026-08-31 13:22 ` Sasha Levin
2026-08-31 13:22 ` [PATCH AUTOSEL 6.18] PM: hibernate: call preallocate_image() after freeze prepare Sasha Levin
2026-08-31 13:24 ` [PATCH AUTOSEL 6.18-6.12] powercap: intel_rapl: Fix memory leak in rapl_add_package_cpuslocked() Sasha Levin
4 siblings, 0 replies; 5+ messages in thread
From: Sasha Levin @ 2026-08-31 13:22 UTC (permalink / raw)
To: patches, stable
Cc: Daniel Lezcano, Daniel Lezcano, Lukasz Luba, Sasha Levin, rafael,
thierry.reding, jonathanh, linux-pm, linux-tegra, linux-kernel
From: Daniel Lezcano <daniel.lezcano@oss.qualcomm.com>
[ Upstream commit ee126267bc04bfb03816ae9d71ca24c5bf99e739 ]
Use devm_thermal_of_cooling_device_register() to simplify resource
management and avoid manual cleanup in error paths.
As a side effect this change has the benefit of solving an existing
issue. Before, the function tegra_soctherm_remove() only called
debugfs_remove_recursive() and never called thermal_cooling_device_unregister()
for any of the cooling devices registered here.
After the driver removal, the thermal framework's cdev list would
still hold references to thermal_cooling_device objects whose devdata
pointer (ts) pointed to memory already freed by the platform device's
devm cleanup.
With this change, the cooling device is unregistered when the driver
is removed, thus fixing the issue above.
Signed-off-by: Daniel Lezcano <daniel.lezcano@oss.qualcomm.com>
Signed-off-by: Daniel Lezcano <daniel.lezcano@kernel.org>
Reviewed-by: Lukasz Luba <lukasz.luba@arm.com>
Link: https://patch.msgid.link/20260424160019.41710-2-daniel.lezcano@oss.qualcomm.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: tegra/soctherm devm cooling device
registration
**Local tree:** `v6.18.44` (Linux 6.18.44)
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: Subject line
**Record:** `[thermal/drivers/tegra/soctherma]` `[Switch]` — move
throttle cooling-device registration to the devm thermal API.
### Step 1.2: Tags
**Record:**
- **Signed-off-by:** Daniel Lezcano `<daniel.lezcano@oss.qualcomm.com>`,
Daniel Lezcano `<daniel.lezcano@kernel.org>`
- **Reviewed-by:** Lukasz Luba `<lukasz.luba@arm.com>`
- **Link:** https://patch.msgid.link/20260424160019.41710-2-
daniel.lezcano@oss.qualcomm.com
- **Absent (expected):** Fixes:, Reported-by:, Tested-by:, Cc:
stable@vger.kernel.org
- **Notable:** Part of a 2-patch series; no syzbot/fuzzer report.
### Step 1.3: Body analysis
**Record:**
- **Bug:** `tegra_soctherm_remove()` never calls
`thermal_cooling_device_unregister()` for throttle cooling devices
registered in `soctherm_init_hw_throt_cdev()`.
- **Symptom:** After driver removal, the thermal core still holds
`thermal_cooling_device` entries whose `devdata` points at `struct
tegra_soctherm *ts`, but `ts` is freed by devm when the platform
device is torn down → use-after-free.
- **Root cause:** Non-devm `thermal_of_cooling_device_register()` with
no matching unregister in `.remove`.
- **Fix approach:** `devm_thermal_of_cooling_device_register(dev, ...)`
so unregister happens automatically on device release.
### Step 1.4: Hidden bug fix?
**Record:** Yes. The commit is framed as resource-management cleanup,
but it explicitly fixes a real UAF on driver removal.
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: Inventory
**Record:**
- **Files:** `drivers/thermal/tegra/soctherm.c` only (+3 / −3 lines)
- **Function modified:** `soctherm_init_hw_throt_cdev()`
- **Scope:** Single-file, surgical change
### Step 2.2: Code flow change
**Record:**
- **Before:** `thermal_of_cooling_device_register(np_stcc, name, ts,
&throt_cooling_ops)` — lifetime not tied to `pdev->dev`; survives past
`.remove`.
- **After:** `devm_thermal_of_cooling_device_register(dev, np_stcc,
name, ts, &throt_cooling_ops)` — cooling device unregistered when
`dev` is released.
- **Path affected:** Probe-time throttle cooling-device registration;
cleanup on driver remove/unbind.
### Step 2.3: Bug mechanism
**Record:** **Category:** Use-after-free / missing resource cleanup on
driver removal.
Mechanism verified in tree:
1. `tegra` is allocated with `devm_kzalloc(&pdev->dev, ...)` (line
2101).
2. Cooling devices store `ts` as `devdata` (line 1704).
3. `throt_get_cdev_cur_state()` dereferences `cdev->devdata` as `ts` and
reads `ts->regs` (lines 1512–1515).
4. `tegra_soctherm_remove()` only removes debugfs and disables clocks —
no cooling-device unregister (lines 2228–2235).
5. After remove, thermal framework callbacks can touch freed `ts`
memory.
### Step 2.4: Fix quality
**Record:** Obviously correct; matches the pattern already used in the
same probe path for thermal zones (`devm_thermal_of_zone_register` at
line 2197). Minimal regression risk; no new APIs.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: Blame
**Record:** `git blame` on the registration lines attributes them to
`7e22de67e545d` (“drm/amdgpu/gfx10: replace BUG_ON() with WARN_ON()”),
which is clearly unrelated — this tree’s git history for `soctherm.c`
appears squashed/corrupted. **Cannot reliably determine the introducing
commit or kernel version from history in this checkout.**
### Step 3.2: Fixes: tag
**Record:** N/A — no Fixes: tag in the commit message.
### Step 3.3: Related file history
**Record:** `git log --oneline -- drivers/thermal/tegra/soctherm.c`
returns only the unrelated amdgpu commit. History is not usable here.
The buggy pattern is present in the current file content.
### Step 3.4: Author context
**Record:** Daniel Lezcano is a thermal maintainer. No other tegra
thermal commits visible in this tree’s truncated history.
### Step 3.5: Dependencies
**Record:** Patch is **2/2** in a series with patch 1/2 (clock disable
via `devm_add_action_or_reset`). **Patch 2/2 is standalone** — it only
changes the cooling-device registration call and does not depend on
patch 1. `devm_thermal_of_cooling_device_register()` already exists in
this tree’s `thermal_core.c` (lines 1217–1240).
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: Original discussion
**Record:**
- **URL:** https://patch.msgid.link/20260424160019.41710-2-
daniel.lezcano@oss.qualcomm.com
- **Series:** 2 patches (clock devm cleanup + this cooling-device devm
fix)
- **b4:** Reports patch applies clean to current tree
- **Review:** `Reviewed-by: Lukasz Luba` on patch 1/2; no separate
replies found for patch 2/2 in thread grep
- **Stable nomination:** None found in thread or stable@ search
### Step 4.2: Reviewers
**Record:** CC’d: Rafael Wysocki, Daniel Lezcano, Thierry Reding,
Jonathan Hunter; lists: linux-pm, linux-tegra.
### Step 4.3: Bug report
**Record:** No external bug report, syzbot, or crash log — bug
identified by code inspection during cleanup.
### Step 4.4: Series context
**Record:** Patch 1/2 is independent (clock error-path cleanup). Not
required for this fix to work.
### Step 4.5: Stable list
**Record:** No prior stable@ discussion found for this issue.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: Key functions
**Record:** `soctherm_init_hw_throt_cdev()`,
`throt_get_cdev_cur_state()`, `tegra_soctherm_remove()`,
`tegra_soctherm_probe()`.
### Step 5.2: Callers
**Record:**
- `soctherm_init_hw_throt_cdev()` called from `tegra_soctherm_probe()`
(line 2180)
- Driver registered via `module_platform_driver(tegra_soctherm_driver)`
(line 2288) — `.remove` runs on unbind/module unload
- Thermal zone trip handling also references `ts->throt_cfgs[i].cdev`
(lines 617–628)
### Step 5.3: Callees
**Record:** Registration goes through
`devm_thermal_of_cooling_device_register()` →
`__thermal_cooling_device_register()` with devm release via
`thermal_cooling_device_release()`.
### Step 5.4: Reachability
**Record:**
- Requires `CONFIG_TEGRA_SOCTHERM` (tristate, `ARCH_TEGRA ||
COMPILE_TEST`)
- Requires DT `throttle-cfgs` child nodes with non-OC throttle entries
(`stc->id < THROTTLE_OC1`)
- Trigger: platform driver remove/unbind after successful probe with
throttle cooling devices registered
- Post-remove thermal activity (zone polling, trip handling, sysfs) can
invoke cooling-device ops → UAF
### Step 5.5: Similar patterns
**Record:** Same file already uses devm for zones
(`devm_thermal_of_zone_register`), `tegra` struct, clocks, and other
probe allocations. Cooling-device registration was the outlier.
---
## PHASE 6: CROSS-REFERENCE AGAINST LOCAL TREE (v6.18.44)
### Step 6.1: Buggy code present?
**Record:** **Yes.** Lines 1703–1705 still use
`thermal_of_cooling_device_register()`; `tegra_soctherm_remove()` has no
unregister. The fix is not yet in this tree.
### Step 6.2: Backport complications
**Record:** **Clean apply.** Verified with `git apply --check` — 3
insertions, 3 deletions, no conflicts.
`devm_thermal_of_cooling_device_register()` is declared in
`include/linux/thermal.h` and implemented in
`drivers/thermal/thermal_core.c`.
### Step 6.3: Related fixes already present?
**Record:** No. `grep thermal_cooling_device_unregister
drivers/thermal/tegra/` returns nothing. Bug remains unfixed.
---
## PHASE 7: SUBSYSTEM CONTEXT
### Step 7.1: Subsystem and criticality
**Record:** `drivers/thermal/tegra/` — Tegra platform thermal driver.
**PERIPHERAL** (Tegra/embedded only), but thermally safety-relevant on
affected hardware.
### Step 7.2: Activity
**Record:** File history unavailable in this checkout; driver is mature
and actively maintained upstream (April 2026 patch series).
---
## PHASE 8: IMPACT AND RISK
### Step 8.1: Who is affected
**Record:** Systems with `CONFIG_TEGRA_SOCTHERM` built-in or as a
module, DT `throttle-cfgs` present, and throttle cooling devices
registered (LIGHT/HEAVY, not OC-only configs).
### Step 8.2: Trigger conditions
**Record:** Driver removal/unbind/module unload — not every boot, but a
real kernel code path. Any subsequent thermal-framework access to the
stale cooling device can trigger the bug.
### Step 8.3: Failure mode severity
**Record:** **Use-after-free** via `ts->regs` in
`throt_get_cdev_cur_state()` → kernel oops/panic, unpredictable
behavior. **Severity: HIGH.**
### Step 8.4: Risk-benefit
**Record:**
- **Benefit:** HIGH for affected Tegra systems — prevents UAF on
teardown
- **Risk:** VERY LOW — 3-line change, established devm API, no
structural changes
- **Ratio:** Strongly favors backport
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: Evidence summary
**FOR backport:**
- Real UAF on driver removal, clearly described and verified in code
- Dangling `devdata` (`ts`) dereferenced in `throt_get_cdev_cur_state()`
- Small, surgical, obviously correct devm fix
- `devm_thermal_of_cooling_device_register()` exists in v6.18.44
- Patch applies cleanly
- Reviewed in series by Arm thermal reviewer; thermal maintainer
authored
**AGAINST backport:**
- Tegra-specific, not universal
- Driver removal is less common than steady-state operation (often
built-in)
- No fuzzer report or user crash log
- Git history in this checkout cannot confirm how long the bug has
existed
**Unresolved:** Exact commit that introduced the bug (history unusable
in this tree).
### Step 9.2: Stable rules checklist
1. Obviously correct and tested? **PASS** — standard devm pattern;
series reviewed
2. Fixes a real user-affecting bug? **PASS** — UAF on driver teardown
3. Important issue? **PASS** — UAF / potential crash
4. Small and contained? **PASS** — 3 lines, one function
5. No new features/APIs? **PASS** — uses existing devm API
6. Can apply to local tree? **PASS** — verified clean apply; API present
### Step 9.3: Exception categories
**Record:** None (not a quirk/DT-ID/docs fix) — standard bug fix.
### Step 9.4: Decision rationale
For **Linux 6.18.44**, the buggy non-devm cooling-device registration
exists, `tegra_soctherm_remove()` does not unregister those devices, and
thermal callbacks dereference the freed `ts` pointer. The fix is
minimal, self-contained, uses infrastructure already in this tree, and
applies cleanly. This meets stable criteria for a real, important UAF
fix.
---
## Verification
- **[Phase 1]** Parsed subject, tags, and body from provided commit
message
- **[Phase 1]** Confirmed no Fixes:/Reported-by:/Cc: stable tags
- **[Phase 2]** Read `soctherm.c` lines 1502–1534, 1655–1719, 2101,
2180, 2228–2235
- **[Phase 2]** Confirmed `throt_get_cdev_cur_state()` dereferences
`cdev->devdata` as `ts`
- **[Phase 2]** Confirmed `tegra_soctherm_remove()` has no
`thermal_cooling_device_unregister()`
- **[Phase 3]** `git describe HEAD` → `v6.18.44`
- **[Phase 3]** `git blame -L 1700,1710` → history unreliable (unrelated
amdgpu commit)
- **[Phase 3]** `git log --oneline -- drivers/thermal/tegra/soctherm.c`
→ single unrelated commit
- **[Phase 3]** Verified `devm_thermal_of_cooling_device_register` in
`thermal_core.c:1217-1240` and `thermal.h:259`
- **[Phase 4]** `b4 am 20260424160019.41710-2-...` → 2-patch series,
applies clean
- **[Phase 4]** curl lore mbox → patch 2/2 content and series metadata;
Reviewed-by on patch 1/2 only
- **[Phase 4]** curl stable@ search → no prior discussion found
- **[Phase 5]** Traced call chain: `probe` →
`soctherm_init_hw_throt_cdev` → thermal callbacks on stale cdev
- **[Phase 5]** `grep thermal_cooling_device_unregister
drivers/thermal/tegra/` → no matches
- **[Phase 6]** Confirmed buggy `thermal_of_cooling_device_register()`
at lines 1703–1705
- **[Phase 6]** `git apply --check` on provided diff → clean apply
(3+/3-)
- **[Phase 6]** Read `Kconfig` → `CONFIG_TEGRA_SOCTHERM` tristate,
`ARCH_TEGRA || COMPILE_TEST`
- **[Phase 8]** Failure mode: UAF via `ts->regs` → severity HIGH
- **UNVERIFIED:** Exact kernel version/commit that introduced the non-
devm registration (git history in this checkout is not trustworthy)
**YES**
drivers/thermal/tegra/soctherm.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/thermal/tegra/soctherm.c b/drivers/thermal/tegra/soctherm.c
index 5d26b52beaba7..9d3eb3be2db02 100644
--- a/drivers/thermal/tegra/soctherm.c
+++ b/drivers/thermal/tegra/soctherm.c
@@ -1700,9 +1700,9 @@ static void soctherm_init_hw_throt_cdev(struct platform_device *pdev)
stc->init = true;
} else {
- tcd = thermal_of_cooling_device_register(np_stcc,
- (char *)name, ts,
- &throt_cooling_ops);
+ tcd = devm_thermal_of_cooling_device_register(dev, np_stcc,
+ (char *)name, ts,
+ &throt_cooling_ops);
if (IS_ERR_OR_NULL(tcd)) {
dev_err(dev,
"throttle-cfg: %s: failed to register cooling device\n",
--
2.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH AUTOSEL 6.18] PM: hibernate: call preallocate_image() after freeze prepare
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (2 preceding siblings ...)
2026-08-31 13:22 ` [PATCH AUTOSEL 6.18-5.10] thermal/drivers/tegra/soctherma: Switch to devm cooling device registration Sasha Levin
@ 2026-08-31 13:22 ` Sasha Levin
2026-08-31 13:24 ` [PATCH AUTOSEL 6.18-6.12] powercap: intel_rapl: Fix memory leak in rapl_add_package_cpuslocked() Sasha Levin
4 siblings, 0 replies; 5+ messages in thread
From: Sasha Levin @ 2026-08-31 13:22 UTC (permalink / raw)
To: patches, stable
Cc: Matthew Leach, Mario Limonciello (AMD), Rafael J. Wysocki,
Sasha Levin, rafael, linux-pm, linux-kernel
From: Matthew Leach <matthew.leach@collabora.com>
[ Upstream commit 783c8109844503bd1c35dab41b6d5fd074a9f131 ]
Certain drivers release resources (pinned pages, etc.) into system
memory during the prepare freeze PM op, making them swappable.
Currently, hibernate_preallocate_memory() is called before prepare
freeze, so those drivers have no opportunity to release resources
first. If a driver is holding a large amount of unswappable system
RAM, this can cause hibernate_preallocate_memory() to fail.
Move the call to hibernate_preallocate_memory() after prepare freeze.
According to the documentation for the prepare callback, devices should
be left in a usable state, so storage drivers should still be able to
service I/O requests. This allows drivers to release unswappable
resources prior to preallocation, so they can be swapped out through
hibernate_preallocate_memory()'s reclaim path.
Also remove shrink_shmem_memory() since hibernate_preallocate_memory()
will have reclaimed enough memory for the hibernation image.
Signed-off-by: Matthew Leach <matthew.leach@collabora.com>
Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org>
[ rjw: Subject and changelog tweaks ]
Link: https://patch.msgid.link/20260403-hibernation-fixes-v3-1-31bc9fa3ba2d@collabora.com
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: PM: hibernate: call preallocate_image()
after freeze prepare
**Local tree:** `v6.18.44` (stable/linux-6.18.y)
**Upstream commit:** `783c8109844503bd1c35dab41b6d5fd074a9f131` (not
present in this tree; cherry-picks cleanly)
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: Subject line
**Record:** `[PM: hibernate]` `[call/move]` — Reorder
`hibernate_preallocate_memory()` to run after `dpm_prepare(PMSG_FREEZE)`
instead of before it.
### Step 1.2: Tags
**Record:**
- **Signed-off-by:** Matthew Leach (author), Rafael J. Wysocki
(committer)
- **Reviewed-by:** Mario Limonciello (AMD) `<superm1@kernel.org>`
- **Link:** https://patch.msgid.link/20260403-hibernation-
fixes-v3-1-31bc9fa3ba2d@collabora.com
- No Fixes:, Reported-by:, Tested-by:, or Cc: stable tags
- Pipeline-added Signed-off-by: Sasha Levin — ignored per instructions
**Notable:** Reviewed by the AMD maintainer who also committed the
existing `shrink_shmem_memory()` workaround in this tree.
### Step 1.3: Body analysis
**Record:**
- **Bug:** `hibernate_preallocate_memory()` runs before
`dpm_prepare(PMSG_FREEZE)`. Drivers release pinned/unswappable pages
during `prepare`, but preallocation has already counted available
memory, so preallocation can fail.
- **Symptom:** Hibernation fails with insufficient memory for the
snapshot image.
- **Root cause:** Wrong ordering — resource release in `prepare` happens
too late.
- **Fix approach:** Move preallocation after `dpm_prepare`; remove
`shrink_shmem_memory()` as redundant (preallocate's reclaim path
handles it).
### Step 1.4: Hidden bug fix?
**Record:** Yes — described as reordering, but it fixes a real
functional bug (hibernation failure) and replaces an incomplete
workaround (`shrink_shmem_memory()`).
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: Inventory
**Record:**
- **File:** `kernel/power/hibernate.c` only (+9 / -37 lines)
- **Functions modified:** removes `shrink_shmem_memory()`; reorders
logic in `hibernation_snapshot()`
- **Scope:** Single-file, surgical reorder + cleanup
### Step 2.2: Code flow changes
**Record:**
| Hunk | Before | After |
|------|--------|-------|
| `shrink_shmem_memory()` | Called after `dpm_prepare()` | Function
removed entirely |
| Preallocation | Before `freeze_kernel_threads()` | After
`dpm_prepare(PMSG_FREEZE)` |
| `freeze_kernel_threads()` error | `goto Cleanup` → `swsusp_free()` |
`goto Close` (nothing to free yet) |
| `dpm_prepare()` error | inline `dpm_complete` + `goto Thaw` | `goto
Complete` |
| Preallocate error (new position) | N/A | `goto Complete` →
`dpm_complete(PMSG_RECOVER)` + thaw |
| `Cleanup:` label | `swsusp_free()` on early errors | Removed
(preallocate not yet run) |
### Step 2.3: Bug mechanism
**Record:** **Logic / ordering bug** in the hibernation snapshot
sequence.
- Drivers like AMDGPU call `amdgpu_device_prepare()` →
`amdgpu_device_evict_resources()` during `dpm_prepare()`, releasing
pinned BO memory.
- Preallocation before `prepare` cannot see that memory; reclaim during
preallocate cannot swap it out.
- The existing `shrink_shmem_memory()` workaround only partially
addresses a related symptom (VRAM moved to shmem during prepare) and
only reclaims ~50% of shmem.
### Step 2.4: Fix quality
**Record:** Obviously correct ordering fix. Error paths are simplified
and consistent with the new call order. `hibernate_preallocate_memory()`
already calls `shrink_all_memory()` internally (verified in
`snapshot.c:1918`), making the separate `shrink_shmem_memory()`
redundant. Low regression risk — reclaim-after-freeze was already done
at this point via `shrink_shmem_memory()`.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: Blame
**Record:**
- Preallocate-before-prepare ordering: Rafael Wysocki, 2009
(`64a473cb74a88`) — long-standing.
- `shrink_shmem_memory()`: Samuel Zhang, Jul 2025 (`2640e819474f4`) —
workaround for AMDGPU dGPU hibernation failures, **present in this
tree**.
### Step 3.2: Fixes: tag
**Record:** N/A — no Fixes: tag.
### Step 3.3: Related file history
**Record:** Recent related commits in this tree:
- `2640e819474f4` — add `shrink_shmem_memory()` workaround (this commit
removes it)
- `449c9c02537a1` — restore `pm_restrict_gfp_mask()` in
`hibernation_snapshot()`, needed because `shrink_shmem_memory()`
exposed swap/GFP issues (bugzilla #220555, Cc: stable 6.16+)
- `12ffc3b1513eb` — restrict swap use later in suspend sequence
### Step 3.4: Author context
**Record:** Matthew Leach (Collabora). Rafael Wysocki (PM maintainer)
committed upstream. Mario Limonciello (AMD, drm/PM) reviewed with LGTM
and previously committed the `shrink_shmem` workaround.
### Step 3.5: Dependencies
**Record:** Standalone single-patch series (`hibernation-fixes` v1→v3,
only this patch). No prerequisites beyond code already in 6.18.y.
Cherry-pick of `783c81098445` applies cleanly.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: Original discussion
**Record:**
- **URL:** https://patch.msgid.link/20260403-hibernation-
fixes-v3-1-31bc9fa3ba2d@collabora.com
- **Series:** v1 (Mar 21) → v2 (Mar 26) → v3 (Apr 3, committed version)
- v2 added removal of `shrink_shmem_memory()` and fixed error path; v3
renamed error labels
### Step 4.2: Reviewers
**Record:** CC'd Rafael Wysocki, Pavel Machek, Len Brown, Mario
Limonciello, linux-pm@, linux-kernel@. Mario Limonciello: "LGTM" +
Reviewed-by.
### Step 4.3: Bug reports
**Record:** No direct Reported-by. Related bugzilla #220555 (from
`449c9c02537a1`) documents breakage from `shrink_shmem_memory()`
interaction with GFP restrictions — this commit removes that workaround.
### Step 4.4: Series context
**Record:** Single-patch series. Rafael raised deadlock/reclaim concerns
(frozen kthreads, OOM killer disabled); Matthew responded that reclaim
after freeze was already done via `shrink_shmem_memory()` at the same
position — not a new pattern.
### Step 4.5: Stable list history
**Record:** No stable-list discussion found for this specific patch.
Related `449c9c02537a1` was explicitly nominated `Cc: stable 6.16+`.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: Key functions
**Record:** `hibernation_snapshot()`, `hibernate_preallocate_memory()`,
`shrink_shmem_memory()` (removed), `dpm_prepare()`.
### Step 5.2: Callers
**Record:** `hibernation_snapshot()` called from:
- `hibernate()` in `hibernate.c:836` — main hibernation entry via
`/sys/power/disk`
- `snapshot_write()` in `user.c:311` — `/dev/snapshot` interface
Both are userspace-triggered hibernation paths (root/capability
required).
### Step 5.3: Callees
**Record:** `hibernate_preallocate_memory()` → `shrink_all_memory()` →
direct reclaim via `do_try_to_free_pages()`. `dpm_prepare()` → driver
`.prepare` callbacks (e.g. `amdgpu_pmops_prepare()` →
`amdgpu_device_prepare()` → `amdgpu_device_evict_resources()`).
### Step 5.4: Reachability
**Record:** Triggered by any hibernation attempt (`echo disk >
/sys/power/state`, etc.). Requires `CONFIG_HIBERNATION`. Common on
laptops and some servers.
### Step 5.5: Similar patterns
**Record:** `shrink_shmem_memory()` was the prior partial fix for the
same class of problem. This commit is the architecturally correct
replacement.
---
## PHASE 6: CROSS-REFERENCING AGAINST LOCAL TREE
### Step 6.1: Buggy code exists?
**Record:** **Yes.** Current `v6.18.44` tree has preallocate before
`dpm_prepare` and the `shrink_shmem_memory()` workaround at lines
428-460 of `kernel/power/hibernate.c`. Bug present since 2009;
workaround added Jul 2025.
### Step 6.2: Backport complications
**Record:** **Clean apply.** `git cherry-pick --no-commit 783c81098445`
succeeds with auto-merge; `1 file changed, 9 insertions(+), 37
deletions(-)`.
### Step 6.3: Related fixes already present?
**Record:** `shrink_shmem_memory()` workaround (`2640e819474f4`) and GFP
mask fix (`449c9c02537a1`) are already in 6.18.y. This commit supersedes
the workaround with the proper fix. No duplicate fix present.
---
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
### Step 7.1: Subsystem criticality
**Record:** **kernel/power** — CORE subsystem for system
suspend/hibernate. Affects all hibernation users.
### Step 7.2: Activity
**Record:** Actively maintained; multiple hibernation fixes landed in
6.18.y cycle (GFP mask, hybrid-sleep, efivarfs freeze).
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
### Step 8.1: Who is affected
**Record:** Users who hibernate (`CONFIG_HIBERNATION=y`), especially
systems with AMDGPU/dGPUs or other drivers that release pinned memory
during `prepare`. The 6.18.y tree already carries the `shrink_shmem`
workaround, confirming real-world impact on this branch.
### Step 8.2: Trigger conditions
**Record:** Every hibernation attempt on affected hardware. Not timing-
dependent. Requires privilege to initiate hibernation (not unprivileged
attack vector).
### Step 8.3: Failure mode severity
**Record:** Hibernation fails — user cannot suspend-to-disk. **Severity:
MEDIUM-HIGH** for hibernation users (functional failure, no
crash/corruption, but complete feature breakage).
### Step 8.4: Risk-benefit
**Record:**
- **Benefit: HIGH** for hibernation users — fixes root cause, improves
on partial workaround, removes problematic `shrink_shmem_memory()`
that required a separate GFP fix.
- **Risk: LOW** — net code reduction, reclaim-after-freeze already
exercised in this tree, reviewed by subsystem experts, error paths
simplified.
- **Ratio:** Strong benefit, low risk.
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: Evidence summary
**FOR backport:**
- Fixes real hibernation failures on driver-heavy systems (AMD GPU evict
during prepare verified in tree)
- 6.18.y already has the `shrink_shmem` workaround this commit properly
replaces
- Small, surgical, net -28 lines
- Reviewed by Mario Limonciello (AMD) and committed by Rafael Wysocki
(PM maintainer)
- Applies cleanly to v6.18.44
- Reclaim-after-freeze pattern already proven safe in this tree (via
existing `shrink_shmem_memory()`)
- Removes code that previously caused GFP/swap issues (bugzilla #220555)
**AGAINST backport:**
- Not a crash, security, or data-corruption bug
- Partial workaround already in tree may mitigate the shmem-related case
- No explicit Cc: stable or user bug report on this specific patch
**Unresolved:** No end-user bugzilla for the pinned-pages case
specifically; impact inferred from commit message, AMDGPU code path, and
existing workaround history.
### Step 9.2: Stable rules checklist
1. Obviously correct and tested? **PASS** — logical ordering fix;
reviewed by AMD + PM maintainer; v1→v3 review addressed deadlock
concerns.
2. Fixes real bug affecting users? **PASS** — hibernation failure on
systems with drivers releasing pinned memory during prepare.
3. Important issue? **PASS** — hibernation completely fails (MEDIUM-HIGH
for affected users).
4. Small and contained? **PASS** — 1 file, 46 lines changed.
5. No new features/APIs? **PASS** — reordering only.
6. Can apply to local tree? **PASS** — cherry-picks cleanly.
### Step 9.3: Exception categories
**Record:** N/A — standard bug fix, not a quirk/DT/build/doc exception.
### Step 9.4: Problem and why it matters
The hibernation snapshot path preallocates memory for the image before
calling `dpm_prepare(PMSG_FREEZE)`. GPU and other drivers release large
amounts of pinned memory during `prepare`, but that happens too late —
preallocation has already failed or over-committed. The 6.18.y tree
currently papers over a related symptom with `shrink_shmem_memory()`,
which only partially reclaims shmem and required a separate GFP-mask
fix. This commit fixes the root ordering problem and removes the
workaround, making hibernation more reliable on affected hardware.
---
## Verification
- [Phase 1] `git describe HEAD` → v6.18.44; parsed subject, tags, body
from provided commit message
- [Phase 1] Tags: Reviewed-by Mario Limonciello; Link to lore; no
Fixes/Reported-by/Cc:stable
- [Phase 2] Read `kernel/power/hibernate.c:395-500` — confirmed current
buggy ordering and `shrink_shmem_memory()` present
- [Phase 2] Read `kernel/power/snapshot.c:1918` —
`hibernate_preallocate_memory()` calls `shrink_all_memory()`
- [Phase 3] `git blame -L 428,460 kernel/power/hibernate.c` —
preallocate ordering from 2009; shrink_shmem from 2640e819 (Jul 2025)
- [Phase 3] `git show 2640e819474f4` — workaround for dGPU VRAM→shmem
hibernation failure
- [Phase 3] `git show 449c9c02537a1` — GFP fix needed because of
shrink_shmem; bugzilla #220555; Cc: stable 6.16+
- [Phase 3] `git merge-base --is-ancestor 783c81098445 HEAD` →
NOT_IN_CURRENT_TREE
- [Phase 3] `git log --oneline -20 -- kernel/power/hibernate.c` — recent
PM hibernation activity
- [Phase 4] `b4 dig -c 1d74e7f09f725` → lore URL found
- [Phase 4] `b4 dig -c 1d74e7f09f725 -a` → v1/v2/v3 series; v3 is
committed version
- [Phase 4] `b4 dig -c 1d74e7f09f725 -w` → CC'd Rafael, Pavel, Len,
Mario, linux-pm@
- [Phase 4] `b4 dig -m /tmp/hibernate-fix.mbox` — Mario LGTM + Reviewed-
by; Rafael deadlock questions answered
- [Phase 5] `grep hibernation_snapshot(` — callers in `hibernate.c:836`,
`user.c:311`
- [Phase 5] Read `amdgpu_device.c:5174-5200` — `amdgpu_device_prepare()`
evicts resources during prepare
- [Phase 6] Buggy code confirmed present in v6.18.44 at lines 428-460
- [Phase 6] `git cherry-pick --no-commit 783c81098445` → clean apply,
9+/37-
- [Phase 6] `git diff HEAD..1d74e7f09f725 -- kernel/power/hibernate.c` —
identical changes needed
- [Phase 7] Subsystem: kernel/power (CORE)
- [Phase 8] Failure mode: hibernation failure; severity MEDIUM-HIGH for
hibernation users
**YES**The background searches finished and matched what the main
analysis already used:
- **Current tree (`v6.18.44`):** no match for this commit by
subject/grep — it isn’t in `stable/linux-6.18.y` yet.
- **`autosel` branch:** found upstream commit `783c81098445` / stable-
prepared `1d74e7f09f725` — *PM: hibernate: call preallocate_image()
after freeze prepare*.
- **Hibernation-fixes series:** single-patch series (v1→v3); nothing
else required for backport.
**Verdict for 6.18.y: YES** — real hibernation failure on driver
`prepare` paths, replaces the partial `shrink_shmem_memory()` workaround
already in this tree, cherry-picks cleanly.
kernel/power/hibernate.c | 46 ++++++++--------------------------------
1 file changed, 9 insertions(+), 37 deletions(-)
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index 26e45f86b9554..26289e3c28ae7 100644
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -392,23 +392,6 @@ static int create_image(int platform_mode)
return error;
}
-static void shrink_shmem_memory(void)
-{
- struct sysinfo info;
- unsigned long nr_shmem_pages, nr_freed_pages;
-
- si_meminfo(&info);
- nr_shmem_pages = info.sharedram; /* current page count used for shmem */
- /*
- * The intent is to reclaim all shmem pages. Though shrink_all_memory() can
- * only reclaim about half of them, it's enough for creating the hibernation
- * image.
- */
- nr_freed_pages = shrink_all_memory(nr_shmem_pages);
- pr_debug("requested to reclaim %lu shmem pages, actually freed %lu pages\n",
- nr_shmem_pages, nr_freed_pages);
-}
-
/**
* hibernation_snapshot - Quiesce devices and create a hibernation image.
* @platform_mode: If set, use platform driver to prepare for the transition.
@@ -425,14 +408,9 @@ int hibernation_snapshot(int platform_mode)
if (error)
goto Close;
- /* Preallocate image memory before shutting down devices. */
- error = hibernate_preallocate_memory();
- if (error)
- goto Close;
-
error = freeze_kernel_threads();
if (error)
- goto Cleanup;
+ goto Close;
if (hibernation_test(TEST_FREEZER)) {
@@ -445,19 +423,13 @@ int hibernation_snapshot(int platform_mode)
}
error = dpm_prepare(PMSG_FREEZE);
- if (error) {
- dpm_complete(PMSG_RECOVER);
- goto Thaw;
- }
+ if (error)
+ goto Complete;
- /*
- * Device drivers may move lots of data to shmem in dpm_prepare(). The shmem
- * pages will use lots of system memory, causing hibernation image creation
- * fail due to insufficient free memory.
- * This call is to force flush the shmem pages to swap disk and reclaim
- * the system memory so that image creation can succeed.
- */
- shrink_shmem_memory();
+ /* Preallocate image memory before shutting down devices. */
+ error = hibernate_preallocate_memory();
+ if (error)
+ goto Complete;
console_suspend_all();
pm_restrict_gfp_mask();
@@ -492,10 +464,10 @@ int hibernation_snapshot(int platform_mode)
platform_end(platform_mode);
return error;
+ Complete:
+ dpm_complete(PMSG_RECOVER);
Thaw:
thaw_kernel_threads();
- Cleanup:
- swsusp_free();
goto Close;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH AUTOSEL 6.18-6.12] powercap: intel_rapl: Fix memory leak in rapl_add_package_cpuslocked()
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (3 preceding siblings ...)
2026-08-31 13:22 ` [PATCH AUTOSEL 6.18] PM: hibernate: call preallocate_image() after freeze prepare Sasha Levin
@ 2026-08-31 13:24 ` Sasha Levin
4 siblings, 0 replies; 5+ messages in thread
From: Sasha Levin @ 2026-08-31 13:24 UTC (permalink / raw)
To: patches, stable
Cc: Sumeet Pawnikar, Rafael J. Wysocki, Sasha Levin, rafael, linux-pm,
linux-kernel
From: Sumeet Pawnikar <sumeet4linux@gmail.com>
[ Upstream commit bfc7d93bc5e12288e5dc6bb54260f68cdf5a5c47 ]
When topology_physical_package_id()/topology_logical_die_id() returns
a negative value, rapl_add_package_cpuslocked() returns ERR_PTR(-EINVAL)
directly without freeing the rapl_package structure that was just
allocated by kzalloc_obj(), leaking memory on every failed package
addition.
Use the existing err_free_package label so that the allocation is
released on the error path.
Signed-off-by: Sumeet Pawnikar <sumeet4linux@gmail.com>
Link: https://patch.msgid.link/20260515182616.227707-1-sumeet4linux@gmail.com
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit Message Forensics
### Step 1.1: Subject line
**Record:** `[powercap: intel_rapl]` `[Fix]` — memory leak in
`rapl_add_package_cpuslocked()` on topology error path.
### Step 1.2: Tags
**Record:**
- **Signed-off-by:** Sumeet Pawnikar `<sumeet4linux@gmail.com>` (author)
- **Link:** https://patch.msgid.link/20260515182616.227707-1-
sumeet4linux@gmail.com
- **Signed-off-by:** Rafael J. Wysocki `<rafael.j.wysocki@intel.com>`
(powercap/ACPI maintainer)
- No `Fixes:`, `Reported-by:`, `Tested-by:`, `Reviewed-by:`, `Cc:
stable@vger.kernel.org`
Notable: maintainer sign-off; no syzbot/fuzzer report.
### Step 1.3: Body analysis
**Record:**
- **Bug:** After `kzalloc`/`kzalloc_obj` allocates `struct
rapl_package`, if `topology_physical_package_id()` or
`topology_logical_die_id()` yields a negative value, the function
returns `ERR_PTR(-EINVAL)` without freeing `rp`.
- **Symptom:** Kernel memory leak on each failed package addition.
- **Root cause:** Missing jump to existing `err_free_package` cleanup
label on this error path.
- **Fix:** Set `ret = -EINVAL` and `goto err_free_package`.
### Step 1.4: Hidden bug fix?
**Record:** No — explicitly labeled and described as a memory leak fix.
---
## Phase 2: Diff Analysis
### Step 2.1: Inventory
**Record:**
- **File:** `drivers/powercap/intel_rapl_common.c` (+2 / -1 lines in
hunk)
- **Function:** `rapl_add_package_cpuslocked()`
- **Scope:** Single-file, surgical error-path fix
Note: upstream diff uses `kzalloc_obj()`; this tree uses
`kzalloc(sizeof(struct rapl_package), GFP_KERNEL)` at line 2210 —
allocation line unchanged by the fix.
### Step 2.2: Code flow change
**Record:**
- **Before:** On negative topology ID → immediate `return
ERR_PTR(-EINVAL)` with `rp` leaked.
- **After:** On negative topology ID → `ret = -EINVAL; goto
err_free_package;` → `kfree(rp->domains); kfree(rp); return
ERR_PTR(ret);`
- **Path:** Error path in CPU-hotplug-driven package registration,
before `rapl_config()`.
### Step 2.3: Bug mechanism
**Record:** **Category:** Error-path resource leak (missing `kfree`).
- `rp->domains` is not yet allocated at this point; `kfree(NULL)` in
`err_free_package` is safe.
- Other error paths (`rapl_config`, `rapl_detect_domains`,
`rapl_package_register_powercap`) already use `err_free_package`.
### Step 2.4: Fix quality
**Record:** Obviously correct; reuses existing cleanup. Minimal
regression risk — no new APIs, locks, or behavior changes on success
paths.
---
## Phase 3: Git History Investigation
### Step 3.1: Blame
**Record:** Lines 2210–2219 blame to `7e22de67e545d` in this checkout
(shallow/stable history). Buggy early-return pattern is present in
current tree at lines 2217–2219.
### Step 3.2: Fixes: tag
**Record:** N/A — no `Fixes:` tag.
### Step 3.3: Related file history
**Record:** `git log --oneline -- drivers/powercap/intel_rapl_common.c`
shows only one commit in this checkout’s history. Negative-topology
guard and `err_free_package` label are both present; only the EINVAL
path omits cleanup.
### Step 3.4: Author context
**Record:** Sumeet Pawnikar; Rafael Wysocki (subsystem maintainer)
committed/acked. No other author commits visible in this shallow tree.
### Step 3.5: Dependencies
**Record:** Standalone; no series or prerequisite commits.
`err_free_package` already exists in this tree.
---
## Phase 4: Mailing List and External Research
### Step 4.1: Original discussion
**Record:** `b4 dig -c HEAD` found no match. `b4 dig` with message-id
argument failed (wrong syntax). Lore and patch.msgid.link fetches
returned no usable review content (bot protection / thread not indexed).
**Series revisions, reviewer feedback, stable nominations: UNVERIFIED.**
### Step 4.2: Reviewers
**Record:** UNVERIFIED from lore. Maintainer SOB from Rafael Wysocki is
present in commit message.
### Step 4.3: Bug report
**Record:** No external bug report or syzbot link. Issue identified by
code inspection per commit message.
### Step 4.4: Related patches
**Record:** None found in local `.mbx` files.
### Step 4.5: Stable list
**Record:** UNVERIFIED — no stable-list discussion found.
---
## Phase 5: Code Semantic Analysis
### Step 5.1: Key functions
**Record:** `rapl_add_package_cpuslocked()`,
`rapl_find_package_domain_cpuslocked()`, `rapl_cpu_online()`.
### Step 5.2: Callers
**Record:**
- `drivers/powercap/intel_rapl_msr.c:79` — `rapl_cpu_online()` CPU
hotplug callback (`id_is_cpu=true`)
- `rapl_add_package()` wrapper at `intel_rapl_common.c:2258–2261`
- `drivers/powercap/intel_rapl_tpmi.c:309` — `rapl_add_package(...,
false)` (non-CPU ID path; bug path only when `id_is_cpu=true`)
- `drivers/thermal/intel/int340x_thermal/processor_thermal_rapl.c:84` —
`rapl_add_package(0, ..., false)` (not affected)
### Step 5.3: Callees
**Record:** `kzalloc`, `topology_physical_package_id`,
`topology_logical_die_id`, `rapl_config`, `err_free_package` cleanup
(`kfree`).
### Step 5.4: Reachability
**Record:** Reachable from CPU hotplug on Intel/AMD/HYGON systems with
`CONFIG_INTEL_RAPL` MSR driver.
Trigger chain verified in code:
1. `rapl_cpu_online()` calls `rapl_find_package_domain_cpuslocked()` —
if topology ID is negative, returns `NULL` (no leak).
2. Because `!rp`, calls `rapl_add_package_cpuslocked()` — allocates
`rp`, hits same negative check, leaks on current code.
On x86, `topology_get_logical_id()` can return `-ENODEV` or `-ERANGE`;
stored in `u32 logical_die_id`, then `(int)rp->id < 0` detects the
wrapped negative value.
### Step 5.5: Similar patterns
**Record:** `rapl_find_package_domain_cpuslocked()` at lines 2177–2181
handles the same negative-topology case without allocation —
`rapl_add_package_cpuslocked()` is inconsistent.
---
## Phase 6: Cross-Reference Against Local Tree (6.18.44)
### Step 6.1: Buggy code present?
**Record:** **YES.** Tree is `v6.18.44` (`VERSION=6 PATCHLEVEL=18
SUBLEVEL=44`). Bug at:
```2217:2219:drivers/powercap/intel_rapl_common.c
if ((int)(rp->id) < 0) {
pr_err("topology_logical_(package/die)_id()
returned a negative value");
return ERR_PTR(-EINVAL);
```
`err_free_package` exists at lines 2251–2254.
### Step 6.2: Backport complications
**Record:** Clean apply expected — only change `return ERR_PTR(-EINVAL)`
to `ret = -EINVAL; goto err_free_package`. No conflict with `kzalloc` vs
upstream `kzalloc_obj`.
### Step 6.3: Related fixes already present?
**Record:** No — `git log --grep` found no matching fix; leaky path
still present.
---
## Phase 7: Subsystem Context
### Step 7.1: Subsystem criticality
**Record:** `drivers/powercap/intel_rapl` — **IMPORTANT** (Intel/AMD
power monitoring; widely enabled on x86 servers/laptops with
`CONFIG_INTEL_RAPL`).
### Step 7.2: Activity
**Record:** Shallow history in this checkout; driver and CPU hotplug
integration are mature and active in mainline.
---
## Phase 8: Impact and Risk Assessment
### Step 8.1: Who is affected
**Record:** x86 systems with Intel RAPL MSR driver
(`CONFIG_INTEL_RAPL=m/y`), during CPU online/hotplug when topology IDs
are invalid.
### Step 8.2: Trigger conditions
**Record:** `topology_physical_package_id()` or
`topology_logical_die_id()` returns a value that is negative when cast
to `int` (e.g. `topology_get_logical_id()` error stored in `u32`).
Uncommon but realistic during hotplug races or topology registration
failures. Not userspace-triggerable directly; kernel-initiated on CPU
online.
### Step 8.3: Failure mode severity
**Record:** **MEDIUM** — kmem leak (~one `struct rapl_package` per
failed attempt). No crash, corruption, or deadlock. Repeated hotplug
retries could accumulate leaked memory.
### Step 8.4: Risk-benefit
**Record:**
- **Benefit:** Eliminates leak on an error path that is explicitly
exercised when `rapl_find_package_domain_cpuslocked()` already
returned `NULL` for the same reason.
- **Risk:** Very low — 2-line logic change using existing cleanup.
- **Ratio:** Favorable for stable.
---
## Phase 9: Final Synthesis
### Step 9.1: Evidence summary
**FOR backport:**
- Real, verified memory leak on error path
- Buggy code confirmed present in Linux 6.18.44 tree
- Fix is minimal, obviously correct, uses existing `err_free_package`
- Reachable from CPU hotplug (common on servers)
- Maintainer sign-off
- Matches stable pattern for error-path resource leaks
**AGAINST backport:**
- Failure mode is leak, not crash/corruption/security
- Trigger is relatively rare (invalid topology during hotplug)
- No fuzzer report or user bug report
**UNVERIFIED:**
- Lore review discussion and stable nominations
- Exact mainline commit SHA in this autosel checkout
- When the negative-topology guard was first introduced (shallow git
history)
### Step 9.2: Stable rules checklist
1. Obviously correct and tested? **PASS** — standard `goto` cleanup;
maintainer SOB; no Tested-by.
2. Fixes a real bug? **PASS** — kmem leak on EINVAL path.
3. Important issue? **PASS (moderate)** — resource leak on hotplug path,
not critical crash.
4. Small and contained? **PASS** — 2-line functional change.
5. No new features/APIs? **PASS**.
6. Can apply to local tree? **PASS** — code exists; clean apply
expected.
### Step 9.3: Exception categories
**Record:** None (not device ID, quirk, DT, build, or docs).
### Step 9.4: Decision rationale
For **this** tree (Linux 6.18.44), the bug exists, the fix is trivial
and correct, and the leak is on a reachable CPU-hotplug error path.
While not as severe as a crash or UAF, error-path kmem leaks in core
infrastructure drivers are routinely backported when the fix is this
small and low-risk. The inconsistency with
`rapl_find_package_domain_cpuslocked()` (which handles the same
condition without leaking) further supports inclusion.
---
## Verification
- **[Phase 1]** Parsed subject, tags, body from user-provided commit
message
- **[Phase 1]** Confirmed no syzbot/Fixes:/Cc: stable tags
- **[Phase 2]** Read `drivers/powercap/intel_rapl_common.c:2205–2254` —
confirmed leak and `err_free_package` cleanup
- **[Phase 2]** Verified `kfree(rp->domains)` safe before
`rapl_config()` on early error path
- **[Phase 3]** `git describe HEAD` → `v6.18.44`; Makefile → 6.18.44
- **[Phase 3]** `git blame -L 2210,2220` — buggy return at line 2219
- **[Phase 3]** `git log --grep` — no fix commit already in tree
- **[Phase 4]** `b4 dig -c HEAD` — no match
- **[Phase 4]** Lore/patch.msgid.link fetch — no usable review content
(UNVERIFIED review discussion)
- **[Phase 5]** `grep rapl_add_package` — callers in `intel_rapl_msr.c`,
`intel_rapl_tpmi.c`, `processor_thermal_rapl.c`
- **[Phase 5]** Read `intel_rapl_msr.c:73–84` — hotplug call chain
confirmed
- **[Phase 5]** Read `topology.c:311–321` — `topology_get_logical_id()`
returns negative errors
- **[Phase 5]** Read `processor.h:95` — `logical_die_id` is `u32`;
negative errors wrap and are caught by `(int)rp->id < 0`
- **[Phase 5]** Read `rapl_find_package_domain_cpuslocked:2176–2181` —
same check without allocation
- **[Phase 6]** Confirmed buggy code at lines 2217–2219 in local tree
- **[Phase 6]** Confirmed fix not yet applied
- **[Phase 7]** `drivers/powercap/Kconfig` — `CONFIG_INTEL_RAPL` exists
- **[Phase 8]** Assessed severity as MEDIUM kmem leak on hotplug error
path
**YES**
drivers/powercap/intel_rapl_common.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/powercap/intel_rapl_common.c b/drivers/powercap/intel_rapl_common.c
index 57bebd07c7d0d..f08ac99f5e55e 100644
--- a/drivers/powercap/intel_rapl_common.c
+++ b/drivers/powercap/intel_rapl_common.c
@@ -2216,7 +2216,8 @@ struct rapl_package *rapl_add_package_cpuslocked(int id, struct rapl_if_priv *pr
topology_physical_package_id(id) : topology_logical_die_id(id);
if ((int)(rp->id) < 0) {
pr_err("topology_logical_(package/die)_id() returned a negative value");
- return ERR_PTR(-EINVAL);
+ ret = -EINVAL;
+ goto err_free_package;
}
rp->lead_cpu = id;
if (!rapl_msrs_are_pkg_scope() && topology_max_dies_per_package() > 1)
--
2.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-08-31 13:41 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20260831133314.4125787-1-sashal@kernel.org>
2026-08-31 13:20 ` [PATCH AUTOSEL 6.18-6.6] thermal/drivers/qcom/tsens: Atomic temperature read with hardware-guided retries Sasha Levin
2026-08-31 13:22 ` [PATCH AUTOSEL 6.18] cpufreq/amd-pstate: Loosen requirement on lowest nonlinear frequency != min freq Sasha Levin
2026-08-31 13:22 ` [PATCH AUTOSEL 6.18-5.10] thermal/drivers/tegra/soctherma: Switch to devm cooling device registration Sasha Levin
2026-08-31 13:22 ` [PATCH AUTOSEL 6.18] PM: hibernate: call preallocate_image() after freeze prepare Sasha Levin
2026-08-31 13:24 ` [PATCH AUTOSEL 6.18-6.12] powercap: intel_rapl: Fix memory leak in rapl_add_package_cpuslocked() Sasha Levin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox