Skip to content

Commit

Permalink
devlink: convert occ_get op to separate registration
Browse files Browse the repository at this point in the history
This resolves race during initialization where the resources with
ops are registered before driver and the structures used by occ_get
op is initialized. So keep occ_get callbacks registered only when
all structs are initialized.

The example flows, as it is in mlxsw:
1) driver load/asic probe:
   mlxsw_core
      -> mlxsw_sp_resources_register
        -> mlxsw_sp_kvdl_resources_register
          -> devlink_resource_register IDX
   mlxsw_spectrum
      -> mlxsw_sp_kvdl_init
        -> mlxsw_sp_kvdl_parts_init
          -> mlxsw_sp_kvdl_part_init
            -> devlink_resource_size_get IDX (to get the current setup
                                              size from devlink)
        -> devlink_resource_occ_get_register IDX (register current
                                                  occupancy getter)
2) reload triggered by devlink command:
  -> mlxsw_devlink_core_bus_device_reload
    -> mlxsw_sp_fini
      -> mlxsw_sp_kvdl_fini
	-> devlink_resource_occ_get_unregister IDX
    (struct mlxsw_sp *mlxsw_sp is freed at this point, call to occ get
     which is using mlxsw_sp would cause use-after free)
    -> mlxsw_sp_init
      -> mlxsw_sp_kvdl_init
        -> mlxsw_sp_kvdl_parts_init
          -> mlxsw_sp_kvdl_part_init
            -> devlink_resource_size_get IDX (to get the current setup
                                              size from devlink)
        -> devlink_resource_occ_get_register IDX (register current
                                                  occupancy getter)

Fixes: d9f9b9a ("devlink: Add support for resource abstraction")
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Jiri Pirko authored and David S. Miller committed Apr 8, 2018
1 parent 5571196 commit fc56be4
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 106 deletions.
24 changes: 4 additions & 20 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum.c
Original file line number Diff line number Diff line change
Expand Up @@ -3805,18 +3805,6 @@ static const struct mlxsw_config_profile mlxsw_sp_config_profile = {
},
};

static u64 mlxsw_sp_resource_kvd_linear_occ_get(struct devlink *devlink)
{
struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);

return mlxsw_sp_kvdl_occ_get(mlxsw_sp);
}

static const struct devlink_resource_ops mlxsw_sp_resource_kvd_linear_ops = {
.occ_get = mlxsw_sp_resource_kvd_linear_occ_get,
};

static void
mlxsw_sp_resource_size_params_prepare(struct mlxsw_core *mlxsw_core,
struct devlink_resource_size_params *kvd_size_params,
Expand Down Expand Up @@ -3877,8 +3865,7 @@ static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core)
err = devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD,
kvd_size, MLXSW_SP_RESOURCE_KVD,
DEVLINK_RESOURCE_ID_PARENT_TOP,
&kvd_size_params,
NULL);
&kvd_size_params);
if (err)
return err;

Expand All @@ -3887,8 +3874,7 @@ static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core)
linear_size,
MLXSW_SP_RESOURCE_KVD_LINEAR,
MLXSW_SP_RESOURCE_KVD,
&linear_size_params,
&mlxsw_sp_resource_kvd_linear_ops);
&linear_size_params);
if (err)
return err;

Expand All @@ -3905,8 +3891,7 @@ static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core)
double_size,
MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE,
MLXSW_SP_RESOURCE_KVD,
&hash_double_size_params,
NULL);
&hash_double_size_params);
if (err)
return err;

Expand All @@ -3915,8 +3900,7 @@ static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core)
single_size,
MLXSW_SP_RESOURCE_KVD_HASH_SINGLE,
MLXSW_SP_RESOURCE_KVD,
&hash_single_size_params,
NULL);
&hash_single_size_params);
if (err)
return err;

Expand Down
1 change: 0 additions & 1 deletion drivers/net/ethernet/mellanox/mlxsw/spectrum.h
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,6 @@ void mlxsw_sp_kvdl_free(struct mlxsw_sp *mlxsw_sp, int entry_index);
int mlxsw_sp_kvdl_alloc_size_query(struct mlxsw_sp *mlxsw_sp,
unsigned int entry_count,
unsigned int *p_alloc_size);
u64 mlxsw_sp_kvdl_occ_get(const struct mlxsw_sp *mlxsw_sp);
int mlxsw_sp_kvdl_resources_register(struct mlxsw_core *mlxsw_core);

