--- 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); } @@ -545,9 +552,13 @@ static int route4_change(struct net *net route4_reset_fastmap(head); *arg = f; if (fold) { + if (flags & TCA_ACT_FLAGS_NO_RTNL) + rtnl_lock(); tcf_unbind_filter(tp, &fold->res); tcf_exts_get_net(&fold->exts); tcf_queue_work(&fold->rwork, route4_delete_filter_work); + if (flags & TCA_ACT_FLAGS_NO_RTNL) + rtnl_unlock(); } return 0;