Skip to content

Commit 6bd4755

Browse files
committed
Merge branch 'devlink-unregister'
Jakub Kicinski says: ==================== devlink: remove the wait-for-references on unregister Move the registration and unregistration of the devlink instances under their instance locks. Don't perform the netdev-style wait for all references when unregistering the instance. Instead the devlink instance refcount will only ensure that the memory of the instance is not freed. All places which acquire access to devlink instances via a reference must check that the instance is still registered under the instance lock. This fixes the problem of the netdev code accessing devlink instances before they are registered. RFC: https://lore.kernel.org/all/20221217011953.152487-1-kuba@kernel.org/ - rewrite the cover letter - rewrite the commit message for patch 1 - un-export and rename devl_is_alive - squash the netdevsim patches ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
2 parents 6b754d7 + 82a3aef commit 6bd4755

File tree

6 files changed

+137
-112
lines changed

6 files changed

+137
-112
lines changed

drivers/net/netdevsim/dev.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1556,14 +1556,18 @@ int nsim_drv_probe(struct nsim_bus_dev *nsim_bus_dev)
15561556
goto err_devlink_unlock;
15571557
}
15581558

1559-
err = nsim_dev_resources_register(devlink);
1559+
err = devl_register(devlink);
15601560
if (err)
15611561
goto err_vfc_free;
15621562

1563+
err = nsim_dev_resources_register(devlink);
1564+
if (err)
1565+
goto err_dl_unregister;
1566+
15631567
err = devlink_params_register(devlink, nsim_devlink_params,
15641568
ARRAY_SIZE(nsim_devlink_params));
15651569
if (err)
1566-
goto err_dl_unregister;
1570+
goto err_resource_unregister;
15671571
nsim_devlink_set_params_init_values(nsim_dev, devlink);
15681572

15691573
err = nsim_dev_dummy_region_init(nsim_dev, devlink);
@@ -1607,7 +1611,6 @@ int nsim_drv_probe(struct nsim_bus_dev *nsim_bus_dev)
16071611
nsim_dev->esw_mode = DEVLINK_ESWITCH_MODE_LEGACY;
16081612
devlink_set_features(devlink, DEVLINK_F_RELOAD);
16091613
devl_unlock(devlink);
1610-
devlink_register(devlink);
16111614
return 0;
16121615

16131616
err_hwstats_exit:
@@ -1629,8 +1632,10 @@ int nsim_drv_probe(struct nsim_bus_dev *nsim_bus_dev)
16291632
err_params_unregister:
16301633
devlink_params_unregister(devlink, nsim_devlink_params,
16311634
ARRAY_SIZE(nsim_devlink_params));
1632-
err_dl_unregister:
1635+
err_resource_unregister:
16331636
devl_resources_unregister(devlink);
1637+
err_dl_unregister:
1638+
devl_unregister(devlink);
16341639
err_vfc_free:
16351640
kfree(nsim_dev->vfconfigs);
16361641
err_devlink_unlock:
@@ -1668,7 +1673,6 @@ void nsim_drv_remove(struct nsim_bus_dev *nsim_bus_dev)
16681673
struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev);
16691674
struct devlink *devlink = priv_to_devlink(nsim_dev);
16701675

1671-
devlink_unregister(devlink);
16721676
devl_lock(devlink);
16731677
nsim_dev_reload_destroy(nsim_dev);
16741678

@@ -1677,6 +1681,7 @@ void nsim_drv_remove(struct nsim_bus_dev *nsim_bus_dev)
16771681
devlink_params_unregister(devlink, nsim_devlink_params,
16781682
ARRAY_SIZE(nsim_devlink_params));
16791683
devl_resources_unregister(devlink);
1684+
devl_unregister(devlink);
16801685
kfree(nsim_dev->vfconfigs);
16811686
kfree(nsim_dev->fa_cookie);
16821687
devl_unlock(devlink);

