diff options
author | Alex Shi <alex.shi@linaro.org> | 2016-12-12 22:17:37 +0800 |
---|---|---|
committer | Alex Shi <alex.shi@linaro.org> | 2016-12-12 22:17:37 +0800 |
commit | 2f0de5192ae332ff270b2fc30594e4d67002d59b (patch) | |
tree | 475fcbdaf94fdc1bc32c1527d448f702d5c18770 /net/sched/cls_flower.c | |
parent | bdcf7d8df4cfa7f99423da161019b964f7ce2520 (diff) | |
parent | a057484ab40ff81f22a94bb62c035c78b5abd940 (diff) |
Merge branch 'linux-linaro-lsk-v4.4' into linux-linaro-lsk-v4.4-androidlsk-v4.4-16.12-android
Diffstat (limited to 'net/sched/cls_flower.c')
-rw-r--r-- | net/sched/cls_flower.c | 31 |
1 files changed, 26 insertions, 5 deletions
diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c index 95b021243233..e5a58c82728a 100644 --- a/net/sched/cls_flower.c +++ b/net/sched/cls_flower.c @@ -13,6 +13,7 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/rhashtable.h> +#include <linux/workqueue.h> #include <linux/if_ether.h> #include <linux/in6.h> @@ -55,7 +56,10 @@ struct cls_fl_head { bool mask_assigned; struct list_head filters; struct rhashtable_params ht_params; - struct rcu_head rcu; + union { + struct work_struct work; + struct rcu_head rcu; + }; }; struct cls_fl_filter { @@ -165,6 +169,24 @@ static void fl_destroy_filter(struct rcu_head *head) kfree(f); } +static void fl_destroy_sleepable(struct work_struct *work) +{ + struct cls_fl_head *head = container_of(work, struct cls_fl_head, + work); + if (head->mask_assigned) + rhashtable_destroy(&head->ht); + kfree(head); + module_put(THIS_MODULE); +} + +static void fl_destroy_rcu(struct rcu_head *rcu) +{ + struct cls_fl_head *head = container_of(rcu, struct cls_fl_head, rcu); + + INIT_WORK(&head->work, fl_destroy_sleepable); + schedule_work(&head->work); +} + static bool fl_destroy(struct tcf_proto *tp, bool force) { struct cls_fl_head *head = rtnl_dereference(tp->root); @@ -177,10 +199,9 @@ static bool fl_destroy(struct tcf_proto *tp, bool force) list_del_rcu(&f->list); call_rcu(&f->rcu, fl_destroy_filter); } - RCU_INIT_POINTER(tp->root, NULL); - if (head->mask_assigned) - rhashtable_destroy(&head->ht); - kfree_rcu(head, rcu); + + __module_get(THIS_MODULE); + call_rcu(&head->rcu, fl_destroy_rcu); return true; } |