mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 03:15:31 +09:00
iavf: Fix locking for VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS
[ Upstream commit0579fafd37] iavf_virtchnl_completion is called under crit_lock but when the code for VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS is called, this lock is released in order to obtain rtnl_lock to avoid ABBA deadlock with unregister_netdev. Along with the new way iavf_remove behaves, there exist many risks related to the lock release and attmepts to regrab it. The driver faces crashes related to races between unregister_netdev and netdev_update_features. Yet another risk is that the driver could already obtain the crit_lock in order to destroy it and iavf_virtchnl_completion could crash or block forever. Make iavf_virtchnl_completion never relock crit_lock in it's call paths. Extract rtnl_lock locking logic to the driver for unregister_netdev in order to set the netdev_registered flag inside the lock. Introduce a new flag that will inform adminq_task to perform the code from VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS right after it finishes processing messages. Guard this code with remove flags so it's never called when the driver is in remove state. Fixes:5951a2b981("iavf: Fix VLAN feature flags after VFR") Signed-off-by: Slawomir Laba <slawomirx.laba@intel.com> Signed-off-by: Phani Burra <phani.r.burra@intel.com> Signed-off-by: Jacob Keller <jacob.e.keller@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> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
8c0e4da633
commit
ddc5db0bcf
@@ -274,6 +274,7 @@ struct iavf_adapter {
|
||||
#define IAVF_FLAG_LEGACY_RX BIT(15)
|
||||
#define IAVF_FLAG_REINIT_ITR_NEEDED BIT(16)
|
||||
#define IAVF_FLAG_QUEUES_DISABLED BIT(17)
|
||||
#define IAVF_FLAG_SETUP_NETDEV_FEATURES BIT(18)
|
||||
/* duplicates for common code */
|
||||
#define IAVF_FLAG_DCB_ENABLED 0
|
||||
/* flags for admin queue service task */
|
||||
|
||||
@@ -2463,6 +2463,18 @@ static void iavf_adminq_task(struct work_struct *work)
|
||||
} while (pending);
|
||||
mutex_unlock(&adapter->crit_lock);
|
||||
|
||||
if ((adapter->flags & IAVF_FLAG_SETUP_NETDEV_FEATURES)) {
|
||||
if (adapter->netdev_registered ||
|
||||
!test_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section)) {
|
||||
struct net_device *netdev = adapter->netdev;
|
||||
|
||||
rtnl_lock();
|
||||
netdev_update_features(netdev);
|
||||
rtnl_unlock();
|
||||
}
|
||||
|
||||
adapter->flags &= ~IAVF_FLAG_SETUP_NETDEV_FEATURES;
|
||||
}
|
||||
if ((adapter->flags &
|
||||
(IAVF_FLAG_RESET_PENDING | IAVF_FLAG_RESET_NEEDED)) ||
|
||||
adapter->state == __IAVF_RESETTING)
|
||||
@@ -4027,8 +4039,10 @@ static void iavf_remove(struct pci_dev *pdev)
|
||||
cancel_delayed_work_sync(&adapter->watchdog_task);
|
||||
|
||||
if (adapter->netdev_registered) {
|
||||
unregister_netdev(netdev);
|
||||
rtnl_lock();
|
||||
unregister_netdevice(netdev);
|
||||
adapter->netdev_registered = false;
|
||||
rtnl_unlock();
|
||||
}
|
||||
if (CLIENT_ALLOWED(adapter)) {
|
||||
err = iavf_lan_del_device(adapter);
|
||||
|
||||
@@ -1752,19 +1752,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
|
||||
|
||||
spin_unlock_bh(&adapter->mac_vlan_list_lock);
|
||||
iavf_process_config(adapter);
|
||||
|
||||
/* unlock crit_lock before acquiring rtnl_lock as other
|
||||
* processes holding rtnl_lock could be waiting for the same
|
||||
* crit_lock
|
||||
*/
|
||||
mutex_unlock(&adapter->crit_lock);
|
||||
rtnl_lock();
|
||||
netdev_update_features(adapter->netdev);
|
||||
rtnl_unlock();
|
||||
if (iavf_lock_timeout(&adapter->crit_lock, 10000))
|
||||
dev_warn(&adapter->pdev->dev, "failed to acquire crit_lock in %s\n",
|
||||
__FUNCTION__);
|
||||
|
||||
adapter->flags |= IAVF_FLAG_SETUP_NETDEV_FEATURES;
|
||||
}
|
||||
break;
|
||||
case VIRTCHNL_OP_ENABLE_QUEUES:
|
||||
|
||||
Reference in New Issue
Block a user