From 16c45822a89f3b53b300784d08e9665681a43a20 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Mon, 4 Apr 2016 19:30:05 +0300 Subject: [PATCH] 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: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 5648e37..cd71017 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -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); 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); iwl_trans_unref(mvm->trans); } -- 2.7.4