aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ntb_netdev.c
diff options
context:
space:
mode:
authorAllen Hubbe <Allen.Hubbe@emc.com>2015-07-13 08:07:08 -0400
committerJon Mason <jdmason@kudzu.us>2015-08-09 16:32:21 -0400
commitda2e5ae56164b86823c1bff5b4d28430ca4a7108 (patch)
treeb806c45f7d5e96eb1460f3b656bd9b7bb3646ee9 /drivers/net/ntb_netdev.c
parentLinux 4.2-rc6 (diff)
downloadlinux-dev-da2e5ae56164b86823c1bff5b4d28430ca4a7108.tar.xz
linux-dev-da2e5ae56164b86823c1bff5b4d28430ca4a7108.zip
NTB: Fix ntb_transport out-of-order RX update
It was possible for a synchronous update of the RX index in the error case to get ahead of the asynchronous RX index update in the normal case. Change the RX processing to preserve an RX completion order. There were two error cases. First, if a buffer is not present to receive data, there would be no queue entry to preserve the RX completion order. Instead of dropping the RX frame, leave the RX frame in the ring. Schedule RX processing when RX entries are enqueued, in case there are RX frames waiting in the ring to be received. Second, if a buffer is too small to receive data, drop the frame in the ring, mark the RX entry as done, and indicate the error in the RX entry length. Check for a negative length in the receive callback in ntb_netdev, and count occurrences as rx_length_errors. Signed-off-by: Allen Hubbe <Allen.Hubbe@emc.com> Signed-off-by: Jon Mason <jdmason@kudzu.us>
Diffstat (limited to 'drivers/net/ntb_netdev.c')
-rw-r--r--drivers/net/ntb_netdev.c7
1 files changed, 7 insertions, 0 deletions
diff --git a/drivers/net/ntb_netdev.c b/drivers/net/ntb_netdev.c
index 3cc316cb7e6b..5f1ee7c05f68 100644
--- a/drivers/net/ntb_netdev.c
+++ b/drivers/net/ntb_netdev.c
@@ -102,6 +102,12 @@ static void ntb_netdev_rx_handler(struct ntb_transport_qp *qp, void *qp_data,
netdev_dbg(ndev, "%s: %d byte payload received\n", __func__, len);
+ if (len < 0) {
+ ndev->stats.rx_errors++;
+ ndev->stats.rx_length_errors++;
+ goto enqueue_again;
+ }
+
skb_put(skb, len);
skb->protocol = eth_type_trans(skb, ndev);
skb->ip_summed = CHECKSUM_NONE;
@@ -121,6 +127,7 @@ static void ntb_netdev_rx_handler(struct ntb_transport_qp *qp, void *qp_data,
return;
}
+enqueue_again:
rc = ntb_transport_rx_enqueue(qp, skb, skb->data, ndev->mtu + ETH_HLEN);
if (rc) {
dev_kfree_skb(skb);