Skip to content

Commit 1d8134f

Browse files
congwangdavem330
authored andcommitted
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 <[email protected]> Cc: Jamal Hadi Salim <[email protected]> Signed-off-by: Cong Wang <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 76cf546 commit 1d8134f

File tree

1 file changed

+22
-15
lines changed

1 file changed

+22
-15
lines changed

net/sched/cls_basic.c

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@
1717
#include <linux/errno.h>
1818
#include <linux/rtnetlink.h>
1919
#include <linux/skbuff.h>
20+
#include <linux/idr.h>
2021
#include <net/netlink.h>
2122
#include <net/act_api.h>
2223
#include <net/pkt_cls.h>
2324

2425
struct basic_head {
25-
u32 hgenerator;
2626
struct list_head flist;
27+
struct idr handle_idr;
2728
struct rcu_head rcu;
2829
};
2930

@@ -78,6 +79,7 @@ static int basic_init(struct tcf_proto *tp)
7879
if (head == NULL)
7980
return -ENOBUFS;
8081
INIT_LIST_HEAD(&head->flist);
82+
idr_init(&head->handle_idr);
8183
rcu_assign_pointer(tp->root, head);
8284
return 0;
8385
}
@@ -99,8 +101,10 @@ static void basic_destroy(struct tcf_proto *tp)
99101
list_for_each_entry_safe(f, n, &head->flist, link) {
100102
list_del_rcu(&f->link);
101103
tcf_unbind_filter(tp, &f->res);
104+
idr_remove_ext(&head->handle_idr, f->handle);
102105
call_rcu(&f->rcu, basic_delete_filter);
103106
}
107+
idr_destroy(&head->handle_idr);
104108
kfree_rcu(head, rcu);
105109
}
106110

@@ -111,6 +115,7 @@ static int basic_delete(struct tcf_proto *tp, void *arg, bool *last)
111115

112116
list_del_rcu(&f->link);
113117
tcf_unbind_filter(tp, &f->res);
118+
idr_remove_ext(&head->handle_idr, f->handle);
114119
call_rcu(&f->rcu, basic_delete_filter);
115120
*last = list_empty(&head->flist);
116121
return 0;
@@ -154,6 +159,7 @@ static int basic_change(struct net *net, struct sk_buff *in_skb,
154159
struct nlattr *tb[TCA_BASIC_MAX + 1];
155160
struct basic_filter *fold = (struct basic_filter *) *arg;
156161
struct basic_filter *fnew;
162+
unsigned long idr_index;
157163

158164
if (tca[TCA_OPTIONS] == NULL)
159165
return -EINVAL;
@@ -179,30 +185,31 @@ static int basic_change(struct net *net, struct sk_buff *in_skb,
179185
err = -EINVAL;
180186
if (handle) {
181187
fnew->handle = handle;
182-
} else if (fold) {
183-
fnew->handle = fold->handle;
188+
if (!fold) {
189+
err = idr_alloc_ext(&head->handle_idr, fnew, &idr_index,
190+
handle, handle + 1, GFP_KERNEL);
191+
if (err)
192+
goto errout;
193+
}
184194
} else {
185-
unsigned int i = 0x80000000;
186-
do {
187-
if (++head->hgenerator == 0x7FFFFFFF)
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");
195+
err = idr_alloc_ext(&head->handle_idr, fnew, &idr_index,
196+
1, 0x7FFFFFFF, GFP_KERNEL);
197+
if (err)
193198
goto errout;
194-
}
195-
196-
fnew->handle = head->hgenerator;
199+
fnew->handle = idr_index;
197200
}
198201

199202
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);
201206
goto errout;
207+
}
202208

203209
*arg = fnew;
204210

205211
if (fold) {
212+
idr_replace_ext(&head->handle_idr, fnew, fnew->handle);
206213
list_replace_rcu(&fold->link, &fnew->link);
207214
tcf_unbind_filter(tp, &fold->res);
208215
call_rcu(&fold->rcu, basic_delete_filter);

0 commit comments

Comments
 (0)