Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[linux-2.6-block.git] / net / ipv4 / route.c
index d58dd0ec3e5302c2862c8fe53bfd43ca05a3e669..0c63b2abd873fb2102cb5cc34dd80e5d3a26db88 100644 (file)
@@ -1325,14 +1325,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)
@@ -1340,27 +1348,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);
        }
 }
 
@@ -2378,7 +2391,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);
@@ -2470,7 +2484,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);
@@ -2718,6 +2732,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)
@@ -2725,6 +2740,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)