developer | 33907d4 | 2022-09-19 14:33:58 +0800 | [diff] [blame^] | 1 | From: Alexander Wetzel <alexander@wetzel-home.de> |
| 2 | Date: Thu, 15 Sep 2022 14:41:20 +0200 |
| 3 | Subject: [PATCH] mac80211: Fix deadlock: Don't start TX while holding |
| 4 | fq->lock |
| 5 | |
| 6 | ieee80211_txq_purge() calls fq_tin_reset() and |
| 7 | ieee80211_purge_tx_queue(); Both are then calling |
| 8 | ieee80211_free_txskb(). Which can decide to TX the skb again. |
| 9 | |
| 10 | There are at least two ways to get a deadlock: |
| 11 | |
| 12 | 1) When we have a TDLS teardown packet queued in either tin or frags |
| 13 | ieee80211_tdls_td_tx_handle() will call ieee80211_subif_start_xmit() |
| 14 | while we still hold fq->lock. ieee80211_txq_enqueue() will thus |
| 15 | deadlock. |
| 16 | |
| 17 | 2) A variant of the above happens if aggregation is up and running: |
| 18 | In that case ieee80211_iface_work() will deadlock with the original |
| 19 | task: The original tasks already holds fq->lock and tries to get |
| 20 | sta->lock after kicking off ieee80211_iface_work(). But the worker |
| 21 | can get sta->lock prior to the original task and will then spin for |
| 22 | fq->lock. |
| 23 | |
| 24 | Avoid these deadlocks by not sending out any skbs when called via |
| 25 | ieee80211_free_txskb(). |
| 26 | |
| 27 | Signed-off-by: Alexander Wetzel <alexander@wetzel-home.de> |
| 28 | --- |
| 29 | |
| 30 | --- a/net/mac80211/status.c |
| 31 | +++ b/net/mac80211/status.c |
| 32 | @@ -698,7 +698,7 @@ static void ieee80211_report_used_skb(st |
| 33 | |
| 34 | if (!sdata) { |
| 35 | skb->dev = NULL; |
| 36 | - } else { |
| 37 | + } else if (!dropped) { |
| 38 | unsigned int hdr_size = |
| 39 | ieee80211_hdrlen(hdr->frame_control); |
| 40 | |