s390/qeth: fix overestimated count of buffer elements
qeth_get_elements_for_range() doesn't know how to handle a 0-length
range (ie. start == end), and returns 1 when it should return 0.
Such ranges occur on TSO skbs, where the L2/L3/L4 headers (and thus all
of the skb's linear data) are skipped when mapping the skb into regular
buffer elements.
This overestimation may cause several performance-related issues:
1. sub-optimal IO buffer selection, where the next buffer gets selected
even though the skb would actually still fit into the current buffer.
2. forced linearization, if the element count for a non-linear skb
exceeds QETH_MAX_BUFFER_ELEMENTS.
Rather than modifying qeth_get_elements_for_range() and adding overhead
to every caller, fix up those callers that are in risk of passing a
0-length range.
Fixes: 2863c61334
("qeth: refactor calculation of SBALE count")
Signed-off-by: Julian Wiedmann <jwi@linux.vnet.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
590399ddf9
commit
12472af896
@ -3898,10 +3898,12 @@ EXPORT_SYMBOL_GPL(qeth_get_elements_for_frags);
|
||||
int qeth_get_elements_no(struct qeth_card *card,
|
||||
struct sk_buff *skb, int extra_elems, int data_offset)
|
||||
{
|
||||
int elements = qeth_get_elements_for_range(
|
||||
(addr_t)skb->data + data_offset,
|
||||
(addr_t)skb->data + skb_headlen(skb)) +
|
||||
qeth_get_elements_for_frags(skb);
|
||||
addr_t end = (addr_t)skb->data + skb_headlen(skb);
|
||||
int elements = qeth_get_elements_for_frags(skb);
|
||||
addr_t start = (addr_t)skb->data + data_offset;
|
||||
|
||||
if (start != end)
|
||||
elements += qeth_get_elements_for_range(start, end);
|
||||
|
||||
if ((elements + extra_elems) > QETH_MAX_BUFFER_ELEMENTS(card)) {
|
||||
QETH_DBF_MESSAGE(2, "Invalid size of IP packet "
|
||||
|
@ -2450,11 +2450,12 @@ static void qeth_tso_fill_header(struct qeth_card *card,
|
||||
static int qeth_l3_get_elements_no_tso(struct qeth_card *card,
|
||||
struct sk_buff *skb, int extra_elems)
|
||||
{
|
||||
addr_t tcpdptr = (addr_t)tcp_hdr(skb) + tcp_hdrlen(skb);
|
||||
int elements = qeth_get_elements_for_range(
|
||||
tcpdptr,
|
||||
(addr_t)skb->data + skb_headlen(skb)) +
|
||||
qeth_get_elements_for_frags(skb);
|
||||
addr_t start = (addr_t)tcp_hdr(skb) + tcp_hdrlen(skb);
|
||||
addr_t end = (addr_t)skb->data + skb_headlen(skb);
|
||||
int elements = qeth_get_elements_for_frags(skb);
|
||||
|
||||
if (start != end)
|
||||
elements += qeth_get_elements_for_range(start, end);
|
||||
|
||||
if ((elements + extra_elems) > QETH_MAX_BUFFER_ELEMENTS(card)) {
|
||||
QETH_DBF_MESSAGE(2,
|
||||
|
Loading…
Reference in New Issue
Block a user