[50/50] bcm43xx: Fix cancellation of work queue crashes

!MAILaRCHIVE_VOTE_RePLACE
Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]
To: <linux-kernel@...>, <stable@...>
Cc: Justin Forbes <jmforbes@...>, Zwane Mwaikambo <zwane@...>, Theodore Ts'o <tytso@...>, Randy Dunlap <rdunlap@...>, Dave Jones <davej@...>, Chuck Wolber <chuckw@...>, Chris Wedgwood <reviews@...>, Michael Krufky <mkrufky@...>, Chuck Ebbert <cebbert@...>, Domenico Andreoli <cavokz@...>, <torvalds@...>, <akpm@...>, <alan@...>, Larry Finger <Larry.Finger@...>, Michael Buesch <mb@...>, John W. Linville <linville@...>
Date: Monday, September 24, 2007 - 12:22 pm

From: Larry Finger <Larry.Finger@lwfinger.net>

port of 3f7086978fc0193eff24a77d8b57ac4debc088fa from mainline.

A crash upon booting that is caused by bcm43xx has been reported [1] and
found to be due to a work queue being reinitialized while work on that
queue is still pending. This fix modifies the shutdown of work queues and
prevents periodic work from being requeued during shutdown. With this patch,
no more crashes on reboot were observed by the original reporter. I do not
get that particular failure on my system; however, when running a large
number of ifdown/ifup sequences, my system would kernel panic with the
'caps lock' light blinking at roughly a 1 Hz rate. In addition, there were
infrequent failures in the firmware that resulted in 'IRQ READY TIMEOUT'
errors. With this patch, no more of the first type of failure occur, and
incidence of the second type is greatly reduced.

[1] http://bugzilla.kernel.org/show_bug.cgi?id=8937

Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Acked-by: Michael Buesch <mb@bu3sch.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

---
 drivers/net/wireless/bcm43xx/bcm43xx_main.c  |   28 +++++++++++++++++++--------
 drivers/net/wireless/bcm43xx/bcm43xx_main.h  |    2 -
 drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c |    2 -
 3 files changed, 22 insertions(+), 10 deletions(-)

--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -3183,6 +3183,9 @@ static void bcm43xx_periodic_work_handle
 	unsigned long orig_trans_start = 0;
 
 	mutex_lock(&bcm->mutex);
+	/* keep from doing and rearming periodic work if shutting down */
+	if (bcm43xx_status(bcm) == BCM43xx_STAT_UNINIT)
+		goto unlock_mutex;
 	if (unlikely(bcm->periodic_state % 60 == 0)) {
 		/* Periodic work will take a long time, so we want it to
 		 * be preemtible.
@@ -3228,14 +3231,10 @@ static void bcm43xx_periodic_work_handle
 	mmiowb();
 	bcm->periodic_state++;
 	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+unlock_mutex:
 	mutex_unlock(&bcm->mutex);
 }
 
-void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
-{
-	cancel_rearming_delayed_work(&bcm->periodic_work);
-}
-
 void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm)
 {
 	struct delayed_work *work = &bcm->periodic_work;
@@ -3285,6 +3284,14 @@ static int bcm43xx_rng_init(struct bcm43
 	return err;
 }
 
+void bcm43xx_cancel_work(struct bcm43xx_private *bcm)
+{
+	/* The system must be unlocked when this routine is entered.
+	 * If not, the next 2 steps may deadlock */
+	cancel_work_sync(&bcm->restart_work);
+	cancel_rearming_delayed_work(&bcm->periodic_work);
+}
+
 static int bcm43xx_shutdown_all_wireless_cores(struct bcm43xx_private *bcm)
 {
 	int ret = 0;
@@ -3321,7 +3328,12 @@ static void bcm43xx_free_board(struct bc
 {
 	bcm43xx_rng_exit(bcm);
 	bcm43xx_sysfs_unregister(bcm);
-	bcm43xx_periodic_tasks_delete(bcm);
+
+	mutex_lock(&(bcm)->mutex);
+	bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
+	mutex_unlock(&(bcm)->mutex);
+
+	bcm43xx_cancel_work(bcm);
 
 	mutex_lock(&(bcm)->mutex);
 	bcm43xx_shutdown_all_wireless_cores(bcm);
@@ -4018,7 +4030,7 @@ static int bcm43xx_net_stop(struct net_d
 	err = bcm43xx_disable_interrupts_sync(bcm);
 	assert(!err);
 	bcm43xx_free_board(bcm);
-	flush_scheduled_work();
+	bcm43xx_cancel_work(bcm);
 
 	return 0;
 }
@@ -4150,9 +4162,9 @@ static void bcm43xx_chip_reset(struct wo
 	struct bcm43xx_phyinfo *phy;
 	int err = -ENODEV;
 
+	bcm43xx_cancel_work(bcm);
 	mutex_lock(&(bcm)->mutex);
 	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
-		bcm43xx_periodic_tasks_delete(bcm);
 		phy = bcm43xx_current_phy(bcm);
 		err = bcm43xx_select_wireless_core(bcm, phy->type);
 		if (!err)
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
@@ -122,7 +122,7 @@ void bcm43xx_wireless_core_reset(struct 
 void bcm43xx_mac_suspend(struct bcm43xx_private *bcm);
 void bcm43xx_mac_enable(struct bcm43xx_private *bcm);
 
-void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm);
+void bcm43xx_cancel_work(struct bcm43xx_private *bcm);
 void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm);
 
 void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason);
--- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
@@ -327,7 +327,7 @@ static ssize_t bcm43xx_attr_phymode_stor
 		goto out;
 	}
 
-	bcm43xx_periodic_tasks_delete(bcm);
+	bcm43xx_cancel_work(bcm);
 	mutex_lock(&(bcm)->mutex);
 	err = bcm43xx_select_wireless_core(bcm, phytype);
 	if (!err)

-- 
-
Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]

