Skip to content

Commit aae425e

Browse files
JanJSokolowskidavem330
authored andcommitted
i40e: Fix DMA mappings leak
During reallocation of RX buffers, new DMA mappings are created for those buffers. steps for reproduction: while : do for ((i=0; i<=8160; i=i+32)) do ethtool -G enp130s0f0 rx $i tx $i sleep 0.5 ethtool -g enp130s0f0 done done This resulted in crash: i40e 0000:01:00.1: Unable to allocate memory for the Rx descriptor ring, size=65536 Driver BUG WARNING: CPU: 0 PID: 4300 at net/core/xdp.c:141 xdp_rxq_info_unreg+0x43/0x50 Call Trace: i40e_free_rx_resources+0x70/0x80 [i40e] i40e_set_ringparam+0x27c/0x800 [i40e] ethnl_set_rings+0x1b2/0x290 genl_family_rcv_msg_doit.isra.15+0x10f/0x150 genl_family_rcv_msg+0xb3/0x160 ? rings_fill_reply+0x1a0/0x1a0 genl_rcv_msg+0x47/0x90 ? genl_family_rcv_msg+0x160/0x160 netlink_rcv_skb+0x4c/0x120 genl_rcv+0x24/0x40 netlink_unicast+0x196/0x230 netlink_sendmsg+0x204/0x3d0 sock_sendmsg+0x4c/0x50 __sys_sendto+0xee/0x160 ? handle_mm_fault+0xbe/0x1e0 ? syscall_trace_enter+0x1d3/0x2c0 __x64_sys_sendto+0x24/0x30 do_syscall_64+0x5b/0x1a0 entry_SYSCALL_64_after_hwframe+0x65/0xca RIP: 0033:0x7f5eac8b035b Missing register, driver bug WARNING: CPU: 0 PID: 4300 at net/core/xdp.c:119 xdp_rxq_info_unreg_mem_model+0x69/0x140 Call Trace: xdp_rxq_info_unreg+0x1e/0x50 i40e_free_rx_resources+0x70/0x80 [i40e] i40e_set_ringparam+0x27c/0x800 [i40e] ethnl_set_rings+0x1b2/0x290 genl_family_rcv_msg_doit.isra.15+0x10f/0x150 genl_family_rcv_msg+0xb3/0x160 ? rings_fill_reply+0x1a0/0x1a0 genl_rcv_msg+0x47/0x90 ? genl_family_rcv_msg+0x160/0x160 netlink_rcv_skb+0x4c/0x120 genl_rcv+0x24/0x40 netlink_unicast+0x196/0x230 netlink_sendmsg+0x204/0x3d0 sock_sendmsg+0x4c/0x50 __sys_sendto+0xee/0x160 ? handle_mm_fault+0xbe/0x1e0 ? syscall_trace_enter+0x1d3/0x2c0 __x64_sys_sendto+0x24/0x30 do_syscall_64+0x5b/0x1a0 entry_SYSCALL_64_after_hwframe+0x65/0xca RIP: 0033:0x7f5eac8b035b This was caused because of new buffers with different RX ring count should substitute older ones, but those buffers were freed in i40e_configure_rx_ring and reallocated again with i40e_alloc_rx_bi, thus kfree on rx_bi caused leak of already mapped DMA. Fix this by reallocating ZC with rx_bi_zc struct when BPF program loads. Additionally reallocate back to rx_bi when BPF program unloads. If BPF program is loaded/unloaded and XSK pools are created, reallocate RX queues accordingly in XSP_SETUP_XSK_POOL handler. Fixes: be1222b ("i40e: Separate kernel allocated rx_bi rings from AF_XDP rings") Signed-off-by: Jan Sokolowski <[email protected]> Signed-off-by: Mateusz Palczewski <[email protected]> Signed-off-by: Jacob Keller <[email protected]> Tested-by: Chandan <[email protected]> (A Contingent Worker at Intel) Tested-by: Gurucharan <[email protected]> (A Contingent worker at Intel) Signed-off-by: David S. Miller <[email protected]>
1 parent 0d4636f commit aae425e

File tree

6 files changed

+74
-28
lines changed

6 files changed

+74
-28
lines changed

