mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-28 11:18:45 +07:00
ice: prevent ice_open and ice_stop during reset
commit e95fc8573e07c5e4825df4650fd8b8c93fad27a7 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: cdedef59de
("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>
This commit is contained in:
parent
ef7ed8c77d
commit
4686a26e95
@ -605,6 +605,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);
|
||||
|
||||
|
@ -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();
|
||||
@ -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();
|
||||
|
@ -6613,6 +6613,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;
|
||||
@ -6693,6 +6715,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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user