Commit 1d8134fe authored by Cong Wang's avatar Cong Wang Committed by David S. Miller

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: default avatarCong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 76cf546c
...@@ -17,13 +17,14 @@ ...@@ -17,13 +17,14 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/idr.h>
#include <net/netlink.h> #include <net/netlink.h>
#include <net/act_api.h> #include <net/act_api.h>
#include <net/pkt_cls.h> #include <net/pkt_cls.h>
struct basic_head { struct basic_head {
u32 hgenerator;
struct list_head flist; struct list_head flist;
struct idr handle_idr;
struct rcu_head rcu; struct rcu_head rcu;
}; };
...@@ -78,6 +79,7 @@ static int basic_init(struct tcf_proto *tp) ...@@ -78,6 +79,7 @@ static int basic_init(struct tcf_proto *tp)
if (head == NULL) if (head == NULL)
return -ENOBUFS; return -ENOBUFS;
INIT_LIST_HEAD(&head->flist); INIT_LIST_HEAD(&head->flist);
idr_init(&head->handle_idr);
rcu_assign_pointer(tp->root, head); rcu_assign_pointer(tp->root, head);
return 0; return 0;
} }
...@@ -99,8 +101,10 @@ static void basic_destroy(struct tcf_proto *tp) ...@@ -99,8 +101,10 @@ static void basic_destroy(struct tcf_proto *tp)
list_for_each_entry_safe(f, n, &head->flist, link) { list_for_each_entry_safe(f, n, &head->flist, link) {
list_del_rcu(&f->link); list_del_rcu(&f->link);
tcf_unbind_filter(tp, &f->res); tcf_unbind_filter(tp, &f->res);
idr_remove_ext(&head->handle_idr, f->handle);
call_rcu(&f->rcu, basic_delete_filter); call_rcu(&f->rcu, basic_delete_filter);
} }
idr_destroy(&head->handle_idr);
kfree_rcu(head, rcu); kfree_rcu(head, rcu);
} }
...@@ -111,6 +115,7 @@ static int basic_delete(struct tcf_proto *tp, void *arg, bool *last) ...@@ -111,6 +115,7 @@ static int basic_delete(struct tcf_proto *tp, void *arg, bool *last)
list_del_rcu(&f->link); list_del_rcu(&f->link);
tcf_unbind_filter(tp, &f->res); tcf_unbind_filter(tp, &f->res);
idr_remove_ext(&head->handle_idr, f->handle);
call_rcu(&f->rcu, basic_delete_filter); call_rcu(&f->rcu, basic_delete_filter);
*last = list_empty(&head->flist); *last = list_empty(&head->flist);
return 0; return 0;
...@@ -154,6 +159,7 @@ static int basic_change(struct net *net, struct sk_buff *in_skb, ...@@ -154,6 +159,7 @@ static int basic_change(struct net *net, struct sk_buff *in_skb,
struct nlattr *tb[TCA_BASIC_MAX + 1]; struct nlattr *tb[TCA_BASIC_MAX + 1];
struct basic_filter *fold = (struct basic_filter *) *arg; struct basic_filter *fold = (struct basic_filter *) *arg;
struct basic_filter *fnew; struct basic_filter *fnew;
unsigned long idr_index;
if (tca[TCA_OPTIONS] == NULL) if (tca[TCA_OPTIONS] == NULL)
return -EINVAL; return -EINVAL;
...@@ -179,30 +185,31 @@ static int basic_change(struct net *net, struct sk_buff *in_skb, ...@@ -179,30 +185,31 @@ static int basic_change(struct net *net, struct sk_buff *in_skb,
err = -EINVAL; err = -EINVAL;
if (handle) { if (handle) {
fnew->handle = handle; fnew->handle = handle;
} else if (fold) { if (!fold) {
fnew->handle = fold->handle; err = idr_alloc_ext(&head->handle_idr, fnew, &idr_index,
handle, handle + 1, GFP_KERNEL);
if (err)
goto errout;
}
} else { } else {
unsigned int i = 0x80000000; err = idr_alloc_ext(&head->handle_idr, fnew, &idr_index,
do { 1, 0x7FFFFFFF, GFP_KERNEL);
if (++head->hgenerator == 0x7FFFFFFF) if (err)
head->hgenerator = 1;
} while (--i > 0 && basic_get(tp, head->hgenerator));
if (i <= 0) {
pr_err("Insufficient number of handles\n");
goto errout; goto errout;
} fnew->handle = idr_index;
fnew->handle = head->hgenerator;
} }
err = basic_set_parms(net, tp, fnew, base, tb, tca[TCA_RATE], ovr); err = basic_set_parms(net, tp, fnew, base, tb, tca[TCA_RATE], ovr);
if (err < 0) if (err < 0) {
if (!fold)
idr_remove_ext(&head->handle_idr, fnew->handle);
goto errout; goto errout;
}
*arg = fnew; *arg = fnew;
if (fold) { if (fold) {
idr_replace_ext(&head->handle_idr, fnew, fnew->handle);
list_replace_rcu(&fold->link, &fnew->link); list_replace_rcu(&fold->link, &fnew->link);
tcf_unbind_filter(tp, &fold->res); tcf_unbind_filter(tp, &fold->res);
call_rcu(&fold->rcu, basic_delete_filter); call_rcu(&fold->rcu, basic_delete_filter);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment