Skip to contentSkip to conversation

d80211: ieee80211_hw handlers should be allowed to sleep

PATCH Applied Ivo van Doorn 3 participants 5 messages Oct 7, 2006 – Oct 19, 2006

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 d80211: ieee80211_hw handlers should be allowed to sleep

This patch changes the ieee80211_if_sta timer structure into a workqueue. This will allow the config(), reset_tsf() and config_interface() handlers in the ieee80211_hw structure to sleep. This is especially required for USB drivers that have to sleep for all register access.

Signed-off-by Jan Kiszka <[email protected]>
Signed-off-by Ivo van Doorn <[email protected]>

---

Note that this patch is created against the dscape git tree, this patch will likley not apply cleanly against the wireless-dev git tree.

net/d80211/ieee80211.c +4 -4
index 86062c9..aad1a34 100644
@@ -2075,15 +2075,15 @@ void ieee80211_if_shutdown(struct net_de
 	case IEEE80211_IF_TYPE_STA:
 	case IEEE80211_IF_TYPE_IBSS:
 		sdata->u.sta.state = IEEE80211_DISABLED;
-		del_timer_sync(&sdata->u.sta.timer);
+		cancel_delayed_work(&sdata->u.sta.work);
 		if (local->scan_work.data == sdata->dev) {
 			local->sta_scanning = 0;
 			cancel_delayed_work(&local->scan_work);
-			flush_scheduled_work();
 			/* see comment in ieee80211_unregister_hw to
 			 * understand why this works */
 			local->scan_work.data = NULL;
 		}
+		flush_scheduled_work();
 		break;
 	}
 }
@@ -4603,8 +4603,8 @@ void ieee80211_unregister_hw(struct net_
 		flush_scheduled_work();
 		/* The scan_work is guaranteed not to be called at this
 		 * point. It is not scheduled and not running now. It can be
-		 * scheduled again only by some sta_timer (all of them are
-		 * stopped by now) or under rtnl lock. */
+		 * scheduled again only by sta_work (stopped by now) or under
+		 * rtnl lock. */
 	}
 
 	ieee80211_rx_bss_list_deinit(dev);
net/d80211/ieee80211_i.h +2 -2
index 89666ec..5b48ce2 100644
@@ -240,7 +240,7 @@ struct ieee80211_if_sta {
 		IEEE80211_ASSOCIATE, IEEE80211_ASSOCIATED,
 		IEEE80211_IBSS_SEARCH, IEEE80211_IBSS_JOINED
 	} state;
-	struct timer_list timer;
+	struct work_struct work;
 	u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
 	u8 ssid[IEEE80211_MAX_SSID_LEN];
 	size_t ssid_len;
@@ -621,7 +621,7 @@ int ieee80211_set_compression(struct iee
 			      struct net_device *dev, struct sta_info *sta);
 int ieee80211_init_client(struct net_device *dev);
 /* ieee80211_sta.c */
-void ieee80211_sta_timer(unsigned long ptr);
+void ieee80211_sta_work(void *ptr);
 void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb,
 			   struct ieee80211_rx_status *rx_status);
 int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len);
net/d80211/ieee80211_iface.c +1 -3
index 9a187af..4dd480f 100644
@@ -194,9 +194,7 @@ void ieee80211_if_set_type(struct net_de
 		struct ieee80211_if_sta *ifsta;
 
 		ifsta = &sdata->u.sta;
-		init_timer(&ifsta->timer);
-		ifsta->timer.data = (unsigned long) dev;
-		ifsta->timer.function = ieee80211_sta_timer;
+		INIT_WORK(&ifsta->work, ieee80211_sta_work, dev);
 
 		ifsta->capab = WLAN_CAPABILITY_ESS;
 		ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN |
net/d80211/ieee80211_sta.c +19 -20
index 480e9c9..bda4f75 100644
@@ -457,7 +457,7 @@ static void ieee80211_authenticate(struc
 
 	ieee80211_send_auth(dev, ifsta, 1, NULL, 0, 0);
 
-	mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT);
+	schedule_delayed_work(&ifsta->work, IEEE80211_AUTH_TIMEOUT);
 }
 
 
