Merge branch 'devlink-linecard-and-reporters-locking-cleanup'

Jiri Pirko says:

====================
devlink: linecard and reporters locking cleanup

This patchset does not change functionality.

Patches 1-2 remove linecards lock and reference counting, converting
them to be protected by devlink instance lock as the rest of
the objects.

Patches 3-4 fix the mlx5 auxiliary device devlink locking scheme whis is
needed for proper reporters lock conversion done in the following
patches.

Patches 5-8 remove reporters locks and reference counting, converting
them to be protected by devlink instance lock as the rest of
the objects.

Patches 9 and 10 convert linecards and reporters dumpit callbacks to
recently introduced devlink_nl_instance_iter_dump() infra.

Patch 11 removes no longer needed devlink_dump_for_each_instance_get()
helper.

The last patch adds assertion to devl_is_registered() as dependency on
other locks is removed.
====================

Link: https://lore.kernel.org/r/20230118152115.1113149-1-jiri@resnulli.us
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2023-01-19 19:00:31 -08:00
commit 1c5cc01233
16 changed files with 282 additions and 380 deletions

View File

@ -349,7 +349,6 @@ int mlx5_attach_device(struct mlx5_core_dev *dev)
devl_assert_locked(priv_to_devlink(dev));
mutex_lock(&mlx5_intf_mutex);
priv->flags &= ~MLX5_PRIV_FLAGS_DETACH;
priv->flags |= MLX5_PRIV_FLAGS_MLX5E_LOCKED_FLOW;
for (i = 0; i < ARRAY_SIZE(mlx5_adev_devices); i++) {
if (!priv->adev[i]) {
bool is_supported = false;
@ -397,7 +396,6 @@ int mlx5_attach_device(struct mlx5_core_dev *dev)
break;
}
}
priv->flags &= ~MLX5_PRIV_FLAGS_MLX5E_LOCKED_FLOW;
mutex_unlock(&mlx5_intf_mutex);
return ret;
}
@ -412,7 +410,6 @@ void mlx5_detach_device(struct mlx5_core_dev *dev)
devl_assert_locked(priv_to_devlink(dev));
mutex_lock(&mlx5_intf_mutex);
priv->flags |= MLX5_PRIV_FLAGS_MLX5E_LOCKED_FLOW;
for (i = ARRAY_SIZE(mlx5_adev_devices) - 1; i >= 0; i--) {
if (!priv->adev[i])
continue;
@ -441,7 +438,6 @@ void mlx5_detach_device(struct mlx5_core_dev *dev)
del_adev(&priv->adev[i]->adev);
priv->adev[i] = NULL;
}
priv->flags &= ~MLX5_PRIV_FLAGS_MLX5E_LOCKED_FLOW;
priv->flags |= MLX5_PRIV_FLAGS_DETACH;
mutex_unlock(&mlx5_intf_mutex);
}
@ -540,22 +536,16 @@ static void delete_drivers(struct mlx5_core_dev *dev)
int mlx5_rescan_drivers_locked(struct mlx5_core_dev *dev)
{
struct mlx5_priv *priv = &dev->priv;
int err = 0;
lockdep_assert_held(&mlx5_intf_mutex);
if (priv->flags & MLX5_PRIV_FLAGS_DETACH)
return 0;
priv->flags |= MLX5_PRIV_FLAGS_MLX5E_LOCKED_FLOW;
delete_drivers(dev);
if (priv->flags & MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV)
goto out;
return 0;
err = add_drivers(dev);
out:
priv->flags &= ~MLX5_PRIV_FLAGS_MLX5E_LOCKED_FLOW;
return err;
return add_drivers(dev);
}
bool mlx5_same_hw_devs(struct mlx5_core_dev *dev, struct mlx5_core_dev *peer_dev)

View File

