Commit 16c45822 authored by Sara Sharon's avatar Sara Sharon Committed by Luca Coelho

iwlwifi: mvm: don't allow negative reference count

Currently code allows mvm reference to become negative and
only warns in case mvm reference is released while reference
counting is 0.
However, we better prevent this from happening at all since
iwl_mvm_unref() may race against iwl_mvm_unref_all_except()
which is called on restart.
As a result we might get the same reference unreferenced twice
ending with a negative value:
An example for an easily reproduced log:
    [ 2689.909166] iwl_mvm_ref Take mvm reference - type 8
    [ 2690.732716] iwl_mvm_unref_all_except Cleanup: remove mvm ref type 8 (1)
    [ 2690.849708] iwl_mvm_unref Leave mvm reference - type 8
    [ 2690.849721] WARNING: ... iwl_mvm_unref+0xb0/0xc0 [iwlmvm]()

If there will be yet another another restart iwl_mvm_unref_all_except
will run from 0 up to ref count, and since it is unsigned, we will throw
the transport ref count completely out of balance:
    iwl_mvm_unref_all_except[I] -- Cleanup: remove mvm ref type 8 (255)
    iwl_trans_slv_unref[I] -- rpm counter: 0
    iwl_trans_slv_unref[I] -- rpm counter: -1
    iwl_trans_slv_unref[I] -- rpm counter: -2
 ...
    iwl_trans_slv_unref[I] -- rpm counter: -253
    iwl_trans_slv_unref[I] -- rpm counter: -254

As there is no valid scenario where we can get to a negative
reference count - prevent it from happening.
Signed-off-by: default avatarSara Sharon <sara.sharon@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent e87e2639
...@@ -229,7 +229,11 @@ void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) ...@@ -229,7 +229,11 @@ void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type)
IWL_DEBUG_RPM(mvm, "Leave mvm reference - type %d\n", ref_type); IWL_DEBUG_RPM(mvm, "Leave mvm reference - type %d\n", ref_type);
spin_lock_bh(&mvm->refs_lock); spin_lock_bh(&mvm->refs_lock);
WARN_ON(!mvm->refs[ref_type]--); if (WARN_ON(!mvm->refs[ref_type])) {
spin_unlock_bh(&mvm->refs_lock);
return;
}
mvm->refs[ref_type]--;
spin_unlock_bh(&mvm->refs_lock); spin_unlock_bh(&mvm->refs_lock);
iwl_trans_unref(mvm->trans); iwl_trans_unref(mvm->trans);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment