net/i40e: Fix concurrency issues between config flow and XSK
Use synchronize_rcu to wait until the XSK wakeup function finishes before destroying the resources it uses: 1. i40e_down already calls synchronize_rcu. On i40e_down either __I40E_VSI_DOWN or __I40E_CONFIG_BUSY is set. Check the latter in i40e_xsk_wakeup (the former is already checked there). 2. After switching the XDP program, call synchronize_rcu to let i40e_xsk_wakeup exit before the XDP program is freed. 3. Changing the number of channels brings the interface down (see i40e_prep_for_reset and i40e_pf_quiesce_all_vsi). 4. Disabling UMEM sets __I40E_CONFIG_BUSY, too. Signed-off-by: Maxim Mikityanskiy <maximmi@mellanox.com> Signed-off-by: Björn Töpel <bjorn.topel@intel.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Link: https://lore.kernel.org/bpf/20191217162023.16011-4-maximmi@mellanox.com
This commit is contained in:
parent
9cf88808ad
commit
b3873a5be7
|
@ -1152,7 +1152,7 @@ void i40e_set_fec_in_flags(u8 fec_cfg, u32 *flags);
|
|||
|
||||
static inline bool i40e_enabled_xdp_vsi(struct i40e_vsi *vsi)
|
||||
{
|
||||
return !!vsi->xdp_prog;
|
||||
return !!READ_ONCE(vsi->xdp_prog);
|
||||
}
|
||||
|
||||
int i40e_create_queue_channel(struct i40e_vsi *vsi, struct i40e_channel *ch);
|
||||
|
|
|
@ -6823,8 +6823,8 @@ void i40e_down(struct i40e_vsi *vsi)
|
|||
for (i = 0; i < vsi->num_queue_pairs; i++) {
|
||||
i40e_clean_tx_ring(vsi->tx_rings[i]);
|
||||
if (i40e_enabled_xdp_vsi(vsi)) {
|
||||
/* Make sure that in-progress ndo_xdp_xmit
|
||||
* calls are completed.
|
||||
/* Make sure that in-progress ndo_xdp_xmit and
|
||||
* ndo_xsk_wakeup calls are completed.
|
||||
*/
|
||||
synchronize_rcu();
|
||||
i40e_clean_tx_ring(vsi->xdp_rings[i]);
|
||||
|
@ -12546,8 +12546,12 @@ static int i40e_xdp_setup(struct i40e_vsi *vsi,
|
|||
|
||||
old_prog = xchg(&vsi->xdp_prog, prog);
|
||||
|
||||
if (need_reset)
|
||||
if (need_reset) {
|
||||
if (!prog)
|
||||
/* Wait until ndo_xsk_wakeup completes. */
|
||||
synchronize_rcu();
|
||||
i40e_reset_and_rebuild(pf, true, true);
|
||||
}
|
||||
|
||||
for (i = 0; i < vsi->num_queue_pairs; i++)
|
||||
WRITE_ONCE(vsi->rx_rings[i]->xdp_prog, vsi->xdp_prog);
|
||||
|
|
|
@ -787,8 +787,12 @@ int i40e_xsk_wakeup(struct net_device *dev, u32 queue_id, u32 flags)
|
|||
{
|
||||
struct i40e_netdev_priv *np = netdev_priv(dev);
|
||||
struct i40e_vsi *vsi = np->vsi;
|
||||
struct i40e_pf *pf = vsi->back;
|
||||
struct i40e_ring *ring;
|
||||
|
||||
if (test_bit(__I40E_CONFIG_BUSY, pf->state))
|
||||
return -ENETDOWN;
|
||||
|
||||
if (test_bit(__I40E_VSI_DOWN, vsi->state))
|
||||
return -ENETDOWN;
|
||||
|
||||
|
|
Loading…
Reference in New Issue