diff options
author | Sabrina Dubroca <sd@queasysnail.net> | 2018-11-29 08:14:49 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-11-29 14:06:08 -0500 |
commit | 867d0ad476db89a1e8af3f297af402399a54eea5 (patch) | |
tree | 075055a7fd00fe41bc76ba070136c7765cf282c6 /net | |
parent | f28c020fb488e1a8b87469812017044bef88aa2b (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.c | 45 |
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 | ||
2178 | static 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 | |||
2178 | static void clean_xps_maps(struct net_device *dev, const unsigned long *mask, | 2192 | static 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 | ||
2238 | out_no_maps: | 2247 | out_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 | ||
2468 | out_no_maps: | 2471 | out_no_maps: |
2469 | mutex_unlock(&xps_map_mutex); | 2472 | mutex_unlock(&xps_map_mutex); |