mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-27 03:10:12 +00:00
devlink: Add health reporter create/destroy functionality
Devlink health reporter is an instance for reporting, diagnosing and recovering from run time errors discovered by the reporters. Define it's data structure and supported operations. In addition, expose devlink API to create and destroy a reporter. Each devlink instance will hold it's own reporters list. As part of the allocation, driver shall provide a set of callbacks which will be used by devlink in order to handle health reports and user commands related to this reporter. In addition, driver is entitled to provide some priv pointer, which can be fetched from the reporter by devlink_health_reporter_priv function. For each reporter, devlink will hold a metadata of statistics, dump msg and status. For passing dumps and diagnose data to the user-space, it will use devlink fmsg API. Signed-off-by: Eran Ben Elisha <eranbe@mellanox.com> Reviewed-by: Moshe Shemesh <moshe@mellanox.com> Acked-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
1db64e8733
commit
a0bdcc59d1
2 changed files with 145 additions and 0 deletions
|
@ -30,6 +30,7 @@ struct devlink {
|
|||
struct list_head param_list;
|
||||
struct list_head region_list;
|
||||
u32 snapshot_id;
|
||||
struct list_head reporter_list;
|
||||
struct devlink_dpipe_headers *dpipe_headers;
|
||||
const struct devlink_ops *ops;
|
||||
struct device *dev;
|
||||
|
@ -449,6 +450,27 @@ struct devlink_info_req;
|
|||
typedef void devlink_snapshot_data_dest_t(const void *data);
|
||||
|
||||
struct devlink_fmsg;
|
||||
struct devlink_health_reporter;
|
||||
|
||||
/**
|
||||
* struct devlink_health_reporter_ops - Reporter operations
|
||||
* @name: reporter name
|
||||
* @recover: callback to recover from reported error
|
||||
* if priv_ctx is NULL, run a full recover
|
||||
* @dump: callback to dump an object
|
||||
* if priv_ctx is NULL, run a full dump
|
||||
* @diagnose: callback to diagnose the current status
|
||||
*/
|
||||
|
||||
struct devlink_health_reporter_ops {
|
||||
char *name;
|
||||
int (*recover)(struct devlink_health_reporter *reporter,
|
||||
void *priv_ctx);
|
||||
int (*dump)(struct devlink_health_reporter *reporter,
|
||||
struct devlink_fmsg *fmsg, void *priv_ctx);
|
||||
int (*diagnose)(struct devlink_health_reporter *reporter,
|
||||
struct devlink_fmsg *fmsg);
|
||||
};
|
||||
|
||||
struct devlink_ops {
|
||||
int (*reload)(struct devlink *devlink, struct netlink_ext_ack *extack);
|
||||
|
@ -672,6 +694,17 @@ int devlink_fmsg_string_pair_put(struct devlink_fmsg *fmsg, const char *name,
|
|||
int devlink_fmsg_binary_pair_put(struct devlink_fmsg *fmsg, const char *name,
|
||||
const void *value, u16 value_len);
|
||||
|
||||
struct devlink_health_reporter *
|
||||
devlink_health_reporter_create(struct devlink *devlink,
|
||||
const struct devlink_health_reporter_ops *ops,
|
||||
u64 graceful_period, bool auto_recover,
|
||||
void *priv);
|
||||
void
|
||||
devlink_health_reporter_destroy(struct devlink_health_reporter *reporter);
|
||||
|
||||
void *
|
||||
devlink_health_reporter_priv(struct devlink_health_reporter *reporter);
|
||||
|
||||
#else
|
||||
|
||||
static inline struct devlink *devlink_alloc(const struct devlink_ops *ops,
|
||||
|
@ -1120,6 +1153,26 @@ devlink_fmsg_binary_pair_put(struct devlink_fmsg *fmsg, const char *name,
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct devlink_health_reporter *
|
||||
devlink_health_reporter_create(struct devlink *devlink,
|
||||
const struct devlink_health_reporter_ops *ops,
|
||||
u64 graceful_period, bool auto_recover,
|
||||
void *priv)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void
|
||||
devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void *
|
||||
devlink_health_reporter_priv(struct devlink_health_reporter *reporter)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if IS_REACHABLE(CONFIG_NET_DEVLINK)
|
||||
|
|
|
@ -4362,6 +4362,97 @@ static int devlink_fmsg_snd(struct devlink_fmsg *fmsg,
|
|||
return err;
|
||||
}
|
||||
|
||||
struct devlink_health_reporter {
|
||||
struct list_head list;
|
||||
void *priv;
|
||||
const struct devlink_health_reporter_ops *ops;
|
||||
struct devlink *devlink;
|
||||
u64 graceful_period;
|
||||
bool auto_recover;
|
||||
u8 health_state;
|
||||
};
|
||||
|
||||
void *
|
||||
devlink_health_reporter_priv(struct devlink_health_reporter *reporter)
|
||||
{
|
||||
return reporter->priv;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devlink_health_reporter_priv);
|
||||
|
||||
static struct devlink_health_reporter *
|
||||
devlink_health_reporter_find_by_name(struct devlink *devlink,
|
||||
const char *reporter_name)
|
||||
{
|
||||
struct devlink_health_reporter *reporter;
|
||||
|
||||
list_for_each_entry(reporter, &devlink->reporter_list, list)
|
||||
if (!strcmp(reporter->ops->name, reporter_name))
|
||||
return reporter;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* devlink_health_reporter_create - create devlink health reporter
|
||||
*
|
||||
* @devlink: devlink
|
||||
* @ops: ops
|
||||
* @graceful_period: to avoid recovery loops, in msecs
|
||||
* @auto_recover: auto recover when error occurs
|
||||
* @priv: priv
|
||||
*/
|
||||
struct devlink_health_reporter *
|
||||
devlink_health_reporter_create(struct devlink *devlink,
|
||||
const struct devlink_health_reporter_ops *ops,
|
||||
u64 graceful_period, bool auto_recover,
|
||||
void *priv)
|
||||
{
|
||||
struct devlink_health_reporter *reporter;
|
||||
|
||||
mutex_lock(&devlink->lock);
|
||||
if (devlink_health_reporter_find_by_name(devlink, ops->name)) {
|
||||
reporter = ERR_PTR(-EEXIST);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (WARN_ON(auto_recover && !ops->recover) ||
|
||||
WARN_ON(graceful_period && !ops->recover)) {
|
||||
reporter = ERR_PTR(-EINVAL);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
reporter = kzalloc(sizeof(*reporter), GFP_KERNEL);
|
||||
if (!reporter) {
|
||||
reporter = ERR_PTR(-ENOMEM);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
reporter->priv = priv;
|
||||
reporter->ops = ops;
|
||||
reporter->devlink = devlink;
|
||||
reporter->graceful_period = graceful_period;
|
||||
reporter->auto_recover = auto_recover;
|
||||
list_add_tail(&reporter->list, &devlink->reporter_list);
|
||||
unlock:
|
||||
mutex_unlock(&devlink->lock);
|
||||
return reporter;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devlink_health_reporter_create);
|
||||
|
||||
/**
|
||||
* devlink_health_reporter_destroy - destroy devlink health reporter
|
||||
*
|
||||
* @reporter: devlink health reporter to destroy
|
||||
*/
|
||||
void
|
||||
devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
|
||||
{
|
||||
mutex_lock(&reporter->devlink->lock);
|
||||
list_del(&reporter->list);
|
||||
mutex_unlock(&reporter->devlink->lock);
|
||||
kfree(reporter);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devlink_health_reporter_destroy);
|
||||
|
||||
static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
|
||||
[DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING },
|
||||
[DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING },
|
||||
|
@ -4670,6 +4761,7 @@ struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size)
|
|||
INIT_LIST_HEAD(&devlink->resource_list);
|
||||
INIT_LIST_HEAD(&devlink->param_list);
|
||||
INIT_LIST_HEAD(&devlink->region_list);
|
||||
INIT_LIST_HEAD(&devlink->reporter_list);
|
||||
mutex_init(&devlink->lock);
|
||||
return devlink;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue