diff options
| -rw-r--r-- | net/sched/cls_fw.c | 17 |
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 | ||
| 125 | static 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 | |||
| 125 | static void fw_delete_filter_work(struct work_struct *work) | 132 | static 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; |