drivers/net/ethernet/intel/i40e/i40e_ethtool.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2181,9 +2181,6 @@ static int i40e_set_ringparam(struct net_device *netdev,
21812181
*/
21822182
rx_rings[i].tail = hw->hw_addr + I40E_PRTGEN_STATUS;
21832183
err = i40e_setup_rx_descriptors(&rx_rings[i]);
2184-
if (err)
2185-
goto rx_unwind;
2186-
err = i40e_alloc_rx_bi(&rx_rings[i]);
21872184
if (err)
21882185
goto rx_unwind;
21892186

drivers/net/ethernet/intel/i40e/i40e_main.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3566,12 +3566,8 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
35663566
if (ring->vsi->type == I40E_VSI_MAIN)
35673567
xdp_rxq_info_unreg_mem_model(&ring->xdp_rxq);
35683568

3569-
kfree(ring->rx_bi);
35703569
ring->xsk_pool = i40e_xsk_pool(ring);
35713570
if (ring->xsk_pool) {
3572-
ret = i40e_alloc_rx_bi_zc(ring);
3573-
if (ret)
3574-
return ret;
35753571
ring->rx_buf_len =
35763572
xsk_pool_get_rx_frame_size(ring->xsk_pool);
35773573
/* For AF_XDP ZC, we disallow packets to span on
@@ -3589,9 +3585,6 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
35893585
ring->queue_index);
35903586

35913587
} else {
3592-
ret = i40e_alloc_rx_bi(ring);
3593-
if (ret)
3594-
return ret;
35953588
ring->rx_buf_len = vsi->rx_buf_len;
35963589
if (ring->vsi->type == I40E_VSI_MAIN) {
35973590
ret = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
@@ -13296,6 +13289,14 @@ static int i40e_xdp_setup(struct i40e_vsi *vsi, struct bpf_prog *prog,
1329613289
i40e_reset_and_rebuild(pf, true, true);
1329713290
}
1329813291

13292+
if (!i40e_enabled_xdp_vsi(vsi) && prog) {
13293+
if (i40e_realloc_rx_bi_zc(vsi, true))
13294+
return -ENOMEM;
13295+
} else if (i40e_enabled_xdp_vsi(vsi) && !prog) {
13296+
if (i40e_realloc_rx_bi_zc(vsi, false))
13297+
return -ENOMEM;
13298+
}
13299+
1329913300
for (i = 0; i < vsi->num_queue_pairs; i++)
1330013301
WRITE_ONCE(vsi->rx_rings[i]->xdp_prog, vsi->xdp_prog);
1330113302

@@ -13528,6 +13529,7 @@ int i40e_queue_pair_disable(struct i40e_vsi *vsi, int queue_pair)
1352813529

1352913530
i40e_queue_pair_disable_irq(vsi, queue_pair);
1353013531
err = i40e_queue_pair_toggle_rings(vsi, queue_pair, false /* off */);
13532+
i40e_clean_rx_ring(vsi->rx_rings[queue_pair]);
1353113533
i40e_queue_pair_toggle_napi(vsi, queue_pair, false /* off */);
1353213534
i40e_queue_pair_clean_rings(vsi, queue_pair);
1353313535
i40e_queue_pair_reset_stats(vsi, queue_pair);

drivers/net/ethernet/intel/i40e/i40e_txrx.c

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1457,14 +1457,6 @@ int i40e_setup_tx_descriptors(struct i40e_ring *tx_ring)
14571457
return -ENOMEM;
14581458
}
14591459

1460-
int i40e_alloc_rx_bi(struct i40e_ring *rx_ring)
1461-
{
1462-
unsigned long sz = sizeof(*rx_ring->rx_bi) * rx_ring->count;
1463-
1464-
rx_ring->rx_bi = kzalloc(sz, GFP_KERNEL);
1465-
return rx_ring->rx_bi ? 0 : -ENOMEM;
1466-
}
1467-
14681460
static void i40e_clear_rx_bi(struct i40e_ring *rx_ring)
14691461
{
14701462
memset(rx_ring->rx_bi, 0, sizeof(*rx_ring->rx_bi) * rx_ring->count);
@@ -1593,6 +1585,11 @@ int i40e_setup_rx_descriptors(struct i40e_ring *rx_ring)
15931585

15941586
rx_ring->xdp_prog = rx_ring->vsi->xdp_prog;
15951587

1588+
rx_ring->rx_bi =
1589+
kcalloc(rx_ring->count, sizeof(*rx_ring->rx_bi), GFP_KERNEL);
1590+
if (!rx_ring->rx_bi)
1591+
return -ENOMEM;
1592+
15961593
return 0;
15971594
}
15981595

drivers/net/ethernet/intel/i40e/i40e_txrx.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,6 @@ int __i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size);
469469
bool __i40e_chk_linearize(struct sk_buff *skb);
470470
int i40e_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames,
471471
u32 flags);
472-
int i40e_alloc_rx_bi(struct i40e_ring *rx_ring);
473472

