aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/sched/cls_fw.c17
1 files changed, 14 insertions, 3 deletions
diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c
index 99183b8621ec..7f45e5ab8afc 100644
--- a/net/sched/cls_fw.c
+++ b/net/sched/cls_fw.c
@@ -122,13 +122,19 @@ static int fw_init(struct tcf_proto *tp)
122 return 0; 122 return 0;
123} 123}
124 124
125static void __fw_delete_filter(struct fw_filter *f)
126{
127 tcf_exts_destroy(&f->exts);
128 tcf_exts_put_net(&f->exts);
129 kfree(f);
130}
131
125static void fw_delete_filter_work(struct work_struct *work) 132static void fw_delete_filter_work(struct work_struct *work)
126{ 133{
127 struct fw_filter *f = container_of(work, struct fw_filter, work); 134 struct fw_filter *f = container_of(work, struct fw_filter, work);
128 135
129 rtnl_lock(); 136 rtnl_lock();
130 tcf_exts_destroy(&f->exts); 137 __fw_delete_filter(f);
131 kfree(f);
132 rtnl_unlock(); 138 rtnl_unlock();
133} 139}
134 140
@@ -154,7 +160,10 @@ static void fw_destroy(struct tcf_proto *tp)
154 RCU_INIT_POINTER(head->ht[h], 160 RCU_INIT_POINTER(head->ht[h],
155 rtnl_dereference(f->next)); 161 rtnl_dereference(f->next));
156 tcf_unbind_filter(tp, &f->res); 162 tcf_unbind_filter(tp, &f->res);
157 call_rcu(&f->rcu, fw_delete_filter); 163 if (tcf_exts_get_net(&f->exts))
164 call_rcu(&f->rcu, fw_delete_filter);
165 else
166 __fw_delete_filter(f);
158 } 167 }
159 } 168 }
160 kfree_rcu(head, rcu); 169 kfree_rcu(head, rcu);
@@ -179,6 +188,7 @@ static int fw_delete(struct tcf_proto *tp, void *arg, bool *last)
179 if (pfp == f) { 188 if (pfp == f) {
180 RCU_INIT_POINTER(*fp, rtnl_dereference(f->next)); 189 RCU_INIT_POINTER(*fp, rtnl_dereference(f->next));
181 tcf_unbind_filter(tp, &f->res); 190 tcf_unbind_filter(tp, &f->res);
191 tcf_exts_get_net(&f->exts);
182 call_rcu(&f->rcu, fw_delete_filter); 192 call_rcu(&f->rcu, fw_delete_filter);
183 ret = 0; 193 ret = 0;
184 break; 194 break;
@@ -299,6 +309,7 @@ static int fw_change(struct net *net, struct sk_buff *in_skb,
299 RCU_INIT_POINTER(fnew->next, rtnl_dereference(pfp->next)); 309 RCU_INIT_POINTER(fnew->next, rtnl_dereference(pfp->next));
300 rcu_assign_pointer(*fp, fnew); 310 rcu_assign_pointer(*fp, fnew);
301 tcf_unbind_filter(tp, &f->res); 311 tcf_unbind_filter(tp, &f->res);
312 tcf_exts_get_net(&f->exts);
302 call_rcu(&f->rcu, fw_delete_filter); 313 call_rcu(&f->rcu, fw_delete_filter);
303 314
304 *arg = fnew; 315 *arg = fnew;