aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/cls_basic.c
diff options
context:
space:
mode:
authorCong Wang <xiyou.wangcong@gmail.com>2017-09-25 13:13:50 -0400
committerDavid S. Miller <davem@davemloft.net>2017-09-28 12:43:41 -0400
commit1d8134fea2eb460698a281f91c03c400f7e546ce (patch)
tree5bacbb640e20cbfefb00402959cf68125b42d3ac /net/sched/cls_basic.c
parent76cf546c2802f6e25113ba481d7e85d0298768c6 (diff)
net_sched: use idr to allocate basic filter handles
Instead of calling basic_get() in a loop to find a unused handle, just switch to idr API to allocate new handles. Cc: Chris Mi <chrism@mellanox.com> Cc: Jamal Hadi Salim <jhs@mojatatu.com> Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sched/cls_basic.c')
-rw-r--r--net/sched/cls_basic.c37
1 files changed, 22 insertions, 15 deletions
diff --git a/net/sched/cls_basic.c b/net/sched/cls_basic.c
index d89ebafd2239..cfeb6f158566 100644
--- a/net/sched/cls_basic.c
+++ b/net/sched/cls_basic.c
@@ -17,13 +17,14 @@
17#include <linux/errno.h> 17#include <linux/errno.h>
18#include <linux/rtnetlink.h> 18#include <linux/rtnetlink.h>
19#include <linux/skbuff.h> 19#include <linux/skbuff.h>
20#include <linux/idr.h>
20#include <net/netlink.h> 21#include <net/netlink.h>
21#include <net/act_api.h> 22#include <net/act_api.h>
22#include <net/pkt_cls.h> 23#include <net/pkt_cls.h>
23 24
24struct basic_head { 25struct basic_head {
25 u32 hgenerator;
26 struct list_head flist; 26 struct list_head flist;
27 struct idr handle_idr;
27 struct rcu_head rcu; 28 struct rcu_head rcu;
28}; 29};
29 30
@@ -78,6 +79,7 @@ static int basic_init(struct tcf_proto *tp)
78 if (head == NULL) 79 if (head == NULL)
79 return -ENOBUFS; 80 return -ENOBUFS;
80 INIT_LIST_HEAD(&head->flist); 81 INIT_LIST_HEAD(&head->flist);
82 idr_init(&head->handle_idr);
81 rcu_assign_pointer(tp->root, head); 83 rcu_assign_pointer(tp->root, head);
82 return 0; 84 return 0;
83} 85}
@@ -99,8 +101,10 @@ static void basic_destroy(struct tcf_proto *tp)
99 list_for_each_entry_safe(f, n, &head->flist, link) { 101 list_for_each_entry_safe(f, n, &head->flist, link) {
100 list_del_rcu(&f->link); 102 list_del_rcu(&f->link);
101 tcf_unbind_filter(tp, &f->res); 103 tcf_unbind_filter(tp, &f->res);
104 idr_remove_ext(&head->handle_idr, f->handle);
102 call_rcu(&f->rcu, basic_delete_filter); 105 call_rcu(&f->rcu, basic_delete_filter);
103 } 106 }
107 idr_destroy(&head->handle_idr);
104 kfree_rcu(head, rcu); 108 kfree_rcu(head, rcu);
105} 109}
106 110
@@ -111,6 +115,7 @@ static int basic_delete(struct tcf_proto *tp, void *arg, bool *last)
111 115
112 list_del_rcu(&f->link); 116 list_del_rcu(&f->link);
113 tcf_unbind_filter(tp, &f->res); 117 tcf_unbind_filter(tp, &f->res);
118 idr_remove_ext(&head->handle_idr, f->handle);
114 call_rcu(&f->rcu, basic_delete_filter); 119 call_rcu(&f->rcu, basic_delete_filter);
115 *last = list_empty(&head->flist); 120 *last = list_empty(&head->flist);
116 return 0; 121 return 0;
@@ -154,6 +159,7 @@ static int basic_change(struct net *net, struct sk_buff *in_skb,
154 struct nlattr *tb[TCA_BASIC_MAX + 1]; 159 struct nlattr *tb[TCA_BASIC_MAX + 1];
155 struct basic_filter *fold = (struct basic_filter *) *arg; 160 struct basic_filter *fold = (struct basic_filter *) *arg;
156 struct basic_filter *fnew; 161 struct basic_filter *fnew;
162 unsigned long idr_index;
157 163
158 if (tca[TCA_OPTIONS] == NULL) 164 if (tca[TCA_OPTIONS] == NULL)
159 return -EINVAL; 165 return -EINVAL;
@@ -179,30 +185,31 @@ static int basic_change(struct net *net, struct sk_buff *in_skb,
179 err = -EINVAL; 185 err = -EINVAL;
180 if (handle) { 186 if (handle) {
181 fnew->handle = handle; 187 fnew->handle = handle;
182 } else if (fold) { 188 if (!fold) {
183 fnew->handle = fold->handle; 189 err = idr_alloc_ext(&head->handle_idr, fnew, &idr_index,
190 handle, handle + 1, GFP_KERNEL);
191 if (err)
192 goto errout;
193 }
184 } else { 194 } else {
185 unsigned int i = 0x80000000; 195 err = idr_alloc_ext(&head->handle_idr, fnew, &idr_index,
186 do { 196 1, 0x7FFFFFFF, GFP_KERNEL);
187 if (++head->hgenerator == 0x7FFFFFFF) 197 if (err)
188 head->hgenerator = 1;
189 } while (--i > 0 && basic_get(tp, head->hgenerator));
190
191 if (i <= 0) {
192 pr_err("Insufficient number of handles\n");
193 goto errout; 198 goto errout;
194 } 199 fnew->handle = idr_index;
195
196 fnew->handle = head->hgenerator;
197 } 200 }
198 201
199 err = basic_set_parms(net, tp, fnew, base, tb, tca[TCA_RATE], ovr); 202 err = basic_set_parms(net, tp, fnew, base, tb, tca[TCA_RATE], ovr);
200 if (err < 0) 203 if (err < 0) {
204 if (!fold)
205 idr_remove_ext(&head->handle_idr, fnew->handle);
201 goto errout; 206 goto errout;
207 }
202 208
203 *arg = fnew; 209 *arg = fnew;
204 210
205 if (fold) { 211 if (fold) {
212 idr_replace_ext(&head->handle_idr, fnew, fnew->handle);
206 list_replace_rcu(&fold->link, &fnew->link); 213 list_replace_rcu(&fold->link, &fnew->link);
207 tcf_unbind_filter(tp, &fold->res); 214 tcf_unbind_filter(tp, &fold->res);
208 call_rcu(&fold->rcu, basic_delete_filter); 215 call_rcu(&fold->rcu, basic_delete_filter);