devlink: add by-instance dump infra
Most dumpit implementations walk the devlink instances. This requires careful lock taking and reference dropping. Factor the loop out and provide just a callback to handle a single instance dump. Convert one user as an example, other users converted in the next change. Slightly inspired by ethtool netlink code. Reviewed-by: Jacob Keller <jacob.e.keller@intel.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
e4d5015bc1
commit
07f3af6608
@ -122,6 +122,11 @@ struct devlink_nl_dump_state {
|
||||
};
|
||||
};
|
||||
|
||||
struct devlink_gen_cmd {
|
||||
int (*dump_one)(struct sk_buff *msg, struct devlink *devlink,
|
||||
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.
|
||||
@ -140,6 +145,9 @@ struct devlink *devlink_get_from_attrs(struct net *net, struct nlattr **attrs);
|
||||
void devlink_notify_unregister(struct devlink *devlink);
|
||||
void devlink_notify_register(struct devlink *devlink);
|
||||
|
||||
int devlink_nl_instance_iter_dump(struct sk_buff *msg,
|
||||
struct netlink_callback *cb);
|
||||
|
||||
static inline struct devlink_nl_dump_state *
|
||||
devlink_dump_state(struct netlink_callback *cb)
|
||||
{
|
||||
@ -175,6 +183,8 @@ 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;
|
||||
|
||||
struct devlink_rate *
|
||||
devlink_rate_get_from_info(struct devlink *devlink, struct genl_info *info);
|
||||
struct devlink_rate *
|
||||
|
@ -1219,47 +1219,40 @@ static void devlink_rate_notify(struct devlink_rate *devlink_rate,
|
||||
0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
|
||||
}
|
||||
|
||||
static int devlink_nl_cmd_rate_get_dumpit(struct sk_buff *msg,
|
||||
struct netlink_callback *cb)
|
||||
static int
|
||||
devlink_nl_cmd_rate_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_rate *devlink_rate;
|
||||
int idx = 0;
|
||||
int err = 0;
|
||||
|
||||
devlink_dump_for_each_instance_get(msg, state, devlink) {
|
||||
struct devlink_rate *devlink_rate;
|
||||
int idx = 0;
|
||||
list_for_each_entry(devlink_rate, &devlink->rate_list, list) {
|
||||
enum devlink_command cmd = DEVLINK_CMD_RATE_NEW;
|
||||
u32 id = NETLINK_CB(cb->skb).portid;
|
||||
|
||||
devl_lock(devlink);
|
||||
list_for_each_entry(devlink_rate, &devlink->rate_list, list) {
|
||||
enum devlink_command cmd = DEVLINK_CMD_RATE_NEW;
|
||||
u32 id = NETLINK_CB(cb->skb).portid;
|
||||
|
||||
if (idx < state->idx) {
|
||||
idx++;
|
||||
continue;
|
||||
}
|
||||
err = devlink_nl_rate_fill(msg, devlink_rate, cmd, id,
|
||||
cb->nlh->nlmsg_seq,
|
||||
NLM_F_MULTI, NULL);
|
||||
if (err) {
|
||||
devl_unlock(devlink);
|
||||
devlink_put(devlink);
|
||||
state->idx = idx;
|
||||
goto out;
|
||||
}
|
||||
if (idx < state->idx) {
|
||||
idx++;
|
||||
continue;
|
||||
}
|
||||
devl_unlock(devlink);
|
||||
devlink_put(devlink);
|
||||
err = devlink_nl_rate_fill(msg, devlink_rate, cmd, id,
|
||||
cb->nlh->nlmsg_seq,
|
||||
NLM_F_MULTI, NULL);
|
||||
if (err) {
|
||||
state->idx = idx;
|
||||
break;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
out:
|
||||
if (err != -EMSGSIZE)
|
||||
return err;
|
||||
|
||||
return msg->len;
|
||||
return err;
|
||||
}
|
||||
|
||||
const struct devlink_gen_cmd devl_gen_rate_get = {
|
||||
.dump_one = devlink_nl_cmd_rate_get_dump_one,
|
||||
};
|
||||
|
||||
static int devlink_nl_cmd_rate_get_doit(struct sk_buff *skb,
|
||||
struct genl_info *info)
|
||||
{
|
||||
@ -9130,7 +9123,7 @@ const struct genl_small_ops devlink_nl_ops[56] = {
|
||||
{
|
||||
.cmd = DEVLINK_CMD_RATE_GET,
|
||||
.doit = devlink_nl_cmd_rate_get_doit,
|
||||
.dumpit = devlink_nl_cmd_rate_get_dumpit,
|
||||
.dumpit = devlink_nl_instance_iter_dump,
|
||||
.internal_flags = DEVLINK_NL_FLAG_NEED_RATE,
|
||||
/* can be retrieved by unprivileged users */
|
||||
},
|
||||
|
@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include <net/genetlink.h>
|
||||
#include <net/sock.h>
|
||||
|
||||
#include "devl_internal.h"
|
||||
|
||||
@ -177,6 +178,39 @@ static void devlink_nl_post_doit(const struct genl_split_ops *ops,
|
||||
devlink_put(devlink);
|
||||
}
|
||||
|
||||
static const struct devlink_gen_cmd *devl_gen_cmds[] = {
|
||||
[DEVLINK_CMD_RATE_GET] = &devl_gen_rate_get,
|
||||
};
|
||||
|
||||
int devlink_nl_instance_iter_dump(struct sk_buff *msg,
|
||||
struct netlink_callback *cb)
|
||||
{
|
||||
const struct genl_dumpit_info *info = genl_dumpit_info(cb);
|
||||
struct devlink_nl_dump_state *state = devlink_dump_state(cb);
|
||||
const struct devlink_gen_cmd *cmd;
|
||||
struct devlink *devlink;
|
||||
int err = 0;
|
||||
|
||||
cmd = devl_gen_cmds[info->op.cmd];
|
||||
|
||||
devlink_dump_for_each_instance_get(msg, state, devlink) {
|
||||
devl_lock(devlink);
|
||||
err = cmd->dump_one(msg, devlink, cb);
|
||||
devl_unlock(devlink);
|
||||
devlink_put(devlink);
|
||||
|
||||
if (err)
|
||||
break;
|
||||
|
||||
/* restart sub-object walk for the next instance */
|
||||
state->idx = 0;
|
||||
}
|
||||
|
||||
if (err != -EMSGSIZE)
|
||||
return err;
|
||||
return msg->len;
|
||||
}
|
||||
|
||||
struct genl_family devlink_nl_family __ro_after_init = {
|
||||
.name = DEVLINK_GENL_NAME,
|
||||
.version = DEVLINK_GENL_VERSION,
|
||||
|
Loading…
x
Reference in New Issue
Block a user