From patchwork Mon Sep 26 19:13:49 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Stultz X-Patchwork-Id: 4350 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 63F3623FBA for ; Mon, 26 Sep 2011 19:14:08 +0000 (UTC) Received: from mail-fx0-f52.google.com (mail-fx0-f52.google.com [209.85.161.52]) by fiordland.canonical.com (Postfix) with ESMTP id 52B8BA18ABC for ; Mon, 26 Sep 2011 19:14:08 +0000 (UTC) Received: by mail-fx0-f52.google.com with SMTP id 23so8797872fxe.11 for ; Mon, 26 Sep 2011 12:14:08 -0700 (PDT) Received: by 10.223.57.17 with SMTP id a17mr6101707fah.65.1317064448160; Mon, 26 Sep 2011 12:14:08 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.152.3.234 with SMTP id f10cs48597laf; Mon, 26 Sep 2011 12:14:08 -0700 (PDT) Received: by 10.101.203.1 with SMTP id f1mr6219198anq.142.1317064446426; Mon, 26 Sep 2011 12:14:06 -0700 (PDT) Received: from e4.ny.us.ibm.com (e4.ny.us.ibm.com. [32.97.182.144]) by mx.google.com with ESMTPS id o20si5919610anb.166.2011.09.26.12.14.05 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 26 Sep 2011 12:14:06 -0700 (PDT) Received-SPF: pass (google.com: domain of jstultz@us.ibm.com designates 32.97.182.144 as permitted sender) client-ip=32.97.182.144; Authentication-Results: mx.google.com; spf=pass (google.com: domain of jstultz@us.ibm.com designates 32.97.182.144 as permitted sender) smtp.mail=jstultz@us.ibm.com Received: from d01relay04.pok.ibm.com (d01relay04.pok.ibm.com [9.56.227.236]) by e4.ny.us.ibm.com (8.14.4/8.13.1) with ESMTP id p8QIo6ke015558; Mon, 26 Sep 2011 14:50:06 -0400 Received: from d03av02.boulder.ibm.com (d03av02.boulder.ibm.com [9.17.195.168]) by d01relay04.pok.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id p8QJE40e259616; Mon, 26 Sep 2011 15:14:04 -0400 Received: from d03av02.boulder.ibm.com (loopback [127.0.0.1]) by d03av02.boulder.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id p8QJE393011966; Mon, 26 Sep 2011 13:14:04 -0600 Received: from kernel.beaverton.ibm.com ([9.47.67.96]) by d03av02.boulder.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id p8QJE3Hb011922; Mon, 26 Sep 2011 13:14:03 -0600 Received: by kernel.beaverton.ibm.com (Postfix, from userid 1056) id CAAA21E750E; Mon, 26 Sep 2011 12:14:02 -0700 (PDT) From: John Stultz To: lkml Cc: John Stultz , "Rafael J. Wysocki" , arve@android.com, markgross@thegnar.org, Alan Stern , amit.kucheria@linaro.org, farrowg@sg.ibm.com, "Dmitry Fink (Palm GBU)" , linux-pm@lists.linux-foundation.org, khilman@ti.com, Magnus Damm , mjg@redhat.com, peterz@infradead.org Subject: [PATCH 1/6] [RFC] suspend: Block suspend when wakeups are in-progress Date: Mon, 26 Sep 2011 12:13:49 -0700 Message-Id: <1317064434-1829-2-git-send-email-john.stultz@linaro.org> X-Mailer: git-send-email 1.7.3.2.146.gca209 In-Reply-To: <1317064434-1829-1-git-send-email-john.stultz@linaro.org> References: <1317064434-1829-1-git-send-email-john.stultz@linaro.org> With the current pm_stay_awake/pm_relax api, reads to /sys/power/wakeup_count will block when pm_stay_awake() has been called. Then once pm_relax() returns, the read will unblock and return the wakeup_count value. This value can be echo'ed back into wakeup_count, and if no other wakeup events have occured, the system can be suspended by calling "echo mem > /sys/power/state". This method is somewhat advisory, as if a wakeup event has occured between the reading of /sys/power/wakeup_count and the attempt to suspend, that attempt to suspend will fail. However, if a second attmept to suspend is tried, without checking /sys/power/wakeup_count, the suspend will succeed. Similarly, if pm_stay_awake() has been called, and then a suspend is attepted wihtout checking /sys/power/wakeup_count, the suspend will succeed, despite the pm_relax() call not having been made. This patch tries to make the pm_stay_awake() call a bit more enforcing, such that any attempt to suspend that occurs while a wakeup is in progress will fail. Once the matching pm_relax() has been called, suspend will succeed. This does not change the blocking behavior of /sys/power/wakeup_count, or the suspend failure if a stale wakeup count has been echo'ed into the /sys/power/wakeup_count. Also modified the hibernate path in the same way. CC: Rafael J. Wysocki CC: arve@android.com CC: markgross@thegnar.org CC: Alan Stern CC: amit.kucheria@linaro.org CC: farrowg@sg.ibm.com CC: Dmitry Fink (Palm GBU) CC: linux-pm@lists.linux-foundation.org CC: khilman@ti.com CC: Magnus Damm CC: mjg@redhat.com CC: peterz@infradead.org Signed-off-by: John Stultz --- drivers/base/power/wakeup.c | 13 +++++++++++++ include/linux/suspend.h | 3 +++ kernel/power/hibernate.c | 5 +++++ kernel/power/suspend.c | 5 +++++ 4 files changed, 26 insertions(+), 0 deletions(-) diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 84f7c7d..0722873 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -580,6 +580,19 @@ static void pm_wakeup_update_hit_counts(void) rcu_read_unlock(); } + +bool pm_wakeup_in_progress(void) +{ + unsigned int cnt, inpr; + unsigned long flags; + + spin_lock_irqsave(&events_lock, flags); + split_counters(&cnt, &inpr); + spin_unlock_irqrestore(&events_lock, flags); + + return (inpr != 0); +} + /** * pm_wakeup_pending - Check if power transition in progress should be aborted. * diff --git a/include/linux/suspend.h b/include/linux/suspend.h index 6bbcef2..c9403a1 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -294,6 +294,7 @@ extern int unregister_pm_notifier(struct notifier_block *nb); extern bool events_check_enabled; extern bool pm_wakeup_pending(void); +extern bool pm_wakeup_in_progress(void); extern bool pm_get_wakeup_count(unsigned int *count); extern bool pm_save_wakeup_count(unsigned int count); #else /* !CONFIG_PM_SLEEP */ @@ -311,6 +312,8 @@ static inline int unregister_pm_notifier(struct notifier_block *nb) #define pm_notifier(fn, pri) do { (void)(fn); } while (0) static inline bool pm_wakeup_pending(void) { return false; } +static inline bool pm_wakeup_in_progress(void) { return false; } + #endif /* !CONFIG_PM_SLEEP */ extern struct mutex pm_mutex; diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index 8f7b1db..22dc22c 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -611,6 +611,11 @@ int hibernate(void) goto Unlock; } + if (pm_wakeup_in_progress()) { + error = -EBUSY; + goto Unlock; + } + pm_prepare_console(); error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE); if (error) diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index b6b71ad..b2dba52 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -281,6 +281,11 @@ int enter_state(suspend_state_t state) if (!mutex_trylock(&pm_mutex)) return -EBUSY; + if (pm_wakeup_in_progress()) { + error = -EBUSY; + goto Unlock; + } + printk(KERN_INFO "PM: Syncing filesystems ... "); sys_sync(); printk("done.\n");