diff options
author | Vlad Buslov <vladbu@mellanox.com> | 2018-09-24 19:22:56 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-09-25 20:17:36 -0700 |
commit | ab2816295f991700b7e2ee117880751be8f705b4 (patch) | |
tree | 88c2beabdffbd2e3e041cf6826d47cf5fc52f858 /net/sched/cls_api.c | |
parent | f00234367b64503d2436bb3d0f37bbe98ac2cc97 (diff) |
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: Vlad Buslov <vladbu@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sched/cls_api.c')
-rw-r--r-- | net/sched/cls_api.c | 15 |
1 files changed, 13 insertions, 2 deletions
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index cb7422af5e51..5a21888d0ee9 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -473,6 +473,7 @@ tcf_chain0_head_change_cb_del(struct tcf_block *block, } struct tcf_net { + spinlock_t idr_lock; /* Protects idr */ struct idr idr; }; @@ -482,16 +483,25 @@ static int tcf_block_insert(struct tcf_block *block, struct net *net, struct netlink_ext_ack *extack) { 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, - GFP_KERNEL); + return err; } static void tcf_block_remove(struct tcf_block *block, struct net *net) { struct tcf_net *tn = net_generic(net, tcf_net_id); + spin_lock(&tn->idr_lock); idr_remove(&tn->idr, block->index); + spin_unlock(&tn->idr_lock); } 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) { struct tcf_net *tn = net_generic(net, tcf_net_id); + spin_lock_init(&tn->idr_lock); idr_init(&tn->idr); return 0; } |