aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2017-10-10 13:18:34 -0700
committerDavid S. Miller <davem@davemloft.net>2017-10-10 13:18:34 -0700
commitbefc7a3324b45b7478b29861f2a77f8b2bc17922 (patch)
tree97ba442e53e8eb00ea1527077fbd67c3179c5a32
parentMerge branch '40GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net-queue (diff)
parentnfp: handle page allocation failures (diff)
downloadlinux-dev-befc7a3324b45b7478b29861f2a77f8b2bc17922.tar.xz
linux-dev-befc7a3324b45b7478b29861f2a77f8b2bc17922.zip
Merge branch 'nfp-fix-ethtool-stats-and-page-allocation'
Jakub Kicinski says: ==================== nfp: fix ethtool stats and page allocation Two fixes for net. First one makes sure we handle gather of stats on 32bit machines correctly (ouch). The second fix solves a potential NULL-deref if we fail to allocate a page with XDP running. I used Fixes: tags pointing to where the bug was introduced, but for patch 1 it has been in the driver "for ever" and fix won't backport cleanly beyond commit 325945ede6d4 ("nfp: split software and hardware vNIC statistics") which is in net. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_common.c20
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c8
2 files changed, 19 insertions, 9 deletions
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
index 1c0187f0af51..e118b5f23996 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
@@ -1180,10 +1180,14 @@ static void *nfp_net_rx_alloc_one(struct nfp_net_dp *dp, dma_addr_t *dma_addr)
{
void *frag;
- if (!dp->xdp_prog)
+ if (!dp->xdp_prog) {
frag = netdev_alloc_frag(dp->fl_bufsz);
- else
- frag = page_address(alloc_page(GFP_KERNEL | __GFP_COLD));
+ } else {
+ struct page *page;
+
+ page = alloc_page(GFP_KERNEL | __GFP_COLD);
+ frag = page ? page_address(page) : NULL;
+ }
if (!frag) {
nn_dp_warn(dp, "Failed to alloc receive page frag\n");
return NULL;
@@ -1203,10 +1207,14 @@ static void *nfp_net_napi_alloc_one(struct nfp_net_dp *dp, dma_addr_t *dma_addr)
{
void *frag;
- if (!dp->xdp_prog)
+ if (!dp->xdp_prog) {
frag = napi_alloc_frag(dp->fl_bufsz);
- else
- frag = page_address(alloc_page(GFP_ATOMIC | __GFP_COLD));
+ } else {
+ struct page *page;
+
+ page = alloc_page(GFP_ATOMIC | __GFP_COLD);
+ frag = page ? page_address(page) : NULL;
+ }
if (!frag) {
nn_dp_warn(dp, "Failed to alloc receive page frag\n");
return NULL;
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
index 07969f06df10..dc016dfec64d 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
@@ -464,7 +464,7 @@ static u64 *nfp_vnic_get_sw_stats(struct net_device *netdev, u64 *data)
do {
start = u64_stats_fetch_begin(&nn->r_vecs[i].rx_sync);
- *data++ = nn->r_vecs[i].rx_pkts;
+ data[0] = nn->r_vecs[i].rx_pkts;
tmp[0] = nn->r_vecs[i].hw_csum_rx_ok;
tmp[1] = nn->r_vecs[i].hw_csum_rx_inner_ok;
tmp[2] = nn->r_vecs[i].hw_csum_rx_error;
@@ -472,14 +472,16 @@ static u64 *nfp_vnic_get_sw_stats(struct net_device *netdev, u64 *data)
do {
start = u64_stats_fetch_begin(&nn->r_vecs[i].tx_sync);
- *data++ = nn->r_vecs[i].tx_pkts;
- *data++ = nn->r_vecs[i].tx_busy;
+ data[1] = nn->r_vecs[i].tx_pkts;
+ data[2] = nn->r_vecs[i].tx_busy;
tmp[3] = nn->r_vecs[i].hw_csum_tx;
tmp[4] = nn->r_vecs[i].hw_csum_tx_inner;
tmp[5] = nn->r_vecs[i].tx_gather;
tmp[6] = nn->r_vecs[i].tx_lso;
} while (u64_stats_fetch_retry(&nn->r_vecs[i].tx_sync, start));
+ data += 3;
+
for (j = 0; j < NN_ET_RVEC_GATHER_STATS; j++)
gathered_stats[j] += tmp[j];
}