From fc56be47da8cb111add373c36230b0139139898f Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 5 Apr 2018 22:13:21 +0200 Subject: devlink: convert occ_get op to separate registration 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: d9f9b9a4d05f ("devlink: Add support for resource abstraction") Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/netdevsim/devlink.c | 65 ++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 34 deletions(-) (limited to 'drivers/net/netdevsim') diff --git a/drivers/net/netdevsim/devlink.c b/drivers/net/netdevsim/devlink.c index 1dba479..bef7db5 100644 --- a/drivers/net/netdevsim/devlink.c +++ b/drivers/net/netdevsim/devlink.c @@ -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 = { @@ -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, - ¶ms, NULL); + ¶ms); if (err) { pr_err("Failed to register IPv4 top resource\n"); goto out; @@ -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, - ¶ms, &nsim_ipv4_fib_res_ops); + NSIM_RESOURCE_IPV4, ¶ms); if (err) { pr_err("Failed to register IPv4 FIB resource\n"); return err; @@ -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, - ¶ms, &nsim_ipv4_fib_rules_res_ops); + NSIM_RESOURCE_IPV4, ¶ms); if (err) { pr_err("Failed to register IPv4 FIB rules resource\n"); return err; @@ -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, - ¶ms, NULL); + ¶ms); if (err) { pr_err("Failed to register IPv6 top resource\n"); goto out; @@ -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, - ¶ms, &nsim_ipv6_fib_res_ops); + NSIM_RESOURCE_IPV6, ¶ms); if (err) { pr_err("Failed to register IPv6 FIB resource\n"); return err; @@ -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, - ¶ms, &nsim_ipv6_fib_rules_res_ops); + NSIM_RESOURCE_IPV6, ¶ms); 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; } -- cgit v1.1