Skip to content

Commit

Permalink
[PATCH] s390: qeth driver fixes [3/6]
Browse files Browse the repository at this point in the history
[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>
  • Loading branch information
Frank Pavlic authored and Jeff Garzik committed Sep 17, 2006
1 parent 1fda1a1 commit f7b65d7
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 116 deletions.
35 changes: 14 additions & 21 deletions drivers/s390/net/qeth.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 *
Expand All @@ -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
Expand All @@ -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;
}
Expand Down
Loading

0 comments on commit f7b65d7

Please sign in to comment.