| From foo@baz Fri Mar 15 21:00:09 PDT 2019 |
| From: Jack Morgenstein <jackm@dev.mellanox.co.il> |
| Date: Tue, 12 Mar 2019 17:05:48 +0200 |
| Subject: net/mlx4_core: Fix locking in SRIOV mode when switching between events and polling |
| |
| From: Jack Morgenstein <jackm@dev.mellanox.co.il> |
| |
| [ Upstream commit c07d27927f2f2e96fcd27bb9fb330c9ea65612d0 ] |
| |
| In procedures mlx4_cmd_use_events() and mlx4_cmd_use_polling(), we need to |
| guarantee that there are no FW commands in progress on the comm channel |
| (for VFs) or wrapped FW commands (on the PF) when SRIOV is active. |
| |
| We do this by also taking the slave_cmd_mutex when SRIOV is active. |
| |
| This is especially important when switching from event to polling, since we |
| free the command-context array during the switch. If there are FW commands |
| in progress (e.g., waiting for a completion event), the completion event |
| handler will access freed memory. |
| |
| Since the decision to use comm_wait or comm_poll is taken before grabbing |
| the event_sem/poll_sem in mlx4_comm_cmd_wait/poll, we must take the |
| slave_cmd_mutex as well (to guarantee that the decision to use events or |
| polling and the call to the appropriate cmd function are atomic). |
| |
| Fixes: a7e1f04905e5 ("net/mlx4_core: Fix deadlock when switching between polling and event fw commands") |
| Signed-off-by: Jack Morgenstein <jackm@dev.mellanox.co.il> |
| Signed-off-by: Tariq Toukan <tariqt@mellanox.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/net/ethernet/mellanox/mlx4/cmd.c | 8 ++++++++ |
| 1 file changed, 8 insertions(+) |
| |
| --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c |
| +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c |
| @@ -2633,6 +2633,8 @@ int mlx4_cmd_use_events(struct mlx4_dev |
| if (!priv->cmd.context) |
| return -ENOMEM; |
| |
| + if (mlx4_is_mfunc(dev)) |
| + mutex_lock(&priv->cmd.slave_cmd_mutex); |
| down_write(&priv->cmd.switch_sem); |
| for (i = 0; i < priv->cmd.max_cmds; ++i) { |
| priv->cmd.context[i].token = i; |
| @@ -2658,6 +2660,8 @@ int mlx4_cmd_use_events(struct mlx4_dev |
| down(&priv->cmd.poll_sem); |
| priv->cmd.use_events = 1; |
| up_write(&priv->cmd.switch_sem); |
| + if (mlx4_is_mfunc(dev)) |
| + mutex_unlock(&priv->cmd.slave_cmd_mutex); |
| |
| return err; |
| } |
| @@ -2670,6 +2674,8 @@ void mlx4_cmd_use_polling(struct mlx4_de |
| struct mlx4_priv *priv = mlx4_priv(dev); |
| int i; |
| |
| + if (mlx4_is_mfunc(dev)) |
| + mutex_lock(&priv->cmd.slave_cmd_mutex); |
| down_write(&priv->cmd.switch_sem); |
| priv->cmd.use_events = 0; |
| |
| @@ -2681,6 +2687,8 @@ void mlx4_cmd_use_polling(struct mlx4_de |
| |
| up(&priv->cmd.poll_sem); |
| up_write(&priv->cmd.switch_sem); |
| + if (mlx4_is_mfunc(dev)) |
| + mutex_unlock(&priv->cmd.slave_cmd_mutex); |
| } |
| |
| struct mlx4_cmd_mailbox *mlx4_alloc_cmd_mailbox(struct mlx4_dev *dev) |