@ -971,6 +971,10 @@ struct mlx5e_priv {
struct dentry *dfs_root;
};
struct mlx5e_dev {
struct mlx5e_priv *priv;
};
struct mlx5e_rx_handlers {
mlx5e_fp_handle_rx_cqe handle_rx_cqe;
mlx5e_fp_handle_rx_cqe handle_rx_cqe_mpwqe;

View File

@ -4,6 +4,29 @@
#include "en/devlink.h"
#include "eswitch.h"
static const struct devlink_ops mlx5e_devlink_ops = {
};
struct mlx5e_dev *mlx5e_create_devlink(struct device *dev)
{
struct mlx5e_dev *mlx5e_dev;
struct devlink *devlink;
devlink = devlink_alloc(&mlx5e_devlink_ops, sizeof(*mlx5e_dev), dev);
if (!devlink)
return ERR_PTR(-ENOMEM);
devlink_register(devlink);
return devlink_priv(devlink);
}
void mlx5e_destroy_devlink(struct mlx5e_dev *mlx5e_dev)
{
struct devlink *devlink = priv_to_devlink(mlx5e_dev);
devlink_unregister(devlink);
devlink_free(devlink);
}
static void
mlx5e_devlink_get_port_parent_id(struct mlx5_core_dev *dev, struct netdev_phys_item_id *ppid)
{
@ -14,14 +37,14 @@ mlx5e_devlink_get_port_parent_id(struct mlx5_core_dev *dev, struct netdev_phys_i
memcpy(ppid->id, &parent_id, sizeof(parent_id));
}
int mlx5e_devlink_port_register(struct mlx5e_priv *priv)
int mlx5e_devlink_port_register(struct mlx5e_dev *mlx5e_dev,
struct mlx5e_priv *priv)
{
struct devlink *devlink = priv_to_devlink(priv->mdev);
struct devlink *devlink = priv_to_devlink(mlx5e_dev);
struct devlink_port_attrs attrs = {};
struct netdev_phys_item_id ppid = {};
struct devlink_port *dl_port;
unsigned int dl_port_index;
int ret;
if (mlx5_core_is_pf(priv->mdev)) {
attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
@ -42,23 +65,12 @@ int mlx5e_devlink_port_register(struct mlx5e_priv *priv)
memset(dl_port, 0, sizeof(*dl_port));
devlink_port_attrs_set(dl_port, &attrs);
if (!(priv->mdev->priv.flags & MLX5_PRIV_FLAGS_MLX5E_LOCKED_FLOW))
devl_lock(devlink);
ret = devl_port_register(devlink, dl_port, dl_port_index);
if (!(priv->mdev->priv.flags & MLX5_PRIV_FLAGS_MLX5E_LOCKED_FLOW))
devl_unlock(devlink);
return ret;
return devlink_port_register(devlink, dl_port, dl_port_index);
}
void mlx5e_devlink_port_unregister(struct mlx5e_priv *priv)
{
struct devlink_port *dl_port = mlx5e_devlink_get_dl_port(priv);
struct devlink *devlink = priv_to_devlink(priv->mdev);
if (!(priv->mdev->priv.flags & MLX5_PRIV_FLAGS_MLX5E_LOCKED_FLOW))
devl_lock(devlink);
devl_port_unregister(dl_port);
if (!(priv->mdev->priv.flags & MLX5_PRIV_FLAGS_MLX5E_LOCKED_FLOW))
devl_unlock(devlink);
devlink_port_unregister(dl_port);
}

View File

@ -7,7 +7,10 @@
#include <net/devlink.h>
#include "en.h"
int mlx5e_devlink_port_register(struct mlx5e_priv *priv);
struct mlx5e_dev *mlx5e_create_devlink(struct device *dev);
void mlx5e_destroy_devlink(struct mlx5e_dev *mlx5e_dev);
int mlx5e_devlink_port_register(struct mlx5e_dev *mlx5e_dev,
struct mlx5e_priv *priv);
void mlx5e_devlink_port_unregister(struct mlx5e_priv *priv);
static inline struct devlink_port *

View File

@ -754,6 +754,6 @@ void mlx5e_reporter_rx_destroy(struct mlx5e_priv *priv)
if (!priv->rx_reporter)
return;
devlink_port_health_reporter_destroy(priv->rx_reporter);
devlink_health_reporter_destroy(priv->rx_reporter);
priv->rx_reporter = NULL;
}

View File

@ -609,6 +609,6 @@ void mlx5e_reporter_tx_destroy(struct mlx5e_priv *priv)
if (!priv->tx_reporter)
return;
devlink_port_health_reporter_destroy(priv->tx_reporter);
devlink_health_reporter_destroy(priv->tx_reporter);
priv->tx_reporter = NULL;
}

View File

@ -5876,7 +5876,8 @@ void mlx5e_destroy_netdev(struct mlx5e_priv *priv)
static int mlx5e_resume(struct auxiliary_device *adev)
{
struct mlx5_adev *edev = container_of(adev, struct mlx5_adev, adev);
struct mlx5e_priv *priv = auxiliary_get_drvdata(adev);
struct mlx5e_dev *mlx5e_dev = auxiliary_get_drvdata(adev);
struct mlx5e_priv *priv = mlx5e_dev->priv;
struct net_device *netdev = priv->netdev;
struct mlx5_core_dev *mdev = edev->mdev;
int err;
@ -5899,7 +5900,8 @@ static int mlx5e_resume(struct auxiliary_device *adev)
static int mlx5e_suspend(struct auxiliary_device *adev, pm_message_t state)
{
struct mlx5e_priv *priv = auxiliary_get_drvdata(adev);
struct mlx5e_dev *mlx5e_dev = auxiliary_get_drvdata(adev);
struct mlx5e_priv *priv = mlx5e_dev->priv;
struct net_device *netdev = priv->netdev;
struct mlx5_core_dev *mdev = priv->mdev;
@ -5917,21 +5919,28 @@ static int mlx5e_probe(struct auxiliary_device *adev,
struct mlx5_adev *edev = container_of(adev, struct mlx5_adev, adev);
const struct mlx5e_profile *profile = &mlx5e_nic_profile;
struct mlx5_core_dev *mdev = edev->mdev;
struct mlx5e_dev *mlx5e_dev;
struct net_device *netdev;
pm_message_t state = {};
struct mlx5e_priv *priv;
int err;
mlx5e_dev = mlx5e_create_devlink(&adev->dev);
if (IS_ERR(mlx5e_dev))
return PTR_ERR(mlx5e_dev);
auxiliary_set_drvdata(adev, mlx5e_dev);
netdev = mlx5e_create_netdev(mdev, profile);
if (!netdev) {
mlx5_core_err(mdev, "mlx5e_create_netdev failed\n");
return -ENOMEM;
err = -ENOMEM;
goto err_devlink_unregister;
}
mlx5e_build_nic_netdev(netdev);
priv = netdev_priv(netdev);
auxiliary_set_drvdata(adev, priv);
mlx5e_dev->priv = priv;
priv->profile = profile;
priv->ppriv = NULL;
@ -5939,7 +5948,7 @@ static int mlx5e_probe(struct auxiliary_device *adev,
priv->dfs_root = debugfs_create_dir("nic",
mlx5_debugfs_get_dev_root(priv->mdev));
err = mlx5e_devlink_port_register(priv);
err = mlx5e_devlink_port_register(mlx5e_dev, priv);
if (err) {
mlx5_core_err(mdev, "mlx5e_devlink_port_register failed, %d\n", err);
goto err_destroy_netdev;
@ -5978,12 +5987,15 @@ static int mlx5e_probe(struct auxiliary_device *adev,
err_destroy_netdev:
debugfs_remove_recursive(priv->dfs_root);
mlx5e_destroy_netdev(priv);
err_devlink_unregister:
mlx5e_destroy_devlink(mlx5e_dev);
return err;
}
static void mlx5e_remove(struct auxiliary_device *adev)
{
struct mlx5e_priv *priv = auxiliary_get_drvdata(adev);
struct mlx5e_dev *mlx5e_dev = auxiliary_get_drvdata(adev);
struct mlx5e_priv *priv = mlx5e_dev->priv;
pm_message_t state = {};
mlx5e_dcbnl_delete_app(priv);
@ -5993,6 +6005,7 @@ static void mlx5e_remove(struct auxiliary_device *adev)
mlx5e_devlink_port_unregister(priv);
debugfs_remove_recursive(priv->dfs_root);
mlx5e_destroy_netdev(priv);
mlx5e_destroy_devlink(mlx5e_dev);
}
static const struct auxiliary_device_id mlx5e_id_table[] = {

View File

@ -2051,8 +2051,8 @@ static int mlxsw_core_health_init(struct mlxsw_core *mlxsw_core)
if (!(mlxsw_core->bus->features & MLXSW_BUS_F_TXRX))
return 0;
fw_fatal = devlink_health_reporter_create(devlink, &mlxsw_core_health_fw_fatal_ops,
0, mlxsw_core);
fw_fatal = devl_health_reporter_create(devlink, &mlxsw_core_health_fw_fatal_ops,
0, mlxsw_core);
if (IS_ERR(fw_fatal)) {
dev_err(mlxsw_core->bus_info->dev, "Failed to create fw fatal reporter");
return PTR_ERR(fw_fatal);
@ -2072,7 +2072,7 @@ static int mlxsw_core_health_init(struct mlxsw_core *mlxsw_core)
err_fw_fatal_config:
mlxsw_core_trap_unregister(mlxsw_core, &mlxsw_core_health_listener, mlxsw_core);
err_trap_register:
devlink_health_reporter_destroy(mlxsw_core->health.fw_fatal);
devl_health_reporter_destroy(mlxsw_core->health.fw_fatal);
return err;
}
@ -2085,7 +2085,7 @@ static void mlxsw_core_health_fini(struct mlxsw_core *mlxsw_core)
mlxsw_core_trap_unregister(mlxsw_core, &mlxsw_core_health_listener, mlxsw_core);
/* Make sure there is no more event work scheduled */
mlxsw_core_flush_owq();
devlink_health_reporter_destroy(mlxsw_core->health.fw_fatal);
devl_health_reporter_destroy(mlxsw_core->health.fw_fatal);
}
static void mlxsw_core_irq_event_handler_init(struct mlxsw_core *mlxsw_core)

View File

@ -1259,9 +1259,9 @@ static int mlxsw_linecard_init(struct mlxsw_core *mlxsw_core,
linecard->linecards = linecards;
mutex_init(&linecard->lock);
devlink_linecard = devlink_linecard_create(priv_to_devlink(mlxsw_core),
slot_index, &mlxsw_linecard_ops,
linecard);
devlink_linecard = devl_linecard_create(priv_to_devlink(mlxsw_core),
slot_index, &mlxsw_linecard_ops,
linecard);
if (IS_ERR(devlink_linecard))
return PTR_ERR(devlink_linecard);
@ -1285,7 +1285,7 @@ static void mlxsw_linecard_fini(struct mlxsw_core *mlxsw_core,
if (linecard->active)
mlxsw_linecard_active_clear(linecard);
mlxsw_linecard_bdev_del(linecard);
devlink_linecard_destroy(linecard->devlink_linecard);
devl_linecard_destroy(linecard->devlink_linecard);
mutex_destroy(&linecard->lock);
}

View File

@ -233,16 +233,16 @@ int nsim_dev_health_init(struct nsim_dev *nsim_dev, struct devlink *devlink)
int err;
health->empty_reporter =
devlink_health_reporter_create(devlink,
&nsim_dev_empty_reporter_ops,
0, health);
devl_health_reporter_create(devlink,
&nsim_dev_empty_reporter_ops,
0, health);
if (IS_ERR(health->empty_reporter))
return PTR_ERR(health->empty_reporter);
health->dummy_reporter =
devlink_health_reporter_create(devlink,
&nsim_dev_dummy_reporter_ops,
0, health);
devl_health_reporter_create(devlink,
&nsim_dev_dummy_reporter_ops,
0, health);
if (IS_ERR(health->dummy_reporter)) {
err = PTR_ERR(health->dummy_reporter);
goto err_empty_reporter_destroy;
@ -266,9 +266,9 @@ int nsim_dev_health_init(struct nsim_dev *nsim_dev, struct devlink *devlink)
return 0;
err_dummy_reporter_destroy:
devlink_health_reporter_destroy(health->dummy_reporter);
devl_health_reporter_destroy(health->dummy_reporter);
err_empty_reporter_destroy:
devlink_health_reporter_destroy(health->empty_reporter);
devl_health_reporter_destroy(health->empty_reporter);
return err;
}
@ -278,6 +278,6 @@ void nsim_dev_health_exit(struct nsim_dev *nsim_dev)
debugfs_remove_recursive(health->ddir);
kfree(health->recovered_break_msg);
devlink_health_reporter_destroy(health->dummy_reporter);
devlink_health_reporter_destroy(health->empty_reporter);
devl_health_reporter_destroy(health->dummy_reporter);
devl_health_reporter_destroy(health->empty_reporter);
}

View File

@ -554,10 +554,6 @@ enum {
* creation/deletion on drivers rescan. Unset during device attach.
*/
MLX5_PRIV_FLAGS_DETACH = 1 << 2,
/* Distinguish between mlx5e_probe/remove called by module init/cleanup
* and called by other flows which can already hold devlink lock
*/
MLX5_PRIV_FLAGS_MLX5E_LOCKED_FLOW = 1 << 3,
};
struct mlx5_adev {

View File

@ -146,7 +146,6 @@ struct devlink_port {
initialized:1;
struct delayed_work type_warn_dw;
struct list_head reporter_list;
struct mutex reporters_lock; /* Protects reporter_list */
struct devlink_rate *devlink_rate;
struct devlink_linecard *linecard;
@ -1687,9 +1686,9 @@ void devl_rate_nodes_destroy(struct devlink *devlink);
void devlink_port_linecard_set(struct devlink_port *devlink_port,
struct devlink_linecard *linecard);
struct devlink_linecard *
devlink_linecard_create(struct devlink *devlink, unsigned int linecard_index,
const struct devlink_linecard_ops *ops, void *priv);
void devlink_linecard_destroy(struct devlink_linecard *linecard);
devl_linecard_create(struct devlink *devlink, unsigned int linecard_index,
const struct devlink_linecard_ops *ops, void *priv);
void devl_linecard_destroy(struct devlink_linecard *linecard);
void devlink_linecard_provision_set(struct devlink_linecard *linecard,
const char *type);
void devlink_linecard_provision_clear(struct devlink_linecard *linecard);
@ -1865,20 +1864,30 @@ int devlink_fmsg_binary_pair_put(struct devlink_fmsg *fmsg, const char *name,
const void *value, u32 value_len);
struct devlink_health_reporter *
devlink_health_reporter_create(struct devlink *devlink,
const struct devlink_health_reporter_ops *ops,
u64 graceful_period, void *priv);
devl_port_health_reporter_create(struct devlink_port *port,
const struct devlink_health_reporter_ops *ops,
u64 graceful_period, void *priv);
struct devlink_health_reporter *
devlink_port_health_reporter_create(struct devlink_port *port,
const struct devlink_health_reporter_ops *ops,
u64 graceful_period, void *priv);
void
devlink_health_reporter_destroy(struct devlink_health_reporter *reporter);
struct devlink_health_reporter *
devl_health_reporter_create(struct devlink *devlink,
const struct devlink_health_reporter_ops *ops,
u64 graceful_period, void *priv);
struct devlink_health_reporter *
devlink_health_reporter_create(struct devlink *devlink,
const struct devlink_health_reporter_ops *ops,
u64 graceful_period, void *priv);
void
devlink_port_health_reporter_destroy(struct devlink_health_reporter *reporter);
devl_health_reporter_destroy(struct devlink_health_reporter *reporter);
void
devlink_health_reporter_destroy(struct devlink_health_reporter *reporter);
void *
devlink_health_reporter_priv(struct devlink_health_reporter *reporter);

View File

@ -246,8 +246,6 @@ struct devlink *devlink_alloc_ns(const struct devlink_ops *ops,
lockdep_register_key(&devlink->lock_key);
mutex_init(&devlink->lock);
lockdep_set_class(&devlink->lock, &devlink->lock_key);
mutex_init(&devlink->reporters_lock);
mutex_init(&devlink->linecards_lock);
refcount_set(&devlink->refcount, 1);
return devlink;
@ -269,8 +267,6 @@ void devlink_free(struct devlink *devlink)
{
ASSERT_DEVLINK_NOT_REGISTERED(devlink);
mutex_destroy(&devlink->linecards_lock);
mutex_destroy(&devlink->reporters_lock);
WARN_ON(!list_empty(&devlink->trap_policer_list));
WARN_ON(!list_empty(&devlink->trap_group_list));
WARN_ON(!list_empty(&devlink->trap_list));

View File

@ -32,13 +32,11 @@ struct devlink {
struct list_head param_list;
struct list_head region_list;
struct list_head reporter_list;
struct mutex reporters_lock; /* protects reporter_list */
struct devlink_dpipe_headers *dpipe_headers;
struct list_head trap_list;
struct list_head trap_group_list;
struct list_head trap_policer_list;
struct list_head linecard_list;
struct mutex linecards_lock; /* protects linecard_list */
const struct devlink_ops *ops;
u64 features;
struct xarray snapshot_ids;
@ -87,9 +85,7 @@ struct devlink *devlinks_xa_find_get(struct net *net, unsigned long *indexp);
static inline bool devl_is_registered(struct devlink *devlink)
{
/* To prevent races the caller must hold the instance lock
* or another lock taken during unregistration.
*/
devl_assert_locked(devlink);
return xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED);
}
@ -125,17 +121,6 @@ struct devlink_gen_cmd {
struct netlink_callback *cb);
};
/* Iterate over registered devlink instances for devlink dump.
* devlink_put() needs to be called for each iterated devlink pointer
* in loop body in order to release the reference.
* Note: this is NOT a generic iterator, it makes assumptions about the use
* of @state and can only be used once per dumpit implementation.
*/
#define devlink_dump_for_each_instance_get(msg, state, devlink) \
for (; (devlink = devlinks_xa_find_get(sock_net(msg->sk), \
&state->instance)); \
state->instance++, state->idx = 0)
extern const struct genl_small_ops devlink_nl_ops[56];
struct devlink *
@ -166,9 +151,11 @@ extern const struct devlink_gen_cmd devl_gen_selftests;
extern const struct devlink_gen_cmd devl_gen_param;
extern const struct devlink_gen_cmd devl_gen_region;
extern const struct devlink_gen_cmd devl_gen_info;
extern const struct devlink_gen_cmd devl_gen_health_reporter;
extern const struct devlink_gen_cmd devl_gen_trap;
extern const struct devlink_gen_cmd devl_gen_trap_group;
extern const struct devlink_gen_cmd devl_gen_trap_policer;
extern const struct devlink_gen_cmd devl_gen_linecard;
/* Ports */
int devlink_port_netdevice_event(struct notifier_block *nb,
@ -194,7 +181,6 @@ struct devlink_linecard;
struct devlink_linecard *
devlink_linecard_get_from_info(struct devlink *devlink, struct genl_info *info);
void devlink_linecard_put(struct devlink_linecard *linecard);
/* Rates */
extern const struct devlink_gen_cmd devl_gen_rate_get;

View File

@ -37,7 +37,6 @@ struct devlink_linecard {
struct list_head list;
struct devlink *devlink;
unsigned int index;
refcount_t refcount;
const struct devlink_linecard_ops *ops;
void *priv;
enum devlink_linecard_state state;
@ -282,11 +281,7 @@ devlink_linecard_get_from_attrs(struct devlink *devlink, struct nlattr **attrs)
u32 linecard_index = nla_get_u32(attrs[DEVLINK_ATTR_LINECARD_INDEX]);
struct devlink_linecard *linecard;
mutex_lock(&devlink->linecards_lock);
linecard = devlink_linecard_get_by_index(devlink, linecard_index);
if (linecard)
refcount_inc(&linecard->refcount);
mutex_unlock(&devlink->linecards_lock);
if (!linecard)
return ERR_PTR(-ENODEV);
return linecard;
@ -300,14 +295,6 @@ devlink_linecard_get_from_info(struct devlink *devlink, struct genl_info *info)
return devlink_linecard_get_from_attrs(devlink, info->attrs);
}
void devlink_linecard_put(struct devlink_linecard *linecard)
{
if (refcount_dec_and_test(&linecard->refcount)) {
mutex_destroy(&linecard->state_lock);
kfree(linecard);
}
}
struct devlink_sb {
struct list_head list;
unsigned int index;
@ -2118,50 +2105,42 @@ static int devlink_nl_cmd_linecard_get_doit(struct sk_buff *skb,
return genlmsg_reply(msg, info);
}
static int devlink_nl_cmd_linecard_get_dumpit(struct sk_buff *msg,
struct netlink_callback *cb)
static int devlink_nl_cmd_linecard_get_dump_one(struct sk_buff *msg,
struct devlink *devlink,
struct netlink_callback *cb)
{
struct devlink_nl_dump_state *state = devlink_dump_state(cb);
struct devlink_linecard *linecard;
struct devlink *devlink;
int err;
int idx = 0;
int err = 0;
devlink_dump_for_each_instance_get(msg, state, devlink) {
int idx = 0;
mutex_lock(&devlink->linecards_lock);
if (!devl_is_registered(devlink))
goto next_devlink;
list_for_each_entry(linecard, &devlink->linecard_list, list) {
if (idx < state->idx) {
idx++;
continue;
}
mutex_lock(&linecard->state_lock);
err = devlink_nl_linecard_fill(msg, devlink, linecard,
DEVLINK_CMD_LINECARD_NEW,
NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq,
NLM_F_MULTI,
cb->extack);
mutex_unlock(&linecard->state_lock);
if (err) {
mutex_unlock(&devlink->linecards_lock);
devlink_put(devlink);
state->idx = idx;
goto out;
}
list_for_each_entry(linecard, &devlink->linecard_list, list) {
if (idx < state->idx) {
idx++;
continue;
}
next_devlink:
mutex_unlock(&devlink->linecards_lock);
devlink_put(devlink);
mutex_lock(&linecard->state_lock);
err = devlink_nl_linecard_fill(msg, devlink, linecard,
DEVLINK_CMD_LINECARD_NEW,
NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq,
NLM_F_MULTI,
cb->extack);
mutex_unlock(&linecard->state_lock);
if (err) {
state->idx = idx;
break;
}
idx++;
}
out:
return msg->len;
return err;
}
const struct devlink_gen_cmd devl_gen_linecard = {
.dump_one = devlink_nl_cmd_linecard_get_dump_one,
};
static struct devlink_linecard_type *
devlink_linecard_type_lookup(struct devlink_linecard *linecard,
const char *type)
@ -7282,7 +7261,6 @@ struct devlink_health_reporter {
u64 error_count;
u64 recovery_count;
u64 last_recovery_ts;
refcount_t refcount;
};
void *
@ -7294,12 +7272,10 @@ EXPORT_SYMBOL_GPL(devlink_health_reporter_priv);
static struct devlink_health_reporter *
__devlink_health_reporter_find_by_name(struct list_head *reporter_list,
struct mutex *list_lock,
const char *reporter_name)
{
struct devlink_health_reporter *reporter;
lockdep_assert_held(list_lock);
list_for_each_entry(reporter, reporter_list, list)
if (!strcmp(reporter->ops->name, reporter_name))
return reporter;
@ -7311,7 +7287,6 @@ devlink_health_reporter_find_by_name(struct devlink *devlink,
const char *reporter_name)
{
return __devlink_health_reporter_find_by_name(&devlink->reporter_list,
&devlink->reporters_lock,
reporter_name);
}
@ -7320,7 +7295,6 @@ devlink_port_health_reporter_find_by_name(struct devlink_port *devlink_port,
const char *reporter_name)
{
return __devlink_health_reporter_find_by_name(&devlink_port->reporter_list,
&devlink_port->reporters_lock,
reporter_name);
}
@ -7345,54 +7319,88 @@ __devlink_health_reporter_create(struct devlink *devlink,
reporter->auto_recover = !!ops->recover;
reporter->auto_dump = !!ops->dump;
mutex_init(&reporter->dump_lock);
refcount_set(&reporter->refcount, 1);
return reporter;
}
/**
* devlink_port_health_reporter_create - create devlink health reporter for
* specified port instance
* devl_port_health_reporter_create - create devlink health reporter for
* specified port instance
*
* @port: devlink_port which should contain the new reporter
* @ops: ops
* @graceful_period: to avoid recovery loops, in msecs
* @priv: priv
*/
struct devlink_health_reporter *
devl_port_health_reporter_create(struct devlink_port *port,
const struct devlink_health_reporter_ops *ops,
u64 graceful_period, void *priv)
{
struct devlink_health_reporter *reporter;
devl_assert_locked(port->devlink);
if (__devlink_health_reporter_find_by_name(&port->reporter_list,
ops->name))
return ERR_PTR(-EEXIST);
reporter = __devlink_health_reporter_create(port->devlink, ops,
graceful_period, priv);
if (IS_ERR(reporter))
return reporter;
reporter->devlink_port = port;
list_add_tail(&reporter->list, &port->reporter_list);
return reporter;
}
EXPORT_SYMBOL_GPL(devl_port_health_reporter_create);
struct devlink_health_reporter *
devlink_port_health_reporter_create(struct devlink_port *port,
const struct devlink_health_reporter_ops *ops,
u64 graceful_period, void *priv)
{
struct devlink_health_reporter *reporter;
struct devlink *devlink = port->devlink;
mutex_lock(&port->reporters_lock);
if (__devlink_health_reporter_find_by_name(&port->reporter_list,
&port->reporters_lock, ops->name)) {
reporter = ERR_PTR(-EEXIST);
goto unlock;
}
reporter = __devlink_health_reporter_create(port->devlink, ops,
devl_lock(devlink);
reporter = devl_port_health_reporter_create(port, ops,
graceful_period, priv);
if (IS_ERR(reporter))
goto unlock;
reporter->devlink_port = port;
list_add_tail(&reporter->list, &port->reporter_list);
unlock:
mutex_unlock(&port->reporters_lock);
devl_unlock(devlink);
return reporter;
}
EXPORT_SYMBOL_GPL(devlink_port_health_reporter_create);
/**
* devlink_health_reporter_create - create devlink health reporter
* devl_health_reporter_create - create devlink health reporter
*
* @devlink: devlink
* @ops: ops
* @graceful_period: to avoid recovery loops, in msecs
* @priv: priv
*/
struct devlink_health_reporter *
devl_health_reporter_create(struct devlink *devlink,
const struct devlink_health_reporter_ops *ops,
u64 graceful_period, void *priv)
{
struct devlink_health_reporter *reporter;
devl_assert_locked(devlink);
if (devlink_health_reporter_find_by_name(devlink, ops->name))
return ERR_PTR(-EEXIST);
reporter = __devlink_health_reporter_create(devlink, ops,
graceful_period, priv);
if (IS_ERR(reporter))
return reporter;
list_add_tail(&reporter->list, &devlink->reporter_list);
return reporter;
}
EXPORT_SYMBOL_GPL(devl_health_reporter_create);
struct devlink_health_reporter *
devlink_health_reporter_create(struct devlink *devlink,
const struct devlink_health_reporter_ops *ops,
@ -7400,20 +7408,10 @@ devlink_health_reporter_create(struct devlink *devlink,
{
struct devlink_health_reporter *reporter;
mutex_lock(&devlink->reporters_lock);
if (devlink_health_reporter_find_by_name(devlink, ops->name)) {
reporter = ERR_PTR(-EEXIST);
goto unlock;
}
reporter = __devlink_health_reporter_create(devlink, ops,
graceful_period, priv);
if (IS_ERR(reporter))
goto unlock;
list_add_tail(&reporter->list, &devlink->reporter_list);
unlock:
mutex_unlock(&devlink->reporters_lock);
devl_lock(devlink);
reporter = devl_health_reporter_create(devlink, ops,
graceful_period, priv);
devl_unlock(devlink);
return reporter;
}
EXPORT_SYMBOL_GPL(devlink_health_reporter_create);
@ -7427,52 +7425,32 @@ devlink_health_reporter_free(struct devlink_health_reporter *reporter)
kfree(reporter);
}
static void
devlink_health_reporter_put(struct devlink_health_reporter *reporter)
{
if (refcount_dec_and_test(&reporter->refcount))
devlink_health_reporter_free(reporter);
}
static void
__devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
{
list_del(&reporter->list);
devlink_health_reporter_put(reporter);
}
/**
* devlink_health_reporter_destroy - destroy devlink health reporter
* devl_health_reporter_destroy - destroy devlink health reporter
*
* @reporter: devlink health reporter to destroy
*/
void
devl_health_reporter_destroy(struct devlink_health_reporter *reporter)
{
devl_assert_locked(reporter->devlink);
list_del(&reporter->list);
devlink_health_reporter_free(reporter);
}
EXPORT_SYMBOL_GPL(devl_health_reporter_destroy);
void
devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
{
struct mutex *lock = &reporter->devlink->reporters_lock;
struct devlink *devlink = reporter->devlink;
mutex_lock(lock);
__devlink_health_reporter_destroy(reporter);
mutex_unlock(lock);
devl_lock(devlink);
devl_health_reporter_destroy(reporter);
devl_unlock(devlink);
}
EXPORT_SYMBOL_GPL(devlink_health_reporter_destroy);
/**
* devlink_port_health_reporter_destroy - destroy devlink port health reporter
*
* @reporter: devlink health reporter to destroy
*/
void
devlink_port_health_reporter_destroy(struct devlink_health_reporter *reporter)
{
struct mutex *lock = &reporter->devlink_port->reporters_lock;
mutex_lock(lock);
__devlink_health_reporter_destroy(reporter);
mutex_unlock(lock);
}
EXPORT_SYMBOL_GPL(devlink_port_health_reporter_destroy);
static int
devlink_nl_health_reporter_fill(struct sk_buff *msg,
struct devlink_health_reporter *reporter,
@ -7702,7 +7680,6 @@ static struct devlink_health_reporter *
devlink_health_reporter_get_from_attrs(struct devlink *devlink,
struct nlattr **attrs)
{
struct devlink_health_reporter *reporter;
struct devlink_port *devlink_port;
char *reporter_name;
@ -7711,21 +7688,12 @@ devlink_health_reporter_get_from_attrs(struct devlink *devlink,
reporter_name = nla_data(attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]);
devlink_port = devlink_port_get_from_attrs(devlink, attrs);
if (IS_ERR(devlink_port)) {
mutex_lock(&devlink->reporters_lock);
reporter = devlink_health_reporter_find_by_name(devlink, reporter_name);
if (reporter)
refcount_inc(&reporter->refcount);
mutex_unlock(&devlink->reporters_lock);
} else {
mutex_lock(&devlink_port->reporters_lock);
reporter = devlink_port_health_reporter_find_by_name(devlink_port, reporter_name);
if (reporter)
refcount_inc(&reporter->refcount);
mutex_unlock(&devlink_port->reporters_lock);
}
return reporter;
if (IS_ERR(devlink_port))
return devlink_health_reporter_find_by_name(devlink,
reporter_name);
else
return devlink_port_health_reporter_find_by_name(devlink_port,
reporter_name);
}
static struct devlink_health_reporter *
@ -7784,10 +7752,8 @@ static int devlink_nl_cmd_health_reporter_get_doit(struct sk_buff *skb,
return -EINVAL;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg) {
err = -ENOMEM;
goto out;
}
if (!msg)
return -ENOMEM;
err = devlink_nl_health_reporter_fill(msg, reporter,
DEVLINK_CMD_HEALTH_REPORTER_GET,
@ -7795,98 +7761,72 @@ static int devlink_nl_cmd_health_reporter_get_doit(struct sk_buff *skb,
0);
if (err) {
nlmsg_free(msg);
goto out;
return err;
}
err = genlmsg_reply(msg, info);
out:
devlink_health_reporter_put(reporter);
return err;
return genlmsg_reply(msg, info);
}
static int
devlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg,
struct netlink_callback *cb)
devlink_nl_cmd_health_reporter_get_dump_one(struct sk_buff *msg,
struct devlink *devlink,
struct netlink_callback *cb)
{
struct devlink_nl_dump_state *state = devlink_dump_state(cb);
struct devlink *devlink;
struct devlink_health_reporter *reporter;
struct devlink_port *port;
unsigned long port_index;
int idx = 0;
int err;
devlink_dump_for_each_instance_get(msg, state, devlink) {
struct devlink_health_reporter *reporter;
struct devlink_port *port;
unsigned long port_index;
int idx = 0;
mutex_lock(&devlink->reporters_lock);
if (!devl_is_registered(devlink)) {
mutex_unlock(&devlink->reporters_lock);
devlink_put(devlink);
list_for_each_entry(reporter, &devlink->reporter_list, list) {
if (idx < state->idx) {
idx++;
continue;
}
list_for_each_entry(reporter, &devlink->reporter_list,
list) {
err = devlink_nl_health_reporter_fill(msg, reporter,
DEVLINK_CMD_HEALTH_REPORTER_GET,
NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq,
NLM_F_MULTI);
if (err) {
state->idx = idx;
return err;
}
idx++;
}
xa_for_each(&devlink->ports, port_index, port) {
list_for_each_entry(reporter, &port->reporter_list, list) {
if (idx < state->idx) {
idx++;
continue;
}
err = devlink_nl_health_reporter_fill(
msg, reporter, DEVLINK_CMD_HEALTH_REPORTER_GET,
NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
NLM_F_MULTI);
err = devlink_nl_health_reporter_fill(msg, reporter,
DEVLINK_CMD_HEALTH_REPORTER_GET,
NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq,
NLM_F_MULTI);
if (err) {
mutex_unlock(&devlink->reporters_lock);
devlink_put(devlink);
state->idx = idx;
goto out;
return err;
}
idx++;
}
mutex_unlock(&devlink->reporters_lock);
devl_lock(devlink);
if (!devl_is_registered(devlink))
goto next_devlink;
xa_for_each(&devlink->ports, port_index, port) {
mutex_lock(&port->reporters_lock);
list_for_each_entry(reporter, &port->reporter_list, list) {
if (idx < state->idx) {
idx++;
continue;
}
err = devlink_nl_health_reporter_fill(
msg, reporter,
DEVLINK_CMD_HEALTH_REPORTER_GET,
NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, NLM_F_MULTI);
if (err) {
mutex_unlock(&port->reporters_lock);
devl_unlock(devlink);
devlink_put(devlink);
state->idx = idx;
goto out;
}
idx++;
}
mutex_unlock(&port->reporters_lock);
}
next_devlink:
devl_unlock(devlink);
devlink_put(devlink);
}
out:
return msg->len;
return 0;
}
const struct devlink_gen_cmd devl_gen_health_reporter = {
.dump_one = devlink_nl_cmd_health_reporter_get_dump_one,
};
static int
devlink_nl_cmd_health_reporter_set_doit(struct sk_buff *skb,
struct genl_info *info)
{
struct devlink *devlink = info->user_ptr[0];
struct devlink_health_reporter *reporter;
int err;
reporter = devlink_health_reporter_get_from_info(devlink, info);
if (!reporter)
@ -7894,15 +7834,12 @@ devlink_nl_cmd_health_reporter_set_doit(struct sk_buff *skb,
if (!reporter->ops->recover &&
(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] ||
info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])) {
err = -EOPNOTSUPP;
goto out;
}
info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]))
return -EOPNOTSUPP;
if (!reporter->ops->dump &&
info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]) {
err = -EOPNOTSUPP;
goto out;
}
info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP])
return -EOPNOTSUPP;
if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD])
reporter->graceful_period =
@ -7916,11 +7853,7 @@ devlink_nl_cmd_health_reporter_set_doit(struct sk_buff *skb,
reporter->auto_dump =
nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]);
devlink_health_reporter_put(reporter);
return 0;
out:
devlink_health_reporter_put(reporter);
return err;
}
static int devlink_nl_cmd_health_reporter_recover_doit(struct sk_buff *skb,
@ -7928,16 +7861,12 @@ static int devlink_nl_cmd_health_reporter_recover_doit(struct sk_buff *skb,
{
struct devlink *devlink = info->user_ptr[0];
struct devlink_health_reporter *reporter;
int err;
reporter = devlink_health_reporter_get_from_info(devlink, info);
if (!reporter)
return -EINVAL;
err = devlink_health_reporter_recover(reporter, NULL, info->extack);
devlink_health_reporter_put(reporter);
return err;
return devlink_health_reporter_recover(reporter, NULL, info->extack);
}
static int devlink_nl_cmd_health_reporter_diagnose_doit(struct sk_buff *skb,
@ -7952,36 +7881,27 @@ static int devlink_nl_cmd_health_reporter_diagnose_doit(struct sk_buff *skb,
if (!reporter)
return -EINVAL;
if (!reporter->ops->diagnose) {
devlink_health_reporter_put(reporter);
if (!reporter->ops->diagnose)
return -EOPNOTSUPP;
}
fmsg = devlink_fmsg_alloc();
if (!fmsg) {
devlink_health_reporter_put(reporter);
if (!fmsg)
return -ENOMEM;
}
err = devlink_fmsg_obj_nest_start(fmsg);
if (err)
goto out;
return err;
err = reporter->ops->diagnose(reporter, fmsg, info->extack);
if (err)
goto out;
return err;
err = devlink_fmsg_obj_nest_end(fmsg);
if (err)
goto out;
return err;
err = devlink_fmsg_snd(fmsg, info,
DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE, 0);
out:
devlink_fmsg_free(fmsg);
devlink_health_reporter_put(reporter);
return err;
return devlink_fmsg_snd(fmsg, info,
DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE, 0);
}
static int
@ -7996,10 +7916,9 @@ devlink_nl_cmd_health_reporter_dump_get_dumpit(struct sk_buff *skb,
if (!reporter)
return -EINVAL;
if (!reporter->ops->dump) {
err = -EOPNOTSUPP;
goto out;
}
if (!reporter->ops->dump)
return -EOPNOTSUPP;
mutex_lock(&reporter->dump_lock);
if (!state->idx) {
err = devlink_health_do_dump(reporter, NULL, cb->extack);
@ -8017,8 +7936,6 @@ devlink_nl_cmd_health_reporter_dump_get_dumpit(struct sk_buff *skb,
DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET);
unlock:
mutex_unlock(&reporter->dump_lock);
out:
devlink_health_reporter_put(reporter);
return err;
}
@ -8033,15 +7950,12 @@ devlink_nl_cmd_health_reporter_dump_clear_doit(struct sk_buff *skb,
if (!reporter)
return -EINVAL;
if (!reporter->ops->dump) {
devlink_health_reporter_put(reporter);
if (!reporter->ops->dump)
return -EOPNOTSUPP;
}
mutex_lock(&reporter->dump_lock);
devlink_health_dump_clear(reporter);
mutex_unlock(&reporter->dump_lock);
devlink_health_reporter_put(reporter);
return 0;
}
@ -8050,21 +7964,15 @@ static int devlink_nl_cmd_health_reporter_test_doit(struct sk_buff *skb,
{
struct devlink *devlink = info->user_ptr[0];
struct devlink_health_reporter *reporter;
int err;
reporter = devlink_health_reporter_get_from_info(devlink, info);
if (!reporter)
return -EINVAL;
if (!reporter->ops->test) {
devlink_health_reporter_put(reporter);
if (!reporter->ops->test)
return -EOPNOTSUPP;
}
err = reporter->ops->test(reporter, info->extack);
devlink_health_reporter_put(reporter);
return err;
return reporter->ops->test(reporter, info->extack);
}
struct devlink_stats {
@ -9083,7 +8991,7 @@ const struct genl_small_ops devlink_nl_ops[56] = {
{
.cmd = DEVLINK_CMD_LINECARD_GET,
.doit = devlink_nl_cmd_linecard_get_doit,
.dumpit = devlink_nl_cmd_linecard_get_dumpit,
.dumpit = devlink_nl_instance_iter_dump,
.internal_flags = DEVLINK_NL_FLAG_NEED_LINECARD,
/* can be retrieved by unprivileged users */
},
@ -9274,7 +9182,7 @@ const struct genl_small_ops devlink_nl_ops[56] = {
.cmd = DEVLINK_CMD_HEALTH_REPORTER_GET,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = devlink_nl_cmd_health_reporter_get_doit,
.dumpit = devlink_nl_cmd_health_reporter_get_dumpit,
.dumpit = devlink_nl_instance_iter_dump,
.internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT,
/* can be retrieved by unprivileged users */
},
@ -9591,12 +9499,9 @@ int devl_port_register(struct devlink *devlink,
devlink_port->index = port_index;
spin_lock_init(&devlink_port->type_lock);
INIT_LIST_HEAD(&devlink_port->reporter_list);
mutex_init(&devlink_port->reporters_lock);
err = xa_insert(&devlink->ports, port_index, devlink_port, GFP_KERNEL);
if (err) {
mutex_destroy(&devlink_port->reporters_lock);
if (err)
return err;
}
INIT_DELAYED_WORK(&devlink_port->type_warn_dw, &devlink_port_type_warn);
devlink_port_type_warn_schedule(devlink_port);
@ -9647,7 +9552,6 @@ void devl_port_unregister(struct devlink_port *devlink_port)
devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL);
xa_erase(&devlink_port->devlink->ports, devlink_port->index);
WARN_ON(!list_empty(&devlink_port->reporter_list));
mutex_destroy(&devlink_port->reporters_lock);
devlink_port->registered = false;
}
EXPORT_SYMBOL_GPL(devl_port_unregister);
@ -10223,7 +10127,7 @@ static void devlink_linecard_types_fini(struct devlink_linecard *linecard)
}
/**
* devlink_linecard_create - Create devlink linecard
* devl_linecard_create - Create devlink linecard
*
* @devlink: devlink
* @linecard_index: driver-specific numerical identifier of the linecard
@ -10236,8 +10140,8 @@ static void devlink_linecard_types_fini(struct devlink_linecard *linecard)
* Return: Line card structure or an ERR_PTR() encoded error code.
*/
struct devlink_linecard *
devlink_linecard_create(struct devlink *devlink, unsigned int linecard_index,
const struct devlink_linecard_ops *ops, void *priv)
devl_linecard_create(struct devlink *devlink, unsigned int linecard_index,
const struct devlink_linecard_ops *ops, void *priv)
{
struct devlink_linecard *linecard;
int err;
@ -10246,17 +10150,12 @@ devlink_linecard_create(struct devlink *devlink, unsigned int linecard_index,
!ops->types_count || !ops->types_get))
return ERR_PTR(-EINVAL);
mutex_lock(&devlink->linecards_lock);
if (devlink_linecard_index_exists(devlink, linecard_index)) {
mutex_unlock(&devlink->linecards_lock);
if (devlink_linecard_index_exists(devlink, linecard_index))
return ERR_PTR(-EEXIST);
}
linecard = kzalloc(sizeof(*linecard), GFP_KERNEL);
if (!linecard) {
mutex_unlock(&devlink->linecards_lock);
if (!linecard)
return ERR_PTR(-ENOMEM);
}
linecard->devlink = devlink;
linecard->index = linecard_index;
@ -10269,35 +10168,29 @@ devlink_linecard_create(struct devlink *devlink, unsigned int linecard_index,
if (err) {
mutex_destroy(&linecard->state_lock);
kfree(linecard);
mutex_unlock(&devlink->linecards_lock);
return ERR_PTR(err);
}
list_add_tail(&linecard->list, &devlink->linecard_list);
refcount_set(&linecard->refcount, 1);
mutex_unlock(&devlink->linecards_lock);
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
return linecard;
}
EXPORT_SYMBOL_GPL(devlink_linecard_create);
EXPORT_SYMBOL_GPL(devl_linecard_create);
/**
* devlink_linecard_destroy - Destroy devlink linecard
* devl_linecard_destroy - Destroy devlink linecard
*
* @linecard: devlink linecard
*/
void devlink_linecard_destroy(struct devlink_linecard *linecard)
void devl_linecard_destroy(struct devlink_linecard *linecard)
{
struct devlink *devlink = linecard->devlink;
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_DEL);
mutex_lock(&devlink->linecards_lock);
list_del(&linecard->list);
devlink_linecard_types_fini(linecard);
mutex_unlock(&devlink->linecards_lock);
devlink_linecard_put(linecard);
mutex_destroy(&linecard->state_lock);
kfree(linecard);
}
EXPORT_SYMBOL_GPL(devlink_linecard_destroy);
EXPORT_SYMBOL_GPL(devl_linecard_destroy);
/**
* devlink_linecard_provision_set - Set provisioning on linecard

View File

@ -170,14 +170,9 @@ static int devlink_nl_pre_doit(const struct genl_split_ops *ops,
static void devlink_nl_post_doit(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info)
{
struct devlink_linecard *linecard;
struct devlink *devlink;
devlink = info->user_ptr[0];
if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_LINECARD) {
linecard = info->user_ptr[1];
devlink_linecard_put(linecard);
}
devl_unlock(devlink);
devlink_put(devlink);
}
@ -192,10 +187,12 @@ static const struct devlink_gen_cmd *devl_gen_cmds[] = {
[DEVLINK_CMD_PARAM_GET] = &devl_gen_param,
[DEVLINK_CMD_REGION_GET] = &devl_gen_region,
[DEVLINK_CMD_INFO_GET] = &devl_gen_info,
[DEVLINK_CMD_HEALTH_REPORTER_GET] = &devl_gen_health_reporter,
[DEVLINK_CMD_RATE_GET] = &devl_gen_rate_get,
[DEVLINK_CMD_TRAP_GET] = &devl_gen_trap,
[DEVLINK_CMD_TRAP_GROUP_GET] = &devl_gen_trap_group,
[DEVLINK_CMD_TRAP_POLICER_GET] = &devl_gen_trap_policer,
[DEVLINK_CMD_LINECARD_GET] = &devl_gen_linecard,
[DEVLINK_CMD_SELFTESTS_GET] = &devl_gen_selftests,
};
@ -210,7 +207,8 @@ int devlink_nl_instance_iter_dump(struct sk_buff *msg,
cmd = devl_gen_cmds[info->op.cmd];
devlink_dump_for_each_instance_get(msg, state, devlink) {
while ((devlink = devlinks_xa_find_get(sock_net(msg->sk),
&state->instance))) {
devl_lock(devlink);
if (devl_is_registered(devlink))
@ -224,6 +222,8 @@ int devlink_nl_instance_iter_dump(struct sk_buff *msg,
if (err)
break;
state->instance++;
/* restart sub-object walk for the next instance */
state->idx = 0;
}