Commit 37c22a77 authored by Jack Morgenstein's avatar Jack Morgenstein Committed by Roland Dreier

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: default avatarJack Morgenstein <jackm@mellanox.co.il>
Signed-off-by: default avatarMichael S. Tsirkin <mst@mellanox.co.il>
Signed-off-by: default avatarRoland Dreier <rolandd@cisco.com>
parent 31c02e21
...@@ -272,8 +272,7 @@ int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port); ...@@ -272,8 +272,7 @@ int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port);
void ipoib_dev_cleanup(struct net_device *dev); void ipoib_dev_cleanup(struct net_device *dev);
void ipoib_mcast_join_task(void *dev_ptr); void ipoib_mcast_join_task(void *dev_ptr);
void ipoib_mcast_send(struct net_device *dev, union ib_gid *mgid, void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb);
struct sk_buff *skb);
void ipoib_mcast_restart_task(void *dev_ptr); void ipoib_mcast_restart_task(void *dev_ptr);
int ipoib_mcast_start_thread(struct net_device *dev); int ipoib_mcast_start_thread(struct net_device *dev);
...@@ -369,15 +368,26 @@ extern int ipoib_debug_level; ...@@ -369,15 +368,26 @@ extern int ipoib_debug_level;
#endif /* CONFIG_INFINIBAND_IPOIB_DEBUG_DATA */ #endif /* CONFIG_INFINIBAND_IPOIB_DEBUG_DATA */
#define IPOIB_GID_FMT "%x:%x:%x:%x:%x:%x:%x:%x" #define IPOIB_GID_FMT "%2.2x%2.2x:%2.2x%2.2x:%2.2x%2.2x:%2.2x%2.2x:" \
"%2.2x%2.2x:%2.2x%2.2x:%2.2x%2.2x:%2.2x%2.2x"
#define IPOIB_GID_ARG(gid) be16_to_cpup((__be16 *) ((gid).raw + 0)), \
be16_to_cpup((__be16 *) ((gid).raw + 2)), \ #define IPOIB_GID_RAW_ARG(gid) ((u8 *)(gid))[0], \
be16_to_cpup((__be16 *) ((gid).raw + 4)), \ ((u8 *)(gid))[1], \
be16_to_cpup((__be16 *) ((gid).raw + 6)), \ ((u8 *)(gid))[2], \
be16_to_cpup((__be16 *) ((gid).raw + 8)), \ ((u8 *)(gid))[3], \
be16_to_cpup((__be16 *) ((gid).raw + 10)), \ ((u8 *)(gid))[4], \
be16_to_cpup((__be16 *) ((gid).raw + 12)), \ ((u8 *)(gid))[5], \
be16_to_cpup((__be16 *) ((gid).raw + 14)) ((u8 *)(gid))[6], \
((u8 *)(gid))[7], \
((u8 *)(gid))[8], \
((u8 *)(gid))[9], \
((u8 *)(gid))[10],\
((u8 *)(gid))[11],\
((u8 *)(gid))[12],\
((u8 *)(gid))[13],\
((u8 *)(gid))[14],\
((u8 *)(gid))[15]
#define IPOIB_GID_ARG(gid) IPOIB_GID_RAW_ARG((gid).raw)
#endif /* _IPOIB_H */ #endif /* _IPOIB_H */
...@@ -185,8 +185,7 @@ static int ipoib_change_mtu(struct net_device *dev, int new_mtu) ...@@ -185,8 +185,7 @@ static int ipoib_change_mtu(struct net_device *dev, int new_mtu)
return 0; return 0;
} }
static struct ipoib_path *__path_find(struct net_device *dev, static struct ipoib_path *__path_find(struct net_device *dev, void *gid)
union ib_gid *gid)
{ {
struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_dev_priv *priv = netdev_priv(dev);
struct rb_node *n = priv->path_tree.rb_node; struct rb_node *n = priv->path_tree.rb_node;
...@@ -196,7 +195,7 @@ static struct ipoib_path *__path_find(struct net_device *dev, ...@@ -196,7 +195,7 @@ static struct ipoib_path *__path_find(struct net_device *dev,
while (n) { while (n) {
path = rb_entry(n, struct ipoib_path, rb_node); path = rb_entry(n, struct ipoib_path, rb_node);
ret = memcmp(gid->raw, path->pathrec.dgid.raw, ret = memcmp(gid, path->pathrec.dgid.raw,
sizeof (union ib_gid)); sizeof (union ib_gid));
if (ret < 0) if (ret < 0)
...@@ -424,8 +423,7 @@ static void path_rec_completion(int status, ...@@ -424,8 +423,7 @@ static void path_rec_completion(int status,
} }
} }
static struct ipoib_path *path_rec_create(struct net_device *dev, static struct ipoib_path *path_rec_create(struct net_device *dev, void *gid)
union ib_gid *gid)
{ {
struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ipoib_path *path; struct ipoib_path *path;
...@@ -440,7 +438,7 @@ static struct ipoib_path *path_rec_create(struct net_device *dev, ...@@ -440,7 +438,7 @@ static struct ipoib_path *path_rec_create(struct net_device *dev,
INIT_LIST_HEAD(&path->neigh_list); INIT_LIST_HEAD(&path->neigh_list);
memcpy(path->pathrec.dgid.raw, gid->raw, sizeof (union ib_gid)); memcpy(path->pathrec.dgid.raw, gid, sizeof (union ib_gid));
path->pathrec.sgid = priv->local_gid; path->pathrec.sgid = priv->local_gid;
path->pathrec.pkey = cpu_to_be16(priv->pkey); path->pathrec.pkey = cpu_to_be16(priv->pkey);
path->pathrec.numb_path = 1; path->pathrec.numb_path = 1;
...@@ -498,10 +496,9 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) ...@@ -498,10 +496,9 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
*/ */
spin_lock(&priv->lock); spin_lock(&priv->lock);
path = __path_find(dev, (union ib_gid *) (skb->dst->neighbour->ha + 4)); path = __path_find(dev, skb->dst->neighbour->ha + 4);
if (!path) { if (!path) {
path = path_rec_create(dev, path = path_rec_create(dev, skb->dst->neighbour->ha + 4);
(union ib_gid *) (skb->dst->neighbour->ha + 4));
if (!path) if (!path)
goto err_path; goto err_path;
...@@ -551,7 +548,7 @@ static void ipoib_path_lookup(struct sk_buff *skb, struct net_device *dev) ...@@ -551,7 +548,7 @@ static void ipoib_path_lookup(struct sk_buff *skb, struct net_device *dev)
/* Add in the P_Key for multicasts */ /* Add in the P_Key for multicasts */
skb->dst->neighbour->ha[8] = (priv->pkey >> 8) & 0xff; skb->dst->neighbour->ha[8] = (priv->pkey >> 8) & 0xff;
skb->dst->neighbour->ha[9] = priv->pkey & 0xff; skb->dst->neighbour->ha[9] = priv->pkey & 0xff;
ipoib_mcast_send(dev, (union ib_gid *) (skb->dst->neighbour->ha + 4), skb); ipoib_mcast_send(dev, skb->dst->neighbour->ha + 4, skb);
} }
static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, 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,10 +563,9 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
*/ */
spin_lock(&priv->lock); spin_lock(&priv->lock);
path = __path_find(dev, (union ib_gid *) (phdr->hwaddr + 4)); path = __path_find(dev, phdr->hwaddr + 4);
if (!path) { if (!path) {
path = path_rec_create(dev, path = path_rec_create(dev, phdr->hwaddr + 4);
(union ib_gid *) (phdr->hwaddr + 4));
if (path) { if (path) {
/* put pseudoheader back on for next time */ /* put pseudoheader back on for next time */
skb_push(skb, sizeof *phdr); skb_push(skb, sizeof *phdr);
...@@ -660,7 +656,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -660,7 +656,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
phdr->hwaddr[8] = (priv->pkey >> 8) & 0xff; phdr->hwaddr[8] = (priv->pkey >> 8) & 0xff;
phdr->hwaddr[9] = priv->pkey & 0xff; phdr->hwaddr[9] = priv->pkey & 0xff;
ipoib_mcast_send(dev, (union ib_gid *) (phdr->hwaddr + 4), skb); ipoib_mcast_send(dev, phdr->hwaddr + 4, skb);
} else { } else {
/* unicast GID -- should be ARP or RARP reply */ /* unicast GID -- should be ARP or RARP reply */
...@@ -671,7 +667,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -671,7 +667,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb->dst ? "neigh" : "dst", skb->dst ? "neigh" : "dst",
be16_to_cpup((__be16 *) skb->data), be16_to_cpup((__be16 *) skb->data),
be32_to_cpup((__be32 *) phdr->hwaddr), be32_to_cpup((__be32 *) phdr->hwaddr),
IPOIB_GID_ARG(*(union ib_gid *) (phdr->hwaddr + 4))); IPOIB_GID_RAW_ARG(phdr->hwaddr + 4));
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
++priv->stats.tx_dropped; ++priv->stats.tx_dropped;
goto out; goto out;
...@@ -754,7 +750,7 @@ static void ipoib_neigh_destructor(struct neighbour *n) ...@@ -754,7 +750,7 @@ static void ipoib_neigh_destructor(struct neighbour *n)
ipoib_dbg(priv, ipoib_dbg(priv,
"neigh_destructor for %06x " IPOIB_GID_FMT "\n", "neigh_destructor for %06x " IPOIB_GID_FMT "\n",
be32_to_cpup((__be32 *) n->ha), be32_to_cpup((__be32 *) n->ha),
IPOIB_GID_ARG(*((union ib_gid *) (n->ha + 4)))); IPOIB_GID_RAW_ARG(n->ha + 4));
spin_lock_irqsave(&priv->lock, flags); spin_lock_irqsave(&priv->lock, flags);
......
...@@ -154,7 +154,7 @@ static struct ipoib_mcast *ipoib_mcast_alloc(struct net_device *dev, ...@@ -154,7 +154,7 @@ static struct ipoib_mcast *ipoib_mcast_alloc(struct net_device *dev,
return mcast; return mcast;
} }
static struct ipoib_mcast *__ipoib_mcast_find(struct net_device *dev, union ib_gid *mgid) static struct ipoib_mcast *__ipoib_mcast_find(struct net_device *dev, void *mgid)
{ {
struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_dev_priv *priv = netdev_priv(dev);
struct rb_node *n = priv->multicast_tree.rb_node; 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,7 +165,7 @@ static struct ipoib_mcast *__ipoib_mcast_find(struct net_device *dev, union ib_g
mcast = rb_entry(n, struct ipoib_mcast, rb_node); mcast = rb_entry(n, struct ipoib_mcast, rb_node);
ret = memcmp(mgid->raw, mcast->mcmember.mgid.raw, ret = memcmp(mgid, mcast->mcmember.mgid.raw,
sizeof (union ib_gid)); sizeof (union ib_gid));
if (ret < 0) if (ret < 0)
n = n->rb_left; n = n->rb_left;
...@@ -694,8 +694,7 @@ static int ipoib_mcast_leave(struct net_device *dev, struct ipoib_mcast *mcast) ...@@ -694,8 +694,7 @@ static int ipoib_mcast_leave(struct net_device *dev, struct ipoib_mcast *mcast)
return 0; return 0;
} }
void ipoib_mcast_send(struct net_device *dev, union ib_gid *mgid, void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb)
struct sk_buff *skb)
{ {
struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ipoib_mcast *mcast; struct ipoib_mcast *mcast;
...@@ -718,7 +717,7 @@ void ipoib_mcast_send(struct net_device *dev, union ib_gid *mgid, ...@@ -718,7 +717,7 @@ void ipoib_mcast_send(struct net_device *dev, union ib_gid *mgid,
if (!mcast) { if (!mcast) {
/* Let's create a new send only group now */ /* Let's create a new send only group now */
ipoib_dbg_mcast(priv, "setting up send only multicast group for " ipoib_dbg_mcast(priv, "setting up send only multicast group for "
IPOIB_GID_FMT "\n", IPOIB_GID_ARG(*mgid)); IPOIB_GID_FMT "\n", IPOIB_GID_RAW_ARG(mgid));
mcast = ipoib_mcast_alloc(dev, 0); mcast = ipoib_mcast_alloc(dev, 0);
if (!mcast) { if (!mcast) {
...@@ -730,7 +729,7 @@ void ipoib_mcast_send(struct net_device *dev, union ib_gid *mgid, ...@@ -730,7 +729,7 @@ void ipoib_mcast_send(struct net_device *dev, union ib_gid *mgid,
} }
set_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags); set_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags);
mcast->mcmember.mgid = *mgid; memcpy(mcast->mcmember.mgid.raw, mgid, sizeof (union ib_gid));
__ipoib_mcast_add(dev, mcast); __ipoib_mcast_add(dev, mcast);
list_add_tail(&mcast->list, &priv->multicast_list); list_add_tail(&mcast->list, &priv->multicast_list);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment