Message ID | 20240704174756.1225995-1-rwahl@gmx.de (mailing list archive) |
---|---|
State | Superseded |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | [v2] net: ks8851: Fix deadlock with the SPI chip variant | expand |
On Thu, 4 Jul 2024 19:47:56 +0200 Ronald Wahl wrote: > --- a/drivers/net/ethernet/micrel/ks8851_spi.c > +++ b/drivers/net/ethernet/micrel/ks8851_spi.c > @@ -385,7 +385,7 @@ static netdev_tx_t ks8851_start_xmit_spi(struct sk_buff *skb, > netif_dbg(ks, tx_queued, ks->netdev, > "%s: skb %p, %d@%p\n", __func__, skb, skb->len, skb->data); > > - spin_lock(&ks->statelock); > + spin_lock_bh(&ks->statelock); > > if (ks->queued_len + needed > ks->tx_space) { > netif_stop_queue(dev); > @@ -395,7 +395,7 @@ static netdev_tx_t ks8851_start_xmit_spi(struct sk_buff *skb, > skb_queue_tail(&ks->txq, skb); > } > > - spin_unlock(&ks->statelock); > + spin_unlock_bh(&ks->statelock); this one probably can stay as spin_lock() since networking stack only calls xmit in BH context. But I see 2 other spin_lock(statelock) in the driver which I'm not as sure about. Any taking of this lock has to be _bh() unless you're sure the caller is already in BH.
On 06.07.24 02:39, Jakub Kicinski wrote: > On Thu, 4 Jul 2024 19:47:56 +0200 Ronald Wahl wrote: >> --- a/drivers/net/ethernet/micrel/ks8851_spi.c >> +++ b/drivers/net/ethernet/micrel/ks8851_spi.c >> @@ -385,7 +385,7 @@ static netdev_tx_t ks8851_start_xmit_spi(struct sk_buff *skb, >> netif_dbg(ks, tx_queued, ks->netdev, >> "%s: skb %p, %d@%p\n", __func__, skb, skb->len, skb->data); >> >> - spin_lock(&ks->statelock); >> + spin_lock_bh(&ks->statelock); >> >> if (ks->queued_len + needed > ks->tx_space) { >> netif_stop_queue(dev); >> @@ -395,7 +395,7 @@ static netdev_tx_t ks8851_start_xmit_spi(struct sk_buff *skb, >> skb_queue_tail(&ks->txq, skb); >> } >> >> - spin_unlock(&ks->statelock); >> + spin_unlock_bh(&ks->statelock); > > this one probably can stay as spin_lock() since networking stack only > calls xmit in BH context. I already suspected this it was more a mental hint here. I will remove it. > But I see 2 other spin_lock(statelock) in the > driver which I'm not as sure about. Any taking of this lock has to be > _bh() unless you're sure the caller is already in BH. The other two instances are not in BH context as far as I know but also do not interfere with BH. The one in ks8861_tx_work protects only variable assignments used only inside the driver and the one in ks8851_set_rx_mode also only does some driver local variable stuff and a schedule_work which as far as I know has nothing to do with BH because workqueues are running in process context. Am I wrong here? - ron
On 06.07.24 10:38, Ronald Wahl wrote: > On 06.07.24 02:39, Jakub Kicinski wrote: >> On Thu, 4 Jul 2024 19:47:56 +0200 Ronald Wahl wrote: >>> --- a/drivers/net/ethernet/micrel/ks8851_spi.c >>> +++ b/drivers/net/ethernet/micrel/ks8851_spi.c >>> @@ -385,7 +385,7 @@ static netdev_tx_t ks8851_start_xmit_spi(struct >>> sk_buff *skb, >>> netif_dbg(ks, tx_queued, ks->netdev, >>> "%s: skb %p, %d@%p\n", __func__, skb, skb->len, skb->data); >>> >>> - spin_lock(&ks->statelock); >>> + spin_lock_bh(&ks->statelock); >>> >>> if (ks->queued_len + needed > ks->tx_space) { >>> netif_stop_queue(dev); >>> @@ -395,7 +395,7 @@ static netdev_tx_t ks8851_start_xmit_spi(struct >>> sk_buff *skb, >>> skb_queue_tail(&ks->txq, skb); >>> } >>> >>> - spin_unlock(&ks->statelock); >>> + spin_unlock_bh(&ks->statelock); >> >> this one probably can stay as spin_lock() since networking stack only >> calls xmit in BH context. > > I already suspected this it was more a mental hint here. I will remove it. > >> But I see 2 other spin_lock(statelock) in the >> driver which I'm not as sure about. Any taking of this lock has to be >> _bh() unless you're sure the caller is already in BH. > > The other two instances are not in BH context as far as I know but also > do not interfere with BH. The one in ks8861_tx_work protects only > variable assignments used only inside the driver and the one in > ks8851_set_rx_mode also only does some driver local variable stuff and a > schedule_work which as far as I know has nothing to do with BH because > workqueues are running in process context. Am I wrong here? I guess I found a misunderstanding on my side: I was assuming that a softirq cannot asynchronously interrupt a spin lock protected section. Maybe this is wrong. In the one place where I'm waking the queue again the spin_lock_bh avoids synchronously triggering the BH processing while still holding a spinlock. I will use the _bh variants on the two other places. - ron
On Sat, Jul 06, 2024 at 11:22:11AM +0200, Ronald Wahl wrote: > This e-mail, and any document attached hereby, may contain confidential and/or privileged information. If you are not the intended recipient (or have received this e-mail in error) please notify the sender immediately and destroy this e-mail. Any unauthorized, direct or indirect, copying, disclosure, distribution or other use of the material or parts thereof is strictly forbidden. > Now deleted
diff --git a/drivers/net/ethernet/micrel/ks8851_common.c b/drivers/net/ethernet/micrel/ks8851_common.c index 6453c92f0fa7..51fb6c27153e 100644 --- a/drivers/net/ethernet/micrel/ks8851_common.c +++ b/drivers/net/ethernet/micrel/ks8851_common.c @@ -352,11 +352,11 @@ static irqreturn_t ks8851_irq(int irq, void *_ks) netif_dbg(ks, intr, ks->netdev, "%s: txspace %d\n", __func__, tx_space); - spin_lock(&ks->statelock); + spin_lock_bh(&ks->statelock); ks->tx_space = tx_space; if (netif_queue_stopped(ks->netdev)) netif_wake_queue(ks->netdev); - spin_unlock(&ks->statelock); + spin_unlock_bh(&ks->statelock); } if (status & IRQ_SPIBEI) { diff --git a/drivers/net/ethernet/micrel/ks8851_spi.c b/drivers/net/ethernet/micrel/ks8851_spi.c index 670c1de966db..818e1ce3227b 100644 --- a/drivers/net/ethernet/micrel/ks8851_spi.c +++ b/drivers/net/ethernet/micrel/ks8851_spi.c @@ -385,7 +385,7 @@ static netdev_tx_t ks8851_start_xmit_spi(struct sk_buff *skb, netif_dbg(ks, tx_queued, ks->netdev, "%s: skb %p, %d@%p\n", __func__, skb, skb->len, skb->data); - spin_lock(&ks->statelock); + spin_lock_bh(&ks->statelock); if (ks->queued_len + needed > ks->tx_space) { netif_stop_queue(dev); @@ -395,7 +395,7 @@ static netdev_tx_t ks8851_start_xmit_spi(struct sk_buff *skb, skb_queue_tail(&ks->txq, skb); } - spin_unlock(&ks->statelock); + spin_unlock_bh(&ks->statelock); if (ret == NETDEV_TX_OK) schedule_work(&kss->tx_work);