diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/devlink/core.c | 2 | ||||
-rw-r--r-- | net/devlink/devl_internal.h | 16 | ||||
-rw-r--r-- | net/devlink/leftover.c | 36 |
3 files changed, 25 insertions, 29 deletions
diff --git a/net/devlink/core.c b/net/devlink/core.c index 3a99bf84632e..371d6821315d 100644 --- a/net/devlink/core.c +++ b/net/devlink/core.c @@ -91,7 +91,7 @@ void devlink_put(struct devlink *devlink) call_rcu(&devlink->rcu, __devlink_put_rcu); } -static struct devlink * +struct devlink * devlinks_xa_find_get(struct net *net, unsigned long *indexp, void * (*xa_find_fn)(struct xarray *, unsigned long *, unsigned long, xa_mark_t)) diff --git a/net/devlink/devl_internal.h b/net/devlink/devl_internal.h index 86b321aef3eb..b9bb6f73a7c1 100644 --- a/net/devlink/devl_internal.h +++ b/net/devlink/devl_internal.h @@ -87,6 +87,10 @@ extern struct genl_family devlink_nl_family; devlink; devlink = devlinks_xa_find_get_next(net, &index)) struct devlink * +devlinks_xa_find_get(struct net *net, unsigned long *indexp, + void * (*xa_find_fn)(struct xarray *, unsigned long *, + unsigned long, xa_mark_t)); +struct devlink * devlinks_xa_find_get_first(struct net *net, unsigned long *indexp); struct devlink * devlinks_xa_find_get_next(struct net *net, unsigned long *indexp); @@ -104,6 +108,7 @@ enum devlink_multicast_groups { /* state held across netlink dumps */ struct devlink_nl_dump_state { + unsigned long instance; int idx; union { /* DEVLINK_CMD_REGION_READ */ @@ -117,6 +122,17 @@ struct devlink_nl_dump_state { }; }; +/* 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, xa_find)); \ + state->instance++) + extern const struct genl_small_ops devlink_nl_ops[56]; struct devlink *devlink_get_from_attrs(struct net *net, struct nlattr **attrs); diff --git a/net/devlink/leftover.c b/net/devlink/leftover.c index 83cd7bd55941..db7c095a0d75 100644 --- a/net/devlink/leftover.c +++ b/net/devlink/leftover.c @@ -1319,17 +1319,9 @@ static int devlink_nl_cmd_get_dumpit(struct sk_buff *msg, { struct devlink_nl_dump_state *state = devlink_dump_state(cb); struct devlink *devlink; - unsigned long index; - int idx = 0; int err; - devlinks_xa_for_each_registered_get(sock_net(msg->sk), index, devlink) { - if (idx < state->idx) { - idx++; - devlink_put(devlink); - continue; - } - + devlink_dump_for_each_instance_get(msg, state, devlink) { devl_lock(devlink); err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW, NETLINK_CB(cb->skb).portid, @@ -1339,10 +1331,8 @@ static int devlink_nl_cmd_get_dumpit(struct sk_buff *msg, if (err) goto out; - idx++; } out: - state->idx = idx; return msg->len; } @@ -4872,13 +4862,13 @@ static int devlink_nl_cmd_selftests_get_dumpit(struct sk_buff *msg, { struct devlink_nl_dump_state *state = devlink_dump_state(cb); struct devlink *devlink; - unsigned long index; - int idx = 0; int err = 0; - devlinks_xa_for_each_registered_get(sock_net(msg->sk), index, devlink) { - if (idx < state->idx || !devlink->ops->selftest_check) - goto inc; + devlink_dump_for_each_instance_get(msg, state, devlink) { + if (!devlink->ops->selftest_check) { + devlink_put(devlink); + continue; + } devl_lock(devlink); err = devlink_nl_selftests_fill(msg, devlink, @@ -4890,15 +4880,13 @@ static int devlink_nl_cmd_selftests_get_dumpit(struct sk_buff *msg, devlink_put(devlink); break; } -inc: - idx++; + devlink_put(devlink); } if (err != -EMSGSIZE) return err; - state->idx = idx; return msg->len; } @@ -6747,14 +6735,9 @@ static int devlink_nl_cmd_info_get_dumpit(struct sk_buff *msg, { struct devlink_nl_dump_state *state = devlink_dump_state(cb); struct devlink *devlink; - unsigned long index; - int idx = 0; int err = 0; - devlinks_xa_for_each_registered_get(sock_net(msg->sk), index, devlink) { - if (idx < state->idx) - goto inc; - + devlink_dump_for_each_instance_get(msg, state, devlink) { devl_lock(devlink); err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET, NETLINK_CB(cb->skb).portid, @@ -6767,15 +6750,12 @@ static int devlink_nl_cmd_info_get_dumpit(struct sk_buff *msg, devlink_put(devlink); break; } -inc: - idx++; devlink_put(devlink); } if (err != -EMSGSIZE) return err; - state->idx = idx; return msg->len; } |