Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mac80211: calculate hash for fq without holding fq->lock in itxq enqueue

Reduces lock contention on enqueue/dequeue of iTXQ packets

Signed-off-by: Felix Fietkau <nbd@nbd.name>
Acked-by: Toke Høiland-Jørgensen <toke@redhat.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>

authored by

Felix Fietkau and committed by
Johannes Berg
f2af2df8 ef618b1b

+20 -13
+10 -8
include/net/fq_impl.h
··· 107 107 return skb; 108 108 } 109 109 110 + static u32 fq_flow_idx(struct fq *fq, struct sk_buff *skb) 111 + { 112 + u32 hash = skb_get_hash_perturb(skb, fq->perturbation); 113 + 114 + return reciprocal_scale(hash, fq->flows_cnt); 115 + } 116 + 110 117 static struct fq_flow *fq_flow_classify(struct fq *fq, 111 - struct fq_tin *tin, 118 + struct fq_tin *tin, u32 idx, 112 119 struct sk_buff *skb, 113 120 fq_flow_get_default_t get_default_func) 114 121 { 115 122 struct fq_flow *flow; 116 - u32 hash; 117 - u32 idx; 118 123 119 124 lockdep_assert_held(&fq->lock); 120 125 121 - hash = skb_get_hash_perturb(skb, fq->perturbation); 122 - idx = reciprocal_scale(hash, fq->flows_cnt); 123 126 flow = &fq->flows[idx]; 124 - 125 127 if (flow->tin && flow->tin != tin) { 126 128 flow = get_default_func(fq, tin, idx, skb); 127 129 tin->collisions++; ··· 155 153 } 156 154 157 155 static void fq_tin_enqueue(struct fq *fq, 158 - struct fq_tin *tin, 156 + struct fq_tin *tin, u32 idx, 159 157 struct sk_buff *skb, 160 158 fq_skb_free_t free_func, 161 159 fq_flow_get_default_t get_default_func) ··· 165 163 166 164 lockdep_assert_held(&fq->lock); 167 165 168 - flow = fq_flow_classify(fq, tin, skb, get_default_func); 166 + flow = fq_flow_classify(fq, tin, idx, skb, get_default_func); 169 167 170 168 flow->tin = tin; 171 169 flow->backlog += skb->len;
+10 -5
net/mac80211/tx.c
··· 1399 1399 { 1400 1400 struct fq *fq = &local->fq; 1401 1401 struct fq_tin *tin = &txqi->tin; 1402 + u32 flow_idx = fq_flow_idx(fq, skb); 1402 1403 1403 1404 ieee80211_set_skb_enqueue_time(skb); 1404 - fq_tin_enqueue(fq, tin, skb, 1405 + 1406 + spin_lock_bh(&fq->lock); 1407 + fq_tin_enqueue(fq, tin, flow_idx, skb, 1405 1408 fq_skb_free_func, 1406 1409 fq_flow_get_default_func); 1410 + spin_unlock_bh(&fq->lock); 1407 1411 } 1408 1412 1409 1413 static bool fq_vlan_filter_func(struct fq *fq, struct fq_tin *tin, ··· 1594 1590 struct sta_info *sta, 1595 1591 struct sk_buff *skb) 1596 1592 { 1597 - struct fq *fq = &local->fq; 1598 1593 struct ieee80211_vif *vif; 1599 1594 struct txq_info *txqi; 1600 1595 ··· 1611 1608 if (!txqi) 1612 1609 return false; 1613 1610 1614 - spin_lock_bh(&fq->lock); 1615 1611 ieee80211_txq_enqueue(local, txqi, skb); 1616 - spin_unlock_bh(&fq->lock); 1617 1612 1618 1613 schedule_and_wake_txq(local, txqi); 1619 1614 ··· 3222 3221 u8 max_subframes = sta->sta.max_amsdu_subframes; 3223 3222 int max_frags = local->hw.max_tx_fragments; 3224 3223 int max_amsdu_len = sta->sta.max_amsdu_len; 3224 + u32 flow_idx; 3225 3225 __be16 len; 3226 3226 void *data; 3227 3227 bool ret = false; ··· 3251 3249 max_amsdu_len = min_t(int, max_amsdu_len, 3252 3250 sta->sta.max_tid_amsdu_len[tid]); 3253 3251 3252 + flow_idx = fq_flow_idx(fq, skb); 3253 + 3254 3254 spin_lock_bh(&fq->lock); 3255 3255 3256 3256 /* TODO: Ideally aggregation should be done on dequeue to remain ··· 3260 3256 */ 3261 3257 3262 3258 tin = &txqi->tin; 3263 - flow = fq_flow_classify(fq, tin, skb, fq_flow_get_default_func); 3259 + flow = fq_flow_classify(fq, tin, flow_idx, skb, 3260 + fq_flow_get_default_func); 3264 3261 head = skb_peek_tail(&flow->queue); 3265 3262 if (!head || skb_is_gso(head)) 3266 3263 goto out;