* [PATCH 0/2] rtl818x: enhance skb/urb management
@ 2025-06-16 10:10 Daniil Dulov
2025-06-16 10:10 ` [PATCH 1/2] rtl818x: Fix potential data race in rtl8187_tx_cb() Daniil Dulov
2025-06-16 10:10 ` [PATCH 2/2] rtl818x: Kill URBs before clearing tx status queue Daniil Dulov
0 siblings, 2 replies; 6+ messages in thread
From: Daniil Dulov @ 2025-06-16 10:10 UTC (permalink / raw)
To: Hin-Tak Leung
Cc: Daniil Dulov, Larry Finger, John W. Linville, linux-wireless,
linux-kernel, lvc-project
This series of patches is aiming to enhance skb/urb management at rtl818x.
The first patch of the series fixes data race in rtl8187_tx_cb() by acquiring
the queue lock before any work with the queue is done.
The second patch of the series enhances data race protection by killing URBs
before clearing skb queue, thus preventing callbacks from referencing an
already freed skb.
Daniil Dulov (2):
rtl818x: Fix potential data race in rtl8187_tx_cb()
rtl818x: Kill URBs before clearing tx status queue
.../net/wireless/realtek/rtl818x/rtl8187/dev.c | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 1/2] rtl818x: Fix potential data race in rtl8187_tx_cb()
2025-06-16 10:10 [PATCH 0/2] rtl818x: enhance skb/urb management Daniil Dulov
@ 2025-06-16 10:10 ` Daniil Dulov
2025-06-17 1:11 ` Ping-Ke Shih
2025-06-16 10:10 ` [PATCH 2/2] rtl818x: Kill URBs before clearing tx status queue Daniil Dulov
1 sibling, 1 reply; 6+ messages in thread
From: Daniil Dulov @ 2025-06-16 10:10 UTC (permalink / raw)
To: Hin-Tak Leung
Cc: Daniil Dulov, Larry Finger, John W. Linville, linux-wireless,
linux-kernel, lvc-project
There is a potential data race between rtl8187_tx_cb() and rtl8187_stop().
It is possible for rtl8187_stop() to clear the queue right after rtl8187_tx_cb()
checks that queue has more than 5 elements, but before it dequeues any skb.
This results in skb_dequeue() returns NULL and the pointer is dereferenced
in ieee80211_tx_status_irqsafe().
BUG: kernel NULL pointer dereference, address: 0000000000000080
#PF: supervisor read access in kernel mode
#PF: error_code(0x0000) - not-present page
PGD 0 P4D 0
Oops: Oops: 0000 [#1] SMP NOPTI
CPU: 7 UID: 0 PID: 0 Comm: swapper/7 Not tainted 6.15.0 #8 PREEMPT(voluntary)
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 0.0.0 02/06/2015
RIP: 0010:ieee80211_tx_status_irqsafe+0x21/0xc0 [mac80211]
Call Trace:
<IRQ>
rtl8187_tx_cb+0x116/0x150 [rtl8187]
__usb_hcd_giveback_urb+0x9d/0x120
usb_giveback_urb_bh+0xbb/0x140
process_one_work+0x19b/0x3c0
bh_worker+0x1a7/0x210
tasklet_action+0x10/0x30
handle_softirqs+0xf0/0x340
__irq_exit_rcu+0xcd/0xf0
common_interrupt+0x85/0xa0
</IRQ>
In order to avoid potential data races and leading dereference of a NULL
pointer, acquire the queue lock before any work with the queue is done and
replace all skb_* calls with their lockless versions.
Found by Linux Verification Center (linuxtesting.org) with SVACE.
Fixes: 3517afdefc3a ("rtl8187: feedback transmitted packets using tx close descriptor for 8187B")
Signed-off-by: Daniil Dulov <d.dulov@aladdin.ru>
---
.../net/wireless/realtek/rtl818x/rtl8187/dev.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
index 220ac5bdf279..8fe6fdc32e56 100644
--- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
+++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
@@ -189,6 +189,7 @@ static void rtl8187_tx_cb(struct urb *urb)
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hw *hw = info->rate_driver_data[0];
struct rtl8187_priv *priv = hw->priv;
+ unsigned long flags;
skb_pull(skb, priv->is_rtl8187b ? sizeof(struct rtl8187b_tx_hdr) :
sizeof(struct rtl8187_tx_hdr));
@@ -196,7 +197,8 @@ static void rtl8187_tx_cb(struct urb *urb)
if (!(urb->status) && !(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
if (priv->is_rtl8187b) {
- skb_queue_tail(&priv->b_tx_status.queue, skb);
+ spin_lock_irqsave(&priv->b_tx_status.queue.lock, flags);
+ __skb_queue_tail(&priv->b_tx_status.queue, skb);
/* queue is "full", discard last items */
while (skb_queue_len(&priv->b_tx_status.queue) > 5) {
@@ -205,9 +207,11 @@ static void rtl8187_tx_cb(struct urb *urb)
dev_dbg(&priv->udev->dev,
"transmit status queue full\n");
- old_skb = skb_dequeue(&priv->b_tx_status.queue);
+ old_skb = __skb_dequeue(&priv->b_tx_status.queue);
ieee80211_tx_status_irqsafe(hw, old_skb);
}
+
+ spin_unlock_irqrestore(&priv->b_tx_status.queue.lock, flags);
return;
} else {
info->flags |= IEEE80211_TX_STAT_ACK;
@@ -893,6 +897,7 @@ static void rtl8187_work(struct work_struct *work)
work.work);
struct ieee80211_tx_info *info;
struct ieee80211_hw *dev = priv->dev;
+ unsigned long flags;
static u16 retry;
u16 tmp;
u16 avg_retry;
@@ -900,6 +905,8 @@ static void rtl8187_work(struct work_struct *work)
mutex_lock(&priv->conf_mutex);
tmp = rtl818x_ioread16(priv, (__le16 *)0xFFFA);
+
+ spin_lock_irqsave(&priv->b_tx_status.queue.lock, flags);
length = skb_queue_len(&priv->b_tx_status.queue);
if (unlikely(!length))
length = 1;
@@ -909,13 +916,15 @@ static void rtl8187_work(struct work_struct *work)
while (skb_queue_len(&priv->b_tx_status.queue) > 0) {
struct sk_buff *old_skb;
- old_skb = skb_dequeue(&priv->b_tx_status.queue);
+ old_skb = __skb_dequeue(&priv->b_tx_status.queue);
info = IEEE80211_SKB_CB(old_skb);
info->status.rates[0].count = avg_retry + 1;
if (info->status.rates[0].count > RETRY_COUNT)
info->flags &= ~IEEE80211_TX_STAT_ACK;
ieee80211_tx_status_irqsafe(dev, old_skb);
}
+ spin_unlock_irqrestore(&priv->b_tx_status.queue.lock, flags);
+
retry = tmp;
mutex_unlock(&priv->conf_mutex);
}
--
2.34.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 2/2] rtl818x: Kill URBs before clearing tx status queue
2025-06-16 10:10 [PATCH 0/2] rtl818x: enhance skb/urb management Daniil Dulov
2025-06-16 10:10 ` [PATCH 1/2] rtl818x: Fix potential data race in rtl8187_tx_cb() Daniil Dulov
@ 2025-06-16 10:10 ` Daniil Dulov
2025-06-17 1:18 ` Ping-Ke Shih
1 sibling, 1 reply; 6+ messages in thread
From: Daniil Dulov @ 2025-06-16 10:10 UTC (permalink / raw)
To: Hin-Tak Leung
Cc: Daniil Dulov, Larry Finger, John W. Linville, linux-wireless,
linux-kernel, lvc-project
In rtl8187_stop() move the call of usb_kill_anchored_urbs() before clearing
b_tx_status.queue. This change prevents callbacks from using already freed
skb due to anchor was not killed before freeing such skb.
Found by Linux Verification Center (linuxtesting.org) with SVACE.
Fixes: c1db52b9d27e ("rtl8187: Use usb anchor facilities to manage urbs")
Signed-off-by: Daniil Dulov <d.dulov@aladdin.ru>
---
drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
index 8fe6fdc32e56..12e2042ee2d0 100644
--- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
+++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
@@ -1050,10 +1050,10 @@ static void rtl8187_stop(struct ieee80211_hw *dev, bool suspend)
rtl818x_iowrite8(priv, &priv->map->CONFIG4, reg | RTL818X_CONFIG4_VCOOFF);
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+ usb_kill_anchored_urbs(&priv->anchored);
while ((skb = skb_dequeue(&priv->b_tx_status.queue)))
dev_kfree_skb_any(skb);
- usb_kill_anchored_urbs(&priv->anchored);
mutex_unlock(&priv->conf_mutex);
if (!priv->is_rtl8187b)
--
2.34.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* RE: [PATCH 1/2] rtl818x: Fix potential data race in rtl8187_tx_cb()
2025-06-16 10:10 ` [PATCH 1/2] rtl818x: Fix potential data race in rtl8187_tx_cb() Daniil Dulov
@ 2025-06-17 1:11 ` Ping-Ke Shih
2025-06-17 12:41 ` Fedor Pchelkin
0 siblings, 1 reply; 6+ messages in thread
From: Ping-Ke Shih @ 2025-06-17 1:11 UTC (permalink / raw)
To: Daniil Dulov, Hin-Tak Leung
Cc: Larry Finger, John W. Linville, linux-wireless, linux-kernel,
lvc-project
Daniil Dulov <d.dulov@aladdin.ru> wrote:
> There is a potential data race between rtl8187_tx_cb() and rtl8187_stop().
> It is possible for rtl8187_stop() to clear the queue right after rtl8187_tx_cb()
> checks that queue has more than 5 elements, but before it dequeues any skb.
> This results in skb_dequeue() returns NULL and the pointer is dereferenced
> in ieee80211_tx_status_irqsafe().
Is there a way to flush rtl8187_tx_cb() before rtl8187_stop() clear queue?
It looks risky that rtl8187_tx_cb() can still be running after rtl8187_stop().
Maybe you only treat this patch as a workaround?
>
> BUG: kernel NULL pointer dereference, address: 0000000000000080
> #PF: supervisor read access in kernel mode
> #PF: error_code(0x0000) - not-present page
> PGD 0 P4D 0
> Oops: Oops: 0000 [#1] SMP NOPTI
> CPU: 7 UID: 0 PID: 0 Comm: swapper/7 Not tainted 6.15.0 #8 PREEMPT(voluntary)
> Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 0.0.0 02/06/2015
> RIP: 0010:ieee80211_tx_status_irqsafe+0x21/0xc0 [mac80211]
> Call Trace:
> <IRQ>
> rtl8187_tx_cb+0x116/0x150 [rtl8187]
> __usb_hcd_giveback_urb+0x9d/0x120
> usb_giveback_urb_bh+0xbb/0x140
> process_one_work+0x19b/0x3c0
> bh_worker+0x1a7/0x210
> tasklet_action+0x10/0x30
> handle_softirqs+0xf0/0x340
> __irq_exit_rcu+0xcd/0xf0
> common_interrupt+0x85/0xa0
> </IRQ>
>
> In order to avoid potential data races and leading dereference of a NULL
> pointer, acquire the queue lock before any work with the queue is done and
> replace all skb_* calls with their lockless versions.
>
> Found by Linux Verification Center (linuxtesting.org) with SVACE.
Do you have a real hardware and tested this patchset? If not, please mention
compile tested only in commit message.
>
> Fixes: 3517afdefc3a ("rtl8187: feedback transmitted packets using tx close descriptor for 8187B")
> Signed-off-by: Daniil Dulov <d.dulov@aladdin.ru>
> ---
> .../net/wireless/realtek/rtl818x/rtl8187/dev.c | 15 ++++++++++++---
> 1 file changed, 12 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
> b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
> index 220ac5bdf279..8fe6fdc32e56 100644
> --- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
> +++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
> @@ -189,6 +189,7 @@ static void rtl8187_tx_cb(struct urb *urb)
> struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
> struct ieee80211_hw *hw = info->rate_driver_data[0];
> struct rtl8187_priv *priv = hw->priv;
> + unsigned long flags;
>
> skb_pull(skb, priv->is_rtl8187b ? sizeof(struct rtl8187b_tx_hdr) :
> sizeof(struct rtl8187_tx_hdr));
> @@ -196,7 +197,8 @@ static void rtl8187_tx_cb(struct urb *urb)
>
> if (!(urb->status) && !(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
> if (priv->is_rtl8187b) {
> - skb_queue_tail(&priv->b_tx_status.queue, skb);
> + spin_lock_irqsave(&priv->b_tx_status.queue.lock, flags);
> + __skb_queue_tail(&priv->b_tx_status.queue, skb);
>
> /* queue is "full", discard last items */
> while (skb_queue_len(&priv->b_tx_status.queue) > 5) {
> @@ -205,9 +207,11 @@ static void rtl8187_tx_cb(struct urb *urb)
> dev_dbg(&priv->udev->dev,
> "transmit status queue full\n");
>
> - old_skb = skb_dequeue(&priv->b_tx_status.queue);
Another simple way could be just to check if old_skb is NULL here.
if (!old_skb)
break;
No need to adjust spin_lock.
> + old_skb = __skb_dequeue(&priv->b_tx_status.queue);
> ieee80211_tx_status_irqsafe(hw, old_skb);
> }
> +
> + spin_unlock_irqrestore(&priv->b_tx_status.queue.lock, flags);
> return;
> } else {
> info->flags |= IEEE80211_TX_STAT_ACK;
> @@ -893,6 +897,7 @@ static void rtl8187_work(struct work_struct *work)
> work.work);
> struct ieee80211_tx_info *info;
> struct ieee80211_hw *dev = priv->dev;
> + unsigned long flags;
> static u16 retry;
> u16 tmp;
> u16 avg_retry;
> @@ -900,6 +905,8 @@ static void rtl8187_work(struct work_struct *work)
>
> mutex_lock(&priv->conf_mutex);
> tmp = rtl818x_ioread16(priv, (__le16 *)0xFFFA);
> +
> + spin_lock_irqsave(&priv->b_tx_status.queue.lock, flags);
> length = skb_queue_len(&priv->b_tx_status.queue);
> if (unlikely(!length))
> length = 1;
> @@ -909,13 +916,15 @@ static void rtl8187_work(struct work_struct *work)
> while (skb_queue_len(&priv->b_tx_status.queue) > 0) {
> struct sk_buff *old_skb;
>
> - old_skb = skb_dequeue(&priv->b_tx_status.queue);
> + old_skb = __skb_dequeue(&priv->b_tx_status.queue);
And here as well.
if (!old_skb)
break;
> info = IEEE80211_SKB_CB(old_skb);
> info->status.rates[0].count = avg_retry + 1;
> if (info->status.rates[0].count > RETRY_COUNT)
> info->flags &= ~IEEE80211_TX_STAT_ACK;
> ieee80211_tx_status_irqsafe(dev, old_skb);
> }
> + spin_unlock_irqrestore(&priv->b_tx_status.queue.lock, flags);
> +
> retry = tmp;
> mutex_unlock(&priv->conf_mutex);
> }
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 6+ messages in thread
* RE: [PATCH 2/2] rtl818x: Kill URBs before clearing tx status queue
2025-06-16 10:10 ` [PATCH 2/2] rtl818x: Kill URBs before clearing tx status queue Daniil Dulov
@ 2025-06-17 1:18 ` Ping-Ke Shih
0 siblings, 0 replies; 6+ messages in thread
From: Ping-Ke Shih @ 2025-06-17 1:18 UTC (permalink / raw)
To: Daniil Dulov, Hin-Tak Leung
Cc: Larry Finger, John W. Linville, linux-wireless, linux-kernel,
lvc-project
Daniil Dulov <d.dulov@aladdin.ru> wrote:
> In rtl8187_stop() move the call of usb_kill_anchored_urbs() before clearing
> b_tx_status.queue. This change prevents callbacks from using already freed
> skb due to anchor was not killed before freeing such skb.
Oh. This is my question in patch 1/2. Seemingly, with this patch, it can
safely flush rtl8187_tx_cb() and stop, no? I mean just this one is enough,
no need patch 1/2.
>
> Found by Linux Verification Center (linuxtesting.org) with SVACE.
Same question as patch 1/2. Do you have a real hardware and test?
>
> Fixes: c1db52b9d27e ("rtl8187: Use usb anchor facilities to manage urbs")
> Signed-off-by: Daniil Dulov <d.dulov@aladdin.ru>
> ---
> drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
> b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
> index 8fe6fdc32e56..12e2042ee2d0 100644
> --- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
> +++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
> @@ -1050,10 +1050,10 @@ static void rtl8187_stop(struct ieee80211_hw *dev, bool suspend)
> rtl818x_iowrite8(priv, &priv->map->CONFIG4, reg | RTL818X_CONFIG4_VCOOFF);
> rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
>
> + usb_kill_anchored_urbs(&priv->anchored);
nit: an empty line.
> while ((skb = skb_dequeue(&priv->b_tx_status.queue)))
> dev_kfree_skb_any(skb);
>
> - usb_kill_anchored_urbs(&priv->anchored);
> mutex_unlock(&priv->conf_mutex);
>
> if (!priv->is_rtl8187b)
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 1/2] rtl818x: Fix potential data race in rtl8187_tx_cb()
2025-06-17 1:11 ` Ping-Ke Shih
@ 2025-06-17 12:41 ` Fedor Pchelkin
0 siblings, 0 replies; 6+ messages in thread
From: Fedor Pchelkin @ 2025-06-17 12:41 UTC (permalink / raw)
To: Ping-Ke Shih
Cc: Daniil Dulov, Hin-Tak Leung, lvc-project, linux-kernel,
linux-wireless, John W. Linville, Larry Finger
Hi,
We've worked with Daniil internally on the series so I'm chiming into
the thread..
On Tue, 17. Jun 01:11, Ping-Ke Shih wrote:
> Daniil Dulov <d.dulov@aladdin.ru> wrote:
> > There is a potential data race between rtl8187_tx_cb() and rtl8187_stop().
> > It is possible for rtl8187_stop() to clear the queue right after rtl8187_tx_cb()
> > checks that queue has more than 5 elements, but before it dequeues any skb.
> > This results in skb_dequeue() returns NULL and the pointer is dereferenced
> > in ieee80211_tx_status_irqsafe().
>
> Is there a way to flush rtl8187_tx_cb() before rtl8187_stop() clear queue?
> It looks risky that rtl8187_tx_cb() can still be running after rtl8187_stop().
> Maybe you only treat this patch as a workaround?
That's what the second patch does, yes.
I've probably found where we screwed this up and made the patch
description and the actual diff go out of sync, apologies.
The current one should've described that it's targeting a race between
rtl8187_tx_cb() and rtl8187_work().
Thread A Thread B
rtl8187_tx_cb()
while (skb_queue_len > 5) // OK
rtl8187_work()
while (skb_queue_len > 0)
skb_dequeue()
skb_dequeue() -> NULL
But giving this a second glance, it should be impossible because
rtl8187_tx_cb() dequeues elements only for is_rtl8187b case, and the
worker function is only scheduled for the non-is_rtl8187b case.
>
> >
> > BUG: kernel NULL pointer dereference, address: 0000000000000080
> > #PF: supervisor read access in kernel mode
> > #PF: error_code(0x0000) - not-present page
> > PGD 0 P4D 0
> > Oops: Oops: 0000 [#1] SMP NOPTI
> > CPU: 7 UID: 0 PID: 0 Comm: swapper/7 Not tainted 6.15.0 #8 PREEMPT(voluntary)
> > Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 0.0.0 02/06/2015
> > RIP: 0010:ieee80211_tx_status_irqsafe+0x21/0xc0 [mac80211]
> > Call Trace:
> > <IRQ>
> > rtl8187_tx_cb+0x116/0x150 [rtl8187]
> > __usb_hcd_giveback_urb+0x9d/0x120
> > usb_giveback_urb_bh+0xbb/0x140
> > process_one_work+0x19b/0x3c0
> > bh_worker+0x1a7/0x210
> > tasklet_action+0x10/0x30
> > handle_softirqs+0xf0/0x340
> > __irq_exit_rcu+0xcd/0xf0
> > common_interrupt+0x85/0xa0
> > </IRQ>
> >
> > In order to avoid potential data races and leading dereference of a NULL
> > pointer, acquire the queue lock before any work with the queue is done and
> > replace all skb_* calls with their lockless versions.
> >
> > Found by Linux Verification Center (linuxtesting.org) with SVACE.
>
> Do you have a real hardware and tested this patchset? If not, please mention
> compile tested only in commit message.
Yes, the crash above was observed with our RTL8187BvE device and, urgh,
it actually concerns the root cause fixed by the second patch. The changes
were tested for regressions with debug-enabled kernel and basic
throughput checks.
Thank you for review and comments!
Adding skb_dequeue() return value checks here, as now clarified, should
then be considered only as improvement. We understand that proposing such
kind of stuff for old stable drivers is just churn so I think we'd better
go only with the second patch of the series since it entirely eliminates
the real problem. We'll repost it.
>
> >
> > Fixes: 3517afdefc3a ("rtl8187: feedback transmitted packets using tx close descriptor for 8187B")
> > Signed-off-by: Daniil Dulov <d.dulov@aladdin.ru>
> > ---
> > .../net/wireless/realtek/rtl818x/rtl8187/dev.c | 15 ++++++++++++---
> > 1 file changed, 12 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
> > b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
> > index 220ac5bdf279..8fe6fdc32e56 100644
> > --- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
> > +++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
> > @@ -189,6 +189,7 @@ static void rtl8187_tx_cb(struct urb *urb)
> > struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
> > struct ieee80211_hw *hw = info->rate_driver_data[0];
> > struct rtl8187_priv *priv = hw->priv;
> > + unsigned long flags;
> >
> > skb_pull(skb, priv->is_rtl8187b ? sizeof(struct rtl8187b_tx_hdr) :
> > sizeof(struct rtl8187_tx_hdr));
> > @@ -196,7 +197,8 @@ static void rtl8187_tx_cb(struct urb *urb)
> >
> > if (!(urb->status) && !(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
> > if (priv->is_rtl8187b) {
> > - skb_queue_tail(&priv->b_tx_status.queue, skb);
> > + spin_lock_irqsave(&priv->b_tx_status.queue.lock, flags);
> > + __skb_queue_tail(&priv->b_tx_status.queue, skb);
> >
> > /* queue is "full", discard last items */
> > while (skb_queue_len(&priv->b_tx_status.queue) > 5) {
> > @@ -205,9 +207,11 @@ static void rtl8187_tx_cb(struct urb *urb)
> > dev_dbg(&priv->udev->dev,
> > "transmit status queue full\n");
> >
> > - old_skb = skb_dequeue(&priv->b_tx_status.queue);
>
> Another simple way could be just to check if old_skb is NULL here.
>
> if (!old_skb)
> break;
>
> No need to adjust spin_lock.
>
> > + old_skb = __skb_dequeue(&priv->b_tx_status.queue);
> > ieee80211_tx_status_irqsafe(hw, old_skb);
> > }
> > +
> > + spin_unlock_irqrestore(&priv->b_tx_status.queue.lock, flags);
> > return;
> > } else {
> > info->flags |= IEEE80211_TX_STAT_ACK;
> > @@ -893,6 +897,7 @@ static void rtl8187_work(struct work_struct *work)
> > work.work);
> > struct ieee80211_tx_info *info;
> > struct ieee80211_hw *dev = priv->dev;
> > + unsigned long flags;
> > static u16 retry;
> > u16 tmp;
> > u16 avg_retry;
> > @@ -900,6 +905,8 @@ static void rtl8187_work(struct work_struct *work)
> >
> > mutex_lock(&priv->conf_mutex);
> > tmp = rtl818x_ioread16(priv, (__le16 *)0xFFFA);
> > +
> > + spin_lock_irqsave(&priv->b_tx_status.queue.lock, flags);
> > length = skb_queue_len(&priv->b_tx_status.queue);
> > if (unlikely(!length))
> > length = 1;
> > @@ -909,13 +916,15 @@ static void rtl8187_work(struct work_struct *work)
> > while (skb_queue_len(&priv->b_tx_status.queue) > 0) {
> > struct sk_buff *old_skb;
> >
> > - old_skb = skb_dequeue(&priv->b_tx_status.queue);
> > + old_skb = __skb_dequeue(&priv->b_tx_status.queue);
>
> And here as well.
>
> if (!old_skb)
> break;
>
> > info = IEEE80211_SKB_CB(old_skb);
> > info->status.rates[0].count = avg_retry + 1;
> > if (info->status.rates[0].count > RETRY_COUNT)
> > info->flags &= ~IEEE80211_TX_STAT_ACK;
> > ieee80211_tx_status_irqsafe(dev, old_skb);
> > }
> > + spin_unlock_irqrestore(&priv->b_tx_status.queue.lock, flags);
> > +
> > retry = tmp;
> > mutex_unlock(&priv->conf_mutex);
> > }
> > --
> > 2.34.1
> >
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2025-06-17 12:41 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-06-16 10:10 [PATCH 0/2] rtl818x: enhance skb/urb management Daniil Dulov
2025-06-16 10:10 ` [PATCH 1/2] rtl818x: Fix potential data race in rtl8187_tx_cb() Daniil Dulov
2025-06-17 1:11 ` Ping-Ke Shih
2025-06-17 12:41 ` Fedor Pchelkin
2025-06-16 10:10 ` [PATCH 2/2] rtl818x: Kill URBs before clearing tx status queue Daniil Dulov
2025-06-17 1:18 ` Ping-Ke Shih
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®