Commit 17caeaa4 authored by Julian Wiedmann's avatar Julian Wiedmann Committed by David S. Miller

s390/qeth: handle skb allocation error gracefully

When current code fails to allocate an skb in the RX path, it drops the
whole RX buffer. Considering the large number of packets that a single
RX buffer might contain, this is quite drastic.

Skip over the packet instead, and try to extract the next packet from
the RX buffer.
Signed-off-by: default avatarJulian Wiedmann <jwi@linux.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7d4faee7
...@@ -5065,12 +5065,12 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card, ...@@ -5065,12 +5065,12 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
struct qdio_buffer_element *element = *__element; struct qdio_buffer_element *element = *__element;
struct qdio_buffer *buffer = qethbuffer->buffer; struct qdio_buffer *buffer = qethbuffer->buffer;
int offset = *__offset; int offset = *__offset;
bool use_rx_sg = false;
unsigned int headroom;
struct sk_buff *skb; struct sk_buff *skb;
int skb_len = 0; int skb_len = 0;
void *data_ptr; void *data_ptr;
int data_len; int data_len;
int headroom = 0;
int use_rx_sg = 0;
next_packet: next_packet:
/* qeth_hdr must not cross element boundaries */ /* qeth_hdr must not cross element boundaries */
...@@ -5086,6 +5086,7 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card, ...@@ -5086,6 +5086,7 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
switch ((*hdr)->hdr.l2.id) { switch ((*hdr)->hdr.l2.id) {
case QETH_HEADER_TYPE_LAYER2: case QETH_HEADER_TYPE_LAYER2:
skb_len = (*hdr)->hdr.l2.pkt_length; skb_len = (*hdr)->hdr.l2.pkt_length;
headroom = 0;
break; break;
case QETH_HEADER_TYPE_LAYER3: case QETH_HEADER_TYPE_LAYER3:
skb_len = (*hdr)->hdr.l3.length; skb_len = (*hdr)->hdr.l3.length;
...@@ -5120,11 +5121,10 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card, ...@@ -5120,11 +5121,10 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
if (!skb_len) if (!skb_len)
return NULL; return NULL;
if (((skb_len >= card->options.rx_sg_cb) && use_rx_sg = (card->options.cq == QETH_CQ_ENABLED) ||
!IS_OSN(card) && ((skb_len >= card->options.rx_sg_cb) &&
(!atomic_read(&card->force_alloc_skb))) || !atomic_read(&card->force_alloc_skb) &&
(card->options.cq == QETH_CQ_ENABLED)) !IS_OSN(card));
use_rx_sg = 1;
if (use_rx_sg && qethbuffer->rx_skb) { if (use_rx_sg && qethbuffer->rx_skb) {
/* QETH_CQ_ENABLED only: */ /* QETH_CQ_ENABLED only: */
...@@ -5135,9 +5135,10 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card, ...@@ -5135,9 +5135,10 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
skb = napi_alloc_skb(&card->napi, linear + headroom); skb = napi_alloc_skb(&card->napi, linear + headroom);
} }
if (!skb) if (!skb)
goto no_mem; QETH_CARD_STAT_INC(card, rx_dropped_nomem);
if (headroom) else if (headroom)
skb_reserve(skb, headroom); skb_reserve(skb, headroom);
walk_packet: walk_packet:
...@@ -5184,12 +5185,6 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card, ...@@ -5184,12 +5185,6 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
skb_shinfo(skb)->nr_frags); skb_shinfo(skb)->nr_frags);
} }
return skb; return skb;
no_mem:
if (net_ratelimit()) {
QETH_CARD_TEXT(card, 2, "noskbmem");
}
QETH_CARD_STAT_INC(card, rx_dropped_nomem);
return NULL;
} }
EXPORT_SYMBOL_GPL(qeth_core_get_next_skb); EXPORT_SYMBOL_GPL(qeth_core_get_next_skb);
......
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