Messages in current thread:
[00/50] 2.6.22-stable review, Greg KH, (Mon Sep 24, 12:17 pm)
Re: [00/50] 2.6.22-stable review, Greg KH, (Mon Sep 24, 12:31 pm)
Re: [00/50] 2.6.22-stable review, Chris Wedgwood, (Mon Sep 24, 12:44 pm)
Re: [00/50] 2.6.22-stable review, Greg KH, (Mon Sep 24, 1:13 pm)
Re: [00/50] 2.6.22-stable review, Chris Wedgwood, (Mon Sep 24, 12:46 pm)
Re: [00/50] 2.6.22-stable review, Greg KH, (Mon Sep 24, 1:14 pm)
[50/50] bcm43xx: Fix cancellation of work queue crashes, Greg KH, (Mon Sep 24, 12:22 pm)
[49/50] Fix sparc64 v100 platform booting., Greg KH, (Mon Sep 24, 12:22 pm)
[48/50] Fix pktgen src_mac handling., Greg KH, (Mon Sep 24, 12:22 pm)
[46/50] Fix TCP DSACK cwnd handling, Greg KH, (Mon Sep 24, 12:22 pm)
[45/50] Handle snd_una in tcp_cwnd_down(), Greg KH, (Mon Sep 24, 12:22 pm)
[44/50] Fix tc_ematch kbuild, Greg KH, (Mon Sep 24, 12:22 pm)
[43/50] Fix oops in vlan and bridging code, Greg KH, (Mon Sep 24, 12:22 pm)
[42/50] Fix ipv6 source address handling., Greg KH, (Mon Sep 24, 12:22 pm)
[41/50] : Fix IPV6 DAD handling, Greg KH, (Mon Sep 24, 12:22 pm)
[38/50] Fix IPV6 append OOPS., Greg KH, (Mon Sep 24, 12:22 pm)
[39/50] Fix IPSEC AH4 options handling, Greg KH, (Mon Sep 24, 12:22 pm)
[37/50] Fix inet_diag OOPS., Greg KH, (Mon Sep 24, 12:22 pm)
Re: [37/50] Fix inet_diag OOPS., Dan Merillat, (Mon Sep 24, 6:03 pm)
Re: [37/50] Fix inet_diag OOPS., Patrick McHardy, (Tue Sep 25, 12:03 am)
[36/50] Fix device address listing for ipv4., Greg KH, (Mon Sep 24, 12:22 pm)
[35/50] Fix decnet device address listing., Greg KH, (Mon Sep 24, 12:21 pm)
[34/50] fix realtek phy id in forcedeth, Greg KH, (Mon Sep 24, 12:21 pm)
[31/50] Correctly close old nfsd/lockd sockets., Greg KH, (Mon Sep 24, 12:21 pm)
[32/50] Fix race with shared tag queue maps, Greg KH, (Mon Sep 24, 12:21 pm)
[28/50] nfs: fix oops re sysctls and V4 support, Greg KH, (Mon Sep 24, 12:21 pm)
[25/50] futex_compat: fix list traversal bugs, Greg KH, (Mon Sep 24, 12:21 pm)
[26/50] Leases can be hidden by flocks, Greg KH, (Mon Sep 24, 12:21 pm)
[21/50] afs: mntput called before dput, Greg KH, (Mon Sep 24, 12:21 pm)
[20/50] disable sys_timerfd(), Greg KH, (Mon Sep 24, 12:21 pm)
[18/50] splice: fix direct splice error handling, Greg KH, (Mon Sep 24, 12:20 pm)
[17/50] Fix debug regression in video/pwc, Greg KH, (Mon Sep 24, 12:20 pm)
[16/50] hwmon: End of I/O region off-by-one, Greg KH, (Mon Sep 24, 12:20 pm)
[14/50] JFFS2: fix write deadlock regression, Greg KH, (Mon Sep 24, 12:20 pm)
[12/50] 3w-9xxx: Fix dma mask setting, Greg KH, (Mon Sep 24, 12:20 pm)
[08/50] MTD: Makefile fix for mtdsuper, Greg KH, (Mon Sep 24, 12:20 pm)