Commit ab281629 authored by Vlad Buslov's avatar Vlad Buslov Committed by David S. Miller

net: sched: protect block idr with spinlock

Protect block idr access with spinlock, instead of relying on rtnl lock.
Take tn->idr_lock spinlock during block insertion and removal.
Signed-off-by: default avatarVlad Buslov <vladbu@mellanox.com>
Acked-by: default avatarJiri Pirko <jiri@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f0023436
...@@ -473,6 +473,7 @@ tcf_chain0_head_change_cb_del(struct tcf_block *block, ...@@ -473,6 +473,7 @@ tcf_chain0_head_change_cb_del(struct tcf_block *block,
} }
struct tcf_net { struct tcf_net {
spinlock_t idr_lock; /* Protects idr */
struct idr idr; struct idr idr;
}; };
...@@ -482,16 +483,25 @@ static int tcf_block_insert(struct tcf_block *block, struct net *net, ...@@ -482,16 +483,25 @@ static int tcf_block_insert(struct tcf_block *block, struct net *net,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
struct tcf_net *tn = net_generic(net, tcf_net_id); struct tcf_net *tn = net_generic(net, tcf_net_id);
int err;
idr_preload(GFP_KERNEL);
spin_lock(&tn->idr_lock);
err = idr_alloc_u32(&tn->idr, block, &block->index, block->index,
GFP_NOWAIT);
spin_unlock(&tn->idr_lock);
idr_preload_end();
return idr_alloc_u32(&tn->idr, block, &block->index, block->index, return err;
GFP_KERNEL);
} }
static void tcf_block_remove(struct tcf_block *block, struct net *net) static void tcf_block_remove(struct tcf_block *block, struct net *net)
{ {
struct tcf_net *tn = net_generic(net, tcf_net_id); struct tcf_net *tn = net_generic(net, tcf_net_id);
spin_lock(&tn->idr_lock);
idr_remove(&tn->idr, block->index); idr_remove(&tn->idr, block->index);
spin_unlock(&tn->idr_lock);
} }
static struct tcf_block *tcf_block_create(struct net *net, struct Qdisc *q, static struct tcf_block *tcf_block_create(struct net *net, struct Qdisc *q,
...@@ -2278,6 +2288,7 @@ static __net_init int tcf_net_init(struct net *net) ...@@ -2278,6 +2288,7 @@ static __net_init int tcf_net_init(struct net *net)
{ {
struct tcf_net *tn = net_generic(net, tcf_net_id); struct tcf_net *tn = net_generic(net, tcf_net_id);
spin_lock_init(&tn->idr_lock);
idr_init(&tn->idr); idr_init(&tn->idr);
return 0; return 0;
} }
......
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