Commit dfdfd130 authored by Jiri Pirko's avatar Jiri Pirko Committed by Jakub Kicinski
Browse files

devlink: protect health reporter operation with instance lock



Similar to other devlink objects, protect the reporters list
by devlink instance lock. Alongside add unlocked versions
of health reporter create/destroy functions and use them in drivers
on call paths where the instance lock is held.

Signed-off-by: default avatarJiri Pirko <jiri@nvidia.com>
Reviewed-by: default avatarJacob Keller <jacob.e.keller@intel.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 65a20c2e
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -2051,7 +2051,7 @@ 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,
	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");
@@ -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)
+10 −10
Original line number Diff line number Diff line
@@ -233,14 +233,14 @@ int nsim_dev_health_init(struct nsim_dev *nsim_dev, struct devlink *devlink)
	int err;

	health->empty_reporter =
		devlink_health_reporter_create(devlink,
		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,
		devl_health_reporter_create(devlink,
					    &nsim_dev_dummy_reporter_ops,
					    0, health);
	if (IS_ERR(health->dummy_reporter)) {
@@ -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);
}
+19 −3
Original line number Diff line number Diff line
@@ -1865,7 +1865,7 @@ 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,
devl_port_health_reporter_create(struct devlink_port *port,
				 const struct devlink_health_reporter_ops *ops,
				 u64 graceful_period, void *priv);

@@ -1874,9 +1874,25 @@ 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 *
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
devl_health_reporter_destroy(struct devlink_health_reporter *reporter);

void
devlink_health_reporter_destroy(struct devlink_health_reporter *reporter);

void
devl_port_health_reporter_destroy(struct devlink_health_reporter *reporter);

void
devlink_port_health_reporter_destroy(struct devlink_health_reporter *reporter);

+77 −22
Original line number Diff line number Diff line
@@ -7337,7 +7337,7 @@ __devlink_health_reporter_create(struct devlink *devlink,
}

/**
 *	devlink_port_health_reporter_create - create devlink health reporter for
 *	devl_port_health_reporter_create - create devlink health reporter for
 *	                                   specified port instance
 *
 *	@port: devlink_port which should contain the new reporter
@@ -7346,12 +7346,13 @@ __devlink_health_reporter_create(struct devlink *devlink,
 *	@priv: priv
 */
struct devlink_health_reporter *
devlink_port_health_reporter_create(struct devlink_port *port,
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);
	mutex_lock(&port->reporters_lock);
	if (__devlink_health_reporter_find_by_name(&port->reporter_list,
						   &port->reporters_lock, ops->name)) {
@@ -7370,10 +7371,26 @@ devlink_port_health_reporter_create(struct devlink_port *port,
	mutex_unlock(&port->reporters_lock);
	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;

	devl_lock(devlink);
	reporter = devl_port_health_reporter_create(port, ops,
						    graceful_period, priv);
	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
@@ -7381,12 +7398,13 @@ EXPORT_SYMBOL_GPL(devlink_port_health_reporter_create);
 *	@priv: priv
 */
struct devlink_health_reporter *
devlink_health_reporter_create(struct devlink *devlink,
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);
	mutex_lock(&devlink->reporters_lock);
	if (devlink_health_reporter_find_by_name(devlink, ops->name)) {
		reporter = ERR_PTR(-EEXIST);
@@ -7403,6 +7421,21 @@ devlink_health_reporter_create(struct devlink *devlink,
	mutex_unlock(&devlink->reporters_lock);
	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,
			       u64 graceful_period, void *priv)
{
	struct devlink_health_reporter *reporter;

	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);

static void
@@ -7429,35 +7462,61 @@ __devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
}

/**
 *	devlink_health_reporter_destroy - destroy devlink health reporter
 *	devl_health_reporter_destroy - destroy devlink health reporter
 *
 *	@reporter: devlink health reporter to destroy
 */
void
devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
devl_health_reporter_destroy(struct devlink_health_reporter *reporter)
{
	struct mutex *lock = &reporter->devlink->reporters_lock;

	devl_assert_locked(reporter->devlink);

	mutex_lock(lock);
	__devlink_health_reporter_destroy(reporter);
	mutex_unlock(lock);
}
EXPORT_SYMBOL_GPL(devl_health_reporter_destroy);

void
devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
{
	struct devlink *devlink = reporter->devlink;

	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
 *	devl_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)
devl_port_health_reporter_destroy(struct devlink_health_reporter *reporter)
{
	struct mutex *lock = &reporter->devlink_port->reporters_lock;

	devl_assert_locked(reporter->devlink);

	mutex_lock(lock);
	__devlink_health_reporter_destroy(reporter);
	mutex_unlock(lock);
}
EXPORT_SYMBOL_GPL(devl_port_health_reporter_destroy);

void
devlink_port_health_reporter_destroy(struct devlink_health_reporter *reporter)
{
	struct devlink *devlink = reporter->devlink;

	devl_lock(devlink);
	devl_port_health_reporter_destroy(reporter);
	devl_unlock(devlink);
}
EXPORT_SYMBOL_GPL(devlink_port_health_reporter_destroy);

static int
@@ -7805,12 +7864,11 @@ devlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg,
		unsigned long port_index;
		int idx = 0;

		devl_lock(devlink);
		if (!devl_is_registered(devlink))
			goto next_devlink;

		mutex_lock(&devlink->reporters_lock);
		if (!devl_is_registered(devlink)) {
			mutex_unlock(&devlink->reporters_lock);
			devlink_put(devlink);
			continue;
		}

		list_for_each_entry(reporter, &devlink->reporter_list,
				    list) {
@@ -7824,6 +7882,7 @@ devlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg,
				NLM_F_MULTI);
			if (err) {
				mutex_unlock(&devlink->reporters_lock);
				devl_unlock(devlink);
				devlink_put(devlink);
				state->idx = idx;
				goto out;
@@ -7832,10 +7891,6 @@ devlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg,
		}
		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) {