include/net/devlink.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1647,6 +1647,8 @@ static inline struct devlink *devlink_alloc(const struct devlink_ops *ops,
16471647
return devlink_alloc_ns(ops, priv_size, &init_net, dev);
16481648
}
16491649
void devlink_set_features(struct devlink *devlink, u64 features);
1650+
int devl_register(struct devlink *devlink);
1651+
void devl_unregister(struct devlink *devlink);
16501652
void devlink_register(struct devlink *devlink);
16511653
void devlink_unregister(struct devlink *devlink);
16521654
void devlink_free(struct devlink *devlink);

net/devlink/core.c

Lines changed: 55 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -67,73 +67,51 @@ void devl_unlock(struct devlink *devlink)
6767
}
6868
EXPORT_SYMBOL_GPL(devl_unlock);
6969

70+
/**
71+
* devlink_try_get() - try to obtain a reference on a devlink instance
72+
* @devlink: instance to reference
73+
*
74+
* Obtain a reference on a devlink instance. A reference on a devlink instance
75+
* only implies that it's safe to take the instance lock. It does not imply
76+
* that the instance is registered, use devl_is_registered() after taking
77+
* the instance lock to check registration status.
78+
*/
7079
struct devlink *__must_check devlink_try_get(struct devlink *devlink)
7180
{
7281
if (refcount_inc_not_zero(&devlink->refcount))
7382
return devlink;
7483
return NULL;
7584
}
7685

77-
static void __devlink_put_rcu(struct rcu_head *head)
78-
{
79-
struct devlink *devlink = container_of(head, struct devlink, rcu);
80-
81-
complete(&devlink->comp);
82-
}
83-
8486
void devlink_put(struct devlink *devlink)
8587
{
8688
if (refcount_dec_and_test(&devlink->refcount))
87-
/* Make sure unregister operation that may await the completion
88-
* is unblocked only after all users are after the end of
89-
* RCU grace period.
90-
*/
91-
call_rcu(&devlink->rcu, __devlink_put_rcu);
89+
kfree_rcu(devlink, rcu);
9290
}
9391

94-
struct devlink *
95-
devlinks_xa_find_get(struct net *net, unsigned long *indexp,
96-
void * (*xa_find_fn)(struct xarray *, unsigned long *,
97-
unsigned long, xa_mark_t))
92+
struct devlink *devlinks_xa_find_get(struct net *net, unsigned long *indexp)
9893
{
99-
struct devlink *devlink;
94+
struct devlink *devlink = NULL;
10095

10196
rcu_read_lock();
10297
retry:
103-
devlink = xa_find_fn(&devlinks, indexp, ULONG_MAX, DEVLINK_REGISTERED);
98+
devlink = xa_find(&devlinks, indexp, ULONG_MAX, DEVLINK_REGISTERED);
10499
if (!devlink)
105100
goto unlock;
106101

107-
/* In case devlink_unregister() was already called and "unregistering"
108-
* mark was set, do not allow to get a devlink reference here.
109-
* This prevents live-lock of devlink_unregister() wait for completion.
110-
*/
111-
if (xa_get_mark(&devlinks, *indexp, DEVLINK_UNREGISTERING))
112-
goto retry;
113-
114-
/* For a possible retry, the xa_find_after() should be always used */
115-
xa_find_fn = xa_find_after;
116102
if (!devlink_try_get(devlink))
117-
goto retry;
103+
goto next;
118104
if (!net_eq(devlink_net(devlink), net)) {
119105
devlink_put(devlink);
120-
goto retry;
106+
goto next;
121107
}
122108
unlock:
123109
rcu_read_unlock();
124110
return devlink;
125-
}
126111

127-
struct devlink *
128-
devlinks_xa_find_get_first(struct net *net, unsigned long *indexp)
129-
{
130-
return devlinks_xa_find_get(net, indexp, xa_find);
131-
}
132-
133-
struct devlink *
134-
devlinks_xa_find_get_next(struct net *net, unsigned long *indexp)
135-
{
136-
return devlinks_xa_find_get(net, indexp, xa_find_after);
112+
next:
113+
(*indexp)++;
114+
goto retry;
137115
}
138116

