Skip to content

Commit

Permalink
[PATCH] prism54: fix potential race in reset scheduling
Browse files Browse the repository at this point in the history
NET: prism54 - fix potential race in reset scheduling

There appears to be a race in reset scheduling logic - thread
responsible for reseting the interface should clear "reset
pending" flag before restarting the queue, otherwise timeout
handler might not schedule another reset even if it is needed.

This race is mostly theoretical as far as I can see but a race
nonetheless.

Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Dmitry Torokhov authored and Jeff Garzik committed Dec 2, 2006
1 parent 5c877fe commit d18e0c4
Showing 1 changed file with 13 additions and 10 deletions.
23 changes: 13 additions & 10 deletions drivers/net/wireless/prism54/islpci_eth.c
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ islpci_monitor_rx(islpci_private *priv, struct sk_buff **skb)
* header and without the FCS. But there a is a bit that
* indicates if the packet is corrupted :-) */
struct rfmon_header *hdr = (struct rfmon_header *) (*skb)->data;

if (hdr->flags & 0x01)
/* This one is bad. Drop it ! */
return -1;
Expand Down Expand Up @@ -464,10 +465,8 @@ islpci_eth_receive(islpci_private *priv)
break;
}
/* update the fragment address */
control_block->rx_data_low[index].address = cpu_to_le32((u32)
priv->
pci_map_rx_address
[index]);
control_block->rx_data_low[index].address =
cpu_to_le32((u32)priv->pci_map_rx_address[index]);
wmb();

/* increment the driver read pointer */
Expand All @@ -484,10 +483,12 @@ islpci_eth_receive(islpci_private *priv)
void
islpci_do_reset_and_wake(void *data)
{
islpci_private *priv = (islpci_private *) data;
islpci_private *priv = data;

islpci_reset(priv, 1);
netif_wake_queue(priv->ndev);
priv->reset_task_pending = 0;
smp_wmb();
netif_wake_queue(priv->ndev);
}

void
Expand All @@ -499,12 +500,14 @@ islpci_eth_tx_timeout(struct net_device *ndev)
/* increment the transmit error counter */
statistics->tx_errors++;

printk(KERN_WARNING "%s: tx_timeout", ndev->name);
if (!priv->reset_task_pending) {
priv->reset_task_pending = 1;
printk(", scheduling a reset");
printk(KERN_WARNING
"%s: tx_timeout, scheduling reset", ndev->name);
netif_stop_queue(ndev);
priv->reset_task_pending = 1;
schedule_work(&priv->reset_task);
} else {
printk(KERN_WARNING
"%s: tx_timeout, waiting for reset", ndev->name);
}
printk("\n");
}

0 comments on commit d18e0c4

Please sign in to comment.