aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2008-02-25 10:27:46 -0500
committerJohn W. Linville <linville@tuxdriver.com>2008-03-06 15:30:46 -0500
commitd0709a65181beb787ef3f58cfe45536a2bb254c8 (patch)
tree29e5f36583b0e0a3f11b291347e57672eab41dad /drivers/net/wireless/iwlwifi/iwl-3945-rs.c
parent5cf121c3cdb955583bf0c5d28c992b7968a4aa1a (diff)
mac80211: RCU-ify STA info structure access
This makes access to the STA hash table/list use RCU to protect against freeing of items. However, it's not a true RCU, the copy step is missing: whenever somebody changes a STA item it is simply updated. This is an existing race condition that is now somewhat understandable. This patch also fixes the race key freeing vs. STA destruction by making sure that sta_info_destroy() is always called under RTNL and frees the key. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-3945-rs.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-rs.c31
1 files changed, 18 insertions, 13 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
index a8223c4cc97c..c4bfba6f3c2b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
@@ -471,10 +471,11 @@ static void rs_tx_status(void *priv_rate,
471 return; 471 return;
472 } 472 }
473 473
474 rcu_read_lock();
475
474 sta = sta_info_get(local, hdr->addr1); 476 sta = sta_info_get(local, hdr->addr1);
475 if (!sta || !sta->rate_ctrl_priv) { 477 if (!sta || !sta->rate_ctrl_priv) {
476 if (sta) 478 rcu_read_unlock();
477 sta_info_put(sta);
478 IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); 479 IWL_DEBUG_RATE("leave: No STA priv data to update!\n");
479 return; 480 return;
480 } 481 }
@@ -547,7 +548,7 @@ static void rs_tx_status(void *priv_rate,
547 548
548 spin_unlock_irqrestore(&rs_sta->lock, flags); 549 spin_unlock_irqrestore(&rs_sta->lock, flags);
549 550
550 sta_info_put(sta); 551 rcu_read_unlock();
551 552
552 IWL_DEBUG_RATE("leave\n"); 553 IWL_DEBUG_RATE("leave\n");
553 554
@@ -658,6 +659,8 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
658 659
659 IWL_DEBUG_RATE("enter\n"); 660 IWL_DEBUG_RATE("enter\n");
660 661
662 rcu_read_lock();
663
661 sta = sta_info_get(local, hdr->addr1); 664 sta = sta_info_get(local, hdr->addr1);
662 665
663 /* Send management frames and broadcast/multicast data using lowest 666 /* Send management frames and broadcast/multicast data using lowest
@@ -668,8 +671,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
668 !sta || !sta->rate_ctrl_priv) { 671 !sta || !sta->rate_ctrl_priv) {
669 IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); 672 IWL_DEBUG_RATE("leave: No STA priv data to update!\n");
670 sel->rate = rate_lowest(local, band, sta); 673 sel->rate = rate_lowest(local, band, sta);
671 if (sta) 674 rcu_read_unlock();
672 sta_info_put(sta);
673 return; 675 return;
674 } 676 }
675 677
@@ -811,7 +813,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
811 else 813 else
812 sta->txrate_idx = sta->last_txrate_idx; 814 sta->txrate_idx = sta->last_txrate_idx;
813 815
814 sta_info_put(sta); 816 rcu_read_unlock();
815 817
816 IWL_DEBUG_RATE("leave: %d\n", index); 818 IWL_DEBUG_RATE("leave: %d\n", index);
817 819
@@ -843,13 +845,15 @@ int iwl3945_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
843 unsigned long now = jiffies; 845 unsigned long now = jiffies;
844 u32 max_time = 0; 846 u32 max_time = 0;
845 847
848 rcu_read_lock();
849
846 sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr); 850 sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr);
847 if (!sta || !sta->rate_ctrl_priv) { 851 if (!sta || !sta->rate_ctrl_priv) {
848 if (sta) { 852 if (sta)
849 sta_info_put(sta);
850 IWL_DEBUG_RATE("leave - no private rate data!\n"); 853 IWL_DEBUG_RATE("leave - no private rate data!\n");
851 } else 854 else
852 IWL_DEBUG_RATE("leave - no station!\n"); 855 IWL_DEBUG_RATE("leave - no station!\n");
856 rcu_read_unlock();
853 return sprintf(buf, "station %d not found\n", sta_id); 857 return sprintf(buf, "station %d not found\n", sta_id);
854 } 858 }
855 859
@@ -890,7 +894,7 @@ int iwl3945_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
890 i = j; 894 i = j;
891 } 895 }
892 spin_unlock_irqrestore(&rs_sta->lock, flags); 896 spin_unlock_irqrestore(&rs_sta->lock, flags);
893 sta_info_put(sta); 897 rcu_read_unlock();
894 898
895 /* Display the average rate of all samples taken. 899 /* Display the average rate of all samples taken.
896 * 900 *
@@ -927,11 +931,12 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
927 return; 931 return;
928 } 932 }
929 933
934 rcu_read_lock();
935
930 sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr); 936 sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr);
931 if (!sta || !sta->rate_ctrl_priv) { 937 if (!sta || !sta->rate_ctrl_priv) {
932 if (sta)
933 sta_info_put(sta);
934 IWL_DEBUG_RATE("leave - no private rate data!\n"); 938 IWL_DEBUG_RATE("leave - no private rate data!\n");
939 rcu_read_unlock();
935 return; 940 return;
936 } 941 }
937 942
@@ -958,7 +963,7 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
958 break; 963 break;
959 } 964 }
960 965
961 sta_info_put(sta); 966 rcu_read_unlock();
962 spin_unlock_irqrestore(&rs_sta->lock, flags); 967 spin_unlock_irqrestore(&rs_sta->lock, flags);
963 968
964 rssi = priv->last_rx_rssi; 969 rssi = priv->last_rx_rssi;