Re: [Bug 10030] Suspend doesn't work when SD card is inserted

!MAILaRCHIVE_VOTE_RePLACE
Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]
To: Rafael J. Wysocki <rjw@...>
Cc: Pierre Ossman <drzeus-mmc@...>, Zdenek Kabelac <zdenek.kabelac@...>, Kernel development list <linux-kernel@...>
Date: Saturday, February 23, 2008 - 7:29 pm

On Sat, 23 Feb 2008, Rafael J. Wysocki wrote:


In the interest of having a safe release, I guess you're right.  It's 
unfortunate, though -- there's no good way to get thorough testing 
without putting the code in Linus's tree.


Below is my suggested approach, based on yours.  It might even solve
the MMC problem, who knows?  And it adds some potentially useful
debugging, although it would be better to dump just the stack of
suspending_task.  Do you know how to do that from within a timer
routine?

I still have no clear idea about what's going on with the ACPI bug in 
#9874.  However perhaps the bug wouldn't occur if we blocked device 
registration until after the resume was finished, instead of failing it 
outright.  Since the registration in this case was done in a workqueue 
thread, blocking wouldn't cause an immediate deadlock.

Alan Stern



Index: usb-2.6/drivers/base/power/main.c
===================================================================
--- usb-2.6.orig/drivers/base/power/main.c
+++ usb-2.6/drivers/base/power/main.c
@@ -25,6 +25,7 @@
 #include <linux/pm.h>
 #include <linux/resume-trace.h>
 #include <linux/rwsem.h>
+#include <linux/sched.h>
 
 #include "../base.h"
 #include "power.h"
@@ -59,6 +60,13 @@ static DECLARE_RWSEM(pm_sleep_rwsem);
 
 int (*platform_enable_wakeup)(struct device *dev, int is_on);
 
+static struct task_struct *suspending_task;
+
+bool in_suspend_context(void)
+{
+	return (suspending_task == current);
+}
+
 /**
  *	device_pm_add - add a device to the list of active devices
  *	@dev:	Device to be added to the list
@@ -94,14 +102,15 @@ void device_pm_remove(struct device *dev
 			/* No suspend in progress, wait on dev->sem */
 			down(&dev->sem);
 			up_read(&pm_sleep_rwsem);
-		} else {
-			/* Suspend in progress, we may deadlock */
+		} else if (!in_suspend_context()) {
+			/* Suspending in another task, we may deadlock */
 			dev_warn(dev, "Suspicious %s during suspend\n",
 				__FUNCTION__);
 			dump_stack();
 			/* The user has been warned ... */
 			down(&dev->sem);
 		}
+			/* Otherwise we're okay */
 	}
 	pr_debug("PM: Removing info for %s:%s\n",
 		 dev->bus ? dev->bus->name : "No Bus",
@@ -272,6 +281,7 @@ static void dpm_resume(void)
 		mutex_lock(&dpm_list_mtx);
 	}
 	mutex_unlock(&dpm_list_mtx);
+	suspending_task = NULL;
 }
 
 /**
@@ -410,6 +420,17 @@ int device_power_down(pm_message_t state
 }
 EXPORT_SYMBOL_GPL(device_power_down);
 
+/* Provide debugging info if we hang or deadlock during suspend */
+static struct timer_list suspend_timer;
+
+static void suspend_timeout(unsigned long _dev)
+{
+	struct device *dev = (struct device *) _dev;
+
+	dev_err(dev, "deadlock during suspend!\n");
+	show_state();
+}
+
 /**
  *	suspend_device - Save state of one device.
  *	@dev:	Device.
@@ -419,6 +440,10 @@ int suspend_device(struct device *dev, p
 {
 	int error = 0;
 
+	/* Provide debugging output in case of a deadlock */
+	setup_timer(&suspend_timer, suspend_timeout, (unsigned long) dev);
+	mod_timer(&suspend_timer, jiffies + 5*HZ);
+
 	if (dev->power.power_state.event) {
 		dev_dbg(dev, "PM: suspend %d-->%d\n",
 			dev->power.power_state.event, state.event);
@@ -441,6 +466,8 @@ int suspend_device(struct device *dev, p
 		error = dev->bus->suspend(dev, state);
 		suspend_report_result(dev->bus->suspend, error);
 	}
+
+	del_timer_sync(&suspend_timer);
 	return error;
 }
 
