[PATCH] net: Avoid unaligned access in inet_gro_receive()
Helge Deller <[email protected]>
| Newsgroups | org.kernel.vger.linux-parisc |
|---|---|
| Message-ID | <adVNmmHOtaX65KIJ@p100> |
On the parisc platform the following unaligned accesses are reported regularily: Kernel: unaligned access to 0x173d22e76 in inet_gro_receive+0xbc/0x2e8 (iir 0x0e8810b6) Kernel: unaligned access to 0x173d22e7e in inet_gro_receive+0xc4/0x2e8 (iir 0x0e88109a) Kernel: unaligned access to 0x173d22e82 in inet_gro_receive+0xc8/0x2e8 (iir 0x0e90109d) Kernel: unaligned access to 0x173d22e7a in inet_gro_receive+0xd0/0x2e8 (iir 0x0e9810b8) Kernel: unaligned access to 0x173d22e86 in inet_gro_receive+0xdc/0x2e8 (iir 0x0e8810b8) Avoid those unaligned accesses by using the get_unaligned_xx() helpers. While converting the code, I noticed that while calculating the flush variable we canuse the 16-bit accessors instead of the 32-bit ones, and the flush variable should be of type __u16 and doesn't need to be initialized. Note: Since I don't know the network details, I'm not sure if "~IP_DF" (~0x4000) is correct, or if "IP_OFFSET" (0x1FFF) should be used instead (which I think would be more correct). Instead of breaking things I left it as is. Note 2: Patch still needs runtime testing, so I sent to parisc-linux mailing list only for now.. Signed-off-by: Helge Deller <[email protected]> diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index c7731e300a44..9a0d192b2b35 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1479,7 +1479,7 @@ struct sk_buff *inet_gro_receive(struct list_head *head, struct sk_buff *skb) struct sk_buff *p; unsigned int hlen; unsigned int off; - int flush = 1; + __u16 flush; int proto; off = skb_gro_offset(skb); @@ -1504,7 +1504,8 @@ struct sk_buff *inet_gro_receive(struct list_head *head, struct sk_buff *skb) goto out; NAPI_GRO_CB(skb)->proto = proto; - flush = (u16)((ntohl(*(__be32 *)iph) ^ skb_gro_len(skb)) | (ntohl(*(__be32 *)&iph->id) & ~IP_DF)); + flush = (get_unaligned_be16(&iph->tot_len) ^ skb_gro_len(skb)) | + (get_unaligned_be16(&iph->frag_off) & ~IP_DF); list_for_each_entry(p, head, list) { struct iphdr *iph2; @@ -1519,8 +1520,8 @@ struct sk_buff *inet_gro_receive(struct list_head *head, struct sk_buff *skb) * at the same offset. */ if ((iph->protocol ^ iph2->protocol) | - ((__force u32)iph->saddr ^ (__force u32)iph2->saddr) | - ((__force u32)iph->daddr ^ (__force u32)iph2->daddr)) { + (get_unaligned(&iph->saddr) ^ get_unaligned(&iph2->saddr)) | + (get_unaligned(&iph->daddr) ^ get_unaligned(&iph2->daddr))) { NAPI_GRO_CB(p)->same_flow = 0; continue; }