Skip to content

Commit 605ca7c

Browse files
Kaaameanguy11
authored andcommitted
iavf: Fix kernel BUG in free_msi_irqs
Fix driver not freeing VF's traffic irqs, prior to calling pci_disable_msix in iavf_remove. There were possible 2 erroneous states in which, iavf_close would not be called. One erroneous state is fixed by allowing netdev to register, when state is already running. It was possible for VF adapter to enter state loop from running to resetting, where iavf_open would subsequently fail. If user would then unload driver/remove VF pci, iavf_close would not be called, as the netdev was not registered, leaving traffic pcis still allocated. Fixed this by breaking loop, allowing netdev to open device when adapter state is __IAVF_RUNNING and it is not explicitily downed. Other possiblity is entering to iavf_remove from __IAVF_RESETTING state, where iavf_close would not free irqs, but just return 0. Fixed this by checking for last adapter state and then removing irqs. Kernel panic: [ 2773.628585] kernel BUG at drivers/pci/msi.c:375! ... [ 2773.631567] RIP: 0010:free_msi_irqs+0x180/0x1b0 ... [ 2773.640939] Call Trace: [ 2773.641572] pci_disable_msix+0xf7/0x120 [ 2773.642224] iavf_reset_interrupt_capability.part.41+0x15/0x30 [iavf] [ 2773.642897] iavf_remove+0x12e/0x500 [iavf] [ 2773.643578] pci_device_remove+0x3b/0xc0 [ 2773.644266] device_release_driver_internal+0x103/0x1f0 [ 2773.644948] pci_stop_bus_device+0x69/0x90 [ 2773.645576] pci_stop_and_remove_bus_device+0xe/0x20 [ 2773.646215] pci_iov_remove_virtfn+0xba/0x120 [ 2773.646862] sriov_disable+0x2f/0xe0 [ 2773.647531] ice_free_vfs+0x2f8/0x350 [ice] [ 2773.648207] ice_sriov_configure+0x94/0x960 [ice] [ 2773.648883] ? _kstrtoull+0x3b/0x90 [ 2773.649560] sriov_numvfs_store+0x10a/0x190 [ 2773.650249] kernfs_fop_write+0x116/0x190 [ 2773.650948] vfs_write+0xa5/0x1a0 [ 2773.651651] ksys_write+0x4f/0xb0 [ 2773.652358] do_syscall_64+0x5b/0x1a0 [ 2773.653075] entry_SYSCALL_64_after_hwframe+0x65/0xca Fixes: 22ead37 ("i40evf: Add longer wait after remove module") Signed-off-by: Przemyslaw Patynowski <przemyslawx.patynowski@intel.com> Signed-off-by: Mateusz Palczewski <mateusz.palczewski@intel.com> Tested-by: Konrad Jankowski <konrad0.jankowski@intel.com> Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
1 parent 247aa00 commit 605ca7c

File tree

2 files changed

+56
-0
lines changed

2 files changed

+56
-0
lines changed

drivers/net/ethernet/intel/iavf/iavf.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,13 +394,49 @@ struct iavf_device {
394394
extern char iavf_driver_name[];
395395
extern struct workqueue_struct *iavf_wq;
396396

397+
static inline const char *iavf_state_str(enum iavf_state_t state)
398+
{
399+
switch (state) {
400+
case __IAVF_STARTUP:
401+
return "__IAVF_STARTUP";
402+
case __IAVF_REMOVE:
403+
return "__IAVF_REMOVE";
404+
case __IAVF_INIT_VERSION_CHECK:
405+
return "__IAVF_INIT_VERSION_CHECK";
406+
case __IAVF_INIT_GET_RESOURCES:
407+
return "__IAVF_INIT_GET_RESOURCES";
408+
case __IAVF_INIT_SW:
409+
return "__IAVF_INIT_SW";
410+
case __IAVF_INIT_FAILED:
411+
return "__IAVF_INIT_FAILED";
412+
case __IAVF_RESETTING:
413+
return "__IAVF_RESETTING";
414+
case __IAVF_COMM_FAILED:
415+
return "__IAVF_COMM_FAILED";
416+
case __IAVF_DOWN:
417+
return "__IAVF_DOWN";
418+
case __IAVF_DOWN_PENDING:
419+
return "__IAVF_DOWN_PENDING";
420+
case __IAVF_TESTING:
421+
return "__IAVF_TESTING";
422+
case __IAVF_RUNNING:
423+
return "__IAVF_RUNNING";
424+
default:
425+
return "__IAVF_UNKNOWN_STATE";
426+
}
427+
}
428+
397429
static inline void iavf_change_state(struct iavf_adapter *adapter,
398430
enum iavf_state_t state)
399431
{
400432
if (adapter->state != state) {
401433
adapter->last_state = adapter->state;
402434
adapter->state = state;
403435
}
436+
dev_dbg(&adapter->pdev->dev,
437+
"state transition from:%s to:%s\n",
438+
iavf_state_str(adapter->last_state),
439+
iavf_state_str(adapter->state));
404440
}
405441

406442
int iavf_up(struct iavf_adapter *adapter);

drivers/net/ethernet/intel/iavf/iavf_main.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3280,6 +3280,13 @@ static int iavf_open(struct net_device *netdev)
32803280
goto err_unlock;
32813281
}
32823282

3283+
if (adapter->state == __IAVF_RUNNING &&
3284+
!test_bit(__IAVF_VSI_DOWN, adapter->vsi.state)) {
3285+
dev_dbg(&adapter->pdev->dev, "VF is already open.\n");
3286+
err = 0;
3287+
goto err_unlock;
3288+
}
3289+
32833290
/* allocate transmit descriptors */
32843291
err = iavf_setup_all_tx_resources(adapter);
32853292
if (err)
@@ -3915,6 +3922,7 @@ static int __maybe_unused iavf_resume(struct device *dev_d)
39153922
static void iavf_remove(struct pci_dev *pdev)
39163923
{
39173924
struct iavf_adapter *adapter = iavf_pdev_to_adapter(pdev);
3925+
enum iavf_state_t prev_state = adapter->last_state;
39183926
struct net_device *netdev = adapter->netdev;
39193927
struct iavf_fdir_fltr *fdir, *fdirtmp;
39203928
struct iavf_vlan_filter *vlf, *vlftmp;
@@ -3953,10 +3961,22 @@ static void iavf_remove(struct pci_dev *pdev)
39533961
iavf_change_state(adapter, __IAVF_REMOVE);
39543962
adapter->aq_required = 0;
39553963
adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED;
3964+
39563965
iavf_free_all_tx_resources(adapter);
39573966
iavf_free_all_rx_resources(adapter);
39583967
iavf_misc_irq_disable(adapter);
39593968
iavf_free_misc_irq(adapter);
3969+
3970+
/* In case we enter iavf_remove from erroneous state, free traffic irqs
3971+
* here, so as to not cause a kernel crash, when calling
3972+
* iavf_reset_interrupt_capability.
3973+
*/
3974+
if ((adapter->last_state == __IAVF_RESETTING &&
3975+
prev_state != __IAVF_DOWN) ||
3976+
(adapter->last_state == __IAVF_RUNNING &&
3977+
!(netdev->flags & IFF_UP)))
3978+
iavf_free_traffic_irqs(adapter);
3979+
39603980
iavf_reset_interrupt_capability(adapter);
39613981
iavf_free_q_vectors(adapter);
39623982

0 commit comments

Comments
 (0)