Skip to content

Commit

Permalink
ice: prevent ice_open and ice_stop during reset
Browse files Browse the repository at this point in the history
commit e95fc85 upstream.

There is a possibility of race between ice_open or ice_stop calls
performed by OS and reset handling routine both trying to modify VSI
resources. Observed scenarios:
- reset handler deallocates memory in ice_vsi_free_arrays and ice_open
  tries to access it in ice_vsi_cfg_txq leading to driver crash
- reset handler deallocates memory in ice_vsi_free_arrays and ice_close
  tries to access it in ice_down leading to driver crash
- reset handler clears port scheduler topology and sets port state to
  ICE_SCHED_PORT_STATE_INIT leading to ice_ena_vsi_txq fail in ice_open

To prevent this additional checks in ice_open and ice_stop are
introduced to make sure that OS is not allowed to alter VSI config while
reset is in progress.

Fixes: cdedef5 ("ice: Configure VSIs for Tx/Rx")
Signed-off-by: Krzysztof Goreczny <krzysztof.goreczny@intel.com>
Tested-by: Tony Brelinski <tonyx.brelinski@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Krzysztof Goreczny authored and gregkh committed Apr 14, 2021
1 parent 8f0ed12 commit 95067fe
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 2 deletions.
1 change: 1 addition & 0 deletions drivers/net/ethernet/intel/ice/ice.h
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,7 @@ int ice_fdir_create_dflt_rules(struct ice_pf *pf);
int ice_aq_wait_for_event(struct ice_pf *pf, u16 opcode, unsigned long timeout,
struct ice_rq_event_info *event);
int ice_open(struct net_device *netdev);
int ice_open_internal(struct net_device *netdev);
int ice_stop(struct net_device *netdev);
void ice_service_task_schedule(struct ice_pf *pf);

Expand Down
4 changes: 2 additions & 2 deletions drivers/net/ethernet/intel/ice/ice_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -2489,7 +2489,7 @@ int ice_ena_vsi(struct ice_vsi *vsi, bool locked)
if (!locked)
rtnl_lock();

err = ice_open(vsi->netdev);
err = ice_open_internal(vsi->netdev);

if (!locked)
rtnl_unlock();
Expand Down Expand Up @@ -2518,7 +2518,7 @@ void ice_dis_vsi(struct ice_vsi *vsi, bool locked)
if (!locked)
rtnl_lock();

ice_stop(vsi->netdev);
ice_vsi_close(vsi);

if (!locked)
rtnl_unlock();
Expand Down
28 changes: 28 additions & 0 deletions drivers/net/ethernet/intel/ice/ice_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -6610,6 +6610,28 @@ static void ice_tx_timeout(struct net_device *netdev, unsigned int txqueue)
* Returns 0 on success, negative value on failure
*/
int ice_open(struct net_device *netdev)
{
struct ice_netdev_priv *np = netdev_priv(netdev);
struct ice_pf *pf = np->vsi->back;

if (ice_is_reset_in_progress(pf->state)) {
netdev_err(netdev, "can't open net device while reset is in progress");
return -EBUSY;
}

return ice_open_internal(netdev);
}

/**
* ice_open_internal - Called when a network interface becomes active
* @netdev: network interface device structure
*
* Internal ice_open implementation. Should not be used directly except for ice_open and reset
* handling routine
*
* Returns 0 on success, negative value on failure
*/
int ice_open_internal(struct net_device *netdev)
{
struct ice_netdev_priv *np = netdev_priv(netdev);
struct ice_vsi *vsi = np->vsi;
Expand Down Expand Up @@ -6690,6 +6712,12 @@ int ice_stop(struct net_device *netdev)
{
struct ice_netdev_priv *np = netdev_priv(netdev);
struct ice_vsi *vsi = np->vsi;
struct ice_pf *pf = vsi->back;

if (ice_is_reset_in_progress(pf->state)) {
netdev_err(netdev, "can't stop net device while reset is in progress");
return -EBUSY;
}

ice_vsi_close(vsi);

Expand Down

0 comments on commit 95067fe

Please sign in to comment.