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