struct mlxsw_sp_acl_rule_info {
Expand Down
67 changes: 39 additions & 28 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum_kvdl.c
Original file line number Diff line number Diff line change
Expand Up @@ -315,8 +315,9 @@ static u64 mlxsw_sp_kvdl_part_occ(struct mlxsw_sp_kvdl_part *part)
return occ;
}

u64 mlxsw_sp_kvdl_occ_get(const struct mlxsw_sp *mlxsw_sp)
static u64 mlxsw_sp_kvdl_occ_get(void *priv)
{
const struct mlxsw_sp *mlxsw_sp = priv;
u64 occ = 0;
int i;

Expand All @@ -326,48 +327,33 @@ u64 mlxsw_sp_kvdl_occ_get(const struct mlxsw_sp *mlxsw_sp)
return occ;
}

static u64 mlxsw_sp_kvdl_single_occ_get(struct devlink *devlink)
static u64 mlxsw_sp_kvdl_single_occ_get(void *priv)
{
struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
const struct mlxsw_sp *mlxsw_sp = priv;
struct mlxsw_sp_kvdl_part *part;

part = mlxsw_sp->kvdl->parts[MLXSW_SP_KVDL_PART_ID_SINGLE];
return mlxsw_sp_kvdl_part_occ(part);
}

static u64 mlxsw_sp_kvdl_chunks_occ_get(struct devlink *devlink)
static u64 mlxsw_sp_kvdl_chunks_occ_get(void *priv)
{
struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
const struct mlxsw_sp *mlxsw_sp = priv;
struct mlxsw_sp_kvdl_part *part;

part = mlxsw_sp->kvdl->parts[MLXSW_SP_KVDL_PART_ID_CHUNKS];
return mlxsw_sp_kvdl_part_occ(part);
}

static u64 mlxsw_sp_kvdl_large_chunks_occ_get(struct devlink *devlink)
static u64 mlxsw_sp_kvdl_large_chunks_occ_get(void *priv)
{
struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
const struct mlxsw_sp *mlxsw_sp = priv;
struct mlxsw_sp_kvdl_part *part;

part = mlxsw_sp->kvdl->parts[MLXSW_SP_KVDL_PART_ID_LARGE_CHUNKS];
return mlxsw_sp_kvdl_part_occ(part);
}

static const struct devlink_resource_ops mlxsw_sp_kvdl_single_ops = {
.occ_get = mlxsw_sp_kvdl_single_occ_get,
};

static const struct devlink_resource_ops mlxsw_sp_kvdl_chunks_ops = {
.occ_get = mlxsw_sp_kvdl_chunks_occ_get,
};

static const struct devlink_resource_ops mlxsw_sp_kvdl_chunks_large_ops = {
.occ_get = mlxsw_sp_kvdl_large_chunks_occ_get,
};

int mlxsw_sp_kvdl_resources_register(struct mlxsw_core *mlxsw_core)
{
struct devlink *devlink = priv_to_devlink(mlxsw_core);
Expand All @@ -386,8 +372,7 @@ int mlxsw_sp_kvdl_resources_register(struct mlxsw_core *mlxsw_core)
MLXSW_SP_KVDL_SINGLE_SIZE,
MLXSW_SP_RESOURCE_KVD_LINEAR_SINGLE,
MLXSW_SP_RESOURCE_KVD_LINEAR,
&size_params,
&mlxsw_sp_kvdl_single_ops);
&size_params);
if (err)
return err;

Expand All @@ -398,8 +383,7 @@ int mlxsw_sp_kvdl_resources_register(struct mlxsw_core *mlxsw_core)
MLXSW_SP_KVDL_CHUNKS_SIZE,
MLXSW_SP_RESOURCE_KVD_LINEAR_CHUNKS,
MLXSW_SP_RESOURCE_KVD_LINEAR,
&size_params,
&mlxsw_sp_kvdl_chunks_ops);
&size_params);
if (err)
return err;

