diff options
Diffstat (limited to 'net/sched/cls_u32.c')
-rw-r--r-- | net/sched/cls_u32.c | 37 |
1 files changed, 10 insertions, 27 deletions
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index bac47b5d18fd..fb861f90fde6 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c | |||
@@ -68,10 +68,7 @@ struct tc_u_knode { | |||
68 | u32 __percpu *pcpu_success; | 68 | u32 __percpu *pcpu_success; |
69 | #endif | 69 | #endif |
70 | struct tcf_proto *tp; | 70 | struct tcf_proto *tp; |
71 | union { | 71 | struct rcu_work rwork; |
72 | struct work_struct work; | ||
73 | struct rcu_head rcu; | ||
74 | }; | ||
75 | /* The 'sel' field MUST be the last field in structure to allow for | 72 | /* The 'sel' field MUST be the last field in structure to allow for |
76 | * tc_u32_keys allocated at end of structure. | 73 | * tc_u32_keys allocated at end of structure. |
77 | */ | 74 | */ |
@@ -436,21 +433,14 @@ static int u32_destroy_key(struct tcf_proto *tp, struct tc_u_knode *n, | |||
436 | */ | 433 | */ |
437 | static void u32_delete_key_work(struct work_struct *work) | 434 | static void u32_delete_key_work(struct work_struct *work) |
438 | { | 435 | { |
439 | struct tc_u_knode *key = container_of(work, struct tc_u_knode, work); | 436 | struct tc_u_knode *key = container_of(to_rcu_work(work), |
440 | 437 | struct tc_u_knode, | |
438 | rwork); | ||
441 | rtnl_lock(); | 439 | rtnl_lock(); |
442 | u32_destroy_key(key->tp, key, false); | 440 | u32_destroy_key(key->tp, key, false); |
443 | rtnl_unlock(); | 441 | rtnl_unlock(); |
444 | } | 442 | } |
445 | 443 | ||
446 | static void u32_delete_key_rcu(struct rcu_head *rcu) | ||
447 | { | ||
448 | struct tc_u_knode *key = container_of(rcu, struct tc_u_knode, rcu); | ||
449 | |||
450 | INIT_WORK(&key->work, u32_delete_key_work); | ||
451 | tcf_queue_work(&key->work); | ||
452 | } | ||
453 | |||
454 | /* u32_delete_key_freepf_rcu is the rcu callback variant | 444 | /* u32_delete_key_freepf_rcu is the rcu callback variant |
455 | * that free's the entire structure including the statistics | 445 | * that free's the entire structure including the statistics |
456 | * percpu variables. Only use this if the key is not a copy | 446 | * percpu variables. Only use this if the key is not a copy |
@@ -460,21 +450,14 @@ static void u32_delete_key_rcu(struct rcu_head *rcu) | |||
460 | */ | 450 | */ |
461 | static void u32_delete_key_freepf_work(struct work_struct *work) | 451 | static void u32_delete_key_freepf_work(struct work_struct *work) |
462 | { | 452 | { |
463 | struct tc_u_knode *key = container_of(work, struct tc_u_knode, work); | 453 | struct tc_u_knode *key = container_of(to_rcu_work(work), |
464 | 454 | struct tc_u_knode, | |
455 | rwork); | ||
465 | rtnl_lock(); | 456 | rtnl_lock(); |
466 | u32_destroy_key(key->tp, key, true); | 457 | u32_destroy_key(key->tp, key, true); |
467 | rtnl_unlock(); | 458 | rtnl_unlock(); |
468 | } | 459 | } |
469 | 460 | ||
470 | static void u32_delete_key_freepf_rcu(struct rcu_head *rcu) | ||
471 | { | ||
472 | struct tc_u_knode *key = container_of(rcu, struct tc_u_knode, rcu); | ||
473 | |||
474 | INIT_WORK(&key->work, u32_delete_key_freepf_work); | ||
475 | tcf_queue_work(&key->work); | ||
476 | } | ||
477 | |||
478 | static int u32_delete_key(struct tcf_proto *tp, struct tc_u_knode *key) | 461 | static int u32_delete_key(struct tcf_proto *tp, struct tc_u_knode *key) |
479 | { | 462 | { |
480 | struct tc_u_knode __rcu **kp; | 463 | struct tc_u_knode __rcu **kp; |
@@ -491,7 +474,7 @@ static int u32_delete_key(struct tcf_proto *tp, struct tc_u_knode *key) | |||
491 | tcf_unbind_filter(tp, &key->res); | 474 | tcf_unbind_filter(tp, &key->res); |
492 | idr_remove(&ht->handle_idr, key->handle); | 475 | idr_remove(&ht->handle_idr, key->handle); |
493 | tcf_exts_get_net(&key->exts); | 476 | tcf_exts_get_net(&key->exts); |
494 | call_rcu(&key->rcu, u32_delete_key_freepf_rcu); | 477 | tcf_queue_work(&key->rwork, u32_delete_key_freepf_work); |
495 | return 0; | 478 | return 0; |
496 | } | 479 | } |
497 | } | 480 | } |
@@ -611,7 +594,7 @@ static void u32_clear_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht, | |||
611 | u32_remove_hw_knode(tp, n, extack); | 594 | u32_remove_hw_knode(tp, n, extack); |
612 | idr_remove(&ht->handle_idr, n->handle); | 595 | idr_remove(&ht->handle_idr, n->handle); |
613 | if (tcf_exts_get_net(&n->exts)) | 596 | if (tcf_exts_get_net(&n->exts)) |
614 | call_rcu(&n->rcu, u32_delete_key_freepf_rcu); | 597 | tcf_queue_work(&n->rwork, u32_delete_key_freepf_work); |
615 | else | 598 | else |
616 | u32_destroy_key(n->tp, n, true); | 599 | u32_destroy_key(n->tp, n, true); |
617 | } | 600 | } |
@@ -995,7 +978,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, | |||
995 | u32_replace_knode(tp, tp_c, new); | 978 | u32_replace_knode(tp, tp_c, new); |
996 | tcf_unbind_filter(tp, &n->res); | 979 | tcf_unbind_filter(tp, &n->res); |
997 | tcf_exts_get_net(&n->exts); | 980 | tcf_exts_get_net(&n->exts); |
998 | call_rcu(&n->rcu, u32_delete_key_rcu); | 981 | tcf_queue_work(&n->rwork, u32_delete_key_work); |
999 | return 0; | 982 | return 0; |
1000 | } | 983 | } |
1001 | 984 | ||