Commit 30e2561b authored by Anjali Singhai's avatar Anjali Singhai Committed by Jeff Kirsher

i40e: Fix for recursive RTNL lock during PROMISC change

The sync_vsi_filters function can be called directly under RTNL
or through the timer subtask without one. This was causing a deadlock.

If sync_vsi_filters is called from a thread which held the lock,
and in another thread the PROMISC setting got changed we would
be executing the PROMISC change in the thread which already held
the lock alongside the other filter update. The PROMISC change
requires a reset if we are on a VEB, which requires it to be called
under RTNL.

Earlier the driver would call reset for PROMISC change without
checking if we were already under RTNL and would try to grab it
causing a deadlock. This patch changes the flow to see if we are
already under RTNL before trying to grab it.
Signed-off-by: default avatarAnjali Singhai Jain <anjali.singhai@intel.com>
Signed-off-by: default avatarKiran Patil <kiran.patil@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent 58044743
...@@ -666,7 +666,7 @@ struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi, ...@@ -666,7 +666,7 @@ struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi,
bool is_vf, bool is_netdev); bool is_vf, bool is_netdev);
void i40e_del_filter(struct i40e_vsi *vsi, u8 *macaddr, s16 vlan, void i40e_del_filter(struct i40e_vsi *vsi, u8 *macaddr, s16 vlan,
bool is_vf, bool is_netdev); bool is_vf, bool is_netdev);
int i40e_sync_vsi_filters(struct i40e_vsi *vsi); int i40e_sync_vsi_filters(struct i40e_vsi *vsi, bool grab_rtnl);
struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type, struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
u16 uplink, u32 param1); u16 uplink, u32 param1);
int i40e_vsi_release(struct i40e_vsi *vsi); int i40e_vsi_release(struct i40e_vsi *vsi);
......
...@@ -1146,7 +1146,7 @@ static ssize_t i40e_dbg_command_write(struct file *filp, ...@@ -1146,7 +1146,7 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
} }
f = i40e_add_filter(vsi, ma, vlan, false, false); f = i40e_add_filter(vsi, ma, vlan, false, false);
ret = i40e_sync_vsi_filters(vsi); ret = i40e_sync_vsi_filters(vsi, true);
if (f && !ret) if (f && !ret)
dev_info(&pf->pdev->dev, dev_info(&pf->pdev->dev,
"add macaddr: %pM vlan=%d added to VSI %d\n", "add macaddr: %pM vlan=%d added to VSI %d\n",
...@@ -1183,7 +1183,7 @@ static ssize_t i40e_dbg_command_write(struct file *filp, ...@@ -1183,7 +1183,7 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
} }
i40e_del_filter(vsi, ma, vlan, false, false); i40e_del_filter(vsi, ma, vlan, false, false);
ret = i40e_sync_vsi_filters(vsi); ret = i40e_sync_vsi_filters(vsi, true);
if (!ret) if (!ret)
dev_info(&pf->pdev->dev, dev_info(&pf->pdev->dev,
"del macaddr: %pM vlan=%d removed from VSI %d\n", "del macaddr: %pM vlan=%d removed from VSI %d\n",
......
...@@ -1527,7 +1527,7 @@ static int i40e_set_mac(struct net_device *netdev, void *p) ...@@ -1527,7 +1527,7 @@ static int i40e_set_mac(struct net_device *netdev, void *p)
f->is_laa = true; f->is_laa = true;
} }
i40e_sync_vsi_filters(vsi); i40e_sync_vsi_filters(vsi, false);
ether_addr_copy(netdev->dev_addr, addr->sa_data); ether_addr_copy(netdev->dev_addr, addr->sa_data);
return 0; return 0;
...@@ -1764,12 +1764,13 @@ static void i40e_set_rx_mode(struct net_device *netdev) ...@@ -1764,12 +1764,13 @@ static void i40e_set_rx_mode(struct net_device *netdev)
/** /**
* i40e_sync_vsi_filters - Update the VSI filter list to the HW * i40e_sync_vsi_filters - Update the VSI filter list to the HW
* @vsi: ptr to the VSI * @vsi: ptr to the VSI
* @grab_rtnl: whether RTNL needs to be grabbed
* *
* Push any outstanding VSI filter changes through the AdminQ. * Push any outstanding VSI filter changes through the AdminQ.
* *
* Returns 0 or error value * Returns 0 or error value
**/ **/
int i40e_sync_vsi_filters(struct i40e_vsi *vsi) int i40e_sync_vsi_filters(struct i40e_vsi *vsi, bool grab_rtnl)
{ {
struct i40e_mac_filter *f, *ftmp; struct i40e_mac_filter *f, *ftmp;
bool promisc_forced_on = false; bool promisc_forced_on = false;
...@@ -1958,8 +1959,12 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi) ...@@ -1958,8 +1959,12 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
*/ */
if (pf->cur_promisc != cur_promisc) { if (pf->cur_promisc != cur_promisc) {
pf->cur_promisc = cur_promisc; pf->cur_promisc = cur_promisc;
if (grab_rtnl)
i40e_do_reset_safe(pf, i40e_do_reset_safe(pf,
BIT(__I40E_PF_RESET_REQUESTED)); BIT(__I40E_PF_RESET_REQUESTED));
else
i40e_do_reset(pf,
BIT(__I40E_PF_RESET_REQUESTED));
} }
} else { } else {
ret = i40e_aq_set_vsi_unicast_promiscuous( ret = i40e_aq_set_vsi_unicast_promiscuous(
...@@ -2009,7 +2014,7 @@ static void i40e_sync_filters_subtask(struct i40e_pf *pf) ...@@ -2009,7 +2014,7 @@ static void i40e_sync_filters_subtask(struct i40e_pf *pf)
for (v = 0; v < pf->num_alloc_vsi; v++) { for (v = 0; v < pf->num_alloc_vsi; v++) {
if (pf->vsi[v] && if (pf->vsi[v] &&
(pf->vsi[v]->flags & I40E_VSI_FLAG_FILTER_CHANGED)) (pf->vsi[v]->flags & I40E_VSI_FLAG_FILTER_CHANGED))
i40e_sync_vsi_filters(pf->vsi[v]); i40e_sync_vsi_filters(pf->vsi[v], true);
} }
} }
...@@ -2216,7 +2221,7 @@ int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid) ...@@ -2216,7 +2221,7 @@ int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid)
test_bit(__I40E_RESET_RECOVERY_PENDING, &vsi->back->state)) test_bit(__I40E_RESET_RECOVERY_PENDING, &vsi->back->state))
return 0; return 0;
return i40e_sync_vsi_filters(vsi); return i40e_sync_vsi_filters(vsi, false);
} }
/** /**
...@@ -2288,7 +2293,7 @@ int i40e_vsi_kill_vlan(struct i40e_vsi *vsi, s16 vid) ...@@ -2288,7 +2293,7 @@ int i40e_vsi_kill_vlan(struct i40e_vsi *vsi, s16 vid)
test_bit(__I40E_RESET_RECOVERY_PENDING, &vsi->back->state)) test_bit(__I40E_RESET_RECOVERY_PENDING, &vsi->back->state))
return 0; return 0;
return i40e_sync_vsi_filters(vsi); return i40e_sync_vsi_filters(vsi, false);
} }
/** /**
...@@ -8821,7 +8826,7 @@ int i40e_vsi_release(struct i40e_vsi *vsi) ...@@ -8821,7 +8826,7 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list) list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list)
i40e_del_filter(vsi, f->macaddr, f->vlan, i40e_del_filter(vsi, f->macaddr, f->vlan,
f->is_vf, f->is_netdev); f->is_vf, f->is_netdev);
i40e_sync_vsi_filters(vsi); i40e_sync_vsi_filters(vsi, false);
i40e_vsi_delete(vsi); i40e_vsi_delete(vsi);
i40e_vsi_free_q_vectors(vsi); i40e_vsi_free_q_vectors(vsi);
......
...@@ -561,7 +561,7 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type) ...@@ -561,7 +561,7 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type)
} }
/* program mac filter */ /* program mac filter */
ret = i40e_sync_vsi_filters(vsi); ret = i40e_sync_vsi_filters(vsi, false);
if (ret) if (ret)
dev_err(&pf->pdev->dev, "Unable to program ucast filters\n"); dev_err(&pf->pdev->dev, "Unable to program ucast filters\n");
...@@ -1605,7 +1605,7 @@ static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) ...@@ -1605,7 +1605,7 @@ static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
} }
/* program the updated filter list */ /* program the updated filter list */
if (i40e_sync_vsi_filters(vsi)) if (i40e_sync_vsi_filters(vsi, false))
dev_err(&pf->pdev->dev, "Unable to program VF MAC filters\n"); dev_err(&pf->pdev->dev, "Unable to program VF MAC filters\n");
error_param: error_param:
...@@ -1656,7 +1656,7 @@ static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) ...@@ -1656,7 +1656,7 @@ static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
I40E_VLAN_ANY, true, false); I40E_VLAN_ANY, true, false);
/* program the updated filter list */ /* program the updated filter list */
if (i40e_sync_vsi_filters(vsi)) if (i40e_sync_vsi_filters(vsi, false))
dev_err(&pf->pdev->dev, "Unable to program VF MAC filters\n"); dev_err(&pf->pdev->dev, "Unable to program VF MAC filters\n");
error_param: error_param:
...@@ -2062,7 +2062,7 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac) ...@@ -2062,7 +2062,7 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
dev_info(&pf->pdev->dev, "Setting MAC %pM on VF %d\n", mac, vf_id); dev_info(&pf->pdev->dev, "Setting MAC %pM on VF %d\n", mac, vf_id);
/* program mac filter */ /* program mac filter */
if (i40e_sync_vsi_filters(vsi)) { if (i40e_sync_vsi_filters(vsi, false)) {
dev_err(&pf->pdev->dev, "Unable to program ucast filters\n"); dev_err(&pf->pdev->dev, "Unable to program ucast filters\n");
ret = -EIO; ret = -EIO;
goto error_param; goto error_param;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment