Przeglądaj źródła

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
jiad 7 lat temu
rodzic
commit
5b98663690
1 zmienionych plików z 34 dodań i 3 usunięć
  1. 34 3
      core/hdd/src/wlan_hdd_tx_rx.c

+ 34 - 3
core/hdd/src/wlan_hdd_tx_rx.c

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