139117
/**
@@ -147,46 +125,55 @@ devlinks_xa_find_get_next(struct net *net, unsigned long *indexp)
147125
*/
148126
void devlink_set_features(struct devlink *devlink, u64 features)
149127
{
150-
ASSERT_DEVLINK_NOT_REGISTERED(devlink);
151-
152128
WARN_ON(features & DEVLINK_F_RELOAD &&
153129
!devlink_reload_supported(devlink->ops));
154130
devlink->features = features;
155131
}
156132
EXPORT_SYMBOL_GPL(devlink_set_features);
157133

158134
/**
159-
* devlink_register - Register devlink instance
160-
*
161-
* @devlink: devlink
135+
* devl_register - Register devlink instance
136+
* @devlink: devlink
162137
*/
163-
void devlink_register(struct devlink *devlink)
138+
int devl_register(struct devlink *devlink)
164139
{
165140
ASSERT_DEVLINK_NOT_REGISTERED(devlink);
166-
/* Make sure that we are in .probe() routine */
141+
devl_assert_locked(devlink);
167142

168143
xa_set_mark(&devlinks, devlink->index, DEVLINK_REGISTERED);
169144
devlink_notify_register(devlink);
145+
146+
return 0;
147+
}
148+
EXPORT_SYMBOL_GPL(devl_register);
149+
150+
void devlink_register(struct devlink *devlink)
151+
{
152+
devl_lock(devlink);
153+
devl_register(devlink);
154+
devl_unlock(devlink);
170155
}
171156
EXPORT_SYMBOL_GPL(devlink_register);
172157

173158
/**
174-
* devlink_unregister - Unregister devlink instance
175-
*
176-
* @devlink: devlink
159+
* devl_unregister - Unregister devlink instance
160+
* @devlink: devlink
177161
*/
178-
void devlink_unregister(struct devlink *devlink)
162+
void devl_unregister(struct devlink *devlink)
179163
{
180164
ASSERT_DEVLINK_REGISTERED(devlink);
181-
/* Make sure that we are in .remove() routine */
182-
183-
xa_set_mark(&devlinks, devlink->index, DEVLINK_UNREGISTERING);
184-
devlink_put(devlink);
185-
wait_for_completion(&devlink->comp);
165+
devl_assert_locked(devlink);
186166

187167
devlink_notify_unregister(devlink);
188168
xa_clear_mark(&devlinks, devlink->index, DEVLINK_REGISTERED);
189-
xa_clear_mark(&devlinks, devlink->index, DEVLINK_UNREGISTERING);
169+
}
170+
EXPORT_SYMBOL_GPL(devl_unregister);
171+
172+
void devlink_unregister(struct devlink *devlink)
173+
{
174+
devl_lock(devlink);
175+
devl_unregister(devlink);
176+
devl_unlock(devlink);
190177
}
191178
EXPORT_SYMBOL_GPL(devlink_unregister);
192179

@@ -250,7 +237,6 @@ struct devlink *devlink_alloc_ns(const struct devlink_ops *ops,
250237
mutex_init(&devlink->reporters_lock);
251238
mutex_init(&devlink->linecards_lock);
252239
refcount_set(&devlink->refcount, 1);
253-
init_completion(&devlink->comp);
254240

255241
return devlink;
256242

@@ -296,7 +282,7 @@ void devlink_free(struct devlink *devlink)
296282

297283
xa_erase(&devlinks, devlink->index);
298284

299-
kfree(devlink);
285+
devlink_put(devlink);
300286
}
301287
EXPORT_SYMBOL_GPL(devlink_free);
302288

