]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
net: sched: protect block idr with spinlock
authorVlad Buslov <vladbu@mellanox.com>
Mon, 24 Sep 2018 16:22:56 +0000 (19:22 +0300)
committerDavid S. Miller <davem@davemloft.net>
Wed, 26 Sep 2018 03:17:36 +0000 (20:17 -0700)
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>
net/sched/cls_api.c

index cb7422af5e5110600ccf53577ec94b1ee3acebef..5a21888d0ee9a18fd25811b5cdf473686d798f88 100644 (file)
@@ -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;
 }