All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC][PATCH 0/8] Suspend block api
@ 2009-04-15  1:41 Arve Hjønnevåg
  2009-04-15  1:41 ` [PATCH 1/8] PM: Add suspend " Arve Hjønnevåg
  2009-04-15 23:04 ` [RFC][PATCH 0/8] Suspend " Rafael J. Wysocki
  0 siblings, 2 replies; 93+ messages in thread
From: Arve Hjønnevåg @ 2009-04-15  1:41 UTC (permalink / raw)
  To: linux-pm; +Cc: ncunningham, u.luckas, swetland, r-woodruff2, 

This patch series adds a suspend-block api that provides the same
functionality as the android wakelock api from my last patch series,
Android PM extensions (version 3). As requested, wake_lock has been
renamed to suspend_block(er), and timeout support has been separated
into its own patch.

--
Arve Hjønnevåg

_______________________________________________
linux-pm mailing list
linux-pm@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/linux-pm

^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 1/8] PM: Add suspend block api.
  2009-04-15  1:41 [RFC][PATCH 0/8] Suspend block api Arve Hjønnevåg
@ 2009-04-15  1:41 ` Arve Hjønnevåg
  2009-04-15  1:41   ` [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space Arve Hjønnevåg
                     ` (4 more replies)
  2009-04-15 23:04 ` [RFC][PATCH 0/8] Suspend " Rafael J. Wysocki
  1 sibling, 5 replies; 93+ messages in thread
From: Arve Hjønnevåg @ 2009-04-15  1:41 UTC (permalink / raw)
  To: linux-pm; +Cc: ncunningham, u.luckas, swetland, r-woodruff2, 

Adds /sys/power/request_state, a non-blocking interface that specifies
which suspend state to enter when no suspend blockers are active. A
special state, "on", stops the process by activating the "main" suspend
blocker.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
 Documentation/power/suspend-blockers.txt |   76 +++++++++
 include/linux/suspend_block.h            |   61 +++++++
 kernel/power/Kconfig                     |   10 ++
 kernel/power/Makefile                    |    1 +
 kernel/power/main.c                      |   62 +++++++
 kernel/power/power.h                     |    6 +
 kernel/power/suspend_block.c             |  257 ++++++++++++++++++++++++++++++
 7 files changed, 473 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/power/suspend-blockers.txt
 create mode 100755 include/linux/suspend_block.h
 create mode 100644 kernel/power/suspend_block.c

diff --git a/Documentation/power/suspend-blockers.txt b/Documentation/power/suspend-blockers.txt
new file mode 100644
index 0000000..743b870
--- /dev/null
+++ b/Documentation/power/suspend-blockers.txt
@@ -0,0 +1,76 @@
+Suspend blockers
+================
+
+A suspend_blocker prevents the system from entering suspend.
+
+If the suspend operation has already started when calling suspend_block on a
+suspend_blocker, it will abort the suspend operation as long it has not already
+reached the sysdev suspend stage. This means that calling suspend_block from an
+interrupt handler or a freezeable thread always works, but if you call
+block_suspend from a sysdev suspend handler you must also return an error from
+that handler to abort suspend.
+
+Suspend blockers can be used to allow user-space to decide which keys should
+wake the full system up and turn the screen on. Use set_irq_wake or a platform
+specific api to make sure the keypad interrupt wakes up the cpu. Once the keypad
+driver has resumed, the sequence of events can look like this:
+- The Keypad driver gets an interrupt. It then calls suspend_block on the
+  keypad-scan suspend_blocker and starts scanning the keypad matrix.
+- The keypad-scan code detects a key change and reports it to the input-event
+  driver.
+- The input-event driver sees the key change, enqueues an event, and calls
+  suspend_block on the input-event-queue suspend_blocker.
+- The keypad-scan code detects that no keys are held and calls suspend_unblock
+  on the keypad-scan suspend_blocker.
+- The user-space input-event thread returns from select/poll, calls
+  suspend_block on the process-input-events suspend_blocker and then calls read
+  on the input-event device.
+- The input-event driver dequeues the key-event and, since the queue is now
+  empty, it calls suspend_unblock on the input-event-queue suspend_blocker.
+- The user-space input-event thread returns from read. It determines that the
+  key should not wake up the full system, calls suspend_unblock on the
+  process-input-events suspend_blocker and calls select or poll.
+
+                 Key pressed   Key released
+                     |             |
+keypad-scan          ++++++++++++++++++
+input-event-queue        +++          +++
+process-input-events       +++          +++
+
+
+Driver API
+==========
+
+A driver can use the suspend block api by adding a suspend_blocker variable to
+its state and calling suspend_blocker_init. For instance:
+struct state {
+	struct suspend_blocker suspend_blocker;
+}
+
+init() {
+	suspend_blocker_init(&state->suspend_blocker, "suspend-blocker-name");
+}
+
+Before freeing the memory, suspend_blocker_destroy must be called:
+
+uninit() {
+	suspend_blocker_destroy(&state->suspend_blocker);
+}
+
+When the driver determines that it needs to run (usually in an interrupt
+handler) it calls suspend_block:
+	suspend_block(&state->suspend_blocker);
+
+When it no longer needs to run it calls suspend_unblock:
+	suspend_unblock(&state->suspend_blocker);
+
+Calling suspend_block when the suspend blocker is active or suspend_unblock when
+it is not active has no effect. This allows drivers to update their state and
+call suspend suspend_block or suspend_unblock based on the result.
+For instance:
+
+if (list_empty(&state->pending_work))
+	suspend_unblock(&state->suspend_blocker);
+else
+	suspend_block(&state->suspend_blocker);
+
diff --git a/include/linux/suspend_block.h b/include/linux/suspend_block.h
new file mode 100755
index 0000000..7820c60
--- /dev/null
+++ b/include/linux/suspend_block.h
@@ -0,0 +1,61 @@
+/* include/linux/suspend_block.h
+ *
+ * Copyright (C) 2007-2009 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _LINUX_SUSPEND_BLOCK_H
+#define _LINUX_SUSPEND_BLOCK_H
+
+/* A suspend_blocker prevents the system from entering suspend when active.
+ */
+
+struct suspend_blocker {
+#ifdef CONFIG_SUSPEND_BLOCK
+	atomic_t            flags;
+	const char         *name;
+#endif
+};
+
+#ifdef CONFIG_SUSPEND_BLOCK
+
+void suspend_blocker_init(struct suspend_blocker *blocker, const char *name);
+void suspend_blocker_destroy(struct suspend_blocker *blocker);
+void suspend_block(struct suspend_blocker *blocker);
+void suspend_unblock(struct suspend_blocker *blocker);
+
+/* is_blocking_suspend returns true if the suspend_blocker is currently active.
+ */
+bool is_blocking_suspend(struct suspend_blocker *blocker);
+
+/* suspend_is_blocked can be used by generic power management code to abort
+ * suspend.
+ *
+ * To preserve backward compatibility suspend_is_blocked returns 0 unless it
+ * is called during suspend initiated from the suspend_block code.
+ */
+bool suspend_is_blocked(void);
+
+#else
+
+static inline void suspend_blocker_init(struct suspend_blocker *blocker,
+					const char *name) {}
+static inline void suspend_blocker_destroy(struct suspend_blocker *blocker) {}
+static inline void suspend_block(struct suspend_blocker *blocker) {}
+static inline void suspend_unblock(struct suspend_blocker *blocker) {}
+static inline bool is_blocking_suspend(struct suspend_blocker *bl) { return 0; }
+static inline bool suspend_is_blocked(void) { return 0; }
+
+#endif
+
+#endif
+
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 23bd4da..9d1df13 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -116,6 +116,16 @@ config SUSPEND_FREEZER
 
 	  Turning OFF this setting is NOT recommended! If in doubt, say Y.
 
+config SUSPEND_BLOCK
+	bool "Suspend block"
+	depends on PM
+	select RTC_LIB
+	default n
+	---help---
+	  Enable suspend_block. When user space requests a sleep state through
+	  /sys/power/request_state, the requested sleep state will be entered
+	  when no suspend_blockers are active.
+
 config HIBERNATION
 	bool "Hibernation (aka 'suspend to disk')"
 	depends on PM && SWAP && ARCH_HIBERNATION_POSSIBLE
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index 720ea4f..29cdc9e 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -6,6 +6,7 @@ endif
 obj-$(CONFIG_PM)		+= main.o
 obj-$(CONFIG_PM_SLEEP)		+= console.o
 obj-$(CONFIG_FREEZER)		+= process.o
+obj-$(CONFIG_SUSPEND_BLOCK)	+= suspend_block.o
 obj-$(CONFIG_HIBERNATION)	+= swsusp.o disk.o snapshot.o swap.o user.o
 
 obj-$(CONFIG_MAGIC_SYSRQ)	+= poweroff.o
diff --git a/kernel/power/main.c b/kernel/power/main.c
index c9632f8..e4c6b20 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -22,6 +22,7 @@
 #include <linux/freezer.h>
 #include <linux/vmstat.h>
 #include <linux/syscalls.h>
+#include <linux/suspend_block.h>
 
 #include "power.h"
 
@@ -392,6 +393,9 @@ static void suspend_finish(void)
 
 
 static const char * const pm_states[PM_SUSPEND_MAX] = {
+#ifdef CONFIG_SUSPEND_BLOCK
+	[PM_SUSPEND_ON]		= "on",
+#endif
 	[PM_SUSPEND_STANDBY]	= "standby",
 	[PM_SUSPEND_MEM]	= "mem",
 };
@@ -540,6 +544,61 @@ static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
 
 power_attr(state);
 
+/**
+ *	request_state - control system power state.
+ *
+ *	This is similar to state, but it does not block until the system
+ *	resumes, and it will try to re-enter the state until another state is
+ *	requested. Suspend blockers are respected and the requested state will
+ *	only be entered when no suspend blockers are active.
+ *	Write "on" to cancel.
+ */
+
+#ifdef CONFIG_SUSPEND_BLOCK
+static ssize_t request_state_show(struct kobject *kobj,
+				  struct kobj_attribute *attr, char *buf)
+{
+	char *s = buf;
+	int i;
+
+	for (i = 0; i < PM_SUSPEND_MAX; i++) {
+		if (pm_states[i] && (i == PM_SUSPEND_ON || valid_state(i)))
+			s += sprintf(s, "%s ", pm_states[i]);
+	}
+	if (s != buf)
+		/* convert the last space to a newline */
+		*(s-1) = '\n';
+	return (s - buf);
+}
+
+static ssize_t request_state_store(struct kobject *kobj,
+				   struct kobj_attribute *attr,
+				   const char *buf, size_t n)
+{
+	suspend_state_t state = PM_SUSPEND_ON;
+	const char * const *s;
+	char *p;
+	int len;
+	int error = -EINVAL;
+
+	p = memchr(buf, '\n', n);
+	len = p ? p - buf : n;
+
+	for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {
+		if (*s && len == strlen(*s) && !strncmp(buf, *s, len))
+			break;
+	}
+	if (state < PM_SUSPEND_MAX && *s)
+		if (state == PM_SUSPEND_ON || valid_state(state)) {
+			error = 0;
+			request_suspend_state(state);
+		}
+	return error ? error : n;
+}
+
+power_attr(request_state);
+#endif /* CONFIG_SUSPEND_BLOCK */
+
 #ifdef CONFIG_PM_TRACE
 int pm_trace_enabled;
 
@@ -567,6 +626,9 @@ power_attr(pm_trace);
 
 static struct attribute * g[] = {
 	&state_attr.attr,
+#ifdef CONFIG_SUSPEND_BLOCK
+	&request_state_attr.attr,
+#endif
 #ifdef CONFIG_PM_TRACE
 	&pm_trace_attr.attr,
 #endif
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 46b5ec7..2414a74 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -223,3 +223,9 @@ static inline void suspend_thaw_processes(void)
 {
 }
 #endif
+
+#ifdef CONFIG_SUSPEND_BLOCK
+/* kernel/power/suspend_block.c */
+void request_suspend_state(suspend_state_t state);
+#endif
+
diff --git a/kernel/power/suspend_block.c b/kernel/power/suspend_block.c
new file mode 100644
index 0000000..b4f2191
--- /dev/null
+++ b/kernel/power/suspend_block.c
@@ -0,0 +1,257 @@
+/* kernel/power/suspend_block.c
+ *
+ * Copyright (C) 2005-2008 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/rtc.h>
+#include <linux/suspend.h>
+#include <linux/suspend_block.h>
+#include <linux/sysdev.h>
+#include "power.h"
+
+enum {
+	DEBUG_EXIT_SUSPEND = 1U << 0,
+	DEBUG_WAKEUP = 1U << 1,
+	DEBUG_USER_STATE = 1U << 2,
+	DEBUG_SUSPEND = 1U << 3,
+	DEBUG_SUSPEND_BLOCKER = 1U << 4,
+};
+static int debug_mask = DEBUG_EXIT_SUSPEND | DEBUG_WAKEUP | DEBUG_USER_STATE;
+module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#define SB_INITIALIZED            (1U << 8)
+#define SB_ACTIVE                 (1U << 9)
+
+static DEFINE_SPINLOCK(state_lock);
+static atomic_t suspend_block_count;
+static atomic_t current_event_num;
+struct workqueue_struct *suspend_work_queue;
+struct suspend_blocker main_suspend_blocker;
+static suspend_state_t requested_suspend_state = PM_SUSPEND_MEM;
+static bool enable_suspend_blockers;
+
+bool suspend_is_blocked(void)
+{
+	if (WARN_ONCE(!enable_suspend_blockers, "ignoring suspend blockers\n"))
+		return 0;
+	return !!atomic_read(&suspend_block_count);
+}
+
+static void suspend_worker(struct work_struct *work)
+{
+	int ret;
+	int entry_event_num;
+
+	enable_suspend_blockers = 1;
+
+retry:
+	if (suspend_is_blocked()) {
+		if (debug_mask & DEBUG_SUSPEND)
+			pr_info("suspend: abort suspend\n");
+		goto abort;
+	}
+
+	entry_event_num = atomic_read(&current_event_num);
+	if (debug_mask & DEBUG_SUSPEND)
+		pr_info("suspend: enter suspend\n");
+	ret = pm_suspend(requested_suspend_state);
+	if (debug_mask & DEBUG_EXIT_SUSPEND) {
+		struct timespec ts;
+		struct rtc_time tm;
+		getnstimeofday(&ts);
+		rtc_time_to_tm(ts.tv_sec, &tm);
+		pr_info("suspend: exit suspend, ret = %d "
+			"(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", ret,
+			tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+			tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
+	}
+	if (atomic_read(&current_event_num) == entry_event_num) {
+		if (debug_mask & DEBUG_SUSPEND)
+			pr_info("suspend: pm_suspend returned with no event\n");
+		goto retry;
+	}
+abort:
+	enable_suspend_blockers = 0;
+}
+static DECLARE_WORK(suspend_work, suspend_worker);
+
+static int suspend_block_suspend(struct sys_device *dev, pm_message_t state)
+{
+	int ret = suspend_is_blocked() ? -EAGAIN : 0;
+	if (debug_mask & DEBUG_SUSPEND)
+		pr_info("suspend_block_suspend return %d\n", ret);
+	return ret;
+}
+
+static struct sysdev_class suspend_block_sysclass = {
+	.name = "suspend_block",
+	.suspend = suspend_block_suspend,
+};
+static struct sys_device suspend_block_sysdev = {
+	.cls = &suspend_block_sysclass,
+};
+
+/**
+ * suspend_blocker_init() - Initialize a suspend blocker
+ * @blocker:	The suspend blocker to initialize.
+ * @name:	The name of the suspend blocker to show in
+ *		/proc/suspend_blockers
+ */
+void suspend_blocker_init(struct suspend_blocker *blocker, const char *name)
+{
+	if (name)
+		blocker->name = name;
+	BUG_ON(!blocker->name);
+
+	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
+		pr_info("suspend_blocker_init name=%s\n", blocker->name);
+
+	atomic_set(&blocker->flags, SB_INITIALIZED);
+}
+EXPORT_SYMBOL(suspend_blocker_init);
+
+/**
+ * suspend_blocker_destroy() - Destroy a suspend blocker
+ * @blocker:	The suspend blocker to destroy.
+ */
+void suspend_blocker_destroy(struct suspend_blocker *blocker)
+{
+	int flags;
+	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
+		pr_info("suspend_blocker_destroy name=%s\n", blocker->name);
+	flags = atomic_xchg(&blocker->flags, 0);
+	WARN(!(flags & SB_INITIALIZED), "suspend_blocker_destroy called on "
+					"uninitialized suspend_blocker\n");
+	if (flags == (SB_INITIALIZED | SB_ACTIVE))
+		if (atomic_dec_and_test(&suspend_block_count))
+			queue_work(suspend_work_queue, &suspend_work);
+}
+EXPORT_SYMBOL(suspend_blocker_destroy);
+
+/**
+ * suspend_block() - Block suspend
+ * @blocker:	The suspend blocker to use
+ */
+void suspend_block(struct suspend_blocker *blocker)
+{
+	BUG_ON(!(atomic_read(&blocker->flags) & SB_INITIALIZED));
+
+	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
+		pr_info("suspend_block: %s\n", blocker->name);
+	if (atomic_cmpxchg(&blocker->flags, SB_INITIALIZED,
+	    SB_INITIALIZED | SB_ACTIVE) == SB_INITIALIZED)
+		atomic_inc(&suspend_block_count);
+
+	atomic_inc(&current_event_num);
+}
+EXPORT_SYMBOL(suspend_block);
+
+/**
+ * suspend_unblock() - Unblock suspend
+ * @blocker:	The suspend blocker to unblock.
+ *
+ * If no other suspend blockers block suspend, the system will suspend.
+ */
+void suspend_unblock(struct suspend_blocker *blocker)
+{
+	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
+		pr_info("suspend_unblock: %s\n", blocker->name);
+
+	if (atomic_cmpxchg(&blocker->flags, SB_INITIALIZED | SB_ACTIVE,
+	    SB_INITIALIZED) == (SB_INITIALIZED | SB_ACTIVE))
+		if (atomic_dec_and_test(&suspend_block_count))
+			queue_work(suspend_work_queue, &suspend_work);
+}
+EXPORT_SYMBOL(suspend_unblock);
+
+/**
+ * is_blocking_suspend() - Test if a suspend blocker is blocking suspend
+ * @blocker:	The suspend blocker to check.
+ */
+bool is_blocking_suspend(struct suspend_blocker *blocker)
+{
+	return !!(atomic_read(&blocker->flags) & SB_ACTIVE);
+}
+EXPORT_SYMBOL(is_blocking_suspend);
+
+void request_suspend_state(suspend_state_t state)
+{
+	unsigned long irqflags;
+	spin_lock_irqsave(&state_lock, irqflags);
+	if (debug_mask & DEBUG_USER_STATE) {
+		struct timespec ts;
+		struct rtc_time tm;
+		getnstimeofday(&ts);
+		rtc_time_to_tm(ts.tv_sec, &tm);
+		pr_info("request_suspend_state: %s (%d->%d) at %lld "
+			"(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n",
+			state != PM_SUSPEND_ON ? "sleep" : "wakeup",
+			requested_suspend_state, state,
+			ktime_to_ns(ktime_get()),
+			tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+			tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
+	}
+	requested_suspend_state = state;
+	if (state == PM_SUSPEND_ON)
+		suspend_block(&main_suspend_blocker);
+	else
+		suspend_unblock(&main_suspend_blocker);
+	spin_unlock_irqrestore(&state_lock, irqflags);
+}
+
+static int __init suspend_block_init(void)
+{
+	int ret;
+
+	suspend_blocker_init(&main_suspend_blocker, "main");
+	suspend_block(&main_suspend_blocker);
+
+	ret = sysdev_class_register(&suspend_block_sysclass);
+	if (ret) {
+		pr_err("suspend_block_init: sysdev_class_register failed\n");
+		goto err_sysdev_class_register;
+	}
+	ret = sysdev_register(&suspend_block_sysdev);
+	if (ret) {
+		pr_err("suspend_block_init: suspend_block_sysdev failed\n");
+		goto err_sysdev_register;
+	}
+
+	suspend_work_queue = create_singlethread_workqueue("suspend");
+	if (suspend_work_queue == NULL) {
+		ret = -ENOMEM;
+		goto err_suspend_work_queue;
+	}
+
+	return 0;
+
+err_suspend_work_queue:
+	sysdev_unregister(&suspend_block_sysdev);
+err_sysdev_register:
+	sysdev_class_unregister(&suspend_block_sysclass);
+err_sysdev_class_register:
+	suspend_blocker_destroy(&main_suspend_blocker);
+	return ret;
+}
+
+static void  __exit suspend_block_exit(void)
+{
+	destroy_workqueue(suspend_work_queue);
+	sysdev_unregister(&suspend_block_sysdev);
+	sysdev_class_unregister(&suspend_block_sysclass);
+	suspend_blocker_destroy(&main_suspend_blocker);
+}
+
+core_initcall(suspend_block_init);
+module_exit(suspend_block_exit);
-- 
1.6.1

_______________________________________________
linux-pm mailing list
linux-pm@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/linux-pm

^ permalink raw reply related	[flat|nested] 93+ messages in thread

* [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2009-04-15  1:41 ` [PATCH 1/8] PM: Add suspend " Arve Hjønnevåg
@ 2009-04-15  1:41   ` Arve Hjønnevåg
  2009-04-15  1:41     ` [PATCH 3/8] PM: suspend_block: Abort task freezing if a suspend_blocker is active Arve Hjønnevåg
  2009-04-29 22:52     ` [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space Rafael J. Wysocki
  2009-04-15 15:29   ` [PATCH 1/8] PM: Add suspend block api Alan Stern
                     ` (3 subsequent siblings)
  4 siblings, 2 replies; 93+ messages in thread
From: Arve Hjønnevåg @ 2009-04-15  1:41 UTC (permalink / raw)
  To: linux-pm; +Cc: ncunningham, u.luckas, swetland, r-woodruff2, 

Adds ioctls to create a suspend_blocker, and to block and unblock suspend.
To delete the suspend_blocker, close the device.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
 Documentation/power/suspend-blockers.txt |   17 ++++
 include/linux/suspend_block_dev.h        |   25 ++++++
 kernel/power/Kconfig                     |    9 ++
 kernel/power/Makefile                    |    1 +
 kernel/power/user_suspend_block.c        |  125 ++++++++++++++++++++++++++++++
 5 files changed, 177 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/suspend_block_dev.h
 create mode 100644 kernel/power/user_suspend_block.c

diff --git a/Documentation/power/suspend-blockers.txt b/Documentation/power/suspend-blockers.txt
index 743b870..35bc713 100644
--- a/Documentation/power/suspend-blockers.txt
+++ b/Documentation/power/suspend-blockers.txt
@@ -74,3 +74,20 @@ if (list_empty(&state->pending_work))
 else
 	suspend_block(&state->suspend_blocker);
 
+User-space API
+==============
+
+To create a suspend_blocker from user-space, open the suspend_blocker device:
+    fd = open("/dev/suspend_blocker", O_RDWR | O_CLOEXEC);
+then call:
+    ioctl(fd, SUSPEND_BLOCKER_IOCTL_INIT(strlen(name)), name);
+
+To activate a suspend_blocker call:
+    ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK);
+
+To unblock call:
+    ioctl(fd, SUSPEND_BLOCKER_IOCTL_UNBLOCK);
+
+To destroy the suspend_blocker, close the device:
+    close(fd);
+
diff --git a/include/linux/suspend_block_dev.h b/include/linux/suspend_block_dev.h
new file mode 100644
index 0000000..a7c0bf9
--- /dev/null
+++ b/include/linux/suspend_block_dev.h
@@ -0,0 +1,25 @@
+/* include/linux/suspend_block_dev.h
+ *
+ * Copyright (C) 2009 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _LINUX_SUSPEND_BLOCK_DEV_H
+#define _LINUX_SUSPEND_BLOCK_DEV_H
+
+#include <linux/ioctl.h>
+
+#define SUSPEND_BLOCKER_IOCTL_INIT(len)		_IOC(_IOC_WRITE, 's', 0, len)
+#define SUSPEND_BLOCKER_IOCTL_BLOCK		_IO('s', 1)
+#define SUSPEND_BLOCKER_IOCTL_UNBLOCK		_IO('s', 3)
+
+#endif
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 9d1df13..2cf4c4d 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -126,6 +126,15 @@ config SUSPEND_BLOCK
 	  /sys/power/request_state, the requested sleep state will be entered
 	  when no suspend_blockers are active.
 
+config USER_SUSPEND_BLOCK
+	bool "Userspace suspend blockers"
+	depends on SUSPEND_BLOCK
+	default y
+	---help---
+	  User-space suspend block api. Creates a misc device with ioctls
+	  to create, block and unblock a suspend_blocker. The suspend_blocker
+	  will be deleted when the device is closed.
+
 config HIBERNATION
 	bool "Hibernation (aka 'suspend to disk')"
 	depends on PM && SWAP && ARCH_HIBERNATION_POSSIBLE
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index 29cdc9e..5c524f1 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_PM)		+= main.o
 obj-$(CONFIG_PM_SLEEP)		+= console.o
 obj-$(CONFIG_FREEZER)		+= process.o
 obj-$(CONFIG_SUSPEND_BLOCK)	+= suspend_block.o
+obj-$(CONFIG_USER_SUSPEND_BLOCK)	+= user_suspend_block.o
 obj-$(CONFIG_HIBERNATION)	+= swsusp.o disk.o snapshot.o swap.o user.o
 
 obj-$(CONFIG_MAGIC_SYSRQ)	+= poweroff.o
diff --git a/kernel/power/user_suspend_block.c b/kernel/power/user_suspend_block.c
new file mode 100644
index 0000000..782407c
--- /dev/null
+++ b/kernel/power/user_suspend_block.c
@@ -0,0 +1,125 @@
+/* kernel/power/user_suspend_block.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/suspend_block.h>
+#include <linux/suspend_block_dev.h>
+
+enum {
+	DEBUG_FAILURE	= BIT(0),
+};
+static int debug_mask = DEBUG_FAILURE;
+module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+static DEFINE_MUTEX(ioctl_lock);
+
+struct user_suspend_blocker {
+	struct suspend_blocker	blocker;
+	char			name[0];
+};
+
+static int create_user_suspend_blocker(struct file *file, void __user *name,
+				 size_t name_len)
+{
+	struct user_suspend_blocker *bl;
+	if (file->private_data)
+		return -EBUSY;
+	bl = kzalloc(sizeof(*bl) + name_len + 1, GFP_KERNEL);
+	if (!bl)
+		return -ENOMEM;
+	if (copy_from_user(bl->name, name, name_len))
+		goto err_fault;
+	suspend_blocker_init(&bl->blocker, bl->name);
+	file->private_data = bl;
+	return 0;
+
+err_fault:
+	kfree(bl);
+	return -EFAULT;
+}
+
+static long user_suspend_blocker_ioctl(struct file *file, unsigned int cmd,
+				unsigned long _arg)
+{
+	void __user *arg = (void __user *)_arg;
+	struct user_suspend_blocker *bl;
+	long ret;
+
+	mutex_lock(&ioctl_lock);
+	if ((cmd & ~IOCSIZE_MASK) == SUSPEND_BLOCKER_IOCTL_INIT(0)) {
+		ret = create_user_suspend_blocker(file, arg, _IOC_SIZE(cmd));
+		goto done;
+	}
+	bl = file->private_data;
+	if (!bl) {
+		ret = -ENOENT;
+		goto done;
+	}
+	switch (cmd) {
+	case SUSPEND_BLOCKER_IOCTL_BLOCK:
+		suspend_block(&bl->blocker);
+		ret = 0;
+		break;
+	case SUSPEND_BLOCKER_IOCTL_UNBLOCK:
+		suspend_unblock(&bl->blocker);
+		ret = 0;
+		break;
+	default:
+		ret = -ENOTSUPP;
+	}
+done:
+	if (ret && debug_mask & DEBUG_FAILURE)
+		pr_err("user_suspend_blocker_ioctl: cmd %x failed, %ld\n",
+			cmd, ret);
+	mutex_unlock(&ioctl_lock);
+	return ret;
+}
+
+static int user_suspend_blocker_release(struct inode *inode, struct file *file)
+{
+	struct user_suspend_blocker *bl = file->private_data;
+	if (!bl)
+		return 0;
+	suspend_blocker_destroy(&bl->blocker);
+	kfree(bl);
+	return 0;
+}
+
+const struct file_operations user_suspend_blocker_fops = {
+	.release = user_suspend_blocker_release,
+	.unlocked_ioctl = user_suspend_blocker_ioctl,
+};
+
+struct miscdevice user_suspend_blocker_device = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "suspend_blocker",
+	.fops = &user_suspend_blocker_fops,
+};
+
+static int __init user_suspend_blocker_init(void)
+{
+	return misc_register(&user_suspend_blocker_device);
+}
+
+static void __exit user_suspend_blocker_exit(void)
+{
+	misc_deregister(&user_suspend_blocker_device);
+}
+
+module_init(user_suspend_blocker_init);
+module_exit(user_suspend_blocker_exit);
-- 
1.6.1

_______________________________________________
linux-pm mailing list
linux-pm@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/linux-pm

^ permalink raw reply related	[flat|nested] 93+ messages in thread

* [PATCH 3/8] PM: suspend_block: Abort task freezing if a suspend_blocker is active.
  2009-04-15  1:41   ` [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space Arve Hjønnevåg
@ 2009-04-15  1:41     ` Arve Hjønnevåg
  2009-04-15  1:41       ` [PATCH 4/8] Input: Block suspend while event queue is not empty Arve Hjønnevåg
  2009-04-29 22:56       ` [PATCH 3/8] PM: suspend_block: Abort task freezing if a suspend_blocker is active Rafael J. Wysocki
  2009-04-29 22:52     ` [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space Rafael J. Wysocki
  1 sibling, 2 replies; 93+ messages in thread
From: Arve Hjønnevåg @ 2009-04-15  1:41 UTC (permalink / raw)
  To: linux-pm; +Cc: ncunningham, u.luckas, swetland, r-woodruff2, 

If a suspend_blocker is active, suspend will fail anyway. Since
try_to_freeze_tasks can take up to 20 seconds to complete or fail, aborting
as soon as someone blocks suspend (e.g. from an interrupt handler) improves
the worst case wakeup latency.

On an older kernel where task freezing could fail for processes attached
to a debugger, this fixed a problem where the device sometimes hung for
20 seconds before the screen turned on.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
 kernel/power/process.c |   23 ++++++++++++++++++-----
 1 files changed, 18 insertions(+), 5 deletions(-)

diff --git a/kernel/power/process.c b/kernel/power/process.c
index ca63401..76d7cdb 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/syscalls.h>
 #include <linux/freezer.h>
+#include <linux/suspend_block.h>
 
 /* 
  * Timeout for stopping processes
@@ -36,6 +37,7 @@ static int try_to_freeze_tasks(bool sig_only)
 	struct timeval start, end;
 	u64 elapsed_csecs64;
 	unsigned int elapsed_csecs;
+	unsigned int wakeup = 0;
 
 	do_gettimeofday(&start);
 
@@ -62,6 +64,10 @@ static int try_to_freeze_tasks(bool sig_only)
 		} while_each_thread(g, p);
 		read_unlock(&tasklist_lock);
 		yield();			/* Yield is okay here */
+		if (todo && suspend_is_blocked()) {
+			wakeup = 1;
+			break;
+		}
 		if (time_after(jiffies, end_time))
 			break;
 	} while (todo);
@@ -77,11 +83,18 @@ static int try_to_freeze_tasks(bool sig_only)
 		 * and caller must call thaw_processes() if something fails),
 		 * but it cleans up leftover PF_FREEZE requests.
 		 */
-		printk("\n");
-		printk(KERN_ERR "Freezing of tasks failed after %d.%02d seconds "
-				"(%d tasks refusing to freeze):\n",
-				elapsed_csecs / 100, elapsed_csecs % 100, todo);
-		show_state();
+		if (wakeup) {
+			printk("\n");
+			printk(KERN_ERR "Freezing of %s aborted\n",
+					sig_only ? "user space " : "tasks ");
+		} else {
+			printk("\n");
+			printk(KERN_ERR
+			       "Freezing of tasks failed after %d.%02d seconds "
+			       "(%d tasks refusing to freeze):\n",
+			       elapsed_csecs / 100, elapsed_csecs % 100, todo);
+			show_state();
+		}
 		read_lock(&tasklist_lock);
 		do_each_thread(g, p) {
 			task_lock(p);
-- 
1.6.1

_______________________________________________
linux-pm mailing list
linux-pm@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/linux-pm

^ permalink raw reply related	[flat|nested] 93+ messages in thread

* [PATCH 4/8] Input: Block suspend while event queue is not empty.
  2009-04-15  1:41     ` [PATCH 3/8] PM: suspend_block: Abort task freezing if a suspend_blocker is active Arve Hjønnevåg
@ 2009-04-15  1:41       ` Arve Hjønnevåg
  2009-04-15  1:41         ` [PATCH 5/8] PM: suspend_block: Switch to list of active and inactive suspend blockers Arve Hjønnevåg
  2009-04-29 22:56       ` [PATCH 3/8] PM: suspend_block: Abort task freezing if a suspend_blocker is active Rafael J. Wysocki
  1 sibling, 1 reply; 93+ messages in thread
From: Arve Hjønnevåg @ 2009-04-15  1:41 UTC (permalink / raw)
  To: linux-pm; +Cc: ncunningham, u.luckas, swetland, r-woodruff2, 

Add an ioctl, EVIOCSSUSPENDBLOCK, to enables a suspend_blocker that will block
suspend while the event queue is not empty. This allows userspace code to
process input events while the device appears to be asleep.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
 drivers/input/evdev.c |   21 +++++++++++++++++++++
 include/linux/input.h |    3 +++
 2 files changed, 24 insertions(+), 0 deletions(-)

diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index ed8baa0..3a61425 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -19,6 +19,7 @@
 #include <linux/input.h>
 #include <linux/major.h>
 #include <linux/device.h>
+#include <linux/suspend_block.h>
 #include "input-compat.h"
 
 struct evdev {
@@ -43,6 +44,8 @@ struct evdev_client {
 	struct fasync_struct *fasync;
 	struct evdev *evdev;
 	struct list_head node;
+	int use_suspend_blocker;
+	struct suspend_blocker suspend_blocker;
 };
 
 static struct evdev *evdev_table[EVDEV_MINORS];
@@ -55,6 +58,8 @@ static void evdev_pass_event(struct evdev_client *client,
 	 * Interrupts are disabled, just acquire the lock
 	 */
 	spin_lock(&client->buffer_lock);
+	if (client->use_suspend_blocker)
+		suspend_block(&client->suspend_blocker);
 	client->buffer[client->head++] = *event;
 	client->head &= EVDEV_BUFFER_SIZE - 1;
 	spin_unlock(&client->buffer_lock);
@@ -236,6 +241,8 @@ static int evdev_release(struct inode *inode, struct file *file)
 	mutex_unlock(&evdev->mutex);
 
 	evdev_detach_client(evdev, client);
+	if (client->use_suspend_blocker)
+		suspend_blocker_destroy(&client->suspend_blocker);
 	kfree(client);
 
 	evdev_close_device(evdev);
@@ -335,6 +342,8 @@ static int evdev_fetch_next_event(struct evdev_client *client,
 	if (have_event) {
 		*event = client->buffer[client->tail++];
 		client->tail &= EVDEV_BUFFER_SIZE - 1;
+		if (client->use_suspend_blocker && client->head == client->tail)
+			suspend_unblock(&client->suspend_blocker);
 	}
 
 	spin_unlock_irq(&client->buffer_lock);
@@ -585,6 +594,18 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
 		else
 			return evdev_ungrab(evdev, client);
 
+	case EVIOCGSUSPENDBLOCK:
+		return put_user(EV_VERSION, ip);
+
+	case EVIOCSSUSPENDBLOCK:
+		spin_lock_irq(&client->buffer_lock);
+		if ((client->use_suspend_blocker = !!p))
+			suspend_blocker_init(&client->suspend_blocker, "evdev");
+		else
+			suspend_blocker_destroy(&client->suspend_blocker);
+		spin_unlock_irq(&client->buffer_lock);
+		return 0;
+
 	default:
 
 		if (_IOC_TYPE(cmd) != 'E')
diff --git a/include/linux/input.h b/include/linux/input.h
index 1249a0c..67e2332 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -81,6 +81,9 @@ struct input_absinfo {
 
 #define EVIOCGRAB		_IOW('E', 0x90, int)			/* Grab/Release device */
 
+#define EVIOCGSUSPENDBLOCK	_IOR('E', 0x91, int)			/* get suspend block enable */
+#define EVIOCSSUSPENDBLOCK	_IOW('E', 0x91, int)			/* set suspend block enable */
+
 /*
  * Event types
  */
-- 
1.6.1

_______________________________________________
linux-pm mailing list
linux-pm@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/linux-pm

^ permalink raw reply related	[flat|nested] 93+ messages in thread

* [PATCH 5/8] PM: suspend_block: Switch to list of active and inactive suspend blockers
  2009-04-15  1:41       ` [PATCH 4/8] Input: Block suspend while event queue is not empty Arve Hjønnevåg
@ 2009-04-15  1:41         ` Arve Hjønnevåg
  2009-04-15  1:41           ` [PATCH 6/8] PM: suspend_block: Add suspend_blocker stats Arve Hjønnevåg
  0 siblings, 1 reply; 93+ messages in thread
From: Arve Hjønnevåg @ 2009-04-15  1:41 UTC (permalink / raw)
  To: linux-pm; +Cc: ncunningham, u.luckas, swetland, r-woodruff2, 

This allows active suspend blockers to be listed

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
 include/linux/suspend_block.h |    5 ++-
 kernel/power/suspend_block.c  |   77 ++++++++++++++++++++++++++++------------
 2 files changed, 58 insertions(+), 24 deletions(-)

diff --git a/include/linux/suspend_block.h b/include/linux/suspend_block.h
index 7820c60..73ac5f7 100755
--- a/include/linux/suspend_block.h
+++ b/include/linux/suspend_block.h
@@ -16,12 +16,15 @@
 #ifndef _LINUX_SUSPEND_BLOCK_H
 #define _LINUX_SUSPEND_BLOCK_H
 
+#include <linux/list.h>
+
 /* A suspend_blocker prevents the system from entering suspend when active.
  */
 
 struct suspend_blocker {
 #ifdef CONFIG_SUSPEND_BLOCK
-	atomic_t            flags;
+	struct list_head    link;
+	int                 flags;
 	const char         *name;
 #endif
 };
diff --git a/kernel/power/suspend_block.c b/kernel/power/suspend_block.c
index b4f2191..697f52a 100644
--- a/kernel/power/suspend_block.c
+++ b/kernel/power/suspend_block.c
@@ -33,19 +33,29 @@ module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
 #define SB_INITIALIZED            (1U << 8)
 #define SB_ACTIVE                 (1U << 9)
 
+static DEFINE_SPINLOCK(list_lock);
 static DEFINE_SPINLOCK(state_lock);
-static atomic_t suspend_block_count;
-static atomic_t current_event_num;
+static LIST_HEAD(inactive_blockers);
+static LIST_HEAD(active_blockers);
+static int current_event_num;
 struct workqueue_struct *suspend_work_queue;
 struct suspend_blocker main_suspend_blocker;
 static suspend_state_t requested_suspend_state = PM_SUSPEND_MEM;
 static bool enable_suspend_blockers;
 
+static void print_active_blockers_locked(void)
+{
+	struct suspend_blocker *blocker;
+
+	list_for_each_entry(blocker, &active_blockers, link)
+		pr_info("active suspend blocker %s\n", blocker->name);
+}
+
 bool suspend_is_blocked(void)
 {
 	if (WARN_ONCE(!enable_suspend_blockers, "ignoring suspend blockers\n"))
 		return 0;
-	return !!atomic_read(&suspend_block_count);
+	return !list_empty(&active_blockers);
 }
 
 static void suspend_worker(struct work_struct *work)
@@ -62,7 +72,7 @@ retry:
 		goto abort;
 	}
 
-	entry_event_num = atomic_read(&current_event_num);
+	entry_event_num = current_event_num;
 	if (debug_mask & DEBUG_SUSPEND)
 		pr_info("suspend: enter suspend\n");
 	ret = pm_suspend(requested_suspend_state);
@@ -76,7 +86,7 @@ retry:
 			tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
 			tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
 	}
-	if (atomic_read(&current_event_num) == entry_event_num) {
+	if (current_event_num == entry_event_num) {
 		if (debug_mask & DEBUG_SUSPEND)
 			pr_info("suspend: pm_suspend returned with no event\n");
 		goto retry;
@@ -110,6 +120,8 @@ static struct sys_device suspend_block_sysdev = {
  */
 void suspend_blocker_init(struct suspend_blocker *blocker, const char *name)
 {
+	unsigned long irqflags = 0;
+
 	if (name)
 		blocker->name = name;
 	BUG_ON(!blocker->name);
@@ -117,7 +129,12 @@ void suspend_blocker_init(struct suspend_blocker *blocker, const char *name)
 	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
 		pr_info("suspend_blocker_init name=%s\n", blocker->name);
 
-	atomic_set(&blocker->flags, SB_INITIALIZED);
+	blocker->flags = SB_INITIALIZED;
+	INIT_LIST_HEAD(&blocker->link);
+
+	spin_lock_irqsave(&list_lock, irqflags);
+	list_add(&blocker->link, &inactive_blockers);
+	spin_unlock_irqrestore(&list_lock, irqflags);
 }
 EXPORT_SYMBOL(suspend_blocker_init);
 
@@ -127,15 +144,15 @@ EXPORT_SYMBOL(suspend_blocker_init);
  */
 void suspend_blocker_destroy(struct suspend_blocker *blocker)
 {
-	int flags;
+	unsigned long irqflags;
 	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
 		pr_info("suspend_blocker_destroy name=%s\n", blocker->name);
-	flags = atomic_xchg(&blocker->flags, 0);
-	WARN(!(flags & SB_INITIALIZED), "suspend_blocker_destroy called on "
-					"uninitialized suspend_blocker\n");
-	if (flags == (SB_INITIALIZED | SB_ACTIVE))
-		if (atomic_dec_and_test(&suspend_block_count))
-			queue_work(suspend_work_queue, &suspend_work);
+	spin_lock_irqsave(&list_lock, irqflags);
+	blocker->flags &= ~SB_INITIALIZED;
+	list_del(&blocker->link);
+	if ((blocker->flags & SB_ACTIVE) && list_empty(&active_blockers))
+		queue_work(suspend_work_queue, &suspend_work);
+	spin_unlock_irqrestore(&list_lock, irqflags);
 }
 EXPORT_SYMBOL(suspend_blocker_destroy);
 
@@ -145,15 +162,19 @@ EXPORT_SYMBOL(suspend_blocker_destroy);
  */
 void suspend_block(struct suspend_blocker *blocker)
 {
-	BUG_ON(!(atomic_read(&blocker->flags) & SB_INITIALIZED));
+	unsigned long irqflags;
+
+	spin_lock_irqsave(&list_lock, irqflags);
+	BUG_ON(!(blocker->flags & SB_INITIALIZED));
 
+	blocker->flags |= SB_ACTIVE;
+	list_del(&blocker->link);
 	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
 		pr_info("suspend_block: %s\n", blocker->name);
-	if (atomic_cmpxchg(&blocker->flags, SB_INITIALIZED,
-	    SB_INITIALIZED | SB_ACTIVE) == SB_INITIALIZED)
-		atomic_inc(&suspend_block_count);
+	list_add(&blocker->link, &active_blockers);
 
-	atomic_inc(&current_event_num);
+	current_event_num++;
+	spin_unlock_irqrestore(&list_lock, irqflags);
 }
 EXPORT_SYMBOL(suspend_block);
 
@@ -165,13 +186,23 @@ EXPORT_SYMBOL(suspend_block);
  */
 void suspend_unblock(struct suspend_blocker *blocker)
 {
+	unsigned long irqflags;
+
+	spin_lock_irqsave(&list_lock, irqflags);
+
 	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
 		pr_info("suspend_unblock: %s\n", blocker->name);
+	list_del(&blocker->link);
+	list_add(&blocker->link, &inactive_blockers);
 
-	if (atomic_cmpxchg(&blocker->flags, SB_INITIALIZED | SB_ACTIVE,
-	    SB_INITIALIZED) == (SB_INITIALIZED | SB_ACTIVE))
-		if (atomic_dec_and_test(&suspend_block_count))
-			queue_work(suspend_work_queue, &suspend_work);
+	if ((blocker->flags & SB_ACTIVE) && list_empty(&active_blockers))
+		queue_work(suspend_work_queue, &suspend_work);
+	blocker->flags &= ~(SB_ACTIVE);
+	if (blocker == &main_suspend_blocker) {
+		if (debug_mask & DEBUG_SUSPEND)
+			print_active_blockers_locked();
+	}
+	spin_unlock_irqrestore(&list_lock, irqflags);
 }
 EXPORT_SYMBOL(suspend_unblock);
 
@@ -181,7 +212,7 @@ EXPORT_SYMBOL(suspend_unblock);
  */
 bool is_blocking_suspend(struct suspend_blocker *blocker)
 {
-	return !!(atomic_read(&blocker->flags) & SB_ACTIVE);
+	return !!(blocker->flags & SB_ACTIVE);
 }
 EXPORT_SYMBOL(is_blocking_suspend);
 
-- 
1.6.1

_______________________________________________
linux-pm mailing list
linux-pm@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/linux-pm

^ permalink raw reply related	[flat|nested] 93+ messages in thread

* [PATCH 6/8] PM: suspend_block: Add suspend_blocker stats
  2009-04-15  1:41         ` [PATCH 5/8] PM: suspend_block: Switch to list of active and inactive suspend blockers Arve Hjønnevåg
@ 2009-04-15  1:41           ` Arve Hjønnevåg
  2009-04-15  1:41             ` [PATCH 7/8] PM: suspend_block: Add timeout support Arve Hjønnevåg
  0 siblings, 1 reply; 93+ messages in thread
From: Arve Hjønnevåg @ 2009-04-15  1:41 UTC (permalink / raw)
  To: linux-pm; +Cc: ncunningham, u.luckas, swetland, r-woodruff2, 

Report suspend block stats in /proc/suspend_blockers.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
 include/linux/suspend_block.h |   11 +++
 kernel/power/Kconfig          |    7 ++
 kernel/power/suspend_block.c  |  201 ++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 217 insertions(+), 2 deletions(-)

diff --git a/include/linux/suspend_block.h b/include/linux/suspend_block.h
index 73ac5f7..31225c5 100755
--- a/include/linux/suspend_block.h
+++ b/include/linux/suspend_block.h
@@ -17,6 +17,7 @@
 #define _LINUX_SUSPEND_BLOCK_H
 
 #include <linux/list.h>
+#include <linux/ktime.h>
 
 /* A suspend_blocker prevents the system from entering suspend when active.
  */
@@ -26,6 +27,16 @@ struct suspend_blocker {
 	struct list_head    link;
 	int                 flags;
 	const char         *name;
+#ifdef CONFIG_SUSPEND_BLOCK_STAT
+	struct {
+		int             count;
+		int             wakeup_count;
+		ktime_t         total_time;
+		ktime_t         prevent_suspend_time;
+		ktime_t         max_time;
+		ktime_t         last_time;
+	} stat;
+#endif
 #endif
 };
 
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 2cf4c4d..3de0c5f 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -126,6 +126,13 @@ config SUSPEND_BLOCK
 	  /sys/power/request_state, the requested sleep state will be entered
 	  when no suspend_blockers are active.
 
+config SUSPEND_BLOCK_STAT
+	bool "Suspend block stats"
+	depends on SUSPEND_BLOCK
+	default y
+	---help---
+	  Report suspend block stats in /proc/suspend_blockers
+
 config USER_SUSPEND_BLOCK
 	bool "Userspace suspend blockers"
 	depends on SUSPEND_BLOCK
diff --git a/kernel/power/suspend_block.c b/kernel/power/suspend_block.c
index 697f52a..78d5880 100644
--- a/kernel/power/suspend_block.c
+++ b/kernel/power/suspend_block.c
@@ -18,6 +18,9 @@
 #include <linux/suspend.h>
 #include <linux/suspend_block.h>
 #include <linux/sysdev.h>
+#ifdef CONFIG_SUSPEND_BLOCK_STAT
+#include <linux/proc_fs.h>
+#endif
 #include "power.h"
 
 enum {
@@ -32,6 +35,7 @@ module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
 
 #define SB_INITIALIZED            (1U << 8)
 #define SB_ACTIVE                 (1U << 9)
+#define SB_PREVENTING_SUSPEND     (1U << 10)
 
 static DEFINE_SPINLOCK(list_lock);
 static DEFINE_SPINLOCK(state_lock);
@@ -42,6 +46,165 @@ struct workqueue_struct *suspend_work_queue;
 struct suspend_blocker main_suspend_blocker;
 static suspend_state_t requested_suspend_state = PM_SUSPEND_MEM;
 static bool enable_suspend_blockers;
+static struct suspend_blocker unknown_wakeup;
+
+#ifdef CONFIG_SUSPEND_BLOCK_STAT
+static struct suspend_blocker deleted_suspend_blockers;
+static ktime_t last_sleep_time_update;
+static bool wait_for_wakeup;
+
+static int print_blocker_stat(char *buf, struct suspend_blocker *blocker)
+{
+	int lock_count = blocker->stat.count;
+	ktime_t active_time = ktime_set(0, 0);
+	ktime_t total_time = blocker->stat.total_time;
+	ktime_t max_time = blocker->stat.max_time;
+	ktime_t prevent_suspend_time = blocker->stat.prevent_suspend_time;
+	if (blocker->flags & SB_ACTIVE) {
+		ktime_t now, add_time;
+		now = ktime_get();
+		add_time = ktime_sub(now, blocker->stat.last_time);
+		lock_count++;
+		active_time = add_time;
+		total_time = ktime_add(total_time, add_time);
+		if (blocker->flags & SB_PREVENTING_SUSPEND)
+			prevent_suspend_time = ktime_add(prevent_suspend_time,
+					ktime_sub(now, last_sleep_time_update));
+		if (add_time.tv64 > max_time.tv64)
+			max_time = add_time;
+	}
+
+	return sprintf(buf, "\"%s\"\t%d\t%d\t%lld\t%lld\t%lld\t%lld\t%lld\n",
+		       blocker->name, lock_count, blocker->stat.wakeup_count,
+		       ktime_to_ns(active_time), ktime_to_ns(total_time),
+		       ktime_to_ns(prevent_suspend_time), ktime_to_ns(max_time),
+		       ktime_to_ns(blocker->stat.last_time));
+}
+
+
+static int suspend_blocker_stats_read_proc(char *page, char **start, off_t off,
+			       int count, int *eof, void *data)
+{
+	unsigned long irqflags;
+	struct suspend_blocker *blocker;
+	int len = 0;
+	char *p = page;
+
+	spin_lock_irqsave(&list_lock, irqflags);
+
+	p += sprintf(p, "name\tcount\twake_count\tactive_since"
+		     "\ttotal_time\tsleep_time\tmax_time\tlast_change\n");
+	list_for_each_entry(blocker, &inactive_blockers, link) {
+		p += print_blocker_stat(p, blocker);
+	}
+	list_for_each_entry(blocker, &active_blockers, link)
+		p += print_blocker_stat(p, blocker);
+	spin_unlock_irqrestore(&list_lock, irqflags);
+
+	*start = page + off;
+
+	len = p - page;
+	if (len > off)
+		len -= off;
+	else
+		len = 0;
+
+	return len < count ? len  : count;
+}
+
+static void suspend_blocker_stat_init_locked(struct suspend_blocker *blocker)
+{
+	blocker->stat.count = 0;
+	blocker->stat.wakeup_count = 0;
+	blocker->stat.total_time = ktime_set(0, 0);
+	blocker->stat.prevent_suspend_time = ktime_set(0, 0);
+	blocker->stat.max_time = ktime_set(0, 0);
+	blocker->stat.last_time = ktime_set(0, 0);
+}
+
+static void suspend_blocker_stat_destroy_locked(struct suspend_blocker *bl)
+{
+	if (!bl->stat.count)
+		return;
+	deleted_suspend_blockers.stat.count += bl->stat.count;
+	deleted_suspend_blockers.stat.total_time = ktime_add(
+		deleted_suspend_blockers.stat.total_time, bl->stat.total_time);
+	deleted_suspend_blockers.stat.prevent_suspend_time = ktime_add(
+		deleted_suspend_blockers.stat.prevent_suspend_time,
+		bl->stat.prevent_suspend_time);
+	deleted_suspend_blockers.stat.max_time = ktime_add(
+		deleted_suspend_blockers.stat.max_time, bl->stat.max_time);
+}
+
+static void suspend_unblock_stat_locked(struct suspend_blocker *blocker)
+{
+	ktime_t duration;
+	ktime_t now;
+	if (!(blocker->flags & SB_ACTIVE))
+		return;
+	now = ktime_get();
+	blocker->stat.count++;
+	duration = ktime_sub(now, blocker->stat.last_time);
+	blocker->stat.total_time =
+		ktime_add(blocker->stat.total_time, duration);
+	if (ktime_to_ns(duration) > ktime_to_ns(blocker->stat.max_time))
+		blocker->stat.max_time = duration;
+	blocker->stat.last_time = ktime_get();
+	if (blocker->flags & SB_PREVENTING_SUSPEND) {
+		duration = ktime_sub(now, last_sleep_time_update);
+		blocker->stat.prevent_suspend_time = ktime_add(
+			blocker->stat.prevent_suspend_time, duration);
+		blocker->flags &= ~SB_PREVENTING_SUSPEND;
+	}
+}
+
+static void suspend_block_stat_locked(struct suspend_blocker *blocker)
+{
+	if (wait_for_wakeup) {
+		if (debug_mask & DEBUG_WAKEUP)
+			pr_info("wakeup suspend blocker: %s\n", blocker->name);
+		wait_for_wakeup = false;
+		blocker->stat.wakeup_count++;
+	}
+	if (!(blocker->flags & SB_ACTIVE))
+		blocker->stat.last_time = ktime_get();
+}
+
+static void update_sleep_wait_stats_locked(bool done)
+{
+	struct suspend_blocker *blocker;
+	ktime_t now, elapsed, add;
+
+	now = ktime_get();
+	elapsed = ktime_sub(now, last_sleep_time_update);
+	list_for_each_entry(blocker, &active_blockers, link) {
+		if (blocker->flags & SB_PREVENTING_SUSPEND) {
+			add = elapsed;
+			blocker->stat.prevent_suspend_time = ktime_add(
+				blocker->stat.prevent_suspend_time, add);
+		}
+		if (done)
+			blocker->flags &= ~SB_PREVENTING_SUSPEND;
+		else
+			blocker->flags |= SB_PREVENTING_SUSPEND;
+	}
+	last_sleep_time_update = now;
+}
+
+#else
+
+static inline void suspend_blocker_stat_init_locked(
+					struct suspend_blocker *blocker) {}
+static inline void suspend_blocker_stat_destroy_locked(
+					struct suspend_blocker *blocker) {}
+static inline void suspend_block_stat_locked(
+					struct suspend_blocker *blocker) {}
+static inline void suspend_unblock_stat_locked(
+					struct suspend_blocker *blocker) {}
+static inline void update_sleep_wait_stats_locked(bool done) {}
+
+#endif
+
 
 static void print_active_blockers_locked(void)
 {
@@ -65,7 +228,6 @@ static void suspend_worker(struct work_struct *work)
 
 	enable_suspend_blockers = 1;
 
-retry:
 	if (suspend_is_blocked()) {
 		if (debug_mask & DEBUG_SUSPEND)
 			pr_info("suspend: abort suspend\n");
@@ -89,7 +251,8 @@ retry:
 	if (current_event_num == entry_event_num) {
 		if (debug_mask & DEBUG_SUSPEND)
 			pr_info("suspend: pm_suspend returned with no event\n");
-		goto retry;
+		suspend_block(&unknown_wakeup);
+		suspend_unblock(&unknown_wakeup);
 	}
 abort:
 	enable_suspend_blockers = 0;
@@ -99,6 +262,9 @@ static DECLARE_WORK(suspend_work, suspend_worker);
 static int suspend_block_suspend(struct sys_device *dev, pm_message_t state)
 {
 	int ret = suspend_is_blocked() ? -EAGAIN : 0;
+#ifdef CONFIG_SUSPEND_BLOCK_STAT
+	wait_for_wakeup = true;
+#endif
 	if (debug_mask & DEBUG_SUSPEND)
 		pr_info("suspend_block_suspend return %d\n", ret);
 	return ret;
@@ -133,6 +299,7 @@ void suspend_blocker_init(struct suspend_blocker *blocker, const char *name)
 	INIT_LIST_HEAD(&blocker->link);
 
 	spin_lock_irqsave(&list_lock, irqflags);
+	suspend_blocker_stat_init_locked(blocker);
 	list_add(&blocker->link, &inactive_blockers);
 	spin_unlock_irqrestore(&list_lock, irqflags);
 }
@@ -148,6 +315,7 @@ void suspend_blocker_destroy(struct suspend_blocker *blocker)
 	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
 		pr_info("suspend_blocker_destroy name=%s\n", blocker->name);
 	spin_lock_irqsave(&list_lock, irqflags);
+	suspend_blocker_stat_destroy_locked(blocker);
 	blocker->flags &= ~SB_INITIALIZED;
 	list_del(&blocker->link);
 	if ((blocker->flags & SB_ACTIVE) && list_empty(&active_blockers))
@@ -167,6 +335,7 @@ void suspend_block(struct suspend_blocker *blocker)
 	spin_lock_irqsave(&list_lock, irqflags);
 	BUG_ON(!(blocker->flags & SB_INITIALIZED));
 
+	suspend_block_stat_locked(blocker);
 	blocker->flags |= SB_ACTIVE;
 	list_del(&blocker->link);
 	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
@@ -174,6 +343,10 @@ void suspend_block(struct suspend_blocker *blocker)
 	list_add(&blocker->link, &active_blockers);
 
 	current_event_num++;
+	if (blocker == &main_suspend_blocker)
+		update_sleep_wait_stats_locked(true);
+	else if (!is_blocking_suspend(&main_suspend_blocker))
+		update_sleep_wait_stats_locked(false);
 	spin_unlock_irqrestore(&list_lock, irqflags);
 }
 EXPORT_SYMBOL(suspend_block);
@@ -190,6 +363,8 @@ void suspend_unblock(struct suspend_blocker *blocker)
 
 	spin_lock_irqsave(&list_lock, irqflags);
 
+	suspend_unblock_stat_locked(blocker);
+
 	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
 		pr_info("suspend_unblock: %s\n", blocker->name);
 	list_del(&blocker->link);
@@ -201,6 +376,7 @@ void suspend_unblock(struct suspend_blocker *blocker)
 	if (blocker == &main_suspend_blocker) {
 		if (debug_mask & DEBUG_SUSPEND)
 			print_active_blockers_locked();
+		update_sleep_wait_stats_locked(false);
 	}
 	spin_unlock_irqrestore(&list_lock, irqflags);
 }
@@ -245,8 +421,13 @@ static int __init suspend_block_init(void)
 {
 	int ret;
 
+#ifdef CONFIG_SUSPEND_BLOCK_STAT
+	suspend_blocker_init(&deleted_suspend_blockers,
+				"deleted_suspend_blockers");
+#endif
 	suspend_blocker_init(&main_suspend_blocker, "main");
 	suspend_block(&main_suspend_blocker);
+	suspend_blocker_init(&unknown_wakeup, "unknown_wakeups");
 
 	ret = sysdev_class_register(&suspend_block_sysclass);
 	if (ret) {
@@ -265,6 +446,11 @@ static int __init suspend_block_init(void)
 		goto err_suspend_work_queue;
 	}
 
+#ifdef CONFIG_SUSPEND_BLOCK_STAT
+	create_proc_read_entry("suspend_blockers", S_IRUGO, NULL,
+				suspend_blocker_stats_read_proc, NULL);
+#endif
+
 	return 0;
 
 err_suspend_work_queue:
@@ -272,16 +458,27 @@ err_suspend_work_queue:
 err_sysdev_register:
 	sysdev_class_unregister(&suspend_block_sysclass);
 err_sysdev_class_register:
+	suspend_blocker_destroy(&unknown_wakeup);
 	suspend_blocker_destroy(&main_suspend_blocker);
+#ifdef CONFIG_SUSPEND_BLOCK_STAT
+	suspend_blocker_destroy(&deleted_suspend_blockers);
+#endif
 	return ret;
 }
 
 static void  __exit suspend_block_exit(void)
 {
+#ifdef CONFIG_SUSPEND_BLOCK_STAT
+	remove_proc_entry("suspend_blockers", NULL);
+#endif
 	destroy_workqueue(suspend_work_queue);
 	sysdev_unregister(&suspend_block_sysdev);
 	sysdev_class_unregister(&suspend_block_sysclass);
+	suspend_blocker_destroy(&unknown_wakeup);
 	suspend_blocker_destroy(&main_suspend_blocker);
+#ifdef CONFIG_SUSPEND_BLOCK_STAT
+	suspend_blocker_destroy(&deleted_suspend_blockers);
+#endif
 }
 
 core_initcall(suspend_block_init);
-- 
1.6.1

_______________________________________________
linux-pm mailing list
linux-pm@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/linux-pm

^ permalink raw reply related	[flat|nested] 93+ messages in thread

* [PATCH 7/8] PM: suspend_block: Add timeout support.
  2009-04-15  1:41           ` [PATCH 6/8] PM: suspend_block: Add suspend_blocker stats Arve Hjønnevåg
@ 2009-04-15  1:41             ` Arve Hjønnevåg
  2009-04-15  1:41               ` [PATCH 8/8] PM: suspend_block: Add timeout support to user-space suspend_blockers Arve Hjønnevåg
  0 siblings, 1 reply; 93+ messages in thread
From: Arve Hjønnevåg @ 2009-04-15  1:41 UTC (permalink / raw)
  To: linux-pm; +Cc: ncunningham, u.luckas, swetland, r-woodruff2, 

Add suspend_block_timeout to block suspend for a limited time.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
 Documentation/power/suspend-blockers.txt |   10 ++
 include/linux/suspend_block.h            |    7 +
 kernel/power/suspend_block.c             |  232 +++++++++++++++++++++++++-----
 3 files changed, 216 insertions(+), 33 deletions(-)

diff --git a/Documentation/power/suspend-blockers.txt b/Documentation/power/suspend-blockers.txt
index 35bc713..2781e05 100644
--- a/Documentation/power/suspend-blockers.txt
+++ b/Documentation/power/suspend-blockers.txt
@@ -74,6 +74,16 @@ if (list_empty(&state->pending_work))
 else
 	suspend_block(&state->suspend_blocker);
 
+A driver can also call suspend_block_timeout to release the suspend_blocker
+after a delay:
+	suspend_block_timeout(&state->suspend_blocker, HZ);
+
+This works whether the suspend_blocker is already active or not. It is useful if
+the driver woke up other parts of the system that do not use suspend_blockers
+but still need to run. Avoid this when possible, since it will waste power
+if the timeout is long or may fail to finish needed work if the timeout is
+short. Calling suspend_block or suspend_unblock will cancel the timeout.
+
 User-space API
 ==============
 
diff --git a/include/linux/suspend_block.h b/include/linux/suspend_block.h
index 31225c5..9cea772 100755
--- a/include/linux/suspend_block.h
+++ b/include/linux/suspend_block.h
@@ -27,9 +27,11 @@ struct suspend_blocker {
 	struct list_head    link;
 	int                 flags;
 	const char         *name;
+	unsigned long       expires;
 #ifdef CONFIG_SUSPEND_BLOCK_STAT
 	struct {
 		int             count;
+		int             expire_count;
 		int             wakeup_count;
 		ktime_t         total_time;
 		ktime_t         prevent_suspend_time;
@@ -45,9 +47,13 @@ struct suspend_blocker {
 void suspend_blocker_init(struct suspend_blocker *blocker, const char *name);
 void suspend_blocker_destroy(struct suspend_blocker *blocker);
 void suspend_block(struct suspend_blocker *blocker);
+void suspend_block_timeout(struct suspend_blocker *blocker, long timeout);
 void suspend_unblock(struct suspend_blocker *blocker);
 
 /* is_blocking_suspend returns true if the suspend_blocker is currently active.
+ * If the suspend_blocker has a timeout, it does not check the timeout, but if
+ * the timeout had already expired when it was checked elsewhere this function
+ * will return false.
  */
 bool is_blocking_suspend(struct suspend_blocker *blocker);
 
@@ -65,6 +71,7 @@ static inline void suspend_blocker_init(struct suspend_blocker *blocker,
 					const char *name) {}
 static inline void suspend_blocker_destroy(struct suspend_blocker *blocker) {}
 static inline void suspend_block(struct suspend_blocker *blocker) {}
+static inline void suspend_block_timeout(struct suspend_blocker *bl, long t) {}
 static inline void suspend_unblock(struct suspend_blocker *blocker) {}
 static inline bool is_blocking_suspend(struct suspend_blocker *bl) { return 0; }
 static inline bool suspend_is_blocked(void) { return 0; }
diff --git a/kernel/power/suspend_block.c b/kernel/power/suspend_block.c
index 78d5880..9414455 100644
--- a/kernel/power/suspend_block.c
+++ b/kernel/power/suspend_block.c
@@ -29,13 +29,15 @@ enum {
 	DEBUG_USER_STATE = 1U << 2,
 	DEBUG_SUSPEND = 1U << 3,
 	DEBUG_SUSPEND_BLOCKER = 1U << 4,
+	DEBUG_EXPIRE = 1U << 5,
 };
 static int debug_mask = DEBUG_EXIT_SUSPEND | DEBUG_WAKEUP | DEBUG_USER_STATE;
 module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
 
 #define SB_INITIALIZED            (1U << 8)
 #define SB_ACTIVE                 (1U << 9)
-#define SB_PREVENTING_SUSPEND     (1U << 10)
+#define SB_AUTO_EXPIRE            (1U << 10)
+#define SB_PREVENTING_SUSPEND     (1U << 11)
 
 static DEFINE_SPINLOCK(list_lock);
 static DEFINE_SPINLOCK(state_lock);
@@ -53,19 +55,53 @@ static struct suspend_blocker deleted_suspend_blockers;
 static ktime_t last_sleep_time_update;
 static bool wait_for_wakeup;
 
+static bool stats_get_expired_time(struct suspend_blocker *blocker,
+				   ktime_t *expire_time)
+{
+	struct timespec ts;
+	struct timespec kt;
+	struct timespec tomono;
+	struct timespec delta;
+	unsigned long seq;
+	long timeout;
+
+	if (!(blocker->flags & SB_AUTO_EXPIRE))
+		return false;
+	do {
+		seq = read_seqbegin(&xtime_lock);
+		timeout = blocker->expires - jiffies;
+		if (timeout > 0)
+			return false;
+		kt = current_kernel_time();
+		tomono = wall_to_monotonic;
+	} while (read_seqretry(&xtime_lock, seq));
+	jiffies_to_timespec(-timeout, &delta);
+	set_normalized_timespec(&ts, kt.tv_sec + tomono.tv_sec - delta.tv_sec,
+				kt.tv_nsec + tomono.tv_nsec - delta.tv_nsec);
+	*expire_time = timespec_to_ktime(ts);
+	return true;
+}
+
+
 static int print_blocker_stat(char *buf, struct suspend_blocker *blocker)
 {
 	int lock_count = blocker->stat.count;
+	int expire_count = blocker->stat.expire_count;
 	ktime_t active_time = ktime_set(0, 0);
 	ktime_t total_time = blocker->stat.total_time;
 	ktime_t max_time = blocker->stat.max_time;
 	ktime_t prevent_suspend_time = blocker->stat.prevent_suspend_time;
 	if (blocker->flags & SB_ACTIVE) {
 		ktime_t now, add_time;
-		now = ktime_get();
+		bool expired = stats_get_expired_time(blocker, &now);
+		if (!expired)
+			now = ktime_get();
 		add_time = ktime_sub(now, blocker->stat.last_time);
 		lock_count++;
-		active_time = add_time;
+		if (!expired)
+			active_time = add_time;
+		else
+			expire_count++;
 		total_time = ktime_add(total_time, add_time);
 		if (blocker->flags & SB_PREVENTING_SUSPEND)
 			prevent_suspend_time = ktime_add(prevent_suspend_time,
@@ -74,9 +110,10 @@ static int print_blocker_stat(char *buf, struct suspend_blocker *blocker)
 			max_time = add_time;
 	}
 
-	return sprintf(buf, "\"%s\"\t%d\t%d\t%lld\t%lld\t%lld\t%lld\t%lld\n",
-		       blocker->name, lock_count, blocker->stat.wakeup_count,
-		       ktime_to_ns(active_time), ktime_to_ns(total_time),
+	return sprintf(buf, "\"%s\"\t%d\t%d\t%d\t%lld\t%lld\t%lld\t%lld\t"
+		       "%lld\n", blocker->name, lock_count, expire_count,
+		       blocker->stat.wakeup_count, ktime_to_ns(active_time),
+		       ktime_to_ns(total_time),
 		       ktime_to_ns(prevent_suspend_time), ktime_to_ns(max_time),
 		       ktime_to_ns(blocker->stat.last_time));
 }
@@ -92,7 +129,7 @@ static int suspend_blocker_stats_read_proc(char *page, char **start, off_t off,
 
 	spin_lock_irqsave(&list_lock, irqflags);
 
-	p += sprintf(p, "name\tcount\twake_count\tactive_since"
+	p += sprintf(p, "name\tcount\texpire_count\twake_count\tactive_since"
 		     "\ttotal_time\tsleep_time\tmax_time\tlast_change\n");
 	list_for_each_entry(blocker, &inactive_blockers, link) {
 		p += print_blocker_stat(p, blocker);
@@ -115,6 +152,7 @@ static int suspend_blocker_stats_read_proc(char *page, char **start, off_t off,
 static void suspend_blocker_stat_init_locked(struct suspend_blocker *blocker)
 {
 	blocker->stat.count = 0;
+	blocker->stat.expire_count = 0;
 	blocker->stat.wakeup_count = 0;
 	blocker->stat.total_time = ktime_set(0, 0);
 	blocker->stat.prevent_suspend_time = ktime_set(0, 0);
@@ -127,6 +165,7 @@ static void suspend_blocker_stat_destroy_locked(struct suspend_blocker *bl)
 	if (!bl->stat.count)
 		return;
 	deleted_suspend_blockers.stat.count += bl->stat.count;
+	deleted_suspend_blockers.stat.expire_count += bl->stat.expire_count;
 	deleted_suspend_blockers.stat.total_time = ktime_add(
 		deleted_suspend_blockers.stat.total_time, bl->stat.total_time);
 	deleted_suspend_blockers.stat.prevent_suspend_time = ktime_add(
@@ -136,14 +175,20 @@ static void suspend_blocker_stat_destroy_locked(struct suspend_blocker *bl)
 		deleted_suspend_blockers.stat.max_time, bl->stat.max_time);
 }
 
-static void suspend_unblock_stat_locked(struct suspend_blocker *blocker)
+static void suspend_unblock_stat_locked(struct suspend_blocker *blocker,
+					bool expired)
 {
 	ktime_t duration;
 	ktime_t now;
 	if (!(blocker->flags & SB_ACTIVE))
 		return;
-	now = ktime_get();
+	if (stats_get_expired_time(blocker, &now))
+		expired = true;
+	else
+		now = ktime_get();
 	blocker->stat.count++;
+	if (expired)
+		blocker->stat.expire_count++;
 	duration = ktime_sub(now, blocker->stat.last_time);
 	blocker->stat.total_time =
 		ktime_add(blocker->stat.total_time, duration);
@@ -166,6 +211,12 @@ static void suspend_block_stat_locked(struct suspend_blocker *blocker)
 		wait_for_wakeup = false;
 		blocker->stat.wakeup_count++;
 	}
+	if ((blocker->flags & SB_AUTO_EXPIRE) &&
+	    time_is_before_eq_jiffies(blocker->expires)) {
+		suspend_unblock_stat_locked(blocker, false);
+		blocker->stat.last_time = ktime_get();
+	}
+
 	if (!(blocker->flags & SB_ACTIVE))
 		blocker->stat.last_time = ktime_get();
 }
@@ -173,17 +224,22 @@ static void suspend_block_stat_locked(struct suspend_blocker *blocker)
 static void update_sleep_wait_stats_locked(bool done)
 {
 	struct suspend_blocker *blocker;
-	ktime_t now, elapsed, add;
+	ktime_t now, etime, elapsed, add;
+	bool expired;
 
 	now = ktime_get();
 	elapsed = ktime_sub(now, last_sleep_time_update);
 	list_for_each_entry(blocker, &active_blockers, link) {
+		expired = stats_get_expired_time(blocker, &etime);
 		if (blocker->flags & SB_PREVENTING_SUSPEND) {
-			add = elapsed;
+			if (expired)
+				add = ktime_sub(etime, last_sleep_time_update);
+			else
+				add = elapsed;
 			blocker->stat.prevent_suspend_time = ktime_add(
 				blocker->stat.prevent_suspend_time, add);
 		}
-		if (done)
+		if (done || expired)
 			blocker->flags &= ~SB_PREVENTING_SUSPEND;
 		else
 			blocker->flags |= SB_PREVENTING_SUSPEND;
@@ -199,26 +255,69 @@ static inline void suspend_blocker_stat_destroy_locked(
 					struct suspend_blocker *blocker) {}
 static inline void suspend_block_stat_locked(
 					struct suspend_blocker *blocker) {}
-static inline void suspend_unblock_stat_locked(
-					struct suspend_blocker *blocker) {}
+static inline void suspend_unblock_stat_locked(struct suspend_blocker *blocker,
+					   bool expired) {}
 static inline void update_sleep_wait_stats_locked(bool done) {}
 
 #endif
 
 
+static void expire_suspend_blocker(struct suspend_blocker *blocker)
+{
+	suspend_unblock_stat_locked(blocker, true);
+	blocker->flags &= ~(SB_ACTIVE | SB_AUTO_EXPIRE);
+	list_del(&blocker->link);
+	list_add(&blocker->link, &inactive_blockers);
+	if (debug_mask & (DEBUG_SUSPEND_BLOCKER | DEBUG_EXPIRE))
+		pr_info("expired suspend blocker %s\n", blocker->name);
+}
+
 static void print_active_blockers_locked(void)
 {
 	struct suspend_blocker *blocker;
 
-	list_for_each_entry(blocker, &active_blockers, link)
-		pr_info("active suspend blocker %s\n", blocker->name);
+	list_for_each_entry(blocker, &active_blockers, link) {
+		if (blocker->flags & SB_AUTO_EXPIRE) {
+			long timeout = blocker->expires - jiffies;
+			if (timeout <= 0)
+				pr_info("suspend blocker %s, expired\n",
+					blocker->name);
+			else
+				pr_info("active suspend blocker %s, time left "
+					"%ld\n", blocker->name, timeout);
+		} else
+			pr_info("active suspend blocker %s\n", blocker->name);
+	}
+}
+
+static long max_suspend_blocker_timeout_locked(void)
+{
+	struct suspend_blocker *blocker, *n;
+	long max_timeout = 0;
+
+	list_for_each_entry_safe(blocker, n, &active_blockers, link) {
+		if (blocker->flags & SB_AUTO_EXPIRE) {
+			long timeout = blocker->expires - jiffies;
+			if (timeout <= 0)
+				expire_suspend_blocker(blocker);
+			else if (timeout > max_timeout)
+				max_timeout = timeout;
+		} else
+			return -1;
+	}
+	return max_timeout;
 }
 
 bool suspend_is_blocked(void)
 {
+	long ret;
+	unsigned long irqflags;
 	if (WARN_ONCE(!enable_suspend_blockers, "ignoring suspend blockers\n"))
 		return 0;
-	return !list_empty(&active_blockers);
+	spin_lock_irqsave(&list_lock, irqflags);
+	ret = !!max_suspend_blocker_timeout_locked();
+	spin_unlock_irqrestore(&list_lock, irqflags);
+	return ret;
 }
 
 static void suspend_worker(struct work_struct *work)
@@ -251,14 +350,49 @@ static void suspend_worker(struct work_struct *work)
 	if (current_event_num == entry_event_num) {
 		if (debug_mask & DEBUG_SUSPEND)
 			pr_info("suspend: pm_suspend returned with no event\n");
-		suspend_block(&unknown_wakeup);
-		suspend_unblock(&unknown_wakeup);
+		suspend_block_timeout(&unknown_wakeup, HZ / 2);
 	}
 abort:
 	enable_suspend_blockers = 0;
 }
 static DECLARE_WORK(suspend_work, suspend_worker);
 
+static void expire_suspend_blockers(unsigned long data)
+{
+	long timeout;
+	unsigned long irqflags;
+	if (debug_mask & DEBUG_EXPIRE)
+		pr_info("expire_suspend_blockers: start\n");
+	spin_lock_irqsave(&list_lock, irqflags);
+	if (debug_mask & DEBUG_SUSPEND)
+		print_active_blockers_locked();
+	timeout = max_suspend_blocker_timeout_locked();
+	if (debug_mask & DEBUG_EXPIRE)
+		pr_info("expire_suspend_blockers: done, timeout %ld\n",
+			timeout);
+	if (timeout == 0)
+		queue_work(suspend_work_queue, &suspend_work);
+	spin_unlock_irqrestore(&list_lock, irqflags);
+}
+static DEFINE_TIMER(expire_timer, expire_suspend_blockers, 0, 0);
+
+static void update_suspend(struct suspend_blocker *blocker, long max_timeout)
+{
+	if (max_timeout > 0) {
+		if (debug_mask & DEBUG_EXPIRE)
+			pr_info("suspend_blocker: %s, start expire timer, "
+				"%ld\n", blocker->name, max_timeout);
+		mod_timer(&expire_timer, jiffies + max_timeout);
+	} else {
+		if (del_timer(&expire_timer))
+			if (debug_mask & DEBUG_EXPIRE)
+				pr_info("suspend_blocker: %s, stop expire "
+					"timer\n", blocker->name);
+		if (max_timeout == 0)
+			queue_work(suspend_work_queue, &suspend_work);
+	}
+}
+
 static int suspend_block_suspend(struct sys_device *dev, pm_message_t state)
 {
 	int ret = suspend_is_blocked() ? -EAGAIN : 0;
@@ -318,17 +452,14 @@ void suspend_blocker_destroy(struct suspend_blocker *blocker)
 	suspend_blocker_stat_destroy_locked(blocker);
 	blocker->flags &= ~SB_INITIALIZED;
 	list_del(&blocker->link);
-	if ((blocker->flags & SB_ACTIVE) && list_empty(&active_blockers))
-		queue_work(suspend_work_queue, &suspend_work);
+	if (blocker->flags & SB_ACTIVE)
+		update_suspend(blocker, max_suspend_blocker_timeout_locked());
 	spin_unlock_irqrestore(&list_lock, irqflags);
 }
 EXPORT_SYMBOL(suspend_blocker_destroy);
 
-/**
- * suspend_block() - Block suspend
- * @blocker:	The suspend blocker to use
- */
-void suspend_block(struct suspend_blocker *blocker)
+static void __suspend_block(struct suspend_blocker *blocker, long timeout,
+			    bool has_timeout)
 {
 	unsigned long irqflags;
 
@@ -338,20 +469,56 @@ void suspend_block(struct suspend_blocker *blocker)
 	suspend_block_stat_locked(blocker);
 	blocker->flags |= SB_ACTIVE;
 	list_del(&blocker->link);
-	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
-		pr_info("suspend_block: %s\n", blocker->name);
-	list_add(&blocker->link, &active_blockers);
+	if (has_timeout) {
+		if (debug_mask & DEBUG_SUSPEND_BLOCKER)
+			pr_info("suspend_block: %s, timeout %ld.%03lu\n",
+				blocker->name, timeout / HZ,
+				(timeout % HZ) * MSEC_PER_SEC / HZ);
+		blocker->expires = jiffies + timeout;
+		blocker->flags |= SB_AUTO_EXPIRE;
+		list_add_tail(&blocker->link, &active_blockers);
+	} else {
+		if (debug_mask & DEBUG_SUSPEND_BLOCKER)
+			pr_info("suspend_block: %s\n", blocker->name);
+		blocker->expires = LONG_MAX;
+		blocker->flags &= ~SB_AUTO_EXPIRE;
+		/* Add to head so suspend_is_blocked only has to examine */
+		/* one entry */
+		list_add(&blocker->link, &active_blockers);
+	}
 
 	current_event_num++;
 	if (blocker == &main_suspend_blocker)
 		update_sleep_wait_stats_locked(true);
 	else if (!is_blocking_suspend(&main_suspend_blocker))
 		update_sleep_wait_stats_locked(false);
+	update_suspend(blocker, has_timeout ?
+			max_suspend_blocker_timeout_locked() : -1);
 	spin_unlock_irqrestore(&list_lock, irqflags);
 }
+
+/**
+ * suspend_block() - Block suspend
+ * @blocker:	The suspend blocker to use
+ */
+void suspend_block(struct suspend_blocker *blocker)
+{
+	__suspend_block(blocker, 0, false);
+}
 EXPORT_SYMBOL(suspend_block);
 
 /**
+ * suspend_block_timeout() - Block suspend for a limited time
+ * @blocker:	The suspend blocker to use.
+ * @timeout:	Timeout in jiffies before the suspend blocker auto-unblock
+ */
+void suspend_block_timeout(struct suspend_blocker *blocker, long timeout)
+{
+	__suspend_block(blocker, timeout, true);
+}
+EXPORT_SYMBOL(suspend_block_timeout);
+
+/**
  * suspend_unblock() - Unblock suspend
  * @blocker:	The suspend blocker to unblock.
  *
@@ -363,16 +530,15 @@ void suspend_unblock(struct suspend_blocker *blocker)
 
 	spin_lock_irqsave(&list_lock, irqflags);
 
-	suspend_unblock_stat_locked(blocker);
+	suspend_unblock_stat_locked(blocker, false);
 
 	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
 		pr_info("suspend_unblock: %s\n", blocker->name);
+	blocker->flags &= ~(SB_ACTIVE | SB_AUTO_EXPIRE);
 	list_del(&blocker->link);
 	list_add(&blocker->link, &inactive_blockers);
 
-	if ((blocker->flags & SB_ACTIVE) && list_empty(&active_blockers))
-		queue_work(suspend_work_queue, &suspend_work);
-	blocker->flags &= ~(SB_ACTIVE);
+	update_suspend(blocker, max_suspend_blocker_timeout_locked());
 	if (blocker == &main_suspend_blocker) {
 		if (debug_mask & DEBUG_SUSPEND)
 			print_active_blockers_locked();
-- 
1.6.1

_______________________________________________
linux-pm mailing list
linux-pm@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/linux-pm

^ permalink raw reply related	[flat|nested] 93+ messages in thread

* [PATCH 8/8] PM: suspend_block: Add timeout support to user-space suspend_blockers
  2009-04-15  1:41             ` [PATCH 7/8] PM: suspend_block: Add timeout support Arve Hjønnevåg
@ 2009-04-15  1:41               ` Arve Hjønnevåg
  0 siblings, 0 replies; 93+ messages in thread
From: Arve Hjønnevåg @ 2009-04-15  1:41 UTC (permalink / raw)
  To: linux-pm; +Cc: ncunningham, u.luckas, swetland, r-woodruff2, 

This also allows a grace period to be set where suspend is blocked for a while
if a user-space suspend_blocker is destroyed while it was active.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
 Documentation/power/suspend-blockers.txt |    7 +++++++
 include/linux/suspend_block_dev.h        |    1 +
 kernel/power/user_suspend_block.c        |   22 ++++++++++++++++++++++
 3 files changed, 30 insertions(+), 0 deletions(-)

diff --git a/Documentation/power/suspend-blockers.txt b/Documentation/power/suspend-blockers.txt
index 2781e05..890f057 100644
--- a/Documentation/power/suspend-blockers.txt
+++ b/Documentation/power/suspend-blockers.txt
@@ -94,6 +94,8 @@ then call:
 
 To activate a suspend_blocker call:
     ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK);
+or
+    ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK_TIMEOUT, &timespec_timeout);
 
 To unblock call:
     ioctl(fd, SUSPEND_BLOCKER_IOCTL_UNBLOCK);
@@ -101,3 +103,8 @@ To unblock call:
 To destroy the suspend_blocker, close the device:
     close(fd);
 
+A module parameter, unclean_exit_grace_period, can be set to allow servers
+some time to restart if they crash with an active suspend_blocker. If the
+process dies or the device is closed while the suspend_blocker is active, a
+suspend_blocker will be held for the number of seconds specified.
+
diff --git a/include/linux/suspend_block_dev.h b/include/linux/suspend_block_dev.h
index a7c0bf9..cff4943 100644
--- a/include/linux/suspend_block_dev.h
+++ b/include/linux/suspend_block_dev.h
@@ -20,6 +20,7 @@
 
 #define SUSPEND_BLOCKER_IOCTL_INIT(len)		_IOC(_IOC_WRITE, 's', 0, len)
 #define SUSPEND_BLOCKER_IOCTL_BLOCK		_IO('s', 1)
+#define SUSPEND_BLOCKER_IOCTL_BLOCK_TIMEOUT	_IOW('s', 2, struct timespec)
 #define SUSPEND_BLOCKER_IOCTL_UNBLOCK		_IO('s', 3)
 
 #endif
diff --git a/kernel/power/user_suspend_block.c b/kernel/power/user_suspend_block.c
index 782407c..1ba07dd 100644
--- a/kernel/power/user_suspend_block.c
+++ b/kernel/power/user_suspend_block.c
@@ -26,7 +26,12 @@ enum {
 static int debug_mask = DEBUG_FAILURE;
 module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
 
+static int unclean_exit_grace_period;
+module_param_named(unclean_exit_grace_period, unclean_exit_grace_period, int,
+						S_IRUGO | S_IWUSR | S_IWGRP);
+
 static DEFINE_MUTEX(ioctl_lock);
+static struct suspend_blocker unclean_exit_suspend_blocker;
 
 struct user_suspend_blocker {
 	struct suspend_blocker	blocker;
@@ -58,6 +63,8 @@ static long user_suspend_blocker_ioctl(struct file *file, unsigned int cmd,
 {
 	void __user *arg = (void __user *)_arg;
 	struct user_suspend_blocker *bl;
+	struct timespec ts;
+	unsigned long timeout;
 	long ret;
 
 	mutex_lock(&ioctl_lock);
@@ -75,6 +82,15 @@ static long user_suspend_blocker_ioctl(struct file *file, unsigned int cmd,
 		suspend_block(&bl->blocker);
 		ret = 0;
 		break;
+	case SUSPEND_BLOCKER_IOCTL_BLOCK_TIMEOUT:
+		if (copy_from_user(&ts, arg, sizeof(ts))) {
+			ret = -EFAULT;
+			goto done;
+		}
+		timeout  = timespec_to_jiffies(&ts);
+		suspend_block_timeout(&bl->blocker, timeout);
+		ret = 0;
+		break;
 	case SUSPEND_BLOCKER_IOCTL_UNBLOCK:
 		suspend_unblock(&bl->blocker);
 		ret = 0;
@@ -95,6 +111,9 @@ static int user_suspend_blocker_release(struct inode *inode, struct file *file)
 	struct user_suspend_blocker *bl = file->private_data;
 	if (!bl)
 		return 0;
+	if (is_blocking_suspend(&bl->blocker) && unclean_exit_grace_period)
+		suspend_block_timeout(&unclean_exit_suspend_blocker,
+					unclean_exit_grace_period * HZ);
 	suspend_blocker_destroy(&bl->blocker);
 	kfree(bl);
 	return 0;
@@ -113,12 +132,15 @@ struct miscdevice user_suspend_blocker_device = {
 
 static int __init user_suspend_blocker_init(void)
 {
+	suspend_blocker_init(&unclean_exit_suspend_blocker,
+				"user-unclean-exit");
 	return misc_register(&user_suspend_blocker_device);
 }
 
 static void __exit user_suspend_blocker_exit(void)
 {
 	misc_deregister(&user_suspend_blocker_device);
+	suspend_blocker_destroy(&unclean_exit_suspend_blocker);
 }
 
 module_init(user_suspend_blocker_init);
-- 
1.6.1

_______________________________________________
linux-pm mailing list
linux-pm@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/linux-pm

^ permalink raw reply related	[flat|nested] 93+ messages in thread

* Re: [PATCH 1/8] PM: Add suspend block api.
  2009-04-15  1:41 ` [PATCH 1/8] PM: Add suspend " Arve Hjønnevåg
  2009-04-15  1:41   ` [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space Arve Hjønnevåg
@ 2009-04-15 15:29   ` Alan Stern
  2009-04-15 19:08     ` mark gross
  2009-04-16  0:34     ` Arve Hjønnevåg
  2009-04-15 22:31   ` mark gross
                     ` (2 subsequent siblings)
  4 siblings, 2 replies; 93+ messages in thread
From: Alan Stern @ 2009-04-15 15:29 UTC (permalink / raw)
  To: Arve Hjønnevåg
  Cc: ncunningham, u.luckas, swetland, Linux-pm mailing list

On Tue, 14 Apr 2009, [utf-8] Arve Hjønnevåg wrote:

> +Suspend blockers can be used to allow user-space to decide which keys should
> +wake the full system up and turn the screen on.

This sentence still grates on me.  For readers not familiar with the 
embedded/phone environment, it won't make any sense.  Furthermore the 
rest of the text below doesn't even mention the screen, which will 
cause readers to wonder why it is mentioned here.

>  Use set_irq_wake or a platform
> +specific api to make sure the keypad interrupt wakes up the cpu. Once the keypad
> +driver has resumed, the sequence of events can look like this:
> +- The Keypad driver gets an interrupt. It then calls suspend_block on the
> +  keypad-scan suspend_blocker and starts scanning the keypad matrix.
> +- The keypad-scan code detects a key change and reports it to the input-event
> +  driver.
> +- The input-event driver sees the key change, enqueues an event, and calls
> +  suspend_block on the input-event-queue suspend_blocker.
> +- The keypad-scan code detects that no keys are held and calls suspend_unblock
> +  on the keypad-scan suspend_blocker.
> +- The user-space input-event thread returns from select/poll, calls
> +  suspend_block on the process-input-events suspend_blocker and then calls read
> +  on the input-event device.
> +- The input-event driver dequeues the key-event and, since the queue is now
> +  empty, it calls suspend_unblock on the input-event-queue suspend_blocker.
> +- The user-space input-event thread returns from read. It determines that the
> +  key should not wake up the full system, calls suspend_unblock on the
> +  process-input-events suspend_blocker and calls select or poll.
> +
> +                 Key pressed   Key released
> +                     |             |
> +keypad-scan          ++++++++++++++++++
> +input-event-queue        +++          +++
> +process-input-events       +++          +++

How about replacing that first sentence with something like this:

	In cell phones or other embedded systems where powering the
	screen is a significant drain on the battery, suspend blockers 
	can be used to allow user-space to decide whether a keystroke
	received while the system is suspended should cause the screen 
	to be turned back on or allow the system to go back into 
	suspend.

Then in the last section, say this:

      - The user-space input-event thread returns from read. If it 
	determines that the key should leave the screen off, it
	calls suspend_unblock on the process_input_events
	suspend_blocker and then calls select or poll.  The system
	will automatically suspend again, since now no suspend blockers
	are active.

Alan Stern

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 1/8] PM: Add suspend block api.
  2009-04-15 15:29   ` [PATCH 1/8] PM: Add suspend block api Alan Stern
@ 2009-04-15 19:08     ` mark gross
  2009-04-16  0:40       ` Arve Hjønnevåg
  2009-04-16  0:34     ` Arve Hjønnevåg
  1 sibling, 1 reply; 93+ messages in thread
From: mark gross @ 2009-04-15 19:08 UTC (permalink / raw)
  To: Alan Stern; +Cc: ncunningham, u.luckas, swetland, Linux-pm mailing list

On Wed, Apr 15, 2009 at 11:29:01AM -0400, Alan Stern wrote:
> On Tue, 14 Apr 2009, [utf-8] Arve Hjønnevåg wrote:
> 
> > +Suspend blockers can be used to allow user-space to decide which keys should
> > +wake the full system up and turn the screen on.
> 
> This sentence still grates on me.  For readers not familiar with the 
> embedded/phone environment, it won't make any sense.  Furthermore the 
> rest of the text below doesn't even mention the screen, which will 
> cause readers to wonder why it is mentioned here.
> 
> >  Use set_irq_wake or a platform
> > +specific api to make sure the keypad interrupt wakes up the cpu. Once the keypad
> > +driver has resumed, the sequence of events can look like this:
> > +- The Keypad driver gets an interrupt. It then calls suspend_block on the
> > +  keypad-scan suspend_blocker and starts scanning the keypad matrix.
> > +- The keypad-scan code detects a key change and reports it to the input-event
> > +  driver.
> > +- The input-event driver sees the key change, enqueues an event, and calls
> > +  suspend_block on the input-event-queue suspend_blocker.
> > +- The keypad-scan code detects that no keys are held and calls suspend_unblock
> > +  on the keypad-scan suspend_blocker.
> > +- The user-space input-event thread returns from select/poll, calls
> > +  suspend_block on the process-input-events suspend_blocker and then calls read
> > +  on the input-event device.
> > +- The input-event driver dequeues the key-event and, since the queue is now
> > +  empty, it calls suspend_unblock on the input-event-queue suspend_blocker.
> > +- The user-space input-event thread returns from read. It determines that the
> > +  key should not wake up the full system, calls suspend_unblock on the
> > +  process-input-events suspend_blocker and calls select or poll.
> > +
> > +                 Key pressed   Key released
> > +                     |             |
> > +keypad-scan          ++++++++++++++++++
> > +input-event-queue        +++          +++
> > +process-input-events       +++          +++
> 
> How about replacing that first sentence with something like this:
> 
> 	In cell phones or other embedded systems where powering the
> 	screen is a significant drain on the battery, suspend blockers 
> 	can be used to allow user-space to decide whether a keystroke
> 	received while the system is suspended should cause the screen 
> 	to be turned back on or allow the system to go back into 
> 	suspend.
> 
> Then in the last section, say this:
> 
>       - The user-space input-event thread returns from read. If it 
> 	determines that the key should leave the screen off, it
> 	calls suspend_unblock on the process_input_events
> 	suspend_blocker and then calls select or poll.  The system
> 	will automatically suspend again, since now no suspend blockers
> 	are active.

I'm still re-reviewing the design so I probably should keep my mouth
shut, but I only see code for constraining entry into suspend state (S3
if you will)  I didn't see code that would get called to block device
entry into higher power states just constraints on entire system entry
into sleep state.  (I apologize if I missed that code and will happily
eat my words if needed.)

more comments after I finish looking over the code.

--mgross

 

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 1/8] PM: Add suspend block api.
  2009-04-15  1:41 ` [PATCH 1/8] PM: Add suspend " Arve Hjønnevåg
  2009-04-15  1:41   ` [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space Arve Hjønnevåg
  2009-04-15 15:29   ` [PATCH 1/8] PM: Add suspend block api Alan Stern
@ 2009-04-15 22:31   ` mark gross
  2009-04-16  1:45     ` Arve Hjønnevåg
  2009-04-20  9:29   ` Pavel Machek
  2009-04-29 22:34   ` Rafael J. Wysocki
  4 siblings, 1 reply; 93+ messages in thread
From: mark gross @ 2009-04-15 22:31 UTC (permalink / raw)
  To: Arve Hjønnevåg; +Cc: ncunningham, u.luckas, swetland, linux-pm

I'm sure you are sick of this question, but couldn't you do this same
functionality (constraining entry to Suspend) using existing
infrastructure.  You are clearly aggregating a block-count and triggering
on an zero aggregate value to enter Suspend.

I'm thinking you could do something like CPUIDLE to push the implicit
suspend call and use a new pmqos parameter to keep the system alive.
We'd have to look at the API to make sure it would work in interrupt
mode.

The only thing I got from the earlier threads asking why not PMQOS, was
some complaint about the strcmp the constraint aggregation does WRT
performance.  I don't think it would be too hard to address the perceived
performance issue (even if its yet to be proven as an issue anywhere)

FWIW there is some talk of re-factoring some of pmqos to sit on top of a
constraint framework (to generalize the code a little and support
constraining things that are not really measurable in terms of latencies
or throughputs)

anyway a few comments below.

On Tue, Apr 14, 2009 at 06:41:25PM -0700, Arve Hjønnevåg wrote:
> Adds /sys/power/request_state, a non-blocking interface that specifies
> which suspend state to enter when no suspend blockers are active. A
> special state, "on", stops the process by activating the "main" suspend
> blocker.
> 
> Signed-off-by: Arve Hjønnevåg <arve@android.com>
> ---
>  Documentation/power/suspend-blockers.txt |   76 +++++++++
>  include/linux/suspend_block.h            |   61 +++++++
>  kernel/power/Kconfig                     |   10 ++
>  kernel/power/Makefile                    |    1 +
>  kernel/power/main.c                      |   62 +++++++
>  kernel/power/power.h                     |    6 +
>  kernel/power/suspend_block.c             |  257 ++++++++++++++++++++++++++++++
>  7 files changed, 473 insertions(+), 0 deletions(-)
>  create mode 100644 Documentation/power/suspend-blockers.txt
>  create mode 100755 include/linux/suspend_block.h
>  create mode 100644 kernel/power/suspend_block.c
> 
> diff --git a/Documentation/power/suspend-blockers.txt b/Documentation/power/suspend-blockers.txt
> new file mode 100644
> index 0000000..743b870
> --- /dev/null
> +++ b/Documentation/power/suspend-blockers.txt
> @@ -0,0 +1,76 @@
> +Suspend blockers
> +================
> +
> +A suspend_blocker prevents the system from entering suspend.

And trigger implicit entry into suspend when last blocker is released.

> +
> +If the suspend operation has already started when calling suspend_block on a
> +suspend_blocker, it will abort the suspend operation as long it has not already
> +reached the sysdev suspend stage. This means that calling suspend_block from an
> +interrupt handler or a freezeable thread always works, but if you call
> +block_suspend from a sysdev suspend handler you must also return an error from
> +that handler to abort suspend.
> +
> +Suspend blockers can be used to allow user-space to decide which keys should
> +wake the full system up and turn the screen on. 

Provided the user mode process controlling the screen power is in the calling
path of user-space input-event thread.

Basically it should be made clear that this is not a device PM
implementation.  Its a global system suspend constraint system, where
the count of blockers is aggregated in a static variable,
suspend_block_count, within suspend_block.c  with implicit suspend
called when block count gets to zero.

i.e. only useful in platform specific code for platforms that can do
~10ms suspends and resumes.
 
> Use set_irq_wake or a platform
> +specific api to make sure the keypad interrupt wakes up the cpu. Once the keypad
> +driver has resumed, the sequence of events can look like this:
> +- The Keypad driver gets an interrupt. It then calls suspend_block on the
> +  keypad-scan suspend_blocker and starts scanning the keypad matrix.
count = 1
> +- The keypad-scan code detects a key change and reports it to the input-event
> +  driver.
> +- The input-event driver sees the key change, enqueues an event, and calls
> +  suspend_block on the input-event-queue suspend_blocker.
count = 2
> +- The keypad-scan code detects that no keys are held and calls suspend_unblock
> +  on the keypad-scan suspend_blocker.
count = 1
> +- The user-space input-event thread returns from select/poll, calls
> +  suspend_block on the process-input-events suspend_blocker and then calls read
> +  on the input-event device.
count = 2
> +- The input-event driver dequeues the key-event and, since the queue is now
> +  empty, it calls suspend_unblock on the input-event-queue suspend_blocker.
count = 1
> +- The user-space input-event thread returns from read. It determines that the
> +  key should not wake up the full system, calls suspend_unblock on the
> +  process-input-events suspend_blocker and calls select or poll.
count = 0 + race between dropping into Suspend state and the execution
of the select or poll.  (should probably be ok)

> +
> +                 Key pressed   Key released
> +                     |             |
> +keypad-scan          ++++++++++++++++++
> +input-event-queue        +++          +++
> +process-input-events       +++          +++
> +
> +
> +Driver API
> +==========
> +
> +A driver can use the suspend block api by adding a suspend_blocker variable to
> +its state and calling suspend_blocker_init. For instance:
> +struct state {
> +	struct suspend_blocker suspend_blocker;
> +}
> +
> +init() {
> +	suspend_blocker_init(&state->suspend_blocker, "suspend-blocker-name");
> +}
> +
> +Before freeing the memory, suspend_blocker_destroy must be called:
> +
> +uninit() {
> +	suspend_blocker_destroy(&state->suspend_blocker);
> +}
> +
> +When the driver determines that it needs to run (usually in an interrupt
> +handler) it calls suspend_block:
> +	suspend_block(&state->suspend_blocker);
> +
> +When it no longer needs to run it calls suspend_unblock:
> +	suspend_unblock(&state->suspend_blocker);
> +
> +Calling suspend_block when the suspend blocker is active or suspend_unblock when
> +it is not active has no effect. This allows drivers to update their state and
> +call suspend suspend_block or suspend_unblock based on the result.
> +For instance:
> +
> +if (list_empty(&state->pending_work))
> +	suspend_unblock(&state->suspend_blocker);
> +else
> +	suspend_block(&state->suspend_blocker);
> +
> diff --git a/include/linux/suspend_block.h b/include/linux/suspend_block.h
> new file mode 100755
> index 0000000..7820c60
> --- /dev/null
> +++ b/include/linux/suspend_block.h
> @@ -0,0 +1,61 @@
> +/* include/linux/suspend_block.h
> + *
> + * Copyright (C) 2007-2009 Google, Inc.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#ifndef _LINUX_SUSPEND_BLOCK_H
> +#define _LINUX_SUSPEND_BLOCK_H
> +
> +/* A suspend_blocker prevents the system from entering suspend when active.
> + */
> +
> +struct suspend_blocker {
> +#ifdef CONFIG_SUSPEND_BLOCK
> +	atomic_t            flags;
> +	const char         *name;
> +#endif
> +};
> +
> +#ifdef CONFIG_SUSPEND_BLOCK
> +
> +void suspend_blocker_init(struct suspend_blocker *blocker, const char *name);
> +void suspend_blocker_destroy(struct suspend_blocker *blocker);
> +void suspend_block(struct suspend_blocker *blocker);
> +void suspend_unblock(struct suspend_blocker *blocker);
> +
> +/* is_blocking_suspend returns true if the suspend_blocker is currently active.
> + */
> +bool is_blocking_suspend(struct suspend_blocker *blocker);
> +
> +/* suspend_is_blocked can be used by generic power management code to abort
> + * suspend.
> + *
> + * To preserve backward compatibility suspend_is_blocked returns 0 unless it
> + * is called during suspend initiated from the suspend_block code.
> + */
> +bool suspend_is_blocked(void);
> +
> +#else
> +
> +static inline void suspend_blocker_init(struct suspend_blocker *blocker,
> +					const char *name) {}
> +static inline void suspend_blocker_destroy(struct suspend_blocker *blocker) {}
> +static inline void suspend_block(struct suspend_blocker *blocker) {}
> +static inline void suspend_unblock(struct suspend_blocker *blocker) {}
> +static inline bool is_blocking_suspend(struct suspend_blocker *bl) { return 0; }
> +static inline bool suspend_is_blocked(void) { return 0; }
> +
> +#endif
> +
> +#endif
> +
> diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
> index 23bd4da..9d1df13 100644
> --- a/kernel/power/Kconfig
> +++ b/kernel/power/Kconfig
> @@ -116,6 +116,16 @@ config SUSPEND_FREEZER
>  
>  	  Turning OFF this setting is NOT recommended! If in doubt, say Y.
>  
> +config SUSPEND_BLOCK
> +	bool "Suspend block"
> +	depends on PM
> +	select RTC_LIB
> +	default n
> +	---help---
> +	  Enable suspend_block. When user space requests a sleep state through
> +	  /sys/power/request_state, the requested sleep state will be entered
> +	  when no suspend_blockers are active.
> +
>  config HIBERNATION
>  	bool "Hibernation (aka 'suspend to disk')"
>  	depends on PM && SWAP && ARCH_HIBERNATION_POSSIBLE
> diff --git a/kernel/power/Makefile b/kernel/power/Makefile
> index 720ea4f..29cdc9e 100644
> --- a/kernel/power/Makefile
> +++ b/kernel/power/Makefile
> @@ -6,6 +6,7 @@ endif
>  obj-$(CONFIG_PM)		+= main.o
>  obj-$(CONFIG_PM_SLEEP)		+= console.o
>  obj-$(CONFIG_FREEZER)		+= process.o
> +obj-$(CONFIG_SUSPEND_BLOCK)	+= suspend_block.o
>  obj-$(CONFIG_HIBERNATION)	+= swsusp.o disk.o snapshot.o swap.o user.o
>  
>  obj-$(CONFIG_MAGIC_SYSRQ)	+= poweroff.o
> diff --git a/kernel/power/main.c b/kernel/power/main.c
> index c9632f8..e4c6b20 100644
> --- a/kernel/power/main.c
> +++ b/kernel/power/main.c
> @@ -22,6 +22,7 @@
>  #include <linux/freezer.h>
>  #include <linux/vmstat.h>
>  #include <linux/syscalls.h>
> +#include <linux/suspend_block.h>
>  
>  #include "power.h"
>  
> @@ -392,6 +393,9 @@ static void suspend_finish(void)
>  
>  
>  static const char * const pm_states[PM_SUSPEND_MAX] = {
> +#ifdef CONFIG_SUSPEND_BLOCK
> +	[PM_SUSPEND_ON]		= "on",
> +#endif
>  	[PM_SUSPEND_STANDBY]	= "standby",
>  	[PM_SUSPEND_MEM]	= "mem",
>  };
> @@ -540,6 +544,61 @@ static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
>  
>  power_attr(state);
>  
> +/**
> + *	request_state - control system power state.
> + *
> + *	This is similar to state, but it does not block until the system
> + *	resumes, and it will try to re-enter the state until another state is
> + *	requested. Suspend blockers are respected and the requested state will
> + *	only be entered when no suspend blockers are active.
> + *	Write "on" to cancel.
> + */
> +
> +#ifdef CONFIG_SUSPEND_BLOCK
> +static ssize_t request_state_show(struct kobject *kobj,
> +				  struct kobj_attribute *attr, char *buf)
> +{
> +	char *s = buf;
> +	int i;
> +
> +	for (i = 0; i < PM_SUSPEND_MAX; i++) {
> +		if (pm_states[i] && (i == PM_SUSPEND_ON || valid_state(i)))
> +			s += sprintf(s, "%s ", pm_states[i]);
> +	}
> +	if (s != buf)
> +		/* convert the last space to a newline */
> +		*(s-1) = '\n';
> +	return (s - buf);
> +}
> +
> +static ssize_t request_state_store(struct kobject *kobj,
> +				   struct kobj_attribute *attr,
> +				   const char *buf, size_t n)
> +{
> +	suspend_state_t state = PM_SUSPEND_ON;
> +	const char * const *s;
> +	char *p;
> +	int len;
> +	int error = -EINVAL;
> +
> +	p = memchr(buf, '\n', n);
> +	len = p ? p - buf : n;
> +
> +	for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {
> +		if (*s && len == strlen(*s) && !strncmp(buf, *s, len))
> +			break;
> +	}
> +	if (state < PM_SUSPEND_MAX && *s)
> +		if (state == PM_SUSPEND_ON || valid_state(state)) {
> +			error = 0;
> +			request_suspend_state(state);
> +		}
> +	return error ? error : n;
> +}
> +
> +power_attr(request_state);
> +#endif /* CONFIG_SUSPEND_BLOCK */
> +
>  #ifdef CONFIG_PM_TRACE
>  int pm_trace_enabled;
>  
> @@ -567,6 +626,9 @@ power_attr(pm_trace);
>  
>  static struct attribute * g[] = {
>  	&state_attr.attr,
> +#ifdef CONFIG_SUSPEND_BLOCK
> +	&request_state_attr.attr,
> +#endif
>  #ifdef CONFIG_PM_TRACE
>  	&pm_trace_attr.attr,
>  #endif
> diff --git a/kernel/power/power.h b/kernel/power/power.h
> index 46b5ec7..2414a74 100644
> --- a/kernel/power/power.h
> +++ b/kernel/power/power.h
> @@ -223,3 +223,9 @@ static inline void suspend_thaw_processes(void)
>  {
>  }
>  #endif
> +
> +#ifdef CONFIG_SUSPEND_BLOCK
> +/* kernel/power/suspend_block.c */
> +void request_suspend_state(suspend_state_t state);
> +#endif
> +
> diff --git a/kernel/power/suspend_block.c b/kernel/power/suspend_block.c
> new file mode 100644
> index 0000000..b4f2191
> --- /dev/null
> +++ b/kernel/power/suspend_block.c
> @@ -0,0 +1,257 @@
> +/* kernel/power/suspend_block.c
> + *
> + * Copyright (C) 2005-2008 Google, Inc.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/rtc.h>
> +#include <linux/suspend.h>
> +#include <linux/suspend_block.h>
> +#include <linux/sysdev.h>
> +#include "power.h"
> +
> +enum {
> +	DEBUG_EXIT_SUSPEND = 1U << 0,
> +	DEBUG_WAKEUP = 1U << 1,
> +	DEBUG_USER_STATE = 1U << 2,
> +	DEBUG_SUSPEND = 1U << 3,
> +	DEBUG_SUSPEND_BLOCKER = 1U << 4,
> +};
> +static int debug_mask = DEBUG_EXIT_SUSPEND | DEBUG_WAKEUP | DEBUG_USER_STATE;
> +module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
> +
> +#define SB_INITIALIZED            (1U << 8)
> +#define SB_ACTIVE                 (1U << 9)
> +
> +static DEFINE_SPINLOCK(state_lock);
> +static atomic_t suspend_block_count;

So if suspend_block_count is the lynch pin of the design, why have all
the suspend_blocker structs?  Why have all the logic around the
different suspend blocker instances?

It seems like a lot of extra effort for an atomic "stay awake" counter.


--mgross


> +static atomic_t current_event_num;
> +struct workqueue_struct *suspend_work_queue;
> +struct suspend_blocker main_suspend_blocker;
> +static suspend_state_t requested_suspend_state = PM_SUSPEND_MEM;
> +static bool enable_suspend_blockers;
> +
> +bool suspend_is_blocked(void)
> +{
> +	if (WARN_ONCE(!enable_suspend_blockers, "ignoring suspend blockers\n"))
> +		return 0;
> +	return !!atomic_read(&suspend_block_count);
> +}
> +
> +static void suspend_worker(struct work_struct *work)
> +{
> +	int ret;
> +	int entry_event_num;
> +
> +	enable_suspend_blockers = 1;
> +
> +retry:
> +	if (suspend_is_blocked()) {
> +		if (debug_mask & DEBUG_SUSPEND)
> +			pr_info("suspend: abort suspend\n");
> +		goto abort;
> +	}
> +
> +	entry_event_num = atomic_read(&current_event_num);
> +	if (debug_mask & DEBUG_SUSPEND)
> +		pr_info("suspend: enter suspend\n");
> +	ret = pm_suspend(requested_suspend_state);
> +	if (debug_mask & DEBUG_EXIT_SUSPEND) {
> +		struct timespec ts;
> +		struct rtc_time tm;
> +		getnstimeofday(&ts);
> +		rtc_time_to_tm(ts.tv_sec, &tm);
> +		pr_info("suspend: exit suspend, ret = %d "
> +			"(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", ret,
> +			tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
> +			tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
> +	}
> +	if (atomic_read(&current_event_num) == entry_event_num) {
> +		if (debug_mask & DEBUG_SUSPEND)
> +			pr_info("suspend: pm_suspend returned with no event\n");
> +		goto retry;
> +	}
> +abort:
> +	enable_suspend_blockers = 0;
> +}
> +static DECLARE_WORK(suspend_work, suspend_worker);
> +
> +static int suspend_block_suspend(struct sys_device *dev, pm_message_t state)
> +{
> +	int ret = suspend_is_blocked() ? -EAGAIN : 0;
> +	if (debug_mask & DEBUG_SUSPEND)
> +		pr_info("suspend_block_suspend return %d\n", ret);
> +	return ret;
> +}
> +
> +static struct sysdev_class suspend_block_sysclass = {
> +	.name = "suspend_block",
> +	.suspend = suspend_block_suspend,
> +};
> +static struct sys_device suspend_block_sysdev = {
> +	.cls = &suspend_block_sysclass,
> +};
> +
> +/**
> + * suspend_blocker_init() - Initialize a suspend blocker
> + * @blocker:	The suspend blocker to initialize.
> + * @name:	The name of the suspend blocker to show in
> + *		/proc/suspend_blockers
> + */
> +void suspend_blocker_init(struct suspend_blocker *blocker, const char *name)
> +{
> +	if (name)
> +		blocker->name = name;
> +	BUG_ON(!blocker->name);
> +
> +	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
> +		pr_info("suspend_blocker_init name=%s\n", blocker->name);
> +
> +	atomic_set(&blocker->flags, SB_INITIALIZED);
> +}
> +EXPORT_SYMBOL(suspend_blocker_init);
> +
> +/**
> + * suspend_blocker_destroy() - Destroy a suspend blocker
> + * @blocker:	The suspend blocker to destroy.
> + */
> +void suspend_blocker_destroy(struct suspend_blocker *blocker)
> +{
> +	int flags;
> +	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
> +		pr_info("suspend_blocker_destroy name=%s\n", blocker->name);
> +	flags = atomic_xchg(&blocker->flags, 0);
> +	WARN(!(flags & SB_INITIALIZED), "suspend_blocker_destroy called on "
> +					"uninitialized suspend_blocker\n");
> +	if (flags == (SB_INITIALIZED | SB_ACTIVE))
> +		if (atomic_dec_and_test(&suspend_block_count))
> +			queue_work(suspend_work_queue, &suspend_work);
> +}
> +EXPORT_SYMBOL(suspend_blocker_destroy);
> +
> +/**
> + * suspend_block() - Block suspend
> + * @blocker:	The suspend blocker to use
> + */
> +void suspend_block(struct suspend_blocker *blocker)
> +{
> +	BUG_ON(!(atomic_read(&blocker->flags) & SB_INITIALIZED));
> +
> +	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
> +		pr_info("suspend_block: %s\n", blocker->name);
> +	if (atomic_cmpxchg(&blocker->flags, SB_INITIALIZED,
> +	    SB_INITIALIZED | SB_ACTIVE) == SB_INITIALIZED)
> +		atomic_inc(&suspend_block_count);
> +
> +	atomic_inc(&current_event_num);
> +}
> +EXPORT_SYMBOL(suspend_block);
> +
> +/**
> + * suspend_unblock() - Unblock suspend
> + * @blocker:	The suspend blocker to unblock.
> + *
> + * If no other suspend blockers block suspend, the system will suspend.
> + */
> +void suspend_unblock(struct suspend_blocker *blocker)
> +{
> +	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
> +		pr_info("suspend_unblock: %s\n", blocker->name);
> +
> +	if (atomic_cmpxchg(&blocker->flags, SB_INITIALIZED | SB_ACTIVE,
> +	    SB_INITIALIZED) == (SB_INITIALIZED | SB_ACTIVE))
> +		if (atomic_dec_and_test(&suspend_block_count))
> +			queue_work(suspend_work_queue, &suspend_work);
> +}
> +EXPORT_SYMBOL(suspend_unblock);
> +
> +/**
> + * is_blocking_suspend() - Test if a suspend blocker is blocking suspend
> + * @blocker:	The suspend blocker to check.
> + */
> +bool is_blocking_suspend(struct suspend_blocker *blocker)
> +{
> +	return !!(atomic_read(&blocker->flags) & SB_ACTIVE);
> +}
> +EXPORT_SYMBOL(is_blocking_suspend);
> +
> +void request_suspend_state(suspend_state_t state)
> +{
> +	unsigned long irqflags;
> +	spin_lock_irqsave(&state_lock, irqflags);
> +	if (debug_mask & DEBUG_USER_STATE) {
> +		struct timespec ts;
> +		struct rtc_time tm;
> +		getnstimeofday(&ts);
> +		rtc_time_to_tm(ts.tv_sec, &tm);
> +		pr_info("request_suspend_state: %s (%d->%d) at %lld "
> +			"(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n",
> +			state != PM_SUSPEND_ON ? "sleep" : "wakeup",
> +			requested_suspend_state, state,
> +			ktime_to_ns(ktime_get()),
> +			tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
> +			tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
> +	}
> +	requested_suspend_state = state;
> +	if (state == PM_SUSPEND_ON)
> +		suspend_block(&main_suspend_blocker);
> +	else
> +		suspend_unblock(&main_suspend_blocker);
> +	spin_unlock_irqrestore(&state_lock, irqflags);
> +}
> +
> +static int __init suspend_block_init(void)
> +{
> +	int ret;
> +
> +	suspend_blocker_init(&main_suspend_blocker, "main");
> +	suspend_block(&main_suspend_blocker);
> +
> +	ret = sysdev_class_register(&suspend_block_sysclass);
> +	if (ret) {
> +		pr_err("suspend_block_init: sysdev_class_register failed\n");
> +		goto err_sysdev_class_register;
> +	}
> +	ret = sysdev_register(&suspend_block_sysdev);
> +	if (ret) {
> +		pr_err("suspend_block_init: suspend_block_sysdev failed\n");
> +		goto err_sysdev_register;
> +	}
> +
> +	suspend_work_queue = create_singlethread_workqueue("suspend");
> +	if (suspend_work_queue == NULL) {
> +		ret = -ENOMEM;
> +		goto err_suspend_work_queue;
> +	}
> +
> +	return 0;
> +
> +err_suspend_work_queue:
> +	sysdev_unregister(&suspend_block_sysdev);
> +err_sysdev_register:
> +	sysdev_class_unregister(&suspend_block_sysclass);
> +err_sysdev_class_register:
> +	suspend_blocker_destroy(&main_suspend_blocker);
> +	return ret;
> +}
> +
> +static void  __exit suspend_block_exit(void)
> +{
> +	destroy_workqueue(suspend_work_queue);
> +	sysdev_unregister(&suspend_block_sysdev);
> +	sysdev_class_unregister(&suspend_block_sysclass);
> +	suspend_blocker_destroy(&main_suspend_blocker);
> +}
> +
> +core_initcall(suspend_block_init);
> +module_exit(suspend_block_exit);
> -- 
> 1.6.1

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [RFC][PATCH 0/8] Suspend block api
  2009-04-15  1:41 [RFC][PATCH 0/8] Suspend block api Arve Hjønnevåg
  2009-04-15  1:41 ` [PATCH 1/8] PM: Add suspend " Arve Hjønnevåg
@ 2009-04-15 23:04 ` Rafael J. Wysocki
  1 sibling, 0 replies; 93+ messages in thread
From: Rafael J. Wysocki @ 2009-04-15 23:04 UTC (permalink / raw)
  To: Arve Hjønnevåg; +Cc: ncunningham, u.luckas, swetland, linux-pm

On Wednesday 15 April 2009, Arve Hjønnevåg wrote:
> This patch series adds a suspend-block api that provides the same
> functionality as the android wakelock api from my last patch series,
> Android PM extensions (version 3). As requested, wake_lock has been
> renamed to suspend_block(er), and timeout support has been separated
> into its own patch.

Sounds good.

Unfortunately, I don't have the time to review the patches in detail at the
moment.  Will to that as soon as I can.

Thanks,
Rafael
_______________________________________________
linux-pm mailing list
linux-pm@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/linux-pm

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 1/8] PM: Add suspend block api.
  2009-04-15 15:29   ` [PATCH 1/8] PM: Add suspend block api Alan Stern
  2009-04-15 19:08     ` mark gross
@ 2009-04-16  0:34     ` Arve Hjønnevåg
  1 sibling, 0 replies; 93+ messages in thread
From: Arve Hjønnevåg @ 2009-04-16  0:34 UTC (permalink / raw)
  To: Alan Stern; +Cc: ncunningham, u.luckas, swetland, Linux-pm mailing list

2009/4/15 Alan Stern <stern@rowland.harvard.edu>:
> On Tue, 14 Apr 2009, [utf-8] Arve Hjønnevåg wrote:
>
>> +Suspend blockers can be used to allow user-space to decide which keys should
>> +wake the full system up and turn the screen on.
>
> This sentence still grates on me.  For readers not familiar with the
> embedded/phone environment, it won't make any sense.  Furthermore the
> rest of the text below doesn't even mention the screen, which will
> cause readers to wonder why it is mentioned here.
>
>>  Use set_irq_wake or a platform
>> +specific api to make sure the keypad interrupt wakes up the cpu. Once the keypad
>> +driver has resumed, the sequence of events can look like this:
>> +- The Keypad driver gets an interrupt. It then calls suspend_block on the
>> +  keypad-scan suspend_blocker and starts scanning the keypad matrix.
>> +- The keypad-scan code detects a key change and reports it to the input-event
>> +  driver.
>> +- The input-event driver sees the key change, enqueues an event, and calls
>> +  suspend_block on the input-event-queue suspend_blocker.
>> +- The keypad-scan code detects that no keys are held and calls suspend_unblock
>> +  on the keypad-scan suspend_blocker.
>> +- The user-space input-event thread returns from select/poll, calls
>> +  suspend_block on the process-input-events suspend_blocker and then calls read
>> +  on the input-event device.
>> +- The input-event driver dequeues the key-event and, since the queue is now
>> +  empty, it calls suspend_unblock on the input-event-queue suspend_blocker.
>> +- The user-space input-event thread returns from read. It determines that the
>> +  key should not wake up the full system, calls suspend_unblock on the
>> +  process-input-events suspend_blocker and calls select or poll.
>> +
>> +                 Key pressed   Key released
>> +                     |             |
>> +keypad-scan          ++++++++++++++++++
>> +input-event-queue        +++          +++
>> +process-input-events       +++          +++
>
> How about replacing that first sentence with something like this:
>
>        In cell phones or other embedded systems where powering the
>        screen is a significant drain on the battery, suspend blockers
>        can be used to allow user-space to decide whether a keystroke
>        received while the system is suspended should cause the screen
>        to be turned back on or allow the system to go back into
>        suspend.
>
> Then in the last section, say this:
>
>      - The user-space input-event thread returns from read. If it
>        determines that the key should leave the screen off, it
>        calls suspend_unblock on the process_input_events
>        suspend_blocker and then calls select or poll.  The system
>        will automatically suspend again, since now no suspend blockers
>        are active.
>

This sounds reasonable too me.

-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 1/8] PM: Add suspend block api.
  2009-04-15 19:08     ` mark gross
@ 2009-04-16  0:40       ` Arve Hjønnevåg
  0 siblings, 0 replies; 93+ messages in thread
From: Arve Hjønnevåg @ 2009-04-16  0:40 UTC (permalink / raw)
  To: mgross; +Cc: ncunningham, u.luckas, swetland, Linux-pm mailing list

On Wed, Apr 15, 2009 at 12:08 PM, mark gross <mgross@linux.intel.com> wrote:
> I'm still re-reviewing the design so I probably should keep my mouth
> shut, but I only see code for constraining entry into suspend state (S3
> if you will)  I didn't see code that would get called to block device
> entry into higher power states just constraints on entire system entry
> into sleep state.  (I apologize if I missed that code and will happily
> eat my words if needed.)
>

I removed the idle wake lock type since it had too much overlap with
pm_qos. Are there any references to them left in the documentation?

-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 1/8] PM: Add suspend block api.
  2009-04-15 22:31   ` mark gross
@ 2009-04-16  1:45     ` Arve Hjønnevåg
  2009-04-16 17:49       ` mark gross
  0 siblings, 1 reply; 93+ messages in thread
From: Arve Hjønnevåg @ 2009-04-16  1:45 UTC (permalink / raw)
  To: mgross; +Cc: ncunningham, u.luckas, swetland, linux-pm

2009/4/15 mark gross <mgross@linux.intel.com>:
> I'm sure you are sick of this question, but couldn't you do this same
> functionality (constraining entry to Suspend) using existing
> infrastructure.  You are clearly aggregating a block-count and triggering
> on an zero aggregate value to enter Suspend.

The only reason I have a block count, is that the feedback on this
list was that it is too expensive to use a spin-lock every time we
want to block or unblock suspend. The later patches that enable stats
and timeout support uses inactive and active lists instead.

>
> I'm thinking you could do something like CPUIDLE to push the implicit
> suspend call and use a new pmqos parameter to keep the system alive.
> We'd have to look at the API to make sure it would work in interrupt
> mode.
>
> The only thing I got from the earlier threads asking why not PMQOS, was
> some complaint about the strcmp the constraint aggregation does WRT
> performance.  I don't think it would be too hard to address the perceived
> performance issue (even if its yet to be proven as an issue anywhere)

There was a question about why we did not use pmqos instead othe the
idle wake locks. One reason was that we mainly needed to prevent a
specific state to not loose interrupts, not because the latency was
too high. The other reason was that the pm qos interface uses strings
instead of handles. Using strings to search to a list for the item you
want to update has an impact on performance that is not hard to
measure, but it also require the clients to create unique strings.

> FWIW there is some talk of re-factoring some of pmqos to sit on top of a
> constraint framework (to generalize the code a little and support
> constraining things that are not really measurable in terms of latencies
> or throughputs)
>

That should help with replacing the idle-wake-locks.

> anyway a few comments below.
>
> On Tue, Apr 14, 2009 at 06:41:25PM -0700, Arve Hjønnevåg wrote:
>> Adds /sys/power/request_state, a non-blocking interface that specifies
>> which suspend state to enter when no suspend blockers are active. A
>> special state, "on", stops the process by activating the "main" suspend
>> blocker.
>>
>> Signed-off-by: Arve Hjønnevåg <arve@android.com>
>> ---
>>  Documentation/power/suspend-blockers.txt |   76 +++++++++
>>  include/linux/suspend_block.h            |   61 +++++++
>>  kernel/power/Kconfig                     |   10 ++
>>  kernel/power/Makefile                    |    1 +
>>  kernel/power/main.c                      |   62 +++++++
>>  kernel/power/power.h                     |    6 +
>>  kernel/power/suspend_block.c             |  257 ++++++++++++++++++++++++++++++
>>  7 files changed, 473 insertions(+), 0 deletions(-)
>>  create mode 100644 Documentation/power/suspend-blockers.txt
>>  create mode 100755 include/linux/suspend_block.h
>>  create mode 100644 kernel/power/suspend_block.c
>>
>> diff --git a/Documentation/power/suspend-blockers.txt b/Documentation/power/suspend-blockers.txt
>> new file mode 100644
>> index 0000000..743b870
>> --- /dev/null
>> +++ b/Documentation/power/suspend-blockers.txt
>> @@ -0,0 +1,76 @@
>> +Suspend blockers
>> +================
>> +
>> +A suspend_blocker prevents the system from entering suspend.
>
> And trigger implicit entry into suspend when last blocker is released.
>
>> +
>> +If the suspend operation has already started when calling suspend_block on a
>> +suspend_blocker, it will abort the suspend operation as long it has not already
>> +reached the sysdev suspend stage. This means that calling suspend_block from an
>> +interrupt handler or a freezeable thread always works, but if you call
>> +block_suspend from a sysdev suspend handler you must also return an error from
>> +that handler to abort suspend.
>> +
>> +Suspend blockers can be used to allow user-space to decide which keys should
>> +wake the full system up and turn the screen on.
>
> Provided the user mode process controlling the screen power is in the calling
> path of user-space input-event thread.

What you mean by this? Our user-space input event thread does not turn
the screen on, but translates the events and queues the translated
event on another queue. As long as all queues are protected by a
suspend blocker, there is no requirement about which thread turns the
screen on.

>
> Basically it should be made clear that this is not a device PM
> implementation.  Its a global system suspend constraint system, where
> the count of blockers is aggregated in a static variable,
> suspend_block_count, within suspend_block.c  with implicit suspend
> called when block count gets to zero.
>
> i.e. only useful in platform specific code for platforms that can do
> ~10ms suspends and resumes.

I disagree. If I have a desktop system that takes 5 seconds to wake up
from sleep, I still want the ability to auto suspend after user
inactivity, and to prevent suspend while some tasks are running.

>
>> Use set_irq_wake or a platform
>> +specific api to make sure the keypad interrupt wakes up the cpu. Once the keypad
>> +driver has resumed, the sequence of events can look like this:
>> +- The Keypad driver gets an interrupt. It then calls suspend_block on the
>> +  keypad-scan suspend_blocker and starts scanning the keypad matrix.
> count = 1
>> +- The keypad-scan code detects a key change and reports it to the input-event
>> +  driver.
>> +- The input-event driver sees the key change, enqueues an event, and calls
>> +  suspend_block on the input-event-queue suspend_blocker.
> count = 2
>> +- The keypad-scan code detects that no keys are held and calls suspend_unblock
>> +  on the keypad-scan suspend_blocker.
> count = 1
>> +- The user-space input-event thread returns from select/poll, calls
>> +  suspend_block on the process-input-events suspend_blocker and then calls read
>> +  on the input-event device.
> count = 2
>> +- The input-event driver dequeues the key-event and, since the queue is now
>> +  empty, it calls suspend_unblock on the input-event-queue suspend_blocker.
> count = 1
>> +- The user-space input-event thread returns from read. It determines that the
>> +  key should not wake up the full system, calls suspend_unblock on the
>> +  process-input-events suspend_blocker and calls select or poll.
> count = 0 + race between dropping into Suspend state and the execution
> of the select or poll.  (should probably be ok)

This is not a race condition, select or poll does not affect the
suspend blocker in the input driver to it does not matter if the poll
is called before or after suspend.

>
>> +
>> +                 Key pressed   Key released
>> +                     |             |
>> +keypad-scan          ++++++++++++++++++
>> +input-event-queue        +++          +++
>> +process-input-events       +++          +++
>> +
>> +

>> +struct suspend_blocker {
>> +#ifdef CONFIG_SUSPEND_BLOCK
>> +     atomic_t            flags;
>> +     const char         *name;
>> +#endif
>> +};
>> +
...
>> +
>> +#define SB_INITIALIZED            (1U << 8)
>> +#define SB_ACTIVE                 (1U << 9)
>> +
>> +static DEFINE_SPINLOCK(state_lock);
>> +static atomic_t suspend_block_count;
>
> So if suspend_block_count is the lynch pin of the design, why have all
> the suspend_blocker structs?  Why have all the logic around the
> different suspend blocker instances?

The suspend block structs need to be part of the api to allow stats
and/or debugging. It also ensures that a single suspend_blocker does
not change the global count by more than one. Also,
suspend_block_count is not part of the design, it is an optimization
that becomes useless when you enable stats.

>
> It seems like a lot of extra effort for an atomic "stay awake" counter.
>


-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 1/8] PM: Add suspend block api.
  2009-04-16  1:45     ` Arve Hjønnevåg
@ 2009-04-16 17:49       ` mark gross
  0 siblings, 0 replies; 93+ messages in thread
From: mark gross @ 2009-04-16 17:49 UTC (permalink / raw)
  To: Arve Hjønnevåg; +Cc: ncunningham, u.luckas, swetland, linux-pm

On Wed, Apr 15, 2009 at 06:45:00PM -0700, Arve Hjønnevåg wrote:
> 2009/4/15 mark gross <mgross@linux.intel.com>:
> > I'm sure you are sick of this question, but couldn't you do this same
> > functionality (constraining entry to Suspend) using existing
> > infrastructure.  You are clearly aggregating a block-count and triggering
> > on an zero aggregate value to enter Suspend.
> 
> The only reason I have a block count, is that the feedback on this
> list was that it is too expensive to use a spin-lock every time we
> want to block or unblock suspend. The later patches that enable stats
> and timeout support uses inactive and active lists instead.
> 
> >
> > I'm thinking you could do something like CPUIDLE to push the implicit
> > suspend call and use a new pmqos parameter to keep the system alive.
> > We'd have to look at the API to make sure it would work in interrupt
> > mode.
> >
> > The only thing I got from the earlier threads asking why not PMQOS, was
> > some complaint about the strcmp the constraint aggregation does WRT
> > performance.  I don't think it would be too hard to address the perceived
> > performance issue (even if its yet to be proven as an issue anywhere)
> 
> There was a question about why we did not use pmqos instead othe the
> idle wake locks. One reason was that we mainly needed to prevent a
> specific state to not loose interrupts, not because the latency was
> too high. The other reason was that the pm qos interface uses strings
> instead of handles. Using strings to search to a list for the item you
> want to update has an impact on performance that is not hard to
> measure, but it also require the clients to create unique strings.

really?  How many times / second was your system changing the pmqos
parameter?  If that turns out to be realistic, non-abusive use of the api
then perhaps I need to migrate pmqos to include / use handles.  

when pmqos was designed we assumed it wouldn't be hit with high
parameter change rates.  What could be a realistic upper bound on
change rate for the parameters?

> 
> > FWIW there is some talk of re-factoring some of pmqos to sit on top of a
> > constraint framework (to generalize the code a little and support
> > constraining things that are not really measurable in terms of latencies
> > or throughputs)
> >
> 
> That should help with replacing the idle-wake-locks.
> 
> > anyway a few comments below.
> >
> > On Tue, Apr 14, 2009 at 06:41:25PM -0700, Arve Hjønnevåg wrote:
> >> Adds /sys/power/request_state, a non-blocking interface that specifies
> >> which suspend state to enter when no suspend blockers are active. A
> >> special state, "on", stops the process by activating the "main" suspend
> >> blocker.
> >>
> >> Signed-off-by: Arve Hjønnevåg <arve@android.com>
> >> ---
> >>  Documentation/power/suspend-blockers.txt |   76 +++++++++
> >>  include/linux/suspend_block.h            |   61 +++++++
> >>  kernel/power/Kconfig                     |   10 ++
> >>  kernel/power/Makefile                    |    1 +
> >>  kernel/power/main.c                      |   62 +++++++
> >>  kernel/power/power.h                     |    6 +
> >>  kernel/power/suspend_block.c             |  257 ++++++++++++++++++++++++++++++
> >>  7 files changed, 473 insertions(+), 0 deletions(-)
> >>  create mode 100644 Documentation/power/suspend-blockers.txt
> >>  create mode 100755 include/linux/suspend_block.h
> >>  create mode 100644 kernel/power/suspend_block.c
> >>
> >> diff --git a/Documentation/power/suspend-blockers.txt b/Documentation/power/suspend-blockers.txt
> >> new file mode 100644
> >> index 0000000..743b870
> >> --- /dev/null
> >> +++ b/Documentation/power/suspend-blockers.txt
> >> @@ -0,0 +1,76 @@
> >> +Suspend blockers
> >> +================
> >> +
> >> +A suspend_blocker prevents the system from entering suspend.
> >
> > And trigger implicit entry into suspend when last blocker is released.
> >
> >> +
> >> +If the suspend operation has already started when calling suspend_block on a
> >> +suspend_blocker, it will abort the suspend operation as long it has not already
> >> +reached the sysdev suspend stage. This means that calling suspend_block from an
> >> +interrupt handler or a freezeable thread always works, but if you call
> >> +block_suspend from a sysdev suspend handler you must also return an error from
> >> +that handler to abort suspend.
> >> +
> >> +Suspend blockers can be used to allow user-space to decide which keys should
> >> +wake the full system up and turn the screen on.
> >
> > Provided the user mode process controlling the screen power is in the calling
> > path of user-space input-event thread.
> 
> What you mean by this? Our user-space input event thread does not turn
> the screen on, but translates the events and queues the translated
> event on another queue. As long as all queues are protected by a
> suspend blocker, there is no requirement about which thread turns the
> screen on.

I mean that to enable the promised partial system wake up ( "Suspend
blockers can be used to allow user-space to decide which keys should
wake the full system up and turn the screen on.") there is more to the
story as this API is about system level pm not device PM needed to keep
the screen off while partially waking things up before suspending again.

Perhaps an explanation on how suspend blocker can be used to partially
wake up a system without the screen coming on would help me.  Right now
I'm not seeing how that can be implemented in the context of this patch.


 
> >
> > Basically it should be made clear that this is not a device PM
> > implementation.  Its a global system suspend constraint system, where
> > the count of blockers is aggregated in a static variable,
> > suspend_block_count, within suspend_block.c  with implicit suspend
> > called when block count gets to zero.
> >
> > i.e. only useful in platform specific code for platforms that can do
> > ~10ms suspends and resumes.
> 
> I disagree. If I have a desktop system that takes 5 seconds to wake up
> from sleep, I still want the ability to auto suspend after user
> inactivity, and to prevent suspend while some tasks are running.

I guess we have this now, but the user mode implementations don't scale
to low latency and frequent suspend applications.


--mgross


> >
> >> Use set_irq_wake or a platform
> >> +specific api to make sure the keypad interrupt wakes up the cpu. Once the keypad
> >> +driver has resumed, the sequence of events can look like this:
> >> +- The Keypad driver gets an interrupt. It then calls suspend_block on the
> >> +  keypad-scan suspend_blocker and starts scanning the keypad matrix.
> > count = 1
> >> +- The keypad-scan code detects a key change and reports it to the input-event
> >> +  driver.
> >> +- The input-event driver sees the key change, enqueues an event, and calls
> >> +  suspend_block on the input-event-queue suspend_blocker.
> > count = 2
> >> +- The keypad-scan code detects that no keys are held and calls suspend_unblock
> >> +  on the keypad-scan suspend_blocker.
> > count = 1
> >> +- The user-space input-event thread returns from select/poll, calls
> >> +  suspend_block on the process-input-events suspend_blocker and then calls read
> >> +  on the input-event device.
> > count = 2
> >> +- The input-event driver dequeues the key-event and, since the queue is now
> >> +  empty, it calls suspend_unblock on the input-event-queue suspend_blocker.
> > count = 1
> >> +- The user-space input-event thread returns from read. It determines that the
> >> +  key should not wake up the full system, calls suspend_unblock on the
> >> +  process-input-events suspend_blocker and calls select or poll.
> > count = 0 + race between dropping into Suspend state and the execution
> > of the select or poll.  (should probably be ok)
> 
> This is not a race condition, select or poll does not affect the
> suspend blocker in the input driver to it does not matter if the poll
> is called before or after suspend.
> 
> >
> >> +
> >> +                 Key pressed   Key released
> >> +                     |             |
> >> +keypad-scan          ++++++++++++++++++
> >> +input-event-queue        +++          +++
> >> +process-input-events       +++          +++
> >> +
> >> +
> 
> >> +struct suspend_blocker {
> >> +#ifdef CONFIG_SUSPEND_BLOCK
> >> +     atomic_t            flags;
> >> +     const char         *name;
> >> +#endif
> >> +};
> >> +
> ...
> >> +
> >> +#define SB_INITIALIZED            (1U << 8)
> >> +#define SB_ACTIVE                 (1U << 9)
> >> +
> >> +static DEFINE_SPINLOCK(state_lock);
> >> +static atomic_t suspend_block_count;
> >
> > So if suspend_block_count is the lynch pin of the design, why have all
> > the suspend_blocker structs?  Why have all the logic around the
> > different suspend blocker instances?
> 
> The suspend block structs need to be part of the api to allow stats
> and/or debugging. It also ensures that a single suspend_blocker does
> not change the global count by more than one. Also,
> suspend_block_count is not part of the design, it is an optimization
> that becomes useless when you enable stats.
> 
> >
> > It seems like a lot of extra effort for an atomic "stay awake" counter.
> >
> 
> 
> -- 
> Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 1/8] PM: Add suspend block api.
  2009-04-15  1:41 ` [PATCH 1/8] PM: Add suspend " Arve Hjønnevåg
                     ` (2 preceding siblings ...)
  2009-04-15 22:31   ` mark gross
@ 2009-04-20  9:29   ` Pavel Machek
  2009-04-21  4:44     ` Arve Hjønnevåg
  2009-04-29 22:34   ` Rafael J. Wysocki
  4 siblings, 1 reply; 93+ messages in thread
From: Pavel Machek @ 2009-04-20  9:29 UTC (permalink / raw)
  To: Arve Hj??nnev??g; +Cc: ncunningham, u.luckas, swetland, linux-pm

Hi!


> +Driver API
> +==========
> +
> +A driver can use the suspend block api by adding a suspend_blocker variable to
> +its state and calling suspend_blocker_init. For instance:
> +struct state {
> +	struct suspend_blocker suspend_blocker;
> +}
> +
> +init() {
> +	suspend_blocker_init(&state->suspend_blocker, "suspend-blocker-name");
> +}
> +
> +Before freeing the memory, suspend_blocker_destroy must be called:
> +
> +uninit() {
> +	suspend_blocker_destroy(&state->suspend_blocker);
> +}
> +
> +When the driver determines that it needs to run (usually in an interrupt
> +handler) it calls suspend_block:
> +	suspend_block(&state->suspend_blocker);
> +
> +When it no longer needs to run it calls suspend_unblock:
> +	suspend_unblock(&state->suspend_blocker);

Sounds reasonably sane. Maybe it should be block_suspend(), because
suspend_block() sounds like... something that builds suspend, but I
guess it is good enough.

> +/* A suspend_blocker prevents the system from entering suspend when active.
> + */
> +

linuxdoc?

> +struct suspend_blocker {
> +#ifdef CONFIG_SUSPEND_BLOCK
> +	atomic_t            flags;
> +	const char         *name;
> +#endif
> +};
> +
> +#ifdef CONFIG_SUSPEND_BLOCK
> +
> +void suspend_blocker_init(struct suspend_blocker *blocker, const char *name);
> +void suspend_blocker_destroy(struct suspend_blocker *blocker);
> +void suspend_block(struct suspend_blocker *blocker);
> +void suspend_unblock(struct suspend_blocker *blocker);
> +
> +/* is_blocking_suspend returns true if the suspend_blocker is currently active.
> + */
> +bool is_blocking_suspend(struct suspend_blocker *blocker);

Same here?

> diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
> index 23bd4da..9d1df13 100644
> --- a/kernel/power/Kconfig
> +++ b/kernel/power/Kconfig
> @@ -116,6 +116,16 @@ config SUSPEND_FREEZER
>  
>  	  Turning OFF this setting is NOT recommended! If in doubt, say Y.
>  
> +config SUSPEND_BLOCK
> +	bool "Suspend block"
> +	depends on PM
> +	select RTC_LIB

Is RTC_LIB okay to select?

> @@ -392,6 +393,9 @@ static void suspend_finish(void)
>  
>  
>  static const char * const pm_states[PM_SUSPEND_MAX] = {
> +#ifdef CONFIG_SUSPEND_BLOCK
> +	[PM_SUSPEND_ON]		= "on",
> +#endif
>  	[PM_SUSPEND_STANDBY]	= "standby",
>  	[PM_SUSPEND_MEM]	= "mem",
>  };

This allows you to write "on" to the other interfaces where that makes
no sense.... right?

> +static bool enable_suspend_blockers;

Uhuh... What is this good for... except debugging?

> +bool suspend_is_blocked(void)
> +{
> +	if (WARN_ONCE(!enable_suspend_blockers, "ignoring suspend blockers\n"))
> +		return 0;
> +	return !!atomic_read(&suspend_block_count);
> +}

Yes, if enable_suspend_blockers is one, we are in deep trouble.

> +/**
> + * suspend_blocker_init() - Initialize a suspend blocker
> + * @blocker:	The suspend blocker to initialize.
> + * @name:	The name of the suspend blocker to show in
> + *		/proc/suspend_blockers

I don't think suspend_blockers should go to /proc. They are not process-related.

> +/**
> + * suspend_block() - Block suspend
> + * @blocker:	The suspend blocker to use
> + */
> +void suspend_block(struct suspend_blocker *blocker)
> +{
> +	BUG_ON(!(atomic_read(&blocker->flags) & SB_INITIALIZED));
As blocker->flags seem to be used mostly for debugging; do they have
to use "atomic"? Normally, "magic" variable is used, instead. (Single
bit is probably not enough to guard against using uninitialized
memory.)

> + * suspend_unblock() - Unblock suspend
> + * @blocker:	The suspend blocker to unblock.
> + *
> + * If no other suspend blockers block suspend, the system will suspend.
> + */
> +void suspend_unblock(struct suspend_blocker *blocker)
> +{

...BUG_ON(!(atomic_read(&blocker->flags) & SB_INITIALIZED)); ?

> +	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
> +		pr_info("suspend_unblock: %s\n", blocker->name);
> +
> +	if (atomic_cmpxchg(&blocker->flags, SB_INITIALIZED | SB_ACTIVE,
> +	    SB_INITIALIZED) == (SB_INITIALIZED | SB_ACTIVE))
> +		if (atomic_dec_and_test(&suspend_block_count))
> +			queue_work(suspend_work_queue, &suspend_work);
> +}
> +EXPORT_SYMBOL(suspend_unblock);

Uhuh... can we "loose a oportunity to suspend" here? If someone is
just updating the flags...? Is it guaranteed that if two people do
suspend_unblock at the same time, one of them will pass?

> +void request_suspend_state(suspend_state_t state)
> +{
> +	unsigned long irqflags;
> +	spin_lock_irqsave(&state_lock, irqflags);
> +	if (debug_mask & DEBUG_USER_STATE) {
> +		struct timespec ts;
> +		struct rtc_time tm;
> +		getnstimeofday(&ts);
> +		rtc_time_to_tm(ts.tv_sec, &tm);
> +		pr_info("request_suspend_state: %s (%d->%d) at %lld "
> +			"(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n",
> +			state != PM_SUSPEND_ON ? "sleep" : "wakeup",
> +			requested_suspend_state, state,
> +			ktime_to_ns(ktime_get()),
> +			tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
> +			tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);

Introduce macro for printing time?

Otherwise, it looks good...
									Pavel

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 1/8] PM: Add suspend block api.
  2009-04-20  9:29   ` Pavel Machek
@ 2009-04-21  4:44     ` Arve Hjønnevåg
  2009-04-24 20:59       ` Pavel Machek
  0 siblings, 1 reply; 93+ messages in thread
From: Arve Hjønnevåg @ 2009-04-21  4:44 UTC (permalink / raw)
  To: Pavel Machek; +Cc: ncunningham, u.luckas, swetland, linux-pm

On Mon, Apr 20, 2009 at 2:29 AM, Pavel Machek <pavel@ucw.cz> wrote:

>> +When the driver determines that it needs to run (usually in an interrupt
>> +handler) it calls suspend_block:
>> +     suspend_block(&state->suspend_blocker);
>> +
>> +When it no longer needs to run it calls suspend_unblock:
>> +     suspend_unblock(&state->suspend_blocker);
>
> Sounds reasonably sane. Maybe it should be block_suspend(), because
> suspend_block() sounds like... something that builds suspend, but I
> guess it is good enough.
>

I was trying to keep a common prefix.

>> +/* A suspend_blocker prevents the system from entering suspend when active.
>> + */
>> +
>
> linuxdoc?
>
>> +struct suspend_blocker {
>> +#ifdef CONFIG_SUSPEND_BLOCK
>> +     atomic_t            flags;
>> +     const char         *name;
>> +#endif
>> +};
>> +
>> +#ifdef CONFIG_SUSPEND_BLOCK
>> +
>> +void suspend_blocker_init(struct suspend_blocker *blocker, const char *name);
>> +void suspend_blocker_destroy(struct suspend_blocker *blocker);
>> +void suspend_block(struct suspend_blocker *blocker);
>> +void suspend_unblock(struct suspend_blocker *blocker);
>> +
>> +/* is_blocking_suspend returns true if the suspend_blocker is currently active.
>> + */
>> +bool is_blocking_suspend(struct suspend_blocker *blocker);
>
> Same here?

I moved this to the c file, see diff below.

>
>> diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
>> index 23bd4da..9d1df13 100644
>> --- a/kernel/power/Kconfig
>> +++ b/kernel/power/Kconfig
>> @@ -116,6 +116,16 @@ config SUSPEND_FREEZER
>>
>>         Turning OFF this setting is NOT recommended! If in doubt, say Y.
>>
>> +config SUSPEND_BLOCK
>> +     bool "Suspend block"
>> +     depends on PM
>> +     select RTC_LIB
>
> Is RTC_LIB okay to select?

It should be. It cannot be enabled manually.

>> @@ -392,6 +393,9 @@ static void suspend_finish(void)
>>
>>
>>  static const char * const pm_states[PM_SUSPEND_MAX] = {
>> +#ifdef CONFIG_SUSPEND_BLOCK
>> +     [PM_SUSPEND_ON]         = "on",
>> +#endif
>>       [PM_SUSPEND_STANDBY]    = "standby",
>>       [PM_SUSPEND_MEM]        = "mem",
>>  };
>
> This allows you to write "on" to the other interfaces where that makes
> no sense.... right?

state_store starts iterating at PM_SUSPEND_STANDBY, so don't think so.

>
>> +static bool enable_suspend_blockers;
>
> Uhuh... What is this good for... except debugging?

It prevents suspend blockers from affecting existing suspend and
freezing interfaces (while auto suspend is not active).

>
>> +bool suspend_is_blocked(void)
>> +{
>> +     if (WARN_ONCE(!enable_suspend_blockers, "ignoring suspend blockers\n"))
>> +             return 0;
>> +     return !!atomic_read(&suspend_block_count);
>> +}
>
> Yes, if enable_suspend_blockers is one, we are in deep trouble.

It just means that you compiled suspend blocker support into the
kernel, but used an old interface to enter suspend. It warns if
enable_suspend_blockers is 0 not 1.

>
>> +/**
>> + * suspend_blocker_init() - Initialize a suspend blocker
>> + * @blocker: The suspend blocker to initialize.
>> + * @name:    The name of the suspend blocker to show in
>> + *           /proc/suspend_blockers
>
> I don't think suspend_blockers should go to /proc. They are not process-related.

I moved that comment to the stats patch. It is still in procfs though,
as it is most similar to other procfs entries. It is not allowed under
the sysfs rules, and we do not want to enable debugfs on a production
system since it exposes some unsafe interfaces.

>
>> +/**
>> + * suspend_block() - Block suspend
>> + * @blocker: The suspend blocker to use
>> + */
>> +void suspend_block(struct suspend_blocker *blocker)
>> +{
>> +     BUG_ON(!(atomic_read(&blocker->flags) & SB_INITIALIZED));
> As blocker->flags seem to be used mostly for debugging; do they have
> to use "atomic"? Normally, "magic" variable is used, instead. (Single
> bit is probably not enough to guard against using uninitialized
> memory.)

It is mostly used to determine if the suspend blocker is already
active, so yes it has to be atomic. I could add a magic value, but a
single bit is enough to catch uninitialized global and kzalloced
members.

>
>> + * suspend_unblock() - Unblock suspend
>> + * @blocker: The suspend blocker to unblock.
>> + *
>> + * If no other suspend blockers block suspend, the system will suspend.
>> + */
>> +void suspend_unblock(struct suspend_blocker *blocker)
>> +{
>
> ...BUG_ON(!(atomic_read(&blocker->flags) & SB_INITIALIZED)); ?

Perhaps. This function does not do anything unless you have already
called suspend_block though.

>
>> +     if (debug_mask & DEBUG_SUSPEND_BLOCKER)
>> +             pr_info("suspend_unblock: %s\n", blocker->name);
>> +
>> +     if (atomic_cmpxchg(&blocker->flags, SB_INITIALIZED | SB_ACTIVE,
>> +         SB_INITIALIZED) == (SB_INITIALIZED | SB_ACTIVE))
>> +             if (atomic_dec_and_test(&suspend_block_count))
>> +                     queue_work(suspend_work_queue, &suspend_work);
>> +}
>> +EXPORT_SYMBOL(suspend_unblock);
>
> Uhuh... can we "loose a oportunity to suspend" here? If someone is
> just updating the flags...? Is it guaranteed that if two people do
> suspend_unblock at the same time, one of them will pass?

What do you mean by just updating the flags? SB_ACTIVE was either
cleared or not, if it was, then atomic_dec_and_test is called.

>
>> +void request_suspend_state(suspend_state_t state)
>> +{
>> +     unsigned long irqflags;
>> +     spin_lock_irqsave(&state_lock, irqflags);
>> +     if (debug_mask & DEBUG_USER_STATE) {
>> +             struct timespec ts;
>> +             struct rtc_time tm;
>> +             getnstimeofday(&ts);
>> +             rtc_time_to_tm(ts.tv_sec, &tm);
>> +             pr_info("request_suspend_state: %s (%d->%d) at %lld "
>> +                     "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n",
>> +                     state != PM_SUSPEND_ON ? "sleep" : "wakeup",
>> +                     requested_suspend_state, state,
>> +                     ktime_to_ns(ktime_get()),
>> +                     tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
>> +                     tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
>
> Introduce macro for printing time?

OK.

-- 
Arve Hjønnevåg

----
diff --git a/Documentation/power/suspend-blockers.txt
b/Documentation/power/suspend-blockers.txt
index 743b870..e95a507 100644
--- a/Documentation/power/suspend-blockers.txt
+++ b/Documentation/power/suspend-blockers.txt
@@ -10,10 +10,14 @@ interrupt handler or a freezeable thread always
works, but if you call
 block_suspend from a sysdev suspend handler you must also return an error from
 that handler to abort suspend.

-Suspend blockers can be used to allow user-space to decide which keys should
-wake the full system up and turn the screen on. Use set_irq_wake or a platform
-specific api to make sure the keypad interrupt wakes up the cpu. Once
the keypad
-driver has resumed, the sequence of events can look like this:
+In cell phones or other embedded systems where powering the screen is a
+significant drain on the battery, suspend blockers can be used to allow
+user-space to decide whether a keystroke received while the system is suspended
+should cause the screen to be turned back on or allow the system to
go back into
+suspend. Use set_irq_wake or a platform specific api to make sure the keypad
+interrupt wakes up the cpu. Once the keypad driver has resumed, the sequence of
+events can look like this:
+
 - The Keypad driver gets an interrupt. It then calls suspend_block on the
   keypad-scan suspend_blocker and starts scanning the keypad matrix.
 - The keypad-scan code detects a key change and reports it to the input-event
@@ -27,9 +31,11 @@ driver has resumed, the sequence of events can look
like this:
   on the input-event device.
 - The input-event driver dequeues the key-event and, since the queue is now
   empty, it calls suspend_unblock on the input-event-queue suspend_blocker.
-- The user-space input-event thread returns from read. It determines that the
-  key should not wake up the full system, calls suspend_unblock on the
-  process-input-events suspend_blocker and calls select or poll.
+- The user-space input-event thread returns from read. If it determines that
+  the key should leave the screen off, it calls suspend_unblock on the
+  process_input_events suspend_blocker and then calls select or poll. The
+  system will automatically suspend again, since now no suspend blockers are
+  active.

                  Key pressed   Key released
                      |             |
diff --git a/include/linux/suspend_block.h b/include/linux/suspend_block.h
index 7820c60..54bf9c4 100755
--- a/include/linux/suspend_block.h
+++ b/include/linux/suspend_block.h
@@ -16,7 +16,15 @@
 #ifndef _LINUX_SUSPEND_BLOCK_H
 #define _LINUX_SUSPEND_BLOCK_H

-/* A suspend_blocker prevents the system from entering suspend when active.
+/**
+ * struct suspend_blocker - the basic suspend_blocker structure
+ * @flags:     Tracks initialized and active state.
+ * @name:      Name used for debugging.
+ *
+ * When a suspend_blocker is active it prevents the system from entering
+ * suspend.
+ *
+ * The suspend_blocker structure must be initialized by suspend_blocker_init()
  */

 struct suspend_blocker {
@@ -32,17 +40,7 @@ void suspend_blocker_init(struct suspend_blocker
*blocker, const char *name);
 void suspend_blocker_destroy(struct suspend_blocker *blocker);
 void suspend_block(struct suspend_blocker *blocker);
 void suspend_unblock(struct suspend_blocker *blocker);
-
-/* is_blocking_suspend returns true if the suspend_blocker is currently active.
- */
 bool is_blocking_suspend(struct suspend_blocker *blocker);
-
-/* suspend_is_blocked can be used by generic power management code to abort
- * suspend.
- *
- * To preserve backward compatibility suspend_is_blocked returns 0 unless it
- * is called during suspend initiated from the suspend_block code.
- */
 bool suspend_is_blocked(void);

 #else
diff --git a/kernel/power/suspend_block.c b/kernel/power/suspend_block.c
index b4f2191..1adf075 100644
--- a/kernel/power/suspend_block.c
+++ b/kernel/power/suspend_block.c
@@ -41,6 +41,27 @@ struct suspend_blocker main_suspend_blocker;
 static suspend_state_t requested_suspend_state = PM_SUSPEND_MEM;
 static bool enable_suspend_blockers;

+#define pr_info_time(fmt, args...) \
+       do { \
+               struct timespec ts; \
+               struct rtc_time tm; \
+               getnstimeofday(&ts); \
+               rtc_time_to_tm(ts.tv_sec, &tm); \
+               pr_info(fmt "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n" , \
+                       args, \
+                       tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, \
+                       tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec); \
+       } while (0);
+
+/**
+ * suspend_is_blocked() - Check if suspend should be blocked
+ *
+ * suspend_is_blocked can be used by generic power management code to abort
+ * suspend.
+ *
+ * To preserve backward compatibility suspend_is_blocked returns 0 unless it
+ * is called during suspend initiated from the suspend_block code.
+ */
 bool suspend_is_blocked(void)
 {
        if (WARN_ONCE(!enable_suspend_blockers, "ignoring suspend blockers\n"))
@@ -66,16 +87,8 @@ retry:
        if (debug_mask & DEBUG_SUSPEND)
                pr_info("suspend: enter suspend\n");
        ret = pm_suspend(requested_suspend_state);
-       if (debug_mask & DEBUG_EXIT_SUSPEND) {
-               struct timespec ts;
-               struct rtc_time tm;
-               getnstimeofday(&ts);
-               rtc_time_to_tm(ts.tv_sec, &tm);
-               pr_info("suspend: exit suspend, ret = %d "
-                       "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", ret,
-                       tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
-                       tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
-       }
+       if (debug_mask & DEBUG_EXIT_SUSPEND)
+               pr_info_time("suspend: exit suspend, ret = %d ", ret);
        if (atomic_read(&current_event_num) == entry_event_num) {
                if (debug_mask & DEBUG_SUSPEND)
                        pr_info("suspend: pm_suspend returned with no event\n");
@@ -105,8 +118,7 @@ static struct sys_device suspend_block_sysdev = {
 /**
  * suspend_blocker_init() - Initialize a suspend blocker
  * @blocker:   The suspend blocker to initialize.
- * @name:      The name of the suspend blocker to show in
- *             /proc/suspend_blockers
+ * @name:      The name of the suspend blocker to show in debug messages.
  */
 void suspend_blocker_init(struct suspend_blocker *blocker, const char *name)
 {
@@ -178,6 +190,8 @@ EXPORT_SYMBOL(suspend_unblock);
 /**
  * is_blocking_suspend() - Test if a suspend blocker is blocking suspend
  * @blocker:   The suspend blocker to check.
+ *
+ * Returns true if the suspend_blocker is currently active.
  */
 bool is_blocking_suspend(struct suspend_blocker *blocker)
 {
@@ -189,19 +203,11 @@ void request_suspend_state(suspend_state_t state)
 {
        unsigned long irqflags;
        spin_lock_irqsave(&state_lock, irqflags);
-       if (debug_mask & DEBUG_USER_STATE) {
-               struct timespec ts;
-               struct rtc_time tm;
-               getnstimeofday(&ts);
-               rtc_time_to_tm(ts.tv_sec, &tm);
-               pr_info("request_suspend_state: %s (%d->%d) at %lld "
-                       "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n",
-                       state != PM_SUSPEND_ON ? "sleep" : "wakeup",
-                       requested_suspend_state, state,
-                       ktime_to_ns(ktime_get()),
-                       tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
-                       tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
-       }
+       if (debug_mask & DEBUG_USER_STATE)
+               pr_info_time("request_suspend_state: %s (%d->%d) at %lld ",
+                            state != PM_SUSPEND_ON ? "sleep" : "wakeup",
+                            requested_suspend_state, state,
+                            ktime_to_ns(ktime_get()));
        requested_suspend_state = state;
        if (state == PM_SUSPEND_ON)
                suspend_block(&main_suspend_blocker);

^ permalink raw reply related	[flat|nested] 93+ messages in thread

* Re: [PATCH 1/8] PM: Add suspend block api.
  2009-04-21  4:44     ` Arve Hjønnevåg
@ 2009-04-24 20:59       ` Pavel Machek
  2009-04-29 21:24         ` Rafael J. Wysocki
  0 siblings, 1 reply; 93+ messages in thread
From: Pavel Machek @ 2009-04-24 20:59 UTC (permalink / raw)
  To: Arve Hj?nnev?g; +Cc: ncunningham, u.luckas, swetland, linux-pm

Hi!

> >> @@ -392,6 +393,9 @@ static void suspend_finish(void)
> >>
> >>
> >>  static const char * const pm_states[PM_SUSPEND_MAX] = {
> >> +#ifdef CONFIG_SUSPEND_BLOCK
> >> +     [PM_SUSPEND_ON]         = "on",
> >> +#endif
> >>       [PM_SUSPEND_STANDBY]    = "standby",
> >>       [PM_SUSPEND_MEM]        = "mem",
> >>  };
> >
> > This allows you to write "on" to the other interfaces where that makes
> > no sense.... right?
> 
> state_store starts iterating at PM_SUSPEND_STANDBY, so don't think so.

Good.


> >> +bool suspend_is_blocked(void)
> >> +{
> >> +     if (WARN_ONCE(!enable_suspend_blockers, "ignoring suspend blockers\n"))
> >> +             return 0;
> >> +     return !!atomic_read(&suspend_block_count);
> >> +}
> >
> > Yes, if enable_suspend_blockers is one, we are in deep trouble.
> 
> It just means that you compiled suspend blocker support into the
> kernel, but used an old interface to enter suspend. It warns if
> enable_suspend_blockers is 0 not 1.

I do not think WARN_ONCE() should be that easy to trigger. WARN is
very scary animal; better use normal printk?



> >> +/**
> >> + * suspend_blocker_init() - Initialize a suspend blocker
> >> + * @blocker: The suspend blocker to initialize.
> >> + * @name:    The name of the suspend blocker to show in
> >> + *           /proc/suspend_blockers
> >
> > I don't think suspend_blockers should go to /proc. They are not process-related.
> 
> I moved that comment to the stats patch. It is still in procfs though,
> as it is most similar to other procfs entries. It is not allowed under
> the sysfs rules, and we do not want to enable debugfs on a production
> system since it exposes some unsafe interfaces.

You have to sort this out somehow. It does not belong to /proc.

									Pavel

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 1/8] PM: Add suspend block api.
  2009-04-30  0:49     ` Arve Hjønnevåg
@ 2009-04-26  9:42       ` Pavel Machek
  2009-05-02 12:17         ` Rafael J. Wysocki
  2009-05-02 12:14       ` Rafael J. Wysocki
  1 sibling, 1 reply; 93+ messages in thread
From: Pavel Machek @ 2009-04-26  9:42 UTC (permalink / raw)
  To: Arve Hj?nnev?g; +Cc: ncunningham, u.luckas, swetland, linux-pm

Hi!

> >> --- a/kernel/power/power.h
> >> +++ b/kernel/power/power.h
> >> @@ -223,3 +223,9 @@ static inline void suspend_thaw_processes(void)
> >>  {
> >>  }
> >>  #endif
> >> +
> >> +#ifdef CONFIG_SUSPEND_BLOCK
> >> +/* kernel/power/suspend_block.c */
> >> +void request_suspend_state(suspend_state_t state);
> >> +#endif
> >
> > Is the #ifdef really necessary?
> >
> 
> No, but it gives a compile error instead of a link error if you call
> request_suspend_state when it is not available so it is useful.

I believe #ifdef is too ugly and link error is really good enough.

  	  	    	     	      	       	      	   Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 1/8] PM: Add suspend block api.
  2009-04-24 20:59       ` Pavel Machek
@ 2009-04-29 21:24         ` Rafael J. Wysocki
  2009-04-29 22:52           ` Arve Hjønnevåg
  0 siblings, 1 reply; 93+ messages in thread
From: Rafael J. Wysocki @ 2009-04-29 21:24 UTC (permalink / raw)
  To: Pavel Machek; +Cc: ncunningham, u.luckas, swetland, linux-pm

On Friday 24 April 2009, Pavel Machek wrote:
> Hi!
> 
> > >> @@ -392,6 +393,9 @@ static void suspend_finish(void)
> > >>
> > >>
> > >>  static const char * const pm_states[PM_SUSPEND_MAX] = {
> > >> +#ifdef CONFIG_SUSPEND_BLOCK
> > >> +     [PM_SUSPEND_ON]         = "on",
> > >> +#endif
> > >>       [PM_SUSPEND_STANDBY]    = "standby",
> > >>       [PM_SUSPEND_MEM]        = "mem",
> > >>  };
> > >
> > > This allows you to write "on" to the other interfaces where that makes
> > > no sense.... right?
> > 
> > state_store starts iterating at PM_SUSPEND_STANDBY, so don't think so.
> 
> Good.
> 
> 
> > >> +bool suspend_is_blocked(void)
> > >> +{
> > >> +     if (WARN_ONCE(!enable_suspend_blockers, "ignoring suspend blockers\n"))
> > >> +             return 0;
> > >> +     return !!atomic_read(&suspend_block_count);
> > >> +}
> > >
> > > Yes, if enable_suspend_blockers is one, we are in deep trouble.
> > 
> > It just means that you compiled suspend blocker support into the
> > kernel, but used an old interface to enter suspend. It warns if
> > enable_suspend_blockers is 0 not 1.
> 
> I do not think WARN_ONCE() should be that easy to trigger. WARN is
> very scary animal; better use normal printk?

Yes, printk() please.

> > >> +/**
> > >> + * suspend_blocker_init() - Initialize a suspend blocker
> > >> + * @blocker: The suspend blocker to initialize.
> > >> + * @name:    The name of the suspend blocker to show in
> > >> + *           /proc/suspend_blockers
> > >
> > > I don't think suspend_blockers should go to /proc. They are not process-related.
> > 
> > I moved that comment to the stats patch. It is still in procfs though,
> > as it is most similar to other procfs entries. It is not allowed under
> > the sysfs rules, and we do not want to enable debugfs on a production
> > system since it exposes some unsafe interfaces.
> 
> You have to sort this out somehow. It does not belong to /proc.

Agreed.

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 1/8] PM: Add suspend block api.
  2009-04-15  1:41 ` [PATCH 1/8] PM: Add suspend " Arve Hjønnevåg
                     ` (3 preceding siblings ...)
  2009-04-20  9:29   ` Pavel Machek
@ 2009-04-29 22:34   ` Rafael J. Wysocki
  2009-04-29 23:45     ` Arve Hjønnevåg
  2009-04-30  0:49     ` Arve Hjønnevåg
  4 siblings, 2 replies; 93+ messages in thread
From: Rafael J. Wysocki @ 2009-04-29 22:34 UTC (permalink / raw)
  To: Arve Hjønnevåg; +Cc: ncunningham, u.luckas, swetland, linux-pm

On Wednesday 15 April 2009, Arve Hjønnevåg wrote:
> Adds /sys/power/request_state, a non-blocking interface that specifies
> which suspend state to enter when no suspend blockers are active. A
> special state, "on", stops the process by activating the "main" suspend
> blocker.

Finally I have some time to look at this more thoroughly, sorry for the long
delay.

I'll try not to repeate the others' comments, but I guess that may not be
totally avoidable.

> Signed-off-by: Arve Hjønnevåg <arve@android.com>
> ---
>  Documentation/power/suspend-blockers.txt |   76 +++++++++
>  include/linux/suspend_block.h            |   61 +++++++
>  kernel/power/Kconfig                     |   10 ++
>  kernel/power/Makefile                    |    1 +
>  kernel/power/main.c                      |   62 +++++++
>  kernel/power/power.h                     |    6 +
>  kernel/power/suspend_block.c             |  257 ++++++++++++++++++++++++++++++
>  7 files changed, 473 insertions(+), 0 deletions(-)
>  create mode 100644 Documentation/power/suspend-blockers.txt
>  create mode 100755 include/linux/suspend_block.h
>  create mode 100644 kernel/power/suspend_block.c
> 
> diff --git a/Documentation/power/suspend-blockers.txt b/Documentation/power/suspend-blockers.txt
> new file mode 100644
> index 0000000..743b870
> --- /dev/null
> +++ b/Documentation/power/suspend-blockers.txt
> @@ -0,0 +1,76 @@
> +Suspend blockers
> +================
> +
> +A suspend_blocker prevents the system from entering suspend.

I'd say "suspend blocker", without the underscore.

Also, I'd try to provide a general explanation of how this is supposed to
work here, as an introduction.  Something like:

"Suspend blockers provide a mechanism allowing device drivers and user
space processes to prevent the system from entering a sleep state, such as
the ACPI S3 state.

To use a suspend blocker, a device driver needs a struct suspend_blocker object
that has to be initialized with the help of suspend_blocker_init().  When no
longer needed, the suspend blocker must be garbage collected with the help
of suspend_blocker_destroy().

A suspend blocker is activated using suspend_block(), which prevents the
system from entering any sleep state until the suspend blocker is deactivated
with suspend_unblock().  Many suspend blockers may be used simultaneously
and the system is prevented from entering sleep states as long as at least one
of them is active."

BTW, I don't really like the names "suspend_block" and "suspend_unblock".
See below for possible alternatives.

> +If the suspend operation has already started when calling suspend_block on a
> +suspend_blocker, it will abort the suspend operation as long it has not already
> +reached the sysdev suspend stage. This means that calling suspend_block from an
> +interrupt handler or a freezeable thread always works, but if you call
> +block_suspend

Surely suspend_block() ?

> from a sysdev suspend handler you must also return an error from
> +that handler to abort suspend.

Well, if a sysdev suspend handler returns an error code, suspend will be
aborted anyway, so I'm not sure what the point in using suspend blockers from
sysdev suspend handlers really is.  Perhaps it's better to say "don't use
suspend blockers from withing sysdev suspend handlers"?

> +

I'd say "For example" here.

> +Suspend blockers can be used to allow user-space to decide which keys should
> +wake the full system up and turn the screen on. Use set_irq_wake or a platform
> +specific api to make sure the keypad interrupt wakes up the cpu. Once the keypad
> +driver has resumed, the sequence of events can look like this:
> +- The Keypad driver gets an interrupt. It then calls suspend_block on the
> +  keypad-scan suspend_blocker and starts scanning the keypad matrix.
> +- The keypad-scan code detects a key change and reports it to the input-event
> +  driver.
> +- The input-event driver sees the key change, enqueues an event, and calls
> +  suspend_block on the input-event-queue suspend_blocker.
> +- The keypad-scan code detects that no keys are held and calls suspend_unblock
> +  on the keypad-scan suspend_blocker.
> +- The user-space input-event thread returns from select/poll, calls
> +  suspend_block on the process-input-events suspend_blocker and then calls read
> +  on the input-event device.
> +- The input-event driver dequeues the key-event and, since the queue is now
> +  empty, it calls suspend_unblock on the input-event-queue suspend_blocker.
> +- The user-space input-event thread returns from read. It determines that the
> +  key should not wake up the full system, calls suspend_unblock on the
> +  process-input-events suspend_blocker and calls select or poll.
> +
> +                 Key pressed   Key released
> +                     |             |
> +keypad-scan          ++++++++++++++++++
> +input-event-queue        +++          +++
> +process-input-events       +++          +++
> +
> +
> +Driver API
> +==========
> +
> +A driver can use the suspend block api by adding a suspend_blocker variable to
> +its state and calling suspend_blocker_init. For instance:
> +struct state {
> +	struct suspend_blocker suspend_blocker;
> +}
> +
> +init() {
> +	suspend_blocker_init(&state->suspend_blocker, "suspend-blocker-name");
> +}
> +
> +Before freeing the memory, suspend_blocker_destroy must be called:
> +
> +uninit() {
> +	suspend_blocker_destroy(&state->suspend_blocker);
> +}
> +
> +When the driver determines that it needs to run (usually in an interrupt
> +handler) it calls suspend_block:
> +	suspend_block(&state->suspend_blocker);

suspend_blocker_activate() ?
suspend_blocker_enable() ?
suspend_blocker_start() ?

> +
> +When it no longer needs to run it calls suspend_unblock:
> +	suspend_unblock(&state->suspend_blocker);

suspend_blocker_deactivate() ?
suspend_blocker_disable() ?
suspend_blocker_finish() ?

> +
> +Calling suspend_block when the suspend blocker is active or suspend_unblock when
> +it is not active has no effect. This allows drivers to update their state and
> +call suspend suspend_block or suspend_unblock based on the result.
> +For instance:
> +
> +if (list_empty(&state->pending_work))
> +	suspend_unblock(&state->suspend_blocker);
> +else
> +	suspend_block(&state->suspend_blocker);
> +
> diff --git a/include/linux/suspend_block.h b/include/linux/suspend_block.h
> new file mode 100755
> index 0000000..7820c60
> --- /dev/null
> +++ b/include/linux/suspend_block.h

suspend_blockers.h perhaps?

> @@ -0,0 +1,61 @@
> +/* include/linux/suspend_block.h
> + *
> + * Copyright (C) 2007-2009 Google, Inc.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#ifndef _LINUX_SUSPEND_BLOCK_H
> +#define _LINUX_SUSPEND_BLOCK_H

SUSPEND_BLOCKERS_H ?

> +
> +/* A suspend_blocker prevents the system from entering suspend when active.
> + */
> +
> +struct suspend_blocker {
> +#ifdef CONFIG_SUSPEND_BLOCK

CONFIG_SUSPEND_BLOCKERS ?

> +	atomic_t            flags;
> +	const char         *name;
> +#endif
> +};
> +
> +#ifdef CONFIG_SUSPEND_BLOCK
> +
> +void suspend_blocker_init(struct suspend_blocker *blocker, const char *name);
> +void suspend_blocker_destroy(struct suspend_blocker *blocker);
> +void suspend_block(struct suspend_blocker *blocker);
> +void suspend_unblock(struct suspend_blocker *blocker);
> +
> +/* is_blocking_suspend returns true if the suspend_blocker is currently active.
> + */
> +bool is_blocking_suspend(struct suspend_blocker *blocker);

suspend_blocker_is_active() ?
suspend_blocker_enabled() ?

> +
> +/* suspend_is_blocked can be used by generic power management code to abort
> + * suspend.
> + *
> + * To preserve backward compatibility suspend_is_blocked returns 0 unless it
> + * is called during suspend initiated from the suspend_block code.
> + */
> +bool suspend_is_blocked(void);
> +
> +#else
> +
> +static inline void suspend_blocker_init(struct suspend_blocker *blocker,
> +					const char *name) {}
> +static inline void suspend_blocker_destroy(struct suspend_blocker *blocker) {}
> +static inline void suspend_block(struct suspend_blocker *blocker) {}
> +static inline void suspend_unblock(struct suspend_blocker *blocker) {}
> +static inline bool is_blocking_suspend(struct suspend_blocker *bl) { return 0; }
> +static inline bool suspend_is_blocked(void) { return 0; }
> +
> +#endif
> +
> +#endif
> +
> diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
> index 23bd4da..9d1df13 100644
> --- a/kernel/power/Kconfig
> +++ b/kernel/power/Kconfig
> @@ -116,6 +116,16 @@ config SUSPEND_FREEZER
>  
>  	  Turning OFF this setting is NOT recommended! If in doubt, say Y.
>  
> +config SUSPEND_BLOCK
> +	bool "Suspend block"
> +	depends on PM
> +	select RTC_LIB

depends on RTC_LIB

select doesn't really work and I don't think it ever will.

> +	default n
> +	---help---
> +	  Enable suspend_block.

Enable suspend blockers.

> When user space requests a sleep state through
> +	  /sys/power/request_state, the requested sleep state will be entered
> +	  when no suspend_blockers are active.

Well, if you don't want suspend blockers to block suspend started via
/sys/power/state, it's worth making it crystal clear in the documentation too.

> +
>  config HIBERNATION
>  	bool "Hibernation (aka 'suspend to disk')"
>  	depends on PM && SWAP && ARCH_HIBERNATION_POSSIBLE
> diff --git a/kernel/power/Makefile b/kernel/power/Makefile
> index 720ea4f..29cdc9e 100644
> --- a/kernel/power/Makefile
> +++ b/kernel/power/Makefile
> @@ -6,6 +6,7 @@ endif
>  obj-$(CONFIG_PM)		+= main.o
>  obj-$(CONFIG_PM_SLEEP)		+= console.o
>  obj-$(CONFIG_FREEZER)		+= process.o
> +obj-$(CONFIG_SUSPEND_BLOCK)	+= suspend_block.o
>  obj-$(CONFIG_HIBERNATION)	+= swsusp.o disk.o snapshot.o swap.o user.o
>  
>  obj-$(CONFIG_MAGIC_SYSRQ)	+= poweroff.o
> diff --git a/kernel/power/main.c b/kernel/power/main.c
> index c9632f8..e4c6b20 100644
> --- a/kernel/power/main.c
> +++ b/kernel/power/main.c
> @@ -22,6 +22,7 @@
>  #include <linux/freezer.h>
>  #include <linux/vmstat.h>
>  #include <linux/syscalls.h>
> +#include <linux/suspend_block.h>
>  
>  #include "power.h"
>  
> @@ -392,6 +393,9 @@ static void suspend_finish(void)
>  
>  
>  static const char * const pm_states[PM_SUSPEND_MAX] = {
> +#ifdef CONFIG_SUSPEND_BLOCK
> +	[PM_SUSPEND_ON]		= "on",
> +#endif

Why #ifdef?

>  	[PM_SUSPEND_STANDBY]	= "standby",
>  	[PM_SUSPEND_MEM]	= "mem",
>  };
> @@ -540,6 +544,61 @@ static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
>  
>  power_attr(state);
>  
> +/**
> + *	request_state - control system power state.
> + *
> + *	This is similar to state, but it does not block until the system
> + *	resumes, and it will try to re-enter the state until another state is
> + *	requested. Suspend blockers are respected and the requested state will
> + *	only be entered when no suspend blockers are active.
> + *	Write "on" to cancel.
> + */
> +
> +#ifdef CONFIG_SUSPEND_BLOCK
> +static ssize_t request_state_show(struct kobject *kobj,
> +				  struct kobj_attribute *attr, char *buf)
> +{
> +	char *s = buf;
> +	int i;
> +
> +	for (i = 0; i < PM_SUSPEND_MAX; i++) {
> +		if (pm_states[i] && (i == PM_SUSPEND_ON || valid_state(i)))
> +			s += sprintf(s, "%s ", pm_states[i]);
> +	}
> +	if (s != buf)
> +		/* convert the last space to a newline */
> +		*(s-1) = '\n';
> +	return (s - buf);
> +}
> +
> +static ssize_t request_state_store(struct kobject *kobj,
> +				   struct kobj_attribute *attr,
> +				   const char *buf, size_t n)
> +{
> +	suspend_state_t state = PM_SUSPEND_ON;
> +	const char * const *s;
> +	char *p;
> +	int len;
> +	int error = -EINVAL;
> +
> +	p = memchr(buf, '\n', n);
> +	len = p ? p - buf : n;
> +
> +	for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {
> +		if (*s && len == strlen(*s) && !strncmp(buf, *s, len))
> +			break;
> +	}
> +	if (state < PM_SUSPEND_MAX && *s)
> +		if (state == PM_SUSPEND_ON || valid_state(state)) {
> +			error = 0;
> +			request_suspend_state(state);
> +		}
> +	return error ? error : n;
> +}
> +
> +power_attr(request_state);
> +#endif /* CONFIG_SUSPEND_BLOCK */
> +
>  #ifdef CONFIG_PM_TRACE
>  int pm_trace_enabled;
>  
> @@ -567,6 +626,9 @@ power_attr(pm_trace);
>  
>  static struct attribute * g[] = {
>  	&state_attr.attr,
> +#ifdef CONFIG_SUSPEND_BLOCK
> +	&request_state_attr.attr,
> +#endif
>  #ifdef CONFIG_PM_TRACE
>  	&pm_trace_attr.attr,
>  #endif
> diff --git a/kernel/power/power.h b/kernel/power/power.h
> index 46b5ec7..2414a74 100644
> --- a/kernel/power/power.h
> +++ b/kernel/power/power.h
> @@ -223,3 +223,9 @@ static inline void suspend_thaw_processes(void)
>  {
>  }
>  #endif
> +
> +#ifdef CONFIG_SUSPEND_BLOCK
> +/* kernel/power/suspend_block.c */
> +void request_suspend_state(suspend_state_t state);
> +#endif

Is the #ifdef really necessary?

> +
> diff --git a/kernel/power/suspend_block.c b/kernel/power/suspend_block.c
> new file mode 100644
> index 0000000..b4f2191
> --- /dev/null
> +++ b/kernel/power/suspend_block.c
> @@ -0,0 +1,257 @@
> +/* kernel/power/suspend_block.c
> + *
> + * Copyright (C) 2005-2008 Google, Inc.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/rtc.h>
> +#include <linux/suspend.h>
> +#include <linux/suspend_block.h>
> +#include <linux/sysdev.h>
> +#include "power.h"
> +
> +enum {
> +	DEBUG_EXIT_SUSPEND = 1U << 0,
> +	DEBUG_WAKEUP = 1U << 1,
> +	DEBUG_USER_STATE = 1U << 2,
> +	DEBUG_SUSPEND = 1U << 3,
> +	DEBUG_SUSPEND_BLOCKER = 1U << 4,
> +};
> +static int debug_mask = DEBUG_EXIT_SUSPEND | DEBUG_WAKEUP | DEBUG_USER_STATE;
> +module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
> +
> +#define SB_INITIALIZED            (1U << 8)
> +#define SB_ACTIVE                 (1U << 9)
> +
> +static DEFINE_SPINLOCK(state_lock);
> +static atomic_t suspend_block_count;
> +static atomic_t current_event_num;
> +struct workqueue_struct *suspend_work_queue;
> +struct suspend_blocker main_suspend_blocker;
> +static suspend_state_t requested_suspend_state = PM_SUSPEND_MEM;
> +static bool enable_suspend_blockers;
> +
> +bool suspend_is_blocked(void)
> +{
> +	if (WARN_ONCE(!enable_suspend_blockers, "ignoring suspend blockers\n"))
> +		return 0;
> +	return !!atomic_read(&suspend_block_count);
> +}
> +
> +static void suspend_worker(struct work_struct *work)
> +{
> +	int ret;
> +	int entry_event_num;
> +
> +	enable_suspend_blockers = 1;

'true' instead of '1', please.

> +
> +retry:
> +	if (suspend_is_blocked()) {
> +		if (debug_mask & DEBUG_SUSPEND)
> +			pr_info("suspend: abort suspend\n");
> +		goto abort;

If that were in a loop you could just use 'break' here.

> +	}
> +
> +	entry_event_num = atomic_read(&current_event_num);
> +	if (debug_mask & DEBUG_SUSPEND)
> +		pr_info("suspend: enter suspend\n");
> +	ret = pm_suspend(requested_suspend_state);
> +	if (debug_mask & DEBUG_EXIT_SUSPEND) {
> +		struct timespec ts;
> +		struct rtc_time tm;
> +		getnstimeofday(&ts);
> +		rtc_time_to_tm(ts.tv_sec, &tm);
> +		pr_info("suspend: exit suspend, ret = %d "
> +			"(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", ret,
> +			tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
> +			tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
> +	}
> +	if (atomic_read(&current_event_num) == entry_event_num) {
> +		if (debug_mask & DEBUG_SUSPEND)
> +			pr_info("suspend: pm_suspend returned with no event\n");
> +		goto retry;

Put that into a loop and use 'continue' here?  Or use 'break' to go out of
the loop?

> +	}
> +abort:
> +	enable_suspend_blockers = 0;

'false' instead of '0', please.

> +}
> +static DECLARE_WORK(suspend_work, suspend_worker);
> +
> +static int suspend_block_suspend(struct sys_device *dev, pm_message_t state)
> +{
> +	int ret = suspend_is_blocked() ? -EAGAIN : 0;
> +	if (debug_mask & DEBUG_SUSPEND)
> +		pr_info("suspend_block_suspend return %d\n", ret);
> +	return ret;
> +}
> +
> +static struct sysdev_class suspend_block_sysclass = {
> +	.name = "suspend_block",
> +	.suspend = suspend_block_suspend,
> +};
> +static struct sys_device suspend_block_sysdev = {
> +	.cls = &suspend_block_sysclass,
> +};
> +

Hmm.  Perhaps add the suspend_is_blocked() check at the beginning of
sysdev_suspend() instead of this?  Surely you don't want to suspend
any sysdevs with any suspend blockers active, right?

> +/**
> + * suspend_blocker_init() - Initialize a suspend blocker
> + * @blocker:	The suspend blocker to initialize.
> + * @name:	The name of the suspend blocker to show in
> + *		/proc/suspend_blockers
> + */
> +void suspend_blocker_init(struct suspend_blocker *blocker, const char *name)
> +{
> +	if (name)
> +		blocker->name = name;
> +	BUG_ON(!blocker->name);

Do you really want to crash the kernel in this case?  WARN_ON() might be better IMO.

Also, this assumes that the caller won't release the memory used to store the
'name' string.  it might be a good idea to point that out in the kerneldoc
comment.

> +
> +	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
> +		pr_info("suspend_blocker_init name=%s\n", blocker->name);
> +
> +	atomic_set(&blocker->flags, SB_INITIALIZED);
> +}
> +EXPORT_SYMBOL(suspend_blocker_init);
> +
> +/**
> + * suspend_blocker_destroy() - Destroy a suspend blocker
> + * @blocker:	The suspend blocker to destroy.
> + */
> +void suspend_blocker_destroy(struct suspend_blocker *blocker)
> +{
> +	int flags;
> +	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
> +		pr_info("suspend_blocker_destroy name=%s\n", blocker->name);
> +	flags = atomic_xchg(&blocker->flags, 0);
> +	WARN(!(flags & SB_INITIALIZED), "suspend_blocker_destroy called on "
> +					"uninitialized suspend_blocker\n");
> +	if (flags == (SB_INITIALIZED | SB_ACTIVE))
> +		if (atomic_dec_and_test(&suspend_block_count))
> +			queue_work(suspend_work_queue, &suspend_work);
> +}
> +EXPORT_SYMBOL(suspend_blocker_destroy);
> +
> +/**
> + * suspend_block() - Block suspend
> + * @blocker:	The suspend blocker to use
> + */
> +void suspend_block(struct suspend_blocker *blocker)
> +{
> +	BUG_ON(!(atomic_read(&blocker->flags) & SB_INITIALIZED));

WARN_ON() and exit instead?  BUG_ON() is a bit drastic IMHO.

> +
> +	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
> +		pr_info("suspend_block: %s\n", blocker->name);
> +	if (atomic_cmpxchg(&blocker->flags, SB_INITIALIZED,
> +	    SB_INITIALIZED | SB_ACTIVE) == SB_INITIALIZED)
> +		atomic_inc(&suspend_block_count);
> +
> +	atomic_inc(&current_event_num);
> +}
> +EXPORT_SYMBOL(suspend_block);
> +
> +/**
> + * suspend_unblock() - Unblock suspend
> + * @blocker:	The suspend blocker to unblock.
> + *
> + * If no other suspend blockers block suspend, the system will suspend.
> + */
> +void suspend_unblock(struct suspend_blocker *blocker)
> +{
> +	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
> +		pr_info("suspend_unblock: %s\n", blocker->name);
> +
> +	if (atomic_cmpxchg(&blocker->flags, SB_INITIALIZED | SB_ACTIVE,
> +	    SB_INITIALIZED) == (SB_INITIALIZED | SB_ACTIVE))
> +		if (atomic_dec_and_test(&suspend_block_count))
> +			queue_work(suspend_work_queue, &suspend_work);
> +}
> +EXPORT_SYMBOL(suspend_unblock);
> +
> +/**
> + * is_blocking_suspend() - Test if a suspend blocker is blocking suspend
> + * @blocker:	The suspend blocker to check.
> + */
> +bool is_blocking_suspend(struct suspend_blocker *blocker)
> +{
> +	return !!(atomic_read(&blocker->flags) & SB_ACTIVE);

Check SB_INITIALIZED too, perhaps?  WARN_ON(!SB_INITIALIZED)?

> +}
> +EXPORT_SYMBOL(is_blocking_suspend);
> +
> +void request_suspend_state(suspend_state_t state)
> +{
> +	unsigned long irqflags;
> +	spin_lock_irqsave(&state_lock, irqflags);
> +	if (debug_mask & DEBUG_USER_STATE) {
> +		struct timespec ts;
> +		struct rtc_time tm;
> +		getnstimeofday(&ts);
> +		rtc_time_to_tm(ts.tv_sec, &tm);
> +		pr_info("request_suspend_state: %s (%d->%d) at %lld "
> +			"(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n",
> +			state != PM_SUSPEND_ON ? "sleep" : "wakeup",
> +			requested_suspend_state, state,
> +			ktime_to_ns(ktime_get()),
> +			tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
> +			tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
> +	}
> +	requested_suspend_state = state;
> +	if (state == PM_SUSPEND_ON)
> +		suspend_block(&main_suspend_blocker);
> +	else
> +		suspend_unblock(&main_suspend_blocker);
> +	spin_unlock_irqrestore(&state_lock, irqflags);
> +}
> +
> +static int __init suspend_block_init(void)
> +{
> +	int ret;
> +
> +	suspend_blocker_init(&main_suspend_blocker, "main");
> +	suspend_block(&main_suspend_blocker);
> +
> +	ret = sysdev_class_register(&suspend_block_sysclass);
> +	if (ret) {
> +		pr_err("suspend_block_init: sysdev_class_register failed\n");
> +		goto err_sysdev_class_register;
> +	}
> +	ret = sysdev_register(&suspend_block_sysdev);
> +	if (ret) {
> +		pr_err("suspend_block_init: suspend_block_sysdev failed\n");
> +		goto err_sysdev_register;
> +	}
> +
> +	suspend_work_queue = create_singlethread_workqueue("suspend");

Do we need a separate workqueue for this purpose?

> +	if (suspend_work_queue == NULL) {
> +		ret = -ENOMEM;
> +		goto err_suspend_work_queue;
> +	}
> +
> +	return 0;
> +
> +err_suspend_work_queue:
> +	sysdev_unregister(&suspend_block_sysdev);
> +err_sysdev_register:
> +	sysdev_class_unregister(&suspend_block_sysclass);
> +err_sysdev_class_register:
> +	suspend_blocker_destroy(&main_suspend_blocker);
> +	return ret;
> +}
> +
> +static void  __exit suspend_block_exit(void)
> +{
> +	destroy_workqueue(suspend_work_queue);
> +	sysdev_unregister(&suspend_block_sysdev);
> +	sysdev_class_unregister(&suspend_block_sysclass);
> +	suspend_blocker_destroy(&main_suspend_blocker);
> +}
> +
> +core_initcall(suspend_block_init);
> +module_exit(suspend_block_exit);

Thanks,
Rafael
_______________________________________________
linux-pm mailing list
linux-pm@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/linux-pm

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 1/8] PM: Add suspend block api.
  2009-04-29 21:24         ` Rafael J. Wysocki
@ 2009-04-29 22:52           ` Arve Hjønnevåg
  0 siblings, 0 replies; 93+ messages in thread
From: Arve Hjønnevåg @ 2009-04-29 22:52 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: ncunningham, u.luckas, swetland, linux-pm

On Wed, Apr 29, 2009 at 2:24 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> On Friday 24 April 2009, Pavel Machek wrote:
>> Hi!
>>
>> > >> @@ -392,6 +393,9 @@ static void suspend_finish(void)
>> > >>
>> > >>
>> > >>  static const char * const pm_states[PM_SUSPEND_MAX] = {
>> > >> +#ifdef CONFIG_SUSPEND_BLOCK
>> > >> +     [PM_SUSPEND_ON]         = "on",
>> > >> +#endif
>> > >>       [PM_SUSPEND_STANDBY]    = "standby",
>> > >>       [PM_SUSPEND_MEM]        = "mem",
>> > >>  };
>> > >
>> > > This allows you to write "on" to the other interfaces where that makes
>> > > no sense.... right?
>> >
>> > state_store starts iterating at PM_SUSPEND_STANDBY, so don't think so.
>>
>> Good.
>>
>>
>> > >> +bool suspend_is_blocked(void)
>> > >> +{
>> > >> +     if (WARN_ONCE(!enable_suspend_blockers, "ignoring suspend blockers\n"))
>> > >> +             return 0;
>> > >> +     return !!atomic_read(&suspend_block_count);
>> > >> +}
>> > >
>> > > Yes, if enable_suspend_blockers is one, we are in deep trouble.
>> >
>> > It just means that you compiled suspend blocker support into the
>> > kernel, but used an old interface to enter suspend. It warns if
>> > enable_suspend_blockers is 0 not 1.
>>
>> I do not think WARN_ONCE() should be that easy to trigger. WARN is
>> very scary animal; better use normal printk?
>
> Yes, printk() please.

Using printk instead of WARN_ONCE would be much more verbose, so I
removed it instead.

>
>> > >> +/**
>> > >> + * suspend_blocker_init() - Initialize a suspend blocker
>> > >> + * @blocker: The suspend blocker to initialize.
>> > >> + * @name:    The name of the suspend blocker to show in
>> > >> + *           /proc/suspend_blockers
>> > >
>> > > I don't think suspend_blockers should go to /proc. They are not process-related.
>> >
>> > I moved that comment to the stats patch. It is still in procfs though,
>> > as it is most similar to other procfs entries. It is not allowed under
>> > the sysfs rules, and we do not want to enable debugfs on a production
>> > system since it exposes some unsafe interfaces.
>>
>> You have to sort this out somehow. It does not belong to /proc.
>
> Agreed.

OK. I moved it to debugfs.

-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2009-04-15  1:41   ` [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space Arve Hjønnevåg
  2009-04-15  1:41     ` [PATCH 3/8] PM: suspend_block: Abort task freezing if a suspend_blocker is active Arve Hjønnevåg
@ 2009-04-29 22:52     ` Rafael J. Wysocki
  1 sibling, 0 replies; 93+ messages in thread
From: Rafael J. Wysocki @ 2009-04-29 22:52 UTC (permalink / raw)
  To: Arve Hjønnevåg; +Cc: ncunningham, u.luckas, swetland, linux-pm

On Wednesday 15 April 2009, Arve Hjønnevåg wrote:
> Adds ioctls to create a suspend_blocker, and to block and unblock suspend.
> To delete the suspend_blocker, close the device.

The changelog is minimalistic, so to speak.

Can you please describe the idea in more detail in it?

Also, perhaps you could use write() to initialize the suspend blocker?
I don't know really, it's just a thought.

You might not need ioctls() at all if you used write() like
write(name) -> initialize
write(1) -> activate
write(0) -> deactivate
write(1) -> activate
write(0) -> deactivate
etc.
read() -> check status (0 -> inactive, 1 -> active)
or something like this.

It might be extended for timeouts too. ;-)

> Signed-off-by: Arve Hjønnevåg <arve@android.com>
> ---
>  Documentation/power/suspend-blockers.txt |   17 ++++
>  include/linux/suspend_block_dev.h        |   25 ++++++
>  kernel/power/Kconfig                     |    9 ++
>  kernel/power/Makefile                    |    1 +
>  kernel/power/user_suspend_block.c        |  125 ++++++++++++++++++++++++++++++
>  5 files changed, 177 insertions(+), 0 deletions(-)
>  create mode 100644 include/linux/suspend_block_dev.h
>  create mode 100644 kernel/power/user_suspend_block.c
> 
> diff --git a/Documentation/power/suspend-blockers.txt b/Documentation/power/suspend-blockers.txt
> index 743b870..35bc713 100644
> --- a/Documentation/power/suspend-blockers.txt
> +++ b/Documentation/power/suspend-blockers.txt
> @@ -74,3 +74,20 @@ if (list_empty(&state->pending_work))
>  else
>  	suspend_block(&state->suspend_blocker);
>  
> +User-space API
> +==============
> +
> +To create a suspend_blocker from user-space, open the suspend_blocker device:
> +    fd = open("/dev/suspend_blocker", O_RDWR | O_CLOEXEC);
> +then call:
> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_INIT(strlen(name)), name);
> +
> +To activate a suspend_blocker call:
> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK);
> +
> +To unblock call:
> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_UNBLOCK);
> +
> +To destroy the suspend_blocker, close the device:
> +    close(fd);
> +
> diff --git a/include/linux/suspend_block_dev.h b/include/linux/suspend_block_dev.h
> new file mode 100644
> index 0000000..a7c0bf9
> --- /dev/null
> +++ b/include/linux/suspend_block_dev.h
> @@ -0,0 +1,25 @@
> +/* include/linux/suspend_block_dev.h
> + *
> + * Copyright (C) 2009 Google, Inc.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#ifndef _LINUX_SUSPEND_BLOCK_DEV_H
> +#define _LINUX_SUSPEND_BLOCK_DEV_H
> +
> +#include <linux/ioctl.h>
> +
> +#define SUSPEND_BLOCKER_IOCTL_INIT(len)		_IOC(_IOC_WRITE, 's', 0, len)
> +#define SUSPEND_BLOCKER_IOCTL_BLOCK		_IO('s', 1)
> +#define SUSPEND_BLOCKER_IOCTL_UNBLOCK		_IO('s', 3)
> +
> +#endif
> diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
> index 9d1df13..2cf4c4d 100644
> --- a/kernel/power/Kconfig
> +++ b/kernel/power/Kconfig
> @@ -126,6 +126,15 @@ config SUSPEND_BLOCK
>  	  /sys/power/request_state, the requested sleep state will be entered
>  	  when no suspend_blockers are active.
>  
> +config USER_SUSPEND_BLOCK
> +	bool "Userspace suspend blockers"
> +	depends on SUSPEND_BLOCK
> +	default y
> +	---help---
> +	  User-space suspend block api. Creates a misc device with ioctls
> +	  to create, block and unblock a suspend_blocker. The suspend_blocker
> +	  will be deleted when the device is closed.
> +
>  config HIBERNATION
>  	bool "Hibernation (aka 'suspend to disk')"
>  	depends on PM && SWAP && ARCH_HIBERNATION_POSSIBLE
> diff --git a/kernel/power/Makefile b/kernel/power/Makefile
> index 29cdc9e..5c524f1 100644
> --- a/kernel/power/Makefile
> +++ b/kernel/power/Makefile
> @@ -7,6 +7,7 @@ obj-$(CONFIG_PM)		+= main.o
>  obj-$(CONFIG_PM_SLEEP)		+= console.o
>  obj-$(CONFIG_FREEZER)		+= process.o
>  obj-$(CONFIG_SUSPEND_BLOCK)	+= suspend_block.o
> +obj-$(CONFIG_USER_SUSPEND_BLOCK)	+= user_suspend_block.o
>  obj-$(CONFIG_HIBERNATION)	+= swsusp.o disk.o snapshot.o swap.o user.o
>  
>  obj-$(CONFIG_MAGIC_SYSRQ)	+= poweroff.o
> diff --git a/kernel/power/user_suspend_block.c b/kernel/power/user_suspend_block.c
> new file mode 100644
> index 0000000..782407c
> --- /dev/null
> +++ b/kernel/power/user_suspend_block.c
> @@ -0,0 +1,125 @@
> +/* kernel/power/user_suspend_block.c
> + *
> + * Copyright (C) 2009 Google, Inc.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#include <linux/fs.h>
> +#include <linux/miscdevice.h>
> +#include <linux/module.h>
> +#include <linux/uaccess.h>
> +#include <linux/suspend_block.h>
> +#include <linux/suspend_block_dev.h>
> +
> +enum {
> +	DEBUG_FAILURE	= BIT(0),
> +};
> +static int debug_mask = DEBUG_FAILURE;
> +module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
> +
> +static DEFINE_MUTEX(ioctl_lock);
> +
> +struct user_suspend_blocker {
> +	struct suspend_blocker	blocker;
> +	char			name[0];
> +};
> +
> +static int create_user_suspend_blocker(struct file *file, void __user *name,
> +				 size_t name_len)
> +{
> +	struct user_suspend_blocker *bl;
> +	if (file->private_data)
> +		return -EBUSY;
> +	bl = kzalloc(sizeof(*bl) + name_len + 1, GFP_KERNEL);
> +	if (!bl)
> +		return -ENOMEM;
> +	if (copy_from_user(bl->name, name, name_len))
> +		goto err_fault;
> +	suspend_blocker_init(&bl->blocker, bl->name);
> +	file->private_data = bl;
> +	return 0;
> +
> +err_fault:
> +	kfree(bl);
> +	return -EFAULT;
> +}
> +
> +static long user_suspend_blocker_ioctl(struct file *file, unsigned int cmd,
> +				unsigned long _arg)
> +{
> +	void __user *arg = (void __user *)_arg;
> +	struct user_suspend_blocker *bl;
> +	long ret;
> +
> +	mutex_lock(&ioctl_lock);
> +	if ((cmd & ~IOCSIZE_MASK) == SUSPEND_BLOCKER_IOCTL_INIT(0)) {
> +		ret = create_user_suspend_blocker(file, arg, _IOC_SIZE(cmd));
> +		goto done;
> +	}
> +	bl = file->private_data;
> +	if (!bl) {
> +		ret = -ENOENT;
> +		goto done;
> +	}
> +	switch (cmd) {
> +	case SUSPEND_BLOCKER_IOCTL_BLOCK:
> +		suspend_block(&bl->blocker);
> +		ret = 0;
> +		break;
> +	case SUSPEND_BLOCKER_IOCTL_UNBLOCK:
> +		suspend_unblock(&bl->blocker);
> +		ret = 0;
> +		break;
> +	default:
> +		ret = -ENOTSUPP;
> +	}
> +done:
> +	if (ret && debug_mask & DEBUG_FAILURE)
> +		pr_err("user_suspend_blocker_ioctl: cmd %x failed, %ld\n",
> +			cmd, ret);
> +	mutex_unlock(&ioctl_lock);
> +	return ret;
> +}
> +
> +static int user_suspend_blocker_release(struct inode *inode, struct file *file)
> +{
> +	struct user_suspend_blocker *bl = file->private_data;
> +	if (!bl)
> +		return 0;
> +	suspend_blocker_destroy(&bl->blocker);
> +	kfree(bl);
> +	return 0;
> +}
> +
> +const struct file_operations user_suspend_blocker_fops = {
> +	.release = user_suspend_blocker_release,
> +	.unlocked_ioctl = user_suspend_blocker_ioctl,
> +};
> +
> +struct miscdevice user_suspend_blocker_device = {
> +	.minor = MISC_DYNAMIC_MINOR,
> +	.name = "suspend_blocker",
> +	.fops = &user_suspend_blocker_fops,
> +};
> +
> +static int __init user_suspend_blocker_init(void)
> +{
> +	return misc_register(&user_suspend_blocker_device);
> +}
> +
> +static void __exit user_suspend_blocker_exit(void)
> +{
> +	misc_deregister(&user_suspend_blocker_device);
> +}
> +
> +module_init(user_suspend_blocker_init);
> +module_exit(user_suspend_blocker_exit);


-- 
Everyone knows that debugging is twice as hard as writing a program
in the first place.  So if you're as clever as you can be when you write it,
how will you ever debug it? --- Brian Kernighan
_______________________________________________
linux-pm mailing list
linux-pm@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/linux-pm

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 3/8] PM: suspend_block: Abort task freezing if a suspend_blocker is active.
  2009-04-15  1:41     ` [PATCH 3/8] PM: suspend_block: Abort task freezing if a suspend_blocker is active Arve Hjønnevåg
  2009-04-15  1:41       ` [PATCH 4/8] Input: Block suspend while event queue is not empty Arve Hjønnevåg
@ 2009-04-29 22:56       ` Rafael J. Wysocki
  1 sibling, 0 replies; 93+ messages in thread
From: Rafael J. Wysocki @ 2009-04-29 22:56 UTC (permalink / raw)
  To: Arve Hjønnevåg; +Cc: ncunningham, u.luckas, swetland, linux-pm

On Wednesday 15 April 2009, Arve Hjønnevåg wrote:
> If a suspend_blocker is active, suspend will fail anyway. Since
> try_to_freeze_tasks can take up to 20 seconds to complete or fail, aborting
> as soon as someone blocks suspend (e.g. from an interrupt handler) improves
> the worst case wakeup latency.
> 
> On an older kernel where task freezing could fail for processes attached
> to a debugger, this fixed a problem where the device sometimes hung for
> 20 seconds before the screen turned on.
> 
> Signed-off-by: Arve Hjønnevåg <arve@android.com>
> ---
>  kernel/power/process.c |   23 ++++++++++++++++++-----
>  1 files changed, 18 insertions(+), 5 deletions(-)
> 
> diff --git a/kernel/power/process.c b/kernel/power/process.c
> index ca63401..76d7cdb 100644
> --- a/kernel/power/process.c
> +++ b/kernel/power/process.c
> @@ -13,6 +13,7 @@
>  #include <linux/module.h>
>  #include <linux/syscalls.h>
>  #include <linux/freezer.h>
> +#include <linux/suspend_block.h>
>  
>  /* 
>   * Timeout for stopping processes
> @@ -36,6 +37,7 @@ static int try_to_freeze_tasks(bool sig_only)
>  	struct timeval start, end;
>  	u64 elapsed_csecs64;
>  	unsigned int elapsed_csecs;
> +	unsigned int wakeup = 0;

Make it a bool, please.

>  	do_gettimeofday(&start);
>  
> @@ -62,6 +64,10 @@ static int try_to_freeze_tasks(bool sig_only)
>  		} while_each_thread(g, p);
>  		read_unlock(&tasklist_lock);
>  		yield();			/* Yield is okay here */
> +		if (todo && suspend_is_blocked()) {
> +			wakeup = 1;

'true', please.

> +			break;
> +		}
>  		if (time_after(jiffies, end_time))
>  			break;
>  	} while (todo);
> @@ -77,11 +83,18 @@ static int try_to_freeze_tasks(bool sig_only)
>  		 * and caller must call thaw_processes() if something fails),
>  		 * but it cleans up leftover PF_FREEZE requests.
>  		 */
> -		printk("\n");
> -		printk(KERN_ERR "Freezing of tasks failed after %d.%02d seconds "
> -				"(%d tasks refusing to freeze):\n",
> -				elapsed_csecs / 100, elapsed_csecs % 100, todo);
> -		show_state();
> +		if (wakeup) {
> +			printk("\n");

Why is the separate printk() necessary ?

> +			printk(KERN_ERR "Freezing of %s aborted\n",
> +					sig_only ? "user space " : "tasks ");
> +		} else {
> +			printk("\n");

Why is the separate printk() necessary ?

> +			printk(KERN_ERR
> +			       "Freezing of tasks failed after %d.%02d seconds "
> +			       "(%d tasks refusing to freeze):\n",
> +			       elapsed_csecs / 100, elapsed_csecs % 100, todo);
> +			show_state();
> +		}
>  		read_lock(&tasklist_lock);
>  		do_each_thread(g, p) {
>  			task_lock(p);


-- 
Everyone knows that debugging is twice as hard as writing a program
in the first place.  So if you're as clever as you can be when you write it,
how will you ever debug it? --- Brian Kernighan
_______________________________________________
linux-pm mailing list
linux-pm@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/linux-pm

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 1/8] PM: Add suspend block api.
  2009-04-29 22:34   ` Rafael J. Wysocki
@ 2009-04-29 23:45     ` Arve Hjønnevåg
  2009-04-30  0:49     ` Arve Hjønnevåg
  1 sibling, 0 replies; 93+ messages in thread
From: Arve Hjønnevåg @ 2009-04-29 23:45 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: ncunningham, u.luckas, swetland, linux-pm

2009/4/29 Rafael J. Wysocki <rjw@sisk.pl>:
> On Wednesday 15 April 2009, Arve Hjønnevåg wrote:
>> diff --git a/Documentation/power/suspend-blockers.txt b/Documentation/power/suspend-blockers.txt
>> new file mode 100644
>> index 0000000..743b870
>> --- /dev/null
>> +++ b/Documentation/power/suspend-blockers.txt
>> @@ -0,0 +1,76 @@
>> +Suspend blockers
>> +================
>> +
>> +A suspend_blocker prevents the system from entering suspend.
>
> I'd say "suspend blocker", without the underscore.
>
> Also, I'd try to provide a general explanation of how this is supposed to
> work here, as an introduction.  Something like:
>
> "Suspend blockers provide a mechanism allowing device drivers and user
> space processes to prevent the system from entering a sleep state, such as
> the ACPI S3 state.
>
> To use a suspend blocker, a device driver needs a struct suspend_blocker object
> that has to be initialized with the help of suspend_blocker_init().  When no
> longer needed, the suspend blocker must be garbage collected with the help
> of suspend_blocker_destroy().
>
> A suspend blocker is activated using suspend_block(), which prevents the
> system from entering any sleep state until the suspend blocker is deactivated
> with suspend_unblock().  Many suspend blockers may be used simultaneously
> and the system is prevented from entering sleep states as long as at least one
> of them is active."
>

I added most of this, see new text below.

> BTW, I don't really like the names "suspend_block" and "suspend_unblock".
> See below for possible alternatives.
>
>> +If the suspend operation has already started when calling suspend_block on a
>> +suspend_blocker, it will abort the suspend operation as long it has not already
>> +reached the sysdev suspend stage. This means that calling suspend_block from an
>> +interrupt handler or a freezeable thread always works, but if you call
>> +block_suspend
>
> Surely suspend_block() ?

Yes.

>
>> from a sysdev suspend handler you must also return an error from
>> +that handler to abort suspend.
>
> Well, if a sysdev suspend handler returns an error code, suspend will be
> aborted anyway, so I'm not sure what the point in using suspend blockers from
> sysdev suspend handlers really is.  Perhaps it's better to say "don't use
> suspend blockers from withing sysdev suspend handlers"?

You still need the suspend blocker to prevent the system from trying
to enter suspend again. I changed the text to "to abort a suspend
sequence that was already started".

>
>> +
>
> I'd say "For example" here.
>
>> +Suspend blockers can be used to allow user-space to decide which keys should
>> +wake the full system up and turn the screen on. Use set_irq_wake or a platform
>> +specific api to make sure the keypad interrupt wakes up the cpu. Once the keypad
>> +driver has resumed, the sequence of events can look like this:
>> +- The Keypad driver gets an interrupt. It then calls suspend_block on the
>> +  keypad-scan suspend_blocker and starts scanning the keypad matrix.
>> +- The keypad-scan code detects a key change and reports it to the input-event
>> +  driver.
>> +- The input-event driver sees the key change, enqueues an event, and calls
>> +  suspend_block on the input-event-queue suspend_blocker.
>> +- The keypad-scan code detects that no keys are held and calls suspend_unblock
>> +  on the keypad-scan suspend_blocker.
>> +- The user-space input-event thread returns from select/poll, calls
>> +  suspend_block on the process-input-events suspend_blocker and then calls read
>> +  on the input-event device.
>> +- The input-event driver dequeues the key-event and, since the queue is now
>> +  empty, it calls suspend_unblock on the input-event-queue suspend_blocker.
>> +- The user-space input-event thread returns from read. It determines that the
>> +  key should not wake up the full system, calls suspend_unblock on the
>> +  process-input-events suspend_blocker and calls select or poll.
>> +
>> +                 Key pressed   Key released
>> +                     |             |
>> +keypad-scan          ++++++++++++++++++
>> +input-event-queue        +++          +++
>> +process-input-events       +++          +++
>> +
>> +
>> +Driver API
>> +==========
>> +
>> +A driver can use the suspend block api by adding a suspend_blocker variable to
>> +its state and calling suspend_blocker_init. For instance:
>> +struct state {
>> +     struct suspend_blocker suspend_blocker;
>> +}
>> +
>> +init() {
>> +     suspend_blocker_init(&state->suspend_blocker, "suspend-blocker-name");
>> +}
>> +
>> +Before freeing the memory, suspend_blocker_destroy must be called:
>> +
>> +uninit() {
>> +     suspend_blocker_destroy(&state->suspend_blocker);
>> +}
>> +
>> +When the driver determines that it needs to run (usually in an interrupt
>> +handler) it calls suspend_block:
>> +     suspend_block(&state->suspend_blocker);
>
> suspend_blocker_activate() ?
> suspend_blocker_enable() ?
> suspend_blocker_start() ?
>

I don't like any of those better than suspend_block, but if there is
some agreement on what it should be changed to, I'll change it.

>> +
>> +When it no longer needs to run it calls suspend_unblock:
>> +     suspend_unblock(&state->suspend_blocker);
>
> suspend_blocker_deactivate() ?
> suspend_blocker_disable() ?
> suspend_blocker_finish() ?
>
>> +
>> +Calling suspend_block when the suspend blocker is active or suspend_unblock when
>> +it is not active has no effect. This allows drivers to update their state and
>> +call suspend suspend_block or suspend_unblock based on the result.
>> +For instance:
>> +
>> +if (list_empty(&state->pending_work))
>> +     suspend_unblock(&state->suspend_blocker);
>> +else
>> +     suspend_block(&state->suspend_blocker);
>> +


-- 
Arve Hjønnevåg


----

Suspend blockers
================

Suspend blockers provide a mechanism for device drivers and user-space processes
to prevent the system from entering suspend. Only suspend states requested
through /sys/power/request_state are prevented. Writing to /sys/power/state
will ignore suspend blockers, and sleep states entered from idle are unaffected.

To use a suspend blocker, a device driver needs a struct suspend_blocker object
that has to be initialized with suspend_blocker_init. When no longer needed,
the suspend blocker must be destroyed with suspend_blocker_destroy.

A suspend blocker is activated using suspend_block, which prevents the system
from entering suspend until the suspend blocker is deactivated with
suspend_unblock. Many suspend blockers may be used simultaneously, and the
system is prevented from entering suspend as long as at least one of them is
active.

If the suspend operation has already started when calling suspend_block on a
suspend_blocker, it will abort the suspend operation as long it has not already
reached the sysdev suspend stage. This means that calling suspend_block from an
interrupt handler or a freezeable thread always works, but if you call
suspend_block from a sysdev suspend handler you must also return an error from
that handler to abort a suspend sequence that was already started.

In cell phones or other embedded systems where powering the screen is a
significant drain on the battery, suspend blockers can be used to allow
user-space to decide whether a keystroke received while the system is suspended
should cause the screen to be turned back on or allow the system to go back into
suspend. Use set_irq_wake or a platform specific api to make sure the keypad
interrupt wakes up the cpu. Once the keypad driver has resumed, the sequence of
events can look like this:

- The Keypad driver gets an interrupt. It then calls suspend_block on the
  keypad-scan suspend_blocker and starts scanning the keypad matrix.
- The keypad-scan code detects a key change and reports it to the input-event
  driver.
- The input-event driver sees the key change, enqueues an event, and calls
  suspend_block on the input-event-queue suspend_blocker.
- The keypad-scan code detects that no keys are held and calls suspend_unblock
  on the keypad-scan suspend_blocker.
- The user-space input-event thread returns from select/poll, calls
  suspend_block on the process-input-events suspend_blocker and then calls read
  on the input-event device.
- The input-event driver dequeues the key-event and, since the queue is now
  empty, it calls suspend_unblock on the input-event-queue suspend_blocker.
- The user-space input-event thread returns from read. If it determines that
  the key should leave the screen off, it calls suspend_unblock on the
  process_input_events suspend_blocker and then calls select or poll. The
  system will automatically suspend again, since now no suspend blockers are
  active.

                 Key pressed   Key released
                     |             |
keypad-scan          ++++++++++++++++++
input-event-queue        +++          +++
process-input-events       +++          +++


Driver API
==========

A driver can use the suspend block api by adding a suspend_blocker variable to
its state and calling suspend_blocker_init. For instance:
struct state {
        struct suspend_blocker suspend_blocker;
}

init() {
        suspend_blocker_init(&state->suspend_blocker, "suspend-blocker-name");
}

Before freeing the memory, suspend_blocker_destroy must be called:

uninit() {
        suspend_blocker_destroy(&state->suspend_blocker);
}

When the driver determines that it needs to run (usually in an interrupt
handler) it calls suspend_block:
        suspend_block(&state->suspend_blocker);

When it no longer needs to run it calls suspend_unblock:
        suspend_unblock(&state->suspend_blocker);

Calling suspend_block when the suspend blocker is active or suspend_unblock when
it is not active has no effect. This allows drivers to update their state and
call suspend suspend_block or suspend_unblock based on the result.
For instance:

if (list_empty(&state->pending_work))
        suspend_unblock(&state->suspend_blocker);
else
        suspend_block(&state->suspend_blocker);

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 1/8] PM: Add suspend block api.
  2009-04-29 22:34   ` Rafael J. Wysocki
  2009-04-29 23:45     ` Arve Hjønnevåg
@ 2009-04-30  0:49     ` Arve Hjønnevåg
  2009-04-26  9:42       ` Pavel Machek
  2009-05-02 12:14       ` Rafael J. Wysocki
  1 sibling, 2 replies; 93+ messages in thread
From: Arve Hjønnevåg @ 2009-04-30  0:49 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: ncunningham, u.luckas, swetland, linux-pm

2009/4/29 Rafael J. Wysocki <rjw@sisk.pl>:
> On Wednesday 15 April 2009, Arve Hjønnevåg wrote:
>> diff --git a/include/linux/suspend_block.h b/include/linux/suspend_block.h
>> new file mode 100755
>> index 0000000..7820c60
>> --- /dev/null
>> +++ b/include/linux/suspend_block.h
>
> suspend_blockers.h perhaps?

suspend_blocker.h?

>
>> @@ -0,0 +1,61 @@
>> +/* include/linux/suspend_block.h
>> + *
>> + * Copyright (C) 2007-2009 Google, Inc.
>> + *
>> + * This software is licensed under the terms of the GNU General Public
>> + * License version 2, as published by the Free Software Foundation, and
>> + * may be copied, distributed, and modified under those terms.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + */
>> +
>> +#ifndef _LINUX_SUSPEND_BLOCK_H
>> +#define _LINUX_SUSPEND_BLOCK_H
>
> SUSPEND_BLOCKERS_H ?
>
>> +
>> +/* A suspend_blocker prevents the system from entering suspend when active.
>> + */
>> +
>> +struct suspend_blocker {
>> +#ifdef CONFIG_SUSPEND_BLOCK
>
> CONFIG_SUSPEND_BLOCKERS ?

OK.

>
>> +     atomic_t            flags;
>> +     const char         *name;
>> +#endif
>> +};
>> +
>> +#ifdef CONFIG_SUSPEND_BLOCK
>> +
>> +void suspend_blocker_init(struct suspend_blocker *blocker, const char *name);
>> +void suspend_blocker_destroy(struct suspend_blocker *blocker);
>> +void suspend_block(struct suspend_blocker *blocker);
>> +void suspend_unblock(struct suspend_blocker *blocker);
>> +
>> +/* is_blocking_suspend returns true if the suspend_blocker is currently active.
>> + */
>> +bool is_blocking_suspend(struct suspend_blocker *blocker);
>
> suspend_blocker_is_active() ?
OK.
> suspend_blocker_enabled() ?
>
>> +
>> +/* suspend_is_blocked can be used by generic power management code to abort
>> + * suspend.
>> + *
>> + * To preserve backward compatibility suspend_is_blocked returns 0 unless it
>> + * is called during suspend initiated from the suspend_block code.
>> + */
>> +bool suspend_is_blocked(void);
>> +
>> +#else
>> +
>> +static inline void suspend_blocker_init(struct suspend_blocker *blocker,
>> +                                     const char *name) {}
>> +static inline void suspend_blocker_destroy(struct suspend_blocker *blocker) {}
>> +static inline void suspend_block(struct suspend_blocker *blocker) {}
>> +static inline void suspend_unblock(struct suspend_blocker *blocker) {}
>> +static inline bool is_blocking_suspend(struct suspend_blocker *bl) { return 0; }
>> +static inline bool suspend_is_blocked(void) { return 0; }
>> +
>> +#endif
>> +
>> +#endif
>> +
>> diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
>> index 23bd4da..9d1df13 100644
>> --- a/kernel/power/Kconfig
>> +++ b/kernel/power/Kconfig
>> @@ -116,6 +116,16 @@ config SUSPEND_FREEZER
>>
>>         Turning OFF this setting is NOT recommended! If in doubt, say Y.
>>
>> +config SUSPEND_BLOCK
>> +     bool "Suspend block"
>> +     depends on PM
>> +     select RTC_LIB
>
> depends on RTC_LIB
>
> select doesn't really work and I don't think it ever will.

Nothing depends on RTC_LIB, it is only selected.

>
>> +     default n
>> +     ---help---
>> +       Enable suspend_block.
>
> Enable suspend blockers.

OK.

>
>> When user space requests a sleep state through
>> +       /sys/power/request_state, the requested sleep state will be entered
>> +       when no suspend_blockers are active.
>
> Well, if you don't want suspend blockers to block suspend started via
> /sys/power/state, it's worth making it crystal clear in the documentation too.

I added this to the intro.

>
>> +
>>  config HIBERNATION
>>       bool "Hibernation (aka 'suspend to disk')"
>>       depends on PM && SWAP && ARCH_HIBERNATION_POSSIBLE
>> diff --git a/kernel/power/Makefile b/kernel/power/Makefile
>> index 720ea4f..29cdc9e 100644
>> --- a/kernel/power/Makefile
>> +++ b/kernel/power/Makefile
>> @@ -6,6 +6,7 @@ endif
>>  obj-$(CONFIG_PM)             += main.o
>>  obj-$(CONFIG_PM_SLEEP)               += console.o
>>  obj-$(CONFIG_FREEZER)                += process.o
>> +obj-$(CONFIG_SUSPEND_BLOCK)  += suspend_block.o
>>  obj-$(CONFIG_HIBERNATION)    += swsusp.o disk.o snapshot.o swap.o user.o
>>
>>  obj-$(CONFIG_MAGIC_SYSRQ)    += poweroff.o
>> diff --git a/kernel/power/main.c b/kernel/power/main.c
>> index c9632f8..e4c6b20 100644
>> --- a/kernel/power/main.c
>> +++ b/kernel/power/main.c
>> @@ -22,6 +22,7 @@
>>  #include <linux/freezer.h>
>>  #include <linux/vmstat.h>
>>  #include <linux/syscalls.h>
>> +#include <linux/suspend_block.h>
>>
>>  #include "power.h"
>>
>> @@ -392,6 +393,9 @@ static void suspend_finish(void)
>>
>>
>>  static const char * const pm_states[PM_SUSPEND_MAX] = {
>> +#ifdef CONFIG_SUSPEND_BLOCK
>> +     [PM_SUSPEND_ON]         = "on",
>> +#endif
>
> Why #ifdef?

Removed.

>
>>       [PM_SUSPEND_STANDBY]    = "standby",
>>       [PM_SUSPEND_MEM]        = "mem",
>>  };
>> @@ -540,6 +544,61 @@ static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
>>
>>  power_attr(state);
>>
>> +/**
>> + *   request_state - control system power state.
>> + *
>> + *   This is similar to state, but it does not block until the system
>> + *   resumes, and it will try to re-enter the state until another state is
>> + *   requested. Suspend blockers are respected and the requested state will
>> + *   only be entered when no suspend blockers are active.
>> + *   Write "on" to cancel.
>> + */
>> +
>> +#ifdef CONFIG_SUSPEND_BLOCK
>> +static ssize_t request_state_show(struct kobject *kobj,
>> +                               struct kobj_attribute *attr, char *buf)
>> +{
>> +     char *s = buf;
>> +     int i;
>> +
>> +     for (i = 0; i < PM_SUSPEND_MAX; i++) {
>> +             if (pm_states[i] && (i == PM_SUSPEND_ON || valid_state(i)))
>> +                     s += sprintf(s, "%s ", pm_states[i]);
>> +     }
>> +     if (s != buf)
>> +             /* convert the last space to a newline */
>> +             *(s-1) = '\n';
>> +     return (s - buf);
>> +}
>> +
>> +static ssize_t request_state_store(struct kobject *kobj,
>> +                                struct kobj_attribute *attr,
>> +                                const char *buf, size_t n)
>> +{
>> +     suspend_state_t state = PM_SUSPEND_ON;
>> +     const char * const *s;
>> +     char *p;
>> +     int len;
>> +     int error = -EINVAL;
>> +
>> +     p = memchr(buf, '\n', n);
>> +     len = p ? p - buf : n;
>> +
>> +     for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {
>> +             if (*s && len == strlen(*s) && !strncmp(buf, *s, len))
>> +                     break;
>> +     }
>> +     if (state < PM_SUSPEND_MAX && *s)
>> +             if (state == PM_SUSPEND_ON || valid_state(state)) {
>> +                     error = 0;
>> +                     request_suspend_state(state);
>> +             }
>> +     return error ? error : n;
>> +}
>> +
>> +power_attr(request_state);
>> +#endif /* CONFIG_SUSPEND_BLOCK */
>> +
>>  #ifdef CONFIG_PM_TRACE
>>  int pm_trace_enabled;
>>
>> @@ -567,6 +626,9 @@ power_attr(pm_trace);
>>
>>  static struct attribute * g[] = {
>>       &state_attr.attr,
>> +#ifdef CONFIG_SUSPEND_BLOCK
>> +     &request_state_attr.attr,
>> +#endif
>>  #ifdef CONFIG_PM_TRACE
>>       &pm_trace_attr.attr,
>>  #endif
>> diff --git a/kernel/power/power.h b/kernel/power/power.h
>> index 46b5ec7..2414a74 100644
>> --- a/kernel/power/power.h
>> +++ b/kernel/power/power.h
>> @@ -223,3 +223,9 @@ static inline void suspend_thaw_processes(void)
>>  {
>>  }
>>  #endif
>> +
>> +#ifdef CONFIG_SUSPEND_BLOCK
>> +/* kernel/power/suspend_block.c */
>> +void request_suspend_state(suspend_state_t state);
>> +#endif
>
> Is the #ifdef really necessary?
>

No, but it gives a compile error instead of a link error if you call
request_suspend_state when it is not available so it is useful.

>> +
>> diff --git a/kernel/power/suspend_block.c b/kernel/power/suspend_block.c
>> new file mode 100644
>> index 0000000..b4f2191
>> --- /dev/null
>> +++ b/kernel/power/suspend_block.c
>> @@ -0,0 +1,257 @@
>> +/* kernel/power/suspend_block.c
>> + *
>> + * Copyright (C) 2005-2008 Google, Inc.
>> + *
>> + * This software is licensed under the terms of the GNU General Public
>> + * License version 2, as published by the Free Software Foundation, and
>> + * may be copied, distributed, and modified under those terms.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/rtc.h>
>> +#include <linux/suspend.h>
>> +#include <linux/suspend_block.h>
>> +#include <linux/sysdev.h>
>> +#include "power.h"
>> +
>> +enum {
>> +     DEBUG_EXIT_SUSPEND = 1U << 0,
>> +     DEBUG_WAKEUP = 1U << 1,
>> +     DEBUG_USER_STATE = 1U << 2,
>> +     DEBUG_SUSPEND = 1U << 3,
>> +     DEBUG_SUSPEND_BLOCKER = 1U << 4,
>> +};
>> +static int debug_mask = DEBUG_EXIT_SUSPEND | DEBUG_WAKEUP | DEBUG_USER_STATE;
>> +module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
>> +
>> +#define SB_INITIALIZED            (1U << 8)
>> +#define SB_ACTIVE                 (1U << 9)
>> +
>> +static DEFINE_SPINLOCK(state_lock);
>> +static atomic_t suspend_block_count;
>> +static atomic_t current_event_num;
>> +struct workqueue_struct *suspend_work_queue;
>> +struct suspend_blocker main_suspend_blocker;
>> +static suspend_state_t requested_suspend_state = PM_SUSPEND_MEM;
>> +static bool enable_suspend_blockers;
>> +
>> +bool suspend_is_blocked(void)
>> +{
>> +     if (WARN_ONCE(!enable_suspend_blockers, "ignoring suspend blockers\n"))
>> +             return 0;
>> +     return !!atomic_read(&suspend_block_count);
>> +}
>> +
>> +static void suspend_worker(struct work_struct *work)
>> +{
>> +     int ret;
>> +     int entry_event_num;
>> +
>> +     enable_suspend_blockers = 1;
>
> 'true' instead of '1', please.

OK.

>
>> +
>> +retry:
>> +     if (suspend_is_blocked()) {
>> +             if (debug_mask & DEBUG_SUSPEND)
>> +                     pr_info("suspend: abort suspend\n");
>> +             goto abort;
>
> If that were in a loop you could just use 'break' here.

do you think this is better:
while(1) {
        if (exception1) {
                ...
                break;
        }
        ...
        if (exception2) {
                ...
                continue;
        }
        break;
}
>
>> +     }
>> +
>> +     entry_event_num = atomic_read(&current_event_num);
>> +     if (debug_mask & DEBUG_SUSPEND)
>> +             pr_info("suspend: enter suspend\n");
>> +     ret = pm_suspend(requested_suspend_state);
>> +     if (debug_mask & DEBUG_EXIT_SUSPEND) {
>> +             struct timespec ts;
>> +             struct rtc_time tm;
>> +             getnstimeofday(&ts);
>> +             rtc_time_to_tm(ts.tv_sec, &tm);
>> +             pr_info("suspend: exit suspend, ret = %d "
>> +                     "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", ret,
>> +                     tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
>> +                     tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
>> +     }
>> +     if (atomic_read(&current_event_num) == entry_event_num) {
>> +             if (debug_mask & DEBUG_SUSPEND)
>> +                     pr_info("suspend: pm_suspend returned with no event\n");
>> +             goto retry;
>
> Put that into a loop and use 'continue' here?  Or use 'break' to go out of
> the loop?

The retry is a workaround for the lack of suspend_block_timeout.

>
>> +     }
>> +abort:
>> +     enable_suspend_blockers = 0;
>
> 'false' instead of '0', please.

OK.

>
>> +}
>> +static DECLARE_WORK(suspend_work, suspend_worker);
>> +
>> +static int suspend_block_suspend(struct sys_device *dev, pm_message_t state)
>> +{
>> +     int ret = suspend_is_blocked() ? -EAGAIN : 0;
>> +     if (debug_mask & DEBUG_SUSPEND)
>> +             pr_info("suspend_block_suspend return %d\n", ret);
>> +     return ret;
>> +}
>> +
>> +static struct sysdev_class suspend_block_sysclass = {
>> +     .name = "suspend_block",
>> +     .suspend = suspend_block_suspend,
>> +};
>> +static struct sys_device suspend_block_sysdev = {
>> +     .cls = &suspend_block_sysclass,
>> +};
>> +
>
> Hmm.  Perhaps add the suspend_is_blocked() check at the beginning of
> sysdev_suspend() instead of this?  Surely you don't want to suspend
> any sysdevs with any suspend blockers active, right?

You could make the same argument for any device. Using a sysdev makes
the patch easier to apply.

>
>> +/**
>> + * suspend_blocker_init() - Initialize a suspend blocker
>> + * @blocker: The suspend blocker to initialize.
>> + * @name:    The name of the suspend blocker to show in
>> + *           /proc/suspend_blockers
>> + */
>> +void suspend_blocker_init(struct suspend_blocker *blocker, const char *name)
>> +{
>> +     if (name)
>> +             blocker->name = name;
>> +     BUG_ON(!blocker->name);
>
> Do you really want to crash the kernel in this case?  WARN_ON() might be better IMO.

OK.

>
> Also, this assumes that the caller won't release the memory used to store the
> 'name' string.  it might be a good idea to point that out in the kerneldoc
> comment.
>
>> +
>> +     if (debug_mask & DEBUG_SUSPEND_BLOCKER)
>> +             pr_info("suspend_blocker_init name=%s\n", blocker->name);
>> +
>> +     atomic_set(&blocker->flags, SB_INITIALIZED);
>> +}
>> +EXPORT_SYMBOL(suspend_blocker_init);
>> +
>> +/**
>> + * suspend_blocker_destroy() - Destroy a suspend blocker
>> + * @blocker: The suspend blocker to destroy.
>> + */
>> +void suspend_blocker_destroy(struct suspend_blocker *blocker)
>> +{
>> +     int flags;
>> +     if (debug_mask & DEBUG_SUSPEND_BLOCKER)
>> +             pr_info("suspend_blocker_destroy name=%s\n", blocker->name);
>> +     flags = atomic_xchg(&blocker->flags, 0);
>> +     WARN(!(flags & SB_INITIALIZED), "suspend_blocker_destroy called on "
>> +                                     "uninitialized suspend_blocker\n");
>> +     if (flags == (SB_INITIALIZED | SB_ACTIVE))
>> +             if (atomic_dec_and_test(&suspend_block_count))
>> +                     queue_work(suspend_work_queue, &suspend_work);
>> +}
>> +EXPORT_SYMBOL(suspend_blocker_destroy);
>> +
>> +/**
>> + * suspend_block() - Block suspend
>> + * @blocker: The suspend blocker to use
>> + */
>> +void suspend_block(struct suspend_blocker *blocker)
>> +{
>> +     BUG_ON(!(atomic_read(&blocker->flags) & SB_INITIALIZED));
>
> WARN_ON() and exit instead?  BUG_ON() is a bit drastic IMHO.
>
>> +
>> +     if (debug_mask & DEBUG_SUSPEND_BLOCKER)
>> +             pr_info("suspend_block: %s\n", blocker->name);
>> +     if (atomic_cmpxchg(&blocker->flags, SB_INITIALIZED,
>> +         SB_INITIALIZED | SB_ACTIVE) == SB_INITIALIZED)
>> +             atomic_inc(&suspend_block_count);
>> +
>> +     atomic_inc(&current_event_num);
>> +}
>> +EXPORT_SYMBOL(suspend_block);
>> +
>> +/**
>> + * suspend_unblock() - Unblock suspend
>> + * @blocker: The suspend blocker to unblock.
>> + *
>> + * If no other suspend blockers block suspend, the system will suspend.
>> + */
>> +void suspend_unblock(struct suspend_blocker *blocker)
>> +{
>> +     if (debug_mask & DEBUG_SUSPEND_BLOCKER)
>> +             pr_info("suspend_unblock: %s\n", blocker->name);
>> +
>> +     if (atomic_cmpxchg(&blocker->flags, SB_INITIALIZED | SB_ACTIVE,
>> +         SB_INITIALIZED) == (SB_INITIALIZED | SB_ACTIVE))
>> +             if (atomic_dec_and_test(&suspend_block_count))
>> +                     queue_work(suspend_work_queue, &suspend_work);
>> +}
>> +EXPORT_SYMBOL(suspend_unblock);
>> +
>> +/**
>> + * is_blocking_suspend() - Test if a suspend blocker is blocking suspend
>> + * @blocker: The suspend blocker to check.
>> + */
>> +bool is_blocking_suspend(struct suspend_blocker *blocker)
>> +{
>> +     return !!(atomic_read(&blocker->flags) & SB_ACTIVE);
>
> Check SB_INITIALIZED too, perhaps?  WARN_ON(!SB_INITIALIZED)?

Added WARN_ON.

>
>> +}
>> +EXPORT_SYMBOL(is_blocking_suspend);
>> +
>> +void request_suspend_state(suspend_state_t state)
>> +{
>> +     unsigned long irqflags;
>> +     spin_lock_irqsave(&state_lock, irqflags);
>> +     if (debug_mask & DEBUG_USER_STATE) {
>> +             struct timespec ts;
>> +             struct rtc_time tm;
>> +             getnstimeofday(&ts);
>> +             rtc_time_to_tm(ts.tv_sec, &tm);
>> +             pr_info("request_suspend_state: %s (%d->%d) at %lld "
>> +                     "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n",
>> +                     state != PM_SUSPEND_ON ? "sleep" : "wakeup",
>> +                     requested_suspend_state, state,
>> +                     ktime_to_ns(ktime_get()),
>> +                     tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
>> +                     tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
>> +     }
>> +     requested_suspend_state = state;
>> +     if (state == PM_SUSPEND_ON)
>> +             suspend_block(&main_suspend_blocker);
>> +     else
>> +             suspend_unblock(&main_suspend_blocker);
>> +     spin_unlock_irqrestore(&state_lock, irqflags);
>> +}
>> +
>> +static int __init suspend_block_init(void)
>> +{
>> +     int ret;
>> +
>> +     suspend_blocker_init(&main_suspend_blocker, "main");
>> +     suspend_block(&main_suspend_blocker);
>> +
>> +     ret = sysdev_class_register(&suspend_block_sysclass);
>> +     if (ret) {
>> +             pr_err("suspend_block_init: sysdev_class_register failed\n");
>> +             goto err_sysdev_class_register;
>> +     }
>> +     ret = sysdev_register(&suspend_block_sysdev);
>> +     if (ret) {
>> +             pr_err("suspend_block_init: suspend_block_sysdev failed\n");
>> +             goto err_sysdev_register;
>> +     }
>> +
>> +     suspend_work_queue = create_singlethread_workqueue("suspend");
>
> Do we need a separate workqueue for this purpose?
>

Yes. Some drivers wait on work that runs on the main workqueue in
their suspend handler.

>> +     if (suspend_work_queue == NULL) {
>> +             ret = -ENOMEM;
>> +             goto err_suspend_work_queue;
>> +     }
>> +
>> +     return 0;
>> +
>> +err_suspend_work_queue:
>> +     sysdev_unregister(&suspend_block_sysdev);
>> +err_sysdev_register:
>> +     sysdev_class_unregister(&suspend_block_sysclass);
>> +err_sysdev_class_register:
>> +     suspend_blocker_destroy(&main_suspend_blocker);
>> +     return ret;
>> +}
>> +
>> +static void  __exit suspend_block_exit(void)
>> +{
>> +     destroy_workqueue(suspend_work_queue);
>> +     sysdev_unregister(&suspend_block_sysdev);
>> +     sysdev_class_unregister(&suspend_block_sysclass);
>> +     suspend_blocker_destroy(&main_suspend_blocker);
>> +}
>> +
>> +core_initcall(suspend_block_init);
>> +module_exit(suspend_block_exit);
>
> Thanks,
> Rafael
>



-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 1/8] PM: Add suspend block api.
  2009-04-30  0:49     ` Arve Hjønnevåg
  2009-04-26  9:42       ` Pavel Machek
@ 2009-05-02 12:14       ` Rafael J. Wysocki
  2009-05-02 20:51         ` Pavel Machek
  2009-05-05  3:48         ` Arve Hjønnevåg
  1 sibling, 2 replies; 93+ messages in thread
From: Rafael J. Wysocki @ 2009-05-02 12:14 UTC (permalink / raw)
  To: Arve Hjønnevåg; +Cc: ncunningham, u.luckas, swetland, linux-pm

On Thursday 30 April 2009, Arve Hjønnevåg wrote:
> 2009/4/29 Rafael J. Wysocki <rjw@sisk.pl>:
> > On Wednesday 15 April 2009, Arve Hjønnevåg wrote:
> >> diff --git a/include/linux/suspend_block.h b/include/linux/suspend_block.h
> >> new file mode 100755
> >> index 0000000..7820c60
> >> --- /dev/null
> >> +++ b/include/linux/suspend_block.h
> >
> > suspend_blockers.h perhaps?
> 
> suspend_blocker.h?

Fine by me.

[--snip--]
> >> +config SUSPEND_BLOCK
> >> +     bool "Suspend block"
> >> +     depends on PM
> >> +     select RTC_LIB
> >
> > depends on RTC_LIB
> >
> > select doesn't really work and I don't think it ever will.
> 
> Nothing depends on RTC_LIB, it is only selected.

If nothing in your code needs anything depending on RTC_LIB, why select it?

[--snip--]
> >
> >> +
> >> +retry:
> >> +     if (suspend_is_blocked()) {
> >> +             if (debug_mask & DEBUG_SUSPEND)
> >> +                     pr_info("suspend: abort suspend\n");
> >> +             goto abort;
> >
> > If that were in a loop you could just use 'break' here.
> 
> do you think this is better:
> while(1) {
>         if (exception1) {
>                 ...
>                 break;
>         }
>         ...
>         if (exception2) {
>                 ...
>                 continue;
>         }
>         break;
> }

I rather thought of

for (;;) {
         if (exception1) {
                 ...
                 break;
         }
         ...
         if (!exception2)
                 break;
         ...
}

[--snip--]
> >> +static int suspend_block_suspend(struct sys_device *dev, pm_message_t state)
> >> +{
> >> +     int ret = suspend_is_blocked() ? -EAGAIN : 0;
> >> +     if (debug_mask & DEBUG_SUSPEND)
> >> +             pr_info("suspend_block_suspend return %d\n", ret);
> >> +     return ret;
> >> +}
> >> +
> >> +static struct sysdev_class suspend_block_sysclass = {
> >> +     .name = "suspend_block",
> >> +     .suspend = suspend_block_suspend,
> >> +};
> >> +static struct sys_device suspend_block_sysdev = {
> >> +     .cls = &suspend_block_sysclass,
> >> +};
> >> +
> >
> > Hmm.  Perhaps add the suspend_is_blocked() check at the beginning of
> > sysdev_suspend() instead of this?  Surely you don't want to suspend
> > any sysdevs with any suspend blockers active, right?
> 
> You could make the same argument for any device. Using a sysdev makes
> the patch easier to apply.

You've lost me here. :-)

AFAICT, the only purpose of the sysdev class above is to abort suspend if
suspend_is_blocked() returns 'true'.  If that is correct, then IMO you could
achieve the same goal by calling suspend_is_blocked() directly from
sysdev_suspend(), right before check_wakeup_irqs().  Or am I missing anything?

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 1/8] PM: Add suspend block api.
  2009-04-26  9:42       ` Pavel Machek
@ 2009-05-02 12:17         ` Rafael J. Wysocki
  0 siblings, 0 replies; 93+ messages in thread
From: Rafael J. Wysocki @ 2009-05-02 12:17 UTC (permalink / raw)
  To: Pavel Machek, Arve Hj?nnev?g; +Cc: ncunningham, u.luckas, swetland, linux-pm

On Sunday 26 April 2009, Pavel Machek wrote:
> Hi!
> 
> > >> --- a/kernel/power/power.h
> > >> +++ b/kernel/power/power.h
> > >> @@ -223,3 +223,9 @@ static inline void suspend_thaw_processes(void)
> > >>  {
> > >>  }
> > >>  #endif
> > >> +
> > >> +#ifdef CONFIG_SUSPEND_BLOCK
> > >> +/* kernel/power/suspend_block.c */
> > >> +void request_suspend_state(suspend_state_t state);
> > >> +#endif
> > >
> > > Is the #ifdef really necessary?
> > >
> > 
> > No, but it gives a compile error instead of a link error if you call
> > request_suspend_state when it is not available so it is useful.
> 
> I believe #ifdef is too ugly and link error is really good enough.

Well, I agree with this FWIW.

We don't ususally use #ifdefs around function headers, unless they are defined
conditionally.

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 1/8] PM: Add suspend block api.
  2009-05-02 12:14       ` Rafael J. Wysocki
@ 2009-05-02 20:51         ` Pavel Machek
  2009-05-05  3:48         ` Arve Hjønnevåg
  1 sibling, 0 replies; 93+ messages in thread
From: Pavel Machek @ 2009-05-02 20:51 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: ncunningham, u.luckas, swetland, linux-pm

Hi!

> > >> +config SUSPEND_BLOCK
> > >> +     bool "Suspend block"
> > >> +     depends on PM
> > >> +     select RTC_LIB
> > >
> > > depends on RTC_LIB
> > >
> > > select doesn't really work and I don't think it ever will.
> > 
> > Nothing depends on RTC_LIB, it is only selected.
> 
> If nothing in your code needs anything depending on RTC_LIB, why select it?

He wants to say nothing in _kernel proper_ depends on RTC_LIB:

pavel@amd:/data/l/linux-good$ grep 'select RTC_LIB' `find . -name
"Kconfig"`
./arch/arm/Kconfig:	select RTC_LIB
./arch/mips/Kconfig:	select RTC_LIB
./drivers/rtc/Kconfig:	select RTC_LIB
pavel@amd:/data/l/linux-good$ grep 'depends.*RTC_LIB' `find . -name
"Kconfig"`
pavel@amd:/data/l/linux-good$ 

RTC_LIB seems to be designed for select.
									Pavel

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 1/8] PM: Add suspend block api.
  2009-05-02 12:14       ` Rafael J. Wysocki
  2009-05-02 20:51         ` Pavel Machek
@ 2009-05-05  3:48         ` Arve Hjønnevåg
  1 sibling, 0 replies; 93+ messages in thread
From: Arve Hjønnevåg @ 2009-05-05  3:48 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: ncunningham, u.luckas, swetland, linux-pm

2009/5/2 Rafael J. Wysocki <rjw@sisk.pl>:
> [--snip--]
>> >
>> >> +
>> >> +retry:
>> >> +     if (suspend_is_blocked()) {
>> >> +             if (debug_mask & DEBUG_SUSPEND)
>> >> +                     pr_info("suspend: abort suspend\n");
>> >> +             goto abort;
>> >
>> > If that were in a loop you could just use 'break' here.
>>
>> do you think this is better:
>> while(1) {
>>         if (exception1) {
>>                 ...
>>                 break;
>>         }
>>         ...
>>         if (exception2) {
>>                 ...
>>                 continue;
>>         }
>>         break;
>> }
>
> I rather thought of
>
> for (;;) {
>         if (exception1) {
>                 ...
>                 break;
>         }
>         ...
>         if (!exception2)
>                 break;
>         ...
> }

I don't think that is much better, but I changed the first patch to
use a loop anyway. The loop is then removed (as before) in the patch
that adds the stats.

>
> [--snip--]
>> >> +static int suspend_block_suspend(struct sys_device *dev, pm_message_t state)
>> >> +{
>> >> +     int ret = suspend_is_blocked() ? -EAGAIN : 0;
>> >> +     if (debug_mask & DEBUG_SUSPEND)
>> >> +             pr_info("suspend_block_suspend return %d\n", ret);
>> >> +     return ret;
>> >> +}
>> >> +
>> >> +static struct sysdev_class suspend_block_sysclass = {
>> >> +     .name = "suspend_block",
>> >> +     .suspend = suspend_block_suspend,
>> >> +};
>> >> +static struct sys_device suspend_block_sysdev = {
>> >> +     .cls = &suspend_block_sysclass,
>> >> +};
>> >> +
>> >
>> > Hmm.  Perhaps add the suspend_is_blocked() check at the beginning of
>> > sysdev_suspend() instead of this?  Surely you don't want to suspend
>> > any sysdevs with any suspend blockers active, right?
>>
>> You could make the same argument for any device. Using a sysdev makes
>> the patch easier to apply.
>
> You've lost me here. :-)

You have been making other changes to those files which made it a moving target.

> AFAICT, the only purpose of the sysdev class above is to abort suspend if
> suspend_is_blocked() returns 'true'.  If that is correct, then IMO you could
> achieve the same goal by calling suspend_is_blocked() directly from
> sysdev_suspend(), right before check_wakeup_irqs().  Or am I missing anything?

The stats patch also used it to track wakeup events, but I have added
another call for this to get rid of the sysdev.

-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend  blockers from user-space
  2010-05-26 23:00               ` Arve Hjønnevåg
@ 2010-05-26 23:52                 ` Alan Cox
  0 siblings, 0 replies; 93+ messages in thread
From: Alan Cox @ 2010-05-26 23:52 UTC (permalink / raw)
  To: Arve Hjønnevåg
  Cc: Brian Swetland, Rafael J. Wysocki, Peter Zijlstra, Cornelia Huck,
	linux-kernel, Randy Dunlap, Andrew Morton, Ryusuke Konishi,
	Jim Collar, Greg Kroah-Hartman, Avi Kivity, Len Brown,
	Pavel Machek, Magnus Damm, Nigel Cunningham, linux-doc

> No, many suspend blockers protect data, not tasks. We block suspend
> when there are unprocessed input events in the kernel queue.
> User-space then blocks suspend before reading those events, and it
> blocks suspend using a different suspend blocker when its queue of
> processed events become not-empty.

That sounds to me like higher level user space implementation plus a
kernel driver imposing a power level limit.

The fact your suspend blockers as a user construct are tied to data isn't
neccessarily what the kernel needs to provide.

That aside we could equally provide latency constraints using a file
handle based semantic like your suspend blockers. That would make it
easier to do suspend blockers in those terms and provide an interface
that can be used for more elegant expression of desire.

I suggested setpidle() to keep resources tied and bounded to tasks and
to make SMP work nicely. I have no problem with the latency constraints
being floating file handles, although some thought would be needed as to
how that is then mapped to SMP.

The problem with an arbitary mapping is that if I have an 8 processor
system I might want to use the latency info to stuff tasks onto different
cores so that most of them are in a deeper idle than the others. I can't
do that unless I know who the latency constraint applies to. But
hopefully someone in scheduler land has bright ideas - eg could we keep a
per task variable and adjust it when people open/close blockers with the
assumption being anyone who has open a given constraint is bound by it
and nobody else is.

Might need it to be a constraintfs so you can open other people's
constraints but all the framework for that is there in the kernel too.

Alan

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend  blockers from user-space
  2010-05-26 10:50         ` Peter Zijlstra
  2010-05-26 23:13           ` Arve Hjønnevåg
@ 2010-05-26 23:13           ` Arve Hjønnevåg
  1 sibling, 0 replies; 93+ messages in thread
From: Arve Hjønnevåg @ 2010-05-26 23:13 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: linux-pm, linux-kernel, Rafael J. Wysocki, Randy Dunlap,
	Andrew Morton, Ryusuke Konishi, Jim Collar, Greg Kroah-Hartman,
	Avi Kivity, Len Brown, Pavel Machek, Magnus Damm, Cornelia Huck,
	Nigel Cunningham, linux-doc

2010/5/26 Peter Zijlstra <peterz@infradead.org>:
> On Wed, 2010-05-26 at 03:47 -0700, Arve Hjønnevåg wrote:
>> 2010/5/26 Peter Zijlstra <peterz@infradead.org>:
>> > On Fri, 2010-05-21 at 15:46 -0700, Arve Hjønnevåg wrote:
>> >> +To create a suspend blocker from user space, open the suspend_blocker
>> >> special
>> >> +device file:
>> >> +
>> >> +    fd = open("/dev/suspend_blocker", O_RDWR | O_CLOEXEC);
>> >> +
>> >> +then optionally call:
>> >> +
>> >> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_SET_NAME(strlen(name)), name);
>> >> +
>> >> +To activate the suspend blocker call:
>> >> +
>> >> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK);
>> >> +
>> >> +To deactivate it call:
>> >> +
>> >> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_UNBLOCK);
>> >> +
>> >> +To destroy the suspend blocker, close the device:
>> >> +
>> >> +    close(fd);
>> >
>> > Urgh, please let the open() be BLOCK, the close() be UNBLOCK, and keep
>> > the SET_NAME thing if you really care.
>> >
>>
>> That would be very inefficient.
>
> How so? Anyway, since you admitted this thing isn't needed at all, I say
> we remove it altogether.
>

I also said it was useful. I don't think we should drop it just
because we can work around its absence.

-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-05-26 10:50         ` Peter Zijlstra
@ 2010-05-26 23:13           ` Arve Hjønnevåg
  2010-05-26 23:13           ` Arve Hjønnevåg
  1 sibling, 0 replies; 93+ messages in thread
From: Arve Hjønnevåg @ 2010-05-26 23:13 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Len Brown, Jim Collar, linux-doc, Greg Kroah-Hartman,
	linux-kernel, Avi Kivity, Ryusuke Konishi, Magnus Damm, linux-pm,
	Andrew Morton

2010/5/26 Peter Zijlstra <peterz@infradead.org>:
> On Wed, 2010-05-26 at 03:47 -0700, Arve Hjønnevåg wrote:
>> 2010/5/26 Peter Zijlstra <peterz@infradead.org>:
>> > On Fri, 2010-05-21 at 15:46 -0700, Arve Hjønnevåg wrote:
>> >> +To create a suspend blocker from user space, open the suspend_blocker
>> >> special
>> >> +device file:
>> >> +
>> >> +    fd = open("/dev/suspend_blocker", O_RDWR | O_CLOEXEC);
>> >> +
>> >> +then optionally call:
>> >> +
>> >> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_SET_NAME(strlen(name)), name);
>> >> +
>> >> +To activate the suspend blocker call:
>> >> +
>> >> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK);
>> >> +
>> >> +To deactivate it call:
>> >> +
>> >> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_UNBLOCK);
>> >> +
>> >> +To destroy the suspend blocker, close the device:
>> >> +
>> >> +    close(fd);
>> >
>> > Urgh, please let the open() be BLOCK, the close() be UNBLOCK, and keep
>> > the SET_NAME thing if you really care.
>> >
>>
>> That would be very inefficient.
>
> How so? Anyway, since you admitted this thing isn't needed at all, I say
> we remove it altogether.
>

I also said it was useful. I don't think we should drop it just
because we can work around its absence.

-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend  blockers from user-space
  2010-05-26 23:00             ` Alan Cox
@ 2010-05-26 23:00               ` Arve Hjønnevåg
  2010-05-26 23:52                 ` Alan Cox
  0 siblings, 1 reply; 93+ messages in thread
From: Arve Hjønnevåg @ 2010-05-26 23:00 UTC (permalink / raw)
  To: Alan Cox
  Cc: Brian Swetland, Rafael J. Wysocki, Peter Zijlstra, Cornelia Huck,
	linux-kernel, Randy Dunlap, Andrew Morton, Ryusuke Konishi,
	Jim Collar, Greg Kroah-Hartman, Avi Kivity, Len Brown,
	Pavel Machek, Magnus Damm, Nigel Cunningham, linux-doc

On Wed, May 26, 2010 at 4:00 PM, Alan Cox <alan@lxorguk.ukuu.org.uk> wrote:
>> desired.  The device node interface came about after discussions last
>> year and concerns that userspace could create an unbounded number of
>> suspend blockers.
>
> Surely you only need one block per task (or better yet one expression of

No, many suspend blockers protect data, not tasks. We block suspend
when there are unprocessed input events in the kernel queue.
User-space then blocks suspend before reading those events, and it
blocks suspend using a different suspend blocker when its queue of
processed events become not-empty.

> latency per task). If not can you explain why a setup which has a per
> task expression of latency needs (and a 'hard limit' set which you can't
> then bump back down except as root) isn't enough ?
>

> I'd really like this lot to also fix the hard real time and power
> management problem we have today and to try an fix the "suspend is
> special and different" mentality in the kernel, which is getting less and
> less true on a variety of chips.
>
>> > It's all an economic system, proprietary app vendors are in it to make
>> > money, some will therefore game the system and the rest will be forced to
>> > follow to keep their playing field fair.
>>
>> Untrusted (non-system) code can't directly access the device node from
>> userspace in the Android world -- so directly created suspend blockers
>
> Great - but the world is not Android and even if they can't access it
> directly but get passed a handle they can play.
>
>> For suspend blockers created by drivers and by trusted userspace
>> processes, having a meaningful name significantly helps statistics
>> gathering.
>
> By drivers I agree but in the driver case the cost is minimal because
> there should not be many and it is bounded clearly. Again I really think
> 'suspend blocking' is the wrong expression.
>
> A driver needs to express
>
> 'Don't go below this latency'
>
> and
>
> 'Don't go below this state'
>
> This is more generic and helps our power management do the right thing on
> all boxes. For example a serial port can meaningfully say 'I want X
> latency worst case' based upon the fact the fifo is 64 bytes and the user
> space just asked for 115,200 baud.
>
> The don't go below for states out of which the device must wake but
> cannot. Eg if your device is being told by user space to set wake on lan
> and can only wake on lan from a higher state than 'off' it needs to say
> so.
>
> Alan
>



-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend  blockers from user-space
  2010-05-26 22:18           ` Brian Swetland
@ 2010-05-26 23:00             ` Alan Cox
  2010-05-26 23:00               ` Arve Hjønnevåg
  0 siblings, 1 reply; 93+ messages in thread
From: Alan Cox @ 2010-05-26 23:00 UTC (permalink / raw)
  To: Brian Swetland
  Cc: Rafael J. Wysocki, Peter Zijlstra, Cornelia Huck,
	Arve Hjønnevåg, linux-kernel, Randy Dunlap,
	Andrew Morton, Ryusuke Konishi, Jim Collar, Greg Kroah-Hartman,
	Avi Kivity, Len Brown, Pavel Machek, Magnus Damm,
	Nigel Cunningham, linux-doc

> desired.  The device node interface came about after discussions last
> year and concerns that userspace could create an unbounded number of
> suspend blockers.

Surely you only need one block per task (or better yet one expression of
latency per task). If not can you explain why a setup which has a per
task expression of latency needs (and a 'hard limit' set which you can't
then bump back down except as root) isn't enough ?

I'd really like this lot to also fix the hard real time and power
management problem we have today and to try an fix the "suspend is
special and different" mentality in the kernel, which is getting less and
less true on a variety of chips.

> > It's all an economic system, proprietary app vendors are in it to make
> > money, some will therefore game the system and the rest will be forced to
> > follow to keep their playing field fair.
> 
> Untrusted (non-system) code can't directly access the device node from
> userspace in the Android world -- so directly created suspend blockers

Great - but the world is not Android and even if they can't access it
directly but get passed a handle they can play.

> For suspend blockers created by drivers and by trusted userspace
> processes, having a meaningful name significantly helps statistics
> gathering.

By drivers I agree but in the driver case the cost is minimal because
there should not be many and it is bounded clearly. Again I really think
'suspend blocking' is the wrong expression.

A driver needs to express

'Don't go below this latency'

and

'Don't go below this state'

This is more generic and helps our power management do the right thing on
all boxes. For example a serial port can meaningfully say 'I want X
latency worst case' based upon the fact the fifo is 64 bytes and the user
space just asked for 115,200 baud.

The don't go below for states out of which the device must wake but
cannot. Eg if your device is being told by user space to set wake on lan
and can only wake on lan from a higher state than 'off' it needs to say
so.

Alan

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-05-26 22:14         ` Alan Cox
  2010-05-26 22:18           ` Brian Swetland
@ 2010-05-26 22:45           ` Rafael J. Wysocki
  1 sibling, 0 replies; 93+ messages in thread
From: Rafael J. Wysocki @ 2010-05-26 22:45 UTC (permalink / raw)
  To: Alan Cox
  Cc: Peter Zijlstra, Cornelia Huck, Arve Hjønnevåg,
	linux-kernel, Randy Dunlap, Andrew Morton, Ryusuke Konishi,
	Jim Collar, Greg Kroah-Hartman, Avi Kivity, Len Brown,
	Pavel Machek, Magnus Damm, Nigel Cunningham, linux-doc

On Thursday 27 May 2010, Alan Cox wrote:
> > This whole thing is related to the statistics part, which Arve says is
> > essential to him.  He wants to collect statistics for each suspend blocker
> > activated and deactivated so that he can tell who's causing problems by
> > blocking suspend too often.  The name also is a part of this.
> 
> If he wants to collect stats about misbehaving code then presumably he
> needs reliable stats. Arbitary user set names are not reliable and
> judging by app vendor behaviour in the proprietary space with other such
> examples they will actively name their blockers in a manner specifically
> intended to hide the cause so as to 'reduce support costs'.
> 
> Its a waste of memory (especially if I create a million of them with a
> long name for fun).

Well, I won't argue with that. :-)

> It's all an economic system, proprietary app vendors are in it to make
> money, some will therefore game the system and the rest will be forced to
> follow to keep their playing field fair.

Good point.

Rafael

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-05-26 22:18 [linux-pm] " Alan Stern
@ 2010-05-26 22:34 ` Rafael J. Wysocki
  0 siblings, 0 replies; 93+ messages in thread
From: Rafael J. Wysocki @ 2010-05-26 22:34 UTC (permalink / raw)
  To: Alan Stern
  Cc: Len Brown, Jim Collar, linux-doc, Peter Zijlstra,
	Greg Kroah-Hartman, linux-kernel, Avi Kivity, Ryusuke Konishi,
	Magnus Damm, linux-pm, Andrew Morton

On Thursday 27 May 2010, Alan Stern wrote:
> On Wed, 26 May 2010, Rafael J. Wysocki wrote:
> 
> > On Wednesday 26 May 2010, Peter Zijlstra wrote:
> > > On Fri, 2010-05-21 at 15:46 -0700, Arve Hjønnevåg wrote:
> > > > +To create a suspend blocker from user space, open the suspend_blocker
> > > > special
> > > > +device file:
> > > > +
> > > > +    fd = open("/dev/suspend_blocker", O_RDWR | O_CLOEXEC);
> > > > +
> > > > +then optionally call:
> > > > +
> > > > +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_SET_NAME(strlen(name)), name);
> > > > +
> > > > +To activate the suspend blocker call:
> > > > +
> > > > +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK);
> > > > +
> > > > +To deactivate it call:
> > > > +
> > > > +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_UNBLOCK);
> > > > +
> > > > +To destroy the suspend blocker, close the device:
> > > > +
> > > > +    close(fd);
> > > 
> > > Urgh, please let the open() be BLOCK, the close() be UNBLOCK, and keep
> > > the SET_NAME thing if you really care.
> > 
> > SET_NAME wouldn't serve any purpose in that case.
> > 
> > This whole thing is related to the statistics part, which Arve says is
> > essential to him.  He wants to collect statistics for each suspend blocker
> > activated and deactivated so that he can tell who's causing problems by
> > blocking suspend too often.  The name also is a part of this.
> > 
> > In fact, without the statistics part the whole thing might be implemented
> > as a single reference counter such that suspend would happen when it went down
> > to zero.
> 
> There's also Arve's other main point: These suspend blockers tend to
> get used quite a lot.  Opening and closing a file each time has much
> higher overhead than a simple ioctl.
> 
> All these topics have been covered earlier in this discussion.  Peter 
> should go back and read the emails in the linux-pm archive.

Yeah.

Although with a reference counter the special device file won't be necessary.

Rafael

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-05-26 21:57       ` Rafael J. Wysocki
  2010-05-26 22:14         ` Alan Cox
@ 2010-05-26 22:18         ` Alan Stern
  2010-05-26 22:18         ` Alan Stern
  2 siblings, 0 replies; 93+ messages in thread
From: Alan Stern @ 2010-05-26 22:18 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Len Brown, Jim Collar, linux-doc, Peter Zijlstra,
	Greg Kroah-Hartman, linux-kernel, Avi Kivity, Ryusuke Konishi,
	Magnus Damm, linux-pm, Andrew Morton

On Wed, 26 May 2010, Rafael J. Wysocki wrote:

> On Wednesday 26 May 2010, Peter Zijlstra wrote:
> > On Fri, 2010-05-21 at 15:46 -0700, Arve Hjønnevåg wrote:
> > > +To create a suspend blocker from user space, open the suspend_blocker
> > > special
> > > +device file:
> > > +
> > > +    fd = open("/dev/suspend_blocker", O_RDWR | O_CLOEXEC);
> > > +
> > > +then optionally call:
> > > +
> > > +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_SET_NAME(strlen(name)), name);
> > > +
> > > +To activate the suspend blocker call:
> > > +
> > > +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK);
> > > +
> > > +To deactivate it call:
> > > +
> > > +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_UNBLOCK);
> > > +
> > > +To destroy the suspend blocker, close the device:
> > > +
> > > +    close(fd);
> > 
> > Urgh, please let the open() be BLOCK, the close() be UNBLOCK, and keep
> > the SET_NAME thing if you really care.
> 
> SET_NAME wouldn't serve any purpose in that case.
> 
> This whole thing is related to the statistics part, which Arve says is
> essential to him.  He wants to collect statistics for each suspend blocker
> activated and deactivated so that he can tell who's causing problems by
> blocking suspend too often.  The name also is a part of this.
> 
> In fact, without the statistics part the whole thing might be implemented
> as a single reference counter such that suspend would happen when it went down
> to zero.

There's also Arve's other main point: These suspend blockers tend to
get used quite a lot.  Opening and closing a file each time has much
higher overhead than a simple ioctl.

All these topics have been covered earlier in this discussion.  Peter 
should go back and read the emails in the linux-pm archive.

Alan Stern

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-05-26 21:57       ` Rafael J. Wysocki
  2010-05-26 22:14         ` Alan Cox
  2010-05-26 22:18         ` Alan Stern
@ 2010-05-26 22:18         ` Alan Stern
  2 siblings, 0 replies; 93+ messages in thread
From: Alan Stern @ 2010-05-26 22:18 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Len Brown, Jim Collar, linux-doc, Peter Zijlstra,
	Greg Kroah-Hartman, linux-kernel, Avi Kivity, Ryusuke Konishi,
	Magnus Damm, linux-pm, Andrew Morton

On Wed, 26 May 2010, Rafael J. Wysocki wrote:

> On Wednesday 26 May 2010, Peter Zijlstra wrote:
> > On Fri, 2010-05-21 at 15:46 -0700, Arve Hjønnevåg wrote:
> > > +To create a suspend blocker from user space, open the suspend_blocker
> > > special
> > > +device file:
> > > +
> > > +    fd = open("/dev/suspend_blocker", O_RDWR | O_CLOEXEC);
> > > +
> > > +then optionally call:
> > > +
> > > +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_SET_NAME(strlen(name)), name);
> > > +
> > > +To activate the suspend blocker call:
> > > +
> > > +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK);
> > > +
> > > +To deactivate it call:
> > > +
> > > +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_UNBLOCK);
> > > +
> > > +To destroy the suspend blocker, close the device:
> > > +
> > > +    close(fd);
> > 
> > Urgh, please let the open() be BLOCK, the close() be UNBLOCK, and keep
> > the SET_NAME thing if you really care.
> 
> SET_NAME wouldn't serve any purpose in that case.
> 
> This whole thing is related to the statistics part, which Arve says is
> essential to him.  He wants to collect statistics for each suspend blocker
> activated and deactivated so that he can tell who's causing problems by
> blocking suspend too often.  The name also is a part of this.
> 
> In fact, without the statistics part the whole thing might be implemented
> as a single reference counter such that suspend would happen when it went down
> to zero.

There's also Arve's other main point: These suspend blockers tend to
get used quite a lot.  Opening and closing a file each time has much
higher overhead than a simple ioctl.

All these topics have been covered earlier in this discussion.  Peter 
should go back and read the emails in the linux-pm archive.

Alan Stern

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend  blockers from user-space
  2010-05-26 22:14         ` Alan Cox
@ 2010-05-26 22:18           ` Brian Swetland
  2010-05-26 23:00             ` Alan Cox
  2010-05-26 22:45           ` Rafael J. Wysocki
  1 sibling, 1 reply; 93+ messages in thread
From: Brian Swetland @ 2010-05-26 22:18 UTC (permalink / raw)
  To: Alan Cox
  Cc: Rafael J. Wysocki, Peter Zijlstra, Cornelia Huck,
	Arve Hjønnevåg, linux-kernel, Randy Dunlap,
	Andrew Morton, Ryusuke Konishi, Jim Collar, Greg Kroah-Hartman,
	Avi Kivity, Len Brown, Pavel Machek, Magnus Damm,
	Nigel Cunningham, linux-doc

On Wed, May 26, 2010 at 3:14 PM, Alan Cox <alan@lxorguk.ukuu.org.uk> wrote:
>> This whole thing is related to the statistics part, which Arve says is
>> essential to him.  He wants to collect statistics for each suspend blocker
>> activated and deactivated so that he can tell who's causing problems by
>> blocking suspend too often.  The name also is a part of this.
>
> If he wants to collect stats about misbehaving code then presumably he
> needs reliable stats. Arbitary user set names are not reliable and
> judging by app vendor behaviour in the proprietary space with other such
> examples they will actively name their blockers in a manner specifically
> intended to hide the cause so as to 'reduce support costs'.
>
> Its a waste of memory (especially if I create a million of them with a
> long name for fun).

You are limited to one per open fd of the device, and a max name size
which could be further shrunk to something pretty small (32?) if
desired.  The device node interface came about after discussions last
year and concerns that userspace could create an unbounded number of
suspend blockers.

> It's all an economic system, proprietary app vendors are in it to make
> money, some will therefore game the system and the rest will be forced to
> follow to keep their playing field fair.

Untrusted (non-system) code can't directly access the device node from
userspace in the Android world -- so directly created suspend blockers
from userspace are only created by a couple system processes (3-4
typically).  Applications are sandboxed by UID and there is (much
more) per-application accounting in the userspace application manager
process (other resource consumption such as sensors, CPU, etc is
tracked here as well).

For suspend blockers created by drivers and by trusted userspace
processes, having a meaningful name significantly helps statistics
gathering.

Brian

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-05-26 21:57       ` Rafael J. Wysocki
@ 2010-05-26 22:14         ` Alan Cox
  2010-05-26 22:18           ` Brian Swetland
  2010-05-26 22:45           ` Rafael J. Wysocki
  2010-05-26 22:18         ` Alan Stern
  2010-05-26 22:18         ` Alan Stern
  2 siblings, 2 replies; 93+ messages in thread
From: Alan Cox @ 2010-05-26 22:14 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Peter Zijlstra, Cornelia Huck, Arve Hjønnevåg,
	linux-kernel, Randy Dunlap, Andrew Morton, Ryusuke Konishi,
	Jim Collar, Greg Kroah-Hartman, Avi Kivity, Len Brown,
	Pavel Machek, Magnus Damm, Nigel Cunningham, linux-doc

> This whole thing is related to the statistics part, which Arve says is
> essential to him.  He wants to collect statistics for each suspend blocker
> activated and deactivated so that he can tell who's causing problems by
> blocking suspend too often.  The name also is a part of this.

If he wants to collect stats about misbehaving code then presumably he
needs reliable stats. Arbitary user set names are not reliable and
judging by app vendor behaviour in the proprietary space with other such
examples they will actively name their blockers in a manner specifically
intended to hide the cause so as to 'reduce support costs'.

Its a waste of memory (especially if I create a million of them with a
long name for fun).

It's all an economic system, proprietary app vendors are in it to make
money, some will therefore game the system and the rest will be forced to
follow to keep their playing field fair.

Alan

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-05-26  8:43     ` Peter Zijlstra
                         ` (2 preceding siblings ...)
  2010-05-26 21:57       ` Rafael J. Wysocki
@ 2010-05-26 21:57       ` Rafael J. Wysocki
  2010-05-26 22:14         ` Alan Cox
                           ` (2 more replies)
  3 siblings, 3 replies; 93+ messages in thread
From: Rafael J. Wysocki @ 2010-05-26 21:57 UTC (permalink / raw)
  To: Peter Zijlstra, Cornelia Huck
  Cc: Arve Hjønnevåg, linux-pm, linux-kernel, Randy Dunlap,
	Andrew Morton, Ryusuke Konishi, Jim Collar, Greg Kroah-Hartman,
	Avi Kivity, Len Brown, Pavel Machek, Magnus Damm,
	Nigel Cunningham, linux-doc

On Wednesday 26 May 2010, Peter Zijlstra wrote:
> On Fri, 2010-05-21 at 15:46 -0700, Arve Hjønnevåg wrote:
> > +To create a suspend blocker from user space, open the suspend_blocker
> > special
> > +device file:
> > +
> > +    fd = open("/dev/suspend_blocker", O_RDWR | O_CLOEXEC);
> > +
> > +then optionally call:
> > +
> > +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_SET_NAME(strlen(name)), name);
> > +
> > +To activate the suspend blocker call:
> > +
> > +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK);
> > +
> > +To deactivate it call:
> > +
> > +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_UNBLOCK);
> > +
> > +To destroy the suspend blocker, close the device:
> > +
> > +    close(fd);
> 
> Urgh, please let the open() be BLOCK, the close() be UNBLOCK, and keep
> the SET_NAME thing if you really care.

SET_NAME wouldn't serve any purpose in that case.

This whole thing is related to the statistics part, which Arve says is
essential to him.  He wants to collect statistics for each suspend blocker
activated and deactivated so that he can tell who's causing problems by
blocking suspend too often.  The name also is a part of this.

In fact, without the statistics part the whole thing might be implemented
as a single reference counter such that suspend would happen when it went down
to zero.

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-05-26  8:43     ` Peter Zijlstra
  2010-05-26 10:47       ` Arve Hjønnevåg
  2010-05-26 10:47       ` Arve Hjønnevåg
@ 2010-05-26 21:57       ` Rafael J. Wysocki
  2010-05-26 21:57       ` Rafael J. Wysocki
  3 siblings, 0 replies; 93+ messages in thread
From: Rafael J. Wysocki @ 2010-05-26 21:57 UTC (permalink / raw)
  To: Peter Zijlstra, Cornelia Huck
  Cc: Len Brown, Jim Collar, linux-doc, Greg Kroah-Hartman,
	linux-kernel, Avi Kivity, Ryusuke Konishi, Magnus Damm, linux-pm,
	Andrew Morton

On Wednesday 26 May 2010, Peter Zijlstra wrote:
> On Fri, 2010-05-21 at 15:46 -0700, Arve Hjønnevåg wrote:
> > +To create a suspend blocker from user space, open the suspend_blocker
> > special
> > +device file:
> > +
> > +    fd = open("/dev/suspend_blocker", O_RDWR | O_CLOEXEC);
> > +
> > +then optionally call:
> > +
> > +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_SET_NAME(strlen(name)), name);
> > +
> > +To activate the suspend blocker call:
> > +
> > +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK);
> > +
> > +To deactivate it call:
> > +
> > +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_UNBLOCK);
> > +
> > +To destroy the suspend blocker, close the device:
> > +
> > +    close(fd);
> 
> Urgh, please let the open() be BLOCK, the close() be UNBLOCK, and keep
> the SET_NAME thing if you really care.

SET_NAME wouldn't serve any purpose in that case.

This whole thing is related to the statistics part, which Arve says is
essential to him.  He wants to collect statistics for each suspend blocker
activated and deactivated so that he can tell who's causing problems by
blocking suspend too often.  The name also is a part of this.

In fact, without the statistics part the whole thing might be implemented
as a single reference counter such that suspend would happen when it went down
to zero.

Thanks,
Rafael
_______________________________________________
linux-pm mailing list
linux-pm@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/linux-pm

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend  blockers from user-space
  2010-05-26 10:51         ` Florian Mickler
  2010-05-26 11:06           ` Peter Zijlstra
@ 2010-05-26 11:06           ` Peter Zijlstra
  1 sibling, 0 replies; 93+ messages in thread
From: Peter Zijlstra @ 2010-05-26 11:06 UTC (permalink / raw)
  To: Florian Mickler
  Cc: Arve Hjønnevåg, linux-pm, linux-kernel,
	Rafael J. Wysocki, Randy Dunlap, Andrew Morton, Ryusuke Konishi,
	Jim Collar, Greg Kroah-Hartman, Avi Kivity, Len Brown,
	Pavel Machek, Magnus Damm, Cornelia Huck, Nigel Cunningham,
	linux-doc

On Wed, 2010-05-26 at 12:51 +0200, Florian Mickler wrote:
> On Wed, 26 May 2010 03:47:27 -0700
> Arve Hjønnevåg <arve@android.com> wrote:
> 
> > 2010/5/26 Peter Zijlstra <peterz@infradead.org>:
> > > On Fri, 2010-05-21 at 15:46 -0700, Arve Hjønnevåg wrote:
> > >> +To create a suspend blocker from user space, open the suspend_blocker
> > >> special
> > >> +device file:
> > >> +
> > >> +    fd = open("/dev/suspend_blocker", O_RDWR | O_CLOEXEC);
> > >> +
> > >> +then optionally call:
> > >> +
> > >> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_SET_NAME(strlen(name)), name);
> > >> +
> > >> +To activate the suspend blocker call:
> > >> +
> > >> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK);
> > >> +
> > >> +To deactivate it call:
> > >> +
> > >> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_UNBLOCK);
> > >> +
> > >> +To destroy the suspend blocker, close the device:
> > >> +
> > >> +    close(fd);
> > >
> > > Urgh, please let the open() be BLOCK, the close() be UNBLOCK, and keep
> > > the SET_NAME thing if you really care.
> > >
> > 
> > That would be very inefficient.
> > 
> 
> Also I think it is intended to enforce named suspend blockers. (For
> debugging/accounting purposes).

I don't think the code as proposed mandates you SET_NAME, and I didn't
propose killing that off, you can still SET_NAME after you open() and
acquire the thing.

Anyway, the whole point is moot since its simply not needed at all.

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-05-26 10:51         ` Florian Mickler
@ 2010-05-26 11:06           ` Peter Zijlstra
  2010-05-26 11:06           ` Peter Zijlstra
  1 sibling, 0 replies; 93+ messages in thread
From: Peter Zijlstra @ 2010-05-26 11:06 UTC (permalink / raw)
  To: Florian Mickler
  Cc: Len Brown, Jim Collar, linux-doc, Greg Kroah-Hartman,
	linux-kernel, Avi Kivity, Ryusuke Konishi, Magnus Damm, linux-pm,
	Andrew Morton

On Wed, 2010-05-26 at 12:51 +0200, Florian Mickler wrote:
> On Wed, 26 May 2010 03:47:27 -0700
> Arve Hjønnevåg <arve@android.com> wrote:
> 
> > 2010/5/26 Peter Zijlstra <peterz@infradead.org>:
> > > On Fri, 2010-05-21 at 15:46 -0700, Arve Hjønnevåg wrote:
> > >> +To create a suspend blocker from user space, open the suspend_blocker
> > >> special
> > >> +device file:
> > >> +
> > >> +    fd = open("/dev/suspend_blocker", O_RDWR | O_CLOEXEC);
> > >> +
> > >> +then optionally call:
> > >> +
> > >> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_SET_NAME(strlen(name)), name);
> > >> +
> > >> +To activate the suspend blocker call:
> > >> +
> > >> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK);
> > >> +
> > >> +To deactivate it call:
> > >> +
> > >> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_UNBLOCK);
> > >> +
> > >> +To destroy the suspend blocker, close the device:
> > >> +
> > >> +    close(fd);
> > >
> > > Urgh, please let the open() be BLOCK, the close() be UNBLOCK, and keep
> > > the SET_NAME thing if you really care.
> > >
> > 
> > That would be very inefficient.
> > 
> 
> Also I think it is intended to enforce named suspend blockers. (For
> debugging/accounting purposes).

I don't think the code as proposed mandates you SET_NAME, and I didn't
propose killing that off, you can still SET_NAME after you open() and
acquire the thing.

Anyway, the whole point is moot since its simply not needed at all.
_______________________________________________
linux-pm mailing list
linux-pm@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/linux-pm

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend  blockers from user-space
  2010-05-26 10:47       ` Arve Hjønnevåg
                           ` (2 preceding siblings ...)
  2010-05-26 10:51         ` Florian Mickler
@ 2010-05-26 10:51         ` Florian Mickler
  2010-05-26 11:06           ` Peter Zijlstra
  2010-05-26 11:06           ` Peter Zijlstra
  3 siblings, 2 replies; 93+ messages in thread
From: Florian Mickler @ 2010-05-26 10:51 UTC (permalink / raw)
  To: Arve Hjønnevåg
  Cc: Peter Zijlstra, linux-pm, linux-kernel, Rafael J. Wysocki,
	Randy Dunlap, Andrew Morton, Ryusuke Konishi, Jim Collar,
	Greg Kroah-Hartman, Avi Kivity, Len Brown, Pavel Machek,
	Magnus Damm, Cornelia Huck, Nigel Cunningham, linux-doc

On Wed, 26 May 2010 03:47:27 -0700
Arve Hjønnevåg <arve@android.com> wrote:

> 2010/5/26 Peter Zijlstra <peterz@infradead.org>:
> > On Fri, 2010-05-21 at 15:46 -0700, Arve Hjønnevåg wrote:
> >> +To create a suspend blocker from user space, open the suspend_blocker
> >> special
> >> +device file:
> >> +
> >> +    fd = open("/dev/suspend_blocker", O_RDWR | O_CLOEXEC);
> >> +
> >> +then optionally call:
> >> +
> >> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_SET_NAME(strlen(name)), name);
> >> +
> >> +To activate the suspend blocker call:
> >> +
> >> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK);
> >> +
> >> +To deactivate it call:
> >> +
> >> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_UNBLOCK);
> >> +
> >> +To destroy the suspend blocker, close the device:
> >> +
> >> +    close(fd);
> >
> > Urgh, please let the open() be BLOCK, the close() be UNBLOCK, and keep
> > the SET_NAME thing if you really care.
> >
> 
> That would be very inefficient.
> 

Also I think it is intended to enforce named suspend blockers. (For
debugging/accounting purposes).

Cheers,
Flo

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-05-26 10:47       ` Arve Hjønnevåg
  2010-05-26 10:50         ` Peter Zijlstra
  2010-05-26 10:50         ` Peter Zijlstra
@ 2010-05-26 10:51         ` Florian Mickler
  2010-05-26 10:51         ` Florian Mickler
  3 siblings, 0 replies; 93+ messages in thread
From: Florian Mickler @ 2010-05-26 10:51 UTC (permalink / raw)
  To: Arve Hjønnevåg
  Cc: Len Brown, Jim Collar, Peter Zijlstra, Nigel, Kroah-Hartman,
	linux-doc, linux-kernel, Andrew, Greg, Avi Kivity,
	Ryusuke Konishi, Magnus Damm, linux-pm, Morton

On Wed, 26 May 2010 03:47:27 -0700
Arve Hjønnevåg <arve@android.com> wrote:

> 2010/5/26 Peter Zijlstra <peterz@infradead.org>:
> > On Fri, 2010-05-21 at 15:46 -0700, Arve Hjønnevåg wrote:
> >> +To create a suspend blocker from user space, open the suspend_blocker
> >> special
> >> +device file:
> >> +
> >> +    fd = open("/dev/suspend_blocker", O_RDWR | O_CLOEXEC);
> >> +
> >> +then optionally call:
> >> +
> >> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_SET_NAME(strlen(name)), name);
> >> +
> >> +To activate the suspend blocker call:
> >> +
> >> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK);
> >> +
> >> +To deactivate it call:
> >> +
> >> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_UNBLOCK);
> >> +
> >> +To destroy the suspend blocker, close the device:
> >> +
> >> +    close(fd);
> >
> > Urgh, please let the open() be BLOCK, the close() be UNBLOCK, and keep
> > the SET_NAME thing if you really care.
> >
> 
> That would be very inefficient.
> 

Also I think it is intended to enforce named suspend blockers. (For
debugging/accounting purposes).

Cheers,
Flo

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend  blockers from user-space
  2010-05-26 10:47       ` Arve Hjønnevåg
  2010-05-26 10:50         ` Peter Zijlstra
@ 2010-05-26 10:50         ` Peter Zijlstra
  2010-05-26 23:13           ` Arve Hjønnevåg
  2010-05-26 23:13           ` Arve Hjønnevåg
  2010-05-26 10:51         ` Florian Mickler
  2010-05-26 10:51         ` Florian Mickler
  3 siblings, 2 replies; 93+ messages in thread
From: Peter Zijlstra @ 2010-05-26 10:50 UTC (permalink / raw)
  To: Arve Hjønnevåg
  Cc: linux-pm, linux-kernel, Rafael J. Wysocki, Randy Dunlap,
	Andrew Morton, Ryusuke Konishi, Jim Collar, Greg Kroah-Hartman,
	Avi Kivity, Len Brown, Pavel Machek, Magnus Damm, Cornelia Huck,
	Nigel Cunningham, linux-doc

On Wed, 2010-05-26 at 03:47 -0700, Arve Hjønnevåg wrote:
> 2010/5/26 Peter Zijlstra <peterz@infradead.org>:
> > On Fri, 2010-05-21 at 15:46 -0700, Arve Hjønnevåg wrote:
> >> +To create a suspend blocker from user space, open the suspend_blocker
> >> special
> >> +device file:
> >> +
> >> +    fd = open("/dev/suspend_blocker", O_RDWR | O_CLOEXEC);
> >> +
> >> +then optionally call:
> >> +
> >> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_SET_NAME(strlen(name)), name);
> >> +
> >> +To activate the suspend blocker call:
> >> +
> >> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK);
> >> +
> >> +To deactivate it call:
> >> +
> >> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_UNBLOCK);
> >> +
> >> +To destroy the suspend blocker, close the device:
> >> +
> >> +    close(fd);
> >
> > Urgh, please let the open() be BLOCK, the close() be UNBLOCK, and keep
> > the SET_NAME thing if you really care.
> >
> 
> That would be very inefficient.

How so? Anyway, since you admitted this thing isn't needed at all, I say
we remove it altogether.

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-05-26 10:47       ` Arve Hjønnevåg
@ 2010-05-26 10:50         ` Peter Zijlstra
  2010-05-26 10:50         ` Peter Zijlstra
                           ` (2 subsequent siblings)
  3 siblings, 0 replies; 93+ messages in thread
From: Peter Zijlstra @ 2010-05-26 10:50 UTC (permalink / raw)
  To: Arve Hjønnevåg
  Cc: Len Brown, Jim Collar, linux-doc, Greg Kroah-Hartman,
	linux-kernel, Avi Kivity, Ryusuke Konishi, Magnus Damm, linux-pm,
	Andrew Morton

On Wed, 2010-05-26 at 03:47 -0700, Arve Hjønnevåg wrote:
> 2010/5/26 Peter Zijlstra <peterz@infradead.org>:
> > On Fri, 2010-05-21 at 15:46 -0700, Arve Hjønnevåg wrote:
> >> +To create a suspend blocker from user space, open the suspend_blocker
> >> special
> >> +device file:
> >> +
> >> +    fd = open("/dev/suspend_blocker", O_RDWR | O_CLOEXEC);
> >> +
> >> +then optionally call:
> >> +
> >> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_SET_NAME(strlen(name)), name);
> >> +
> >> +To activate the suspend blocker call:
> >> +
> >> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK);
> >> +
> >> +To deactivate it call:
> >> +
> >> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_UNBLOCK);
> >> +
> >> +To destroy the suspend blocker, close the device:
> >> +
> >> +    close(fd);
> >
> > Urgh, please let the open() be BLOCK, the close() be UNBLOCK, and keep
> > the SET_NAME thing if you really care.
> >
> 
> That would be very inefficient.

How so? Anyway, since you admitted this thing isn't needed at all, I say
we remove it altogether.
_______________________________________________
linux-pm mailing list
linux-pm@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/linux-pm

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend  blockers from user-space
  2010-05-26  8:43     ` Peter Zijlstra
  2010-05-26 10:47       ` Arve Hjønnevåg
@ 2010-05-26 10:47       ` Arve Hjønnevåg
  2010-05-26 10:50         ` Peter Zijlstra
                           ` (3 more replies)
  2010-05-26 21:57       ` Rafael J. Wysocki
  2010-05-26 21:57       ` Rafael J. Wysocki
  3 siblings, 4 replies; 93+ messages in thread
From: Arve Hjønnevåg @ 2010-05-26 10:47 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: linux-pm, linux-kernel, Rafael J. Wysocki, Randy Dunlap,
	Andrew Morton, Ryusuke Konishi, Jim Collar, Greg Kroah-Hartman,
	Avi Kivity, Len Brown, Pavel Machek, Magnus Damm, Cornelia Huck,
	Nigel Cunningham, linux-doc

2010/5/26 Peter Zijlstra <peterz@infradead.org>:
> On Fri, 2010-05-21 at 15:46 -0700, Arve Hjønnevåg wrote:
>> +To create a suspend blocker from user space, open the suspend_blocker
>> special
>> +device file:
>> +
>> +    fd = open("/dev/suspend_blocker", O_RDWR | O_CLOEXEC);
>> +
>> +then optionally call:
>> +
>> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_SET_NAME(strlen(name)), name);
>> +
>> +To activate the suspend blocker call:
>> +
>> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK);
>> +
>> +To deactivate it call:
>> +
>> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_UNBLOCK);
>> +
>> +To destroy the suspend blocker, close the device:
>> +
>> +    close(fd);
>
> Urgh, please let the open() be BLOCK, the close() be UNBLOCK, and keep
> the SET_NAME thing if you really care.
>

That would be very inefficient.

-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-05-26  8:43     ` Peter Zijlstra
@ 2010-05-26 10:47       ` Arve Hjønnevåg
  2010-05-26 10:47       ` Arve Hjønnevåg
                         ` (2 subsequent siblings)
  3 siblings, 0 replies; 93+ messages in thread
From: Arve Hjønnevåg @ 2010-05-26 10:47 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Len Brown, Jim Collar, linux-doc, Greg Kroah-Hartman,
	linux-kernel, Avi Kivity, Ryusuke Konishi, Magnus Damm, linux-pm,
	Andrew Morton

2010/5/26 Peter Zijlstra <peterz@infradead.org>:
> On Fri, 2010-05-21 at 15:46 -0700, Arve Hjønnevåg wrote:
>> +To create a suspend blocker from user space, open the suspend_blocker
>> special
>> +device file:
>> +
>> +    fd = open("/dev/suspend_blocker", O_RDWR | O_CLOEXEC);
>> +
>> +then optionally call:
>> +
>> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_SET_NAME(strlen(name)), name);
>> +
>> +To activate the suspend blocker call:
>> +
>> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK);
>> +
>> +To deactivate it call:
>> +
>> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_UNBLOCK);
>> +
>> +To destroy the suspend blocker, close the device:
>> +
>> +    close(fd);
>
> Urgh, please let the open() be BLOCK, the close() be UNBLOCK, and keep
> the SET_NAME thing if you really care.
>

That would be very inefficient.

-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-05-21 22:46   ` [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space Arve Hjønnevåg
@ 2010-05-26  8:43     ` Peter Zijlstra
  2010-05-26 10:47       ` Arve Hjønnevåg
                         ` (3 more replies)
  2010-05-26  8:43     ` Peter Zijlstra
  1 sibling, 4 replies; 93+ messages in thread
From: Peter Zijlstra @ 2010-05-26  8:43 UTC (permalink / raw)
  To: Arve Hjønnevåg
  Cc: linux-pm, linux-kernel, Rafael J. Wysocki, Randy Dunlap,
	Andrew Morton, Ryusuke Konishi, Jim Collar, Greg Kroah-Hartman,
	Avi Kivity, Len Brown, Pavel Machek, Magnus Damm, Cornelia Huck,
	Nigel Cunningham, linux-doc

On Fri, 2010-05-21 at 15:46 -0700, Arve Hjønnevåg wrote:
> +To create a suspend blocker from user space, open the suspend_blocker
> special
> +device file:
> +
> +    fd = open("/dev/suspend_blocker", O_RDWR | O_CLOEXEC);
> +
> +then optionally call:
> +
> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_SET_NAME(strlen(name)), name);
> +
> +To activate the suspend blocker call:
> +
> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK);
> +
> +To deactivate it call:
> +
> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_UNBLOCK);
> +
> +To destroy the suspend blocker, close the device:
> +
> +    close(fd);

Urgh, please let the open() be BLOCK, the close() be UNBLOCK, and keep
the SET_NAME thing if you really care.


^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-05-21 22:46   ` [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space Arve Hjønnevåg
  2010-05-26  8:43     ` Peter Zijlstra
@ 2010-05-26  8:43     ` Peter Zijlstra
  1 sibling, 0 replies; 93+ messages in thread
From: Peter Zijlstra @ 2010-05-26  8:43 UTC (permalink / raw)
  To: Arve Hjønnevåg
  Cc: Len Brown, Jim Collar, linux-doc, Greg Kroah-Hartman,
	linux-kernel, Avi Kivity, Ryusuke Konishi, Magnus Damm, linux-pm,
	Andrew Morton

On Fri, 2010-05-21 at 15:46 -0700, Arve Hjønnevåg wrote:
> +To create a suspend blocker from user space, open the suspend_blocker
> special
> +device file:
> +
> +    fd = open("/dev/suspend_blocker", O_RDWR | O_CLOEXEC);
> +
> +then optionally call:
> +
> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_SET_NAME(strlen(name)), name);
> +
> +To activate the suspend blocker call:
> +
> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK);
> +
> +To deactivate it call:
> +
> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_UNBLOCK);
> +
> +To destroy the suspend blocker, close the device:
> +
> +    close(fd);

Urgh, please let the open() be BLOCK, the close() be UNBLOCK, and keep
the SET_NAME thing if you really care.

_______________________________________________
linux-pm mailing list
linux-pm@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/linux-pm

^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-05-21 22:46 ` [PATCH 1/8] PM: Opportunistic suspend support Arve Hjønnevåg
@ 2010-05-21 22:46   ` Arve Hjønnevåg
  2010-05-26  8:43     ` Peter Zijlstra
  2010-05-26  8:43     ` Peter Zijlstra
  2010-05-21 22:46   ` Arve Hjønnevåg
  1 sibling, 2 replies; 93+ messages in thread
From: Arve Hjønnevåg @ 2010-05-21 22:46 UTC (permalink / raw)
  To: linux-pm, linux-kernel
  Cc: Rafael J. Wysocki, Arve Hjønnevåg, Randy Dunlap,
	Andrew Morton, Ryusuke Konishi, Jim Collar, Greg Kroah-Hartman,
	Avi Kivity, Len Brown, Pavel Machek, Magnus Damm, Cornelia Huck,
	Nigel Cunningham, linux-doc

Add a misc device, "suspend_blocker", that allows user-space processes
to block automatic suspend.

Opening this device creates a suspend blocker that can be used by the
opener to prevent automatic suspend from occurring.  There are ioctls
provided for blocking and unblocking suspend and for giving the
suspend blocker a meaningful name.  Closing the device special file
causes the suspend blocker to be destroyed.

For example, when select or poll indicates that input event are
available, this interface can be used by user space to block suspend
before it reads those events. This allows the input driver to release
its suspend blocker as soon as the event queue is empty. If user space
could not use a suspend blocker here the input driver would need to
delay the release of its suspend blocker until it knows (or assumes)
that user space has finished processing the events.

By careful use of suspend blockers in drivers and user space system
code, one can arrange for the system to stay awake for extremely short
periods of time in reaction to events, rapidly returning to a fully
suspended state.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
 Documentation/ioctl/ioctl-number.txt          |    3 +-
 Documentation/power/opportunistic-suspend.txt |   27 +++++
 include/linux/suspend_ioctls.h                |    4 +
 kernel/power/Kconfig                          |    7 ++
 kernel/power/Makefile                         |    1 +
 kernel/power/user_suspend_blocker.c           |  143 +++++++++++++++++++++++++
 6 files changed, 184 insertions(+), 1 deletions(-)
 create mode 100644 kernel/power/user_suspend_blocker.c

diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index dd5806f..e2458f7 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -254,7 +254,8 @@ Code  Seq#(hex)	Include File		Comments
 'q'	80-FF	linux/telephony.h	Internet PhoneJACK, Internet LineJACK
 		linux/ixjuser.h		<http://www.quicknet.net>
 'r'	00-1F	linux/msdos_fs.h and fs/fat/dir.c
-'s'	all	linux/cdk.h
+'s'	all	linux/cdk.h	conflict!
+'s'	all	linux/suspend_block_dev.h	conflict!
 't'	00-7F	linux/if_ppp.h
 't'	80-8F	linux/isdn_ppp.h
 't'	90	linux/toshiba.h
diff --git a/Documentation/power/opportunistic-suspend.txt b/Documentation/power/opportunistic-suspend.txt
index 4bee7bc..93f4c24 100644
--- a/Documentation/power/opportunistic-suspend.txt
+++ b/Documentation/power/opportunistic-suspend.txt
@@ -127,3 +127,30 @@ if (list_empty(&state->pending_work))
 	suspend_unblock(&state->suspend_blocker);
 else
 	suspend_block(&state->suspend_blocker);
+
+User space API
+==============
+
+To create a suspend blocker from user space, open the suspend_blocker special
+device file:
+
+    fd = open("/dev/suspend_blocker", O_RDWR | O_CLOEXEC);
+
+then optionally call:
+
+    ioctl(fd, SUSPEND_BLOCKER_IOCTL_SET_NAME(strlen(name)), name);
+
+To activate the suspend blocker call:
+
+    ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK);
+
+To deactivate it call:
+
+    ioctl(fd, SUSPEND_BLOCKER_IOCTL_UNBLOCK);
+
+To destroy the suspend blocker, close the device:
+
+    close(fd);
+
+If the first ioctl called is not SUSPEND_BLOCKER_IOCTL_SET_NAME the suspend
+blocker will get the default name "(userspace)".
diff --git a/include/linux/suspend_ioctls.h b/include/linux/suspend_ioctls.h
index 0b30382..b95a6b2 100644
--- a/include/linux/suspend_ioctls.h
+++ b/include/linux/suspend_ioctls.h
@@ -30,4 +30,8 @@ struct resume_swap_area {
 #define SNAPSHOT_ALLOC_SWAP_PAGE	_IOR(SNAPSHOT_IOC_MAGIC, 20, __kernel_loff_t)
 #define SNAPSHOT_IOC_MAXNR	20
 
+#define SUSPEND_BLOCKER_IOCTL_SET_NAME(len)	_IOC(_IOC_WRITE, 's', 0, len)
+#define SUSPEND_BLOCKER_IOCTL_BLOCK		_IO('s', 1)
+#define SUSPEND_BLOCKER_IOCTL_UNBLOCK		_IO('s', 2)
+
 #endif /* _LINUX_SUSPEND_IOCTLS_H */
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 6d11a45..2e665cd 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -146,6 +146,13 @@ config OPPORTUNISTIC_SUSPEND
 	  determines the sleep state the system will be put into when there are
 	  no active suspend blockers.
 
+config USER_SUSPEND_BLOCKERS
+	bool "User space suspend blockers"
+	depends on OPPORTUNISTIC_SUSPEND
+	---help---
+	  User space suspend blockers API.  Creates a misc device allowing user
+	  space to create, use and destroy suspend blockers.
+
 config HIBERNATION_NVS
 	bool
 
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index 95d8e6d..2015594 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_PM_SLEEP)		+= console.o
 obj-$(CONFIG_FREEZER)		+= process.o
 obj-$(CONFIG_SUSPEND)		+= suspend.o
 obj-$(CONFIG_OPPORTUNISTIC_SUSPEND)	+= opportunistic_suspend.o
+obj-$(CONFIG_USER_SUSPEND_BLOCKERS)	+= user_suspend_blocker.o
 obj-$(CONFIG_PM_TEST_SUSPEND)	+= suspend_test.o
 obj-$(CONFIG_HIBERNATION)	+= hibernate.o snapshot.o swap.o user.o
 obj-$(CONFIG_HIBERNATION_NVS)	+= hibernate_nvs.o
diff --git a/kernel/power/user_suspend_blocker.c b/kernel/power/user_suspend_blocker.c
new file mode 100644
index 0000000..d53f939
--- /dev/null
+++ b/kernel/power/user_suspend_blocker.c
@@ -0,0 +1,143 @@
+/*
+ * kernel/power/user_suspend_blocker.c
+ *
+ * Copyright (C) 2009-2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/suspend.h>
+#include <linux/suspend_ioctls.h>
+
+enum {
+	DEBUG_FAILURE	= BIT(0),
+};
+static int debug_mask = DEBUG_FAILURE;
+module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+static DEFINE_MUTEX(ioctl_lock);
+
+#define USER_SUSPEND_BLOCKER_NAME_LEN 31
+
+struct user_suspend_blocker {
+	struct suspend_blocker	blocker;
+	char			name[USER_SUSPEND_BLOCKER_NAME_LEN + 1];
+	bool			registered;
+};
+
+static int user_suspend_blocker_open(struct inode *inode, struct file *filp)
+{
+	struct user_suspend_blocker *blocker;
+
+	blocker = kzalloc(sizeof(*blocker), GFP_KERNEL);
+	if (!blocker)
+		return -ENOMEM;
+
+	nonseekable_open(inode, filp);
+	strcpy(blocker->name, "(userspace)");
+	blocker->blocker.name = blocker->name;
+	filp->private_data = blocker;
+
+	return 0;
+}
+
+static int suspend_blocker_set_name(struct user_suspend_blocker *blocker,
+				    void __user *name, size_t name_len)
+{
+	if (blocker->registered)
+		return -EBUSY;
+
+	if (name_len > USER_SUSPEND_BLOCKER_NAME_LEN)
+		name_len = USER_SUSPEND_BLOCKER_NAME_LEN;
+
+	if (copy_from_user(blocker->name, name, name_len))
+		return -EFAULT;
+	blocker->name[name_len] = '\0';
+
+	return 0;
+}
+
+static long user_suspend_blocker_ioctl(struct file *filp, unsigned int cmd,
+					unsigned long _arg)
+{
+	void __user *arg = (void __user *)_arg;
+	struct user_suspend_blocker *blocker = filp->private_data;
+	long ret = 0;
+
+	mutex_lock(&ioctl_lock);
+	if ((cmd & ~IOCSIZE_MASK) == SUSPEND_BLOCKER_IOCTL_SET_NAME(0)) {
+		ret = suspend_blocker_set_name(blocker, arg, _IOC_SIZE(cmd));
+		goto done;
+	}
+	if (!blocker->registered) {
+		suspend_blocker_register(&blocker->blocker);
+		blocker->registered = true;
+	}
+	switch (cmd) {
+	case SUSPEND_BLOCKER_IOCTL_BLOCK:
+		suspend_block(&blocker->blocker);
+		break;
+
+	case SUSPEND_BLOCKER_IOCTL_UNBLOCK:
+		suspend_unblock(&blocker->blocker);
+		break;
+
+	default:
+		ret = -ENOTTY;
+	}
+done:
+	if (ret && (debug_mask & DEBUG_FAILURE))
+		pr_err("user_suspend_blocker_ioctl: cmd %x failed, %ld\n",
+			cmd, ret);
+	mutex_unlock(&ioctl_lock);
+	return ret;
+}
+
+static int user_suspend_blocker_release(struct inode *inode, struct file *filp)
+{
+	struct user_suspend_blocker *blocker = filp->private_data;
+
+	if (blocker->registered)
+		suspend_blocker_unregister(&blocker->blocker);
+	kfree(blocker);
+
+	return 0;
+}
+
+const struct file_operations user_suspend_blocker_fops = {
+	.open = user_suspend_blocker_open,
+	.release = user_suspend_blocker_release,
+	.unlocked_ioctl = user_suspend_blocker_ioctl,
+};
+
+struct miscdevice user_suspend_blocker_device = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "suspend_blocker",
+	.fops = &user_suspend_blocker_fops,
+};
+
+static int __init user_suspend_blocker_init(void)
+{
+	return misc_register(&user_suspend_blocker_device);
+}
+
+static void __exit user_suspend_blocker_exit(void)
+{
+	misc_deregister(&user_suspend_blocker_device);
+}
+
+module_init(user_suspend_blocker_init);
+module_exit(user_suspend_blocker_exit);
-- 
1.6.5.1


^ permalink raw reply related	[flat|nested] 93+ messages in thread

* [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-05-21 22:46 ` [PATCH 1/8] PM: Opportunistic suspend support Arve Hjønnevåg
  2010-05-21 22:46   ` [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space Arve Hjønnevåg
@ 2010-05-21 22:46   ` Arve Hjønnevåg
  1 sibling, 0 replies; 93+ messages in thread
From: Arve Hjønnevåg @ 2010-05-21 22:46 UTC (permalink / raw)
  To: linux-pm, linux-kernel
  Cc: Len Brown, Jim Collar, linux-doc, Greg Kroah-Hartman, Avi Kivity,
	Ryusuke Konishi, Magnus Damm, Andrew Morton

Add a misc device, "suspend_blocker", that allows user-space processes
to block automatic suspend.

Opening this device creates a suspend blocker that can be used by the
opener to prevent automatic suspend from occurring.  There are ioctls
provided for blocking and unblocking suspend and for giving the
suspend blocker a meaningful name.  Closing the device special file
causes the suspend blocker to be destroyed.

For example, when select or poll indicates that input event are
available, this interface can be used by user space to block suspend
before it reads those events. This allows the input driver to release
its suspend blocker as soon as the event queue is empty. If user space
could not use a suspend blocker here the input driver would need to
delay the release of its suspend blocker until it knows (or assumes)
that user space has finished processing the events.

By careful use of suspend blockers in drivers and user space system
code, one can arrange for the system to stay awake for extremely short
periods of time in reaction to events, rapidly returning to a fully
suspended state.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
 Documentation/ioctl/ioctl-number.txt          |    3 +-
 Documentation/power/opportunistic-suspend.txt |   27 +++++
 include/linux/suspend_ioctls.h                |    4 +
 kernel/power/Kconfig                          |    7 ++
 kernel/power/Makefile                         |    1 +
 kernel/power/user_suspend_blocker.c           |  143 +++++++++++++++++++++++++
 6 files changed, 184 insertions(+), 1 deletions(-)
 create mode 100644 kernel/power/user_suspend_blocker.c

diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index dd5806f..e2458f7 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -254,7 +254,8 @@ Code  Seq#(hex)	Include File		Comments
 'q'	80-FF	linux/telephony.h	Internet PhoneJACK, Internet LineJACK
 		linux/ixjuser.h		<http://www.quicknet.net>
 'r'	00-1F	linux/msdos_fs.h and fs/fat/dir.c
-'s'	all	linux/cdk.h
+'s'	all	linux/cdk.h	conflict!
+'s'	all	linux/suspend_block_dev.h	conflict!
 't'	00-7F	linux/if_ppp.h
 't'	80-8F	linux/isdn_ppp.h
 't'	90	linux/toshiba.h
diff --git a/Documentation/power/opportunistic-suspend.txt b/Documentation/power/opportunistic-suspend.txt
index 4bee7bc..93f4c24 100644
--- a/Documentation/power/opportunistic-suspend.txt
+++ b/Documentation/power/opportunistic-suspend.txt
@@ -127,3 +127,30 @@ if (list_empty(&state->pending_work))
 	suspend_unblock(&state->suspend_blocker);
 else
 	suspend_block(&state->suspend_blocker);
+
+User space API
+==============
+
+To create a suspend blocker from user space, open the suspend_blocker special
+device file:
+
+    fd = open("/dev/suspend_blocker", O_RDWR | O_CLOEXEC);
+
+then optionally call:
+
+    ioctl(fd, SUSPEND_BLOCKER_IOCTL_SET_NAME(strlen(name)), name);
+
+To activate the suspend blocker call:
+
+    ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK);
+
+To deactivate it call:
+
+    ioctl(fd, SUSPEND_BLOCKER_IOCTL_UNBLOCK);
+
+To destroy the suspend blocker, close the device:
+
+    close(fd);
+
+If the first ioctl called is not SUSPEND_BLOCKER_IOCTL_SET_NAME the suspend
+blocker will get the default name "(userspace)".
diff --git a/include/linux/suspend_ioctls.h b/include/linux/suspend_ioctls.h
index 0b30382..b95a6b2 100644
--- a/include/linux/suspend_ioctls.h
+++ b/include/linux/suspend_ioctls.h
@@ -30,4 +30,8 @@ struct resume_swap_area {
 #define SNAPSHOT_ALLOC_SWAP_PAGE	_IOR(SNAPSHOT_IOC_MAGIC, 20, __kernel_loff_t)
 #define SNAPSHOT_IOC_MAXNR	20
 
+#define SUSPEND_BLOCKER_IOCTL_SET_NAME(len)	_IOC(_IOC_WRITE, 's', 0, len)
+#define SUSPEND_BLOCKER_IOCTL_BLOCK		_IO('s', 1)
+#define SUSPEND_BLOCKER_IOCTL_UNBLOCK		_IO('s', 2)
+
 #endif /* _LINUX_SUSPEND_IOCTLS_H */
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 6d11a45..2e665cd 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -146,6 +146,13 @@ config OPPORTUNISTIC_SUSPEND
 	  determines the sleep state the system will be put into when there are
 	  no active suspend blockers.
 
+config USER_SUSPEND_BLOCKERS
+	bool "User space suspend blockers"
+	depends on OPPORTUNISTIC_SUSPEND
+	---help---
+	  User space suspend blockers API.  Creates a misc device allowing user
+	  space to create, use and destroy suspend blockers.
+
 config HIBERNATION_NVS
 	bool
 
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index 95d8e6d..2015594 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_PM_SLEEP)		+= console.o
 obj-$(CONFIG_FREEZER)		+= process.o
 obj-$(CONFIG_SUSPEND)		+= suspend.o
 obj-$(CONFIG_OPPORTUNISTIC_SUSPEND)	+= opportunistic_suspend.o
+obj-$(CONFIG_USER_SUSPEND_BLOCKERS)	+= user_suspend_blocker.o
 obj-$(CONFIG_PM_TEST_SUSPEND)	+= suspend_test.o
 obj-$(CONFIG_HIBERNATION)	+= hibernate.o snapshot.o swap.o user.o
 obj-$(CONFIG_HIBERNATION_NVS)	+= hibernate_nvs.o
diff --git a/kernel/power/user_suspend_blocker.c b/kernel/power/user_suspend_blocker.c
new file mode 100644
index 0000000..d53f939
--- /dev/null
+++ b/kernel/power/user_suspend_blocker.c
@@ -0,0 +1,143 @@
+/*
+ * kernel/power/user_suspend_blocker.c
+ *
+ * Copyright (C) 2009-2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/suspend.h>
+#include <linux/suspend_ioctls.h>
+
+enum {
+	DEBUG_FAILURE	= BIT(0),
+};
+static int debug_mask = DEBUG_FAILURE;
+module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+static DEFINE_MUTEX(ioctl_lock);
+
+#define USER_SUSPEND_BLOCKER_NAME_LEN 31
+
+struct user_suspend_blocker {
+	struct suspend_blocker	blocker;
+	char			name[USER_SUSPEND_BLOCKER_NAME_LEN + 1];
+	bool			registered;
+};
+
+static int user_suspend_blocker_open(struct inode *inode, struct file *filp)
+{
+	struct user_suspend_blocker *blocker;
+
+	blocker = kzalloc(sizeof(*blocker), GFP_KERNEL);
+	if (!blocker)
+		return -ENOMEM;
+
+	nonseekable_open(inode, filp);
+	strcpy(blocker->name, "(userspace)");
+	blocker->blocker.name = blocker->name;
+	filp->private_data = blocker;
+
+	return 0;
+}
+
+static int suspend_blocker_set_name(struct user_suspend_blocker *blocker,
+				    void __user *name, size_t name_len)
+{
+	if (blocker->registered)
+		return -EBUSY;
+
+	if (name_len > USER_SUSPEND_BLOCKER_NAME_LEN)
+		name_len = USER_SUSPEND_BLOCKER_NAME_LEN;
+
+	if (copy_from_user(blocker->name, name, name_len))
+		return -EFAULT;
+	blocker->name[name_len] = '\0';
+
+	return 0;
+}
+
+static long user_suspend_blocker_ioctl(struct file *filp, unsigned int cmd,
+					unsigned long _arg)
+{
+	void __user *arg = (void __user *)_arg;
+	struct user_suspend_blocker *blocker = filp->private_data;
+	long ret = 0;
+
+	mutex_lock(&ioctl_lock);
+	if ((cmd & ~IOCSIZE_MASK) == SUSPEND_BLOCKER_IOCTL_SET_NAME(0)) {
+		ret = suspend_blocker_set_name(blocker, arg, _IOC_SIZE(cmd));
+		goto done;
+	}
+	if (!blocker->registered) {
+		suspend_blocker_register(&blocker->blocker);
+		blocker->registered = true;
+	}
+	switch (cmd) {
+	case SUSPEND_BLOCKER_IOCTL_BLOCK:
+		suspend_block(&blocker->blocker);
+		break;
+
+	case SUSPEND_BLOCKER_IOCTL_UNBLOCK:
+		suspend_unblock(&blocker->blocker);
+		break;
+
+	default:
+		ret = -ENOTTY;
+	}
+done:
+	if (ret && (debug_mask & DEBUG_FAILURE))
+		pr_err("user_suspend_blocker_ioctl: cmd %x failed, %ld\n",
+			cmd, ret);
+	mutex_unlock(&ioctl_lock);
+	return ret;
+}
+
+static int user_suspend_blocker_release(struct inode *inode, struct file *filp)
+{
+	struct user_suspend_blocker *blocker = filp->private_data;
+
+	if (blocker->registered)
+		suspend_blocker_unregister(&blocker->blocker);
+	kfree(blocker);
+
+	return 0;
+}
+
+const struct file_operations user_suspend_blocker_fops = {
+	.open = user_suspend_blocker_open,
+	.release = user_suspend_blocker_release,
+	.unlocked_ioctl = user_suspend_blocker_ioctl,
+};
+
+struct miscdevice user_suspend_blocker_device = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "suspend_blocker",
+	.fops = &user_suspend_blocker_fops,
+};
+
+static int __init user_suspend_blocker_init(void)
+{
+	return misc_register(&user_suspend_blocker_device);
+}
+
+static void __exit user_suspend_blocker_exit(void)
+{
+	misc_deregister(&user_suspend_blocker_device);
+}
+
+module_init(user_suspend_blocker_init);
+module_exit(user_suspend_blocker_exit);
-- 
1.6.5.1

_______________________________________________
linux-pm mailing list
linux-pm@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/linux-pm

^ permalink raw reply related	[flat|nested] 93+ messages in thread

* [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-05-14  4:11 ` [PATCH 1/8] PM: Add suspend block api Arve Hjønnevåg
@ 2010-05-14  4:11     ` Arve Hjønnevåg
  0 siblings, 0 replies; 93+ messages in thread
From: Arve Hjønnevåg @ 2010-05-14  4:11 UTC (permalink / raw)
  To: linux-pm, linux-kernel
  Cc: Rafael J. Wysocki, Arve Hjønnevåg, Randy Dunlap,
	Andrew Morton, Ryusuke Konishi, Jim Collar, Greg Kroah-Hartman,
	Avi Kivity, Len Brown, Pavel Machek, Magnus Damm, Cornelia Huck,
	Nigel Cunningham, linux-doc

Add a misc device, "suspend_blocker", that allows user-space processes
to block auto suspend. The device has ioctls to create a suspend_blocker,
and to block and unblock suspend. To delete the suspend_blocker, close
the device.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
 Documentation/ioctl/ioctl-number.txt          |    3 +-
 Documentation/power/opportunistic-suspend.txt |   27 +++++
 include/linux/suspend_ioctls.h                |    4 +
 kernel/power/Kconfig                          |    7 ++
 kernel/power/Makefile                         |    1 +
 kernel/power/user_suspend_blocker.c           |  143 +++++++++++++++++++++++++
 6 files changed, 184 insertions(+), 1 deletions(-)
 create mode 100644 kernel/power/user_suspend_blocker.c

diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index dd5806f..e2458f7 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -254,7 +254,8 @@ Code  Seq#(hex)	Include File		Comments
 'q'	80-FF	linux/telephony.h	Internet PhoneJACK, Internet LineJACK
 		linux/ixjuser.h		<http://www.quicknet.net>
 'r'	00-1F	linux/msdos_fs.h and fs/fat/dir.c
-'s'	all	linux/cdk.h
+'s'	all	linux/cdk.h	conflict!
+'s'	all	linux/suspend_block_dev.h	conflict!
 't'	00-7F	linux/if_ppp.h
 't'	80-8F	linux/isdn_ppp.h
 't'	90	linux/toshiba.h
diff --git a/Documentation/power/opportunistic-suspend.txt b/Documentation/power/opportunistic-suspend.txt
index 4bee7bc..93f4c24 100644
--- a/Documentation/power/opportunistic-suspend.txt
+++ b/Documentation/power/opportunistic-suspend.txt
@@ -127,3 +127,30 @@ if (list_empty(&state->pending_work))
 	suspend_unblock(&state->suspend_blocker);
 else
 	suspend_block(&state->suspend_blocker);
+
+User space API
+==============
+
+To create a suspend blocker from user space, open the suspend_blocker special
+device file:
+
+    fd = open("/dev/suspend_blocker", O_RDWR | O_CLOEXEC);
+
+then optionally call:
+
+    ioctl(fd, SUSPEND_BLOCKER_IOCTL_SET_NAME(strlen(name)), name);
+
+To activate the suspend blocker call:
+
+    ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK);
+
+To deactivate it call:
+
+    ioctl(fd, SUSPEND_BLOCKER_IOCTL_UNBLOCK);
+
+To destroy the suspend blocker, close the device:
+
+    close(fd);
+
+If the first ioctl called is not SUSPEND_BLOCKER_IOCTL_SET_NAME the suspend
+blocker will get the default name "(userspace)".
diff --git a/include/linux/suspend_ioctls.h b/include/linux/suspend_ioctls.h
index 0b30382..b95a6b2 100644
--- a/include/linux/suspend_ioctls.h
+++ b/include/linux/suspend_ioctls.h
@@ -30,4 +30,8 @@ struct resume_swap_area {
 #define SNAPSHOT_ALLOC_SWAP_PAGE	_IOR(SNAPSHOT_IOC_MAGIC, 20, __kernel_loff_t)
 #define SNAPSHOT_IOC_MAXNR	20
 
+#define SUSPEND_BLOCKER_IOCTL_SET_NAME(len)	_IOC(_IOC_WRITE, 's', 0, len)
+#define SUSPEND_BLOCKER_IOCTL_BLOCK		_IO('s', 1)
+#define SUSPEND_BLOCKER_IOCTL_UNBLOCK		_IO('s', 2)
+
 #endif /* _LINUX_SUSPEND_IOCTLS_H */
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 6d11a45..2e665cd 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -146,6 +146,13 @@ config OPPORTUNISTIC_SUSPEND
 	  determines the sleep state the system will be put into when there are
 	  no active suspend blockers.
 
+config USER_SUSPEND_BLOCKERS
+	bool "User space suspend blockers"
+	depends on OPPORTUNISTIC_SUSPEND
+	---help---
+	  User space suspend blockers API.  Creates a misc device allowing user
+	  space to create, use and destroy suspend blockers.
+
 config HIBERNATION_NVS
 	bool
 
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index 95d8e6d..2015594 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_PM_SLEEP)		+= console.o
 obj-$(CONFIG_FREEZER)		+= process.o
 obj-$(CONFIG_SUSPEND)		+= suspend.o
 obj-$(CONFIG_OPPORTUNISTIC_SUSPEND)	+= opportunistic_suspend.o
+obj-$(CONFIG_USER_SUSPEND_BLOCKERS)	+= user_suspend_blocker.o
 obj-$(CONFIG_PM_TEST_SUSPEND)	+= suspend_test.o
 obj-$(CONFIG_HIBERNATION)	+= hibernate.o snapshot.o swap.o user.o
 obj-$(CONFIG_HIBERNATION_NVS)	+= hibernate_nvs.o
diff --git a/kernel/power/user_suspend_blocker.c b/kernel/power/user_suspend_blocker.c
new file mode 100644
index 0000000..d53f939
--- /dev/null
+++ b/kernel/power/user_suspend_blocker.c
@@ -0,0 +1,143 @@
+/*
+ * kernel/power/user_suspend_blocker.c
+ *
+ * Copyright (C) 2009-2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/suspend.h>
+#include <linux/suspend_ioctls.h>
+
+enum {
+	DEBUG_FAILURE	= BIT(0),
+};
+static int debug_mask = DEBUG_FAILURE;
+module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+static DEFINE_MUTEX(ioctl_lock);
+
+#define USER_SUSPEND_BLOCKER_NAME_LEN 31
+
+struct user_suspend_blocker {
+	struct suspend_blocker	blocker;
+	char			name[USER_SUSPEND_BLOCKER_NAME_LEN + 1];
+	bool			registered;
+};
+
+static int user_suspend_blocker_open(struct inode *inode, struct file *filp)
+{
+	struct user_suspend_blocker *blocker;
+
+	blocker = kzalloc(sizeof(*blocker), GFP_KERNEL);
+	if (!blocker)
+		return -ENOMEM;
+
+	nonseekable_open(inode, filp);
+	strcpy(blocker->name, "(userspace)");
+	blocker->blocker.name = blocker->name;
+	filp->private_data = blocker;
+
+	return 0;
+}
+
+static int suspend_blocker_set_name(struct user_suspend_blocker *blocker,
+				    void __user *name, size_t name_len)
+{
+	if (blocker->registered)
+		return -EBUSY;
+
+	if (name_len > USER_SUSPEND_BLOCKER_NAME_LEN)
+		name_len = USER_SUSPEND_BLOCKER_NAME_LEN;
+
+	if (copy_from_user(blocker->name, name, name_len))
+		return -EFAULT;
+	blocker->name[name_len] = '\0';
+
+	return 0;
+}
+
+static long user_suspend_blocker_ioctl(struct file *filp, unsigned int cmd,
+					unsigned long _arg)
+{
+	void __user *arg = (void __user *)_arg;
+	struct user_suspend_blocker *blocker = filp->private_data;
+	long ret = 0;
+
+	mutex_lock(&ioctl_lock);
+	if ((cmd & ~IOCSIZE_MASK) == SUSPEND_BLOCKER_IOCTL_SET_NAME(0)) {
+		ret = suspend_blocker_set_name(blocker, arg, _IOC_SIZE(cmd));
+		goto done;
+	}
+	if (!blocker->registered) {
+		suspend_blocker_register(&blocker->blocker);
+		blocker->registered = true;
+	}
+	switch (cmd) {
+	case SUSPEND_BLOCKER_IOCTL_BLOCK:
+		suspend_block(&blocker->blocker);
+		break;
+
+	case SUSPEND_BLOCKER_IOCTL_UNBLOCK:
+		suspend_unblock(&blocker->blocker);
+		break;
+
+	default:
+		ret = -ENOTTY;
+	}
+done:
+	if (ret && (debug_mask & DEBUG_FAILURE))
+		pr_err("user_suspend_blocker_ioctl: cmd %x failed, %ld\n",
+			cmd, ret);
+	mutex_unlock(&ioctl_lock);
+	return ret;
+}
+
+static int user_suspend_blocker_release(struct inode *inode, struct file *filp)
+{
+	struct user_suspend_blocker *blocker = filp->private_data;
+
+	if (blocker->registered)
+		suspend_blocker_unregister(&blocker->blocker);
+	kfree(blocker);
+
+	return 0;
+}
+
+const struct file_operations user_suspend_blocker_fops = {
+	.open = user_suspend_blocker_open,
+	.release = user_suspend_blocker_release,
+	.unlocked_ioctl = user_suspend_blocker_ioctl,
+};
+
+struct miscdevice user_suspend_blocker_device = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "suspend_blocker",
+	.fops = &user_suspend_blocker_fops,
+};
+
+static int __init user_suspend_blocker_init(void)
+{
+	return misc_register(&user_suspend_blocker_device);
+}
+
+static void __exit user_suspend_blocker_exit(void)
+{
+	misc_deregister(&user_suspend_blocker_device);
+}
+
+module_init(user_suspend_blocker_init);
+module_exit(user_suspend_blocker_exit);
-- 
1.6.5.1


^ permalink raw reply related	[flat|nested] 93+ messages in thread

* [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
@ 2010-05-14  4:11     ` Arve Hjønnevåg
  0 siblings, 0 replies; 93+ messages in thread
From: Arve Hjønnevåg @ 2010-05-14  4:11 UTC (permalink / raw)
  To: linux-pm, linux-kernel
  Cc: Len Brown, Jim Collar, linux-doc, Greg Kroah-Hartman, Avi Kivity,
	Ryusuke Konishi, Magnus Damm, Andrew Morton

Add a misc device, "suspend_blocker", that allows user-space processes
to block auto suspend. The device has ioctls to create a suspend_blocker,
and to block and unblock suspend. To delete the suspend_blocker, close
the device.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
 Documentation/ioctl/ioctl-number.txt          |    3 +-
 Documentation/power/opportunistic-suspend.txt |   27 +++++
 include/linux/suspend_ioctls.h                |    4 +
 kernel/power/Kconfig                          |    7 ++
 kernel/power/Makefile                         |    1 +
 kernel/power/user_suspend_blocker.c           |  143 +++++++++++++++++++++++++
 6 files changed, 184 insertions(+), 1 deletions(-)
 create mode 100644 kernel/power/user_suspend_blocker.c

diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index dd5806f..e2458f7 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -254,7 +254,8 @@ Code  Seq#(hex)	Include File		Comments
 'q'	80-FF	linux/telephony.h	Internet PhoneJACK, Internet LineJACK
 		linux/ixjuser.h		<http://www.quicknet.net>
 'r'	00-1F	linux/msdos_fs.h and fs/fat/dir.c
-'s'	all	linux/cdk.h
+'s'	all	linux/cdk.h	conflict!
+'s'	all	linux/suspend_block_dev.h	conflict!
 't'	00-7F	linux/if_ppp.h
 't'	80-8F	linux/isdn_ppp.h
 't'	90	linux/toshiba.h
diff --git a/Documentation/power/opportunistic-suspend.txt b/Documentation/power/opportunistic-suspend.txt
index 4bee7bc..93f4c24 100644
--- a/Documentation/power/opportunistic-suspend.txt
+++ b/Documentation/power/opportunistic-suspend.txt
@@ -127,3 +127,30 @@ if (list_empty(&state->pending_work))
 	suspend_unblock(&state->suspend_blocker);
 else
 	suspend_block(&state->suspend_blocker);
+
+User space API
+==============
+
+To create a suspend blocker from user space, open the suspend_blocker special
+device file:
+
+    fd = open("/dev/suspend_blocker", O_RDWR | O_CLOEXEC);
+
+then optionally call:
+
+    ioctl(fd, SUSPEND_BLOCKER_IOCTL_SET_NAME(strlen(name)), name);
+
+To activate the suspend blocker call:
+
+    ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK);
+
+To deactivate it call:
+
+    ioctl(fd, SUSPEND_BLOCKER_IOCTL_UNBLOCK);
+
+To destroy the suspend blocker, close the device:
+
+    close(fd);
+
+If the first ioctl called is not SUSPEND_BLOCKER_IOCTL_SET_NAME the suspend
+blocker will get the default name "(userspace)".
diff --git a/include/linux/suspend_ioctls.h b/include/linux/suspend_ioctls.h
index 0b30382..b95a6b2 100644
--- a/include/linux/suspend_ioctls.h
+++ b/include/linux/suspend_ioctls.h
@@ -30,4 +30,8 @@ struct resume_swap_area {
 #define SNAPSHOT_ALLOC_SWAP_PAGE	_IOR(SNAPSHOT_IOC_MAGIC, 20, __kernel_loff_t)
 #define SNAPSHOT_IOC_MAXNR	20
 
+#define SUSPEND_BLOCKER_IOCTL_SET_NAME(len)	_IOC(_IOC_WRITE, 's', 0, len)
+#define SUSPEND_BLOCKER_IOCTL_BLOCK		_IO('s', 1)
+#define SUSPEND_BLOCKER_IOCTL_UNBLOCK		_IO('s', 2)
+
 #endif /* _LINUX_SUSPEND_IOCTLS_H */
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 6d11a45..2e665cd 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -146,6 +146,13 @@ config OPPORTUNISTIC_SUSPEND
 	  determines the sleep state the system will be put into when there are
 	  no active suspend blockers.
 
+config USER_SUSPEND_BLOCKERS
+	bool "User space suspend blockers"
+	depends on OPPORTUNISTIC_SUSPEND
+	---help---
+	  User space suspend blockers API.  Creates a misc device allowing user
+	  space to create, use and destroy suspend blockers.
+
 config HIBERNATION_NVS
 	bool
 
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index 95d8e6d..2015594 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_PM_SLEEP)		+= console.o
 obj-$(CONFIG_FREEZER)		+= process.o
 obj-$(CONFIG_SUSPEND)		+= suspend.o
 obj-$(CONFIG_OPPORTUNISTIC_SUSPEND)	+= opportunistic_suspend.o
+obj-$(CONFIG_USER_SUSPEND_BLOCKERS)	+= user_suspend_blocker.o
 obj-$(CONFIG_PM_TEST_SUSPEND)	+= suspend_test.o
 obj-$(CONFIG_HIBERNATION)	+= hibernate.o snapshot.o swap.o user.o
 obj-$(CONFIG_HIBERNATION_NVS)	+= hibernate_nvs.o
diff --git a/kernel/power/user_suspend_blocker.c b/kernel/power/user_suspend_blocker.c
new file mode 100644
index 0000000..d53f939
--- /dev/null
+++ b/kernel/power/user_suspend_blocker.c
@@ -0,0 +1,143 @@
+/*
+ * kernel/power/user_suspend_blocker.c
+ *
+ * Copyright (C) 2009-2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/suspend.h>
+#include <linux/suspend_ioctls.h>
+
+enum {
+	DEBUG_FAILURE	= BIT(0),
+};
+static int debug_mask = DEBUG_FAILURE;
+module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+static DEFINE_MUTEX(ioctl_lock);
+
+#define USER_SUSPEND_BLOCKER_NAME_LEN 31
+
+struct user_suspend_blocker {
+	struct suspend_blocker	blocker;
+	char			name[USER_SUSPEND_BLOCKER_NAME_LEN + 1];
+	bool			registered;
+};
+
+static int user_suspend_blocker_open(struct inode *inode, struct file *filp)
+{
+	struct user_suspend_blocker *blocker;
+
+	blocker = kzalloc(sizeof(*blocker), GFP_KERNEL);
+	if (!blocker)
+		return -ENOMEM;
+
+	nonseekable_open(inode, filp);
+	strcpy(blocker->name, "(userspace)");
+	blocker->blocker.name = blocker->name;
+	filp->private_data = blocker;
+
+	return 0;
+}
+
+static int suspend_blocker_set_name(struct user_suspend_blocker *blocker,
+				    void __user *name, size_t name_len)
+{
+	if (blocker->registered)
+		return -EBUSY;
+
+	if (name_len > USER_SUSPEND_BLOCKER_NAME_LEN)
+		name_len = USER_SUSPEND_BLOCKER_NAME_LEN;
+
+	if (copy_from_user(blocker->name, name, name_len))
+		return -EFAULT;
+	blocker->name[name_len] = '\0';
+
+	return 0;
+}
+
+static long user_suspend_blocker_ioctl(struct file *filp, unsigned int cmd,
+					unsigned long _arg)
+{
+	void __user *arg = (void __user *)_arg;
+	struct user_suspend_blocker *blocker = filp->private_data;
+	long ret = 0;
+
+	mutex_lock(&ioctl_lock);
+	if ((cmd & ~IOCSIZE_MASK) == SUSPEND_BLOCKER_IOCTL_SET_NAME(0)) {
+		ret = suspend_blocker_set_name(blocker, arg, _IOC_SIZE(cmd));
+		goto done;
+	}
+	if (!blocker->registered) {
+		suspend_blocker_register(&blocker->blocker);
+		blocker->registered = true;
+	}
+	switch (cmd) {
+	case SUSPEND_BLOCKER_IOCTL_BLOCK:
+		suspend_block(&blocker->blocker);
+		break;
+
+	case SUSPEND_BLOCKER_IOCTL_UNBLOCK:
+		suspend_unblock(&blocker->blocker);
+		break;
+
+	default:
+		ret = -ENOTTY;
+	}
+done:
+	if (ret && (debug_mask & DEBUG_FAILURE))
+		pr_err("user_suspend_blocker_ioctl: cmd %x failed, %ld\n",
+			cmd, ret);
+	mutex_unlock(&ioctl_lock);
+	return ret;
+}
+
+static int user_suspend_blocker_release(struct inode *inode, struct file *filp)
+{
+	struct user_suspend_blocker *blocker = filp->private_data;
+
+	if (blocker->registered)
+		suspend_blocker_unregister(&blocker->blocker);
+	kfree(blocker);
+
+	return 0;
+}
+
+const struct file_operations user_suspend_blocker_fops = {
+	.open = user_suspend_blocker_open,
+	.release = user_suspend_blocker_release,
+	.unlocked_ioctl = user_suspend_blocker_ioctl,
+};
+
+struct miscdevice user_suspend_blocker_device = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "suspend_blocker",
+	.fops = &user_suspend_blocker_fops,
+};
+
+static int __init user_suspend_blocker_init(void)
+{
+	return misc_register(&user_suspend_blocker_device);
+}
+
+static void __exit user_suspend_blocker_exit(void)
+{
+	misc_deregister(&user_suspend_blocker_device);
+}
+
+module_init(user_suspend_blocker_init);
+module_exit(user_suspend_blocker_exit);
-- 
1.6.5.1

_______________________________________________
linux-pm mailing list
linux-pm@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/linux-pm

^ permalink raw reply related	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-05-03 22:01               ` Arve Hjønnevåg
  2010-05-04 20:02                 ` Rafael J. Wysocki
@ 2010-05-04 20:02                 ` Rafael J. Wysocki
  1 sibling, 0 replies; 93+ messages in thread
From: Rafael J. Wysocki @ 2010-05-04 20:02 UTC (permalink / raw)
  To: Arve Hjønnevåg
  Cc: Alan Stern, Linux-pm mailing list, Kernel development list,
	Tejun Heo, Oleg Nesterov, Randy Dunlap, Andrew Morton,
	Ryusuke Konishi, Jim Collar, Greg Kroah-Hartman, Avi Kivity,
	Len Brown, Pavel Machek, Cornelia Huck, Nigel Cunningham,
	linux-doc

On Tuesday 04 May 2010, Arve Hjønnevåg wrote:
> 2010/5/3 Rafael J. Wysocki <rjw@sisk.pl>:
> > On Monday 03 May 2010, Arve Hjønnevåg wrote:
> >> On Mon, May 3, 2010 at 8:03 AM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> >> > On Sunday 02 May 2010, Alan Stern wrote:
> >> >> On Sun, 2 May 2010, Rafael J. Wysocki wrote:
> >> >>
> >> >> > Hmm.  It doesn't seem to be possible to create two different suspend blockers
> >> >> > using the same file handle.  So, what exactly is a process supposed to do to
> >> >> > use two suspend blockers at the same time?
> >> >>
> >> >> Open the file twice, thereby obtaining two file handles.
> >> >
> >> > Well, that's what I thought.
> >> >
> >> > I must admit I'm not really comfortable with this interface.  IMO it would
> >> > be better if _open() created the suspend blocker giving it a name based on
> >> > the name of the process that called it.  Something like
> >> > "<process name>_<timestamp>" might work at first sight.
> >> >
> >> > Alternatively, "<process_name><number>", where <number> is 0 for the first
> >> > suspend blocker created by the given process, 1 for the second one etc., also
> >> > seems to be doable.
> >>
> >> I think it is important to let user-space specify the name. If a
> >> process uses multiple suspend blockers, it is impossible to tell what
> >> each one is used for if they are automatically named.
> >
> > Well, the problem is the only purpose of this is user space debugging, isn't it?
> >
> At the moment, yes.

OK

> But having an explicit init call also simplifies future expansion.

That's irrelevant.  Let's focus _only_ on the "at the moment" part, please.

And BTW, a "future expansion" is not relevant at all to the patchset at hand
and let's work with this assumption from now on.  OK?

> If we ever need to add back multiple types of
> suspend blockers, we can add an init call with a type argument and
> have the current init call use the default type. If the past we have
> had types that keeps the screen on and prevented idle sleep modes. In
> the future we could for instance want to specify if a suspend blocker
> should prevent suspend when the battery is low or when the lid is
> closed.

_If_ we ever do anything like thie, _then_ we will extend the interface.

> > Now, while I don't think it's generally bad to provide kernel interfaces
> > helping to debug user space, I'm not quite sure if that should be done at the
> > expense of the clarity of kernel-user space interfaces.
> >
> > I wonder how many cases there are in which distinguishing between suspend
> > blockers used by the same user space task is practically relevant.
> >
> 
> I think all of them (when more than one suspend blocker is used).

So how many user space processes use more than one suspend blocker right
now on Android?  I'm interested only in the order of magnitude.

Rafael

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-05-03 22:01               ` Arve Hjønnevåg
@ 2010-05-04 20:02                 ` Rafael J. Wysocki
  2010-05-04 20:02                 ` Rafael J. Wysocki
  1 sibling, 0 replies; 93+ messages in thread
From: Rafael J. Wysocki @ 2010-05-04 20:02 UTC (permalink / raw)
  To: Arve Hjønnevåg
  Cc: Len Brown, Jim Collar, linux-doc, Greg Kroah-Hartman,
	Kernel development list, Oleg Nesterov, Avi Kivity,
	Ryusuke Konishi, Tejun Heo, Linux-pm mailing list, Andrew Morton

On Tuesday 04 May 2010, Arve Hjønnevåg wrote:
> 2010/5/3 Rafael J. Wysocki <rjw@sisk.pl>:
> > On Monday 03 May 2010, Arve Hjønnevåg wrote:
> >> On Mon, May 3, 2010 at 8:03 AM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> >> > On Sunday 02 May 2010, Alan Stern wrote:
> >> >> On Sun, 2 May 2010, Rafael J. Wysocki wrote:
> >> >>
> >> >> > Hmm.  It doesn't seem to be possible to create two different suspend blockers
> >> >> > using the same file handle.  So, what exactly is a process supposed to do to
> >> >> > use two suspend blockers at the same time?
> >> >>
> >> >> Open the file twice, thereby obtaining two file handles.
> >> >
> >> > Well, that's what I thought.
> >> >
> >> > I must admit I'm not really comfortable with this interface.  IMO it would
> >> > be better if _open() created the suspend blocker giving it a name based on
> >> > the name of the process that called it.  Something like
> >> > "<process name>_<timestamp>" might work at first sight.
> >> >
> >> > Alternatively, "<process_name><number>", where <number> is 0 for the first
> >> > suspend blocker created by the given process, 1 for the second one etc., also
> >> > seems to be doable.
> >>
> >> I think it is important to let user-space specify the name. If a
> >> process uses multiple suspend blockers, it is impossible to tell what
> >> each one is used for if they are automatically named.
> >
> > Well, the problem is the only purpose of this is user space debugging, isn't it?
> >
> At the moment, yes.

OK

> But having an explicit init call also simplifies future expansion.

That's irrelevant.  Let's focus _only_ on the "at the moment" part, please.

And BTW, a "future expansion" is not relevant at all to the patchset at hand
and let's work with this assumption from now on.  OK?

> If we ever need to add back multiple types of
> suspend blockers, we can add an init call with a type argument and
> have the current init call use the default type. If the past we have
> had types that keeps the screen on and prevented idle sleep modes. In
> the future we could for instance want to specify if a suspend blocker
> should prevent suspend when the battery is low or when the lid is
> closed.

_If_ we ever do anything like thie, _then_ we will extend the interface.

> > Now, while I don't think it's generally bad to provide kernel interfaces
> > helping to debug user space, I'm not quite sure if that should be done at the
> > expense of the clarity of kernel-user space interfaces.
> >
> > I wonder how many cases there are in which distinguishing between suspend
> > blockers used by the same user space task is practically relevant.
> >
> 
> I think all of them (when more than one suspend blocker is used).

So how many user space processes use more than one suspend blocker right
now on Android?  I'm interested only in the order of magnitude.

Rafael

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-05-03 15:03         ` Rafael J. Wysocki
                             ` (2 preceding siblings ...)
  2010-05-04  4:16           ` Pavel Machek
@ 2010-05-04  4:16           ` Pavel Machek
  3 siblings, 0 replies; 93+ messages in thread
From: Pavel Machek @ 2010-05-04  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Alan Stern, Arve Hj?nnev?g, Linux-pm mailing list,
	Kernel development list, Tejun Heo, Oleg Nesterov, Randy Dunlap,
	Andrew Morton, Ryusuke Konishi, Jim Collar, Greg Kroah-Hartman,
	Avi Kivity, Len Brown, Cornelia Huck, Nigel Cunningham,
	linux-doc

On Mon 2010-05-03 17:03:11, Rafael J. Wysocki wrote:
> On Sunday 02 May 2010, Alan Stern wrote:
> > On Sun, 2 May 2010, Rafael J. Wysocki wrote:
> > 
> > > Hmm.  It doesn't seem to be possible to create two different suspend blockers
> > > using the same file handle.  So, what exactly is a process supposed to do to
> > > use two suspend blockers at the same time?
> > 
> > Open the file twice, thereby obtaining two file handles.
> 
> Well, that's what I thought.
> 
> I must admit I'm not really comfortable with this interface.  IMO it would
> be better if _open() created the suspend blocker giving it a name based on
> the name of the process that called it.  Something like
> "<process name>_<timestamp>" might work at first sight.
> 
> Alternatively, "<process_name><number>", where <number> is 0 for the first
> suspend blocker created by the given process, 1 for the second one etc., also
> seems to be doable.

Yes please.

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-05-03 15:03         ` Rafael J. Wysocki
  2010-05-03 21:26           ` Arve Hjønnevåg
  2010-05-03 21:26           ` Arve Hjønnevåg
@ 2010-05-04  4:16           ` Pavel Machek
  2010-05-04  4:16           ` Pavel Machek
  3 siblings, 0 replies; 93+ messages in thread
From: Pavel Machek @ 2010-05-04  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Len Brown, Jim Collar, linux-doc, Greg Kroah-Hartman,
	Oleg Nesterov, Kernel development list, Avi Kivity,
	Ryusuke Konishi, Tejun Heo, Linux-pm mailing list, Andrew Morton

On Mon 2010-05-03 17:03:11, Rafael J. Wysocki wrote:
> On Sunday 02 May 2010, Alan Stern wrote:
> > On Sun, 2 May 2010, Rafael J. Wysocki wrote:
> > 
> > > Hmm.  It doesn't seem to be possible to create two different suspend blockers
> > > using the same file handle.  So, what exactly is a process supposed to do to
> > > use two suspend blockers at the same time?
> > 
> > Open the file twice, thereby obtaining two file handles.
> 
> Well, that's what I thought.
> 
> I must admit I'm not really comfortable with this interface.  IMO it would
> be better if _open() created the suspend blocker giving it a name based on
> the name of the process that called it.  Something like
> "<process name>_<timestamp>" might work at first sight.
> 
> Alternatively, "<process_name><number>", where <number> is 0 for the first
> suspend blocker created by the given process, 1 for the second one etc., also
> seems to be doable.

Yes please.

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend  blockers from user-space
  2010-05-03 21:49             ` Rafael J. Wysocki
  2010-05-03 22:01               ` Arve Hjønnevåg
@ 2010-05-03 22:01               ` Arve Hjønnevåg
  2010-05-04 20:02                 ` Rafael J. Wysocki
  2010-05-04 20:02                 ` Rafael J. Wysocki
  1 sibling, 2 replies; 93+ messages in thread
From: Arve Hjønnevåg @ 2010-05-03 22:01 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Alan Stern, Linux-pm mailing list, Kernel development list,
	Tejun Heo, Oleg Nesterov, Randy Dunlap, Andrew Morton,
	Ryusuke Konishi, Jim Collar, Greg Kroah-Hartman, Avi Kivity,
	Len Brown, Pavel Machek, Cornelia Huck, Nigel Cunningham,
	linux-doc

2010/5/3 Rafael J. Wysocki <rjw@sisk.pl>:
> On Monday 03 May 2010, Arve Hjønnevåg wrote:
>> On Mon, May 3, 2010 at 8:03 AM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
>> > On Sunday 02 May 2010, Alan Stern wrote:
>> >> On Sun, 2 May 2010, Rafael J. Wysocki wrote:
>> >>
>> >> > Hmm.  It doesn't seem to be possible to create two different suspend blockers
>> >> > using the same file handle.  So, what exactly is a process supposed to do to
>> >> > use two suspend blockers at the same time?
>> >>
>> >> Open the file twice, thereby obtaining two file handles.
>> >
>> > Well, that's what I thought.
>> >
>> > I must admit I'm not really comfortable with this interface.  IMO it would
>> > be better if _open() created the suspend blocker giving it a name based on
>> > the name of the process that called it.  Something like
>> > "<process name>_<timestamp>" might work at first sight.
>> >
>> > Alternatively, "<process_name><number>", where <number> is 0 for the first
>> > suspend blocker created by the given process, 1 for the second one etc., also
>> > seems to be doable.
>>
>> I think it is important to let user-space specify the name. If a
>> process uses multiple suspend blockers, it is impossible to tell what
>> each one is used for if they are automatically named.
>
> Well, the problem is the only purpose of this is user space debugging, isn't it?
>
At the moment, yes. But having an explicit init call also simplifies
future expansion. If we ever need to add back multiple types of
suspend blockers, we can add an init call with a type argument and
have the current init call use the default type. If the past we have
had types that keeps the screen on and prevented idle sleep modes. In
the future we could for instance want to specify if a suspend blocker
should prevent suspend when the battery is low or when the lid is
closed.

> Now, while I don't think it's generally bad to provide kernel interfaces
> helping to debug user space, I'm not quite sure if that should be done at the
> expense of the clarity of kernel-user space interfaces.
>
> I wonder how many cases there are in which distinguishing between suspend
> blockers used by the same user space task is practically relevant.
>

I think all of them (when more than one suspend blocker is used).

-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-05-03 21:49             ` Rafael J. Wysocki
@ 2010-05-03 22:01               ` Arve Hjønnevåg
  2010-05-03 22:01               ` Arve Hjønnevåg
  1 sibling, 0 replies; 93+ messages in thread
From: Arve Hjønnevåg @ 2010-05-03 22:01 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Len Brown, Jim Collar, linux-doc, Greg Kroah-Hartman,
	Kernel development list, Oleg Nesterov, Avi Kivity,
	Ryusuke Konishi, Tejun Heo, Linux-pm mailing list, Andrew Morton

2010/5/3 Rafael J. Wysocki <rjw@sisk.pl>:
> On Monday 03 May 2010, Arve Hjønnevåg wrote:
>> On Mon, May 3, 2010 at 8:03 AM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
>> > On Sunday 02 May 2010, Alan Stern wrote:
>> >> On Sun, 2 May 2010, Rafael J. Wysocki wrote:
>> >>
>> >> > Hmm.  It doesn't seem to be possible to create two different suspend blockers
>> >> > using the same file handle.  So, what exactly is a process supposed to do to
>> >> > use two suspend blockers at the same time?
>> >>
>> >> Open the file twice, thereby obtaining two file handles.
>> >
>> > Well, that's what I thought.
>> >
>> > I must admit I'm not really comfortable with this interface.  IMO it would
>> > be better if _open() created the suspend blocker giving it a name based on
>> > the name of the process that called it.  Something like
>> > "<process name>_<timestamp>" might work at first sight.
>> >
>> > Alternatively, "<process_name><number>", where <number> is 0 for the first
>> > suspend blocker created by the given process, 1 for the second one etc., also
>> > seems to be doable.
>>
>> I think it is important to let user-space specify the name. If a
>> process uses multiple suspend blockers, it is impossible to tell what
>> each one is used for if they are automatically named.
>
> Well, the problem is the only purpose of this is user space debugging, isn't it?
>
At the moment, yes. But having an explicit init call also simplifies
future expansion. If we ever need to add back multiple types of
suspend blockers, we can add an init call with a type argument and
have the current init call use the default type. If the past we have
had types that keeps the screen on and prevented idle sleep modes. In
the future we could for instance want to specify if a suspend blocker
should prevent suspend when the battery is low or when the lid is
closed.

> Now, while I don't think it's generally bad to provide kernel interfaces
> helping to debug user space, I'm not quite sure if that should be done at the
> expense of the clarity of kernel-user space interfaces.
>
> I wonder how many cases there are in which distinguishing between suspend
> blockers used by the same user space task is practically relevant.
>

I think all of them (when more than one suspend blocker is used).

-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-05-03 21:26           ` Arve Hjønnevåg
  2010-05-03 21:49             ` Rafael J. Wysocki
@ 2010-05-03 21:49             ` Rafael J. Wysocki
  2010-05-03 22:01               ` Arve Hjønnevåg
  2010-05-03 22:01               ` Arve Hjønnevåg
  1 sibling, 2 replies; 93+ messages in thread
From: Rafael J. Wysocki @ 2010-05-03 21:49 UTC (permalink / raw)
  To: Arve Hjønnevåg
  Cc: Alan Stern, Linux-pm mailing list, Kernel development list,
	Tejun Heo, Oleg Nesterov, Randy Dunlap, Andrew Morton,
	Ryusuke Konishi, Jim Collar, Greg Kroah-Hartman, Avi Kivity,
	Len Brown, Pavel Machek, Cornelia Huck, Nigel Cunningham,
	linux-doc

On Monday 03 May 2010, Arve Hjønnevåg wrote:
> On Mon, May 3, 2010 at 8:03 AM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> > On Sunday 02 May 2010, Alan Stern wrote:
> >> On Sun, 2 May 2010, Rafael J. Wysocki wrote:
> >>
> >> > Hmm.  It doesn't seem to be possible to create two different suspend blockers
> >> > using the same file handle.  So, what exactly is a process supposed to do to
> >> > use two suspend blockers at the same time?
> >>
> >> Open the file twice, thereby obtaining two file handles.
> >
> > Well, that's what I thought.
> >
> > I must admit I'm not really comfortable with this interface.  IMO it would
> > be better if _open() created the suspend blocker giving it a name based on
> > the name of the process that called it.  Something like
> > "<process name>_<timestamp>" might work at first sight.
> >
> > Alternatively, "<process_name><number>", where <number> is 0 for the first
> > suspend blocker created by the given process, 1 for the second one etc., also
> > seems to be doable.
> 
> I think it is important to let user-space specify the name. If a
> process uses multiple suspend blockers, it is impossible to tell what
> each one is used for if they are automatically named.

Well, the problem is the only purpose of this is user space debugging, isn't it?

Now, while I don't think it's generally bad to provide kernel interfaces
helping to debug user space, I'm not quite sure if that should be done at the
expense of the clarity of kernel-user space interfaces.

I wonder how many cases there are in which distinguishing between suspend
blockers used by the same user space task is practically relevant.

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-05-03 21:26           ` Arve Hjønnevåg
@ 2010-05-03 21:49             ` Rafael J. Wysocki
  2010-05-03 21:49             ` Rafael J. Wysocki
  1 sibling, 0 replies; 93+ messages in thread
From: Rafael J. Wysocki @ 2010-05-03 21:49 UTC (permalink / raw)
  To: Arve Hjønnevåg
  Cc: Len Brown, Jim Collar, linux-doc, Greg Kroah-Hartman,
	Kernel development list, Oleg Nesterov, Avi Kivity,
	Ryusuke Konishi, Tejun Heo, Linux-pm mailing list, Andrew Morton

On Monday 03 May 2010, Arve Hjønnevåg wrote:
> On Mon, May 3, 2010 at 8:03 AM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> > On Sunday 02 May 2010, Alan Stern wrote:
> >> On Sun, 2 May 2010, Rafael J. Wysocki wrote:
> >>
> >> > Hmm.  It doesn't seem to be possible to create two different suspend blockers
> >> > using the same file handle.  So, what exactly is a process supposed to do to
> >> > use two suspend blockers at the same time?
> >>
> >> Open the file twice, thereby obtaining two file handles.
> >
> > Well, that's what I thought.
> >
> > I must admit I'm not really comfortable with this interface.  IMO it would
> > be better if _open() created the suspend blocker giving it a name based on
> > the name of the process that called it.  Something like
> > "<process name>_<timestamp>" might work at first sight.
> >
> > Alternatively, "<process_name><number>", where <number> is 0 for the first
> > suspend blocker created by the given process, 1 for the second one etc., also
> > seems to be doable.
> 
> I think it is important to let user-space specify the name. If a
> process uses multiple suspend blockers, it is impossible to tell what
> each one is used for if they are automatically named.

Well, the problem is the only purpose of this is user space debugging, isn't it?

Now, while I don't think it's generally bad to provide kernel interfaces
helping to debug user space, I'm not quite sure if that should be done at the
expense of the clarity of kernel-user space interfaces.

I wonder how many cases there are in which distinguishing between suspend
blockers used by the same user space task is practically relevant.

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend  blockers from user-space
  2010-05-03 15:03         ` Rafael J. Wysocki
  2010-05-03 21:26           ` Arve Hjønnevåg
@ 2010-05-03 21:26           ` Arve Hjønnevåg
  2010-05-03 21:49             ` Rafael J. Wysocki
  2010-05-03 21:49             ` Rafael J. Wysocki
  2010-05-04  4:16           ` Pavel Machek
  2010-05-04  4:16           ` Pavel Machek
  3 siblings, 2 replies; 93+ messages in thread
From: Arve Hjønnevåg @ 2010-05-03 21:26 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Alan Stern, Linux-pm mailing list, Kernel development list,
	Tejun Heo, Oleg Nesterov, Randy Dunlap, Andrew Morton,
	Ryusuke Konishi, Jim Collar, Greg Kroah-Hartman, Avi Kivity,
	Len Brown, Pavel Machek, Cornelia Huck, Nigel Cunningham,
	linux-doc

On Mon, May 3, 2010 at 8:03 AM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> On Sunday 02 May 2010, Alan Stern wrote:
>> On Sun, 2 May 2010, Rafael J. Wysocki wrote:
>>
>> > Hmm.  It doesn't seem to be possible to create two different suspend blockers
>> > using the same file handle.  So, what exactly is a process supposed to do to
>> > use two suspend blockers at the same time?
>>
>> Open the file twice, thereby obtaining two file handles.
>
> Well, that's what I thought.
>
> I must admit I'm not really comfortable with this interface.  IMO it would
> be better if _open() created the suspend blocker giving it a name based on
> the name of the process that called it.  Something like
> "<process name>_<timestamp>" might work at first sight.
>
> Alternatively, "<process_name><number>", where <number> is 0 for the first
> suspend blocker created by the given process, 1 for the second one etc., also
> seems to be doable.

I think it is important to let user-space specify the name. If a
process uses multiple suspend blockers, it is impossible to tell what
each one is used for if they are automatically named.

-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-05-03 15:03         ` Rafael J. Wysocki
@ 2010-05-03 21:26           ` Arve Hjønnevåg
  2010-05-03 21:26           ` Arve Hjønnevåg
                             ` (2 subsequent siblings)
  3 siblings, 0 replies; 93+ messages in thread
From: Arve Hjønnevåg @ 2010-05-03 21:26 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Len Brown, Jim Collar, linux-doc, Greg Kroah-Hartman,
	Kernel development list, Oleg Nesterov, Avi Kivity,
	Ryusuke Konishi, Tejun Heo, Linux-pm mailing list, Andrew Morton

On Mon, May 3, 2010 at 8:03 AM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> On Sunday 02 May 2010, Alan Stern wrote:
>> On Sun, 2 May 2010, Rafael J. Wysocki wrote:
>>
>> > Hmm.  It doesn't seem to be possible to create two different suspend blockers
>> > using the same file handle.  So, what exactly is a process supposed to do to
>> > use two suspend blockers at the same time?
>>
>> Open the file twice, thereby obtaining two file handles.
>
> Well, that's what I thought.
>
> I must admit I'm not really comfortable with this interface.  IMO it would
> be better if _open() created the suspend blocker giving it a name based on
> the name of the process that called it.  Something like
> "<process name>_<timestamp>" might work at first sight.
>
> Alternatively, "<process_name><number>", where <number> is 0 for the first
> suspend blocker created by the given process, 1 for the second one etc., also
> seems to be doable.

I think it is important to let user-space specify the name. If a
process uses multiple suspend blockers, it is impossible to tell what
each one is used for if they are automatically named.

-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-05-02 21:56       ` Alan Stern
@ 2010-05-03 15:03         ` Rafael J. Wysocki
  2010-05-03 21:26           ` Arve Hjønnevåg
                             ` (3 more replies)
  2010-05-03 15:03         ` Rafael J. Wysocki
  1 sibling, 4 replies; 93+ messages in thread
From: Rafael J. Wysocki @ 2010-05-03 15:03 UTC (permalink / raw)
  To: Alan Stern
  Cc: Arve Hjønnevåg, Linux-pm mailing list,
	Kernel development list, Tejun Heo, Oleg Nesterov, Randy Dunlap,
	Andrew Morton, Ryusuke Konishi, Jim Collar, Greg Kroah-Hartman,
	Avi Kivity, Len Brown, Pavel Machek, Cornelia Huck,
	Nigel Cunningham, linux-doc

On Sunday 02 May 2010, Alan Stern wrote:
> On Sun, 2 May 2010, Rafael J. Wysocki wrote:
> 
> > Hmm.  It doesn't seem to be possible to create two different suspend blockers
> > using the same file handle.  So, what exactly is a process supposed to do to
> > use two suspend blockers at the same time?
> 
> Open the file twice, thereby obtaining two file handles.

Well, that's what I thought.

I must admit I'm not really comfortable with this interface.  IMO it would
be better if _open() created the suspend blocker giving it a name based on
the name of the process that called it.  Something like
"<process name>_<timestamp>" might work at first sight.

Alternatively, "<process_name><number>", where <number> is 0 for the first
suspend blocker created by the given process, 1 for the second one etc., also
seems to be doable.

Rafael

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-05-02 21:56       ` Alan Stern
  2010-05-03 15:03         ` Rafael J. Wysocki
@ 2010-05-03 15:03         ` Rafael J. Wysocki
  1 sibling, 0 replies; 93+ messages in thread
From: Rafael J. Wysocki @ 2010-05-03 15:03 UTC (permalink / raw)
  To: Alan Stern
  Cc: Len Brown, Jim Collar, linux-doc, Kernel development list,
	Greg Kroah-Hartman, Oleg Nesterov, Avi Kivity, Ryusuke Konishi,
	Tejun Heo, Linux-pm mailing list, Andrew Morton

On Sunday 02 May 2010, Alan Stern wrote:
> On Sun, 2 May 2010, Rafael J. Wysocki wrote:
> 
> > Hmm.  It doesn't seem to be possible to create two different suspend blockers
> > using the same file handle.  So, what exactly is a process supposed to do to
> > use two suspend blockers at the same time?
> 
> Open the file twice, thereby obtaining two file handles.

Well, that's what I thought.

I must admit I'm not really comfortable with this interface.  IMO it would
be better if _open() created the suspend blocker giving it a name based on
the name of the process that called it.  Something like
"<process name>_<timestamp>" might work at first sight.

Alternatively, "<process_name><number>", where <number> is 0 for the first
suspend blocker created by the given process, 1 for the second one etc., also
seems to be doable.

Rafael

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-05-02 21:23       ` Rafael J. Wysocki
  (?)
  (?)
@ 2010-05-02 21:56       ` Alan Stern
  2010-05-03 15:03         ` Rafael J. Wysocki
  2010-05-03 15:03         ` Rafael J. Wysocki
  -1 siblings, 2 replies; 93+ messages in thread
From: Alan Stern @ 2010-05-02 21:56 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Arve Hjønnevåg, Linux-pm mailing list,
	Kernel development list, Tejun Heo, Oleg Nesterov, Randy Dunlap,
	Andrew Morton, Ryusuke Konishi, Jim Collar, Greg Kroah-Hartman,
	Avi Kivity, Len Brown, Pavel Machek, Cornelia Huck,
	Nigel Cunningham, linux-doc

On Sun, 2 May 2010, Rafael J. Wysocki wrote:

> Hmm.  It doesn't seem to be possible to create two different suspend blockers
> using the same file handle.  So, what exactly is a process supposed to do to
> use two suspend blockers at the same time?

Open the file twice, thereby obtaining two file handles.

Alan Stern


^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-05-02 21:23       ` Rafael J. Wysocki
  (?)
@ 2010-05-02 21:56       ` Alan Stern
  -1 siblings, 0 replies; 93+ messages in thread
From: Alan Stern @ 2010-05-02 21:56 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Len Brown, Jim Collar, linux-doc, Kernel development list,
	Greg Kroah-Hartman, Oleg Nesterov, Avi Kivity, Ryusuke Konishi,
	Tejun Heo, Linux-pm mailing list, Andrew Morton

On Sun, 2 May 2010, Rafael J. Wysocki wrote:

> Hmm.  It doesn't seem to be possible to create two different suspend blockers
> using the same file handle.  So, what exactly is a process supposed to do to
> use two suspend blockers at the same time?

Open the file twice, thereby obtaining two file handles.

Alan Stern

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-04-30 22:36     ` Arve Hjønnevåg
@ 2010-05-02 21:23       ` Rafael J. Wysocki
  -1 siblings, 0 replies; 93+ messages in thread
From: Rafael J. Wysocki @ 2010-05-02 21:23 UTC (permalink / raw)
  To: Arve Hjønnevåg
  Cc: linux-pm, linux-kernel, Alan Stern, Tejun Heo, Oleg Nesterov,
	Randy Dunlap, Andrew Morton, Ryusuke Konishi, Jim Collar,
	Greg Kroah-Hartman, Avi Kivity, Len Brown, Pavel Machek,
	Magnus Damm, Cornelia Huck, Nigel Cunningham, linux-doc

On Saturday 01 May 2010, Arve Hjønnevåg wrote:
> Add a misc device, "suspend_blocker", that allows user-space processes
> to block auto suspend. The device has ioctls to create a suspend_blocker,
> and to block and unblock suspend. To delete the suspend_blocker, close
> the device.
> 
> Signed-off-by: Arve Hjønnevåg <arve@android.com>
> ---
>  Documentation/ioctl/ioctl-number.txt          |    3 +-
>  Documentation/power/opportunistic-suspend.txt |   17 ++++
>  include/linux/suspend_block_dev.h             |   25 +++++
>  kernel/power/Kconfig                          |    9 ++
>  kernel/power/Makefile                         |    1 +
>  kernel/power/user_suspend_blocker.c           |  128 +++++++++++++++++++++++++
>  6 files changed, 182 insertions(+), 1 deletions(-)
>  create mode 100644 include/linux/suspend_block_dev.h
>  create mode 100644 kernel/power/user_suspend_blocker.c
> 
> diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
> index dd5806f..e2458f7 100644
> --- a/Documentation/ioctl/ioctl-number.txt
> +++ b/Documentation/ioctl/ioctl-number.txt
> @@ -254,7 +254,8 @@ Code  Seq#(hex)	Include File		Comments
>  'q'	80-FF	linux/telephony.h	Internet PhoneJACK, Internet LineJACK
>  		linux/ixjuser.h		<http://www.quicknet.net>
>  'r'	00-1F	linux/msdos_fs.h and fs/fat/dir.c
> -'s'	all	linux/cdk.h
> +'s'	all	linux/cdk.h	conflict!
> +'s'	all	linux/suspend_block_dev.h	conflict!
>  't'	00-7F	linux/if_ppp.h
>  't'	80-8F	linux/isdn_ppp.h
>  't'	90	linux/toshiba.h
> diff --git a/Documentation/power/opportunistic-suspend.txt b/Documentation/power/opportunistic-suspend.txt
> index 3d060e8..f2b145e 100644
> --- a/Documentation/power/opportunistic-suspend.txt
> +++ b/Documentation/power/opportunistic-suspend.txt
> @@ -117,3 +117,20 @@ if (list_empty(&state->pending_work))
>  else
>  	suspend_block(&state->suspend_blocker);
>  
> +User-space API
> +==============
> +
> +To create a suspend_blocker from user-space, open the suspend_blocker device:
> +    fd = open("/dev/suspend_blocker", O_RDWR | O_CLOEXEC);
> +then call:
> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_INIT(strlen(name)), name);
> +
> +To activate a suspend_blocker call:
> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK);
> +
> +To unblock call:
> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_UNBLOCK);
> +
> +To destroy the suspend_blocker, close the device:
> +    close(fd);
> +
> diff --git a/include/linux/suspend_block_dev.h b/include/linux/suspend_block_dev.h
> new file mode 100644
> index 0000000..24bc5c7
> --- /dev/null
> +++ b/include/linux/suspend_block_dev.h
> @@ -0,0 +1,25 @@
> +/* include/linux/suspend_block_dev.h
> + *
> + * Copyright (C) 2009 Google, Inc.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#ifndef _LINUX_SUSPEND_BLOCK_DEV_H
> +#define _LINUX_SUSPEND_BLOCK_DEV_H
> +
> +#include <linux/ioctl.h>
> +
> +#define SUSPEND_BLOCKER_IOCTL_INIT(len)		_IOC(_IOC_WRITE, 's', 0, len)
> +#define SUSPEND_BLOCKER_IOCTL_BLOCK		_IO('s', 1)
> +#define SUSPEND_BLOCKER_IOCTL_UNBLOCK		_IO('s', 2)
> +
> +#endif
> diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
> index 55a06a1..fe5a2f2 100644
> --- a/kernel/power/Kconfig
> +++ b/kernel/power/Kconfig
> @@ -146,6 +146,15 @@ config OPPORTUNISTIC_SUSPEND
>  	  determines the sleep state the system will be put into when there are
>  	  no active suspend blockers.
>  
> +config USER_SUSPEND_BLOCKERS
> +	bool "Userspace suspend blockers"
> +	depends on OPPORTUNISTIC_SUSPEND
> +	default y
> +	---help---
> +	  User-space suspend block api. Creates a misc device with ioctls
> +	  to create, block and unblock a suspend_blocker. The suspend_blocker
> +	  will be deleted when the device is closed.
> +
>  config HIBERNATION_NVS
>  	bool
>  
> diff --git a/kernel/power/Makefile b/kernel/power/Makefile
> index ee5276d..78f703b 100644
> --- a/kernel/power/Makefile
> +++ b/kernel/power/Makefile
> @@ -8,6 +8,7 @@ obj-$(CONFIG_PM_SLEEP)		+= console.o
>  obj-$(CONFIG_FREEZER)		+= process.o
>  obj-$(CONFIG_SUSPEND)		+= suspend.o
>  obj-$(CONFIG_OPPORTUNISTIC_SUSPEND)	+= suspend_blocker.o
> +obj-$(CONFIG_USER_SUSPEND_BLOCKERS)	+= user_suspend_blocker.o
>  obj-$(CONFIG_PM_TEST_SUSPEND)	+= suspend_test.o
>  obj-$(CONFIG_HIBERNATION)	+= hibernate.o snapshot.o swap.o user.o
>  obj-$(CONFIG_HIBERNATION_NVS)	+= hibernate_nvs.o
> diff --git a/kernel/power/user_suspend_blocker.c b/kernel/power/user_suspend_blocker.c
> new file mode 100644
> index 0000000..dc1d06f
> --- /dev/null
> +++ b/kernel/power/user_suspend_blocker.c
> @@ -0,0 +1,128 @@
> +/* kernel/power/user_suspend_block.c
> + *
> + * Copyright (C) 2009-2010 Google, Inc.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#include <linux/fs.h>
> +#include <linux/miscdevice.h>
> +#include <linux/module.h>
> +#include <linux/uaccess.h>
> +#include <linux/slab.h>
> +#include <linux/suspend_blocker.h>
> +#include <linux/suspend_block_dev.h>
> +
> +enum {
> +	DEBUG_FAILURE	= BIT(0),
> +};
> +static int debug_mask = DEBUG_FAILURE;
> +module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
> +
> +static DEFINE_MUTEX(ioctl_lock);
> +
> +struct user_suspend_blocker {
> +	struct suspend_blocker	blocker;
> +	char			name[0];
> +};
> +
> +static int create_user_suspend_blocker(struct file *file, void __user *name,
> +				 size_t name_len)
> +{
> +	struct user_suspend_blocker *bl;
> +	if (file->private_data)
> +		return -EBUSY;
> +	if (name_len > NAME_MAX)
> +		return -ENAMETOOLONG;
> +	bl = kzalloc(sizeof(*bl) + name_len + 1, GFP_KERNEL);
> +	if (!bl)
> +		return -ENOMEM;
> +	if (copy_from_user(bl->name, name, name_len))
> +		goto err_fault;
> +	suspend_blocker_init(&bl->blocker, bl->name);
> +	file->private_data = bl;

Hmm.  It doesn't seem to be possible to create two different suspend blockers
using the same file handle.  So, what exactly is a process supposed to do to
use two suspend blockers at the same time?

Rafael

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
@ 2010-05-02 21:23       ` Rafael J. Wysocki
  0 siblings, 0 replies; 93+ messages in thread
From: Rafael J. Wysocki @ 2010-05-02 21:23 UTC (permalink / raw)
  To: Arve Hjønnevåg
  Cc: Len Brown, Jim Collar, linux-doc, Greg Kroah-Hartman,
	linux-kernel, Oleg Nesterov, Avi Kivity, Ryusuke Konishi,
	Tejun Heo, Magnus Damm, linux-pm, Andrew Morton

On Saturday 01 May 2010, Arve Hjønnevåg wrote:
> Add a misc device, "suspend_blocker", that allows user-space processes
> to block auto suspend. The device has ioctls to create a suspend_blocker,
> and to block and unblock suspend. To delete the suspend_blocker, close
> the device.
> 
> Signed-off-by: Arve Hjønnevåg <arve@android.com>
> ---
>  Documentation/ioctl/ioctl-number.txt          |    3 +-
>  Documentation/power/opportunistic-suspend.txt |   17 ++++
>  include/linux/suspend_block_dev.h             |   25 +++++
>  kernel/power/Kconfig                          |    9 ++
>  kernel/power/Makefile                         |    1 +
>  kernel/power/user_suspend_blocker.c           |  128 +++++++++++++++++++++++++
>  6 files changed, 182 insertions(+), 1 deletions(-)
>  create mode 100644 include/linux/suspend_block_dev.h
>  create mode 100644 kernel/power/user_suspend_blocker.c
> 
> diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
> index dd5806f..e2458f7 100644
> --- a/Documentation/ioctl/ioctl-number.txt
> +++ b/Documentation/ioctl/ioctl-number.txt
> @@ -254,7 +254,8 @@ Code  Seq#(hex)	Include File		Comments
>  'q'	80-FF	linux/telephony.h	Internet PhoneJACK, Internet LineJACK
>  		linux/ixjuser.h		<http://www.quicknet.net>
>  'r'	00-1F	linux/msdos_fs.h and fs/fat/dir.c
> -'s'	all	linux/cdk.h
> +'s'	all	linux/cdk.h	conflict!
> +'s'	all	linux/suspend_block_dev.h	conflict!
>  't'	00-7F	linux/if_ppp.h
>  't'	80-8F	linux/isdn_ppp.h
>  't'	90	linux/toshiba.h
> diff --git a/Documentation/power/opportunistic-suspend.txt b/Documentation/power/opportunistic-suspend.txt
> index 3d060e8..f2b145e 100644
> --- a/Documentation/power/opportunistic-suspend.txt
> +++ b/Documentation/power/opportunistic-suspend.txt
> @@ -117,3 +117,20 @@ if (list_empty(&state->pending_work))
>  else
>  	suspend_block(&state->suspend_blocker);
>  
> +User-space API
> +==============
> +
> +To create a suspend_blocker from user-space, open the suspend_blocker device:
> +    fd = open("/dev/suspend_blocker", O_RDWR | O_CLOEXEC);
> +then call:
> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_INIT(strlen(name)), name);
> +
> +To activate a suspend_blocker call:
> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK);
> +
> +To unblock call:
> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_UNBLOCK);
> +
> +To destroy the suspend_blocker, close the device:
> +    close(fd);
> +
> diff --git a/include/linux/suspend_block_dev.h b/include/linux/suspend_block_dev.h
> new file mode 100644
> index 0000000..24bc5c7
> --- /dev/null
> +++ b/include/linux/suspend_block_dev.h
> @@ -0,0 +1,25 @@
> +/* include/linux/suspend_block_dev.h
> + *
> + * Copyright (C) 2009 Google, Inc.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#ifndef _LINUX_SUSPEND_BLOCK_DEV_H
> +#define _LINUX_SUSPEND_BLOCK_DEV_H
> +
> +#include <linux/ioctl.h>
> +
> +#define SUSPEND_BLOCKER_IOCTL_INIT(len)		_IOC(_IOC_WRITE, 's', 0, len)
> +#define SUSPEND_BLOCKER_IOCTL_BLOCK		_IO('s', 1)
> +#define SUSPEND_BLOCKER_IOCTL_UNBLOCK		_IO('s', 2)
> +
> +#endif
> diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
> index 55a06a1..fe5a2f2 100644
> --- a/kernel/power/Kconfig
> +++ b/kernel/power/Kconfig
> @@ -146,6 +146,15 @@ config OPPORTUNISTIC_SUSPEND
>  	  determines the sleep state the system will be put into when there are
>  	  no active suspend blockers.
>  
> +config USER_SUSPEND_BLOCKERS
> +	bool "Userspace suspend blockers"
> +	depends on OPPORTUNISTIC_SUSPEND
> +	default y
> +	---help---
> +	  User-space suspend block api. Creates a misc device with ioctls
> +	  to create, block and unblock a suspend_blocker. The suspend_blocker
> +	  will be deleted when the device is closed.
> +
>  config HIBERNATION_NVS
>  	bool
>  
> diff --git a/kernel/power/Makefile b/kernel/power/Makefile
> index ee5276d..78f703b 100644
> --- a/kernel/power/Makefile
> +++ b/kernel/power/Makefile
> @@ -8,6 +8,7 @@ obj-$(CONFIG_PM_SLEEP)		+= console.o
>  obj-$(CONFIG_FREEZER)		+= process.o
>  obj-$(CONFIG_SUSPEND)		+= suspend.o
>  obj-$(CONFIG_OPPORTUNISTIC_SUSPEND)	+= suspend_blocker.o
> +obj-$(CONFIG_USER_SUSPEND_BLOCKERS)	+= user_suspend_blocker.o
>  obj-$(CONFIG_PM_TEST_SUSPEND)	+= suspend_test.o
>  obj-$(CONFIG_HIBERNATION)	+= hibernate.o snapshot.o swap.o user.o
>  obj-$(CONFIG_HIBERNATION_NVS)	+= hibernate_nvs.o
> diff --git a/kernel/power/user_suspend_blocker.c b/kernel/power/user_suspend_blocker.c
> new file mode 100644
> index 0000000..dc1d06f
> --- /dev/null
> +++ b/kernel/power/user_suspend_blocker.c
> @@ -0,0 +1,128 @@
> +/* kernel/power/user_suspend_block.c
> + *
> + * Copyright (C) 2009-2010 Google, Inc.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#include <linux/fs.h>
> +#include <linux/miscdevice.h>
> +#include <linux/module.h>
> +#include <linux/uaccess.h>
> +#include <linux/slab.h>
> +#include <linux/suspend_blocker.h>
> +#include <linux/suspend_block_dev.h>
> +
> +enum {
> +	DEBUG_FAILURE	= BIT(0),
> +};
> +static int debug_mask = DEBUG_FAILURE;
> +module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
> +
> +static DEFINE_MUTEX(ioctl_lock);
> +
> +struct user_suspend_blocker {
> +	struct suspend_blocker	blocker;
> +	char			name[0];
> +};
> +
> +static int create_user_suspend_blocker(struct file *file, void __user *name,
> +				 size_t name_len)
> +{
> +	struct user_suspend_blocker *bl;
> +	if (file->private_data)
> +		return -EBUSY;
> +	if (name_len > NAME_MAX)
> +		return -ENAMETOOLONG;
> +	bl = kzalloc(sizeof(*bl) + name_len + 1, GFP_KERNEL);
> +	if (!bl)
> +		return -ENOMEM;
> +	if (copy_from_user(bl->name, name, name_len))
> +		goto err_fault;
> +	suspend_blocker_init(&bl->blocker, bl->name);
> +	file->private_data = bl;

Hmm.  It doesn't seem to be possible to create two different suspend blockers
using the same file handle.  So, what exactly is a process supposed to do to
use two suspend blockers at the same time?

Rafael
_______________________________________________
linux-pm mailing list
linux-pm@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/linux-pm

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-04-30 22:36     ` Arve Hjønnevåg
  (?)
@ 2010-05-02  7:04     ` Pavel Machek
  -1 siblings, 0 replies; 93+ messages in thread
From: Pavel Machek @ 2010-05-02  7:04 UTC (permalink / raw)
  To: Arve Hj??nnev??g
  Cc: linux-pm, linux-kernel, Rafael J. Wysocki, Alan Stern, Tejun Heo,
	Oleg Nesterov, Randy Dunlap, Andrew Morton, Ryusuke Konishi,
	Jim Collar, Greg Kroah-Hartman, Avi Kivity, Len Brown,
	Magnus Damm, Cornelia Huck, Nigel Cunningham, linux-doc

On Fri 2010-04-30 15:36:55, Arve Hj??nnev??g wrote:
> Add a misc device, "suspend_blocker", that allows user-space processes
> to block auto suspend. The device has ioctls to create a suspend_blocker,
> and to block and unblock suspend. To delete the suspend_blocker, close
> the device.

Yeah, this one is overly complex; instead of having 'open blocks
suspend' semantics and lsof listing active blockers, it adds strange
ioctl based interface passing names, and then adds debugfs
infrastructure listing those back.

I guess this is why you are getying 'it should be in /proc, no in
/sys, no in debugfs, no in /proc' kind of feedback. This should simply
not exist in the first place...

> Signed-off-by: Arve Hj??nnev??g <arve@android.com>

NAK.

> ---
>  Documentation/ioctl/ioctl-number.txt          |    3 +-
>  Documentation/power/opportunistic-suspend.txt |   17 ++++
>  include/linux/suspend_block_dev.h             |   25 +++++
>  kernel/power/Kconfig                          |    9 ++
>  kernel/power/Makefile                         |    1 +
>  kernel/power/user_suspend_blocker.c           |  128 +++++++++++++++++++++++++
>  6 files changed, 182 insertions(+), 1 deletions(-)
>  create mode 100644 include/linux/suspend_block_dev.h
>  create mode 100644 kernel/power/user_suspend_blocker.c
> 
> diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
> index dd5806f..e2458f7 100644
> --- a/Documentation/ioctl/ioctl-number.txt
> +++ b/Documentation/ioctl/ioctl-number.txt
> @@ -254,7 +254,8 @@ Code  Seq#(hex)	Include File		Comments
>  'q'	80-FF	linux/telephony.h	Internet PhoneJACK, Internet LineJACK
>  		linux/ixjuser.h		<http://www.quicknet.net>
>  'r'	00-1F	linux/msdos_fs.h and fs/fat/dir.c
> -'s'	all	linux/cdk.h
> +'s'	all	linux/cdk.h	conflict!
> +'s'	all	linux/suspend_block_dev.h	conflict!
>  't'	00-7F	linux/if_ppp.h
>  't'	80-8F	linux/isdn_ppp.h
>  't'	90	linux/toshiba.h
> diff --git a/Documentation/power/opportunistic-suspend.txt b/Documentation/power/opportunistic-suspend.txt
> index 3d060e8..f2b145e 100644
> --- a/Documentation/power/opportunistic-suspend.txt
> +++ b/Documentation/power/opportunistic-suspend.txt
> @@ -117,3 +117,20 @@ if (list_empty(&state->pending_work))
>  else
>  	suspend_block(&state->suspend_blocker);
>  
> +User-space API
> +==============
> +
> +To create a suspend_blocker from user-space, open the suspend_blocker device:
> +    fd = open("/dev/suspend_blocker", O_RDWR | O_CLOEXEC);
> +then call:
> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_INIT(strlen(name)), name);
> +
> +To activate a suspend_blocker call:
> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK);
> +
> +To unblock call:
> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_UNBLOCK);
> +
> +To destroy the suspend_blocker, close the device:
> +    close(fd);
> +
> diff --git a/include/linux/suspend_block_dev.h b/include/linux/suspend_block_dev.h
> new file mode 100644
> index 0000000..24bc5c7
> --- /dev/null
> +++ b/include/linux/suspend_block_dev.h
> @@ -0,0 +1,25 @@
> +/* include/linux/suspend_block_dev.h
> + *
> + * Copyright (C) 2009 Google, Inc.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#ifndef _LINUX_SUSPEND_BLOCK_DEV_H
> +#define _LINUX_SUSPEND_BLOCK_DEV_H
> +
> +#include <linux/ioctl.h>
> +
> +#define SUSPEND_BLOCKER_IOCTL_INIT(len)		_IOC(_IOC_WRITE, 's', 0, len)
> +#define SUSPEND_BLOCKER_IOCTL_BLOCK		_IO('s', 1)
> +#define SUSPEND_BLOCKER_IOCTL_UNBLOCK		_IO('s', 2)
> +
> +#endif
> diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
> index 55a06a1..fe5a2f2 100644
> --- a/kernel/power/Kconfig
> +++ b/kernel/power/Kconfig
> @@ -146,6 +146,15 @@ config OPPORTUNISTIC_SUSPEND
>  	  determines the sleep state the system will be put into when there are
>  	  no active suspend blockers.
>  
> +config USER_SUSPEND_BLOCKERS
> +	bool "Userspace suspend blockers"
> +	depends on OPPORTUNISTIC_SUSPEND
> +	default y
> +	---help---
> +	  User-space suspend block api. Creates a misc device with ioctls
> +	  to create, block and unblock a suspend_blocker. The suspend_blocker
> +	  will be deleted when the device is closed.
> +
>  config HIBERNATION_NVS
>  	bool
>  
> diff --git a/kernel/power/Makefile b/kernel/power/Makefile
> index ee5276d..78f703b 100644
> --- a/kernel/power/Makefile
> +++ b/kernel/power/Makefile
> @@ -8,6 +8,7 @@ obj-$(CONFIG_PM_SLEEP)		+= console.o
>  obj-$(CONFIG_FREEZER)		+= process.o
>  obj-$(CONFIG_SUSPEND)		+= suspend.o
>  obj-$(CONFIG_OPPORTUNISTIC_SUSPEND)	+= suspend_blocker.o
> +obj-$(CONFIG_USER_SUSPEND_BLOCKERS)	+= user_suspend_blocker.o
>  obj-$(CONFIG_PM_TEST_SUSPEND)	+= suspend_test.o
>  obj-$(CONFIG_HIBERNATION)	+= hibernate.o snapshot.o swap.o user.o
>  obj-$(CONFIG_HIBERNATION_NVS)	+= hibernate_nvs.o
> diff --git a/kernel/power/user_suspend_blocker.c b/kernel/power/user_suspend_blocker.c
> new file mode 100644
> index 0000000..dc1d06f
> --- /dev/null
> +++ b/kernel/power/user_suspend_blocker.c
> @@ -0,0 +1,128 @@
> +/* kernel/power/user_suspend_block.c
> + *
> + * Copyright (C) 2009-2010 Google, Inc.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#include <linux/fs.h>
> +#include <linux/miscdevice.h>
> +#include <linux/module.h>
> +#include <linux/uaccess.h>
> +#include <linux/slab.h>
> +#include <linux/suspend_blocker.h>
> +#include <linux/suspend_block_dev.h>
> +
> +enum {
> +	DEBUG_FAILURE	= BIT(0),
> +};
> +static int debug_mask = DEBUG_FAILURE;
> +module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
> +
> +static DEFINE_MUTEX(ioctl_lock);
> +
> +struct user_suspend_blocker {
> +	struct suspend_blocker	blocker;
> +	char			name[0];
> +};
> +
> +static int create_user_suspend_blocker(struct file *file, void __user *name,
> +				 size_t name_len)
> +{
> +	struct user_suspend_blocker *bl;
> +	if (file->private_data)
> +		return -EBUSY;
> +	if (name_len > NAME_MAX)
> +		return -ENAMETOOLONG;
> +	bl = kzalloc(sizeof(*bl) + name_len + 1, GFP_KERNEL);
> +	if (!bl)
> +		return -ENOMEM;
> +	if (copy_from_user(bl->name, name, name_len))
> +		goto err_fault;
> +	suspend_blocker_init(&bl->blocker, bl->name);
> +	file->private_data = bl;
> +	return 0;
> +
> +err_fault:
> +	kfree(bl);
> +	return -EFAULT;
> +}
> +
> +static long user_suspend_blocker_ioctl(struct file *file, unsigned int cmd,
> +				unsigned long _arg)
> +{
> +	void __user *arg = (void __user *)_arg;
> +	struct user_suspend_blocker *bl;
> +	long ret;
> +
> +	mutex_lock(&ioctl_lock);
> +	if ((cmd & ~IOCSIZE_MASK) == SUSPEND_BLOCKER_IOCTL_INIT(0)) {
> +		ret = create_user_suspend_blocker(file, arg, _IOC_SIZE(cmd));
> +		goto done;
> +	}
> +	bl = file->private_data;
> +	if (!bl) {
> +		ret = -ENOENT;
> +		goto done;
> +	}
> +	switch (cmd) {
> +	case SUSPEND_BLOCKER_IOCTL_BLOCK:
> +		suspend_block(&bl->blocker);
> +		ret = 0;
> +		break;
> +	case SUSPEND_BLOCKER_IOCTL_UNBLOCK:
> +		suspend_unblock(&bl->blocker);
> +		ret = 0;
> +		break;
> +	default:
> +		ret = -ENOTSUPP;
> +	}
> +done:
> +	if (ret && (debug_mask & DEBUG_FAILURE))
> +		pr_err("user_suspend_blocker_ioctl: cmd %x failed, %ld\n",
> +			cmd, ret);
> +	mutex_unlock(&ioctl_lock);
> +	return ret;
> +}
> +
> +static int user_suspend_blocker_release(struct inode *inode, struct file *file)
> +{
> +	struct user_suspend_blocker *bl = file->private_data;
> +	if (!bl)
> +		return 0;
> +	suspend_blocker_destroy(&bl->blocker);
> +	kfree(bl);
> +	return 0;
> +}
> +
> +const struct file_operations user_suspend_blocker_fops = {
> +	.release = user_suspend_blocker_release,
> +	.unlocked_ioctl = user_suspend_blocker_ioctl,
> +};
> +
> +struct miscdevice user_suspend_blocker_device = {
> +	.minor = MISC_DYNAMIC_MINOR,
> +	.name = "suspend_blocker",
> +	.fops = &user_suspend_blocker_fops,
> +};
> +
> +static int __init user_suspend_blocker_init(void)
> +{
> +	return misc_register(&user_suspend_blocker_device);
> +}
> +
> +static void __exit user_suspend_blocker_exit(void)
> +{
> +	misc_deregister(&user_suspend_blocker_device);
> +}
> +
> +module_init(user_suspend_blocker_init);
> +module_exit(user_suspend_blocker_exit);

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-04-30 22:36     ` Arve Hjønnevåg
  (?)
  (?)
@ 2010-05-02  7:04     ` Pavel Machek
  -1 siblings, 0 replies; 93+ messages in thread
From: Pavel Machek @ 2010-05-02  7:04 UTC (permalink / raw)
  To: Arve Hj??nnev??g
  Cc: Len Brown, Jim Collar, linux-doc, Greg Kroah-Hartman,
	linux-kernel, Oleg Nesterov, Avi Kivity, Ryusuke Konishi,
	Tejun Heo, Magnus Damm, linux-pm, Andrew Morton

On Fri 2010-04-30 15:36:55, Arve Hj??nnev??g wrote:
> Add a misc device, "suspend_blocker", that allows user-space processes
> to block auto suspend. The device has ioctls to create a suspend_blocker,
> and to block and unblock suspend. To delete the suspend_blocker, close
> the device.

Yeah, this one is overly complex; instead of having 'open blocks
suspend' semantics and lsof listing active blockers, it adds strange
ioctl based interface passing names, and then adds debugfs
infrastructure listing those back.

I guess this is why you are getying 'it should be in /proc, no in
/sys, no in debugfs, no in /proc' kind of feedback. This should simply
not exist in the first place...

> Signed-off-by: Arve Hj??nnev??g <arve@android.com>

NAK.

> ---
>  Documentation/ioctl/ioctl-number.txt          |    3 +-
>  Documentation/power/opportunistic-suspend.txt |   17 ++++
>  include/linux/suspend_block_dev.h             |   25 +++++
>  kernel/power/Kconfig                          |    9 ++
>  kernel/power/Makefile                         |    1 +
>  kernel/power/user_suspend_blocker.c           |  128 +++++++++++++++++++++++++
>  6 files changed, 182 insertions(+), 1 deletions(-)
>  create mode 100644 include/linux/suspend_block_dev.h
>  create mode 100644 kernel/power/user_suspend_blocker.c
> 
> diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
> index dd5806f..e2458f7 100644
> --- a/Documentation/ioctl/ioctl-number.txt
> +++ b/Documentation/ioctl/ioctl-number.txt
> @@ -254,7 +254,8 @@ Code  Seq#(hex)	Include File		Comments
>  'q'	80-FF	linux/telephony.h	Internet PhoneJACK, Internet LineJACK
>  		linux/ixjuser.h		<http://www.quicknet.net>
>  'r'	00-1F	linux/msdos_fs.h and fs/fat/dir.c
> -'s'	all	linux/cdk.h
> +'s'	all	linux/cdk.h	conflict!
> +'s'	all	linux/suspend_block_dev.h	conflict!
>  't'	00-7F	linux/if_ppp.h
>  't'	80-8F	linux/isdn_ppp.h
>  't'	90	linux/toshiba.h
> diff --git a/Documentation/power/opportunistic-suspend.txt b/Documentation/power/opportunistic-suspend.txt
> index 3d060e8..f2b145e 100644
> --- a/Documentation/power/opportunistic-suspend.txt
> +++ b/Documentation/power/opportunistic-suspend.txt
> @@ -117,3 +117,20 @@ if (list_empty(&state->pending_work))
>  else
>  	suspend_block(&state->suspend_blocker);
>  
> +User-space API
> +==============
> +
> +To create a suspend_blocker from user-space, open the suspend_blocker device:
> +    fd = open("/dev/suspend_blocker", O_RDWR | O_CLOEXEC);
> +then call:
> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_INIT(strlen(name)), name);
> +
> +To activate a suspend_blocker call:
> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK);
> +
> +To unblock call:
> +    ioctl(fd, SUSPEND_BLOCKER_IOCTL_UNBLOCK);
> +
> +To destroy the suspend_blocker, close the device:
> +    close(fd);
> +
> diff --git a/include/linux/suspend_block_dev.h b/include/linux/suspend_block_dev.h
> new file mode 100644
> index 0000000..24bc5c7
> --- /dev/null
> +++ b/include/linux/suspend_block_dev.h
> @@ -0,0 +1,25 @@
> +/* include/linux/suspend_block_dev.h
> + *
> + * Copyright (C) 2009 Google, Inc.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#ifndef _LINUX_SUSPEND_BLOCK_DEV_H
> +#define _LINUX_SUSPEND_BLOCK_DEV_H
> +
> +#include <linux/ioctl.h>
> +
> +#define SUSPEND_BLOCKER_IOCTL_INIT(len)		_IOC(_IOC_WRITE, 's', 0, len)
> +#define SUSPEND_BLOCKER_IOCTL_BLOCK		_IO('s', 1)
> +#define SUSPEND_BLOCKER_IOCTL_UNBLOCK		_IO('s', 2)
> +
> +#endif
> diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
> index 55a06a1..fe5a2f2 100644
> --- a/kernel/power/Kconfig
> +++ b/kernel/power/Kconfig
> @@ -146,6 +146,15 @@ config OPPORTUNISTIC_SUSPEND
>  	  determines the sleep state the system will be put into when there are
>  	  no active suspend blockers.
>  
> +config USER_SUSPEND_BLOCKERS
> +	bool "Userspace suspend blockers"
> +	depends on OPPORTUNISTIC_SUSPEND
> +	default y
> +	---help---
> +	  User-space suspend block api. Creates a misc device with ioctls
> +	  to create, block and unblock a suspend_blocker. The suspend_blocker
> +	  will be deleted when the device is closed.
> +
>  config HIBERNATION_NVS
>  	bool
>  
> diff --git a/kernel/power/Makefile b/kernel/power/Makefile
> index ee5276d..78f703b 100644
> --- a/kernel/power/Makefile
> +++ b/kernel/power/Makefile
> @@ -8,6 +8,7 @@ obj-$(CONFIG_PM_SLEEP)		+= console.o
>  obj-$(CONFIG_FREEZER)		+= process.o
>  obj-$(CONFIG_SUSPEND)		+= suspend.o
>  obj-$(CONFIG_OPPORTUNISTIC_SUSPEND)	+= suspend_blocker.o
> +obj-$(CONFIG_USER_SUSPEND_BLOCKERS)	+= user_suspend_blocker.o
>  obj-$(CONFIG_PM_TEST_SUSPEND)	+= suspend_test.o
>  obj-$(CONFIG_HIBERNATION)	+= hibernate.o snapshot.o swap.o user.o
>  obj-$(CONFIG_HIBERNATION_NVS)	+= hibernate_nvs.o
> diff --git a/kernel/power/user_suspend_blocker.c b/kernel/power/user_suspend_blocker.c
> new file mode 100644
> index 0000000..dc1d06f
> --- /dev/null
> +++ b/kernel/power/user_suspend_blocker.c
> @@ -0,0 +1,128 @@
> +/* kernel/power/user_suspend_block.c
> + *
> + * Copyright (C) 2009-2010 Google, Inc.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#include <linux/fs.h>
> +#include <linux/miscdevice.h>
> +#include <linux/module.h>
> +#include <linux/uaccess.h>
> +#include <linux/slab.h>
> +#include <linux/suspend_blocker.h>
> +#include <linux/suspend_block_dev.h>
> +
> +enum {
> +	DEBUG_FAILURE	= BIT(0),
> +};
> +static int debug_mask = DEBUG_FAILURE;
> +module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
> +
> +static DEFINE_MUTEX(ioctl_lock);
> +
> +struct user_suspend_blocker {
> +	struct suspend_blocker	blocker;
> +	char			name[0];
> +};
> +
> +static int create_user_suspend_blocker(struct file *file, void __user *name,
> +				 size_t name_len)
> +{
> +	struct user_suspend_blocker *bl;
> +	if (file->private_data)
> +		return -EBUSY;
> +	if (name_len > NAME_MAX)
> +		return -ENAMETOOLONG;
> +	bl = kzalloc(sizeof(*bl) + name_len + 1, GFP_KERNEL);
> +	if (!bl)
> +		return -ENOMEM;
> +	if (copy_from_user(bl->name, name, name_len))
> +		goto err_fault;
> +	suspend_blocker_init(&bl->blocker, bl->name);
> +	file->private_data = bl;
> +	return 0;
> +
> +err_fault:
> +	kfree(bl);
> +	return -EFAULT;
> +}
> +
> +static long user_suspend_blocker_ioctl(struct file *file, unsigned int cmd,
> +				unsigned long _arg)
> +{
> +	void __user *arg = (void __user *)_arg;
> +	struct user_suspend_blocker *bl;
> +	long ret;
> +
> +	mutex_lock(&ioctl_lock);
> +	if ((cmd & ~IOCSIZE_MASK) == SUSPEND_BLOCKER_IOCTL_INIT(0)) {
> +		ret = create_user_suspend_blocker(file, arg, _IOC_SIZE(cmd));
> +		goto done;
> +	}
> +	bl = file->private_data;
> +	if (!bl) {
> +		ret = -ENOENT;
> +		goto done;
> +	}
> +	switch (cmd) {
> +	case SUSPEND_BLOCKER_IOCTL_BLOCK:
> +		suspend_block(&bl->blocker);
> +		ret = 0;
> +		break;
> +	case SUSPEND_BLOCKER_IOCTL_UNBLOCK:
> +		suspend_unblock(&bl->blocker);
> +		ret = 0;
> +		break;
> +	default:
> +		ret = -ENOTSUPP;
> +	}
> +done:
> +	if (ret && (debug_mask & DEBUG_FAILURE))
> +		pr_err("user_suspend_blocker_ioctl: cmd %x failed, %ld\n",
> +			cmd, ret);
> +	mutex_unlock(&ioctl_lock);
> +	return ret;
> +}
> +
> +static int user_suspend_blocker_release(struct inode *inode, struct file *file)
> +{
> +	struct user_suspend_blocker *bl = file->private_data;
> +	if (!bl)
> +		return 0;
> +	suspend_blocker_destroy(&bl->blocker);
> +	kfree(bl);
> +	return 0;
> +}
> +
> +const struct file_operations user_suspend_blocker_fops = {
> +	.release = user_suspend_blocker_release,
> +	.unlocked_ioctl = user_suspend_blocker_ioctl,
> +};
> +
> +struct miscdevice user_suspend_blocker_device = {
> +	.minor = MISC_DYNAMIC_MINOR,
> +	.name = "suspend_blocker",
> +	.fops = &user_suspend_blocker_fops,
> +};
> +
> +static int __init user_suspend_blocker_init(void)
> +{
> +	return misc_register(&user_suspend_blocker_device);
> +}
> +
> +static void __exit user_suspend_blocker_exit(void)
> +{
> +	misc_deregister(&user_suspend_blocker_device);
> +}
> +
> +module_init(user_suspend_blocker_init);
> +module_exit(user_suspend_blocker_exit);

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-04-30 22:36 ` [PATCH 1/8] PM: Add suspend block api Arve Hjønnevåg
@ 2010-04-30 22:36     ` Arve Hjønnevåg
  0 siblings, 0 replies; 93+ messages in thread
From: Arve Hjønnevåg @ 2010-04-30 22:36 UTC (permalink / raw)
  To: linux-pm, linux-kernel
  Cc: Rafael J. Wysocki, Alan Stern, Tejun Heo, Oleg Nesterov,
	Arve Hjønnevåg, Randy Dunlap, Andrew Morton,
	Ryusuke Konishi, Jim Collar, Greg Kroah-Hartman, Avi Kivity,
	Len Brown, Pavel Machek, Magnus Damm, Cornelia Huck,
	Nigel Cunningham, linux-doc

Add a misc device, "suspend_blocker", that allows user-space processes
to block auto suspend. The device has ioctls to create a suspend_blocker,
and to block and unblock suspend. To delete the suspend_blocker, close
the device.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
 Documentation/ioctl/ioctl-number.txt          |    3 +-
 Documentation/power/opportunistic-suspend.txt |   17 ++++
 include/linux/suspend_block_dev.h             |   25 +++++
 kernel/power/Kconfig                          |    9 ++
 kernel/power/Makefile                         |    1 +
 kernel/power/user_suspend_blocker.c           |  128 +++++++++++++++++++++++++
 6 files changed, 182 insertions(+), 1 deletions(-)
 create mode 100644 include/linux/suspend_block_dev.h
 create mode 100644 kernel/power/user_suspend_blocker.c

diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index dd5806f..e2458f7 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -254,7 +254,8 @@ Code  Seq#(hex)	Include File		Comments
 'q'	80-FF	linux/telephony.h	Internet PhoneJACK, Internet LineJACK
 		linux/ixjuser.h		<http://www.quicknet.net>
 'r'	00-1F	linux/msdos_fs.h and fs/fat/dir.c
-'s'	all	linux/cdk.h
+'s'	all	linux/cdk.h	conflict!
+'s'	all	linux/suspend_block_dev.h	conflict!
 't'	00-7F	linux/if_ppp.h
 't'	80-8F	linux/isdn_ppp.h
 't'	90	linux/toshiba.h
diff --git a/Documentation/power/opportunistic-suspend.txt b/Documentation/power/opportunistic-suspend.txt
index 3d060e8..f2b145e 100644
--- a/Documentation/power/opportunistic-suspend.txt
+++ b/Documentation/power/opportunistic-suspend.txt
@@ -117,3 +117,20 @@ if (list_empty(&state->pending_work))
 else
 	suspend_block(&state->suspend_blocker);
 
+User-space API
+==============
+
+To create a suspend_blocker from user-space, open the suspend_blocker device:
+    fd = open("/dev/suspend_blocker", O_RDWR | O_CLOEXEC);
+then call:
+    ioctl(fd, SUSPEND_BLOCKER_IOCTL_INIT(strlen(name)), name);
+
+To activate a suspend_blocker call:
+    ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK);
+
+To unblock call:
+    ioctl(fd, SUSPEND_BLOCKER_IOCTL_UNBLOCK);
+
+To destroy the suspend_blocker, close the device:
+    close(fd);
+
diff --git a/include/linux/suspend_block_dev.h b/include/linux/suspend_block_dev.h
new file mode 100644
index 0000000..24bc5c7
--- /dev/null
+++ b/include/linux/suspend_block_dev.h
@@ -0,0 +1,25 @@
+/* include/linux/suspend_block_dev.h
+ *
+ * Copyright (C) 2009 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _LINUX_SUSPEND_BLOCK_DEV_H
+#define _LINUX_SUSPEND_BLOCK_DEV_H
+
+#include <linux/ioctl.h>
+
+#define SUSPEND_BLOCKER_IOCTL_INIT(len)		_IOC(_IOC_WRITE, 's', 0, len)
+#define SUSPEND_BLOCKER_IOCTL_BLOCK		_IO('s', 1)
+#define SUSPEND_BLOCKER_IOCTL_UNBLOCK		_IO('s', 2)
+
+#endif
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 55a06a1..fe5a2f2 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -146,6 +146,15 @@ config OPPORTUNISTIC_SUSPEND
 	  determines the sleep state the system will be put into when there are
 	  no active suspend blockers.
 
+config USER_SUSPEND_BLOCKERS
+	bool "Userspace suspend blockers"
+	depends on OPPORTUNISTIC_SUSPEND
+	default y
+	---help---
+	  User-space suspend block api. Creates a misc device with ioctls
+	  to create, block and unblock a suspend_blocker. The suspend_blocker
+	  will be deleted when the device is closed.
+
 config HIBERNATION_NVS
 	bool
 
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index ee5276d..78f703b 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_PM_SLEEP)		+= console.o
 obj-$(CONFIG_FREEZER)		+= process.o
 obj-$(CONFIG_SUSPEND)		+= suspend.o
 obj-$(CONFIG_OPPORTUNISTIC_SUSPEND)	+= suspend_blocker.o
+obj-$(CONFIG_USER_SUSPEND_BLOCKERS)	+= user_suspend_blocker.o
 obj-$(CONFIG_PM_TEST_SUSPEND)	+= suspend_test.o
 obj-$(CONFIG_HIBERNATION)	+= hibernate.o snapshot.o swap.o user.o
 obj-$(CONFIG_HIBERNATION_NVS)	+= hibernate_nvs.o
diff --git a/kernel/power/user_suspend_blocker.c b/kernel/power/user_suspend_blocker.c
new file mode 100644
index 0000000..dc1d06f
--- /dev/null
+++ b/kernel/power/user_suspend_blocker.c
@@ -0,0 +1,128 @@
+/* kernel/power/user_suspend_block.c
+ *
+ * Copyright (C) 2009-2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/suspend_blocker.h>
+#include <linux/suspend_block_dev.h>
+
+enum {
+	DEBUG_FAILURE	= BIT(0),
+};
+static int debug_mask = DEBUG_FAILURE;
+module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+static DEFINE_MUTEX(ioctl_lock);
+
+struct user_suspend_blocker {
+	struct suspend_blocker	blocker;
+	char			name[0];
+};
+
+static int create_user_suspend_blocker(struct file *file, void __user *name,
+				 size_t name_len)
+{
+	struct user_suspend_blocker *bl;
+	if (file->private_data)
+		return -EBUSY;
+	if (name_len > NAME_MAX)
+		return -ENAMETOOLONG;
+	bl = kzalloc(sizeof(*bl) + name_len + 1, GFP_KERNEL);
+	if (!bl)
+		return -ENOMEM;
+	if (copy_from_user(bl->name, name, name_len))
+		goto err_fault;
+	suspend_blocker_init(&bl->blocker, bl->name);
+	file->private_data = bl;
+	return 0;
+
+err_fault:
+	kfree(bl);
+	return -EFAULT;
+}
+
+static long user_suspend_blocker_ioctl(struct file *file, unsigned int cmd,
+				unsigned long _arg)
+{
+	void __user *arg = (void __user *)_arg;
+	struct user_suspend_blocker *bl;
+	long ret;
+
+	mutex_lock(&ioctl_lock);
+	if ((cmd & ~IOCSIZE_MASK) == SUSPEND_BLOCKER_IOCTL_INIT(0)) {
+		ret = create_user_suspend_blocker(file, arg, _IOC_SIZE(cmd));
+		goto done;
+	}
+	bl = file->private_data;
+	if (!bl) {
+		ret = -ENOENT;
+		goto done;
+	}
+	switch (cmd) {
+	case SUSPEND_BLOCKER_IOCTL_BLOCK:
+		suspend_block(&bl->blocker);
+		ret = 0;
+		break;
+	case SUSPEND_BLOCKER_IOCTL_UNBLOCK:
+		suspend_unblock(&bl->blocker);
+		ret = 0;
+		break;
+	default:
+		ret = -ENOTSUPP;
+	}
+done:
+	if (ret && (debug_mask & DEBUG_FAILURE))
+		pr_err("user_suspend_blocker_ioctl: cmd %x failed, %ld\n",
+			cmd, ret);
+	mutex_unlock(&ioctl_lock);
+	return ret;
+}
+
+static int user_suspend_blocker_release(struct inode *inode, struct file *file)
+{
+	struct user_suspend_blocker *bl = file->private_data;
+	if (!bl)
+		return 0;
+	suspend_blocker_destroy(&bl->blocker);
+	kfree(bl);
+	return 0;
+}
+
+const struct file_operations user_suspend_blocker_fops = {
+	.release = user_suspend_blocker_release,
+	.unlocked_ioctl = user_suspend_blocker_ioctl,
+};
+
+struct miscdevice user_suspend_blocker_device = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "suspend_blocker",
+	.fops = &user_suspend_blocker_fops,
+};
+
+static int __init user_suspend_blocker_init(void)
+{
+	return misc_register(&user_suspend_blocker_device);
+}
+
+static void __exit user_suspend_blocker_exit(void)
+{
+	misc_deregister(&user_suspend_blocker_device);
+}
+
+module_init(user_suspend_blocker_init);
+module_exit(user_suspend_blocker_exit);
-- 
1.6.5.1


^ permalink raw reply related	[flat|nested] 93+ messages in thread

* [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
@ 2010-04-30 22:36     ` Arve Hjønnevåg
  0 siblings, 0 replies; 93+ messages in thread
From: Arve Hjønnevåg @ 2010-04-30 22:36 UTC (permalink / raw)
  To: linux-pm, linux-kernel
  Cc: Len Brown, Jim Collar, linux-doc, Greg Kroah-Hartman,
	Oleg Nesterov, Avi Kivity, Ryusuke Konishi, Tejun Heo,
	Magnus Damm, Andrew Morton

Add a misc device, "suspend_blocker", that allows user-space processes
to block auto suspend. The device has ioctls to create a suspend_blocker,
and to block and unblock suspend. To delete the suspend_blocker, close
the device.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
 Documentation/ioctl/ioctl-number.txt          |    3 +-
 Documentation/power/opportunistic-suspend.txt |   17 ++++
 include/linux/suspend_block_dev.h             |   25 +++++
 kernel/power/Kconfig                          |    9 ++
 kernel/power/Makefile                         |    1 +
 kernel/power/user_suspend_blocker.c           |  128 +++++++++++++++++++++++++
 6 files changed, 182 insertions(+), 1 deletions(-)
 create mode 100644 include/linux/suspend_block_dev.h
 create mode 100644 kernel/power/user_suspend_blocker.c

diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index dd5806f..e2458f7 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -254,7 +254,8 @@ Code  Seq#(hex)	Include File		Comments
 'q'	80-FF	linux/telephony.h	Internet PhoneJACK, Internet LineJACK
 		linux/ixjuser.h		<http://www.quicknet.net>
 'r'	00-1F	linux/msdos_fs.h and fs/fat/dir.c
-'s'	all	linux/cdk.h
+'s'	all	linux/cdk.h	conflict!
+'s'	all	linux/suspend_block_dev.h	conflict!
 't'	00-7F	linux/if_ppp.h
 't'	80-8F	linux/isdn_ppp.h
 't'	90	linux/toshiba.h
diff --git a/Documentation/power/opportunistic-suspend.txt b/Documentation/power/opportunistic-suspend.txt
index 3d060e8..f2b145e 100644
--- a/Documentation/power/opportunistic-suspend.txt
+++ b/Documentation/power/opportunistic-suspend.txt
@@ -117,3 +117,20 @@ if (list_empty(&state->pending_work))
 else
 	suspend_block(&state->suspend_blocker);
 
+User-space API
+==============
+
+To create a suspend_blocker from user-space, open the suspend_blocker device:
+    fd = open("/dev/suspend_blocker", O_RDWR | O_CLOEXEC);
+then call:
+    ioctl(fd, SUSPEND_BLOCKER_IOCTL_INIT(strlen(name)), name);
+
+To activate a suspend_blocker call:
+    ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK);
+
+To unblock call:
+    ioctl(fd, SUSPEND_BLOCKER_IOCTL_UNBLOCK);
+
+To destroy the suspend_blocker, close the device:
+    close(fd);
+
diff --git a/include/linux/suspend_block_dev.h b/include/linux/suspend_block_dev.h
new file mode 100644
index 0000000..24bc5c7
--- /dev/null
+++ b/include/linux/suspend_block_dev.h
@@ -0,0 +1,25 @@
+/* include/linux/suspend_block_dev.h
+ *
+ * Copyright (C) 2009 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _LINUX_SUSPEND_BLOCK_DEV_H
+#define _LINUX_SUSPEND_BLOCK_DEV_H
+
+#include <linux/ioctl.h>
+
+#define SUSPEND_BLOCKER_IOCTL_INIT(len)		_IOC(_IOC_WRITE, 's', 0, len)
+#define SUSPEND_BLOCKER_IOCTL_BLOCK		_IO('s', 1)
+#define SUSPEND_BLOCKER_IOCTL_UNBLOCK		_IO('s', 2)
+
+#endif
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 55a06a1..fe5a2f2 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -146,6 +146,15 @@ config OPPORTUNISTIC_SUSPEND
 	  determines the sleep state the system will be put into when there are
 	  no active suspend blockers.
 
+config USER_SUSPEND_BLOCKERS
+	bool "Userspace suspend blockers"
+	depends on OPPORTUNISTIC_SUSPEND
+	default y
+	---help---
+	  User-space suspend block api. Creates a misc device with ioctls
+	  to create, block and unblock a suspend_blocker. The suspend_blocker
+	  will be deleted when the device is closed.
+
 config HIBERNATION_NVS
 	bool
 
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index ee5276d..78f703b 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_PM_SLEEP)		+= console.o
 obj-$(CONFIG_FREEZER)		+= process.o
 obj-$(CONFIG_SUSPEND)		+= suspend.o
 obj-$(CONFIG_OPPORTUNISTIC_SUSPEND)	+= suspend_blocker.o
+obj-$(CONFIG_USER_SUSPEND_BLOCKERS)	+= user_suspend_blocker.o
 obj-$(CONFIG_PM_TEST_SUSPEND)	+= suspend_test.o
 obj-$(CONFIG_HIBERNATION)	+= hibernate.o snapshot.o swap.o user.o
 obj-$(CONFIG_HIBERNATION_NVS)	+= hibernate_nvs.o
diff --git a/kernel/power/user_suspend_blocker.c b/kernel/power/user_suspend_blocker.c
new file mode 100644
index 0000000..dc1d06f
--- /dev/null
+++ b/kernel/power/user_suspend_blocker.c
@@ -0,0 +1,128 @@
+/* kernel/power/user_suspend_block.c
+ *
+ * Copyright (C) 2009-2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/suspend_blocker.h>
+#include <linux/suspend_block_dev.h>
+
+enum {
+	DEBUG_FAILURE	= BIT(0),
+};
+static int debug_mask = DEBUG_FAILURE;
+module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+static DEFINE_MUTEX(ioctl_lock);
+
+struct user_suspend_blocker {
+	struct suspend_blocker	blocker;
+	char			name[0];
+};
+
+static int create_user_suspend_blocker(struct file *file, void __user *name,
+				 size_t name_len)
+{
+	struct user_suspend_blocker *bl;
+	if (file->private_data)
+		return -EBUSY;
+	if (name_len > NAME_MAX)
+		return -ENAMETOOLONG;
+	bl = kzalloc(sizeof(*bl) + name_len + 1, GFP_KERNEL);
+	if (!bl)
+		return -ENOMEM;
+	if (copy_from_user(bl->name, name, name_len))
+		goto err_fault;
+	suspend_blocker_init(&bl->blocker, bl->name);
+	file->private_data = bl;
+	return 0;
+
+err_fault:
+	kfree(bl);
+	return -EFAULT;
+}
+
+static long user_suspend_blocker_ioctl(struct file *file, unsigned int cmd,
+				unsigned long _arg)
+{
+	void __user *arg = (void __user *)_arg;
+	struct user_suspend_blocker *bl;
+	long ret;
+
+	mutex_lock(&ioctl_lock);
+	if ((cmd & ~IOCSIZE_MASK) == SUSPEND_BLOCKER_IOCTL_INIT(0)) {
+		ret = create_user_suspend_blocker(file, arg, _IOC_SIZE(cmd));
+		goto done;
+	}
+	bl = file->private_data;
+	if (!bl) {
+		ret = -ENOENT;
+		goto done;
+	}
+	switch (cmd) {
+	case SUSPEND_BLOCKER_IOCTL_BLOCK:
+		suspend_block(&bl->blocker);
+		ret = 0;
+		break;
+	case SUSPEND_BLOCKER_IOCTL_UNBLOCK:
+		suspend_unblock(&bl->blocker);
+		ret = 0;
+		break;
+	default:
+		ret = -ENOTSUPP;
+	}
+done:
+	if (ret && (debug_mask & DEBUG_FAILURE))
+		pr_err("user_suspend_blocker_ioctl: cmd %x failed, %ld\n",
+			cmd, ret);
+	mutex_unlock(&ioctl_lock);
+	return ret;
+}
+
+static int user_suspend_blocker_release(struct inode *inode, struct file *file)
+{
+	struct user_suspend_blocker *bl = file->private_data;
+	if (!bl)
+		return 0;
+	suspend_blocker_destroy(&bl->blocker);
+	kfree(bl);
+	return 0;
+}
+
+const struct file_operations user_suspend_blocker_fops = {
+	.release = user_suspend_blocker_release,
+	.unlocked_ioctl = user_suspend_blocker_ioctl,
+};
+
+struct miscdevice user_suspend_blocker_device = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "suspend_blocker",
+	.fops = &user_suspend_blocker_fops,
+};
+
+static int __init user_suspend_blocker_init(void)
+{
+	return misc_register(&user_suspend_blocker_device);
+}
+
+static void __exit user_suspend_blocker_exit(void)
+{
+	misc_deregister(&user_suspend_blocker_device);
+}
+
+module_init(user_suspend_blocker_init);
+module_exit(user_suspend_blocker_exit);
-- 
1.6.5.1

_______________________________________________
linux-pm mailing list
linux-pm@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/linux-pm

^ permalink raw reply related	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend  blockers from user-space
  2010-04-29 21:11               ` Rafael J. Wysocki
@ 2010-04-29 23:41                 ` Arve Hjønnevåg
  -1 siblings, 0 replies; 93+ messages in thread
From: Arve Hjønnevåg @ 2010-04-29 23:41 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: linux-pm, linux-kernel, Alan Stern, Tejun Heo, Oleg Nesterov,
	Randy Dunlap, Andrew Morton, Ryusuke Konishi, Jim Collar,
	Greg Kroah-Hartman, Avi Kivity, Len Brown, Pavel Machek,
	Magnus Damm, Cornelia Huck, Nigel Cunningham, linux-doc

2010/4/29 Rafael J. Wysocki <rjw@sisk.pl>:
> On Thursday 29 April 2010, Arve Hjønnevåg wrote:
>> 2010/4/28 Rafael J. Wysocki <rjw@sisk.pl>:
>> > On Thursday 29 April 2010, Arve Hjønnevåg wrote:
>> >> 2010/4/28 Rafael J. Wysocki <rjw@sisk.pl>:
>> >> > On Wednesday 28 April 2010, Arve Hjønnevåg wrote:
>> >> >> Add a misc device, "suspend_blocker", that allows user-space processes
>> >> >> to block auto suspend. The device has ioctls to create a suspend_blocker,
>> >> >> and to block and unblock suspend. To delete the suspend_blocker, close
>> >> >> the device.
>> >> >>
>> >> >> Signed-off-by: Arve Hjønnevåg <arve@android.com>
>> >> > ...
>> >> >> +
>> >> >> +#include <linux/fs.h>
>> >> >> +#include <linux/miscdevice.h>
>> >> >> +#include <linux/module.h>
>> >> >> +#include <linux/uaccess.h>
>> >> >> +#include <linux/slab.h>
>> >> >> +#include <linux/suspend_blocker.h>
>> >> >> +#include <linux/suspend_block_dev.h>
>> >> >> +
>> >> >> +enum {
>> >> >> +     DEBUG_FAILURE   = BIT(0),
>> >> >> +};
>> >> >> +static int debug_mask = DEBUG_FAILURE;
>> >> >
>> >> > What's the exact purpose of this?
>> >>
>> >> To show errors returned to user space. I can turn it off by default if you want.
>> >
>> > Not necessarily, but why is it a mask?  It looks like a 0/1 thing would be
>> > sufficient.
>>
>> I may want to add a bit to print all user-space block and unblock calls.
>
> Alternatively, you can add a new parameter for that, which I think I would prefer.
>

I use a bit-mask in the main suspend blocker code. This makes it easy
to turn on or off all the messages.

-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
@ 2010-04-29 23:41                 ` Arve Hjønnevåg
  0 siblings, 0 replies; 93+ messages in thread
From: Arve Hjønnevåg @ 2010-04-29 23:41 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Len Brown, Jim Collar, linux-doc, Greg Kroah-Hartman,
	linux-kernel, Oleg Nesterov, Avi Kivity, Ryusuke Konishi,
	Tejun Heo, Magnus Damm, linux-pm, Andrew Morton

2010/4/29 Rafael J. Wysocki <rjw@sisk.pl>:
> On Thursday 29 April 2010, Arve Hjønnevåg wrote:
>> 2010/4/28 Rafael J. Wysocki <rjw@sisk.pl>:
>> > On Thursday 29 April 2010, Arve Hjønnevåg wrote:
>> >> 2010/4/28 Rafael J. Wysocki <rjw@sisk.pl>:
>> >> > On Wednesday 28 April 2010, Arve Hjønnevåg wrote:
>> >> >> Add a misc device, "suspend_blocker", that allows user-space processes
>> >> >> to block auto suspend. The device has ioctls to create a suspend_blocker,
>> >> >> and to block and unblock suspend. To delete the suspend_blocker, close
>> >> >> the device.
>> >> >>
>> >> >> Signed-off-by: Arve Hjønnevåg <arve@android.com>
>> >> > ...
>> >> >> +
>> >> >> +#include <linux/fs.h>
>> >> >> +#include <linux/miscdevice.h>
>> >> >> +#include <linux/module.h>
>> >> >> +#include <linux/uaccess.h>
>> >> >> +#include <linux/slab.h>
>> >> >> +#include <linux/suspend_blocker.h>
>> >> >> +#include <linux/suspend_block_dev.h>
>> >> >> +
>> >> >> +enum {
>> >> >> +     DEBUG_FAILURE   = BIT(0),
>> >> >> +};
>> >> >> +static int debug_mask = DEBUG_FAILURE;
>> >> >
>> >> > What's the exact purpose of this?
>> >>
>> >> To show errors returned to user space. I can turn it off by default if you want.
>> >
>> > Not necessarily, but why is it a mask?  It looks like a 0/1 thing would be
>> > sufficient.
>>
>> I may want to add a bit to print all user-space block and unblock calls.
>
> Alternatively, you can add a new parameter for that, which I think I would prefer.
>

I use a bit-mask in the main suspend blocker code. This makes it easy
to turn on or off all the messages.

-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-04-28 23:38           ` Arve Hjønnevåg
@ 2010-04-29 21:11               ` Rafael J. Wysocki
  0 siblings, 0 replies; 93+ messages in thread
From: Rafael J. Wysocki @ 2010-04-29 21:11 UTC (permalink / raw)
  To: Arve Hjønnevåg
  Cc: linux-pm, linux-kernel, Alan Stern, Tejun Heo, Oleg Nesterov,
	Randy Dunlap, Andrew Morton, Ryusuke Konishi, Jim Collar,
	Greg Kroah-Hartman, Avi Kivity, Len Brown, Pavel Machek,
	Magnus Damm, Cornelia Huck, Nigel Cunningham, linux-doc

On Thursday 29 April 2010, Arve Hjønnevåg wrote:
> 2010/4/28 Rafael J. Wysocki <rjw@sisk.pl>:
> > On Thursday 29 April 2010, Arve Hjønnevåg wrote:
> >> 2010/4/28 Rafael J. Wysocki <rjw@sisk.pl>:
> >> > On Wednesday 28 April 2010, Arve Hjønnevåg wrote:
> >> >> Add a misc device, "suspend_blocker", that allows user-space processes
> >> >> to block auto suspend. The device has ioctls to create a suspend_blocker,
> >> >> and to block and unblock suspend. To delete the suspend_blocker, close
> >> >> the device.
> >> >>
> >> >> Signed-off-by: Arve Hjønnevåg <arve@android.com>
> >> > ...
> >> >> +
> >> >> +#include <linux/fs.h>
> >> >> +#include <linux/miscdevice.h>
> >> >> +#include <linux/module.h>
> >> >> +#include <linux/uaccess.h>
> >> >> +#include <linux/slab.h>
> >> >> +#include <linux/suspend_blocker.h>
> >> >> +#include <linux/suspend_block_dev.h>
> >> >> +
> >> >> +enum {
> >> >> +     DEBUG_FAILURE   = BIT(0),
> >> >> +};
> >> >> +static int debug_mask = DEBUG_FAILURE;
> >> >
> >> > What's the exact purpose of this?
> >>
> >> To show errors returned to user space. I can turn it off by default if you want.
> >
> > Not necessarily, but why is it a mask?  It looks like a 0/1 thing would be
> > sufficient.
> 
> I may want to add a bit to print all user-space block and unblock calls.

Alternatively, you can add a new parameter for that, which I think I would prefer.

Rafael

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
@ 2010-04-29 21:11               ` Rafael J. Wysocki
  0 siblings, 0 replies; 93+ messages in thread
From: Rafael J. Wysocki @ 2010-04-29 21:11 UTC (permalink / raw)
  To: Arve Hjønnevåg
  Cc: Len Brown, Jim Collar, linux-doc, Greg Kroah-Hartman,
	linux-kernel, Oleg Nesterov, Avi Kivity, Ryusuke Konishi,
	Tejun Heo, Magnus Damm, linux-pm, Andrew Morton

On Thursday 29 April 2010, Arve Hjønnevåg wrote:
> 2010/4/28 Rafael J. Wysocki <rjw@sisk.pl>:
> > On Thursday 29 April 2010, Arve Hjønnevåg wrote:
> >> 2010/4/28 Rafael J. Wysocki <rjw@sisk.pl>:
> >> > On Wednesday 28 April 2010, Arve Hjønnevåg wrote:
> >> >> Add a misc device, "suspend_blocker", that allows user-space processes
> >> >> to block auto suspend. The device has ioctls to create a suspend_blocker,
> >> >> and to block and unblock suspend. To delete the suspend_blocker, close
> >> >> the device.
> >> >>
> >> >> Signed-off-by: Arve Hjønnevåg <arve@android.com>
> >> > ...
> >> >> +
> >> >> +#include <linux/fs.h>
> >> >> +#include <linux/miscdevice.h>
> >> >> +#include <linux/module.h>
> >> >> +#include <linux/uaccess.h>
> >> >> +#include <linux/slab.h>
> >> >> +#include <linux/suspend_blocker.h>
> >> >> +#include <linux/suspend_block_dev.h>
> >> >> +
> >> >> +enum {
> >> >> +     DEBUG_FAILURE   = BIT(0),
> >> >> +};
> >> >> +static int debug_mask = DEBUG_FAILURE;
> >> >
> >> > What's the exact purpose of this?
> >>
> >> To show errors returned to user space. I can turn it off by default if you want.
> >
> > Not necessarily, but why is it a mask?  It looks like a 0/1 thing would be
> > sufficient.
> 
> I may want to add a bit to print all user-space block and unblock calls.

Alternatively, you can add a new parameter for that, which I think I would prefer.

Rafael

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend  blockers from user-space
  2010-04-28 23:05         ` Rafael J. Wysocki
  2010-04-28 23:38           ` Arve Hjønnevåg
@ 2010-04-28 23:38           ` Arve Hjønnevåg
  2010-04-29 21:11               ` Rafael J. Wysocki
  1 sibling, 1 reply; 93+ messages in thread
From: Arve Hjønnevåg @ 2010-04-28 23:38 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: linux-pm, linux-kernel, Alan Stern, Tejun Heo, Oleg Nesterov,
	Randy Dunlap, Andrew Morton, Ryusuke Konishi, Jim Collar,
	Greg Kroah-Hartman, Avi Kivity, Len Brown, Pavel Machek,
	Magnus Damm, Cornelia Huck, Nigel Cunningham, linux-doc

2010/4/28 Rafael J. Wysocki <rjw@sisk.pl>:
> On Thursday 29 April 2010, Arve Hjønnevåg wrote:
>> 2010/4/28 Rafael J. Wysocki <rjw@sisk.pl>:
>> > On Wednesday 28 April 2010, Arve Hjønnevåg wrote:
>> >> Add a misc device, "suspend_blocker", that allows user-space processes
>> >> to block auto suspend. The device has ioctls to create a suspend_blocker,
>> >> and to block and unblock suspend. To delete the suspend_blocker, close
>> >> the device.
>> >>
>> >> Signed-off-by: Arve Hjønnevåg <arve@android.com>
>> > ...
>> >> +
>> >> +#include <linux/fs.h>
>> >> +#include <linux/miscdevice.h>
>> >> +#include <linux/module.h>
>> >> +#include <linux/uaccess.h>
>> >> +#include <linux/slab.h>
>> >> +#include <linux/suspend_blocker.h>
>> >> +#include <linux/suspend_block_dev.h>
>> >> +
>> >> +enum {
>> >> +     DEBUG_FAILURE   = BIT(0),
>> >> +};
>> >> +static int debug_mask = DEBUG_FAILURE;
>> >
>> > What's the exact purpose of this?
>>
>> To show errors returned to user space. I can turn it off by default if you want.
>
> Not necessarily, but why is it a mask?  It looks like a 0/1 thing would be
> sufficient.

I may want to add a bit to print all user-space block and unblock calls.

>
> BTW, I'd put parens around (debug_mask & DEBUG_FAILURE) for clarity.

OK.

-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-04-28 23:05         ` Rafael J. Wysocki
@ 2010-04-28 23:38           ` Arve Hjønnevåg
  2010-04-28 23:38           ` Arve Hjønnevåg
  1 sibling, 0 replies; 93+ messages in thread
From: Arve Hjønnevåg @ 2010-04-28 23:38 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Len Brown, Jim Collar, linux-doc, Greg Kroah-Hartman,
	linux-kernel, Oleg Nesterov, Avi Kivity, Ryusuke Konishi,
	Tejun Heo, Magnus Damm, linux-pm, Andrew Morton

2010/4/28 Rafael J. Wysocki <rjw@sisk.pl>:
> On Thursday 29 April 2010, Arve Hjønnevåg wrote:
>> 2010/4/28 Rafael J. Wysocki <rjw@sisk.pl>:
>> > On Wednesday 28 April 2010, Arve Hjønnevåg wrote:
>> >> Add a misc device, "suspend_blocker", that allows user-space processes
>> >> to block auto suspend. The device has ioctls to create a suspend_blocker,
>> >> and to block and unblock suspend. To delete the suspend_blocker, close
>> >> the device.
>> >>
>> >> Signed-off-by: Arve Hjønnevåg <arve@android.com>
>> > ...
>> >> +
>> >> +#include <linux/fs.h>
>> >> +#include <linux/miscdevice.h>
>> >> +#include <linux/module.h>
>> >> +#include <linux/uaccess.h>
>> >> +#include <linux/slab.h>
>> >> +#include <linux/suspend_blocker.h>
>> >> +#include <linux/suspend_block_dev.h>
>> >> +
>> >> +enum {
>> >> +     DEBUG_FAILURE   = BIT(0),
>> >> +};
>> >> +static int debug_mask = DEBUG_FAILURE;
>> >
>> > What's the exact purpose of this?
>>
>> To show errors returned to user space. I can turn it off by default if you want.
>
> Not necessarily, but why is it a mask?  It looks like a 0/1 thing would be
> sufficient.

I may want to add a bit to print all user-space block and unblock calls.

>
> BTW, I'd put parens around (debug_mask & DEBUG_FAILURE) for clarity.

OK.

-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-04-28 22:31       ` Arve Hjønnevåg
  2010-04-28 23:05         ` Rafael J. Wysocki
@ 2010-04-28 23:05         ` Rafael J. Wysocki
  2010-04-28 23:38           ` Arve Hjønnevåg
  2010-04-28 23:38           ` Arve Hjønnevåg
  1 sibling, 2 replies; 93+ messages in thread
From: Rafael J. Wysocki @ 2010-04-28 23:05 UTC (permalink / raw)
  To: Arve Hjønnevåg
  Cc: linux-pm, linux-kernel, Alan Stern, Tejun Heo, Oleg Nesterov,
	Randy Dunlap, Andrew Morton, Ryusuke Konishi, Jim Collar,
	Greg Kroah-Hartman, Avi Kivity, Len Brown, Pavel Machek,
	Magnus Damm, Cornelia Huck, Nigel Cunningham, linux-doc

On Thursday 29 April 2010, Arve Hjønnevåg wrote:
> 2010/4/28 Rafael J. Wysocki <rjw@sisk.pl>:
> > On Wednesday 28 April 2010, Arve Hjønnevåg wrote:
> >> Add a misc device, "suspend_blocker", that allows user-space processes
> >> to block auto suspend. The device has ioctls to create a suspend_blocker,
> >> and to block and unblock suspend. To delete the suspend_blocker, close
> >> the device.
> >>
> >> Signed-off-by: Arve Hjønnevåg <arve@android.com>
> > ...
> >> +
> >> +#include <linux/fs.h>
> >> +#include <linux/miscdevice.h>
> >> +#include <linux/module.h>
> >> +#include <linux/uaccess.h>
> >> +#include <linux/slab.h>
> >> +#include <linux/suspend_blocker.h>
> >> +#include <linux/suspend_block_dev.h>
> >> +
> >> +enum {
> >> +     DEBUG_FAILURE   = BIT(0),
> >> +};
> >> +static int debug_mask = DEBUG_FAILURE;
> >
> > What's the exact purpose of this?
> 
> To show errors returned to user space. I can turn it off by default if you want.

Not necessarily, but why is it a mask?  It looks like a 0/1 thing would be
sufficient.

BTW, I'd put parens around (debug_mask & DEBUG_FAILURE) for clarity.

Rafael

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-04-28 22:31       ` Arve Hjønnevåg
@ 2010-04-28 23:05         ` Rafael J. Wysocki
  2010-04-28 23:05         ` Rafael J. Wysocki
  1 sibling, 0 replies; 93+ messages in thread
From: Rafael J. Wysocki @ 2010-04-28 23:05 UTC (permalink / raw)
  To: Arve Hjønnevåg
  Cc: Len Brown, Jim Collar, linux-doc, Greg Kroah-Hartman,
	linux-kernel, Oleg Nesterov, Avi Kivity, Ryusuke Konishi,
	Tejun Heo, Magnus Damm, linux-pm, Andrew Morton

On Thursday 29 April 2010, Arve Hjønnevåg wrote:
> 2010/4/28 Rafael J. Wysocki <rjw@sisk.pl>:
> > On Wednesday 28 April 2010, Arve Hjønnevåg wrote:
> >> Add a misc device, "suspend_blocker", that allows user-space processes
> >> to block auto suspend. The device has ioctls to create a suspend_blocker,
> >> and to block and unblock suspend. To delete the suspend_blocker, close
> >> the device.
> >>
> >> Signed-off-by: Arve Hjønnevåg <arve@android.com>
> > ...
> >> +
> >> +#include <linux/fs.h>
> >> +#include <linux/miscdevice.h>
> >> +#include <linux/module.h>
> >> +#include <linux/uaccess.h>
> >> +#include <linux/slab.h>
> >> +#include <linux/suspend_blocker.h>
> >> +#include <linux/suspend_block_dev.h>
> >> +
> >> +enum {
> >> +     DEBUG_FAILURE   = BIT(0),
> >> +};
> >> +static int debug_mask = DEBUG_FAILURE;
> >
> > What's the exact purpose of this?
> 
> To show errors returned to user space. I can turn it off by default if you want.

Not necessarily, but why is it a mask?  It looks like a 0/1 thing would be
sufficient.

BTW, I'd put parens around (debug_mask & DEBUG_FAILURE) for clarity.

Rafael

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend  blockers from user-space
  2010-04-28 20:58     ` Rafael J. Wysocki
  2010-04-28 22:31       ` Arve Hjønnevåg
@ 2010-04-28 22:31       ` Arve Hjønnevåg
  2010-04-28 23:05         ` Rafael J. Wysocki
  2010-04-28 23:05         ` Rafael J. Wysocki
  1 sibling, 2 replies; 93+ messages in thread
From: Arve Hjønnevåg @ 2010-04-28 22:31 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: linux-pm, linux-kernel, Alan Stern, Tejun Heo, Oleg Nesterov,
	Randy Dunlap, Andrew Morton, Ryusuke Konishi, Jim Collar,
	Greg Kroah-Hartman, Avi Kivity, Len Brown, Pavel Machek,
	Magnus Damm, Cornelia Huck, Nigel Cunningham, linux-doc

2010/4/28 Rafael J. Wysocki <rjw@sisk.pl>:
> On Wednesday 28 April 2010, Arve Hjønnevåg wrote:
>> Add a misc device, "suspend_blocker", that allows user-space processes
>> to block auto suspend. The device has ioctls to create a suspend_blocker,
>> and to block and unblock suspend. To delete the suspend_blocker, close
>> the device.
>>
>> Signed-off-by: Arve Hjønnevåg <arve@android.com>
> ...
>> +
>> +#include <linux/fs.h>
>> +#include <linux/miscdevice.h>
>> +#include <linux/module.h>
>> +#include <linux/uaccess.h>
>> +#include <linux/slab.h>
>> +#include <linux/suspend_blocker.h>
>> +#include <linux/suspend_block_dev.h>
>> +
>> +enum {
>> +     DEBUG_FAILURE   = BIT(0),
>> +};
>> +static int debug_mask = DEBUG_FAILURE;
>
> What's the exact purpose of this?

To show errors returned to user space. I can turn it off by default if you want.

>
>> +module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
>> +
>> +static DEFINE_MUTEX(ioctl_lock);
>> +
>> +struct user_suspend_blocker {
>> +     struct suspend_blocker  blocker;
>> +     char                    name[0];
>> +};
>
> Why is this not in a header?

It's private to this file.

>
> Rafael
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
>



-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-04-28 20:58     ` Rafael J. Wysocki
@ 2010-04-28 22:31       ` Arve Hjønnevåg
  2010-04-28 22:31       ` Arve Hjønnevåg
  1 sibling, 0 replies; 93+ messages in thread
From: Arve Hjønnevåg @ 2010-04-28 22:31 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Len Brown, Jim Collar, linux-doc, Greg Kroah-Hartman,
	linux-kernel, Oleg Nesterov, Avi Kivity, Ryusuke Konishi,
	Tejun Heo, Magnus Damm, linux-pm, Andrew Morton

2010/4/28 Rafael J. Wysocki <rjw@sisk.pl>:
> On Wednesday 28 April 2010, Arve Hjønnevåg wrote:
>> Add a misc device, "suspend_blocker", that allows user-space processes
>> to block auto suspend. The device has ioctls to create a suspend_blocker,
>> and to block and unblock suspend. To delete the suspend_blocker, close
>> the device.
>>
>> Signed-off-by: Arve Hjønnevåg <arve@android.com>
> ...
>> +
>> +#include <linux/fs.h>
>> +#include <linux/miscdevice.h>
>> +#include <linux/module.h>
>> +#include <linux/uaccess.h>
>> +#include <linux/slab.h>
>> +#include <linux/suspend_blocker.h>
>> +#include <linux/suspend_block_dev.h>
>> +
>> +enum {
>> +     DEBUG_FAILURE   = BIT(0),
>> +};
>> +static int debug_mask = DEBUG_FAILURE;
>
> What's the exact purpose of this?

To show errors returned to user space. I can turn it off by default if you want.

>
>> +module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
>> +
>> +static DEFINE_MUTEX(ioctl_lock);
>> +
>> +struct user_suspend_blocker {
>> +     struct suspend_blocker  blocker;
>> +     char                    name[0];
>> +};
>
> Why is this not in a header?

It's private to this file.

>
> Rafael
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
>



-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-04-28  4:31     ` Arve Hjønnevåg
  (?)
  (?)
@ 2010-04-28 20:58     ` Rafael J. Wysocki
  2010-04-28 22:31       ` Arve Hjønnevåg
  2010-04-28 22:31       ` Arve Hjønnevåg
  -1 siblings, 2 replies; 93+ messages in thread
From: Rafael J. Wysocki @ 2010-04-28 20:58 UTC (permalink / raw)
  To: Arve Hjønnevåg
  Cc: linux-pm, linux-kernel, Alan Stern, Tejun Heo, Oleg Nesterov,
	Randy Dunlap, Andrew Morton, Ryusuke Konishi, Jim Collar,
	Greg Kroah-Hartman, Avi Kivity, Len Brown, Pavel Machek,
	Magnus Damm, Cornelia Huck, Nigel Cunningham, linux-doc

On Wednesday 28 April 2010, Arve Hjønnevåg wrote:
> Add a misc device, "suspend_blocker", that allows user-space processes
> to block auto suspend. The device has ioctls to create a suspend_blocker,
> and to block and unblock suspend. To delete the suspend_blocker, close
> the device.
> 
> Signed-off-by: Arve Hjønnevåg <arve@android.com>
...
> +
> +#include <linux/fs.h>
> +#include <linux/miscdevice.h>
> +#include <linux/module.h>
> +#include <linux/uaccess.h>
> +#include <linux/slab.h>
> +#include <linux/suspend_blocker.h>
> +#include <linux/suspend_block_dev.h>
> +
> +enum {
> +	DEBUG_FAILURE	= BIT(0),
> +};
> +static int debug_mask = DEBUG_FAILURE;

What's the exact purpose of this?

> +module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
> +
> +static DEFINE_MUTEX(ioctl_lock);
> +
> +struct user_suspend_blocker {
> +	struct suspend_blocker	blocker;
> +	char			name[0];
> +};

Why is this not in a header?

Rafael

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-04-28  4:31     ` Arve Hjønnevåg
  (?)
@ 2010-04-28 20:58     ` Rafael J. Wysocki
  -1 siblings, 0 replies; 93+ messages in thread
From: Rafael J. Wysocki @ 2010-04-28 20:58 UTC (permalink / raw)
  To: Arve Hjønnevåg
  Cc: Len Brown, Jim Collar, linux-doc, Greg Kroah-Hartman,
	linux-kernel, Oleg Nesterov, Avi Kivity, Ryusuke Konishi,
	Tejun Heo, Magnus Damm, linux-pm, Andrew Morton

On Wednesday 28 April 2010, Arve Hjønnevåg wrote:
> Add a misc device, "suspend_blocker", that allows user-space processes
> to block auto suspend. The device has ioctls to create a suspend_blocker,
> and to block and unblock suspend. To delete the suspend_blocker, close
> the device.
> 
> Signed-off-by: Arve Hjønnevåg <arve@android.com>
...
> +
> +#include <linux/fs.h>
> +#include <linux/miscdevice.h>
> +#include <linux/module.h>
> +#include <linux/uaccess.h>
> +#include <linux/slab.h>
> +#include <linux/suspend_blocker.h>
> +#include <linux/suspend_block_dev.h>
> +
> +enum {
> +	DEBUG_FAILURE	= BIT(0),
> +};
> +static int debug_mask = DEBUG_FAILURE;

What's the exact purpose of this?

> +module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
> +
> +static DEFINE_MUTEX(ioctl_lock);
> +
> +struct user_suspend_blocker {
> +	struct suspend_blocker	blocker;
> +	char			name[0];
> +};

Why is this not in a header?

Rafael
_______________________________________________
linux-pm mailing list
linux-pm@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/linux-pm

^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-04-28  4:31 ` [PATCH 1/8] PM: Add suspend block api Arve Hjønnevåg
@ 2010-04-28  4:31     ` Arve Hjønnevåg
  0 siblings, 0 replies; 93+ messages in thread
From: Arve Hjønnevåg @ 2010-04-28  4:31 UTC (permalink / raw)
  To: linux-pm, linux-kernel
  Cc: Rafael J. Wysocki, Alan Stern, Tejun Heo, Oleg Nesterov,
	Arve Hjønnevåg, Randy Dunlap, Andrew Morton,
	Ryusuke Konishi, Jim Collar, Greg Kroah-Hartman, Avi Kivity,
	Len Brown, Pavel Machek, Magnus Damm, Cornelia Huck,
	Nigel Cunningham, linux-doc

Add a misc device, "suspend_blocker", that allows user-space processes
to block auto suspend. The device has ioctls to create a suspend_blocker,
and to block and unblock suspend. To delete the suspend_blocker, close
the device.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
 Documentation/ioctl/ioctl-number.txt          |    3 +-
 Documentation/power/opportunistic-suspend.txt |   17 ++++
 include/linux/suspend_block_dev.h             |   25 +++++
 kernel/power/Kconfig                          |    9 ++
 kernel/power/Makefile                         |    1 +
 kernel/power/user_suspend_blocker.c           |  128 +++++++++++++++++++++++++
 6 files changed, 182 insertions(+), 1 deletions(-)
 create mode 100644 include/linux/suspend_block_dev.h
 create mode 100644 kernel/power/user_suspend_blocker.c

diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index dd5806f..e2458f7 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -254,7 +254,8 @@ Code  Seq#(hex)	Include File		Comments
 'q'	80-FF	linux/telephony.h	Internet PhoneJACK, Internet LineJACK
 		linux/ixjuser.h		<http://www.quicknet.net>
 'r'	00-1F	linux/msdos_fs.h and fs/fat/dir.c
-'s'	all	linux/cdk.h
+'s'	all	linux/cdk.h	conflict!
+'s'	all	linux/suspend_block_dev.h	conflict!
 't'	00-7F	linux/if_ppp.h
 't'	80-8F	linux/isdn_ppp.h
 't'	90	linux/toshiba.h
diff --git a/Documentation/power/opportunistic-suspend.txt b/Documentation/power/opportunistic-suspend.txt
index 1a29d10..639da73 100644
--- a/Documentation/power/opportunistic-suspend.txt
+++ b/Documentation/power/opportunistic-suspend.txt
@@ -112,3 +112,20 @@ if (list_empty(&state->pending_work))
 else
 	suspend_block(&state->suspend_blocker);
 
+User-space API
+==============
+
+To create a suspend_blocker from user-space, open the suspend_blocker device:
+    fd = open("/dev/suspend_blocker", O_RDWR | O_CLOEXEC);
+then call:
+    ioctl(fd, SUSPEND_BLOCKER_IOCTL_INIT(strlen(name)), name);
+
+To activate a suspend_blocker call:
+    ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK);
+
+To unblock call:
+    ioctl(fd, SUSPEND_BLOCKER_IOCTL_UNBLOCK);
+
+To destroy the suspend_blocker, close the device:
+    close(fd);
+
diff --git a/include/linux/suspend_block_dev.h b/include/linux/suspend_block_dev.h
new file mode 100644
index 0000000..24bc5c7
--- /dev/null
+++ b/include/linux/suspend_block_dev.h
@@ -0,0 +1,25 @@
+/* include/linux/suspend_block_dev.h
+ *
+ * Copyright (C) 2009 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _LINUX_SUSPEND_BLOCK_DEV_H
+#define _LINUX_SUSPEND_BLOCK_DEV_H
+
+#include <linux/ioctl.h>
+
+#define SUSPEND_BLOCKER_IOCTL_INIT(len)		_IOC(_IOC_WRITE, 's', 0, len)
+#define SUSPEND_BLOCKER_IOCTL_BLOCK		_IO('s', 1)
+#define SUSPEND_BLOCKER_IOCTL_UNBLOCK		_IO('s', 2)
+
+#endif
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 55a06a1..fe5a2f2 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -146,6 +146,15 @@ config OPPORTUNISTIC_SUSPEND
 	  determines the sleep state the system will be put into when there are
 	  no active suspend blockers.
 
+config USER_SUSPEND_BLOCKERS
+	bool "Userspace suspend blockers"
+	depends on OPPORTUNISTIC_SUSPEND
+	default y
+	---help---
+	  User-space suspend block api. Creates a misc device with ioctls
+	  to create, block and unblock a suspend_blocker. The suspend_blocker
+	  will be deleted when the device is closed.
+
 config HIBERNATION_NVS
 	bool
 
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index ee5276d..78f703b 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_PM_SLEEP)		+= console.o
 obj-$(CONFIG_FREEZER)		+= process.o
 obj-$(CONFIG_SUSPEND)		+= suspend.o
 obj-$(CONFIG_OPPORTUNISTIC_SUSPEND)	+= suspend_blocker.o
+obj-$(CONFIG_USER_SUSPEND_BLOCKERS)	+= user_suspend_blocker.o
 obj-$(CONFIG_PM_TEST_SUSPEND)	+= suspend_test.o
 obj-$(CONFIG_HIBERNATION)	+= hibernate.o snapshot.o swap.o user.o
 obj-$(CONFIG_HIBERNATION_NVS)	+= hibernate_nvs.o
diff --git a/kernel/power/user_suspend_blocker.c b/kernel/power/user_suspend_blocker.c
new file mode 100644
index 0000000..a9be6f4
--- /dev/null
+++ b/kernel/power/user_suspend_blocker.c
@@ -0,0 +1,128 @@
+/* kernel/power/user_suspend_block.c
+ *
+ * Copyright (C) 2009-2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/suspend_blocker.h>
+#include <linux/suspend_block_dev.h>
+
+enum {
+	DEBUG_FAILURE	= BIT(0),
+};
+static int debug_mask = DEBUG_FAILURE;
+module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+static DEFINE_MUTEX(ioctl_lock);
+
+struct user_suspend_blocker {
+	struct suspend_blocker	blocker;
+	char			name[0];
+};
+
+static int create_user_suspend_blocker(struct file *file, void __user *name,
+				 size_t name_len)
+{
+	struct user_suspend_blocker *bl;
+	if (file->private_data)
+		return -EBUSY;
+	if (name_len > NAME_MAX)
+		return -ENAMETOOLONG;
+	bl = kzalloc(sizeof(*bl) + name_len + 1, GFP_KERNEL);
+	if (!bl)
+		return -ENOMEM;
+	if (copy_from_user(bl->name, name, name_len))
+		goto err_fault;
+	suspend_blocker_init(&bl->blocker, bl->name);
+	file->private_data = bl;
+	return 0;
+
+err_fault:
+	kfree(bl);
+	return -EFAULT;
+}
+
+static long user_suspend_blocker_ioctl(struct file *file, unsigned int cmd,
+				unsigned long _arg)
+{
+	void __user *arg = (void __user *)_arg;
+	struct user_suspend_blocker *bl;
+	long ret;
+
+	mutex_lock(&ioctl_lock);
+	if ((cmd & ~IOCSIZE_MASK) == SUSPEND_BLOCKER_IOCTL_INIT(0)) {
+		ret = create_user_suspend_blocker(file, arg, _IOC_SIZE(cmd));
+		goto done;
+	}
+	bl = file->private_data;
+	if (!bl) {
+		ret = -ENOENT;
+		goto done;
+	}
+	switch (cmd) {
+	case SUSPEND_BLOCKER_IOCTL_BLOCK:
+		suspend_block(&bl->blocker);
+		ret = 0;
+		break;
+	case SUSPEND_BLOCKER_IOCTL_UNBLOCK:
+		suspend_unblock(&bl->blocker);
+		ret = 0;
+		break;
+	default:
+		ret = -ENOTSUPP;
+	}
+done:
+	if (ret && debug_mask & DEBUG_FAILURE)
+		pr_err("user_suspend_blocker_ioctl: cmd %x failed, %ld\n",
+			cmd, ret);
+	mutex_unlock(&ioctl_lock);
+	return ret;
+}
+
+static int user_suspend_blocker_release(struct inode *inode, struct file *file)
+{
+	struct user_suspend_blocker *bl = file->private_data;
+	if (!bl)
+		return 0;
+	suspend_blocker_destroy(&bl->blocker);
+	kfree(bl);
+	return 0;
+}
+
+const struct file_operations user_suspend_blocker_fops = {
+	.release = user_suspend_blocker_release,
+	.unlocked_ioctl = user_suspend_blocker_ioctl,
+};
+
+struct miscdevice user_suspend_blocker_device = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "suspend_blocker",
+	.fops = &user_suspend_blocker_fops,
+};
+
+static int __init user_suspend_blocker_init(void)
+{
+	return misc_register(&user_suspend_blocker_device);
+}
+
+static void __exit user_suspend_blocker_exit(void)
+{
+	misc_deregister(&user_suspend_blocker_device);
+}
+
+module_init(user_suspend_blocker_init);
+module_exit(user_suspend_blocker_exit);
-- 
1.6.5.1


^ permalink raw reply related	[flat|nested] 93+ messages in thread

* [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
@ 2010-04-28  4:31     ` Arve Hjønnevåg
  0 siblings, 0 replies; 93+ messages in thread
From: Arve Hjønnevåg @ 2010-04-28  4:31 UTC (permalink / raw)
  To: linux-pm, linux-kernel
  Cc: Len Brown, Jim Collar, linux-doc, Greg Kroah-Hartman,
	Oleg Nesterov, Avi Kivity, Ryusuke Konishi, Tejun Heo,
	Magnus Damm, Andrew Morton

Add a misc device, "suspend_blocker", that allows user-space processes
to block auto suspend. The device has ioctls to create a suspend_blocker,
and to block and unblock suspend. To delete the suspend_blocker, close
the device.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
 Documentation/ioctl/ioctl-number.txt          |    3 +-
 Documentation/power/opportunistic-suspend.txt |   17 ++++
 include/linux/suspend_block_dev.h             |   25 +++++
 kernel/power/Kconfig                          |    9 ++
 kernel/power/Makefile                         |    1 +
 kernel/power/user_suspend_blocker.c           |  128 +++++++++++++++++++++++++
 6 files changed, 182 insertions(+), 1 deletions(-)
 create mode 100644 include/linux/suspend_block_dev.h
 create mode 100644 kernel/power/user_suspend_blocker.c

diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index dd5806f..e2458f7 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -254,7 +254,8 @@ Code  Seq#(hex)	Include File		Comments
 'q'	80-FF	linux/telephony.h	Internet PhoneJACK, Internet LineJACK
 		linux/ixjuser.h		<http://www.quicknet.net>
 'r'	00-1F	linux/msdos_fs.h and fs/fat/dir.c
-'s'	all	linux/cdk.h
+'s'	all	linux/cdk.h	conflict!
+'s'	all	linux/suspend_block_dev.h	conflict!
 't'	00-7F	linux/if_ppp.h
 't'	80-8F	linux/isdn_ppp.h
 't'	90	linux/toshiba.h
diff --git a/Documentation/power/opportunistic-suspend.txt b/Documentation/power/opportunistic-suspend.txt
index 1a29d10..639da73 100644
--- a/Documentation/power/opportunistic-suspend.txt
+++ b/Documentation/power/opportunistic-suspend.txt
@@ -112,3 +112,20 @@ if (list_empty(&state->pending_work))
 else
 	suspend_block(&state->suspend_blocker);
 
+User-space API
+==============
+
+To create a suspend_blocker from user-space, open the suspend_blocker device:
+    fd = open("/dev/suspend_blocker", O_RDWR | O_CLOEXEC);
+then call:
+    ioctl(fd, SUSPEND_BLOCKER_IOCTL_INIT(strlen(name)), name);
+
+To activate a suspend_blocker call:
+    ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK);
+
+To unblock call:
+    ioctl(fd, SUSPEND_BLOCKER_IOCTL_UNBLOCK);
+
+To destroy the suspend_blocker, close the device:
+    close(fd);
+
diff --git a/include/linux/suspend_block_dev.h b/include/linux/suspend_block_dev.h
new file mode 100644
index 0000000..24bc5c7
--- /dev/null
+++ b/include/linux/suspend_block_dev.h
@@ -0,0 +1,25 @@
+/* include/linux/suspend_block_dev.h
+ *
+ * Copyright (C) 2009 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _LINUX_SUSPEND_BLOCK_DEV_H
+#define _LINUX_SUSPEND_BLOCK_DEV_H
+
+#include <linux/ioctl.h>
+
+#define SUSPEND_BLOCKER_IOCTL_INIT(len)		_IOC(_IOC_WRITE, 's', 0, len)
+#define SUSPEND_BLOCKER_IOCTL_BLOCK		_IO('s', 1)
+#define SUSPEND_BLOCKER_IOCTL_UNBLOCK		_IO('s', 2)
+
+#endif
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 55a06a1..fe5a2f2 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -146,6 +146,15 @@ config OPPORTUNISTIC_SUSPEND
 	  determines the sleep state the system will be put into when there are
 	  no active suspend blockers.
 
+config USER_SUSPEND_BLOCKERS
+	bool "Userspace suspend blockers"
+	depends on OPPORTUNISTIC_SUSPEND
+	default y
+	---help---
+	  User-space suspend block api. Creates a misc device with ioctls
+	  to create, block and unblock a suspend_blocker. The suspend_blocker
+	  will be deleted when the device is closed.
+
 config HIBERNATION_NVS
 	bool
 
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index ee5276d..78f703b 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_PM_SLEEP)		+= console.o
 obj-$(CONFIG_FREEZER)		+= process.o
 obj-$(CONFIG_SUSPEND)		+= suspend.o
 obj-$(CONFIG_OPPORTUNISTIC_SUSPEND)	+= suspend_blocker.o
+obj-$(CONFIG_USER_SUSPEND_BLOCKERS)	+= user_suspend_blocker.o
 obj-$(CONFIG_PM_TEST_SUSPEND)	+= suspend_test.o
 obj-$(CONFIG_HIBERNATION)	+= hibernate.o snapshot.o swap.o user.o
 obj-$(CONFIG_HIBERNATION_NVS)	+= hibernate_nvs.o
diff --git a/kernel/power/user_suspend_blocker.c b/kernel/power/user_suspend_blocker.c
new file mode 100644
index 0000000..a9be6f4
--- /dev/null
+++ b/kernel/power/user_suspend_blocker.c
@@ -0,0 +1,128 @@
+/* kernel/power/user_suspend_block.c
+ *
+ * Copyright (C) 2009-2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/suspend_blocker.h>
+#include <linux/suspend_block_dev.h>
+
+enum {
+	DEBUG_FAILURE	= BIT(0),
+};
+static int debug_mask = DEBUG_FAILURE;
+module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+static DEFINE_MUTEX(ioctl_lock);
+
+struct user_suspend_blocker {
+	struct suspend_blocker	blocker;
+	char			name[0];
+};
+
+static int create_user_suspend_blocker(struct file *file, void __user *name,
+				 size_t name_len)
+{
+	struct user_suspend_blocker *bl;
+	if (file->private_data)
+		return -EBUSY;
+	if (name_len > NAME_MAX)
+		return -ENAMETOOLONG;
+	bl = kzalloc(sizeof(*bl) + name_len + 1, GFP_KERNEL);
+	if (!bl)
+		return -ENOMEM;
+	if (copy_from_user(bl->name, name, name_len))
+		goto err_fault;
+	suspend_blocker_init(&bl->blocker, bl->name);
+	file->private_data = bl;
+	return 0;
+
+err_fault:
+	kfree(bl);
+	return -EFAULT;
+}
+
+static long user_suspend_blocker_ioctl(struct file *file, unsigned int cmd,
+				unsigned long _arg)
+{
+	void __user *arg = (void __user *)_arg;
+	struct user_suspend_blocker *bl;
+	long ret;
+
+	mutex_lock(&ioctl_lock);
+	if ((cmd & ~IOCSIZE_MASK) == SUSPEND_BLOCKER_IOCTL_INIT(0)) {
+		ret = create_user_suspend_blocker(file, arg, _IOC_SIZE(cmd));
+		goto done;
+	}
+	bl = file->private_data;
+	if (!bl) {
+		ret = -ENOENT;
+		goto done;
+	}
+	switch (cmd) {
+	case SUSPEND_BLOCKER_IOCTL_BLOCK:
+		suspend_block(&bl->blocker);
+		ret = 0;
+		break;
+	case SUSPEND_BLOCKER_IOCTL_UNBLOCK:
+		suspend_unblock(&bl->blocker);
+		ret = 0;
+		break;
+	default:
+		ret = -ENOTSUPP;
+	}
+done:
+	if (ret && debug_mask & DEBUG_FAILURE)
+		pr_err("user_suspend_blocker_ioctl: cmd %x failed, %ld\n",
+			cmd, ret);
+	mutex_unlock(&ioctl_lock);
+	return ret;
+}
+
+static int user_suspend_blocker_release(struct inode *inode, struct file *file)
+{
+	struct user_suspend_blocker *bl = file->private_data;
+	if (!bl)
+		return 0;
+	suspend_blocker_destroy(&bl->blocker);
+	kfree(bl);
+	return 0;
+}
+
+const struct file_operations user_suspend_blocker_fops = {
+	.release = user_suspend_blocker_release,
+	.unlocked_ioctl = user_suspend_blocker_ioctl,
+};
+
+struct miscdevice user_suspend_blocker_device = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "suspend_blocker",
+	.fops = &user_suspend_blocker_fops,
+};
+
+static int __init user_suspend_blocker_init(void)
+{
+	return misc_register(&user_suspend_blocker_device);
+}
+
+static void __exit user_suspend_blocker_exit(void)
+{
+	misc_deregister(&user_suspend_blocker_device);
+}
+
+module_init(user_suspend_blocker_init);
+module_exit(user_suspend_blocker_exit);
-- 
1.6.5.1

_______________________________________________
linux-pm mailing list
linux-pm@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/linux-pm

^ permalink raw reply related	[flat|nested] 93+ messages in thread

end of thread, other threads:[~2010-05-26 23:46 UTC | newest]

Thread overview: 93+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-04-15  1:41 [RFC][PATCH 0/8] Suspend block api Arve Hjønnevåg
2009-04-15  1:41 ` [PATCH 1/8] PM: Add suspend " Arve Hjønnevåg
2009-04-15  1:41   ` [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space Arve Hjønnevåg
2009-04-15  1:41     ` [PATCH 3/8] PM: suspend_block: Abort task freezing if a suspend_blocker is active Arve Hjønnevåg
2009-04-15  1:41       ` [PATCH 4/8] Input: Block suspend while event queue is not empty Arve Hjønnevåg
2009-04-15  1:41         ` [PATCH 5/8] PM: suspend_block: Switch to list of active and inactive suspend blockers Arve Hjønnevåg
2009-04-15  1:41           ` [PATCH 6/8] PM: suspend_block: Add suspend_blocker stats Arve Hjønnevåg
2009-04-15  1:41             ` [PATCH 7/8] PM: suspend_block: Add timeout support Arve Hjønnevåg
2009-04-15  1:41               ` [PATCH 8/8] PM: suspend_block: Add timeout support to user-space suspend_blockers Arve Hjønnevåg
2009-04-29 22:56       ` [PATCH 3/8] PM: suspend_block: Abort task freezing if a suspend_blocker is active Rafael J. Wysocki
2009-04-29 22:52     ` [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space Rafael J. Wysocki
2009-04-15 15:29   ` [PATCH 1/8] PM: Add suspend block api Alan Stern
2009-04-15 19:08     ` mark gross
2009-04-16  0:40       ` Arve Hjønnevåg
2009-04-16  0:34     ` Arve Hjønnevåg
2009-04-15 22:31   ` mark gross
2009-04-16  1:45     ` Arve Hjønnevåg
2009-04-16 17:49       ` mark gross
2009-04-20  9:29   ` Pavel Machek
2009-04-21  4:44     ` Arve Hjønnevåg
2009-04-24 20:59       ` Pavel Machek
2009-04-29 21:24         ` Rafael J. Wysocki
2009-04-29 22:52           ` Arve Hjønnevåg
2009-04-29 22:34   ` Rafael J. Wysocki
2009-04-29 23:45     ` Arve Hjønnevåg
2009-04-30  0:49     ` Arve Hjønnevåg
2009-04-26  9:42       ` Pavel Machek
2009-05-02 12:17         ` Rafael J. Wysocki
2009-05-02 12:14       ` Rafael J. Wysocki
2009-05-02 20:51         ` Pavel Machek
2009-05-05  3:48         ` Arve Hjønnevåg
2009-04-15 23:04 ` [RFC][PATCH 0/8] Suspend " Rafael J. Wysocki
2010-04-28  4:31 [PATCH 0/9] Suspend block api (version 5) Arve Hjønnevåg
2010-04-28  4:31 ` [PATCH 1/8] PM: Add suspend block api Arve Hjønnevåg
2010-04-28  4:31   ` [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space Arve Hjønnevåg
2010-04-28  4:31     ` Arve Hjønnevåg
2010-04-28 20:58     ` Rafael J. Wysocki
2010-04-28 20:58     ` Rafael J. Wysocki
2010-04-28 22:31       ` Arve Hjønnevåg
2010-04-28 22:31       ` Arve Hjønnevåg
2010-04-28 23:05         ` Rafael J. Wysocki
2010-04-28 23:05         ` Rafael J. Wysocki
2010-04-28 23:38           ` Arve Hjønnevåg
2010-04-28 23:38           ` Arve Hjønnevåg
2010-04-29 21:11             ` Rafael J. Wysocki
2010-04-29 21:11               ` Rafael J. Wysocki
2010-04-29 23:41               ` Arve Hjønnevåg
2010-04-29 23:41                 ` Arve Hjønnevåg
2010-04-30 22:36 [PATCH 0/8] Suspend block api (version 6) Arve Hjønnevåg
2010-04-30 22:36 ` [PATCH 1/8] PM: Add suspend block api Arve Hjønnevåg
2010-04-30 22:36   ` [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space Arve Hjønnevåg
2010-04-30 22:36     ` Arve Hjønnevåg
2010-05-02  7:04     ` Pavel Machek
2010-05-02  7:04     ` Pavel Machek
2010-05-02 21:23     ` Rafael J. Wysocki
2010-05-02 21:23       ` Rafael J. Wysocki
2010-05-02 21:56       ` Alan Stern
2010-05-02 21:56       ` Alan Stern
2010-05-03 15:03         ` Rafael J. Wysocki
2010-05-03 21:26           ` Arve Hjønnevåg
2010-05-03 21:26           ` Arve Hjønnevåg
2010-05-03 21:49             ` Rafael J. Wysocki
2010-05-03 21:49             ` Rafael J. Wysocki
2010-05-03 22:01               ` Arve Hjønnevåg
2010-05-03 22:01               ` Arve Hjønnevåg
2010-05-04 20:02                 ` Rafael J. Wysocki
2010-05-04 20:02                 ` Rafael J. Wysocki
2010-05-04  4:16           ` Pavel Machek
2010-05-04  4:16           ` Pavel Machek
2010-05-03 15:03         ` Rafael J. Wysocki
2010-05-14  4:11 [PATCH 0/8] Suspend block api (version 7) Arve Hjønnevåg
2010-05-14  4:11 ` [PATCH 1/8] PM: Add suspend block api Arve Hjønnevåg
2010-05-14  4:11   ` [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space Arve Hjønnevåg
2010-05-14  4:11     ` Arve Hjønnevåg
2010-05-21 22:46 [PATCH 0/8] Suspend block api (version 8) Arve Hjønnevåg
2010-05-21 22:46 ` [PATCH 1/8] PM: Opportunistic suspend support Arve Hjønnevåg
2010-05-21 22:46   ` [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space Arve Hjønnevåg
2010-05-26  8:43     ` Peter Zijlstra
2010-05-26 10:47       ` Arve Hjønnevåg
2010-05-26 10:47       ` Arve Hjønnevåg
2010-05-26 10:50         ` Peter Zijlstra
2010-05-26 10:50         ` Peter Zijlstra
2010-05-26 23:13           ` Arve Hjønnevåg
2010-05-26 23:13           ` Arve Hjønnevåg
2010-05-26 10:51         ` Florian Mickler
2010-05-26 10:51         ` Florian Mickler
2010-05-26 11:06           ` Peter Zijlstra
2010-05-26 11:06           ` Peter Zijlstra
2010-05-26 21:57       ` Rafael J. Wysocki
2010-05-26 21:57       ` Rafael J. Wysocki
2010-05-26 22:14         ` Alan Cox
2010-05-26 22:18           ` Brian Swetland
2010-05-26 23:00             ` Alan Cox
2010-05-26 23:00               ` Arve Hjønnevåg
2010-05-26 23:52                 ` Alan Cox
2010-05-26 22:45           ` Rafael J. Wysocki
2010-05-26 22:18         ` Alan Stern
2010-05-26 22:18         ` Alan Stern
2010-05-26  8:43     ` Peter Zijlstra
2010-05-21 22:46   ` Arve Hjønnevåg
2010-05-26 22:18 [linux-pm] " Alan Stern
2010-05-26 22:34 ` Rafael J. Wysocki

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.