On 26. 07. 23 22:43, Aleksandr Loktionov wrote:
Fix livelocks by acquiring rtnl_lock() before any reset related operations. Add rtnl_lock()/rtnl_unlock() at top/bottom of i40e_reset_subtask() Add check for __I40E_RESET_INTR_RECEIVED bit. Add re-entry guard by fast return in case reset is already in progress. Fixes: 373149fc99a0 ("i40e: Decrease the scope of rtnl lock") Signed-off-by: Aleksandr Loktionov <[email protected]> --- v3->v4 fix | position in the code v2->v3 fix typo in the commit message v1->v2 * apply on https://git.kernel.org/pub/scm/linux/kernel/git/tnguy/net-queue.git --- --- drivers/net/ethernet/intel/i40e/i40e_main.c | 39 +++++++++++---------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 7c30abd..164f7c6 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -10011,42 +10011,44 @@ static void i40e_reset_subtask(struct i40e_pf *pf) { u32 reset_flags = 0;- if (test_bit(__I40E_REINIT_REQUESTED, pf->state)) {+ if (test_and_clear_bit(__I40E_REINIT_REQUESTED, pf->state)) reset_flags |= BIT(__I40E_REINIT_REQUESTED); - clear_bit(__I40E_REINIT_REQUESTED, pf->state); - } - if (test_bit(__I40E_PF_RESET_REQUESTED, pf->state)) { + if (test_and_clear_bit(__I40E_PF_RESET_REQUESTED, pf->state)) reset_flags |= BIT(__I40E_PF_RESET_REQUESTED); - clear_bit(__I40E_PF_RESET_REQUESTED, pf->state); - } - if (test_bit(__I40E_CORE_RESET_REQUESTED, pf->state)) { + if (test_and_clear_bit(__I40E_CORE_RESET_REQUESTED, pf->state)) reset_flags |= BIT(__I40E_CORE_RESET_REQUESTED); - clear_bit(__I40E_CORE_RESET_REQUESTED, pf->state); - } - if (test_bit(__I40E_GLOBAL_RESET_REQUESTED, pf->state)) { + if (test_and_clear_bit(__I40E_GLOBAL_RESET_REQUESTED, pf->state)) reset_flags |= BIT(__I40E_GLOBAL_RESET_REQUESTED); - clear_bit(__I40E_GLOBAL_RESET_REQUESTED, pf->state); - } - if (test_bit(__I40E_DOWN_REQUESTED, pf->state)) { + if (test_and_clear_bit(__I40E_DOWN_REQUESTED, pf->state)) reset_flags |= BIT(__I40E_DOWN_REQUESTED); - clear_bit(__I40E_DOWN_REQUESTED, pf->state); - } + if (test_and_clear_bit(__I40E_RESET_INTR_RECEIVED, pf->state)) + reset_flags |= BIT(__I40E_RESET_INTR_RECEIVED); + + if (!(reset_flags & (BIT(__I40E_PF_RESET_REQUESTED) | + BIT(__I40E_CORE_RESET_REQUESTED) | + BIT(__I40E_GLOBAL_RESET_REQUESTED) | + BIT(__I40E_RESET_INTR_RECEIVED)))) + return; + + rtnl_lock();/* If there's a recovery already waiting, it takes* precedence before starting a new reset sequence. */ - if (test_bit(__I40E_RESET_INTR_RECEIVED, pf->state)) { + if (reset_flags & BIT(__I40E_RESET_INTR_RECEIVED)) { i40e_prep_for_reset(pf); i40e_reset(pf); - i40e_rebuild(pf, false, false); + i40e_rebuild(pf, false, true); }/* If we're already down or resetting, just bail */if (reset_flags && !test_bit(__I40E_DOWN, pf->state) && !test_bit(__I40E_CONFIG_BUSY, pf->state)) { - i40e_do_reset(pf, reset_flags, false); + i40e_do_reset(pf, reset_flags, true); } + + rtnl_unlock(); }/**@@ -10694,7 +10696,6 @@ static void i40e_prep_for_reset(struct i40e_pf *pf) int ret = 0; u32 v;- clear_bit(__I40E_RESET_INTR_RECEIVED, pf->state);if (test_and_set_bit(__I40E_RESET_RECOVERY_PENDING, pf->state)) return; if (i40e_check_asq_alive(&pf->hw))
Tony, why this is marked in IWL patchwork as ChangesRequested? There were no comments and the patch disappeared from dev-queue. Are you planning to process it?
Thanks, Ivan
