summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVlad Buslov <vladbu@mellanox.com>2018-09-26 15:19:19 +0300
committerSaeed Mahameed <saeedm@mellanox.com>2018-10-18 23:13:31 +0300
commit2a4c4298025084ba61788dfa27bcf6ea3f3c789e (patch)
tree49db76eee5150e18d15395a57acb7077d7cc7f0c
parentfd3307130344ef5fa5af0089d343ca4fc074322e (diff)
downloadlinux-2a4c4298025084ba61788dfa27bcf6ea3f3c789e.tar.xz
net/mlx5: Remove counter from idr after removing it from list
Fs_counters list can temporary become unsorted when new counters are created/deleted concurrently. Idr is used to quickly lookup position to insert new counter in logarithmic time. However, if new flows are concurrently inserted during time window when flows with adjacent ids are already removed from idr but are still present in counters list, mlx5_fc_stats_work() observes counters list in inconsistent state, which results following warning: [ 1839.561955] mlx5_core 0000:81:00.0: mlx5_cmd_fc_bulk_get:587:(pid 729): Flow counter id (0x102d5) out of range (0x1c0a8..0x1c10b). Counter ignored. Move idr_remove() call to be executed synchronously with counter deletion from list. Extract this code to mlx5_fc_stats_remove() helper function that is called by workqueue job handler mlx5_fc_stats_work(). Fixes: 12d6066c3b29 ("net/mlx5: Add flow counters idr") Signed-off-by: Vlad Buslov <vladbu@mellanox.com> Reviewed-by: Roi Dayan <roid@mellanox.com>
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c18
1 files changed, 13 insertions, 5 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c
index 77bd4cd3a1db..32accd6b041b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c
@@ -99,6 +99,18 @@ static void mlx5_fc_stats_insert(struct mlx5_core_dev *dev,
list_add_tail(&counter->list, next);
}
+static void mlx5_fc_stats_remove(struct mlx5_core_dev *dev,
+ struct mlx5_fc *counter)
+{
+ struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats;
+
+ list_del(&counter->list);
+
+ spin_lock(&fc_stats->counters_idr_lock);
+ WARN_ON(!idr_remove(&fc_stats->counters_idr, counter->id));
+ spin_unlock(&fc_stats->counters_idr_lock);
+}
+
/* The function returns the last counter that was queried so the caller
* function can continue calling it till all counters are queried.
*/
@@ -195,7 +207,7 @@ static void mlx5_fc_stats_work(struct work_struct *work)
mlx5_fc_stats_insert(dev, counter);
llist_for_each_entry_safe(counter, tmp, dellist, dellist) {
- list_del(&counter->list);
+ mlx5_fc_stats_remove(dev, counter);
mlx5_free_fc(dev, counter);
}
@@ -275,10 +287,6 @@ void mlx5_fc_destroy(struct mlx5_core_dev *dev, struct mlx5_fc *counter)
return;
if (counter->aging) {
- spin_lock(&fc_stats->counters_idr_lock);
- WARN_ON(!idr_remove(&fc_stats->counters_idr, counter->id));
- spin_unlock(&fc_stats->counters_idr_lock);
-
llist_add(&counter->dellist, &fc_stats->dellist);
mod_delayed_work(fc_stats->wq, &fc_stats->work, 0);
return;