@@ -460,6 +487,7 @@ static int dpm_suspend(pm_message_t stat
 {
 	int error = 0;
 
+	suspending_task = current;
 	mutex_lock(&dpm_list_mtx);
 	while (!list_empty(&dpm_locked)) {
 		struct list_head *entry = dpm_locked.prev;
Index: usb-2.6/drivers/base/power/power.h
===================================================================
--- usb-2.6.orig/drivers/base/power/power.h
+++ usb-2.6/drivers/base/power/power.h
@@ -11,6 +11,7 @@ static inline struct device *to_device(s
 	return container_of(entry, struct device, power.entry);
 }
 
+extern bool in_suspend_context(void);
 extern void device_pm_add(struct device *);
 extern void device_pm_remove(struct device *);
 extern int pm_sleep_lock(void);
@@ -18,6 +19,10 @@ extern void pm_sleep_unlock(void);
 
 #else /* CONFIG_PM_SLEEP */
 
+static inline bool in_suspend_context(void)
+{
+	return false;
+}
 
 static inline void device_pm_add(struct device *dev)
 {
Index: usb-2.6/drivers/base/dd.c
===================================================================
--- usb-2.6.orig/drivers/base/dd.c
+++ usb-2.6/drivers/base/dd.c
@@ -325,10 +325,18 @@ void device_release_driver(struct device
 	 * If anyone calls device_release_driver() recursively from
 	 * within their ->remove callback for the same device, they
 	 * will deadlock right here.
+	 *
+	 * We avoid locking dev->sem if we are in the context of a
+	 * task doing a system suspend, in order that drivers can
+	 * unregister devices from within their suspend() methods.
+	 * This is okay because the suspending task will already own
+	 * all the device semaphores.
 	 */
-	down(&dev->sem);
+	if (!in_suspend_context())
+		down(&dev->sem);
 	__device_release_driver(dev);
-	up(&dev->sem);
+	if (!in_suspend_context())
+		up(&dev->sem);
 }
 EXPORT_SYMBOL_GPL(device_release_driver);
 

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

Messages in current thread:
Re: [Bug 10030] Suspend doesn't work when SD card is inserted, Rafael J. Wysocki, (Wed Feb 20, 6:15 pm)
Re: [Bug 10030] Suspend doesn't work when SD card is inserted, Rafael J. Wysocki, (Wed Feb 20, 8:02 pm)
Re: [Bug 10030] Suspend doesn't work when SD card is inserted, Rafael J. Wysocki, (Thu Feb 21, 12:38 pm)
Re: [Bug 10030] Suspend doesn't work when SD card is inserted, Rafael J. Wysocki, (Thu Feb 21, 6:47 pm)
Re: [Bug 10030] Suspend doesn't work when SD card is inserted, Rafael J. Wysocki, (Fri Feb 22, 9:30 pm)
Re: [Bug 10030] Suspend doesn't work when SD card is inserted, Rafael J. Wysocki, (Sat Feb 23, 4:16 pm)
Re: [Bug 10030] Suspend doesn't work when SD card is inserted, Alan Stern, (Sat Feb 23, 7:29 pm)
Re: [Bug 10030] Suspend doesn't work when SD card is inserted, Rafael J. Wysocki, (Sat Feb 23, 8:19 pm)
Re: [linux-pm] [Bug 10030] Suspend doesn't work when SD card..., Rafael J. Wysocki, (Sun Feb 24, 10:00 am)
Re: [Bug 10030] Suspend doesn't work when SD card is inserted, Rafael J. Wysocki, (Mon Feb 25, 7:40 am)
Re: [Bug 10030] Suspend doesn't work when SD card is inserted, Rafael J. Wysocki, (Sun Feb 24, 6:21 pm)
Re: [Bug 10030] Suspend doesn't work when SD card is inserted, Rafael J. Wysocki, (Mon Feb 25, 7:41 am)
Re: [Bug 10030] Suspend doesn't work when SD card is inserted, Rafael J. Wysocki, (Sun Feb 24, 9:51 am)
Re: [Bug 10030] Suspend doesn't work when SD card is inserted, Rafael J. Wysocki, (Sun Feb 24, 4:09 pm)
Re: [Bug 10030] Suspend doesn't work when SD card is inserted, Rafael J. Wysocki, (Sun Feb 24, 9:33 am)
Re: [Bug 10030] Suspend doesn't work when SD card is inserted, Rafael J. Wysocki, (Sun Feb 24, 4:25 pm)
Re: [Bug 10030] Suspend doesn't work when SD card is inserted, Rafael J. Wysocki, (Sun Feb 24, 4:56 pm)
Re: [Bug 10030] Suspend doesn't work when SD card is inserted, Rafael J. Wysocki, (Sun Feb 24, 6:18 pm)
Re: [Bug 10030] Suspend doesn't work when SD card is inserted, Rafael J. Wysocki, (Wed Feb 20, 6:41 pm)
Re: [Bug 10030] Suspend doesn't work when SD card is inserted, Rafael J. Wysocki, (Wed Feb 20, 4:58 pm)