From: "Matthew Wilcox (Oracle)" <wi...@infradead.org> Rename this IDR to 'knodes' since that's what's being stored in it. Use xa_alloc_cyclic() since that's what's being emulated in gen_new_kid(). Allow gen_new_kid() to return a "no space" indicator. Access to this XArray is now under both the rtnl lock and the XArray spinlock.
Signed-off-by: Matthew Wilcox (Oracle) <wi...@infradead.org> --- net/sched/cls_u32.c | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 18ef5f375976..46ddfd312952 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -38,7 +38,7 @@ #include <net/netlink.h> #include <net/act_api.h> #include <net/pkt_cls.h> -#include <linux/idr.h> +#include <linux/xarray.h> struct tc_u_knode { struct tc_u_knode __rcu *next; @@ -72,7 +72,7 @@ struct tc_u_hnode { u32 prio; int refcnt; unsigned int divisor; - struct idr handle_idr; + struct xarray knodes; bool is_root; struct rcu_head rcu; u32 flags; @@ -366,7 +366,7 @@ static int u32_init(struct tcf_proto *tp) root_ht->handle = tp_c ? gen_new_htid(tp_c, root_ht) : 0x80000000; root_ht->prio = tp->prio; root_ht->is_root = true; - idr_init(&root_ht->handle_idr); + xa_init_flags(&root_ht->knodes, XA_FLAGS_ALLOC); if (tp_c == NULL) { tp_c = kzalloc(sizeof(*tp_c), GFP_KERNEL); @@ -461,7 +461,7 @@ static int u32_delete_key(struct tcf_proto *tp, struct tc_u_knode *key) tp_c->knodes--; tcf_unbind_filter(tp, &key->res); - idr_remove(&ht->handle_idr, key->handle); + xa_erase(&ht->knodes, key->handle); tcf_exts_get_net(&key->exts); tcf_queue_work(&key->rwork, u32_delete_key_freepf_work); return 0; @@ -585,7 +585,7 @@ static void u32_clear_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht, tp_c->knodes--; tcf_unbind_filter(tp, &n->res); u32_remove_hw_knode(tp, n, extack); - idr_remove(&ht->handle_idr, n->handle); + xa_erase(&ht->knodes, n->handle); if (tcf_exts_get_net(&n->exts)) tcf_queue_work(&n->rwork, u32_delete_key_freepf_work); else @@ -611,7 +611,6 @@ static int u32_destroy_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht, hn = &phn->next, phn = rtnl_dereference(*hn)) { if (phn == ht) { u32_clear_hw_hnode(tp, ht, extack); - idr_destroy(&ht->handle_idr); xa_erase(&tp_c->ht_xa, ht->handle); RCU_INIT_POINTER(*hn, ht->next); kfree_rcu(ht, rcu); @@ -687,15 +686,13 @@ static int u32_delete(struct tcf_proto *tp, void *arg, bool *last, static u32 gen_new_kid(struct tc_u_hnode *ht, u32 htid) { - u32 index = htid | 0x800; - u32 max = htid | 0xFFF; - - if (idr_alloc_u32(&ht->handle_idr, NULL, &index, max, GFP_KERNEL)) { - index = htid + 1; - if (idr_alloc_u32(&ht->handle_idr, NULL, &index, max, - GFP_KERNEL)) - index = max; - } + u32 start = htid | 0x800; + u32 index; + + if (xa_alloc_cyclic(&ht->knodes, &index, NULL, + XA_LIMIT(htid + 1, htid | 0xfff), &start, + GFP_KERNEL) < 0) + index = htid; return index; } @@ -789,7 +786,7 @@ static void u32_replace_knode(struct tcf_proto *tp, struct tc_u_common *tp_c, if (pins->handle == n->handle) break; - idr_replace(&ht->handle_idr, n, n->handle); + xa_store(&ht->knodes, n->handle, n, 0); RCU_INIT_POINTER(n->next, pins->next); rcu_assign_pointer(*ins, n); } @@ -963,7 +960,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, ht->divisor = divisor; ht->handle = handle; ht->prio = tp->prio; - idr_init(&ht->handle_idr); + xa_init_flags(&ht->knodes, XA_FLAGS_ALLOC); ht->flags = flags; err = u32_replace_hw_hnode(tp, ht, flags, extack); @@ -1008,12 +1005,14 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, return -EINVAL; } handle = htid | TC_U32_NODE(handle); - err = idr_alloc_u32(&ht->handle_idr, NULL, &handle, handle, - GFP_KERNEL); + err = xa_insert(&ht->knodes, handle, NULL, GFP_KERNEL); if (err) return err; - } else + } else { handle = gen_new_kid(ht, htid); + if (handle == htid) + return -ENOBUFS; + } if (tb[TCA_U32_SEL] == NULL) { NL_SET_ERR_MSG_MOD(extack, "Selector not specified"); @@ -1108,7 +1107,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, #endif kfree(n); erridr: - idr_remove(&ht->handle_idr, handle); + xa_erase(&ht->knodes, handle); return err; } -- 2.23.0.rc1