@@ -677,7 +677,7 @@ static void ieee80211_associate(struct n
 
 	ieee80211_send_assoc(dev, ifsta);
 
-	mod_timer(&ifsta->timer, jiffies + IEEE80211_ASSOC_TIMEOUT);
+	schedule_delayed_work(&ifsta->work, IEEE80211_ASSOC_TIMEOUT);
 }
 
 
@@ -735,11 +735,11 @@ static void ieee80211_associated(struct 
 		memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
 		wrqu.ap_addr.sa_family = ARPHRD_ETHER;
 		wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
-		mod_timer(&ifsta->timer,
-			  jiffies + IEEE80211_MONITORING_INTERVAL + 30 * HZ);
+		schedule_delayed_work(&ifsta->work,
+				      IEEE80211_MONITORING_INTERVAL + 30 * HZ);
 	} else {
-		mod_timer(&ifsta->timer,
-			  jiffies + IEEE80211_MONITORING_INTERVAL);
+		schedule_delayed_work(&ifsta->work,
+				      IEEE80211_MONITORING_INTERVAL);
 	}
 }
 
@@ -1019,8 +1019,8 @@ static void ieee80211_rx_mgmt_deauth(str
 	    ifsta->state == IEEE80211_ASSOCIATE ||
 	    ifsta->state == IEEE80211_ASSOCIATED) {
 		ifsta->state = IEEE80211_AUTHENTICATE;
-		mod_timer(&ifsta->timer,
-			  jiffies + IEEE80211_RETRY_AUTH_INTERVAL);
+		schedule_delayed_work(&ifsta->work,
+				      IEEE80211_RETRY_AUTH_INTERVAL);
 	}
 
 	ieee80211_set_associated(dev, ifsta, 0);