@@ -312,15 +298,18 @@ static void __net_exit devlink_pernet_pre_exit(struct net *net)
312298
*/
313299
devlinks_xa_for_each_registered_get(net, index, devlink) {
314300
WARN_ON(!(devlink->features & DEVLINK_F_RELOAD));
315-
mutex_lock(&devlink->lock);
316-
err = devlink_reload(devlink, &init_net,
317-
DEVLINK_RELOAD_ACTION_DRIVER_REINIT,
318-
DEVLINK_RELOAD_LIMIT_UNSPEC,
319-
&actions_performed, NULL);
320-
mutex_unlock(&devlink->lock);
301+
devl_lock(devlink);
302+
err = 0;
303+
if (devl_is_registered(devlink))
304+
err = devlink_reload(devlink, &init_net,
305+
DEVLINK_RELOAD_ACTION_DRIVER_REINIT,
306+
DEVLINK_RELOAD_LIMIT_UNSPEC,
307+
&actions_performed, NULL);
308+
devl_unlock(devlink);
309+
devlink_put(devlink);
310+
321311
if (err && err != -EOPNOTSUPP)
322312
pr_warn("Failed to reload devlink instance into init_net\n");
323-
devlink_put(devlink);
324313
}
325314
}
326315

net/devlink/devl_internal.h

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
#include <net/net_namespace.h>
1313

1414
#define DEVLINK_REGISTERED XA_MARK_1
15-
#define DEVLINK_UNREGISTERING XA_MARK_2
1615

1716
#define DEVLINK_RELOAD_STATS_ARRAY_SIZE \
1817
(__DEVLINK_RELOAD_LIMIT_MAX * __DEVLINK_RELOAD_ACTION_MAX)
@@ -52,7 +51,6 @@ struct devlink {
5251
struct lock_class_key lock_key;
5352
u8 reload_failed:1;
5453
refcount_t refcount;
55-
struct completion comp;
5654
struct rcu_head rcu;
5755
struct notifier_block netdevice_nb;
5856
char priv[] __aligned(NETDEV_ALIGN);
@@ -82,18 +80,17 @@ extern struct genl_family devlink_nl_family;
8280
* in loop body in order to release the reference.
8381
*/
8482
#define devlinks_xa_for_each_registered_get(net, index, devlink) \
85-
for (index = 0, \
86-
devlink = devlinks_xa_find_get_first(net, &index); \
87-
devlink; devlink = devlinks_xa_find_get_next(net, &index))
83+
for (index = 0; (devlink = devlinks_xa_find_get(net, &index)); index++)
8884

89-
struct devlink *
90-
devlinks_xa_find_get(struct net *net, unsigned long *indexp,
91-
void * (*xa_find_fn)(struct xarray *, unsigned long *,
92-
unsigned long, xa_mark_t));
93-
struct devlink *
94-
devlinks_xa_find_get_first(struct net *net, unsigned long *indexp);
95-
struct devlink *
96-
devlinks_xa_find_get_next(struct net *net, unsigned long *indexp);
85+
struct devlink *devlinks_xa_find_get(struct net *net, unsigned long *indexp);
86+
87+
static inline bool devl_is_registered(struct devlink *devlink)
88+
{
89+
/* To prevent races the caller must hold the instance lock
90+
* or another lock taken during unregistration.
91+
*/
92+
return xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED);
93+
}
9794

9895
/* Netlink */
9996
#define DEVLINK_NL_FLAG_NEED_PORT BIT(0)
@@ -135,12 +132,13 @@ struct devlink_gen_cmd {
135132
*/
136133
#define devlink_dump_for_each_instance_get(msg, state, devlink) \
137134
for (; (devlink = devlinks_xa_find_get(sock_net(msg->sk), \
138-
&state->instance, xa_find)); \
135+
&state->instance)); \
139136
state->instance++, state->idx = 0)
140137

141138
extern const struct genl_small_ops devlink_nl_ops[56];
142139

143-
struct devlink *devlink_get_from_attrs(struct net *net, struct nlattr **attrs);
140+
struct devlink *
141+
devlink_get_from_attrs_lock(struct net *net, struct nlattr **attrs);
144142

145143
void devlink_notify_unregister(struct devlink *devlink);
146144
void devlink_notify_register(struct devlink *devlink);

0 commit comments

Comments
 (0)