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:
jiad
2017-08-04 11:59:20 +08:00
committato da snandini
parent d13036f3f7
commit 5b98663690

Vedi File

@@ -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
* @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++) {
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);
}
}
}
}