qcacld-3.0: Fix potential spinlock recursion on UP
wlan_hdd_update_txq_timestamp tries to grab txq spinlock in __dev_queue_xmit context. Issue is txq spinlock is already held before calling into driver's ndo_start_xmit callback. On UP system, kernel throws a BUG and system crashes. Fix is to detect spinlock recursion and only tries to grab the lock when it is not held on the same CPU or not held. Change-Id: I3956ef00c4f4a563155dc82ed8f95f097129fb0c CRs-Fixed: 2050134
This commit is contained in:
@@ -1364,6 +1364,27 @@ static void wlan_hdd_update_queue_oper_stats(hdd_adapter_t *adapter,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hdd_netdev_queue_is_locked()
|
||||||
|
* @txq: net device tx queue
|
||||||
|
*
|
||||||
|
* For SMP system, always return false and we could safely rely on
|
||||||
|
* __netif_tx_trylock().
|
||||||
|
*
|
||||||
|
* Return: true locked; false not locked
|
||||||
|
*/
|
||||||
|
#ifdef QCA_CONFIG_SMP
|
||||||
|
static inline bool hdd_netdev_queue_is_locked(struct netdev_queue *txq)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static inline bool hdd_netdev_queue_is_locked(struct netdev_queue *txq)
|
||||||
|
{
|
||||||
|
return txq->xmit_lock_owner != -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* wlan_hdd_update_txq_timestamp() - update txq timestamp
|
* wlan_hdd_update_txq_timestamp() - update txq timestamp
|
||||||
* @dev: net device
|
* @dev: net device
|
||||||
@@ -1377,9 +1398,19 @@ static void wlan_hdd_update_txq_timestamp(struct net_device *dev)
|
|||||||
|
|
||||||
for (i = 0; i < NUM_TX_QUEUES; i++) {
|
for (i = 0; i < NUM_TX_QUEUES; i++) {
|
||||||
txq = netdev_get_tx_queue(dev, i);
|
txq = netdev_get_tx_queue(dev, i);
|
||||||
if (__netif_tx_trylock(txq)) {
|
|
||||||
txq_trans_update(txq);
|
/*
|
||||||
__netif_tx_unlock(txq);
|
* On UP system, kernel will trigger watchdog bite if spinlock
|
||||||
|
* recursion is detected. Unfortunately recursion is possible
|
||||||
|
* when it is called in dev_queue_xmit() context, where stack
|
||||||
|
* grabs the lock before calling driver's ndo_start_xmit
|
||||||
|
* callback.
|
||||||
|
*/
|
||||||
|
if (!hdd_netdev_queue_is_locked(txq)) {
|
||||||
|
if (__netif_tx_trylock(txq)) {
|
||||||
|
txq_trans_update(txq);
|
||||||
|
__netif_tx_unlock(txq);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user