352-mac80211-rework-locking-for-txq-scheduling-airtime-f.patch 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. From: Felix Fietkau <nbd@nbd.name>
  2. Date: Wed, 13 Mar 2019 19:09:22 +0100
  3. Subject: [PATCH] mac80211: rework locking for txq scheduling / airtime
  4. fairness
  5. Holding the lock around the entire duration of tx scheduling can create
  6. some nasty lock contention, especially when processing airtime information
  7. from the tx status or the rx path.
  8. Improve locking by only holding the active_txq_lock for lookups / scheduling
  9. list modifications.
  10. Signed-off-by: Felix Fietkau <nbd@nbd.name>
  11. ---
  12. --- a/include/net/mac80211.h
  13. +++ b/include/net/mac80211.h
  14. @@ -6069,8 +6069,6 @@ struct sk_buff *ieee80211_tx_dequeue(str
  15. * @hw: pointer as obtained from ieee80211_alloc_hw()
  16. * @ac: AC number to return packets from.
  17. *
  18. - * Should only be called between calls to ieee80211_txq_schedule_start()
  19. - * and ieee80211_txq_schedule_end().
  20. * Returns the next txq if successful, %NULL if no queue is eligible. If a txq
  21. * is returned, it should be returned with ieee80211_return_txq() after the
  22. * driver has finished scheduling it.
  23. @@ -6078,51 +6076,41 @@ struct sk_buff *ieee80211_tx_dequeue(str
  24. struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac);
  25. /**
  26. - * ieee80211_return_txq - return a TXQ previously acquired by ieee80211_next_txq()
  27. - *
  28. - * @hw: pointer as obtained from ieee80211_alloc_hw()
  29. - * @txq: pointer obtained from station or virtual interface
  30. - *
  31. - * Should only be called between calls to ieee80211_txq_schedule_start()
  32. - * and ieee80211_txq_schedule_end().
  33. - */
  34. -void ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq);
  35. -
  36. -/**
  37. - * ieee80211_txq_schedule_start - acquire locks for safe scheduling of an AC
  38. + * ieee80211_txq_schedule_start - start new scheduling round for TXQs
  39. *
  40. * @hw: pointer as obtained from ieee80211_alloc_hw()
  41. * @ac: AC number to acquire locks for
  42. *
  43. - * Acquire locks needed to schedule TXQs from the given AC. Should be called
  44. - * before ieee80211_next_txq() or ieee80211_return_txq().
  45. + * Should be called before ieee80211_next_txq() or ieee80211_return_txq().
  46. */
  47. -void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac)
  48. - __acquires(txq_lock);
  49. +void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac);
  50. +
  51. +/* (deprecated) */
  52. +static inline void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac)
  53. +{
  54. +}
  55. /**
  56. - * ieee80211_txq_schedule_end - release locks for safe scheduling of an AC
  57. + * ieee80211_schedule_txq - schedule a TXQ for transmission
  58. *
  59. * @hw: pointer as obtained from ieee80211_alloc_hw()
  60. - * @ac: AC number to acquire locks for
  61. + * @txq: pointer obtained from station or virtual interface
  62. *
  63. - * Release locks previously acquired by ieee80211_txq_schedule_end().
  64. + * Schedules a TXQ for transmission if it is not already scheduled.
  65. */
  66. -void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac)
  67. - __releases(txq_lock);
  68. +void ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq);
  69. /**
  70. - * ieee80211_schedule_txq - schedule a TXQ for transmission
  71. + * ieee80211_return_txq - return a TXQ previously acquired by ieee80211_next_txq()
  72. *
  73. * @hw: pointer as obtained from ieee80211_alloc_hw()
  74. * @txq: pointer obtained from station or virtual interface
  75. - *
  76. - * Schedules a TXQ for transmission if it is not already scheduled. Takes a
  77. - * lock, which means it must *not* be called between
  78. - * ieee80211_txq_schedule_start() and ieee80211_txq_schedule_end()
  79. */
  80. -void ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
  81. - __acquires(txq_lock) __releases(txq_lock);
  82. +static inline void
  83. +ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
  84. +{
  85. + ieee80211_schedule_txq(hw, txq);
  86. +}
  87. /**
  88. * ieee80211_txq_may_transmit - check whether TXQ is allowed to transmit
  89. --- a/net/mac80211/tx.c
  90. +++ b/net/mac80211/tx.c
  91. @@ -3637,16 +3637,17 @@ EXPORT_SYMBOL(ieee80211_tx_dequeue);
  92. struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac)
  93. {
  94. struct ieee80211_local *local = hw_to_local(hw);
  95. + struct ieee80211_txq *ret = NULL;
  96. struct txq_info *txqi = NULL;
  97. - lockdep_assert_held(&local->active_txq_lock[ac]);
  98. + spin_lock_bh(&local->active_txq_lock[ac]);
  99. begin:
  100. txqi = list_first_entry_or_null(&local->active_txqs[ac],
  101. struct txq_info,
  102. schedule_order);
  103. if (!txqi)
  104. - return NULL;
  105. + goto out;
  106. if (txqi->txq.sta) {
  107. struct sta_info *sta = container_of(txqi->txq.sta,
  108. @@ -3663,21 +3664,25 @@ struct ieee80211_txq *ieee80211_next_txq
  109. if (txqi->schedule_round == local->schedule_round[ac])
  110. - return NULL;
  111. + goto out;
  112. list_del_init(&txqi->schedule_order);
  113. txqi->schedule_round = local->schedule_round[ac];
  114. - return &txqi->txq;
  115. + ret = &txqi->txq;
  116. +
  117. +out:
  118. + spin_unlock_bh(&local->active_txq_lock[ac]);
  119. + return ret;
  120. }
  121. EXPORT_SYMBOL(ieee80211_next_txq);
  122. -void ieee80211_return_txq(struct ieee80211_hw *hw,
  123. - struct ieee80211_txq *txq)
  124. +void ieee80211_schedule_txq(struct ieee80211_hw *hw,
  125. + struct ieee80211_txq *txq)
  126. {
  127. struct ieee80211_local *local = hw_to_local(hw);
  128. struct txq_info *txqi = to_txq_info(txq);
  129. - lockdep_assert_held(&local->active_txq_lock[txq->ac]);
  130. + spin_lock_bh(&local->active_txq_lock[txq->ac]);
  131. if (list_empty(&txqi->schedule_order) &&
  132. (!skb_queue_empty(&txqi->frags) || txqi->tin.backlog_packets)) {
  133. @@ -3697,18 +3702,7 @@ void ieee80211_return_txq(struct ieee802
  134. list_add_tail(&txqi->schedule_order,
  135. &local->active_txqs[txq->ac]);
  136. }
  137. -}
  138. -EXPORT_SYMBOL(ieee80211_return_txq);
  139. -void ieee80211_schedule_txq(struct ieee80211_hw *hw,
  140. - struct ieee80211_txq *txq)
  141. - __acquires(txq_lock) __releases(txq_lock)
  142. -{
  143. - struct ieee80211_local *local = hw_to_local(hw);
  144. - struct txq_info *txqi = to_txq_info(txq);
  145. -
  146. - spin_lock_bh(&local->active_txq_lock[txq->ac]);
  147. - ieee80211_return_txq(hw, txq);
  148. spin_unlock_bh(&local->active_txq_lock[txq->ac]);
  149. }
  150. EXPORT_SYMBOL(ieee80211_schedule_txq);
  151. @@ -3721,7 +3715,7 @@ bool ieee80211_txq_may_transmit(struct i
  152. struct sta_info *sta;
  153. u8 ac = txq->ac;
  154. - lockdep_assert_held(&local->active_txq_lock[ac]);
  155. + spin_lock_bh(&local->active_txq_lock[ac]);
  156. if (!txqi->txq.sta)
  157. goto out;
  158. @@ -3751,34 +3745,27 @@ bool ieee80211_txq_may_transmit(struct i
  159. sta->airtime[ac].deficit += sta->airtime_weight;
  160. list_move_tail(&txqi->schedule_order, &local->active_txqs[ac]);
  161. + spin_unlock_bh(&local->active_txq_lock[ac]);
  162. return false;
  163. out:
  164. if (!list_empty(&txqi->schedule_order))
  165. list_del_init(&txqi->schedule_order);
  166. + spin_unlock_bh(&local->active_txq_lock[ac]);
  167. return true;
  168. }
  169. EXPORT_SYMBOL(ieee80211_txq_may_transmit);
  170. void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac)
  171. - __acquires(txq_lock)
  172. {
  173. struct ieee80211_local *local = hw_to_local(hw);
  174. spin_lock_bh(&local->active_txq_lock[ac]);
  175. local->schedule_round[ac]++;
  176. -}
  177. -EXPORT_SYMBOL(ieee80211_txq_schedule_start);
  178. -
  179. -void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac)
  180. - __releases(txq_lock)
  181. -{
  182. - struct ieee80211_local *local = hw_to_local(hw);
  183. -
  184. spin_unlock_bh(&local->active_txq_lock[ac]);
  185. }
  186. -EXPORT_SYMBOL(ieee80211_txq_schedule_end);
  187. +EXPORT_SYMBOL(ieee80211_txq_schedule_start);
  188. void __ieee80211_subif_start_xmit(struct sk_buff *skb,
  189. struct net_device *dev,