aboutsummaryrefslogtreecommitdiff
path: root/drivers/s390/net/qeth.h
diff options
context:
space:
mode:
authorFrank Pavlic <fpavlic@de.ibm.com>2006-09-15 16:26:19 +0200
committerJeff Garzik <jeff@garzik.org>2006-09-17 01:03:07 -0400
commitf7b65d70a3e6f1c97eb614964270816992d0d4b4 (patch)
treefae68b2d6c215abacd3074b81bc320f5b3e3a0e0 /drivers/s390/net/qeth.h
parent1fda1a120b7dcddf382ad105b4783a69e81c7a2b (diff)
[PATCH] s390: qeth driver fixes [3/6]
[PATCH 6/9] s390: qeth driver fixes [3/6] From: Frank Pavlic <fpavlic@de.ibm.com> fixed kernel panic caused by qeth driver: Using a bonding device qeth driver will realloc headroom for every skb coming from the bond device. Once this happens qeth frees the original skb and set the skb pointer to the new realloced skb. Under heavy transmit workload (e.g.UDP streams) through bond network device the qdio output queue might get full. In this case we return with EBUSY from qeth_send_packet. Returning to qeth_hard_start_xmit routine the skb address on the stack still points to the old address, which has been freed before. Returning from qeth_hard_start_xmit with EBUSY results in requeuing the skb. In this case it corrupts the qdisc queue and results in kernel panic. Signed-off-by: Frank Pavlic <fpavlic@de.ibm.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/s390/net/qeth.h')
-rw-r--r--drivers/s390/net/qeth.h35
1 files changed, 14 insertions, 21 deletions
diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h
index e8bd8c5ced1..c04ee915dc1 100644
--- a/drivers/s390/net/qeth.h
+++ b/drivers/s390/net/qeth.h
@@ -859,23 +859,18 @@ qeth_get_ipa_adp_type(enum qeth_link_types link_type)
}
}
-static inline int
-qeth_realloc_headroom(struct qeth_card *card, struct sk_buff **skb, int size)
+static inline struct sk_buff *
+qeth_realloc_headroom(struct qeth_card *card, struct sk_buff *skb, int size)
{
- struct sk_buff *new_skb = NULL;
-
- if (skb_headroom(*skb) < size){
- new_skb = skb_realloc_headroom(*skb, size);
- if (!new_skb) {
- PRINT_ERR("qeth_prepare_skb: could "
- "not realloc headroom for qeth_hdr "
- "on interface %s", QETH_CARD_IFNAME(card));
- return -ENOMEM;
- }
- kfree_skb(*skb);
- *skb = new_skb;
- }
- return 0;
+ struct sk_buff *new_skb = skb;
+
+ if (skb_headroom(skb) >= size)
+ return skb;
+ new_skb = skb_realloc_headroom(skb, size);
+ if (!new_skb)
+ PRINT_ERR("Could not realloc headroom for qeth_hdr "
+ "on interface %s", QETH_CARD_IFNAME(card));
+ return new_skb;
}
static inline struct sk_buff *
@@ -885,16 +880,15 @@ qeth_pskb_unshare(struct sk_buff *skb, int pri)
if (!skb_cloned(skb))
return skb;
nskb = skb_copy(skb, pri);
- kfree_skb(skb); /* free our shared copy */
return nskb;
}
static inline void *
-qeth_push_skb(struct qeth_card *card, struct sk_buff **skb, int size)
+qeth_push_skb(struct qeth_card *card, struct sk_buff *skb, int size)
{
void *hdr;
- hdr = (void *) skb_push(*skb, size);
+ hdr = (void *) skb_push(skb, size);
/*
* sanity check, the Linux memory allocation scheme should
* never present us cases like this one (the qdio header size plus
@@ -903,8 +897,7 @@ qeth_push_skb(struct qeth_card *card, struct sk_buff **skb, int size)
if ((((unsigned long) hdr) & (~(PAGE_SIZE - 1))) !=
(((unsigned long) hdr + size +
QETH_IP_HEADER_SIZE) & (~(PAGE_SIZE - 1)))) {
- PRINT_ERR("qeth_prepare_skb: misaligned "
- "packet on interface %s. Discarded.",
+ PRINT_ERR("Misaligned packet on interface %s. Discarded.",
QETH_CARD_IFNAME(card));
return NULL;
}