474473
/**
475474
* i40e_get_head - Retrieve head from head writeback

drivers/net/ethernet/intel/i40e/i40e_xsk.c

Lines changed: 59 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,6 @@
1010
#include "i40e_txrx_common.h"
1111
#include "i40e_xsk.h"
1212

13-
int i40e_alloc_rx_bi_zc(struct i40e_ring *rx_ring)
14-
{
15-
unsigned long sz = sizeof(*rx_ring->rx_bi_zc) * rx_ring->count;
16-
17-
rx_ring->rx_bi_zc = kzalloc(sz, GFP_KERNEL);
18-
return rx_ring->rx_bi_zc ? 0 : -ENOMEM;
19-
}
20-
2113
void i40e_clear_rx_bi_zc(struct i40e_ring *rx_ring)
2214
{
2315
memset(rx_ring->rx_bi_zc, 0,
@@ -29,6 +21,58 @@ static struct xdp_buff **i40e_rx_bi(struct i40e_ring *rx_ring, u32 idx)
2921
return &rx_ring->rx_bi_zc[idx];
3022
}
3123

24+
/**
25+
* i40e_realloc_rx_xdp_bi - reallocate SW ring for either XSK or normal buffer
26+
* @rx_ring: Current rx ring
27+
* @pool_present: is pool for XSK present
28+
*
29+
* Try allocating memory and return ENOMEM, if failed to allocate.
30+
* If allocation was successful, substitute buffer with allocated one.
31+
* Returns 0 on success, negative on failure
32+
*/
33+
static int i40e_realloc_rx_xdp_bi(struct i40e_ring *rx_ring, bool pool_present)
34+
{
35+
size_t elem_size = pool_present ? sizeof(*rx_ring->rx_bi_zc) :
36+
sizeof(*rx_ring->rx_bi);
37+
void *sw_ring = kcalloc(rx_ring->count, elem_size, GFP_KERNEL);
38+
39+
if (!sw_ring)
40+
return -ENOMEM;
41+
42+
if (pool_present) {
43+
kfree(rx_ring->rx_bi);
44+
rx_ring->rx_bi = NULL;
45+
rx_ring->rx_bi_zc = sw_ring;
46+
} else {
47+
kfree(rx_ring->rx_bi_zc);
48+
rx_ring->rx_bi_zc = NULL;
49+
rx_ring->rx_bi = sw_ring;
50+
}
51+
return 0;
52+
}
53+
54+
/**
55+
* i40e_realloc_rx_bi_zc - reallocate rx SW rings
56+
* @vsi: Current VSI
57+
* @zc: is zero copy set
58+
*
59+
* Reallocate buffer for rx_rings that might be used by XSK.
60+
* XDP requires more memory, than rx_buf provides.
61+
* Returns 0 on success, negative on failure
62+
*/
63+
int i40e_realloc_rx_bi_zc(struct i40e_vsi *vsi, bool zc)
64+
{
65+
struct i40e_ring *rx_ring;
66+
unsigned long q;
67+
68+
for_each_set_bit(q, vsi->af_xdp_zc_qps, vsi->alloc_queue_pairs) {
69+
rx_ring = vsi->rx_rings[q];
70+
if (i40e_realloc_rx_xdp_bi(rx_ring, zc))
71+
return -ENOMEM;
72+
}
73+
return 0;
74+
}
75+
3276
/**
3377
* i40e_xsk_pool_enable - Enable/associate an AF_XDP buffer pool to a
3478
* certain ring/qid
@@ -69,6 +113,10 @@ static int i40e_xsk_pool_enable(struct i40e_vsi *vsi,
69113
if (err)
70114
return err;
71115

116+
err = i40e_realloc_rx_xdp_bi(vsi->rx_rings[qid], true);
117+
if (err)
118+
return err;
119+
72120
err = i40e_queue_pair_enable(vsi, qid);
73121
if (err)
74122
return err;
@@ -113,6 +161,9 @@ static int i40e_xsk_pool_disable(struct i40e_vsi *vsi, u16 qid)
113161
xsk_pool_dma_unmap(pool, I40E_RX_DMA_ATTR);
114162

115163
if (if_running) {
164+
err = i40e_realloc_rx_xdp_bi(vsi->rx_rings[qid], false);
165+
if (err)
166+
return err;
116167
err = i40e_queue_pair_enable(vsi, qid);
117168
if (err)
118169
return err;

drivers/net/ethernet/intel/i40e/i40e_xsk.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget);
3232

3333
bool i40e_clean_xdp_tx_irq(struct i40e_vsi *vsi, struct i40e_ring *tx_ring);
3434
int i40e_xsk_wakeup(struct net_device *dev, u32 queue_id, u32 flags);
35-
int i40e_alloc_rx_bi_zc(struct i40e_ring *rx_ring);
35+
int i40e_realloc_rx_bi_zc(struct i40e_vsi *vsi, bool zc);
3636
void i40e_clear_rx_bi_zc(struct i40e_ring *rx_ring);
3737

3838
#endif /* _I40E_XSK_H_ */

0 commit comments

Comments
 (0)