Commit 5263cecc authored by Ursula Braun's avatar Ursula Braun Committed by Kleber Sacilotto de Souza

s390/qeth: fix underestimated count of buffer elements

BugLink: http://bugs.launchpad.net/bugs/1750810

For a memory range/skb where the last byte falls onto a page boundary
(ie. 'end' is of the form xxx...xxx001), the PFN_UP() part of the
calculation currently doesn't round up to the next PFN due to an
off-by-one error.
Thus qeth believes that the skb occupies one page less than it
actually does, and may select a IO buffer that doesn't have enough spare
buffer elements to fit all of the skb's data.
HW detects this as a malformed buffer descriptor, and raises an
exception which then triggers device recovery.

Fixes: 2863c613 ("qeth: refactor calculation of SBALE count")
Signed-off-by: default avatarUrsula Braun <ubraun@linux.vnet.ibm.com>
Signed-off-by: default avatarJulian Wiedmann <jwi@linux.vnet.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
(back ported from commit 89271c65)
[jwi: backport to older kernels, so that it also
 Fixes: 51aa165c ("qeth: fix page breaks in hw headers")]
Signed-off-by: default avatarJoseph Salisbury <joseph.salisbury@canonical.com>
Acked-by: default avatarStefan Bader <stefan.bader@canonical.com>
Acked-by: default avatarKleber Sacilotto de Souza <kleber.souza@canonical.com>
Signed-off-by: default avatarKleber Sacilotto de Souza <kleber.souza@canonical.com>
parent b9a5fffb
...@@ -3823,7 +3823,7 @@ int qeth_get_elements_for_frags(struct sk_buff *skb) ...@@ -3823,7 +3823,7 @@ int qeth_get_elements_for_frags(struct sk_buff *skb)
data = (char *)page_to_phys(skb_frag_page(frag)) + data = (char *)page_to_phys(skb_frag_page(frag)) +
frag->page_offset; frag->page_offset;
length = frag->size; length = frag->size;
e = PFN_UP((unsigned long)data + length - 1) - e = PFN_UP((unsigned long)data + length) -
PFN_DOWN((unsigned long)data); PFN_DOWN((unsigned long)data);
elements += e; elements += e;
} }
...@@ -3835,7 +3835,7 @@ int qeth_get_elements_no(struct qeth_card *card, ...@@ -3835,7 +3835,7 @@ int qeth_get_elements_no(struct qeth_card *card,
struct sk_buff *skb, int elems) struct sk_buff *skb, int elems)
{ {
int dlen = skb->len - skb->data_len; int dlen = skb->len - skb->data_len;
int elements_needed = PFN_UP((unsigned long)skb->data + dlen - 1) - int elements_needed = PFN_UP((unsigned long)skb->data + dlen) -
PFN_DOWN((unsigned long)skb->data); PFN_DOWN((unsigned long)skb->data);
elements_needed += qeth_get_elements_for_frags(skb); elements_needed += qeth_get_elements_for_frags(skb);
......
...@@ -2815,7 +2815,7 @@ static inline int qeth_l3_tso_elements(struct sk_buff *skb) ...@@ -2815,7 +2815,7 @@ static inline int qeth_l3_tso_elements(struct sk_buff *skb)
unsigned long tcpd = (unsigned long)tcp_hdr(skb) + unsigned long tcpd = (unsigned long)tcp_hdr(skb) +
tcp_hdr(skb)->doff * 4; tcp_hdr(skb)->doff * 4;
int tcpd_len = skb->len - (tcpd - (unsigned long)skb->data); int tcpd_len = skb->len - (tcpd - (unsigned long)skb->data);
int elements = PFN_UP(tcpd + tcpd_len - 1) - PFN_DOWN(tcpd); int elements = PFN_UP(tcpd + tcpd_len) - PFN_DOWN(tcpd);
elements += qeth_get_elements_for_frags(skb); elements += qeth_get_elements_for_frags(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