Merge remote-tracking branch 'regulator/topic/wm8350' into regulator-next
[firefly-linux-kernel-4.4.55.git] / net / ipv4 / route.c
index 52e1f2bf0ca2ff2fe3d85086465068da4bbb43f2..ad5064362c5c7da56e9e22f1a012972bfff58e0e 100644 (file)
@@ -1328,14 +1328,22 @@ static bool rt_cache_route(struct fib_nh *nh, struct rtable *rt)
        return ret;
 }
 
-static DEFINE_SPINLOCK(rt_uncached_lock);
-static LIST_HEAD(rt_uncached_list);
+struct uncached_list {
+       spinlock_t              lock;
+       struct list_head        head;
+};
+
+static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt_uncached_list);
 
 static void rt_add_uncached_list(struct rtable *rt)
 {
-       spin_lock_bh(&rt_uncached_lock);
-       list_add_tail(&rt->rt_uncached, &rt_uncached_list);
-       spin_unlock_bh(&rt_uncached_lock);
+       struct uncached_list *ul = raw_cpu_ptr(&rt_uncached_list);
+
+       rt->rt_uncached_list = ul;
+
+       spin_lock_bh(&ul->lock);
+       list_add_tail(&rt->rt_uncached, &ul->head);
+       spin_unlock_bh(&ul->lock);
 }
 
 static void ipv4_dst_destroy(struct dst_entry *dst)
@@ -1343,27 +1351,32 @@ static void ipv4_dst_destroy(struct dst_entry *dst)
        struct rtable *rt = (struct rtable *) dst;
 
        if (!list_empty(&rt->rt_uncached)) {
-               spin_lock_bh(&rt_uncached_lock);
+               struct uncached_list *ul = rt->rt_uncached_list;
+
+               spin_lock_bh(&ul->lock);
                list_del(&rt->rt_uncached);
-               spin_unlock_bh(&rt_uncached_lock);
+               spin_unlock_bh(&ul->lock);
        }
 }
 
 void rt_flush_dev(struct net_device *dev)
 {
-       if (!list_empty(&rt_uncached_list)) {
-               struct net *net = dev_net(dev);
-               struct rtable *rt;
+       struct net *net = dev_net(dev);
+       struct rtable *rt;
+       int cpu;
 
-               spin_lock_bh(&rt_uncached_lock);
-               list_for_each_entry(rt, &rt_uncached_list, rt_uncached) {
+       for_each_possible_cpu(cpu) {
+               struct uncached_list *ul = &per_cpu(rt_uncached_list, cpu);
+
+               spin_lock_bh(&ul->lock);
+               list_for_each_entry(rt, &ul->head, rt_uncached) {
                        if (rt->dst.dev != dev)
                                continue;
                        rt->dst.dev = net->loopback_dev;
                        dev_hold(rt->dst.dev);
                        dev_put(dev);
                }
-               spin_unlock_bh(&rt_uncached_lock);
+               spin_unlock_bh(&ul->lock);
        }
 }
 
@@ -2381,7 +2394,8 @@ static int rt_fill_info(struct net *net,  __be32 dst, __be32 src,
        if (rtnl_put_cacheinfo(skb, &rt->dst, 0, expires, error) < 0)
                goto nla_put_failure;
 
-       return nlmsg_end(skb, nlh);
+       nlmsg_end(skb, nlh);
+       return 0;
 
 nla_put_failure:
        nlmsg_cancel(skb, nlh);
@@ -2473,7 +2487,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh)
        err = rt_fill_info(net, dst, src, &fl4, skb,
                           NETLINK_CB(in_skb).portid, nlh->nlmsg_seq,
                           RTM_NEWROUTE, 0, 0);
-       if (err <= 0)
+       if (err < 0)
                goto errout_free;
 
        err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
@@ -2721,6 +2735,7 @@ struct ip_rt_acct __percpu *ip_rt_acct __read_mostly;
 int __init ip_rt_init(void)
 {
        int rc = 0;
+       int cpu;
 
        ip_idents = kmalloc(IP_IDENTS_SZ * sizeof(*ip_idents), GFP_KERNEL);
        if (!ip_idents)
@@ -2728,6 +2743,12 @@ int __init ip_rt_init(void)
 
        prandom_bytes(ip_idents, IP_IDENTS_SZ * sizeof(*ip_idents));
 
+       for_each_possible_cpu(cpu) {
+               struct uncached_list *ul = &per_cpu(rt_uncached_list, cpu);
+
+               INIT_LIST_HEAD(&ul->head);
+               spin_lock_init(&ul->lock);
+       }
 #ifdef CONFIG_IP_ROUTE_CLASSID
        ip_rt_acct = __alloc_percpu(256 * sizeof(struct ip_rt_acct), __alignof__(struct ip_rt_acct));
        if (!ip_rt_acct)