summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorSabrina Dubroca <sd@queasysnail.net>2018-11-29 08:14:49 -0500
committerDavid S. Miller <davem@davemloft.net>2018-11-29 14:06:08 -0500
commit867d0ad476db89a1e8af3f297af402399a54eea5 (patch)
tree075055a7fd00fe41bc76ba070136c7765cf282c6 /net
parentf28c020fb488e1a8b87469812017044bef88aa2b (diff)
net: fix XPS static_key accounting
Commit 04157469b7b8 ("net: Use static_key for XPS maps") introduced a static key for XPS, but the increments/decrements don't match. First, the static key's counter is incremented once for each queue, but only decremented once for a whole batch of queues, leading to large unbalances. Second, the xps_rxqs_needed key is decremented whenever we reset a batch of queues, whether they had any rxqs mapping or not, so that if we setup cpu-XPS on em1 and RXQS-XPS on em2, resetting the queues on em1 would decrement the xps_rxqs_needed key. This reworks the accounting scheme so that the xps_needed key is incremented only once for each type of XPS for all the queues on a device, and the xps_rxqs_needed key is incremented only once for all queues. This is sufficient to let us retrieve queues via get_xps_queue(). This patch introduces a new reset_xps_maps(), which reinitializes and frees the appropriate map (xps_rxqs_map or xps_cpus_map), and drops a reference to the needed keys: - both xps_needed and xps_rxqs_needed, in case of rxqs maps, - only xps_needed, in case of CPU maps. Now, we also need to call reset_xps_maps() at the end of __netif_set_xps_queue() when there's no active map left, for example when writing '00000000,00000000' to all queues' xps_rxqs setting. Fixes: 04157469b7b8 ("net: Use static_key for XPS maps") Signed-off-by: Sabrina Dubroca <sd@queasysnail.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/core/dev.c45
1 files changed, 24 insertions, 21 deletions
diff --git a/net/core/dev.c b/net/core/dev.c
index 32a63f4c3a92..3470e7fff1f4 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2175,6 +2175,20 @@ static bool remove_xps_queue_cpu(struct net_device *dev,
2175 return active; 2175 return active;
2176} 2176}
2177 2177
2178static void reset_xps_maps(struct net_device *dev,
2179 struct xps_dev_maps *dev_maps,
2180 bool is_rxqs_map)
2181{
2182 if (is_rxqs_map) {
2183 static_key_slow_dec_cpuslocked(&xps_rxqs_needed);
2184 RCU_INIT_POINTER(dev->xps_rxqs_map, NULL);
2185 } else {
2186 RCU_INIT_POINTER(dev->xps_cpus_map, NULL);
2187 }
2188 static_key_slow_dec_cpuslocked(&xps_needed);
2189 kfree_rcu(dev_maps, rcu);
2190}
2191
2178static void clean_xps_maps(struct net_device *dev, const unsigned long *mask, 2192static void clean_xps_maps(struct net_device *dev, const unsigned long *mask,
2179 struct xps_dev_maps *dev_maps, unsigned int nr_ids, 2193 struct xps_dev_maps *dev_maps, unsigned int nr_ids,
2180 u16 offset, u16 count, bool is_rxqs_map) 2194 u16 offset, u16 count, bool is_rxqs_map)
@@ -2186,13 +2200,8 @@ static void clean_xps_maps(struct net_device *dev, const unsigned long *mask,
2186 j < nr_ids;) 2200 j < nr_ids;)
2187 active |= remove_xps_queue_cpu(dev, dev_maps, j, offset, 2201 active |= remove_xps_queue_cpu(dev, dev_maps, j, offset,
2188 count); 2202 count);
2189 if (!active) { 2203 if (!active)
2190 if (is_rxqs_map) 2204 reset_xps_maps(dev, dev_maps, is_rxqs_map);
2191 RCU_INIT_POINTER(dev->xps_rxqs_map, NULL);
2192 else
2193 RCU_INIT_POINTER(dev->xps_cpus_map, NULL);
2194 kfree_rcu(dev_maps, rcu);
2195 }
2196 2205
2197 if (!is_rxqs_map) { 2206 if (!is_rxqs_map) {
2198 for (i = offset + (count - 1); count--; i--) { 2207 for (i = offset + (count - 1); count--; i--) {
@@ -2236,10 +2245,6 @@ static void netif_reset_xps_queues(struct net_device *dev, u16 offset,
2236 false); 2245 false);
2237 2246
2238out_no_maps: 2247out_no_maps:
2239 if (static_key_enabled(&xps_rxqs_needed))
2240 static_key_slow_dec_cpuslocked(&xps_rxqs_needed);
2241
2242 static_key_slow_dec_cpuslocked(&xps_needed);
2243 mutex_unlock(&xps_map_mutex); 2248 mutex_unlock(&xps_map_mutex);
2244 cpus_read_unlock(); 2249 cpus_read_unlock();
2245} 2250}
@@ -2357,9 +2362,12 @@ int __netif_set_xps_queue(struct net_device *dev, const unsigned long *mask,
2357 if (!new_dev_maps) 2362 if (!new_dev_maps)
2358 goto out_no_new_maps; 2363 goto out_no_new_maps;
2359 2364
2360 static_key_slow_inc_cpuslocked(&xps_needed); 2365 if (!dev_maps) {
2361 if (is_rxqs_map) 2366 /* Increment static keys at most once per type */
2362 static_key_slow_inc_cpuslocked(&xps_rxqs_needed); 2367 static_key_slow_inc_cpuslocked(&xps_needed);
2368 if (is_rxqs_map)
2369 static_key_slow_inc_cpuslocked(&xps_rxqs_needed);
2370 }
2363 2371
2364 for (j = -1; j = netif_attrmask_next(j, possible_mask, nr_ids), 2372 for (j = -1; j = netif_attrmask_next(j, possible_mask, nr_ids),
2365 j < nr_ids;) { 2373 j < nr_ids;) {
@@ -2457,13 +2465,8 @@ out_no_new_maps:
2457 } 2465 }
2458 2466
2459 /* free map if not active */ 2467 /* free map if not active */
2460 if (!active) { 2468 if (!active)
2461 if (is_rxqs_map) 2469 reset_xps_maps(dev, dev_maps, is_rxqs_map);
2462 RCU_INIT_POINTER(dev->xps_rxqs_map, NULL);
2463 else
2464 RCU_INIT_POINTER(dev->xps_cpus_map, NULL);
2465 kfree_rcu(dev_maps, rcu);
2466 }
2467 2470
2468out_no_maps: 2471out_no_maps:
2469 mutex_unlock(&xps_map_mutex); 2472 mutex_unlock(&xps_map_mutex);