aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2011-11-16 22:13:26 -0500
committerDavid S. Miller <davem@davemloft.net>2011-11-17 17:06:08 -0500
commitadc9300e78e6091a7eaa1821213836379d4dbaa8 (patch)
treeb2d075990b32e8c21129851bf1b1adf4cdc441f1
parentd6f144830bdfa5fcf116e9ab8fc6a60d23fa623d (diff)
net: use jump_label to shortcut RPS if not setup
Most machines dont use RPS/RFS, and pay a fair amount of instructions in netif_receive_skb() / netif_rx() / get_rps_cpu() just to discover RPS/RFS is not setup. Add a jump_label named rps_needed. If no device rps_map or global rps_sock_flow_table is setup, netif_receive_skb() / netif_rx() do a single instruction instead of many ones, including conditional jumps. jmp +0 (if CONFIG_JUMP_LABEL=y) Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> CC: Tom Herbert <therbert@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/netdevice.h5
-rw-r--r--net/core/dev.c21
-rw-r--r--net/core/net-sysfs.c7
-rw-r--r--net/core/sysctl_net_core.c9
4 files changed, 26 insertions, 16 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 4d5698aa828b..0bbe030fc014 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -214,6 +214,11 @@ enum {
214#include <linux/cache.h> 214#include <linux/cache.h>
215#include <linux/skbuff.h> 215#include <linux/skbuff.h>
216 216
217#ifdef CONFIG_RPS
218#include <linux/jump_label.h>
219extern struct jump_label_key rps_needed;
220#endif
221
217struct neighbour; 222struct neighbour;
218struct neigh_parms; 223struct neigh_parms;
219struct sk_buff; 224struct sk_buff;
diff --git a/net/core/dev.c b/net/core/dev.c
index 26c49d55e79d..f78959996148 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2711,6 +2711,8 @@ EXPORT_SYMBOL(__skb_get_rxhash);
2711struct rps_sock_flow_table __rcu *rps_sock_flow_table __read_mostly; 2711struct rps_sock_flow_table __rcu *rps_sock_flow_table __read_mostly;
2712EXPORT_SYMBOL(rps_sock_flow_table); 2712EXPORT_SYMBOL(rps_sock_flow_table);
2713 2713
2714struct jump_label_key rps_needed __read_mostly;
2715
2714static struct rps_dev_flow * 2716static struct rps_dev_flow *
2715set_rps_cpu(struct net_device *dev, struct sk_buff *skb, 2717set_rps_cpu(struct net_device *dev, struct sk_buff *skb,
2716 struct rps_dev_flow *rflow, u16 next_cpu) 2718 struct rps_dev_flow *rflow, u16 next_cpu)
@@ -2994,7 +2996,7 @@ int netif_rx(struct sk_buff *skb)
2994 2996
2995 trace_netif_rx(skb); 2997 trace_netif_rx(skb);
2996#ifdef CONFIG_RPS 2998#ifdef CONFIG_RPS
2997 { 2999 if (static_branch(&rps_needed)) {
2998 struct rps_dev_flow voidflow, *rflow = &voidflow; 3000 struct rps_dev_flow voidflow, *rflow = &voidflow;
2999 int cpu; 3001 int cpu;
3000 3002
@@ -3009,14 +3011,13 @@ int netif_rx(struct sk_buff *skb)
3009 3011
3010 rcu_read_unlock(); 3012 rcu_read_unlock();
3011 preempt_enable(); 3013 preempt_enable();
3012 } 3014 } else
3013#else 3015#endif
3014 { 3016 {
3015 unsigned int qtail; 3017 unsigned int qtail;
3016 ret = enqueue_to_backlog(skb, get_cpu(), &qtail); 3018 ret = enqueue_to_backlog(skb, get_cpu(), &qtail);
3017 put_cpu(); 3019 put_cpu();
3018 } 3020 }
3019#endif
3020 return ret; 3021 return ret;
3021} 3022}
3022EXPORT_SYMBOL(netif_rx); 3023EXPORT_SYMBOL(netif_rx);
@@ -3359,7 +3360,7 @@ int netif_receive_skb(struct sk_buff *skb)
3359 return NET_RX_SUCCESS; 3360 return NET_RX_SUCCESS;
3360 3361
3361#ifdef CONFIG_RPS 3362#ifdef CONFIG_RPS
3362 { 3363 if (static_branch(&rps_needed)) {
3363 struct rps_dev_flow voidflow, *rflow = &voidflow; 3364 struct rps_dev_flow voidflow, *rflow = &voidflow;
3364 int cpu, ret; 3365 int cpu, ret;
3365 3366
@@ -3370,16 +3371,12 @@ int netif_receive_skb(struct sk_buff *skb)
3370 if (cpu >= 0) { 3371 if (cpu >= 0) {
3371 ret = enqueue_to_backlog(skb, cpu, &rflow->last_qtail); 3372 ret = enqueue_to_backlog(skb, cpu, &rflow->last_qtail);
3372 rcu_read_unlock(); 3373 rcu_read_unlock();
3373 } else { 3374 return ret;
3374 rcu_read_unlock();
3375 ret = __netif_receive_skb(skb);
3376 } 3375 }
3377 3376 rcu_read_unlock();
3378 return ret;
3379 } 3377 }
3380#else
3381 return __netif_receive_skb(skb);
3382#endif 3378#endif
3379 return __netif_receive_skb(skb);
3383} 3380}
3384EXPORT_SYMBOL(netif_receive_skb); 3381EXPORT_SYMBOL(netif_receive_skb);
3385 3382
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index 602b1419998c..db6c2f83633f 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -606,9 +606,12 @@ static ssize_t store_rps_map(struct netdev_rx_queue *queue,
606 rcu_assign_pointer(queue->rps_map, map); 606 rcu_assign_pointer(queue->rps_map, map);
607 spin_unlock(&rps_map_lock); 607 spin_unlock(&rps_map_lock);
608 608
609 if (old_map) 609 if (map)
610 jump_label_inc(&rps_needed);
611 if (old_map) {
610 kfree_rcu(old_map, rcu); 612 kfree_rcu(old_map, rcu);
611 613 jump_label_dec(&rps_needed);
614 }
612 free_cpumask_var(mask); 615 free_cpumask_var(mask);
613 return len; 616 return len;
614} 617}
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index 77a65f031488..d05559d4d9cd 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -68,8 +68,13 @@ static int rps_sock_flow_sysctl(ctl_table *table, int write,
68 68
69 if (sock_table != orig_sock_table) { 69 if (sock_table != orig_sock_table) {
70 rcu_assign_pointer(rps_sock_flow_table, sock_table); 70 rcu_assign_pointer(rps_sock_flow_table, sock_table);
71 synchronize_rcu(); 71 if (sock_table)
72 vfree(orig_sock_table); 72 jump_label_inc(&rps_needed);
73 if (orig_sock_table) {
74 jump_label_dec(&rps_needed);
75 synchronize_rcu();
76 vfree(orig_sock_table);
77 }
73 } 78 }
74 } 79 }
75 80