mlxsw: spectrum_kvdl: Protect allocations with a lock
authorIdo Schimmel <idosch@mellanox.com>
Thu, 20 Feb 2020 07:07:46 +0000 (09:07 +0200)
committerDavid S. Miller <davem@davemloft.net>
Thu, 20 Feb 2020 18:04:33 +0000 (10:04 -0800)
The KVDL is used to store objects allocated throughout various places
in the driver. For example, both nexthops (adjacency entries) and ACL
actions are stored in the KVDL.

Currently, all allocations are protected by RTNL, but this is going to
change with the removal of RTNL from the routing code.

Therefore, protect KVDL allocations with a lock. A mutex is used since
the free operation can block in Spectrum-2.

Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlxsw/spectrum_kvdl.c

index 715ec8ecacba45da4e31a296064272ab717127ec..20d72f1c0ceed2aa467ad77daaac686c2cf4c092 100644 (file)
@@ -2,12 +2,14 @@
 /* Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved */
 
 #include <linux/kernel.h>
+#include <linux/mutex.h>
 #include <linux/slab.h>
 
 #include "spectrum.h"
 
 struct mlxsw_sp_kvdl {
        const struct mlxsw_sp_kvdl_ops *kvdl_ops;
+       struct mutex kvdl_lock; /* Protects kvdl allocations */
        unsigned long priv[];
        /* priv has to be always the last item */
 };
@@ -22,6 +24,7 @@ int mlxsw_sp_kvdl_init(struct mlxsw_sp *mlxsw_sp)
                       GFP_KERNEL);
        if (!kvdl)
                return -ENOMEM;
+       mutex_init(&kvdl->kvdl_lock);
        kvdl->kvdl_ops = kvdl_ops;
        mlxsw_sp->kvdl = kvdl;
 
@@ -31,6 +34,7 @@ int mlxsw_sp_kvdl_init(struct mlxsw_sp *mlxsw_sp)
        return 0;
 
 err_init:
+       mutex_destroy(&kvdl->kvdl_lock);
        kfree(kvdl);
        return err;
 }
@@ -40,6 +44,7 @@ void mlxsw_sp_kvdl_fini(struct mlxsw_sp *mlxsw_sp)
        struct mlxsw_sp_kvdl *kvdl = mlxsw_sp->kvdl;
 
        kvdl->kvdl_ops->fini(mlxsw_sp, kvdl->priv);
+       mutex_destroy(&kvdl->kvdl_lock);
        kfree(kvdl);
 }
 
@@ -48,9 +53,14 @@ int mlxsw_sp_kvdl_alloc(struct mlxsw_sp *mlxsw_sp,
                        unsigned int entry_count, u32 *p_entry_index)
 {
        struct mlxsw_sp_kvdl *kvdl = mlxsw_sp->kvdl;
+       int err;
+
+       mutex_lock(&kvdl->kvdl_lock);
+       err = kvdl->kvdl_ops->alloc(mlxsw_sp, kvdl->priv, type,
+                                   entry_count, p_entry_index);
+       mutex_unlock(&kvdl->kvdl_lock);
 
-       return kvdl->kvdl_ops->alloc(mlxsw_sp, kvdl->priv, type,
-                                    entry_count, p_entry_index);
+       return err;
 }
 
 void mlxsw_sp_kvdl_free(struct mlxsw_sp *mlxsw_sp,
@@ -59,8 +69,10 @@ void mlxsw_sp_kvdl_free(struct mlxsw_sp *mlxsw_sp,
 {
        struct mlxsw_sp_kvdl *kvdl = mlxsw_sp->kvdl;
 
+       mutex_lock(&kvdl->kvdl_lock);
        kvdl->kvdl_ops->free(mlxsw_sp, kvdl->priv, type,
                             entry_count, entry_index);
+       mutex_unlock(&kvdl->kvdl_lock);
 }
 
 int mlxsw_sp_kvdl_alloc_count_query(struct mlxsw_sp *mlxsw_sp,