diff options
Diffstat (limited to 'net/sched/cls_flower.c')
-rw-r--r-- | net/sched/cls_flower.c | 21 |
1 files changed, 18 insertions, 3 deletions
diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c index d230cb4c8094..5b5722c8b32c 100644 --- a/net/sched/cls_flower.c +++ b/net/sched/cls_flower.c | |||
@@ -87,7 +87,10 @@ struct cls_fl_filter { | |||
87 | struct list_head list; | 87 | struct list_head list; |
88 | u32 handle; | 88 | u32 handle; |
89 | u32 flags; | 89 | u32 flags; |
90 | struct rcu_head rcu; | 90 | union { |
91 | struct work_struct work; | ||
92 | struct rcu_head rcu; | ||
93 | }; | ||
91 | struct net_device *hw_dev; | 94 | struct net_device *hw_dev; |
92 | }; | 95 | }; |
93 | 96 | ||
@@ -215,12 +218,22 @@ static int fl_init(struct tcf_proto *tp) | |||
215 | return 0; | 218 | return 0; |
216 | } | 219 | } |
217 | 220 | ||
218 | static void fl_destroy_filter(struct rcu_head *head) | 221 | static void fl_destroy_filter_work(struct work_struct *work) |
219 | { | 222 | { |
220 | struct cls_fl_filter *f = container_of(head, struct cls_fl_filter, rcu); | 223 | struct cls_fl_filter *f = container_of(work, struct cls_fl_filter, work); |
221 | 224 | ||
225 | rtnl_lock(); | ||
222 | tcf_exts_destroy(&f->exts); | 226 | tcf_exts_destroy(&f->exts); |
223 | kfree(f); | 227 | kfree(f); |
228 | rtnl_unlock(); | ||
229 | } | ||
230 | |||
231 | static void fl_destroy_filter(struct rcu_head *head) | ||
232 | { | ||
233 | struct cls_fl_filter *f = container_of(head, struct cls_fl_filter, rcu); | ||
234 | |||
235 | INIT_WORK(&f->work, fl_destroy_filter_work); | ||
236 | tcf_queue_work(&f->work); | ||
224 | } | 237 | } |
225 | 238 | ||
226 | static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f) | 239 | static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f) |
@@ -234,6 +247,7 @@ static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f) | |||
234 | tc_cls_common_offload_init(&cls_flower.common, tp); | 247 | tc_cls_common_offload_init(&cls_flower.common, tp); |
235 | cls_flower.command = TC_CLSFLOWER_DESTROY; | 248 | cls_flower.command = TC_CLSFLOWER_DESTROY; |
236 | cls_flower.cookie = (unsigned long) f; | 249 | cls_flower.cookie = (unsigned long) f; |
250 | cls_flower.egress_dev = f->hw_dev != tp->q->dev_queue->dev; | ||
237 | 251 | ||
238 | dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_CLSFLOWER, &cls_flower); | 252 | dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_CLSFLOWER, &cls_flower); |
239 | } | 253 | } |
@@ -289,6 +303,7 @@ static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f) | |||
289 | cls_flower.command = TC_CLSFLOWER_STATS; | 303 | cls_flower.command = TC_CLSFLOWER_STATS; |
290 | cls_flower.cookie = (unsigned long) f; | 304 | cls_flower.cookie = (unsigned long) f; |
291 | cls_flower.exts = &f->exts; | 305 | cls_flower.exts = &f->exts; |
306 | cls_flower.egress_dev = f->hw_dev != tp->q->dev_queue->dev; | ||
292 | 307 | ||
293 | dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_CLSFLOWER, | 308 | dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_CLSFLOWER, |
294 | &cls_flower); | 309 | &cls_flower); |