@@ -1062,8 +1062,8 @@ static void ieee80211_rx_mgmt_disassoc(s
 
 	if (ifsta->state == IEEE80211_ASSOCIATED) {
 		ifsta->state = IEEE80211_ASSOCIATE;
-		mod_timer(&ifsta->timer,
-			  jiffies + IEEE80211_RETRY_AUTH_INTERVAL);
+		schedule_delayed_work(&ifsta->work,
+				      IEEE80211_RETRY_AUTH_INTERVAL);
 	}
 
 	ieee80211_set_associated(dev, ifsta, 0);
@@ -1829,7 +1829,7 @@ static void ieee80211_sta_expire(struct 
 static void ieee80211_sta_merge_ibss(struct net_device *dev,
 				     struct ieee80211_if_sta *ifsta)
 {
-	mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
+	schedule_delayed_work(&ifsta->work, IEEE80211_IBSS_MERGE_INTERVAL);
 
 	ieee80211_sta_expire(dev);
 	if (ieee80211_sta_active_ibss(dev))
@@ -1841,20 +1841,19 @@ static void ieee80211_sta_merge_ibss(str
 }
 
 
-void ieee80211_sta_timer(unsigned long ptr)
+void ieee80211_sta_work(void *ptr)
 {
-	struct net_device *dev;
+	struct net_device *dev = ptr;
 	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_if_sta *ifsta;
 
-	dev = (struct net_device *) ptr;
 	if (!netif_running(dev))
 		return;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	if (sdata->type != IEEE80211_IF_TYPE_STA &&
 	    sdata->type != IEEE80211_IF_TYPE_IBSS) {
-		printk(KERN_DEBUG "%s: ieee80211_sta_timer: non-STA interface "
+		printk(KERN_DEBUG "%s: ieee80211_sta_work: non-STA interface "
 		       "(type=%d)\n", dev->name, sdata->type);
 		return;
 	}
@@ -1879,7 +1878,7 @@ void ieee80211_sta_timer(unsigned long p
 		ieee80211_sta_merge_ibss(dev, ifsta);
 		break;
 	default:
-		printk(KERN_DEBUG "ieee80211_sta_timer: Unknown state %d\n",
+		printk(KERN_DEBUG "ieee80211_sta_work: Unknown state %d\n",
 		       ifsta->state);
 		break;
 	}
@@ -2107,7 +2106,7 @@ static int ieee80211_sta_join_ibss(struc
 	}
 
 	ifsta->state = IEEE80211_IBSS_JOINED;
-	mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
+	schedule_delayed_work(&ifsta->work, IEEE80211_IBSS_MERGE_INTERVAL);
 
 	ieee80211_rx_bss_put(dev, bss);
 
@@ -2224,8 +2223,8 @@ #endif /* CONFIG_D80211_IBSS_DEBUG */
 	/* Selected IBSS not found in current scan results - try to scan */
 	if (ifsta->state == IEEE80211_IBSS_JOINED &&
 	    !ieee80211_sta_active_ibss(dev)) {
-		mod_timer(&ifsta->timer,
-			  jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
+		schedule_delayed_work(&ifsta->work,
+				      IEEE80211_IBSS_MERGE_INTERVAL);
 	} else if (time_after(jiffies, local->last_scan_completed +
 			      IEEE80211_SCAN_INTERVAL)) {
 		printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to "
@@ -2253,7 +2252,7 @@ #endif /* CONFIG_D80211_IBSS_DEBUG */
 		}
 
 		ifsta->state = IEEE80211_IBSS_SEARCH;
-		mod_timer(&ifsta->timer, jiffies + interval);
+		schedule_delayed_work(&ifsta->work, interval);
 		return 0;
 	}
 
#1 lore raw
Quoted 7 lines · Ivo van Doorn
net/d80211/ieee80211.c +0 -1
@@ -2075,15 +2075,15 @@ void ieee80211_if_shutdown(struct net_de
 	case IEEE80211_IF_TYPE_STA:
 	case IEEE80211_IF_TYPE_IBSS:
 		sdata->u.sta.state = IEEE80211_DISABLED;
-		del_timer_sync(&sdata->u.sta.timer);

net/d80211/ieee80211.c void ieee80211_if_shutdown(struct net_de · line 2086

Quoted 10 lines
net/d80211/ieee80211.c +2 -1
+		cancel_delayed_work(&sdata->u.sta.work);
 		if (local->scan_work.data == sdata->dev) {
 			local->sta_scanning = 0;
 			cancel_delayed_work(&local->scan_work);
-			flush_scheduled_work();
 			/* see comment in ieee80211_unregister_hw to
 			 * understand why this works */
 			local->scan_work.data = NULL;
 		}
+		flush_scheduled_work();

This is racy. local->scan_work.data can be set to NULL only after flush_scheduled_work().

Other than that, the patch looks good to me.

Thanks,

Jiri

Signature · 2 lines
Jiri Benc
SUSE Labs
#2 lore raw
Quoted 13 lines · Jiri Benc
Quoted 12 lines · Ivo van Doorn
net/d80211/ieee80211.c +1 -2
@@ -2075,15 +2075,15 @@ void ieee80211_if_shutdown(struct net_de
 	case IEEE80211_IF_TYPE_STA:
 	case IEEE80211_IF_TYPE_IBSS:
 		sdata->u.sta.state = IEEE80211_DISABLED;
-		del_timer_sync(&sdata->u.sta.timer);
+		cancel_delayed_work(&sdata->u.sta.work);
 		if (local->scan_work.data == sdata->dev) {
 			local->sta_scanning = 0;
 			cancel_delayed_work(&local->scan_work);
-			flush_scheduled_work();
Quoted 8 lines

net/d80211/ieee80211.c void ieee80211_if_shutdown(struct net_de · line 2086

Quoted 5 lines
net/d80211/ieee80211.c +1 -0
 			/* see comment in ieee80211_unregister_hw to
 			 * understand why this works */
 			local->scan_work.data = NULL;
 		}
+		flush_scheduled_work();

This is racy. local->scan_work.data can be set to NULL only after flush_scheduled_work().

Would something like the patch below be better?
It keeps the flush_scheduled_work() at the same location, but a second is added in case local->scan_work.data != sdata->dev

Jan, was there any particular reason to move flush_cheduled_work() outside of the if-statement?

Signed-off-by Ivo van Doorn <[email protected]>

---

net/d80211/ieee80211.c +5 -4
index 32a1ba7..cb1180c 100644
@@ -2075,7 +2075,7 @@ void ieee80211_if_shutdown(struct net_de
 	case IEEE80211_IF_TYPE_STA:
 	case IEEE80211_IF_TYPE_IBSS:
 		sdata->u.sta.state = IEEE80211_DISABLED;
-		del_timer_sync(&sdata->u.sta.timer);
+		cancel_delayed_work(&sdata->u.sta.work);
 		if (local->scan_work.data == sdata->dev) {
 			local->sta_scanning = 0;
 			cancel_delayed_work(&local->scan_work);
@@ -2083,7 +2083,8 @@ void ieee80211_if_shutdown(struct net_de
 			/* see comment in ieee80211_unregister_hw to
 			 * understand why this works */
 			local->scan_work.data = NULL;
-		}
+		} else
+			flush_scheduled_work();
 		break;
 	}
 }
@@ -4605,8 +4606,8 @@ void ieee80211_unregister_hw(struct net_
 		flush_scheduled_work();
 		/* The scan_work is guaranteed not to be called at this
 		 * point. It is not scheduled and not running now. It can be
-		 * scheduled again only by some sta_timer (all of them are
-		 * stopped by now) or under rtnl lock. */
+		 * scheduled again only by sta_work (stopped by now) or under
+		 * rtnl lock. */
 	}
 
 	ieee80211_rx_bss_list_deinit(dev);
net/d80211/ieee80211_i.h +2 -2
index 89666ec..5b48ce2 100644
@@ -240,7 +240,7 @@ struct ieee80211_if_sta {
 		IEEE80211_ASSOCIATE, IEEE80211_ASSOCIATED,
 		IEEE80211_IBSS_SEARCH, IEEE80211_IBSS_JOINED
 	} state;
-	struct timer_list timer;
+	struct work_struct work;
 	u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
 	u8 ssid[IEEE80211_MAX_SSID_LEN];
 	size_t ssid_len;
@@ -621,7 +621,7 @@ int ieee80211_set_compression(struct iee
 			      struct net_device *dev, struct sta_info *sta);
 int ieee80211_init_client(struct net_device *dev);
 /* ieee80211_sta.c */
-void ieee80211_sta_timer(unsigned long ptr);
+void ieee80211_sta_work(void *ptr);
 void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb,
 			   struct ieee80211_rx_status *rx_status);
 int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len);
net/d80211/ieee80211_iface.c +1 -3
index 9a187af..4dd480f 100644
@@ -194,9 +194,7 @@ void ieee80211_if_set_type(struct net_de
 		struct ieee80211_if_sta *ifsta;
 
 		ifsta = &sdata->u.sta;
-		init_timer(&ifsta->timer);
-		ifsta->timer.data = (unsigned long) dev;
-		ifsta->timer.function = ieee80211_sta_timer;
+		INIT_WORK(&ifsta->work, ieee80211_sta_work, dev);
 
 		ifsta->capab = WLAN_CAPABILITY_ESS;
 		ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN |
net/d80211/ieee80211_sta.c +19 -20
index cc336bd..bf74b6b 100644
@@ -457,7 +457,7 @@ static void ieee80211_authenticate(struc
 
 	ieee80211_send_auth(dev, ifsta, 1, NULL, 0, 0);
 
-	mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT);
+	schedule_delayed_work(&ifsta->work, IEEE80211_AUTH_TIMEOUT);
 }
 
 
@@ -677,7 +677,7 @@ static void ieee80211_associate(struct n
 
 	ieee80211_send_assoc(dev, ifsta);
 
-	mod_timer(&ifsta->timer, jiffies + IEEE80211_ASSOC_TIMEOUT);
+	schedule_delayed_work(&ifsta->work, IEEE80211_ASSOC_TIMEOUT);
 }
 
 
@@ -735,11 +735,11 @@ static void ieee80211_associated(struct 
 		memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
 		wrqu.ap_addr.sa_family = ARPHRD_ETHER;
 		wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
-		mod_timer(&ifsta->timer,
-			  jiffies + IEEE80211_MONITORING_INTERVAL + 30 * HZ);
+		schedule_delayed_work(&ifsta->work,
+				      IEEE80211_MONITORING_INTERVAL + 30 * HZ);
 	} else {
-		mod_timer(&ifsta->timer,
-			  jiffies + IEEE80211_MONITORING_INTERVAL);
+		schedule_delayed_work(&ifsta->work,
+				      IEEE80211_MONITORING_INTERVAL);
 	}
 }
 
@@ -1019,8 +1019,8 @@ static void ieee80211_rx_mgmt_deauth(str
 	    ifsta->state == IEEE80211_ASSOCIATE ||
 	    ifsta->state == IEEE80211_ASSOCIATED) {
 		ifsta->state = IEEE80211_AUTHENTICATE;
-		mod_timer(&ifsta->timer,
-			  jiffies + IEEE80211_RETRY_AUTH_INTERVAL);
+		schedule_delayed_work(&ifsta->work,
+				      IEEE80211_RETRY_AUTH_INTERVAL);
 	}
 
 	ieee80211_set_associated(dev, ifsta, 0);
@@ -1062,8 +1062,8 @@ static void ieee80211_rx_mgmt_disassoc(s
 
 	if (ifsta->state == IEEE80211_ASSOCIATED) {
 		ifsta->state = IEEE80211_ASSOCIATE;
-		mod_timer(&ifsta->timer,
-			  jiffies + IEEE80211_RETRY_AUTH_INTERVAL);
+		schedule_delayed_work(&ifsta->work,
+				      IEEE80211_RETRY_AUTH_INTERVAL);
 	}
 
 	ieee80211_set_associated(dev, ifsta, 0);
@@ -1829,7 +1829,7 @@ static void ieee80211_sta_expire(struct 
 static void ieee80211_sta_merge_ibss(struct net_device *dev,
 				     struct ieee80211_if_sta *ifsta)
 {
-	mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
+	schedule_delayed_work(&ifsta->work, IEEE80211_IBSS_MERGE_INTERVAL);
 
 	ieee80211_sta_expire(dev);
 	if (ieee80211_sta_active_ibss(dev))
@@ -1841,20 +1841,19 @@ static void ieee80211_sta_merge_ibss(str
 }
 
 
-void ieee80211_sta_timer(unsigned long ptr)
+void ieee80211_sta_work(void *ptr)
 {
-	struct net_device *dev;
+	struct net_device *dev = ptr;
 	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_if_sta *ifsta;
 
-	dev = (struct net_device *) ptr;
 	if (!netif_running(dev))
 		return;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	if (sdata->type != IEEE80211_IF_TYPE_STA &&
 	    sdata->type != IEEE80211_IF_TYPE_IBSS) {
-		printk(KERN_DEBUG "%s: ieee80211_sta_timer: non-STA interface "
+		printk(KERN_DEBUG "%s: ieee80211_sta_work: non-STA interface "
 		       "(type=%d)\n", dev->name, sdata->type);
 		return;
 	}
@@ -1879,7 +1878,7 @@ void ieee80211_sta_timer(unsigned long p
 		ieee80211_sta_merge_ibss(dev, ifsta);
 		break;
 	default:
-		printk(KERN_DEBUG "ieee80211_sta_timer: Unknown state %d\n",
+		printk(KERN_DEBUG "ieee80211_sta_work: Unknown state %d\n",
 		       ifsta->state);
 		break;
 	}
@@ -2107,7 +2106,7 @@ static int ieee80211_sta_join_ibss(struc
 	}
 
 	ifsta->state = IEEE80211_IBSS_JOINED;
-	mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
+	schedule_delayed_work(&ifsta->work, IEEE80211_IBSS_MERGE_INTERVAL);
 
 	ieee80211_rx_bss_put(dev, bss);
 
@@ -2224,8 +2223,8 @@ #endif /* CONFIG_D80211_IBSS_DEBUG */
 	/* Selected IBSS not found in current scan results - try to scan */
 	if (ifsta->state == IEEE80211_IBSS_JOINED &&
 	    !ieee80211_sta_active_ibss(dev)) {
-		mod_timer(&ifsta->timer,
-			  jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
+		schedule_delayed_work(&ifsta->work,
+				      IEEE80211_IBSS_MERGE_INTERVAL);
 	} else if (time_after(jiffies, local->last_scan_completed +
 			      IEEE80211_SCAN_INTERVAL)) {
 		printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to "
@@ -2253,7 +2252,7 @@ #endif /* CONFIG_D80211_IBSS_DEBUG */
 		}
 
 		ifsta->state = IEEE80211_IBSS_SEARCH;
-		mod_timer(&ifsta->timer, jiffies + interval);
+		schedule_delayed_work(&ifsta->work, interval);
 		return 0;
 	}
 
#3 lore raw
Quoted 22 lines · Ivo van Doorn
Quoted 12 lines · Jiri Benc
Quoted 11 lines · Ivo van Doorn
net/d80211/ieee80211.c +1 -1
@@ -2075,15 +2075,15 @@ void ieee80211_if_shutdown(struct net_de
 	case IEEE80211_IF_TYPE_STA:
 	case IEEE80211_IF_TYPE_IBSS:
 		sdata->u.sta.state = IEEE80211_DISABLED;
-		del_timer_sync(&sdata->u.sta.timer);
+		cancel_delayed_work(&sdata->u.sta.work);
 		if (local->scan_work.data == sdata->dev) {
 			local->sta_scanning = 0;
 			cancel_delayed_work(&local->scan_work);
Quoted 8 lines

net/d80211/ieee80211.c void ieee80211_if_shutdown(struct net_de

Quoted 6 lines
net/d80211/ieee80211.c +1 -1
-			flush_scheduled_work();
 			/* see comment in ieee80211_unregister_hw to
 			 * understand why this works */
 			local->scan_work.data = NULL;
 		}
+		flush_scheduled_work();

This is racy. local->scan_work.data can be set to NULL only after flush_scheduled_work().

Quoted 5 lines

Would something like the patch below be better?
It keeps the flush_scheduled_work() at the same location, but a second is added in case local->scan_work.data != sdata->dev

Jan, was there any particular reason to move flush_cheduled_work() outside of the if-statement?

It is needed unconditionally now, so I moved it out without knowing about this side effect. Your approach looks good to me.

Quoted 207 lines

Signed-off-by Ivo van Doorn <[email protected]>

---

net/d80211/ieee80211.c +5 -4
index 32a1ba7..cb1180c 100644
@@ -2075,7 +2075,7 @@ void ieee80211_if_shutdown(struct net_de
 	case IEEE80211_IF_TYPE_STA:
 	case IEEE80211_IF_TYPE_IBSS:
 		sdata->u.sta.state = IEEE80211_DISABLED;
-		del_timer_sync(&sdata->u.sta.timer);
+		cancel_delayed_work(&sdata->u.sta.work);
 		if (local->scan_work.data == sdata->dev) {
 			local->sta_scanning = 0;
 			cancel_delayed_work(&local->scan_work);
@@ -2083,7 +2083,8 @@ void ieee80211_if_shutdown(struct net_de
 			/* see comment in ieee80211_unregister_hw to
 			 * understand why this works */
 			local->scan_work.data = NULL;
-		}
+		} else
+			flush_scheduled_work();
 		break;
 	}
 }
@@ -4605,8 +4606,8 @@ void ieee80211_unregister_hw(struct net_
 		flush_scheduled_work();
 		/* The scan_work is guaranteed not to be called at this
 		 * point. It is not scheduled and not running now. It can be
-		 * scheduled again only by some sta_timer (all of them are
-		 * stopped by now) or under rtnl lock. */
+		 * scheduled again only by sta_work (stopped by now) or under
+		 * rtnl lock. */
 	}
 
 	ieee80211_rx_bss_list_deinit(dev);
net/d80211/ieee80211_i.h +2 -2
index 89666ec..5b48ce2 100644
@@ -240,7 +240,7 @@ struct ieee80211_if_sta {
 		IEEE80211_ASSOCIATE, IEEE80211_ASSOCIATED,
 		IEEE80211_IBSS_SEARCH, IEEE80211_IBSS_JOINED
 	} state;
-	struct timer_list timer;
+	struct work_struct work;
 	u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
 	u8 ssid[IEEE80211_MAX_SSID_LEN];
 	size_t ssid_len;
@@ -621,7 +621,7 @@ int ieee80211_set_compression(struct iee
 			      struct net_device *dev, struct sta_info *sta);
 int ieee80211_init_client(struct net_device *dev);
 /* ieee80211_sta.c */
-void ieee80211_sta_timer(unsigned long ptr);
+void ieee80211_sta_work(void *ptr);
 void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb,
 			   struct ieee80211_rx_status *rx_status);
 int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len);
net/d80211/ieee80211_iface.c +1 -3
index 9a187af..4dd480f 100644
@@ -194,9 +194,7 @@ void ieee80211_if_set_type(struct net_de
 		struct ieee80211_if_sta *ifsta;
 
 		ifsta = &sdata->u.sta;
-		init_timer(&ifsta->timer);
-		ifsta->timer.data = (unsigned long) dev;
-		ifsta->timer.function = ieee80211_sta_timer;
+		INIT_WORK(&ifsta->work, ieee80211_sta_work, dev);
 
 		ifsta->capab = WLAN_CAPABILITY_ESS;
 		ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN |
net/d80211/ieee80211_sta.c +19 -20
index cc336bd..bf74b6b 100644
@@ -457,7 +457,7 @@ static void ieee80211_authenticate(struc
 
 	ieee80211_send_auth(dev, ifsta, 1, NULL, 0, 0);
 
-	mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT);
+	schedule_delayed_work(&ifsta->work, IEEE80211_AUTH_TIMEOUT);
 }
 
 
@@ -677,7 +677,7 @@ static void ieee80211_associate(struct n
 
 	ieee80211_send_assoc(dev, ifsta);
 
-	mod_timer(&ifsta->timer, jiffies + IEEE80211_ASSOC_TIMEOUT);
+	schedule_delayed_work(&ifsta->work, IEEE80211_ASSOC_TIMEOUT);
 }
 
 
@@ -735,11 +735,11 @@ static void ieee80211_associated(struct 
 		memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
 		wrqu.ap_addr.sa_family = ARPHRD_ETHER;
 		wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
-		mod_timer(&ifsta->timer,
-			  jiffies + IEEE80211_MONITORING_INTERVAL + 30 * HZ);
+		schedule_delayed_work(&ifsta->work,
+				      IEEE80211_MONITORING_INTERVAL + 30 * HZ);
 	} else {
-		mod_timer(&ifsta->timer,
-			  jiffies + IEEE80211_MONITORING_INTERVAL);
+		schedule_delayed_work(&ifsta->work,
+				      IEEE80211_MONITORING_INTERVAL);
 	}
 }
 
@@ -1019,8 +1019,8 @@ static void ieee80211_rx_mgmt_deauth(str
 	    ifsta->state == IEEE80211_ASSOCIATE ||
 	    ifsta->state == IEEE80211_ASSOCIATED) {
 		ifsta->state = IEEE80211_AUTHENTICATE;
-		mod_timer(&ifsta->timer,
-			  jiffies + IEEE80211_RETRY_AUTH_INTERVAL);
+		schedule_delayed_work(&ifsta->work,
+				      IEEE80211_RETRY_AUTH_INTERVAL);
 	}
 
 	ieee80211_set_associated(dev, ifsta, 0);
@@ -1062,8 +1062,8 @@ static void ieee80211_rx_mgmt_disassoc(s
 
 	if (ifsta->state == IEEE80211_ASSOCIATED) {
 		ifsta->state = IEEE80211_ASSOCIATE;
-		mod_timer(&ifsta->timer,
-			  jiffies + IEEE80211_RETRY_AUTH_INTERVAL);
+		schedule_delayed_work(&ifsta->work,
+				      IEEE80211_RETRY_AUTH_INTERVAL);
 	}
 
 	ieee80211_set_associated(dev, ifsta, 0);
@@ -1829,7 +1829,7 @@ static void ieee80211_sta_expire(struct 
 static void ieee80211_sta_merge_ibss(struct net_device *dev,
 				     struct ieee80211_if_sta *ifsta)
 {
-	mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
+	schedule_delayed_work(&ifsta->work, IEEE80211_IBSS_MERGE_INTERVAL);
 
 	ieee80211_sta_expire(dev);
 	if (ieee80211_sta_active_ibss(dev))
@@ -1841,20 +1841,19 @@ static void ieee80211_sta_merge_ibss(str
 }
 
 
-void ieee80211_sta_timer(unsigned long ptr)
+void ieee80211_sta_work(void *ptr)
 {
-	struct net_device *dev;
+	struct net_device *dev = ptr;
 	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_if_sta *ifsta;
 
-	dev = (struct net_device *) ptr;
 	if (!netif_running(dev))
 		return;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	if (sdata->type != IEEE80211_IF_TYPE_STA &&
 	    sdata->type != IEEE80211_IF_TYPE_IBSS) {
-		printk(KERN_DEBUG "%s: ieee80211_sta_timer: non-STA interface "
+		printk(KERN_DEBUG "%s: ieee80211_sta_work: non-STA interface "
 		       "(type=%d)\n", dev->name, sdata->type);
 		return;
 	}
@@ -1879,7 +1878,7 @@ void ieee80211_sta_timer(unsigned long p
 		ieee80211_sta_merge_ibss(dev, ifsta);
 		break;
 	default:
-		printk(KERN_DEBUG "ieee80211_sta_timer: Unknown state %d\n",
+		printk(KERN_DEBUG "ieee80211_sta_work: Unknown state %d\n",
 		       ifsta->state);
 		break;
 	}
@@ -2107,7 +2106,7 @@ static int ieee80211_sta_join_ibss(struc
 	}
 
 	ifsta->state = IEEE80211_IBSS_JOINED;
-	mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
+	schedule_delayed_work(&ifsta->work, IEEE80211_IBSS_MERGE_INTERVAL);
 
 	ieee80211_rx_bss_put(dev, bss);
 
@@ -2224,8 +2223,8 @@ #endif /* CONFIG_D80211_IBSS_DEBUG */
 	/* Selected IBSS not found in current scan results - try to scan */
 	if (ifsta->state == IEEE80211_IBSS_JOINED &&
 	    !ieee80211_sta_active_ibss(dev)) {
-		mod_timer(&ifsta->timer,
-			  jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
+		schedule_delayed_work(&ifsta->work,
+				      IEEE80211_IBSS_MERGE_INTERVAL);
 	} else if (time_after(jiffies, local->last_scan_completed +
 			      IEEE80211_SCAN_INTERVAL)) {
 		printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to "
@@ -2253,7 +2252,7 @@ #endif /* CONFIG_D80211_IBSS_DEBUG */
 		}
 
 		ifsta->state = IEEE80211_IBSS_SEARCH;
-		mod_timer(&ifsta->timer, jiffies + interval);
+		schedule_delayed_work(&ifsta->work, interval);
 		return 0;
 	}
 
Applied
#4 lore raw
In reply to Ivo van Doorn
Quoted 3 lines · Ivo van Doorn

Would something like the patch below be better?
It keeps the flush_scheduled_work() at the same location, but a second is added in case local->scan_work.data != sdata->dev

Applied to my tree, thanks for the patch!

Jiri

Signature · 2 lines
Jiri Benc
SUSE Labs