--- y/net/sched/cls_route.c +++ c/net/sched/cls_route.c @@ -43,10 +43,15 @@ struct route4_bucket { struct rcu_head rcu; }; +enum { + RT4_FILTER_FL_RCU_PENDING = 0, +}; + struct route4_filter { struct route4_filter __rcu *next; u32 id; int iif; + unsigned long flag; struct tcf_result res; struct tcf_exts exts; @@ -269,6 +274,8 @@ static void route4_delete_filter_work(st static void route4_queue_work(struct route4_filter *f) { + if (test_and_set_bit(RT4_FILTER_FL_RCU_PENDING, &f->flag)) + return; tcf_queue_work(&f->rwork, route4_delete_filter_work); } @@ -341,7 +348,7 @@ static int route4_delete(struct tcf_prot /* Delete it */ tcf_unbind_filter(tp, &f->res); tcf_exts_get_net(&f->exts); - tcf_queue_work(&f->rwork, route4_delete_filter_work); + route4_queue_work(f); /* Strip RTNL protected tree */ for (i = 0; i <= 32; i++) { @@ -547,7 +554,7 @@ static int route4_change(struct net *net if (fold) { tcf_unbind_filter(tp, &fold->res); tcf_exts_get_net(&fold->exts); - tcf_queue_work(&fold->rwork, route4_delete_filter_work); + route4_queue_work(fold); } return 0;