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))
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);
/* state held across netlink dumps */
struct devlink_nl_dump_state {
+ unsigned long instance;
int idx;
union {
/* DEVLINK_CMD_REGION_READ */
};
};
+/* 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);
{
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,
if (err)
goto out;
- idx++;
}
out:
- state->idx = idx;
return msg->len;
}
{
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,
devlink_put(devlink);
break;
}
-inc:
- idx++;
+
devlink_put(devlink);
}
if (err != -EMSGSIZE)
return err;
- state->idx = idx;
return msg->len;
}
{
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,
devlink_put(devlink);
break;
}
-inc:
- idx++;
devlink_put(devlink);
}
if (err != -EMSGSIZE)
return err;
- state->idx = idx;
return msg->len;
}