diff options
author | Jack Morgenstein <jackm@mellanox.co.il> | 2006-05-29 12:14:05 -0400 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2006-06-17 23:37:35 -0400 |
commit | 37c22a77212c13201497378cc8becc5c95d0f3f5 (patch) | |
tree | 5a38388266a09c9892e5d8e336d7287ae763e7c0 /drivers/infiniband | |
parent | 31c02e215700c2b704d9441f629ae87bb9aeb561 (diff) |
IPoIB: Fix kernel unaligned access on ia64
Fix misaligned access faults on ia64: never cast a misaligned
neighbour->ha + 4 pointer to union ib_gid type; pass a void * pointer
instead. The memcpy was being optimized to use full word accesses
because the compiler thought that union ib_gid is always aligned.
The cast in IPOIB_GID_ARG is safe, since it is fixed to access each
byte separately.
Signed-off-by: Jack Morgenstein <jackm@mellanox.co.il>
Signed-off-by: Michael S. Tsirkin <mst@mellanox.co.il>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib.h | 34 | ||||
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_main.c | 28 | ||||
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_multicast.c | 11 |
3 files changed, 39 insertions, 34 deletions
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index 12a1e0572ef2..491d2afaf5b4 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h | |||
@@ -272,8 +272,7 @@ int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port); | |||
272 | void ipoib_dev_cleanup(struct net_device *dev); | 272 | void ipoib_dev_cleanup(struct net_device *dev); |
273 | 273 | ||
274 | void ipoib_mcast_join_task(void *dev_ptr); | 274 | void ipoib_mcast_join_task(void *dev_ptr); |
275 | void ipoib_mcast_send(struct net_device *dev, union ib_gid *mgid, | 275 | void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb); |
276 | struct sk_buff *skb); | ||
277 | 276 | ||
278 | void ipoib_mcast_restart_task(void *dev_ptr); | 277 | void ipoib_mcast_restart_task(void *dev_ptr); |
279 | int ipoib_mcast_start_thread(struct net_device *dev); | 278 | int ipoib_mcast_start_thread(struct net_device *dev); |
@@ -369,15 +368,26 @@ extern int ipoib_debug_level; | |||
369 | #endif /* CONFIG_INFINIBAND_IPOIB_DEBUG_DATA */ | 368 | #endif /* CONFIG_INFINIBAND_IPOIB_DEBUG_DATA */ |
370 | 369 | ||
371 | 370 | ||
372 | #define IPOIB_GID_FMT "%x:%x:%x:%x:%x:%x:%x:%x" | 371 | #define IPOIB_GID_FMT "%2.2x%2.2x:%2.2x%2.2x:%2.2x%2.2x:%2.2x%2.2x:" \ |
373 | 372 | "%2.2x%2.2x:%2.2x%2.2x:%2.2x%2.2x:%2.2x%2.2x" | |
374 | #define IPOIB_GID_ARG(gid) be16_to_cpup((__be16 *) ((gid).raw + 0)), \ | 373 | |
375 | be16_to_cpup((__be16 *) ((gid).raw + 2)), \ | 374 | #define IPOIB_GID_RAW_ARG(gid) ((u8 *)(gid))[0], \ |
376 | be16_to_cpup((__be16 *) ((gid).raw + 4)), \ | 375 | ((u8 *)(gid))[1], \ |
377 | be16_to_cpup((__be16 *) ((gid).raw + 6)), \ | 376 | ((u8 *)(gid))[2], \ |
378 | be16_to_cpup((__be16 *) ((gid).raw + 8)), \ | 377 | ((u8 *)(gid))[3], \ |
379 | be16_to_cpup((__be16 *) ((gid).raw + 10)), \ | 378 | ((u8 *)(gid))[4], \ |
380 | be16_to_cpup((__be16 *) ((gid).raw + 12)), \ | 379 | ((u8 *)(gid))[5], \ |
381 | be16_to_cpup((__be16 *) ((gid).raw + 14)) | 380 | ((u8 *)(gid))[6], \ |
381 | ((u8 *)(gid))[7], \ | ||
382 | ((u8 *)(gid))[8], \ | ||
383 | ((u8 *)(gid))[9], \ | ||
384 | ((u8 *)(gid))[10],\ | ||
385 | ((u8 *)(gid))[11],\ | ||
386 | ((u8 *)(gid))[12],\ | ||
387 | ((u8 *)(gid))[13],\ | ||
388 | ((u8 *)(gid))[14],\ | ||
389 | ((u8 *)(gid))[15] | ||
390 | |||
391 | #define IPOIB_GID_ARG(gid) IPOIB_GID_RAW_ARG((gid).raw) | ||
382 | 392 | ||
383 | #endif /* _IPOIB_H */ | 393 | #endif /* _IPOIB_H */ |
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index cb078a7d0bf5..1c6ea1c682a5 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c | |||
@@ -185,8 +185,7 @@ static int ipoib_change_mtu(struct net_device *dev, int new_mtu) | |||
185 | return 0; | 185 | return 0; |
186 | } | 186 | } |
187 | 187 | ||
188 | static struct ipoib_path *__path_find(struct net_device *dev, | 188 | static struct ipoib_path *__path_find(struct net_device *dev, void *gid) |
189 | union ib_gid *gid) | ||
190 | { | 189 | { |
191 | struct ipoib_dev_priv *priv = netdev_priv(dev); | 190 | struct ipoib_dev_priv *priv = netdev_priv(dev); |
192 | struct rb_node *n = priv->path_tree.rb_node; | 191 | struct rb_node *n = priv->path_tree.rb_node; |
@@ -196,7 +195,7 @@ static struct ipoib_path *__path_find(struct net_device *dev, | |||
196 | while (n) { | 195 | while (n) { |
197 | path = rb_entry(n, struct ipoib_path, rb_node); | 196 | path = rb_entry(n, struct ipoib_path, rb_node); |
198 | 197 | ||
199 | ret = memcmp(gid->raw, path->pathrec.dgid.raw, | 198 | ret = memcmp(gid, path->pathrec.dgid.raw, |
200 | sizeof (union ib_gid)); | 199 | sizeof (union ib_gid)); |
201 | 200 | ||
202 | if (ret < 0) | 201 | if (ret < 0) |
@@ -424,8 +423,7 @@ static void path_rec_completion(int status, | |||
424 | } | 423 | } |
425 | } | 424 | } |
426 | 425 | ||
427 | static struct ipoib_path *path_rec_create(struct net_device *dev, | 426 | static struct ipoib_path *path_rec_create(struct net_device *dev, void *gid) |
428 | union ib_gid *gid) | ||
429 | { | 427 | { |
430 | struct ipoib_dev_priv *priv = netdev_priv(dev); | 428 | struct ipoib_dev_priv *priv = netdev_priv(dev); |
431 | struct ipoib_path *path; | 429 | struct ipoib_path *path; |
@@ -440,7 +438,7 @@ static struct ipoib_path *path_rec_create(struct net_device *dev, | |||
440 | 438 | ||
441 | INIT_LIST_HEAD(&path->neigh_list); | 439 | INIT_LIST_HEAD(&path->neigh_list); |
442 | 440 | ||
443 | memcpy(path->pathrec.dgid.raw, gid->raw, sizeof (union ib_gid)); | 441 | memcpy(path->pathrec.dgid.raw, gid, sizeof (union ib_gid)); |
444 | path->pathrec.sgid = priv->local_gid; | 442 | path->pathrec.sgid = priv->local_gid; |
445 | path->pathrec.pkey = cpu_to_be16(priv->pkey); | 443 | path->pathrec.pkey = cpu_to_be16(priv->pkey); |
446 | path->pathrec.numb_path = 1; | 444 | path->pathrec.numb_path = 1; |
@@ -498,10 +496,9 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) | |||
498 | */ | 496 | */ |
499 | spin_lock(&priv->lock); | 497 | spin_lock(&priv->lock); |
500 | 498 | ||
501 | path = __path_find(dev, (union ib_gid *) (skb->dst->neighbour->ha + 4)); | 499 | path = __path_find(dev, skb->dst->neighbour->ha + 4); |
502 | if (!path) { | 500 | if (!path) { |
503 | path = path_rec_create(dev, | 501 | path = path_rec_create(dev, skb->dst->neighbour->ha + 4); |
504 | (union ib_gid *) (skb->dst->neighbour->ha + 4)); | ||
505 | if (!path) | 502 | if (!path) |
506 | goto err_path; | 503 | goto err_path; |
507 | 504 | ||
@@ -551,7 +548,7 @@ static void ipoib_path_lookup(struct sk_buff *skb, struct net_device *dev) | |||
551 | /* Add in the P_Key for multicasts */ | 548 | /* Add in the P_Key for multicasts */ |
552 | skb->dst->neighbour->ha[8] = (priv->pkey >> 8) & 0xff; | 549 | skb->dst->neighbour->ha[8] = (priv->pkey >> 8) & 0xff; |
553 | skb->dst->neighbour->ha[9] = priv->pkey & 0xff; | 550 | skb->dst->neighbour->ha[9] = priv->pkey & 0xff; |
554 | ipoib_mcast_send(dev, (union ib_gid *) (skb->dst->neighbour->ha + 4), skb); | 551 | ipoib_mcast_send(dev, skb->dst->neighbour->ha + 4, skb); |
555 | } | 552 | } |
556 | 553 | ||
557 | static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, | 554 | static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, |
@@ -566,10 +563,9 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, | |||
566 | */ | 563 | */ |
567 | spin_lock(&priv->lock); | 564 | spin_lock(&priv->lock); |
568 | 565 | ||
569 | path = __path_find(dev, (union ib_gid *) (phdr->hwaddr + 4)); | 566 | path = __path_find(dev, phdr->hwaddr + 4); |
570 | if (!path) { | 567 | if (!path) { |
571 | path = path_rec_create(dev, | 568 | path = path_rec_create(dev, phdr->hwaddr + 4); |
572 | (union ib_gid *) (phdr->hwaddr + 4)); | ||
573 | if (path) { | 569 | if (path) { |
574 | /* put pseudoheader back on for next time */ | 570 | /* put pseudoheader back on for next time */ |
575 | skb_push(skb, sizeof *phdr); | 571 | skb_push(skb, sizeof *phdr); |
@@ -660,7 +656,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
660 | phdr->hwaddr[8] = (priv->pkey >> 8) & 0xff; | 656 | phdr->hwaddr[8] = (priv->pkey >> 8) & 0xff; |
661 | phdr->hwaddr[9] = priv->pkey & 0xff; | 657 | phdr->hwaddr[9] = priv->pkey & 0xff; |
662 | 658 | ||
663 | ipoib_mcast_send(dev, (union ib_gid *) (phdr->hwaddr + 4), skb); | 659 | ipoib_mcast_send(dev, phdr->hwaddr + 4, skb); |
664 | } else { | 660 | } else { |
665 | /* unicast GID -- should be ARP or RARP reply */ | 661 | /* unicast GID -- should be ARP or RARP reply */ |
666 | 662 | ||
@@ -671,7 +667,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
671 | skb->dst ? "neigh" : "dst", | 667 | skb->dst ? "neigh" : "dst", |
672 | be16_to_cpup((__be16 *) skb->data), | 668 | be16_to_cpup((__be16 *) skb->data), |
673 | be32_to_cpup((__be32 *) phdr->hwaddr), | 669 | be32_to_cpup((__be32 *) phdr->hwaddr), |
674 | IPOIB_GID_ARG(*(union ib_gid *) (phdr->hwaddr + 4))); | 670 | IPOIB_GID_RAW_ARG(phdr->hwaddr + 4)); |
675 | dev_kfree_skb_any(skb); | 671 | dev_kfree_skb_any(skb); |
676 | ++priv->stats.tx_dropped; | 672 | ++priv->stats.tx_dropped; |
677 | goto out; | 673 | goto out; |
@@ -754,7 +750,7 @@ static void ipoib_neigh_destructor(struct neighbour *n) | |||
754 | ipoib_dbg(priv, | 750 | ipoib_dbg(priv, |
755 | "neigh_destructor for %06x " IPOIB_GID_FMT "\n", | 751 | "neigh_destructor for %06x " IPOIB_GID_FMT "\n", |
756 | be32_to_cpup((__be32 *) n->ha), | 752 | be32_to_cpup((__be32 *) n->ha), |
757 | IPOIB_GID_ARG(*((union ib_gid *) (n->ha + 4)))); | 753 | IPOIB_GID_RAW_ARG(n->ha + 4)); |
758 | 754 | ||
759 | spin_lock_irqsave(&priv->lock, flags); | 755 | spin_lock_irqsave(&priv->lock, flags); |
760 | 756 | ||
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index 1dae4b238252..ec41c8f46c72 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c | |||
@@ -154,7 +154,7 @@ static struct ipoib_mcast *ipoib_mcast_alloc(struct net_device *dev, | |||
154 | return mcast; | 154 | return mcast; |
155 | } | 155 | } |
156 | 156 | ||
157 | static struct ipoib_mcast *__ipoib_mcast_find(struct net_device *dev, union ib_gid *mgid) | 157 | static struct ipoib_mcast *__ipoib_mcast_find(struct net_device *dev, void *mgid) |
158 | { | 158 | { |
159 | struct ipoib_dev_priv *priv = netdev_priv(dev); | 159 | struct ipoib_dev_priv *priv = netdev_priv(dev); |
160 | struct rb_node *n = priv->multicast_tree.rb_node; | 160 | struct rb_node *n = priv->multicast_tree.rb_node; |
@@ -165,7 +165,7 @@ static struct ipoib_mcast *__ipoib_mcast_find(struct net_device *dev, union ib_g | |||
165 | 165 | ||
166 | mcast = rb_entry(n, struct ipoib_mcast, rb_node); | 166 | mcast = rb_entry(n, struct ipoib_mcast, rb_node); |
167 | 167 | ||
168 | ret = memcmp(mgid->raw, mcast->mcmember.mgid.raw, | 168 | ret = memcmp(mgid, mcast->mcmember.mgid.raw, |
169 | sizeof (union ib_gid)); | 169 | sizeof (union ib_gid)); |
170 | if (ret < 0) | 170 | if (ret < 0) |
171 | n = n->rb_left; | 171 | n = n->rb_left; |
@@ -694,8 +694,7 @@ static int ipoib_mcast_leave(struct net_device *dev, struct ipoib_mcast *mcast) | |||
694 | return 0; | 694 | return 0; |
695 | } | 695 | } |
696 | 696 | ||
697 | void ipoib_mcast_send(struct net_device *dev, union ib_gid *mgid, | 697 | void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb) |
698 | struct sk_buff *skb) | ||
699 | { | 698 | { |
700 | struct ipoib_dev_priv *priv = netdev_priv(dev); | 699 | struct ipoib_dev_priv *priv = netdev_priv(dev); |
701 | struct ipoib_mcast *mcast; | 700 | struct ipoib_mcast *mcast; |
@@ -718,7 +717,7 @@ void ipoib_mcast_send(struct net_device *dev, union ib_gid *mgid, | |||
718 | if (!mcast) { | 717 | if (!mcast) { |
719 | /* Let's create a new send only group now */ | 718 | /* Let's create a new send only group now */ |
720 | ipoib_dbg_mcast(priv, "setting up send only multicast group for " | 719 | ipoib_dbg_mcast(priv, "setting up send only multicast group for " |
721 | IPOIB_GID_FMT "\n", IPOIB_GID_ARG(*mgid)); | 720 | IPOIB_GID_FMT "\n", IPOIB_GID_RAW_ARG(mgid)); |
722 | 721 | ||
723 | mcast = ipoib_mcast_alloc(dev, 0); | 722 | mcast = ipoib_mcast_alloc(dev, 0); |
724 | if (!mcast) { | 723 | if (!mcast) { |
@@ -730,7 +729,7 @@ void ipoib_mcast_send(struct net_device *dev, union ib_gid *mgid, | |||
730 | } | 729 | } |
731 | 730 | ||
732 | set_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags); | 731 | set_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags); |
733 | mcast->mcmember.mgid = *mgid; | 732 | memcpy(mcast->mcmember.mgid.raw, mgid, sizeof (union ib_gid)); |
734 | __ipoib_mcast_add(dev, mcast); | 733 | __ipoib_mcast_add(dev, mcast); |
735 | list_add_tail(&mcast->list, &priv->multicast_list); | 734 | list_add_tail(&mcast->list, &priv->multicast_list); |
736 | } | 735 | } |