summaryrefslogtreecommitdiff
path: root/net/devlink/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/devlink/core.c')
-rw-r--r--net/devlink/core.c121
1 files changed, 55 insertions, 66 deletions
diff --git a/net/devlink/core.c b/net/devlink/core.c
index 371d6821315d..a31a317626d7 100644
--- a/net/devlink/core.c
+++ b/net/devlink/core.c
@@ -67,6 +67,15 @@ void devl_unlock(struct devlink *devlink)
}
EXPORT_SYMBOL_GPL(devl_unlock);
+/**
+ * devlink_try_get() - try to obtain a reference on a devlink instance
+ * @devlink: instance to reference
+ *
+ * Obtain a reference on a devlink instance. A reference on a devlink instance
+ * only implies that it's safe to take the instance lock. It does not imply
+ * that the instance is registered, use devl_is_registered() after taking
+ * the instance lock to check registration status.
+ */
struct devlink *__must_check devlink_try_get(struct devlink *devlink)
{
if (refcount_inc_not_zero(&devlink->refcount))
@@ -74,66 +83,35 @@ struct devlink *__must_check devlink_try_get(struct devlink *devlink)
return NULL;
}
-static void __devlink_put_rcu(struct rcu_head *head)
-{
- struct devlink *devlink = container_of(head, struct devlink, rcu);
-
- complete(&devlink->comp);
-}
-
void devlink_put(struct devlink *devlink)
{
if (refcount_dec_and_test(&devlink->refcount))
- /* Make sure unregister operation that may await the completion
- * is unblocked only after all users are after the end of
- * RCU grace period.
- */
- call_rcu(&devlink->rcu, __devlink_put_rcu);
+ kfree_rcu(devlink, rcu);
}
-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(struct net *net, unsigned long *indexp)
{
- struct devlink *devlink;
+ struct devlink *devlink = NULL;
rcu_read_lock();
retry:
- devlink = xa_find_fn(&devlinks, indexp, ULONG_MAX, DEVLINK_REGISTERED);
+ devlink = xa_find(&devlinks, indexp, ULONG_MAX, DEVLINK_REGISTERED);
if (!devlink)
goto unlock;
- /* In case devlink_unregister() was already called and "unregistering"
- * mark was set, do not allow to get a devlink reference here.
- * This prevents live-lock of devlink_unregister() wait for completion.
- */
- if (xa_get_mark(&devlinks, *indexp, DEVLINK_UNREGISTERING))
- goto retry;
-
- /* For a possible retry, the xa_find_after() should be always used */
- xa_find_fn = xa_find_after;
if (!devlink_try_get(devlink))
- goto retry;
+ goto next;
if (!net_eq(devlink_net(devlink), net)) {
devlink_put(devlink);
- goto retry;
+ goto next;
}
unlock:
rcu_read_unlock();
return devlink;
-}
-struct devlink *
-devlinks_xa_find_get_first(struct net *net, unsigned long *indexp)
-{
- return devlinks_xa_find_get(net, indexp, xa_find);
-}
-
-struct devlink *
-devlinks_xa_find_get_next(struct net *net, unsigned long *indexp)
-{
- return devlinks_xa_find_get(net, indexp, xa_find_after);
+next:
+ (*indexp)++;
+ goto retry;
}
/**
@@ -147,8 +125,6 @@ devlinks_xa_find_get_next(struct net *net, unsigned long *indexp)
*/
void devlink_set_features(struct devlink *devlink, u64 features)
{
- ASSERT_DEVLINK_NOT_REGISTERED(devlink);
-
WARN_ON(features & DEVLINK_F_RELOAD &&
!devlink_reload_supported(devlink->ops));
devlink->features = features;
@@ -156,37 +132,48 @@ void devlink_set_features(struct devlink *devlink, u64 features)
EXPORT_SYMBOL_GPL(devlink_set_features);
/**
- * devlink_register - Register devlink instance
- *
- * @devlink: devlink
+ * devl_register - Register devlink instance
+ * @devlink: devlink
*/
-void devlink_register(struct devlink *devlink)
+int devl_register(struct devlink *devlink)
{
ASSERT_DEVLINK_NOT_REGISTERED(devlink);
- /* Make sure that we are in .probe() routine */
+ devl_assert_locked(devlink);
xa_set_mark(&devlinks, devlink->index, DEVLINK_REGISTERED);
devlink_notify_register(devlink);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(devl_register);
+
+void devlink_register(struct devlink *devlink)
+{
+ devl_lock(devlink);
+ devl_register(devlink);
+ devl_unlock(devlink);
}
EXPORT_SYMBOL_GPL(devlink_register);
/**
- * devlink_unregister - Unregister devlink instance
- *
- * @devlink: devlink
+ * devl_unregister - Unregister devlink instance
+ * @devlink: devlink
*/
-void devlink_unregister(struct devlink *devlink)
+void devl_unregister(struct devlink *devlink)
{
ASSERT_DEVLINK_REGISTERED(devlink);
- /* Make sure that we are in .remove() routine */
-
- xa_set_mark(&devlinks, devlink->index, DEVLINK_UNREGISTERING);
- devlink_put(devlink);
- wait_for_completion(&devlink->comp);
+ devl_assert_locked(devlink);
devlink_notify_unregister(devlink);
xa_clear_mark(&devlinks, devlink->index, DEVLINK_REGISTERED);
- xa_clear_mark(&devlinks, devlink->index, DEVLINK_UNREGISTERING);
+}
+EXPORT_SYMBOL_GPL(devl_unregister);
+
+void devlink_unregister(struct devlink *devlink)
+{
+ devl_lock(devlink);
+ devl_unregister(devlink);
+ devl_unlock(devlink);
}
EXPORT_SYMBOL_GPL(devlink_unregister);
@@ -250,7 +237,6 @@ struct devlink *devlink_alloc_ns(const struct devlink_ops *ops,
mutex_init(&devlink->reporters_lock);
mutex_init(&devlink->linecards_lock);
refcount_set(&devlink->refcount, 1);
- init_completion(&devlink->comp);
return devlink;
@@ -296,7 +282,7 @@ void devlink_free(struct devlink *devlink)
xa_erase(&devlinks, devlink->index);
- kfree(devlink);
+ devlink_put(devlink);
}
EXPORT_SYMBOL_GPL(devlink_free);
@@ -312,15 +298,18 @@ static void __net_exit devlink_pernet_pre_exit(struct net *net)
*/
devlinks_xa_for_each_registered_get(net, index, devlink) {
WARN_ON(!(devlink->features & DEVLINK_F_RELOAD));
- mutex_lock(&devlink->lock);
- err = devlink_reload(devlink, &init_net,
- DEVLINK_RELOAD_ACTION_DRIVER_REINIT,
- DEVLINK_RELOAD_LIMIT_UNSPEC,
- &actions_performed, NULL);
- mutex_unlock(&devlink->lock);
+ devl_lock(devlink);
+ err = 0;
+ if (devl_is_registered(devlink))
+ err = devlink_reload(devlink, &init_net,
+ DEVLINK_RELOAD_ACTION_DRIVER_REINIT,
+ DEVLINK_RELOAD_LIMIT_UNSPEC,
+ &actions_performed, NULL);
+ devl_unlock(devlink);
+ devlink_put(devlink);
+
if (err && err != -EOPNOTSUPP)
pr_warn("Failed to reload devlink instance into init_net\n");
- devlink_put(devlink);
}
}