diff options
author | Tomas Winkler <tomas.winkler@intel.com> | 2008-05-27 10:50:52 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-06-03 15:00:16 -0400 |
commit | b83f4e15e65d94f6f56924b0b06a77a7ca2b4d8a (patch) | |
tree | 0b05ba16e7e2d53d6831e2a198a7a4c41836a752 /net | |
parent | 747cf5e924a469a15a454b88a813236460b30975 (diff) |
mac80211: fix deadlock in sta->lock
This patch fixes a deadlock of sta->lock use, occurring while changing
tx aggregation states, as dev_queue_xmit end up in new function
test_and_clear_sta_flags that uses that lock thus leading to deadlock
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Ron Rindjunsky <ron.rindjunsky@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/main.c | 30 |
1 files changed, 17 insertions, 13 deletions
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 97d4a537ca2f..f79f6b9938a6 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -589,8 +589,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
589 | sta = sta_info_get(local, ra); | 589 | sta = sta_info_get(local, ra); |
590 | if (!sta) { | 590 | if (!sta) { |
591 | printk(KERN_DEBUG "Could not find the station\n"); | 591 | printk(KERN_DEBUG "Could not find the station\n"); |
592 | rcu_read_unlock(); | 592 | ret = -ENOENT; |
593 | return -ENOENT; | 593 | goto exit; |
594 | } | 594 | } |
595 | 595 | ||
596 | spin_lock_bh(&sta->lock); | 596 | spin_lock_bh(&sta->lock); |
@@ -598,7 +598,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
598 | /* we have tried too many times, receiver does not want A-MPDU */ | 598 | /* we have tried too many times, receiver does not want A-MPDU */ |
599 | if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) { | 599 | if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) { |
600 | ret = -EBUSY; | 600 | ret = -EBUSY; |
601 | goto start_ba_exit; | 601 | goto err_unlock_sta; |
602 | } | 602 | } |
603 | 603 | ||
604 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | 604 | state = &sta->ampdu_mlme.tid_state_tx[tid]; |
@@ -609,7 +609,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
609 | "idle on tid %u\n", tid); | 609 | "idle on tid %u\n", tid); |
610 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 610 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
611 | ret = -EAGAIN; | 611 | ret = -EAGAIN; |
612 | goto start_ba_exit; | 612 | goto err_unlock_sta; |
613 | } | 613 | } |
614 | 614 | ||
615 | /* prepare A-MPDU MLME for Tx aggregation */ | 615 | /* prepare A-MPDU MLME for Tx aggregation */ |
@@ -620,7 +620,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
620 | printk(KERN_ERR "allocate tx mlme to tid %d failed\n", | 620 | printk(KERN_ERR "allocate tx mlme to tid %d failed\n", |
621 | tid); | 621 | tid); |
622 | ret = -ENOMEM; | 622 | ret = -ENOMEM; |
623 | goto start_ba_exit; | 623 | goto err_unlock_sta; |
624 | } | 624 | } |
625 | /* Tx timer */ | 625 | /* Tx timer */ |
626 | sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function = | 626 | sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function = |
@@ -643,7 +643,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
643 | printk(KERN_DEBUG "BA request denied - queue unavailable for" | 643 | printk(KERN_DEBUG "BA request denied - queue unavailable for" |
644 | " tid %d\n", tid); | 644 | " tid %d\n", tid); |
645 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 645 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
646 | goto start_ba_err; | 646 | goto err_unlock_queue; |
647 | } | 647 | } |
648 | sdata = sta->sdata; | 648 | sdata = sta->sdata; |
649 | 649 | ||
@@ -665,12 +665,13 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
665 | " tid %d\n", tid); | 665 | " tid %d\n", tid); |
666 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 666 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
667 | *state = HT_AGG_STATE_IDLE; | 667 | *state = HT_AGG_STATE_IDLE; |
668 | goto start_ba_err; | 668 | goto err_unlock_queue; |
669 | } | 669 | } |
670 | 670 | ||
671 | /* Will put all the packets in the new SW queue */ | 671 | /* Will put all the packets in the new SW queue */ |
672 | ieee80211_requeue(local, ieee802_1d_to_ac[tid]); | 672 | ieee80211_requeue(local, ieee802_1d_to_ac[tid]); |
673 | spin_unlock_bh(&local->mdev->queue_lock); | 673 | spin_unlock_bh(&local->mdev->queue_lock); |
674 | spin_unlock_bh(&sta->lock); | ||
674 | 675 | ||
675 | /* send an addBA request */ | 676 | /* send an addBA request */ |
676 | sta->ampdu_mlme.dialog_token_allocator++; | 677 | sta->ampdu_mlme.dialog_token_allocator++; |
@@ -678,25 +679,26 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
678 | sta->ampdu_mlme.dialog_token_allocator; | 679 | sta->ampdu_mlme.dialog_token_allocator; |
679 | sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num; | 680 | sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num; |
680 | 681 | ||
682 | |||
681 | ieee80211_send_addba_request(sta->sdata->dev, ra, tid, | 683 | ieee80211_send_addba_request(sta->sdata->dev, ra, tid, |
682 | sta->ampdu_mlme.tid_tx[tid]->dialog_token, | 684 | sta->ampdu_mlme.tid_tx[tid]->dialog_token, |
683 | sta->ampdu_mlme.tid_tx[tid]->ssn, | 685 | sta->ampdu_mlme.tid_tx[tid]->ssn, |
684 | 0x40, 5000); | 686 | 0x40, 5000); |
685 | |||
686 | /* activate the timer for the recipient's addBA response */ | 687 | /* activate the timer for the recipient's addBA response */ |
687 | sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires = | 688 | sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires = |
688 | jiffies + ADDBA_RESP_INTERVAL; | 689 | jiffies + ADDBA_RESP_INTERVAL; |
689 | add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); | 690 | add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); |
690 | printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid); | 691 | printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid); |
691 | goto start_ba_exit; | 692 | goto exit; |
692 | 693 | ||
693 | start_ba_err: | 694 | err_unlock_queue: |
694 | kfree(sta->ampdu_mlme.tid_tx[tid]); | 695 | kfree(sta->ampdu_mlme.tid_tx[tid]); |
695 | sta->ampdu_mlme.tid_tx[tid] = NULL; | 696 | sta->ampdu_mlme.tid_tx[tid] = NULL; |
696 | spin_unlock_bh(&local->mdev->queue_lock); | 697 | spin_unlock_bh(&local->mdev->queue_lock); |
697 | ret = -EBUSY; | 698 | ret = -EBUSY; |
698 | start_ba_exit: | 699 | err_unlock_sta: |
699 | spin_unlock_bh(&sta->lock); | 700 | spin_unlock_bh(&sta->lock); |
701 | exit: | ||
700 | rcu_read_unlock(); | 702 | rcu_read_unlock(); |
701 | return ret; | 703 | return ret; |
702 | } | 704 | } |
@@ -835,10 +837,11 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) | |||
835 | } | 837 | } |
836 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | 838 | state = &sta->ampdu_mlme.tid_state_tx[tid]; |
837 | 839 | ||
838 | spin_lock_bh(&sta->lock); | 840 | /* NOTE: no need to use sta->lock in this state check, as |
841 | * ieee80211_stop_tx_ba_session will let only | ||
842 | * one stop call to pass through per sta/tid */ | ||
839 | if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) { | 843 | if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) { |
840 | printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n"); | 844 | printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n"); |
841 | spin_unlock_bh(&sta->lock); | ||
842 | rcu_read_unlock(); | 845 | rcu_read_unlock(); |
843 | return; | 846 | return; |
844 | } | 847 | } |
@@ -861,6 +864,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) | |||
861 | * ieee80211_wake_queue is not used here as this queue is not | 864 | * ieee80211_wake_queue is not used here as this queue is not |
862 | * necessarily stopped */ | 865 | * necessarily stopped */ |
863 | netif_schedule(local->mdev); | 866 | netif_schedule(local->mdev); |
867 | spin_lock_bh(&sta->lock); | ||
864 | *state = HT_AGG_STATE_IDLE; | 868 | *state = HT_AGG_STATE_IDLE; |
865 | sta->ampdu_mlme.addba_req_num[tid] = 0; | 869 | sta->ampdu_mlme.addba_req_num[tid] = 0; |
866 | kfree(sta->ampdu_mlme.tid_tx[tid]); | 870 | kfree(sta->ampdu_mlme.tid_tx[tid]); |