Message ID | 89cb805bed5d392affa7184a0ac36fe7c80fb7ad.1520342550.git.joseph.salisbury@canonical.com |
---|---|
State | New |
Headers | show |
Series | [SRU,Xenial,1/1] s390/qeth: fix underestimated count of buffer elements | expand |
On 07.03.2018 10:43, Joseph Salisbury wrote: > From: Ursula Braun <ubraun@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@linux.vnet.ibm.com> > Signed-off-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> > Signed-off-by: David S. Miller <davem@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@canonical.com> Acked-by: Stefan Bader <stefan.bader@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); > >
On 03/07/18 10:43, Joseph Salisbury wrote: > From: Ursula Braun <ubraun@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@linux.vnet.ibm.com> > Signed-off-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> > Signed-off-by: David S. Miller <davem@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@canonical.com> Acked-by: Kleber Sacilotto de Souza <kleber.souza@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); > >
On 03/07/18 10:43, Joseph Salisbury wrote: > From: Ursula Braun <ubraun@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@linux.vnet.ibm.com> > Signed-off-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> > Signed-off-by: David S. Miller <davem@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@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); > > Applied to xenial/master-next branch. Thanks, Kleber
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);