diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2010-06-06 23:17:10 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-06-08 00:25:21 -0400 |
commit | 9a57a9d291980302b4a3184fbc47dbddac71903e (patch) | |
tree | f7e28ced28e4615074ceaf6ab4750a9630cdba95 /net/ipv4/igmp.c | |
parent | 66018506e15bea62de4eefc3298f170b4bfcf5ef (diff) |
igmp: avoid two atomic ops in igmp_rcv()
in_dev_get() -> __in_dev_get_rcu() in a rcu protected function.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/igmp.c')
-rw-r--r-- | net/ipv4/igmp.c | 10 |
1 files changed, 4 insertions, 6 deletions
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 250cb5e1af48..3294f547c481 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c | |||
@@ -916,18 +916,19 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb, | |||
916 | read_unlock(&in_dev->mc_list_lock); | 916 | read_unlock(&in_dev->mc_list_lock); |
917 | } | 917 | } |
918 | 918 | ||
919 | /* called in rcu_read_lock() section */ | ||
919 | int igmp_rcv(struct sk_buff *skb) | 920 | int igmp_rcv(struct sk_buff *skb) |
920 | { | 921 | { |
921 | /* This basically follows the spec line by line -- see RFC1112 */ | 922 | /* This basically follows the spec line by line -- see RFC1112 */ |
922 | struct igmphdr *ih; | 923 | struct igmphdr *ih; |
923 | struct in_device *in_dev = in_dev_get(skb->dev); | 924 | struct in_device *in_dev = __in_dev_get_rcu(skb->dev); |
924 | int len = skb->len; | 925 | int len = skb->len; |
925 | 926 | ||
926 | if (in_dev == NULL) | 927 | if (in_dev == NULL) |
927 | goto drop; | 928 | goto drop; |
928 | 929 | ||
929 | if (!pskb_may_pull(skb, sizeof(struct igmphdr))) | 930 | if (!pskb_may_pull(skb, sizeof(struct igmphdr))) |
930 | goto drop_ref; | 931 | goto drop; |
931 | 932 | ||
932 | switch (skb->ip_summed) { | 933 | switch (skb->ip_summed) { |
933 | case CHECKSUM_COMPLETE: | 934 | case CHECKSUM_COMPLETE: |
@@ -937,7 +938,7 @@ int igmp_rcv(struct sk_buff *skb) | |||
937 | case CHECKSUM_NONE: | 938 | case CHECKSUM_NONE: |
938 | skb->csum = 0; | 939 | skb->csum = 0; |
939 | if (__skb_checksum_complete(skb)) | 940 | if (__skb_checksum_complete(skb)) |
940 | goto drop_ref; | 941 | goto drop; |
941 | } | 942 | } |
942 | 943 | ||
943 | ih = igmp_hdr(skb); | 944 | ih = igmp_hdr(skb); |
@@ -957,7 +958,6 @@ int igmp_rcv(struct sk_buff *skb) | |||
957 | break; | 958 | break; |
958 | case IGMP_PIM: | 959 | case IGMP_PIM: |
959 | #ifdef CONFIG_IP_PIMSM_V1 | 960 | #ifdef CONFIG_IP_PIMSM_V1 |
960 | in_dev_put(in_dev); | ||
961 | return pim_rcv_v1(skb); | 961 | return pim_rcv_v1(skb); |
962 | #endif | 962 | #endif |
963 | case IGMPV3_HOST_MEMBERSHIP_REPORT: | 963 | case IGMPV3_HOST_MEMBERSHIP_REPORT: |
@@ -971,8 +971,6 @@ int igmp_rcv(struct sk_buff *skb) | |||
971 | break; | 971 | break; |
972 | } | 972 | } |
973 | 973 | ||
974 | drop_ref: | ||
975 | in_dev_put(in_dev); | ||
976 | drop: | 974 | drop: |
977 | kfree_skb(skb); | 975 | kfree_skb(skb); |
978 | return 0; | 976 | return 0; |