Skip to content

Commit c0d378e

Browse files
congwangdavem330
authored andcommitted
net_sched: use tcf_queue_work() in u32 filter
Defer the tcf_exts_destroy() in RCU callback to tc filter workqueue and get RTNL lock. Reported-by: Chris Mi <[email protected]> Cc: Daniel Borkmann <[email protected]> Cc: Jiri Pirko <[email protected]> Cc: John Fastabend <[email protected]> Cc: Jamal Hadi Salim <[email protected]> Cc: "Paul E. McKenney" <[email protected]> Signed-off-by: Cong Wang <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent df2735e commit c0d378e

File tree

1 file changed

+26
-3
lines changed

1 file changed

+26
-3
lines changed

net/sched/cls_u32.c

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,10 @@ struct tc_u_knode {
6868
u32 __percpu *pcpu_success;
6969
#endif
7070
struct tcf_proto *tp;
71-
struct rcu_head rcu;
71+
union {
72+
struct work_struct work;
73+
struct rcu_head rcu;
74+
};
7275
/* The 'sel' field MUST be the last field in structure to allow for
7376
* tc_u32_keys allocated at end of structure.
7477
*/
@@ -418,11 +421,21 @@ static int u32_destroy_key(struct tcf_proto *tp, struct tc_u_knode *n,
418421
* this the u32_delete_key_rcu variant does not free the percpu
419422
* statistics.
420423
*/
424+
static void u32_delete_key_work(struct work_struct *work)
425+
{
426+
struct tc_u_knode *key = container_of(work, struct tc_u_knode, work);
427+
428+
rtnl_lock();
429+
u32_destroy_key(key->tp, key, false);
430+
rtnl_unlock();
431+
}
432+
421433
static void u32_delete_key_rcu(struct rcu_head *rcu)
422434
{
423435
struct tc_u_knode *key = container_of(rcu, struct tc_u_knode, rcu);
424436

425-
u32_destroy_key(key->tp, key, false);
437+
INIT_WORK(&key->work, u32_delete_key_work);
438+
tcf_queue_work(&key->work);
426439
}
427440

428441
/* u32_delete_key_freepf_rcu is the rcu callback variant
@@ -432,11 +445,21 @@ static void u32_delete_key_rcu(struct rcu_head *rcu)
432445
* for the variant that should be used with keys return from
433446
* u32_init_knode()
434447
*/
448+
static void u32_delete_key_freepf_work(struct work_struct *work)
449+
{
450+
struct tc_u_knode *key = container_of(work, struct tc_u_knode, work);
451+
452+
rtnl_lock();
453+
u32_destroy_key(key->tp, key, true);
454+
rtnl_unlock();
455+
}
456+
435457
static void u32_delete_key_freepf_rcu(struct rcu_head *rcu)
436458
{
437459
struct tc_u_knode *key = container_of(rcu, struct tc_u_knode, rcu);
438460

439-
u32_destroy_key(key->tp, key, true);
461+
INIT_WORK(&key->work, u32_delete_key_freepf_work);
462+
tcf_queue_work(&key->work);
440463
}
441464

442465
static int u32_delete_key(struct tcf_proto *tp, struct tc_u_knode *key)

0 commit comments

Comments
 (0)