diff options
author | Jamal Hadi Salim <jhs@mojatatu.com> | 2013-12-23 08:02:11 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-12-27 12:50:00 -0500 |
commit | 1a29321ed045e3aad23c5f7b63036e465ee3093a (patch) | |
tree | 8d59b477b4b3fd575dcf33450cfbc7d5e9c3502b /net/sched | |
parent | c2349758acf1874e4c2b93fe41d072336f1a31d0 (diff) |
net_sched: act: Dont increment refcnt on replace
This is a bug fix. The existing code tries to kill many
birds with one stone: Handling binding of actions to
filters, new actions and replacing of action
attributes. A simple test case to illustrate:
XXXX
moja@fe1:~$ sudo tc actions add action drop index 12
moja@fe1:~$ actions get action gact index 12
action order 1: gact action drop
random type none pass val 0
index 12 ref 1 bind 0
moja@fe1:~$ sudo tc actions replace action ok index 12
moja@fe1:~$ actions get action gact index 12
action order 1: gact action drop
random type none pass val 0
index 12 ref 2 bind 0
XXXX
The above shows the refcounf being wrongly incremented on replace.
There are more complex scenarios with binding of actions to filters
that i am leaving out that didnt work as well...
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sched')
-rw-r--r-- | net/sched/act_csum.c | 10 | ||||
-rw-r--r-- | net/sched/act_gact.c | 7 | ||||
-rw-r--r-- | net/sched/act_ipt.c | 8 | ||||
-rw-r--r-- | net/sched/act_nat.c | 10 | ||||
-rw-r--r-- | net/sched/act_pedit.c | 8 | ||||
-rw-r--r-- | net/sched/act_police.c | 4 | ||||
-rw-r--r-- | net/sched/act_simple.c | 9 | ||||
-rw-r--r-- | net/sched/act_skbedit.c | 7 |
8 files changed, 37 insertions, 26 deletions
diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c index 5c5edf56adbd..11fe1a416433 100644 --- a/net/sched/act_csum.c +++ b/net/sched/act_csum.c | |||
@@ -77,16 +77,16 @@ static int tcf_csum_init(struct net *n, struct nlattr *nla, struct nlattr *est, | |||
77 | &csum_idx_gen, &csum_hash_info); | 77 | &csum_idx_gen, &csum_hash_info); |
78 | if (IS_ERR(pc)) | 78 | if (IS_ERR(pc)) |
79 | return PTR_ERR(pc); | 79 | return PTR_ERR(pc); |
80 | p = to_tcf_csum(pc); | ||
81 | ret = ACT_P_CREATED; | 80 | ret = ACT_P_CREATED; |
82 | } else { | 81 | } else { |
83 | p = to_tcf_csum(pc); | 82 | if (bind)/* dont override defaults */ |
84 | if (!ovr) { | 83 | return 0; |
85 | tcf_hash_release(pc, bind, &csum_hash_info); | 84 | tcf_hash_release(pc, bind, &csum_hash_info); |
85 | if (!ovr) | ||
86 | return -EEXIST; | 86 | return -EEXIST; |
87 | } | ||
88 | } | 87 | } |
89 | 88 | ||
89 | p = to_tcf_csum(pc); | ||
90 | spin_lock_bh(&p->tcf_lock); | 90 | spin_lock_bh(&p->tcf_lock); |
91 | p->tcf_action = parm->action; | 91 | p->tcf_action = parm->action; |
92 | p->update_flags = parm->update_flags; | 92 | p->update_flags = parm->update_flags; |
diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c index 5645a4d32abd..eb9ba60ebab4 100644 --- a/net/sched/act_gact.c +++ b/net/sched/act_gact.c | |||
@@ -102,10 +102,11 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla, | |||
102 | return PTR_ERR(pc); | 102 | return PTR_ERR(pc); |
103 | ret = ACT_P_CREATED; | 103 | ret = ACT_P_CREATED; |
104 | } else { | 104 | } else { |
105 | if (!ovr) { | 105 | if (bind)/* dont override defaults */ |
106 | tcf_hash_release(pc, bind, &gact_hash_info); | 106 | return 0; |
107 | tcf_hash_release(pc, bind, &gact_hash_info); | ||
108 | if (!ovr) | ||
107 | return -EEXIST; | 109 | return -EEXIST; |
108 | } | ||
109 | } | 110 | } |
110 | 111 | ||
111 | gact = to_gact(pc); | 112 | gact = to_gact(pc); |
diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c index 882a89762f77..dcbfe8ce04a6 100644 --- a/net/sched/act_ipt.c +++ b/net/sched/act_ipt.c | |||
@@ -141,10 +141,12 @@ static int tcf_ipt_init(struct net *net, struct nlattr *nla, struct nlattr *est, | |||
141 | return PTR_ERR(pc); | 141 | return PTR_ERR(pc); |
142 | ret = ACT_P_CREATED; | 142 | ret = ACT_P_CREATED; |
143 | } else { | 143 | } else { |
144 | if (!ovr) { | 144 | if (bind)/* dont override defaults */ |
145 | tcf_ipt_release(to_ipt(pc), bind); | 145 | return 0; |
146 | tcf_ipt_release(to_ipt(pc), bind); | ||
147 | |||
148 | if (!ovr) | ||
146 | return -EEXIST; | 149 | return -EEXIST; |
147 | } | ||
148 | } | 150 | } |
149 | ipt = to_ipt(pc); | 151 | ipt = to_ipt(pc); |
150 | 152 | ||
diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c index 6a15ace00241..76869538d028 100644 --- a/net/sched/act_nat.c +++ b/net/sched/act_nat.c | |||
@@ -70,15 +70,15 @@ static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est, | |||
70 | &nat_idx_gen, &nat_hash_info); | 70 | &nat_idx_gen, &nat_hash_info); |
71 | if (IS_ERR(pc)) | 71 | if (IS_ERR(pc)) |
72 | return PTR_ERR(pc); | 72 | return PTR_ERR(pc); |
73 | p = to_tcf_nat(pc); | ||
74 | ret = ACT_P_CREATED; | 73 | ret = ACT_P_CREATED; |
75 | } else { | 74 | } else { |
76 | p = to_tcf_nat(pc); | 75 | if (bind) |
77 | if (!ovr) { | 76 | return 0; |
78 | tcf_hash_release(pc, bind, &nat_hash_info); | 77 | tcf_hash_release(pc, bind, &nat_hash_info); |
78 | if (!ovr) | ||
79 | return -EEXIST; | 79 | return -EEXIST; |
80 | } | ||
81 | } | 80 | } |
81 | p = to_tcf_nat(pc); | ||
82 | 82 | ||
83 | spin_lock_bh(&p->tcf_lock); | 83 | spin_lock_bh(&p->tcf_lock); |
84 | p->old_addr = parm->old_addr; | 84 | p->old_addr = parm->old_addr; |
diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c index 03b67674169c..7aa2dcd989f8 100644 --- a/net/sched/act_pedit.c +++ b/net/sched/act_pedit.c | |||
@@ -84,10 +84,12 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, | |||
84 | ret = ACT_P_CREATED; | 84 | ret = ACT_P_CREATED; |
85 | } else { | 85 | } else { |
86 | p = to_pedit(pc); | 86 | p = to_pedit(pc); |
87 | if (!ovr) { | 87 | tcf_hash_release(pc, bind, &pedit_hash_info); |
88 | tcf_hash_release(pc, bind, &pedit_hash_info); | 88 | if (bind) |
89 | return 0; | ||
90 | if (!ovr) | ||
89 | return -EEXIST; | 91 | return -EEXIST; |
90 | } | 92 | |
91 | if (p->tcfp_nkeys && p->tcfp_nkeys != parm->nkeys) { | 93 | if (p->tcfp_nkeys && p->tcfp_nkeys != parm->nkeys) { |
92 | keys = kmalloc(ksize, GFP_KERNEL); | 94 | keys = kmalloc(ksize, GFP_KERNEL); |
93 | if (keys == NULL) | 95 | if (keys == NULL) |
diff --git a/net/sched/act_police.c b/net/sched/act_police.c index 16a62c36928a..ef246d87e68b 100644 --- a/net/sched/act_police.c +++ b/net/sched/act_police.c | |||
@@ -177,10 +177,12 @@ static int tcf_act_police_locate(struct net *net, struct nlattr *nla, | |||
177 | if (bind) { | 177 | if (bind) { |
178 | police->tcf_bindcnt += 1; | 178 | police->tcf_bindcnt += 1; |
179 | police->tcf_refcnt += 1; | 179 | police->tcf_refcnt += 1; |
180 | return 0; | ||
180 | } | 181 | } |
181 | if (ovr) | 182 | if (ovr) |
182 | goto override; | 183 | goto override; |
183 | return ret; | 184 | /* not replacing */ |
185 | return -EEXIST; | ||
184 | } | 186 | } |
185 | } | 187 | } |
186 | 188 | ||
diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c index 31157d3e729c..f7b45ab85388 100644 --- a/net/sched/act_simple.c +++ b/net/sched/act_simple.c | |||
@@ -142,10 +142,13 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla, | |||
142 | ret = ACT_P_CREATED; | 142 | ret = ACT_P_CREATED; |
143 | } else { | 143 | } else { |
144 | d = to_defact(pc); | 144 | d = to_defact(pc); |
145 | if (!ovr) { | 145 | |
146 | tcf_simp_release(d, bind); | 146 | if (bind) |
147 | return 0; | ||
148 | tcf_simp_release(d, bind); | ||
149 | if (!ovr) | ||
147 | return -EEXIST; | 150 | return -EEXIST; |
148 | } | 151 | |
149 | reset_policy(d, defdata, parm); | 152 | reset_policy(d, defdata, parm); |
150 | } | 153 | } |
151 | 154 | ||
diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c index 35ea643b4325..8fe9d25c3008 100644 --- a/net/sched/act_skbedit.c +++ b/net/sched/act_skbedit.c | |||
@@ -120,10 +120,11 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla, | |||
120 | ret = ACT_P_CREATED; | 120 | ret = ACT_P_CREATED; |
121 | } else { | 121 | } else { |
122 | d = to_skbedit(pc); | 122 | d = to_skbedit(pc); |
123 | if (!ovr) { | 123 | if (bind) |
124 | tcf_hash_release(pc, bind, &skbedit_hash_info); | 124 | return 0; |
125 | tcf_hash_release(pc, bind, &skbedit_hash_info); | ||
126 | if (!ovr) | ||
125 | return -EEXIST; | 127 | return -EEXIST; |
126 | } | ||
127 | } | 128 | } |
128 | 129 | ||
129 | spin_lock_bh(&d->tcf_lock); | 130 | spin_lock_bh(&d->tcf_lock); |