Expand All @@ -410,13 +394,13 @@ int mlxsw_sp_kvdl_resources_register(struct mlxsw_core *mlxsw_core)
MLXSW_SP_KVDL_LARGE_CHUNKS_SIZE,
MLXSW_SP_RESOURCE_KVD_LINEAR_LARGE_CHUNKS,
MLXSW_SP_RESOURCE_KVD_LINEAR,
&size_params,
&mlxsw_sp_kvdl_chunks_large_ops);
&size_params);
return err;
}

int mlxsw_sp_kvdl_init(struct mlxsw_sp *mlxsw_sp)
{
struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
struct mlxsw_sp_kvdl *kvdl;
int err;

Expand All @@ -429,6 +413,23 @@ int mlxsw_sp_kvdl_init(struct mlxsw_sp *mlxsw_sp)
if (err)
goto err_kvdl_parts_init;

devlink_resource_occ_get_register(devlink,
MLXSW_SP_RESOURCE_KVD_LINEAR,
mlxsw_sp_kvdl_occ_get,
mlxsw_sp);
devlink_resource_occ_get_register(devlink,
MLXSW_SP_RESOURCE_KVD_LINEAR_SINGLE,
mlxsw_sp_kvdl_single_occ_get,
mlxsw_sp);
devlink_resource_occ_get_register(devlink,
MLXSW_SP_RESOURCE_KVD_LINEAR_CHUNKS,
mlxsw_sp_kvdl_chunks_occ_get,
mlxsw_sp);
devlink_resource_occ_get_register(devlink,
MLXSW_SP_RESOURCE_KVD_LINEAR_LARGE_CHUNKS,
mlxsw_sp_kvdl_large_chunks_occ_get,
mlxsw_sp);

return 0;

err_kvdl_parts_init:
Expand All @@ -438,6 +439,16 @@ int mlxsw_sp_kvdl_init(struct mlxsw_sp *mlxsw_sp)

void mlxsw_sp_kvdl_fini(struct mlxsw_sp *mlxsw_sp)
{
struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);

devlink_resource_occ_get_unregister(devlink,
MLXSW_SP_RESOURCE_KVD_LINEAR_LARGE_CHUNKS);
devlink_resource_occ_get_unregister(devlink,
MLXSW_SP_RESOURCE_KVD_LINEAR_CHUNKS);
devlink_resource_occ_get_unregister(devlink,
MLXSW_SP_RESOURCE_KVD_LINEAR_SINGLE);
devlink_resource_occ_get_unregister(devlink,
MLXSW_SP_RESOURCE_KVD_LINEAR);
mlxsw_sp_kvdl_parts_fini(mlxsw_sp);
kfree(mlxsw_sp->kvdl);
}
65 changes: 31 additions & 34 deletions drivers/net/netdevsim/devlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,52 +30,36 @@ static struct net *nsim_devlink_net(struct devlink *devlink)

/* IPv4
*/
static u64 nsim_ipv4_fib_resource_occ_get(struct devlink *devlink)
static u64 nsim_ipv4_fib_resource_occ_get(void *priv)
{
struct net *net = nsim_devlink_net(devlink);
struct net *net = priv;

return nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB, false);
}

static struct devlink_resource_ops nsim_ipv4_fib_res_ops = {
.occ_get = nsim_ipv4_fib_resource_occ_get,
};

static u64 nsim_ipv4_fib_rules_res_occ_get(struct devlink *devlink)
static u64 nsim_ipv4_fib_rules_res_occ_get(void *priv)
{
struct net *net = nsim_devlink_net(devlink);
struct net *net = priv;

return nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB_RULES, false);
}

static struct devlink_resource_ops nsim_ipv4_fib_rules_res_ops = {
.occ_get = nsim_ipv4_fib_rules_res_occ_get,
};

/* IPv6
*/
static u64 nsim_ipv6_fib_resource_occ_get(struct devlink *devlink)
static u64 nsim_ipv6_fib_resource_occ_get(void *priv)
{
struct net *net = nsim_devlink_net(devlink);
struct net *net = priv;

return nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB, false);
}

static struct devlink_resource_ops nsim_ipv6_fib_res_ops = {
.occ_get = nsim_ipv6_fib_resource_occ_get,
};

