[SRU][Xenial][PATCH 1/1] s390/qeth: fix underestimated count of buffer elements

Joseph Salisbury joseph.salisbury at canonical.com
Wed Mar 7 09:43:05 UTC 2018


From: Ursula Braun <ubraun at linux.vnet.ibm.com>

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: 2863c61334aa ("qeth: refactor calculation of SBALE count")
Signed-off-by: Ursula Braun <ubraun at linux.vnet.ibm.com>
Signed-off-by: Julian Wiedmann <jwi at linux.vnet.ibm.com>
Signed-off-by: David S. Miller <davem at davemloft.net>
(back ported from commit 89271c65edd599207dd982007900506283c90ae3)
[jwi: backport to older kernels, so that it also
 Fixes: 51aa165c9f27 ("qeth: fix page breaks in hw headers")]
Signed-off-by: Joseph Salisbury <joseph.salisbury at canonical.com>
---
 drivers/s390/net/qeth_core_main.c | 4 ++--
 drivers/s390/net/qeth_l3_main.c   | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index e5b9506..63f8583 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -3822,7 +3822,7 @@ int qeth_get_elements_for_frags(struct sk_buff *skb)
 		data = (char *)page_to_phys(skb_frag_page(frag)) +
 			frag->page_offset;
 		length = frag->size;
-		e = PFN_UP((unsigned long)data + length - 1) -
+		e = PFN_UP((unsigned long)data + length) -
 			PFN_DOWN((unsigned long)data);
 		elements += e;
 	}
@@ -3834,7 +3834,7 @@ int qeth_get_elements_no(struct qeth_card *card,
 		     struct sk_buff *skb, int elems)
 {
 	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);
 
 	elements_needed += qeth_get_elements_for_frags(skb);
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index bf3c1b2..e313127 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -2819,7 +2819,7 @@ static inline int qeth_l3_tso_elements(struct sk_buff *skb)
 	unsigned long tcpd = (unsigned long)tcp_hdr(skb) +
 		tcp_hdr(skb)->doff * 4;
 	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);
 
-- 
2.7.4





More information about the kernel-team mailing list