From: Peter Åstrand astrand@lysator.liu.se
[ Upstream commit e75665dd096819b1184087ba5718bd93beafff51 ]
This avoids occasional skb_under_panic Oops from wl1271_tx_work. In this case, headroom is less than needed (typically 110 - 94 = 16 bytes).
Signed-off-by: Peter Astrand astrand@lysator.liu.se Link: https://patch.msgid.link/097bd417-e1d7-acd4-be05-47b199075013@lysator.liu.se Signed-off-by: Johannes Berg johannes.berg@intel.com Signed-off-by: Sasha Levin sashal@kernel.org ---
LLM Generated explanations, may be completely bogus:
## Commit Analysis: wifi: wlcore: ensure skb headroom before skb_push
### 1. COMMIT MESSAGE ANALYSIS
**Key indicators:** - Subject clearly states this ensures skb headroom before skb_push - a defensive check - Body explicitly states: "This avoids occasional skb_under_panic Oops from wl1271_tx_work" - Provides specific details: "headroom is less than needed (typically 110 - 94 = 16 bytes)" - Committed by Johannes Berg (wireless maintainer)
The commit message clearly indicates this fixes a **kernel panic** - one of the most severe bug categories.
### 2. CODE CHANGE ANALYSIS
Let me examine the actual code change:
```c if (total_blocks <= wl->tx_blocks_available) { + if (skb_headroom(skb) < (total_len - skb->len) && + pskb_expand_head(skb, (total_len - skb->len), 0, GFP_ATOMIC)) { + wl1271_free_tx_id(wl, id); + return -EAGAIN; + } desc = skb_push(skb, total_len - skb->len); ```
**The bug mechanism:** - `skb_push()` prepends space to an skb to add the TX hardware descriptor - If the skb doesn't have sufficient headroom, `skb_push()` triggers `skb_under_panic()` - a kernel Oops - The original code assumed sufficient headroom always existed, which is incorrect
**The fix mechanism:** 1. Check if headroom is insufficient: `skb_headroom(skb) < (total_len - skb->len)` 2. If insufficient, call `pskb_expand_head()` to expand the buffer 3. On expansion failure (memory pressure), properly cleanup by freeing the tx_id 4. Return `-EAGAIN` to indicate temporary failure (allows retry) 5. Only proceed with `skb_push()` after headroom is guaranteed
**Technical correctness:** - Uses `GFP_ATOMIC` - correct for TX path which may hold locks - Properly frees the allocated `id` on failure path (no resource leak) - Returns `-EAGAIN` which is the appropriate error for temporary failures - This is a well-established kernel pattern for skb headroom handling
### 3. CLASSIFICATION
**Type:** Bug fix - fixes a kernel panic (skb_under_panic Oops)
**Not in exception categories** - this is a straight bug fix for a crash, not a device ID, quirk, DT update, or build fix.
### 4. SCOPE AND RISK ASSESSMENT
| Metric | Assessment | |--------|------------| | Lines added | +5 lines of actual logic | | Files changed | 1 file | | Complexity | Very low - standard skb headroom check pattern | | Risk | **Very low** - defensive check that cannot make things worse |
**Failure mode analysis:** - If `pskb_expand_head()` fails: returns -EAGAIN, TX retries later (graceful degradation) - If check is overly conservative: no harm, just an extra allocation - Cannot introduce new crashes - the check is purely defensive
### 5. USER IMPACT
**Affected users:** Users of TI WiLink WiFi hardware (wl12xx/wl18xx families) - Common in embedded systems, some laptops, IoT devices - This is a mature, production driver present in all stable trees
**Bug severity:** **Critical** - kernel panic causes system crash - Even "occasional" panics are unacceptable in production - WiFi TX is a common operation, so affected users hit this repeatedly
### 6. STABILITY INDICATORS
- Reviewed and accepted by wireless maintainer (Johannes Berg) - Simple, well-understood pattern used throughout the kernel - The fix has minimal side effects - worst case is a failed TX that retries
### 7. DEPENDENCY CHECK
- **Standalone fix** - no dependencies on other commits - Uses standard kernel APIs (skb_headroom, pskb_expand_head) that exist in all stable trees - The wlcore driver has existed for many years in stable kernels
### SUMMARY
**This is a textbook stable candidate:**
1. **Fixes a kernel panic** - the most critical bug category 2. **Small and surgical** - 5 lines of defensive checking 3. **Obviously correct** - standard skb headroom pattern used throughout kernel 4. **Zero regression risk** - purely defensive, cannot make things worse 5. **No new features** - just adds a safety check before existing operation 6. **Affects real users** - wlcore is a production driver for shipping hardware 7. **No dependencies** - applies cleanly to any kernel version with wlcore
The fix prevents a real kernel Oops that users encounter in production. The change is minimal, the pattern is well-established, and the risk of regression is essentially zero. This is exactly the type of fix that stable kernel rules are designed to accept.
**YES**
drivers/net/wireless/ti/wlcore/tx.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c index 464587d16ab2..f251627c24c6 100644 --- a/drivers/net/wireless/ti/wlcore/tx.c +++ b/drivers/net/wireless/ti/wlcore/tx.c @@ -207,6 +207,11 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif, total_blocks = wlcore_hw_calc_tx_blocks(wl, total_len, spare_blocks);
if (total_blocks <= wl->tx_blocks_available) { + if (skb_headroom(skb) < (total_len - skb->len) && + pskb_expand_head(skb, (total_len - skb->len), 0, GFP_ATOMIC)) { + wl1271_free_tx_id(wl, id); + return -EAGAIN; + } desc = skb_push(skb, total_len - skb->len);
wlcore_hw_set_tx_desc_blocks(wl, desc, total_blocks,