static u64 nsim_ipv6_fib_rules_res_occ_get(struct devlink *devlink)
static u64 nsim_ipv6_fib_rules_res_occ_get(void *priv)
{
struct net *net = nsim_devlink_net(devlink);
struct net *net = priv;

return nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB_RULES, false);
}

static struct devlink_resource_ops nsim_ipv6_fib_rules_res_ops = {
.occ_get = nsim_ipv6_fib_rules_res_occ_get,
};

static int devlink_resources_register(struct devlink *devlink)
{
struct devlink_resource_size_params params = {
Expand All @@ -91,7 +75,7 @@ static int devlink_resources_register(struct devlink *devlink)
err = devlink_resource_register(devlink, "IPv4", (u64)-1,
NSIM_RESOURCE_IPV4,
DEVLINK_RESOURCE_ID_PARENT_TOP,
&params, NULL);
&params);
if (err) {
pr_err("Failed to register IPv4 top resource\n");
goto out;
Expand All @@ -100,8 +84,7 @@ static int devlink_resources_register(struct devlink *devlink)
n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB, true);
err = devlink_resource_register(devlink, "fib", n,
NSIM_RESOURCE_IPV4_FIB,
NSIM_RESOURCE_IPV4,
&params, &nsim_ipv4_fib_res_ops);
NSIM_RESOURCE_IPV4, &params);
if (err) {
pr_err("Failed to register IPv4 FIB resource\n");
return err;
Expand All @@ -110,8 +93,7 @@ static int devlink_resources_register(struct devlink *devlink)
n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB_RULES, true);
err = devlink_resource_register(devlink, "fib-rules", n,
NSIM_RESOURCE_IPV4_FIB_RULES,
NSIM_RESOURCE_IPV4,
&params, &nsim_ipv4_fib_rules_res_ops);
NSIM_RESOURCE_IPV4, &params);
if (err) {
pr_err("Failed to register IPv4 FIB rules resource\n");
return err;
Expand All @@ -121,7 +103,7 @@ static int devlink_resources_register(struct devlink *devlink)
err = devlink_resource_register(devlink, "IPv6", (u64)-1,
NSIM_RESOURCE_IPV6,
DEVLINK_RESOURCE_ID_PARENT_TOP,
&params, NULL);
&params);
if (err) {
pr_err("Failed to register IPv6 top resource\n");
goto out;
Expand All @@ -130,8 +112,7 @@ static int devlink_resources_register(struct devlink *devlink)
n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB, true);
err = devlink_resource_register(devlink, "fib", n,
NSIM_RESOURCE_IPV6_FIB,
NSIM_RESOURCE_IPV6,
&params, &nsim_ipv6_fib_res_ops);
NSIM_RESOURCE_IPV6, &params);
if (err) {
pr_err("Failed to register IPv6 FIB resource\n");
return err;
Expand All @@ -140,12 +121,28 @@ static int devlink_resources_register(struct devlink *devlink)
n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB_RULES, true);
err = devlink_resource_register(devlink, "fib-rules", n,
NSIM_RESOURCE_IPV6_FIB_RULES,
NSIM_RESOURCE_IPV6,
&params, &nsim_ipv6_fib_rules_res_ops);
NSIM_RESOURCE_IPV6, &params);
if (err) {
pr_err("Failed to register IPv6 FIB rules resource\n");
return err;
}

devlink_resource_occ_get_register(devlink,
NSIM_RESOURCE_IPV4_FIB,
nsim_ipv4_fib_resource_occ_get,
net);
devlink_resource_occ_get_register(devlink,
NSIM_RESOURCE_IPV4_FIB_RULES,
nsim_ipv4_fib_rules_res_occ_get,
net);
devlink_resource_occ_get_register(devlink,
NSIM_RESOURCE_IPV6_FIB,
nsim_ipv6_fib_resource_occ_get,
net);
devlink_resource_occ_get_register(devlink,
NSIM_RESOURCE_IPV6_FIB_RULES,
nsim_ipv6_fib_rules_res_occ_get,
net);
out:
return err;
}
Expand Down
Loading

0 comments on commit fc56be4

Please sign in to comment.