linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH -mm 0/2] Separate freezer from PM code
@ 2007-04-27 15:37 Rafael J. Wysocki
  2007-04-27 15:38 ` [PATCH -mm 1/2] " Rafael J. Wysocki
  2007-04-27 15:40 ` [PATCH -mm 2/2] Introduce freezer flags Rafael J. Wysocki
  0 siblings, 2 replies; 23+ messages in thread
From: Rafael J. Wysocki @ 2007-04-27 15:37 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Gautham R Shenoy, Ingo Molnar, Oleg Nesterov, Pavel Machek,
	Pekka Enberg, LKML

Hi,

The first patch in the series separates the tasks freezer from the PM code and
moves it to kernel/freezer.c .  Some cleanups of freezer.c proposed by Gautham
will be sent in a separate patch.

The second one moves all of the freezer-specific per-task flags to a separate
filed of task_struct and defines functions for manipulating them with the help
of set_bit() and friends.  I think I have addressed all of the outstanding
issues with it.

The patches are against 2.6.21-rc7-mm2 with the Gautham's patch from
http://lkml.org/lkml/2007/4/26/250 applied.

Greetings,
Rafael


-- 
If you don't have the time to read,
you don't have the time or the tools to write.
		- Stephen King


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

* [PATCH -mm 1/2] Separate freezer from PM code
  2007-04-27 15:37 [PATCH -mm 0/2] Separate freezer from PM code Rafael J. Wysocki
@ 2007-04-27 15:38 ` Rafael J. Wysocki
  2007-04-27 16:15   ` Sam Ravnborg
  2007-04-27 16:25   ` Jeremy Fitzhardinge
  2007-04-27 15:40 ` [PATCH -mm 2/2] Introduce freezer flags Rafael J. Wysocki
  1 sibling, 2 replies; 23+ messages in thread
From: Rafael J. Wysocki @ 2007-04-27 15:38 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Gautham R Shenoy, Ingo Molnar, Oleg Nesterov, Pavel Machek,
	Pekka Enberg, LKML

From: Rafael J. Wysocki <rjw@sisk.pl>

Now that the freezer is used by kprobes, it is no longer a PM-specific piece of
code.  Move the freezer code out of kernel/power and introduce the
CONFIG_FREEZER option that will be chosen automatically if PM or KPROBES is
set.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Acked-by: Pavel Machek <pavel@ucw.cz>
---
 arch/arm/Kconfig         |    5 
 arch/avr32/Kconfig.debug |    5 
 arch/blackfin/Kconfig    |    5 
 arch/frv/Kconfig         |    5 
 arch/i386/Kconfig        |    5 
 arch/ia64/Kconfig        |    5 
 arch/mips/Kconfig        |    5 
 arch/powerpc/Kconfig     |    5 
 arch/ppc/Kconfig         |    5 
 arch/s390/Kconfig        |    5 
 arch/sh/Kconfig          |    5 
 arch/sparc64/Kconfig     |    5 
 arch/x86_64/Kconfig      |    8 +
 include/linux/freezer.h  |    2 
 kernel/Makefile          |    1 
 kernel/freezer.c         |  236 +++++++++++++++++++++++++++++++++++++++++++++++
 kernel/kprobes.c         |    2 
 kernel/power/Makefile    |    2 
 kernel/power/process.c   |  236 -----------------------------------------------
 19 files changed, 308 insertions(+), 239 deletions(-)

Index: linux-2.6.21-rc7-mm2/arch/x86_64/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/x86_64/Kconfig	2007-04-27 01:22:33.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/x86_64/Kconfig	2007-04-27 01:33:22.000000000 +0200
@@ -703,6 +703,14 @@ config GENERIC_PENDING_IRQ
 	depends on GENERIC_HARDIRQS && SMP
 	default y
 
+#
+# Use the tasks freezer
+#
+config FREEZER
+	bool
+	default y
+	depends on PM || KPROBES
+
 menu "Power management options"
 
 source kernel/power/Kconfig
Index: linux-2.6.21-rc7-mm2/arch/avr32/Kconfig.debug
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/avr32/Kconfig.debug	2007-04-27 01:22:33.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/avr32/Kconfig.debug	2007-04-27 01:33:22.000000000 +0200
@@ -24,3 +24,8 @@ source "kernel/Kconfig.marker"
 endmenu
 
 endmenu
+
+config FREEZER
+	bool
+	default y
+	depends on KPROBES
Index: linux-2.6.21-rc7-mm2/arch/frv/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/frv/Kconfig	2007-04-27 01:22:33.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/frv/Kconfig	2007-04-27 01:33:22.000000000 +0200
@@ -364,6 +364,11 @@ source "drivers/pcmcia/Kconfig"
 #	  sleep-deprived psychotic hacker types can say Y now, everyone else
 #	  should probably wait a while.
 
+config FREEZER
+	bool
+	default y
+	depends on PM
+
 menu "Power management options"
 source kernel/power/Kconfig
 endmenu
Index: linux-2.6.21-rc7-mm2/arch/i386/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/i386/Kconfig	2007-04-27 01:22:33.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/i386/Kconfig	2007-04-27 01:33:22.000000000 +0200
@@ -912,6 +912,11 @@ config ARCH_ENABLE_MEMORY_HOTPLUG
 	def_bool y
 	depends on HIGHMEM
 
+config FREEZER
+	bool
+	default y
+	depends on PM || KPROBES
+
 menu "Power management options (ACPI, APM)"
 	depends on !X86_VOYAGER
 
Index: linux-2.6.21-rc7-mm2/arch/ia64/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/ia64/Kconfig	2007-04-27 01:22:33.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/ia64/Kconfig	2007-04-27 01:33:22.000000000 +0200
@@ -495,6 +495,11 @@ source "fs/Kconfig.binfmt"
 
 endmenu
 
+config FREEZER
+	bool
+	default y
+	depends on PM || KPROBES
+
 menu "Power management and ACPI"
 
 source "kernel/power/Kconfig"
Index: linux-2.6.21-rc7-mm2/arch/powerpc/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/powerpc/Kconfig	2007-04-27 01:22:33.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/powerpc/Kconfig	2007-04-27 01:33:22.000000000 +0200
@@ -552,6 +552,11 @@ config CMDLINE
 	  some command-line options at build time by entering them here.  In
 	  most cases you will need to specify the root device here.
 
+config FREEZER
+	bool
+	default y
+	depends on PM || KPROBES
+
 if !44x || BROKEN
 source kernel/power/Kconfig
 endif
Index: linux-2.6.21-rc7-mm2/arch/ppc/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/ppc/Kconfig	2007-04-27 01:22:33.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/ppc/Kconfig	2007-04-27 01:33:22.000000000 +0200
@@ -1154,6 +1154,11 @@ config PROC_HARDWARE
 source "drivers/zorro/Kconfig"
 
 if !44x || BROKEN
+config FREEZER
+	bool
+	default y
+	depends on PM
+
 source kernel/power/Kconfig
 endif
 
Index: linux-2.6.21-rc7-mm2/arch/s390/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/s390/Kconfig	2007-04-27 01:22:33.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/s390/Kconfig	2007-04-27 01:33:22.000000000 +0200
@@ -564,6 +564,11 @@ config KPROBES
 	  for kernel debugging, non-intrusive instrumentation and testing.
 	  If in doubt, say "N".
 
+config FREEZER
+	bool
+	default y
+	depends on KPROBES
+
 source "kernel/Kconfig.marker"
 
 source "lib/Kconfig.statistic"
Index: linux-2.6.21-rc7-mm2/arch/sh/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/sh/Kconfig	2007-04-27 01:22:33.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/sh/Kconfig	2007-04-27 01:33:22.000000000 +0200
@@ -699,6 +699,11 @@ source "fs/Kconfig.binfmt"
 
 endmenu
 
+config FREEZER
+	bool
+	default y
+	depends on PM
+
 menu "Power management options (EXPERIMENTAL)"
 depends on EXPERIMENTAL
 
Index: linux-2.6.21-rc7-mm2/arch/sparc64/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/sparc64/Kconfig	2007-04-27 01:22:33.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/sparc64/Kconfig	2007-04-27 01:33:22.000000000 +0200
@@ -435,6 +435,11 @@ config KPROBES
 	  for kernel debugging, non-intrusive instrumentation and testing.
 	  If in doubt, say "N".
 
+config FREEZER
+	bool
+	default y
+	depends on KPROBES
+
 source "kernel/Kconfig.marker"
 
 endmenu
Index: linux-2.6.21-rc7-mm2/kernel/Makefile
===================================================================
--- linux-2.6.21-rc7-mm2.orig/kernel/Makefile	2007-04-27 01:22:33.000000000 +0200
+++ linux-2.6.21-rc7-mm2/kernel/Makefile	2007-04-27 01:33:22.000000000 +0200
@@ -33,6 +33,7 @@ obj-$(CONFIG_MODULES) += module.o
 obj-$(CONFIG_KALLSYMS) += kallsyms.o
 obj-$(CONFIG_STACK_UNWIND) += unwind.o
 obj-$(CONFIG_PM) += power/
+obj-$(CONFIG_FREEZER) += freezer.o
 obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
 obj-$(CONFIG_KEXEC) += kexec.o
 obj-$(CONFIG_COMPAT) += compat.o
Index: linux-2.6.21-rc7-mm2/kernel/power/Makefile
===================================================================
--- linux-2.6.21-rc7-mm2.orig/kernel/power/Makefile	2007-04-27 01:22:33.000000000 +0200
+++ linux-2.6.21-rc7-mm2/kernel/power/Makefile	2007-04-27 01:33:22.000000000 +0200
@@ -3,7 +3,7 @@ ifeq ($(CONFIG_PM_DEBUG),y)
 EXTRA_CFLAGS	+=	-DDEBUG
 endif
 
-obj-y				:= main.o process.o console.o notify.o
+obj-y				:= main.o console.o notify.o
 obj-$(CONFIG_PM_LEGACY)		+= pm.o
 obj-$(CONFIG_SOFTWARE_SUSPEND)	+= swsusp.o disk.o snapshot.o swap.o user.o
 
Index: linux-2.6.21-rc7-mm2/kernel/kprobes.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/kernel/kprobes.c	2007-04-27 01:22:33.000000000 +0200
+++ linux-2.6.21-rc7-mm2/kernel/kprobes.c	2007-04-27 01:33:22.000000000 +0200
@@ -108,7 +108,7 @@ static int collect_garbage_slots(void);
 static int __kprobes check_safety(void)
 {
 	int ret = 0;
-#if defined(CONFIG_PREEMPT) && defined(CONFIG_PM)
+#ifdef CONFIG_PREEMPT
 	ret = freeze_processes();
 	if (ret == 0) {
 		struct task_struct *p, *q;
Index: linux-2.6.21-rc7-mm2/include/linux/freezer.h
===================================================================
--- linux-2.6.21-rc7-mm2.orig/include/linux/freezer.h	2007-04-27 01:31:19.000000000 +0200
+++ linux-2.6.21-rc7-mm2/include/linux/freezer.h	2007-04-27 01:33:22.000000000 +0200
@@ -2,7 +2,7 @@
 
 #include <linux/sched.h>
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_FREEZER
 /*
  * Check if a process has been frozen
  */
Index: linux-2.6.21-rc7-mm2/arch/arm/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/arm/Kconfig	2007-04-27 01:22:33.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/arm/Kconfig	2007-04-27 01:33:22.000000000 +0200
@@ -929,6 +929,11 @@ menu "Power management options"
 
 source "kernel/power/Kconfig"
 
+config FREEZER
+	bool
+	default y
+	depends on PM
+
 endmenu
 
 source "net/Kconfig"
Index: linux-2.6.21-rc7-mm2/arch/blackfin/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/blackfin/Kconfig	2007-04-27 01:22:33.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/blackfin/Kconfig	2007-04-27 01:33:22.000000000 +0200
@@ -819,6 +819,11 @@ endmenu
 menu "Power management options"
 source "kernel/power/Kconfig"
 
+config FREEZER
+	bool
+	default y
+	depends on PM
+
 choice
 	prompt "Select PM Wakeup Event Source"
 	default PM_WAKEUP_GPIO_BY_SIC_IWR
Index: linux-2.6.21-rc7-mm2/arch/mips/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/mips/Kconfig	2007-04-27 01:22:33.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/mips/Kconfig	2007-04-27 01:33:22.000000000 +0200
@@ -2138,6 +2138,11 @@ config BINFMT_ELF32
 
 source "kernel/power/Kconfig"
 
+config FREEZER
+	bool
+	default y
+	depends on PM
+
 endmenu
 
 source "net/Kconfig"
Index: linux-2.6.21-rc7-mm2/kernel/freezer.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.21-rc7-mm2/kernel/freezer.c	2007-04-27 01:35:21.000000000 +0200
@@ -0,0 +1,236 @@
+/*
+ * linux/kernel/freezer.c
+ *
+ * Generic mechanism for freezing and thawing tasks, originally from swsusp.
+ *
+ * Distributed under the GPLv2
+ */
+
+
+#undef DEBUG
+
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/syscalls.h>
+#include <linux/freezer.h>
+
+/*
+ * Timeout for stopping processes
+ */
+#define TIMEOUT	(20 * HZ)
+
+#define FREEZER_KERNEL_THREADS 0
+#define FREEZER_USER_SPACE 1
+
+static inline int freezeable(struct task_struct * p)
+{
+	if ((p == current) ||
+	    (p->flags & PF_NOFREEZE) ||
+	    (p->exit_state != 0))
+		return 0;
+	return 1;
+}
+
+/*
+ * freezing is complete, mark current process as frozen
+ */
+static inline void frozen_process(void)
+{
+	if (!unlikely(current->flags & PF_NOFREEZE)) {
+		current->flags |= PF_FROZEN;
+		wmb();
+	}
+	clear_tsk_thread_flag(current, TIF_FREEZE);
+}
+
+/* Refrigerator is place where frozen processes are stored :-). */
+void refrigerator(void)
+{
+	/* Hmm, should we be allowed to suspend when there are realtime
+	   processes around? */
+	long save;
+
+	task_lock(current);
+	if (freezing(current)) {
+		frozen_process();
+		task_unlock(current);
+	} else {
+		task_unlock(current);
+		return;
+	}
+	save = current->state;
+	pr_debug("%s entered refrigerator\n", current->comm);
+
+	spin_lock_irq(&current->sighand->siglock);
+	recalc_sigpending(); /* We sent fake signal, clean it up */
+	spin_unlock_irq(&current->sighand->siglock);
+
+	for (;;) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		if (!frozen(current))
+			break;
+		schedule();
+	}
+	pr_debug("%s left refrigerator\n", current->comm);
+	current->state = save;
+}
+
+static inline void freeze_process(struct task_struct *p)
+{
+	unsigned long flags;
+
+	if (!freezing(p)) {
+		rmb();
+		if (!frozen(p)) {
+			if (p->state == TASK_STOPPED)
+				force_sig_specific(SIGSTOP, p);
+
+			freeze(p);
+			spin_lock_irqsave(&p->sighand->siglock, flags);
+			signal_wake_up(p, p->state == TASK_STOPPED);
+			spin_unlock_irqrestore(&p->sighand->siglock, flags);
+		}
+	}
+}
+
+static void cancel_freezing(struct task_struct *p)
+{
+	unsigned long flags;
+
+	if (freezing(p)) {
+		pr_debug("  clean up: %s\n", p->comm);
+		do_not_freeze(p);
+		spin_lock_irqsave(&p->sighand->siglock, flags);
+		recalc_sigpending_tsk(p);
+		spin_unlock_irqrestore(&p->sighand->siglock, flags);
+	}
+}
+
+static inline int is_user_space(struct task_struct *p)
+{
+	int ret;
+
+	task_lock(p);
+	ret = p->mm && !(p->flags & PF_BORROWED_MM);
+	task_unlock(p);
+	return ret;
+}
+
+static unsigned int try_to_freeze_tasks(int freeze_user_space)
+{
+	struct task_struct *g, *p;
+	unsigned long end_time;
+	unsigned int todo;
+
+	end_time = jiffies + TIMEOUT;
+	do {
+		todo = 0;
+		read_lock(&tasklist_lock);
+		do_each_thread(g, p) {
+			if (!freezeable(p))
+				continue;
+
+			if (frozen(p))
+				continue;
+
+			if (p->state == TASK_TRACED && frozen(p->parent)) {
+				cancel_freezing(p);
+				continue;
+			}
+			if (freeze_user_space && !is_user_space(p))
+				continue;
+
+			freeze_process(p);
+			if (!freezer_should_skip(p))
+				todo++;
+		} while_each_thread(g, p);
+		read_unlock(&tasklist_lock);
+		yield();			/* Yield is okay here */
+		if (todo && time_after(jiffies, end_time))
+			break;
+	} while (todo);
+
+	if (todo) {
+		/* This does not unfreeze processes that are already frozen
+		 * (we have slightly ugly calling convention in that respect,
+		 * and caller must call thaw_processes() if something fails),
+		 * but it cleans up leftover PF_FREEZE requests.
+		 */
+		printk("\n");
+		printk(KERN_ERR "Stopping %s timed out after %d seconds "
+				"(%d tasks refusing to freeze):\n",
+				freeze_user_space ? "user space processes" :
+					"kernel threads",
+				TIMEOUT / HZ, todo);
+		read_lock(&tasklist_lock);
+		do_each_thread(g, p) {
+			if (freeze_user_space && !is_user_space(p))
+				continue;
+
+			task_lock(p);
+			if (freezeable(p) && !frozen(p) &&
+			    !freezer_should_skip(p))
+				printk(KERN_ERR " %s\n", p->comm);
+
+			cancel_freezing(p);
+			task_unlock(p);
+		} while_each_thread(g, p);
+		read_unlock(&tasklist_lock);
+	}
+
+	return todo;
+}
+
+/**
+ *	freeze_processes - tell processes to enter the refrigerator
+ *
+ *	Returns 0 on success, or the number of processes that didn't freeze,
+ *	although they were told to.
+ */
+int freeze_processes(void)
+{
+	unsigned int nr_unfrozen;
+
+	printk("Stopping tasks ... ");
+	nr_unfrozen = try_to_freeze_tasks(FREEZER_USER_SPACE);
+	if (nr_unfrozen)
+		return nr_unfrozen;
+
+	sys_sync();
+	nr_unfrozen = try_to_freeze_tasks(FREEZER_KERNEL_THREADS);
+	if (nr_unfrozen)
+		return nr_unfrozen;
+
+	printk("done.\n");
+	BUG_ON(in_atomic());
+	return 0;
+}
+
+static void thaw_tasks(int thaw_user_space)
+{
+	struct task_struct *g, *p;
+
+	read_lock(&tasklist_lock);
+	do_each_thread(g, p) {
+		if (!freezeable(p))
+			continue;
+
+		if (is_user_space(p) == !thaw_user_space)
+			continue;
+
+		thaw_process(p);
+	} while_each_thread(g, p);
+	read_unlock(&tasklist_lock);
+}
+
+void thaw_processes(void)
+{
+	printk("Restarting tasks ... ");
+	thaw_tasks(FREEZER_KERNEL_THREADS);
+	thaw_tasks(FREEZER_USER_SPACE);
+	schedule();
+	printk("done.\n");
+}
+
+EXPORT_SYMBOL(refrigerator);
Index: linux-2.6.21-rc7-mm2/kernel/power/process.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/kernel/power/process.c	2007-04-27 01:31:00.000000000 +0200
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,236 +0,0 @@
-/*
- * drivers/power/process.c - Functions for starting/stopping processes on 
- *                           suspend transitions.
- *
- * Originally from swsusp.
- */
-
-
-#undef DEBUG
-
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/suspend.h>
-#include <linux/module.h>
-#include <linux/syscalls.h>
-#include <linux/freezer.h>
-
-/* 
- * Timeout for stopping processes
- */
-#define TIMEOUT	(20 * HZ)
-
-#define FREEZER_KERNEL_THREADS 0
-#define FREEZER_USER_SPACE 1
-
-static inline int freezeable(struct task_struct * p)
-{
-	if ((p == current) ||
-	    (p->flags & PF_NOFREEZE) ||
-	    (p->exit_state != 0))
-		return 0;
-	return 1;
-}
-
-/*
- * freezing is complete, mark current process as frozen
- */
-static inline void frozen_process(void)
-{
-	if (!unlikely(current->flags & PF_NOFREEZE)) {
-		current->flags |= PF_FROZEN;
-		wmb();
-	}
-	clear_tsk_thread_flag(current, TIF_FREEZE);
-}
-
-/* Refrigerator is place where frozen processes are stored :-). */
-void refrigerator(void)
-{
-	/* Hmm, should we be allowed to suspend when there are realtime
-	   processes around? */
-	long save;
-
-	task_lock(current);
-	if (freezing(current)) {
-		frozen_process();
-		task_unlock(current);
-	} else {
-		task_unlock(current);
-		return;
-	}
-	save = current->state;
-	pr_debug("%s entered refrigerator\n", current->comm);
-
-	spin_lock_irq(&current->sighand->siglock);
-	recalc_sigpending(); /* We sent fake signal, clean it up */
-	spin_unlock_irq(&current->sighand->siglock);
-
-	for (;;) {
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		if (!frozen(current))
-			break;
-		schedule();
-	}
-	pr_debug("%s left refrigerator\n", current->comm);
-	current->state = save;
-}
-
-static inline void freeze_process(struct task_struct *p)
-{
-	unsigned long flags;
-
-	if (!freezing(p)) {
-		rmb();
-		if (!frozen(p)) {
-			if (p->state == TASK_STOPPED)
-				force_sig_specific(SIGSTOP, p);
-
-			freeze(p);
-			spin_lock_irqsave(&p->sighand->siglock, flags);
-			signal_wake_up(p, p->state == TASK_STOPPED);
-			spin_unlock_irqrestore(&p->sighand->siglock, flags);
-		}
-	}
-}
-
-static void cancel_freezing(struct task_struct *p)
-{
-	unsigned long flags;
-
-	if (freezing(p)) {
-		pr_debug("  clean up: %s\n", p->comm);
-		do_not_freeze(p);
-		spin_lock_irqsave(&p->sighand->siglock, flags);
-		recalc_sigpending_tsk(p);
-		spin_unlock_irqrestore(&p->sighand->siglock, flags);
-	}
-}
-
-static inline int is_user_space(struct task_struct *p)
-{
-	int ret;
-
-	task_lock(p);
-	ret = p->mm && !(p->flags & PF_BORROWED_MM);
-	task_unlock(p);
-	return ret;
-}
-
-static unsigned int try_to_freeze_tasks(int freeze_user_space)
-{
-	struct task_struct *g, *p;
-	unsigned long end_time;
-	unsigned int todo;
-
-	end_time = jiffies + TIMEOUT;
-	do {
-		todo = 0;
-		read_lock(&tasklist_lock);
-		do_each_thread(g, p) {
-			if (!freezeable(p))
-				continue;
-
-			if (frozen(p))
-				continue;
-
-			if (p->state == TASK_TRACED && frozen(p->parent)) {
-				cancel_freezing(p);
-				continue;
-			}
-			if (freeze_user_space && !is_user_space(p))
-				continue;
-
-			freeze_process(p);
-			if (!freezer_should_skip(p))
-				todo++;
-		} while_each_thread(g, p);
-		read_unlock(&tasklist_lock);
-		yield();			/* Yield is okay here */
-		if (todo && time_after(jiffies, end_time))
-			break;
-	} while (todo);
-
-	if (todo) {
-		/* This does not unfreeze processes that are already frozen
-		 * (we have slightly ugly calling convention in that respect,
-		 * and caller must call thaw_processes() if something fails),
-		 * but it cleans up leftover PF_FREEZE requests.
-		 */
-		printk("\n");
-		printk(KERN_ERR "Stopping %s timed out after %d seconds "
-				"(%d tasks refusing to freeze):\n",
-				freeze_user_space ? "user space processes" :
-					"kernel threads",
-				TIMEOUT / HZ, todo);
-		read_lock(&tasklist_lock);
-		do_each_thread(g, p) {
-			if (freeze_user_space && !is_user_space(p))
-				continue;
-
-			task_lock(p);
-			if (freezeable(p) && !frozen(p) &&
-			    !freezer_should_skip(p))
-				printk(KERN_ERR " %s\n", p->comm);
-
-			cancel_freezing(p);
-			task_unlock(p);
-		} while_each_thread(g, p);
-		read_unlock(&tasklist_lock);
-	}
-
-	return todo;
-}
-
-/**
- *	freeze_processes - tell processes to enter the refrigerator
- *
- *	Returns 0 on success, or the number of processes that didn't freeze,
- *	although they were told to.
- */
-int freeze_processes(void)
-{
-	unsigned int nr_unfrozen;
-
-	printk("Stopping tasks ... ");
-	nr_unfrozen = try_to_freeze_tasks(FREEZER_USER_SPACE);
-	if (nr_unfrozen)
-		return nr_unfrozen;
-
-	sys_sync();
-	nr_unfrozen = try_to_freeze_tasks(FREEZER_KERNEL_THREADS);
-	if (nr_unfrozen)
-		return nr_unfrozen;
-
-	printk("done.\n");
-	BUG_ON(in_atomic());
-	return 0;
-}
-
-static void thaw_tasks(int thaw_user_space)
-{
-	struct task_struct *g, *p;
-
-	read_lock(&tasklist_lock);
-	do_each_thread(g, p) {
-		if (!freezeable(p))
-			continue;
-
-		if (is_user_space(p) == !thaw_user_space)
-			continue;
-
-		thaw_process(p);
-	} while_each_thread(g, p);
-	read_unlock(&tasklist_lock);
-}
-
-void thaw_processes(void)
-{
-	printk("Restarting tasks ... ");
-	thaw_tasks(FREEZER_KERNEL_THREADS);
-	thaw_tasks(FREEZER_USER_SPACE);
-	schedule();
-	printk("done.\n");
-}
-
-EXPORT_SYMBOL(refrigerator);


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

* [PATCH -mm 2/2] Introduce freezer flags
  2007-04-27 15:37 [PATCH -mm 0/2] Separate freezer from PM code Rafael J. Wysocki
  2007-04-27 15:38 ` [PATCH -mm 1/2] " Rafael J. Wysocki
@ 2007-04-27 15:40 ` Rafael J. Wysocki
  2007-04-27 16:19   ` Sam Ravnborg
                     ` (2 more replies)
  1 sibling, 3 replies; 23+ messages in thread
From: Rafael J. Wysocki @ 2007-04-27 15:40 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Gautham R Shenoy, Ingo Molnar, Oleg Nesterov, Pavel Machek,
	Pekka Enberg, LKML

From: Rafael J. Wysocki <rjw@sisk.pl>

Move all of the freezer-related flags to a separate field in task_struct and
introduce functions to operate them using set_bit() etc.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Acked-by: Pavel Machek <pavel@ucw.cz>
---
 Documentation/power/kernel_threads.txt |    2 -
 Documentation/power/swsusp.txt         |    4 +-
 arch/i386/kernel/apm.c                 |    2 -
 drivers/block/loop.c                   |    2 -
 drivers/char/apm-emulation.c           |    6 +--
 drivers/ieee1394/ieee1394_core.c       |    2 -
 drivers/md/md.c                        |    2 -
 drivers/mmc/card/queue.c               |    3 +
 drivers/mtd/mtd_blkdevs.c              |    3 +
 drivers/scsi/libsas/sas_scsi_host.c    |    2 -
 drivers/scsi/scsi_error.c              |    2 -
 drivers/usb/storage/usb.c              |    2 -
 include/asm-arm/thread_info.h          |    2 -
 include/asm-blackfin/thread_info.h     |    2 -
 include/asm-frv/thread_info.h          |    2 -
 include/asm-i386/thread_info.h         |    2 -
 include/asm-ia64/thread_info.h         |    2 -
 include/asm-mips/thread_info.h         |    2 -
 include/asm-powerpc/thread_info.h      |    2 -
 include/asm-sh/thread_info.h           |    2 -
 include/asm-x86_64/thread_info.h       |    2 -
 include/linux/freezer.h                |   63 +++++++++++++++++++++++++++------
 include/linux/sched.h                  |    8 ++--
 kernel/fork.c                          |    5 ++
 kernel/freezer.c                       |   10 ++---
 kernel/kthread.c                       |    3 +
 kernel/rcutorture.c                    |    4 +-
 kernel/sched.c                         |    2 -
 kernel/softirq.c                       |    2 -
 kernel/softlockup.c                    |    2 -
 kernel/workqueue.c                     |    2 -
 31 files changed, 90 insertions(+), 61 deletions(-)

Index: linux-2.6.21-rc7-mm2/include/linux/sched.h
===================================================================
--- linux-2.6.21-rc7-mm2.orig/include/linux/sched.h
+++ linux-2.6.21-rc7-mm2/include/linux/sched.h
@@ -1006,7 +1006,10 @@ struct task_struct {
 	/* Deadlock detection and priority inheritance handling */
 	struct rt_mutex_waiter *pi_blocked_on;
 #endif
-
+#ifdef CONFIG_FREEZER
+	/* Used by the process freezer, defined in freezer.h */
+	unsigned int freezer_flags;
+#endif
 #ifdef CONFIG_DEBUG_MUTEXES
 	/* mutex deadlock detection */
 	struct mutex_waiter *blocked_on;
@@ -1189,8 +1192,6 @@ static inline void put_task_struct(struc
 #define PF_MEMALLOC	0x00000800	/* Allocating memory */
 #define PF_FLUSHER	0x00001000	/* responsible for disk writeback */
 #define PF_USED_MATH	0x00002000	/* if unset the fpu must be initialized before use */
-#define PF_NOFREEZE	0x00008000	/* this thread should not be frozen */
-#define PF_FROZEN	0x00010000	/* frozen for system suspend */
 #define PF_FSTRANS	0x00020000	/* inside a filesystem transaction */
 #define PF_KSWAPD	0x00040000	/* I am kswapd */
 #define PF_SWAPOFF	0x00080000	/* I am in swapoff */
@@ -1202,7 +1203,6 @@ static inline void put_task_struct(struc
 #define PF_SPREAD_SLAB	0x02000000	/* Spread some slab caches over cpuset */
 #define PF_MEMPOLICY	0x10000000	/* Non-default NUMA mempolicy */
 #define PF_MUTEX_TESTER	0x20000000	/* Thread belongs to the rt mutex tester */
-#define PF_FREEZER_SKIP	0x40000000	/* Freezer should not count it as freezeable */
 
 /*
  * Only the _current_ task can read/write to tsk->flags, but other
Index: linux-2.6.21-rc7-mm2/include/asm-arm/thread_info.h
===================================================================
--- linux-2.6.21-rc7-mm2.orig/include/asm-arm/thread_info.h
+++ linux-2.6.21-rc7-mm2/include/asm-arm/thread_info.h
@@ -147,7 +147,6 @@ extern void iwmmxt_task_switch(struct th
 #define TIF_POLLING_NRFLAG	16
 #define TIF_USING_IWMMXT	17
 #define TIF_MEMDIE		18
-#define TIF_FREEZE		19
 
 #define _TIF_NOTIFY_RESUME	(1 << TIF_NOTIFY_RESUME)
 #define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
@@ -155,7 +154,6 @@ extern void iwmmxt_task_switch(struct th
 #define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
 #define _TIF_POLLING_NRFLAG	(1 << TIF_POLLING_NRFLAG)
 #define _TIF_USING_IWMMXT	(1 << TIF_USING_IWMMXT)
-#define _TIF_FREEZE		(1 << TIF_FREEZE)
 
 /*
  * Change these and you break ASM code in entry-common.S
Index: linux-2.6.21-rc7-mm2/include/asm-blackfin/thread_info.h
===================================================================
--- linux-2.6.21-rc7-mm2.orig/include/asm-blackfin/thread_info.h
+++ linux-2.6.21-rc7-mm2/include/asm-blackfin/thread_info.h
@@ -125,7 +125,6 @@ static inline struct thread_info *curren
 					   TIF_NEED_RESCHED */
 #define TIF_MEMDIE              5
 #define TIF_RESTORE_SIGMASK	6	/* restore signal mask in do_signal() */
-#define TIF_FREEZE              7       /* is freezing for suspend */
 
 /* as above, but as bit values */
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
@@ -134,7 +133,6 @@ static inline struct thread_info *curren
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
 #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 #define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
-#define _TIF_FREEZE             (1<<TIF_FREEZE)
 
 #define _TIF_WORK_MASK		0x0000FFFE	/* work to do on interrupt/exception return */
 
Index: linux-2.6.21-rc7-mm2/include/asm-frv/thread_info.h
===================================================================
--- linux-2.6.21-rc7-mm2.orig/include/asm-frv/thread_info.h
+++ linux-2.6.21-rc7-mm2/include/asm-frv/thread_info.h
@@ -116,7 +116,6 @@ register struct thread_info *__current_t
 #define TIF_RESTORE_SIGMASK	6	/* restore signal mask in do_signal() */
 #define TIF_POLLING_NRFLAG	16	/* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_MEMDIE		17	/* OOM killer killed process */
-#define TIF_FREEZE		18	/* freezing for suspend */
 
 #define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
 #define _TIF_NOTIFY_RESUME	(1 << TIF_NOTIFY_RESUME)
@@ -126,7 +125,6 @@ register struct thread_info *__current_t
 #define _TIF_IRET		(1 << TIF_IRET)
 #define _TIF_RESTORE_SIGMASK	(1 << TIF_RESTORE_SIGMASK)
 #define _TIF_POLLING_NRFLAG	(1 << TIF_POLLING_NRFLAG)
-#define _TIF_FREEZE		(1 << TIF_FREEZE)
 
 #define _TIF_WORK_MASK		0x0000FFFE	/* work to do on interrupt/exception return */
 #define _TIF_ALLWORK_MASK	0x0000FFFF	/* work to do on any return to u-space */
Index: linux-2.6.21-rc7-mm2/include/asm-i386/thread_info.h
===================================================================
--- linux-2.6.21-rc7-mm2.orig/include/asm-i386/thread_info.h
+++ linux-2.6.21-rc7-mm2/include/asm-i386/thread_info.h
@@ -136,7 +136,6 @@ static inline struct thread_info *curren
 #define TIF_MEMDIE		16
 #define TIF_DEBUG		17	/* uses debug registers */
 #define TIF_IO_BITMAP		18	/* uses I/O bitmap */
-#define TIF_FREEZE		19	/* is freezing for suspend */
 
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
 #define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
@@ -150,7 +149,6 @@ static inline struct thread_info *curren
 #define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
 #define _TIF_DEBUG		(1<<TIF_DEBUG)
 #define _TIF_IO_BITMAP		(1<<TIF_IO_BITMAP)
-#define _TIF_FREEZE		(1<<TIF_FREEZE)
 
 /* work to do on interrupt/exception return */
 #define _TIF_WORK_MASK \
Index: linux-2.6.21-rc7-mm2/include/asm-ia64/thread_info.h
===================================================================
--- linux-2.6.21-rc7-mm2.orig/include/asm-ia64/thread_info.h
+++ linux-2.6.21-rc7-mm2/include/asm-ia64/thread_info.h
@@ -89,7 +89,6 @@ struct thread_info {
 #define TIF_MEMDIE		17
 #define TIF_MCA_INIT		18	/* this task is processing MCA or INIT */
 #define TIF_DB_DISABLED		19	/* debug trap disabled for fsyscall */
-#define TIF_FREEZE		20	/* is freezing for suspend */
 
 #define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
 #define _TIF_SYSCALL_AUDIT	(1 << TIF_SYSCALL_AUDIT)
@@ -101,7 +100,6 @@ struct thread_info {
 #define _TIF_POLLING_NRFLAG	(1 << TIF_POLLING_NRFLAG)
 #define _TIF_MCA_INIT		(1 << TIF_MCA_INIT)
 #define _TIF_DB_DISABLED	(1 << TIF_DB_DISABLED)
-#define _TIF_FREEZE		(1 << TIF_FREEZE)
 
 /* "work to do on user-return" bits */
 #define TIF_ALLWORK_MASK	(_TIF_NOTIFY_RESUME|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
Index: linux-2.6.21-rc7-mm2/include/asm-mips/thread_info.h
===================================================================
--- linux-2.6.21-rc7-mm2.orig/include/asm-mips/thread_info.h
+++ linux-2.6.21-rc7-mm2/include/asm-mips/thread_info.h
@@ -118,7 +118,6 @@ register struct thread_info *__current_t
 #define TIF_USEDFPU		16	/* FPU was used by this task this quantum (SMP) */
 #define TIF_POLLING_NRFLAG	17	/* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_MEMDIE		18
-#define TIF_FREEZE		19
 #define TIF_SYSCALL_TRACE	31	/* syscall trace active */
 
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
@@ -130,7 +129,6 @@ register struct thread_info *__current_t
 #define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
 #define _TIF_USEDFPU		(1<<TIF_USEDFPU)
 #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
-#define _TIF_FREEZE		(1<<TIF_FREEZE)
 
 /* work to do on interrupt/exception return */
 #define _TIF_WORK_MASK		(0x0000ffef & ~_TIF_SECCOMP)
Index: linux-2.6.21-rc7-mm2/include/asm-powerpc/thread_info.h
===================================================================
--- linux-2.6.21-rc7-mm2.orig/include/asm-powerpc/thread_info.h
+++ linux-2.6.21-rc7-mm2/include/asm-powerpc/thread_info.h
@@ -122,7 +122,6 @@ static inline struct thread_info *curren
 #define TIF_RESTOREALL		12	/* Restore all regs (implies NOERROR) */
 #define TIF_NOERROR		14	/* Force successful syscall return */
 #define TIF_RESTORE_SIGMASK	15	/* Restore signal mask in do_signal */
-#define TIF_FREEZE		16	/* Freezing for suspend */
 
 /* as above, but as bit values */
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
@@ -139,7 +138,6 @@ static inline struct thread_info *curren
 #define _TIF_RESTOREALL		(1<<TIF_RESTOREALL)
 #define _TIF_NOERROR		(1<<TIF_NOERROR)
 #define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
-#define _TIF_FREEZE		(1<<TIF_FREEZE)
 #define _TIF_SYSCALL_T_OR_A	(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP)
 
 #define _TIF_USER_WORK_MASK	(_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | \
Index: linux-2.6.21-rc7-mm2/include/asm-sh/thread_info.h
===================================================================
--- linux-2.6.21-rc7-mm2.orig/include/asm-sh/thread_info.h
+++ linux-2.6.21-rc7-mm2/include/asm-sh/thread_info.h
@@ -115,7 +115,6 @@ static inline struct thread_info *curren
 #define TIF_USEDFPU		16	/* FPU was used by this task this quantum (SMP) */
 #define TIF_POLLING_NRFLAG	17	/* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_MEMDIE		18
-#define TIF_FREEZE		19
 
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
 #define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
@@ -125,7 +124,6 @@ static inline struct thread_info *curren
 #define _TIF_SINGLESTEP		(1<<TIF_SINGLESTEP)
 #define _TIF_USEDFPU		(1<<TIF_USEDFPU)
 #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
-#define _TIF_FREEZE		(1<<TIF_FREEZE)
 
 #define _TIF_WORK_MASK		0x000000FE	/* work to do on interrupt/exception return */
 #define _TIF_ALLWORK_MASK	0x000000FF	/* work to do on any return to u-space */
Index: linux-2.6.21-rc7-mm2/include/asm-x86_64/thread_info.h
===================================================================
--- linux-2.6.21-rc7-mm2.orig/include/asm-x86_64/thread_info.h
+++ linux-2.6.21-rc7-mm2/include/asm-x86_64/thread_info.h
@@ -122,7 +122,6 @@ static inline struct thread_info *stack_
 #define TIF_MEMDIE		20
 #define TIF_DEBUG		21	/* uses debug registers */
 #define TIF_IO_BITMAP		22	/* uses I/O bitmap */
-#define TIF_FREEZE		23	/* is freezing for suspend */
 
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
 #define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
@@ -138,7 +137,6 @@ static inline struct thread_info *stack_
 #define _TIF_ABI_PENDING	(1<<TIF_ABI_PENDING)
 #define _TIF_DEBUG		(1<<TIF_DEBUG)
 #define _TIF_IO_BITMAP		(1<<TIF_IO_BITMAP)
-#define _TIF_FREEZE		(1<<TIF_FREEZE)
 
 /* work to do on interrupt/exception return */
 #define _TIF_WORK_MASK \
Index: linux-2.6.21-rc7-mm2/include/linux/freezer.h
===================================================================
--- linux-2.6.21-rc7-mm2.orig/include/linux/freezer.h
+++ linux-2.6.21-rc7-mm2/include/linux/freezer.h
@@ -3,12 +3,33 @@
 #include <linux/sched.h>
 
 #ifdef CONFIG_FREEZER
+
+/*
+ *	Per task flags used by the freezer
+ *
+ *	They should not be referred to directly outside of this file.
+ */
+#define TFF_NOFREEZE	0	/* task should not be frozen */
+#define TFF_FREEZE	8	/* task should go to the refrigerator ASAP */
+#define TFF_SKIP	9	/* do not count this task as freezable */
+#define TFF_FROZEN	10	/* task is frozen */
+
 /*
  * Check if a process has been frozen
  */
 static inline int frozen(struct task_struct *p)
 {
-	return p->flags & PF_FROZEN;
+	return test_bit(TFF_FROZEN, &p->freezer_flags);
+}
+
+static inline void set_frozen_flag(struct task_struct *p)
+{
+	set_bit(TFF_FROZEN, &p->freezer_flags);
+}
+
+static inline void clear_frozen_flag(struct task_struct *p)
+{
+	clear_bit(TFF_FROZEN, &p->freezer_flags);
 }
 
 /*
@@ -16,7 +37,7 @@ static inline int frozen(struct task_str
  */
 static inline int freezing(struct task_struct *p)
 {
-	return test_tsk_thread_flag(p, TIF_FREEZE);
+	return test_bit(TFF_FREEZE, &p->freezer_flags);
 }
 
 /*
@@ -24,15 +45,31 @@ static inline int freezing(struct task_s
  */
 static inline void freeze(struct task_struct *p)
 {
-	set_tsk_thread_flag(p, TIF_FREEZE);
+	set_bit(TFF_FREEZE, &p->freezer_flags);
+}
+
+/*
+ * Cancel the previous 'freeze' request
+ */
+static inline void clear_freeze_flag(struct task_struct *p)
+{
+	clear_bit(TFF_FREEZE, &p->freezer_flags);
+}
+
+/*
+ * Check if the task wants to be exempted from freezing
+ */
+static inline int freezer_should_exempt(struct task_struct *p)
+{
+	return test_bit(TFF_NOFREEZE, &p->freezer_flags);
 }
 
 /*
- * Sometimes we may need to cancel the previous 'freeze' request
+ * Tell the freezer to exempt this task from freezing
  */
-static inline void do_not_freeze(struct task_struct *p)
+static inline void freezer_exempt(struct task_struct *p)
 {
-	clear_tsk_thread_flag(p, TIF_FREEZE);
+	set_bit(TFF_NOFREEZE, &p->freezer_flags);
 }
 
 /*
@@ -48,12 +85,12 @@ static inline int thaw_process(struct ta
 {
 	task_lock(p);
 	if (frozen(p)) {
-		p->flags &= ~PF_FROZEN;
+		clear_frozen_flag(p);
 		task_unlock(p);
 		wake_up_process(p);
 		return 1;
 	}
-	clear_tsk_thread_flag(p, TIF_FREEZE);
+	clear_freeze_flag(p);
 	task_unlock(p);
 	return 0;
 }
@@ -92,7 +129,7 @@ static inline int try_to_freeze(void)
 static inline void freezer_do_not_count(void)
 {
 	if (current->mm)
-		current->flags |= PF_FREEZER_SKIP;
+		set_bit(TFF_SKIP, &current->freezer_flags);
 }
 
 /*
@@ -102,7 +139,7 @@ static inline void freezer_do_not_count(
 static inline void freezer_count(void)
 {
 	if (current->mm) {
-		current->flags &= ~PF_FREEZER_SKIP;
+		clear_bit(TFF_SKIP, &current->freezer_flags);
 		try_to_freeze();
 	}
 }
@@ -112,13 +149,17 @@ static inline void freezer_count(void)
  */
 static inline int freezer_should_skip(struct task_struct *p)
 {
-	return !!(p->flags & PF_FREEZER_SKIP);
+	return test_bit(TFF_SKIP, &current->freezer_flags);
 }
 
 #else
 static inline int frozen(struct task_struct *p) { return 0; }
+static inline void set_frozen_flag(struct task_struct *p) {}
+static inline void clear_frozen_flag(struct task_struct *p) {}
 static inline int freezing(struct task_struct *p) { return 0; }
 static inline void freeze(struct task_struct *p) { BUG(); }
+static inline int freezer_should_exempt(struct task_struct *p) { return 0; }
+static inline void freezer_exempt(struct task_struct *p) {}
 static inline int thaw_process(struct task_struct *p) { return 1; }
 
 static inline void refrigerator(void) {}
Index: linux-2.6.21-rc7-mm2/kernel/sched.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/kernel/sched.c
+++ linux-2.6.21-rc7-mm2/kernel/sched.c
@@ -5478,7 +5478,7 @@ migration_call(struct notifier_block *nf
 		p = kthread_create(migration_thread, hcpu, "migration/%d",cpu);
 		if (IS_ERR(p))
 			return NOTIFY_BAD;
-		p->flags |= PF_NOFREEZE;
+		freezer_exempt(p);
 		kthread_bind(p, cpu);
 		/* Must be high prio: stop_machine expects to yield to it. */
 		rq = task_rq_lock(p, &flags);
Index: linux-2.6.21-rc7-mm2/arch/i386/kernel/apm.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/i386/kernel/apm.c
+++ linux-2.6.21-rc7-mm2/arch/i386/kernel/apm.c
@@ -2313,7 +2313,7 @@ static int __init apm_init(void)
 		remove_proc_entry("apm", NULL);
 		return err;
 	}
-	kapmd_task->flags |= PF_NOFREEZE;
+	freezer_exempt(kapmd_task);
 	wake_up_process(kapmd_task);
 
 	if (num_online_cpus() > 1 && !smp ) {
Index: linux-2.6.21-rc7-mm2/drivers/block/loop.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/drivers/block/loop.c
+++ linux-2.6.21-rc7-mm2/drivers/block/loop.c
@@ -582,7 +582,7 @@ static int loop_thread(void *data)
 	 * hence, it mustn't be stopped at all
 	 * because it could be indirectly used during suspension
 	 */
-	current->flags |= PF_NOFREEZE;
+	freezer_exempt(current);
 
 	set_user_nice(current, -20);
 
Index: linux-2.6.21-rc7-mm2/drivers/char/apm-emulation.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/drivers/char/apm-emulation.c
+++ linux-2.6.21-rc7-mm2/drivers/char/apm-emulation.c
@@ -336,7 +336,7 @@ apm_ioctl(struct inode * inode, struct f
 			 * threads.
 			 */
 			flags = current->flags;
-			current->flags |= PF_NOFREEZE;
+			freezer_exempt(current);
 
 			wait_event(apm_suspend_waitqueue,
 				   as->suspend_state == SUSPEND_DONE);
@@ -372,7 +372,7 @@ apm_ioctl(struct inode * inode, struct f
 			 * threads.
 			 */
 			flags = current->flags;
-			current->flags |= PF_NOFREEZE;
+			freezer_exempt(current);
 
 			wait_event_interruptible(apm_suspend_waitqueue,
 					 as->suspend_state == SUSPEND_DONE);
@@ -601,7 +601,7 @@ static int __init apm_init(void)
 		kapmd_tsk = NULL;
 		return ret;
 	}
-	kapmd_tsk->flags |= PF_NOFREEZE;
+	freezer_exempt(kapmd_tsk);
 	wake_up_process(kapmd_tsk);
 
 #ifdef CONFIG_PROC_FS
Index: linux-2.6.21-rc7-mm2/drivers/ieee1394/ieee1394_core.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/drivers/ieee1394/ieee1394_core.c
+++ linux-2.6.21-rc7-mm2/drivers/ieee1394/ieee1394_core.c
@@ -1134,7 +1134,7 @@ static int hpsbpkt_thread(void *__hi)
 	struct list_head tmp;
 	int may_schedule;
 
-	current->flags |= PF_NOFREEZE;
+	freezer_exempt(current);
 
 	while (!kthread_should_stop()) {
 
Index: linux-2.6.21-rc7-mm2/drivers/md/md.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/drivers/md/md.c
+++ linux-2.6.21-rc7-mm2/drivers/md/md.c
@@ -4541,7 +4541,7 @@ static int md_thread(void * arg)
 	 * many dirty RAID5 blocks.
 	 */
 
-	current->flags |= PF_NOFREEZE;
+	freezer_exempt(current);
 	while (!kthread_should_stop()) {
 
 		/* We need to wait INTERRUPTIBLE so that
Index: linux-2.6.21-rc7-mm2/drivers/mmc/card/queue.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/drivers/mmc/card/queue.c
+++ linux-2.6.21-rc7-mm2/drivers/mmc/card/queue.c
@@ -66,7 +66,8 @@ static int mmc_queue_thread(void *d)
 	 * Set iothread to ensure that we aren't put to sleep by
 	 * the process freezing.  We handle suspension ourselves.
 	 */
-	current->flags |= PF_MEMALLOC|PF_NOFREEZE;
+	current->flags |= PF_MEMALLOC;
+	freezer_exempt(current);
 
 	down(&mq->thread_sem);
 	do {
Index: linux-2.6.21-rc7-mm2/drivers/mtd/mtd_blkdevs.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/drivers/mtd/mtd_blkdevs.c
+++ linux-2.6.21-rc7-mm2/drivers/mtd/mtd_blkdevs.c
@@ -81,7 +81,8 @@ static int mtd_blktrans_thread(void *arg
 	struct request_queue *rq = tr->blkcore_priv->rq;
 
 	/* we might get involved when memory gets low, so use PF_MEMALLOC */
-	current->flags |= PF_MEMALLOC | PF_NOFREEZE;
+	current->flags |= PF_MEMALLOC;
+	freezer_exempt(current);
 
 	spin_lock_irq(rq->queue_lock);
 	while (!kthread_should_stop()) {
Index: linux-2.6.21-rc7-mm2/drivers/scsi/libsas/sas_scsi_host.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/drivers/scsi/libsas/sas_scsi_host.c
+++ linux-2.6.21-rc7-mm2/drivers/scsi/libsas/sas_scsi_host.c
@@ -871,7 +871,7 @@ static int sas_queue_thread(void *_sas_h
 	struct sas_ha_struct *sas_ha = _sas_ha;
 	struct scsi_core *core = &sas_ha->core;
 
-	current->flags |= PF_NOFREEZE;
+	freezer_exempt(current);
 
 	complete(&queue_th_comp);
 
Index: linux-2.6.21-rc7-mm2/drivers/scsi/scsi_error.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/drivers/scsi/scsi_error.c
+++ linux-2.6.21-rc7-mm2/drivers/scsi/scsi_error.c
@@ -1536,7 +1536,7 @@ int scsi_error_handler(void *data)
 {
 	struct Scsi_Host *shost = data;
 
-	current->flags |= PF_NOFREEZE;
+	freezer_exempt(current);
 
 	/*
 	 * We use TASK_INTERRUPTIBLE so that the thread is not
Index: linux-2.6.21-rc7-mm2/drivers/usb/storage/usb.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/drivers/usb/storage/usb.c
+++ linux-2.6.21-rc7-mm2/drivers/usb/storage/usb.c
@@ -301,7 +301,7 @@ static int usb_stor_control_thread(void 
 	struct us_data *us = (struct us_data *)__us;
 	struct Scsi_Host *host = us_to_host(us);
 
-	current->flags |= PF_NOFREEZE;
+	freezer_exempt(current);
 
 	for(;;) {
 		try_to_freeze();
Index: linux-2.6.21-rc7-mm2/kernel/fork.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/kernel/fork.c
+++ linux-2.6.21-rc7-mm2/kernel/fork.c
@@ -921,11 +921,14 @@ static inline void copy_flags(unsigned l
 {
 	unsigned long new_flags = p->flags;
 
-	new_flags &= ~(PF_SUPERPRIV | PF_NOFREEZE);
+	new_flags &= ~PF_SUPERPRIV;
 	new_flags |= PF_FORKNOEXEC;
 	if (!(clone_flags & CLONE_PTRACE))
 		p->ptrace = 0;
 	p->flags = new_flags;
+#ifdef CONFIG_FREEZER
+	p->freezer_flags = 0;
+#endif
 }
 
 asmlinkage long sys_set_tid_address(int __user *tidptr)
Index: linux-2.6.21-rc7-mm2/kernel/rcutorture.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/kernel/rcutorture.c
+++ linux-2.6.21-rc7-mm2/kernel/rcutorture.c
@@ -559,7 +559,7 @@ rcu_torture_fakewriter(void *arg)
 
 	VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task started");
 	set_user_nice(current, 19);
-	current->flags |= PF_NOFREEZE;
+	freezer_exempt(current);
 
 	do {
 		schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10);
@@ -590,7 +590,7 @@ rcu_torture_reader(void *arg)
 
 	VERBOSE_PRINTK_STRING("rcu_torture_reader task started");
 	set_user_nice(current, 19);
-	current->flags |= PF_NOFREEZE;
+	freezer_exempt(current);
 
 	do {
 		idx = cur_ops->readlock();
Index: linux-2.6.21-rc7-mm2/kernel/softirq.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/kernel/softirq.c
+++ linux-2.6.21-rc7-mm2/kernel/softirq.c
@@ -490,7 +490,7 @@ void __init softirq_init(void)
 static int ksoftirqd(void * __bind_cpu)
 {
 	set_user_nice(current, 15);
-	current->flags |= PF_NOFREEZE;
+	freezer_exempt(current);
 
 	set_current_state(TASK_INTERRUPTIBLE);
 
Index: linux-2.6.21-rc7-mm2/kernel/softlockup.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/kernel/softlockup.c
+++ linux-2.6.21-rc7-mm2/kernel/softlockup.c
@@ -117,7 +117,7 @@ static int watchdog(void * __bind_cpu)
 	struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
 
 	sched_setscheduler(current, SCHED_FIFO, &param);
-	current->flags |= PF_NOFREEZE;
+	freezer_exempt(current);
 
 	/* initialize timestamp */
 	touch_softlockup_watchdog();
Index: linux-2.6.21-rc7-mm2/kernel/workqueue.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/kernel/workqueue.c
+++ linux-2.6.21-rc7-mm2/kernel/workqueue.c
@@ -291,7 +291,7 @@ static int worker_thread(void *__cwq)
 	DEFINE_WAIT(wait);
 
 	if (!cwq->wq->freezeable)
-		current->flags |= PF_NOFREEZE;
+		freezer_exempt(current);
 
 	for (;;) {
 		prepare_to_wait(&cwq->more_work, &wait, TASK_INTERRUPTIBLE);
Index: linux-2.6.21-rc7-mm2/kernel/freezer.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/kernel/freezer.c
+++ linux-2.6.21-rc7-mm2/kernel/freezer.c
@@ -26,7 +26,7 @@
 static inline int freezeable(struct task_struct * p)
 {
 	if ((p == current) ||
-	    (p->flags & PF_NOFREEZE) ||
+	    freezer_should_exempt(p) ||
 	    (p->exit_state != 0))
 		return 0;
 	return 1;
@@ -37,11 +37,11 @@ static inline int freezeable(struct task
  */
 static inline void frozen_process(void)
 {
-	if (!unlikely(current->flags & PF_NOFREEZE)) {
-		current->flags |= PF_FROZEN;
+	if (!unlikely(freezer_should_exempt(current))) {
+		set_frozen_flag(current);
 		wmb();
 	}
-	clear_tsk_thread_flag(current, TIF_FREEZE);
+	clear_freeze_flag(current);
 }
 
 /* Refrigerator is place where frozen processes are stored :-). */
@@ -100,7 +100,7 @@ static void cancel_freezing(struct task_
 
 	if (freezing(p)) {
 		pr_debug("  clean up: %s\n", p->comm);
-		do_not_freeze(p);
+		clear_freeze_flag(p);
 		spin_lock_irqsave(&p->sighand->siglock, flags);
 		recalc_sigpending_tsk(p);
 		spin_unlock_irqrestore(&p->sighand->siglock, flags);
Index: linux-2.6.21-rc7-mm2/Documentation/power/kernel_threads.txt
===================================================================
--- linux-2.6.21-rc7-mm2.orig/Documentation/power/kernel_threads.txt
+++ linux-2.6.21-rc7-mm2/Documentation/power/kernel_threads.txt
@@ -32,7 +32,7 @@ like this:
 	 */
 	daemonize("usb-storage");
 
-	current->flags |= PF_NOFREEZE;
+	freezer_exempt(current);
 
 from drivers/usb/storage/usb.c::usb_stor_control_thread()
 
Index: linux-2.6.21-rc7-mm2/Documentation/power/swsusp.txt
===================================================================
--- linux-2.6.21-rc7-mm2.orig/Documentation/power/swsusp.txt
+++ linux-2.6.21-rc7-mm2/Documentation/power/swsusp.txt
@@ -152,8 +152,8 @@ add:
        try_to_freeze();
 
 If the thread is needed for writing the image to storage, you should
-instead set the PF_NOFREEZE process flag when creating the thread (and
-be very careful).
+instead use freezer_exempt() to mark the thread as nonfreezable when creating
+it (and be very careful).
 
 
 Q: What is the difference between "platform" and "shutdown"?
Index: linux-2.6.21-rc7-mm2/kernel/kthread.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/kernel/kthread.c
+++ linux-2.6.21-rc7-mm2/kernel/kthread.c
@@ -13,6 +13,7 @@
 #include <linux/file.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/freezer.h>
 #include <asm/semaphore.h>
 
 static DEFINE_SPINLOCK(kthread_create_lock);
@@ -232,7 +233,7 @@ int kthreadd(void *unused)
 	/* Setup a clean context for our children to inherit. */
 	kthreadd_setup();
 
-	current->flags |= PF_NOFREEZE;
+	freezer_exempt(current);
 
 	for (;;) {
 		set_current_state(TASK_INTERRUPTIBLE);

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

* Re: [PATCH -mm 1/2] Separate freezer from PM code
  2007-04-27 15:38 ` [PATCH -mm 1/2] " Rafael J. Wysocki
@ 2007-04-27 16:15   ` Sam Ravnborg
  2007-04-27 16:25   ` Jeremy Fitzhardinge
  1 sibling, 0 replies; 23+ messages in thread
From: Sam Ravnborg @ 2007-04-27 16:15 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Andrew Morton, Gautham R Shenoy, Ingo Molnar, Oleg Nesterov,
	Pavel Machek, Pekka Enberg, LKML

On Fri, Apr 27, 2007 at 05:38:47PM +0200, Rafael J. Wysocki wrote:
> 
> Index: linux-2.6.21-rc7-mm2/arch/x86_64/Kconfig
> ===================================================================
> --- linux-2.6.21-rc7-mm2.orig/arch/x86_64/Kconfig	2007-04-27 01:22:33.000000000 +0200
> +++ linux-2.6.21-rc7-mm2/arch/x86_64/Kconfig	2007-04-27 01:33:22.000000000 +0200
> @@ -703,6 +703,14 @@ config GENERIC_PENDING_IRQ
>  	depends on GENERIC_HARDIRQS && SMP
>  	default y
>  
> +#
> +# Use the tasks freezer
> +#
> +config FREEZER
> +	bool
> +	default y
> +	depends on PM || KPROBES
> +
>  menu "Power management options"

Could we have this in a generic Kconfig file instead?
IIRC the depends on line may refer to unknown options
without spitting out warnings.

	Sam

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

* Re: [PATCH -mm 2/2] Introduce freezer flags
  2007-04-27 15:40 ` [PATCH -mm 2/2] Introduce freezer flags Rafael J. Wysocki
@ 2007-04-27 16:19   ` Sam Ravnborg
  2007-04-27 16:33     ` Gautham R Shenoy
  2007-04-27 21:40   ` Gautham R Shenoy
  2007-04-28  1:34   ` [PATCH -mm] Allow selective freezing of the system for different events Gautham R Shenoy
  2 siblings, 1 reply; 23+ messages in thread
From: Sam Ravnborg @ 2007-04-27 16:19 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Andrew Morton, Gautham R Shenoy, Ingo Molnar, Oleg Nesterov,
	Pavel Machek, Pekka Enberg, LKML

On Fri, Apr 27, 2007 at 05:40:16PM +0200, Rafael J. Wysocki wrote:

> --- linux-2.6.21-rc7-mm2.orig/kernel/fork.c
> +++ linux-2.6.21-rc7-mm2/kernel/fork.c
> @@ -921,11 +921,14 @@ static inline void copy_flags(unsigned l
>  {
>  	unsigned long new_flags = p->flags;
>  
> -	new_flags &= ~(PF_SUPERPRIV | PF_NOFREEZE);
> +	new_flags &= ~PF_SUPERPRIV;
>  	new_flags |= PF_FORKNOEXEC;
>  	if (!(clone_flags & CLONE_PTRACE))
>  		p->ptrace = 0;
>  	p->flags = new_flags;
> +#ifdef CONFIG_FREEZER
> +	p->freezer_flags = 0;
> +#endif
>  }
Could we have a dedicated clear_freeze_flag() so we could drop the ifdef?

> +		clear_freeze_flag(p);

Or maybe we have it already?


	Sam

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

* Re: [PATCH -mm 1/2] Separate freezer from PM code
  2007-04-27 15:38 ` [PATCH -mm 1/2] " Rafael J. Wysocki
  2007-04-27 16:15   ` Sam Ravnborg
@ 2007-04-27 16:25   ` Jeremy Fitzhardinge
  2007-04-27 20:20     ` Rafael J. Wysocki
  1 sibling, 1 reply; 23+ messages in thread
From: Jeremy Fitzhardinge @ 2007-04-27 16:25 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Andrew Morton, Gautham R Shenoy, Ingo Molnar, Oleg Nesterov,
	Pavel Machek, Pekka Enberg, LKML

Rafael J. Wysocki wrote:
> --- linux-2.6.21-rc7-mm2.orig/arch/x86_64/Kconfig	2007-04-27 01:22:33.000000000 +0200
> +++ linux-2.6.21-rc7-mm2/arch/x86_64/Kconfig	2007-04-27 01:33:22.000000000 +0200
> @@ -703,6 +703,14 @@ config GENERIC_PENDING_IRQ
>  	depends on GENERIC_HARDIRQS && SMP
>  	default y
>  
> +#
> +# Use the tasks freezer
> +#
> +config FREEZER
> +	bool
> +	default y
> +	depends on PM || KPROBES
> +
>   

Shouldn't PM and KPROBES "select" FREEZER if they want it?  That way its
easier for other future users of FREEZER to do so without having to
change the Kconfig here (and the other 23000 Kconfigs).

    J

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

* Re: [PATCH -mm 2/2] Introduce freezer flags
  2007-04-27 16:19   ` Sam Ravnborg
@ 2007-04-27 16:33     ` Gautham R Shenoy
  0 siblings, 0 replies; 23+ messages in thread
From: Gautham R Shenoy @ 2007-04-27 16:33 UTC (permalink / raw)
  To: Sam Ravnborg
  Cc: Rafael J. Wysocki, Andrew Morton, Ingo Molnar, Oleg Nesterov,
	Pavel Machek, Pekka Enberg, LKML

On Fri, Apr 27, 2007 at 06:19:40PM +0200, Sam Ravnborg wrote:
> On Fri, Apr 27, 2007 at 05:40:16PM +0200, Rafael J. Wysocki wrote:
> 
> > --- linux-2.6.21-rc7-mm2.orig/kernel/fork.c
> > +++ linux-2.6.21-rc7-mm2/kernel/fork.c
> > @@ -921,11 +921,14 @@ static inline void copy_flags(unsigned l
> >  {
> >  	unsigned long new_flags = p->flags;
> >  
> > -	new_flags &= ~(PF_SUPERPRIV | PF_NOFREEZE);
> > +	new_flags &= ~PF_SUPERPRIV;
> >  	new_flags |= PF_FORKNOEXEC;
> >  	if (!(clone_flags & CLONE_PTRACE))
> >  		p->ptrace = 0;
> >  	p->flags = new_flags;
> > +#ifdef CONFIG_FREEZER
> > +	p->freezer_flags = 0;
> > +#endif
> >  }
> Could we have a dedicated clear_freeze_flag() so we could drop the ifdef?
> 
> > +		clear_freeze_flag(p);

That means something else. clear_freeze_flag() just clears the 
TFF_FREEZE flag and not necessarily everything.

Besides, this is the only place where we would need to clear all the bits
of p->freezer_flags. Not sure if having a static inline helper function 
is worth it.

> 
> Or maybe we have it already?

We don't yet. But can if badly needed :-)
> 
> 
> 	Sam

Thanks and Regards
gautham.
-- 
Gautham R Shenoy
Linux Technology Center
IBM India.
"Freedom comes with a price tag of responsibility, which is still a bargain,
because Freedom is priceless!"

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

* Re: [PATCH -mm 1/2] Separate freezer from PM code
  2007-04-27 20:20     ` Rafael J. Wysocki
@ 2007-04-27 20:20       ` Jeremy Fitzhardinge
  2007-04-27 21:29         ` Rafael J. Wysocki
  0 siblings, 1 reply; 23+ messages in thread
From: Jeremy Fitzhardinge @ 2007-04-27 20:20 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Andrew Morton, Gautham R Shenoy, Ingo Molnar, Oleg Nesterov,
	Pavel Machek, Pekka Enberg, LKML

Rafael J. Wysocki wrote:
> Makes sense.  Please have a look at the updated patch below.
>
> Sam, does this one look better to you?
>   

If freezer.c is in kernel/, then shouldn't the corresponding config var
be in a non-arch Kconfig file?

    J

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

* Re: [PATCH -mm 1/2] Separate freezer from PM code
  2007-04-27 16:25   ` Jeremy Fitzhardinge
@ 2007-04-27 20:20     ` Rafael J. Wysocki
  2007-04-27 20:20       ` Jeremy Fitzhardinge
  0 siblings, 1 reply; 23+ messages in thread
From: Rafael J. Wysocki @ 2007-04-27 20:20 UTC (permalink / raw)
  To: Jeremy Fitzhardinge
  Cc: Andrew Morton, Gautham R Shenoy, Ingo Molnar, Oleg Nesterov,
	Pavel Machek, Pekka Enberg, LKML

On Friday, 27 April 2007 18:25, Jeremy Fitzhardinge wrote:
> Rafael J. Wysocki wrote:
> > --- linux-2.6.21-rc7-mm2.orig/arch/x86_64/Kconfig	2007-04-27 01:22:33.000000000 +0200
> > +++ linux-2.6.21-rc7-mm2/arch/x86_64/Kconfig	2007-04-27 01:33:22.000000000 +0200
> > @@ -703,6 +703,14 @@ config GENERIC_PENDING_IRQ
> >  	depends on GENERIC_HARDIRQS && SMP
> >  	default y
> >  
> > +#
> > +# Use the tasks freezer
> > +#
> > +config FREEZER
> > +	bool
> > +	default y
> > +	depends on PM || KPROBES
> > +
> >   
> 
> Shouldn't PM and KPROBES "select" FREEZER if they want it?  That way its
> easier for other future users of FREEZER to do so without having to
> change the Kconfig here (and the other 23000 Kconfigs).

Makes sense.  Please have a look at the updated patch below.

Sam, does this one look better to you?

---
From: Rafael J. Wysocki <rjw@sisk.pl>

Now that the freezer is used by kprobes, it is no longer a PM-specific piece of
code.  Move the freezer code out of kernel/power and introduce the
CONFIG_FREEZER option that will be chosen automatically if PM or KPROBES is
set.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 arch/arm/Kconfig         |    4 
 arch/avr32/Kconfig       |    4 
 arch/avr32/Kconfig.debug |    1 
 arch/blackfin/Kconfig    |    4 
 arch/frv/Kconfig         |    4 
 arch/i386/Kconfig        |    5 
 arch/ia64/Kconfig        |    5 
 arch/mips/Kconfig        |    4 
 arch/powerpc/Kconfig     |    5 
 arch/ppc/Kconfig         |    4 
 arch/s390/Kconfig        |    5 
 arch/sh/Kconfig          |    4 
 arch/sparc64/Kconfig     |    5 
 arch/x86_64/Kconfig      |    5 
 include/linux/freezer.h  |    2 
 kernel/Makefile          |    1 
 kernel/freezer.c         |  236 +++++++++++++++++++++++++++++++++++++++++++++++
 kernel/kprobes.c         |    2 
 kernel/power/Kconfig     |    1 
 kernel/power/Makefile    |    2 
 kernel/power/process.c   |  236 -----------------------------------------------
 21 files changed, 300 insertions(+), 239 deletions(-)

Index: linux-2.6.21-rc7-mm2/arch/x86_64/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/x86_64/Kconfig	2007-04-27 21:41:05.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/x86_64/Kconfig	2007-04-27 21:56:01.000000000 +0200
@@ -129,6 +129,10 @@ config ARCH_HAS_ILOG2_U64
 	bool
 	default n
 
+config FREEZER
+	bool
+	default n
+
 source "init/Kconfig"
 
 
@@ -791,6 +795,7 @@ source "arch/x86_64/oprofile/Kconfig"
 config KPROBES
 	bool "Kprobes (EXPERIMENTAL)"
 	depends on KALLSYMS && EXPERIMENTAL && MODULES
+	select FREEZER
 	help
 	  Kprobes allows you to trap at almost any kernel address and
 	  execute a callback function.  register_kprobe() establishes
Index: linux-2.6.21-rc7-mm2/arch/avr32/Kconfig.debug
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/avr32/Kconfig.debug	2007-04-27 21:41:05.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/avr32/Kconfig.debug	2007-04-27 21:54:19.000000000 +0200
@@ -12,6 +12,7 @@ menu "Instrumentation Support"
 config KPROBES
 	bool "Kprobes"
 	depends on DEBUG_KERNEL
+	select FREEZER
 	help
 	  Kprobes allows you to trap at almost any kernel address and
           execute a callback function.  register_kprobe() establishes
Index: linux-2.6.21-rc7-mm2/arch/frv/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/frv/Kconfig	2007-04-27 21:41:05.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/frv/Kconfig	2007-04-27 21:54:34.000000000 +0200
@@ -57,6 +57,10 @@ config ARCH_USES_SLAB_PAGE_STRUCT
 	bool
 	default y
 
+config FREEZER
+	bool
+	default n
+
 mainmenu "Fujitsu FR-V Kernel Configuration"
 
 source "init/Kconfig"
Index: linux-2.6.21-rc7-mm2/arch/i386/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/i386/Kconfig	2007-04-27 21:41:05.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/i386/Kconfig	2007-04-27 21:47:06.000000000 +0200
@@ -87,6 +87,10 @@ config DMI
 	bool
 	default y
 
+config FREEZER
+	bool
+	default n
+
 source "init/Kconfig"
 
 menu "Processor type and features"
@@ -1218,6 +1222,7 @@ source "arch/i386/oprofile/Kconfig"
 config KPROBES
 	bool "Kprobes (EXPERIMENTAL)"
 	depends on KALLSYMS && EXPERIMENTAL && MODULES
+	select FREEZER
 	help
 	  Kprobes allows you to trap at almost any kernel address and
 	  execute a callback function.  register_kprobe() establishes
Index: linux-2.6.21-rc7-mm2/arch/ia64/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/ia64/Kconfig	2007-04-27 21:41:05.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/ia64/Kconfig	2007-04-27 21:47:49.000000000 +0200
@@ -90,6 +90,10 @@ config AUDIT_ARCH
 	bool
 	default y
 
+config FREEZER
+	bool
+	default n
+
 choice
 	prompt "System type"
 	default IA64_GENERIC
@@ -582,6 +586,7 @@ source "arch/ia64/oprofile/Kconfig"
 config KPROBES
 	bool "Kprobes (EXPERIMENTAL)"
 	depends on KALLSYMS && EXPERIMENTAL && MODULES
+	select FREEZER
 	help
 	  Kprobes allows you to trap at almost any kernel address and
 	  execute a callback function.  register_kprobe() establishes
Index: linux-2.6.21-rc7-mm2/arch/powerpc/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/powerpc/Kconfig	2007-04-27 21:41:05.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/powerpc/Kconfig	2007-04-27 21:50:26.000000000 +0200
@@ -123,6 +123,10 @@ config DEFAULT_UIMAGE
 	  Used to allow a board to specify it wants a uImage built by default
 	default n
 
+config FREEZER
+	bool
+	default n
+
 menu "Processor support"
 choice
 	prompt "Processor Type"
@@ -865,6 +869,7 @@ source "arch/powerpc/oprofile/Kconfig"
 config KPROBES
 	bool "Kprobes (EXPERIMENTAL)"
 	depends on !BOOKE && !4xx && KALLSYMS && EXPERIMENTAL && MODULES
+	select FREEZER
 	help
 	  Kprobes allows you to trap at almost any kernel address and
 	  execute a callback function.  register_kprobe() establishes
Index: linux-2.6.21-rc7-mm2/arch/ppc/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/ppc/Kconfig	2007-04-27 21:41:05.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/ppc/Kconfig	2007-04-27 21:55:17.000000000 +0200
@@ -65,6 +65,10 @@ config GENERIC_BUG
 	default y
 	depends on BUG
 
+config FREEZER
+	bool
+	default n
+
 source "init/Kconfig"
 
 menu "Processor"
Index: linux-2.6.21-rc7-mm2/arch/s390/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/s390/Kconfig	2007-04-27 21:41:05.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/s390/Kconfig	2007-04-27 21:51:22.000000000 +0200
@@ -52,6 +52,10 @@ config NO_IOMEM
 config NO_DMA
 	def_bool y
 
+config FREEZER
+	bool
+	default n
+
 mainmenu "Linux Kernel Configuration"
 
 config S390
@@ -557,6 +561,7 @@ source "arch/s390/oprofile/Kconfig"
 config KPROBES
 	bool "Kprobes (EXPERIMENTAL)"
 	depends on EXPERIMENTAL && MODULES
+	select FREEZER
 	help
 	  Kprobes allows you to trap at almost any kernel address and
 	  execute a callback function.	register_kprobe() establishes
Index: linux-2.6.21-rc7-mm2/arch/sh/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/sh/Kconfig	2007-04-27 21:41:05.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/sh/Kconfig	2007-04-27 21:55:36.000000000 +0200
@@ -74,6 +74,10 @@ config ARCH_HAS_ILOG2_U64
 	bool
 	default n
 
+config FREEZER
+	bool
+	default n
+
 source "init/Kconfig"
 
 menu "System type"
Index: linux-2.6.21-rc7-mm2/arch/sparc64/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/sparc64/Kconfig	2007-04-27 21:41:05.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/sparc64/Kconfig	2007-04-27 21:52:31.000000000 +0200
@@ -58,6 +58,10 @@ config AUDIT_ARCH
 	bool
 	default y
 
+config FREEZER
+	bool
+	default n
+
 choice
 	prompt "Kernel page size"
 	default SPARC64_PAGE_SIZE_8KB
@@ -428,6 +432,7 @@ source "arch/sparc64/oprofile/Kconfig"
 config KPROBES
 	bool "Kprobes (EXPERIMENTAL)"
 	depends on KALLSYMS && EXPERIMENTAL && MODULES
+	select FREEZER
 	help
 	  Kprobes allows you to trap at almost any kernel address and
 	  execute a callback function.  register_kprobe() establishes
Index: linux-2.6.21-rc7-mm2/kernel/Makefile
===================================================================
--- linux-2.6.21-rc7-mm2.orig/kernel/Makefile	2007-04-27 21:41:05.000000000 +0200
+++ linux-2.6.21-rc7-mm2/kernel/Makefile	2007-04-27 21:41:28.000000000 +0200
@@ -33,6 +33,7 @@ obj-$(CONFIG_MODULES) += module.o
 obj-$(CONFIG_KALLSYMS) += kallsyms.o
 obj-$(CONFIG_STACK_UNWIND) += unwind.o
 obj-$(CONFIG_PM) += power/
+obj-$(CONFIG_FREEZER) += freezer.o
 obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
 obj-$(CONFIG_KEXEC) += kexec.o
 obj-$(CONFIG_COMPAT) += compat.o
Index: linux-2.6.21-rc7-mm2/kernel/power/Makefile
===================================================================
--- linux-2.6.21-rc7-mm2.orig/kernel/power/Makefile	2007-04-27 21:41:05.000000000 +0200
+++ linux-2.6.21-rc7-mm2/kernel/power/Makefile	2007-04-27 21:41:28.000000000 +0200
@@ -3,7 +3,7 @@ ifeq ($(CONFIG_PM_DEBUG),y)
 EXTRA_CFLAGS	+=	-DDEBUG
 endif
 
-obj-y				:= main.o process.o console.o notify.o
+obj-y				:= main.o console.o notify.o
 obj-$(CONFIG_PM_LEGACY)		+= pm.o
 obj-$(CONFIG_SOFTWARE_SUSPEND)	+= swsusp.o disk.o snapshot.o swap.o user.o
 
Index: linux-2.6.21-rc7-mm2/kernel/kprobes.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/kernel/kprobes.c	2007-04-27 21:41:05.000000000 +0200
+++ linux-2.6.21-rc7-mm2/kernel/kprobes.c	2007-04-27 21:41:28.000000000 +0200
@@ -108,7 +108,7 @@ static int collect_garbage_slots(void);
 static int __kprobes check_safety(void)
 {
 	int ret = 0;
-#if defined(CONFIG_PREEMPT) && defined(CONFIG_PM)
+#ifdef CONFIG_PREEMPT
 	ret = freeze_processes();
 	if (ret == 0) {
 		struct task_struct *p, *q;
Index: linux-2.6.21-rc7-mm2/include/linux/freezer.h
===================================================================
--- linux-2.6.21-rc7-mm2.orig/include/linux/freezer.h	2007-04-27 21:41:27.000000000 +0200
+++ linux-2.6.21-rc7-mm2/include/linux/freezer.h	2007-04-27 21:41:28.000000000 +0200
@@ -2,7 +2,7 @@
 
 #include <linux/sched.h>
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_FREEZER
 /*
  * Check if a process has been frozen
  */
Index: linux-2.6.21-rc7-mm2/arch/arm/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/arm/Kconfig	2007-04-27 21:41:05.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/arm/Kconfig	2007-04-27 21:53:57.000000000 +0200
@@ -41,6 +41,10 @@ config NO_IOPORT
 	bool
 	default n
 
+config FREEZER
+	bool
+	default n
+
 config EISA
 	bool
 	---help---
Index: linux-2.6.21-rc7-mm2/arch/blackfin/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/blackfin/Kconfig	2007-04-27 21:41:05.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/blackfin/Kconfig	2007-04-27 21:54:27.000000000 +0200
@@ -69,6 +69,10 @@ config IRQCHIP_DEMUX_GPIO
 	bool
 	default y
 
+config FREEZER
+	bool
+	default n
+
 source "init/Kconfig"
 source "kernel/Kconfig.preempt"
 
Index: linux-2.6.21-rc7-mm2/arch/mips/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/mips/Kconfig	2007-04-27 21:41:05.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/mips/Kconfig	2007-04-27 21:54:56.000000000 +0200
@@ -877,6 +877,10 @@ config GENERIC_HARDIRQS_NO__DO_IRQ
 	bool
 	default n
 
+config FREEZER
+	bool
+	default n
+
 #
 # Select some configuration options automatically based on user selections.
 #
Index: linux-2.6.21-rc7-mm2/kernel/freezer.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.21-rc7-mm2/kernel/freezer.c	2007-04-27 21:41:28.000000000 +0200
@@ -0,0 +1,236 @@
+/*
+ * linux/kernel/freezer.c
+ *
+ * Generic mechanism for freezing and thawing tasks, originally from swsusp.
+ *
+ * Distributed under the GPLv2
+ */
+
+
+#undef DEBUG
+
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/syscalls.h>
+#include <linux/freezer.h>
+
+/*
+ * Timeout for stopping processes
+ */
+#define TIMEOUT	(20 * HZ)
+
+#define FREEZER_KERNEL_THREADS 0
+#define FREEZER_USER_SPACE 1
+
+static inline int freezeable(struct task_struct * p)
+{
+	if ((p == current) ||
+	    (p->flags & PF_NOFREEZE) ||
+	    (p->exit_state != 0))
+		return 0;
+	return 1;
+}
+
+/*
+ * freezing is complete, mark current process as frozen
+ */
+static inline void frozen_process(void)
+{
+	if (!unlikely(current->flags & PF_NOFREEZE)) {
+		current->flags |= PF_FROZEN;
+		wmb();
+	}
+	clear_tsk_thread_flag(current, TIF_FREEZE);
+}
+
+/* Refrigerator is place where frozen processes are stored :-). */
+void refrigerator(void)
+{
+	/* Hmm, should we be allowed to suspend when there are realtime
+	   processes around? */
+	long save;
+
+	task_lock(current);
+	if (freezing(current)) {
+		frozen_process();
+		task_unlock(current);
+	} else {
+		task_unlock(current);
+		return;
+	}
+	save = current->state;
+	pr_debug("%s entered refrigerator\n", current->comm);
+
+	spin_lock_irq(&current->sighand->siglock);
+	recalc_sigpending(); /* We sent fake signal, clean it up */
+	spin_unlock_irq(&current->sighand->siglock);
+
+	for (;;) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		if (!frozen(current))
+			break;
+		schedule();
+	}
+	pr_debug("%s left refrigerator\n", current->comm);
+	current->state = save;
+}
+
+static inline void freeze_process(struct task_struct *p)
+{
+	unsigned long flags;
+
+	if (!freezing(p)) {
+		rmb();
+		if (!frozen(p)) {
+			if (p->state == TASK_STOPPED)
+				force_sig_specific(SIGSTOP, p);
+
+			freeze(p);
+			spin_lock_irqsave(&p->sighand->siglock, flags);
+			signal_wake_up(p, p->state == TASK_STOPPED);
+			spin_unlock_irqrestore(&p->sighand->siglock, flags);
+		}
+	}
+}
+
+static void cancel_freezing(struct task_struct *p)
+{
+	unsigned long flags;
+
+	if (freezing(p)) {
+		pr_debug("  clean up: %s\n", p->comm);
+		do_not_freeze(p);
+		spin_lock_irqsave(&p->sighand->siglock, flags);
+		recalc_sigpending_tsk(p);
+		spin_unlock_irqrestore(&p->sighand->siglock, flags);
+	}
+}
+
+static inline int is_user_space(struct task_struct *p)
+{
+	int ret;
+
+	task_lock(p);
+	ret = p->mm && !(p->flags & PF_BORROWED_MM);
+	task_unlock(p);
+	return ret;
+}
+
+static unsigned int try_to_freeze_tasks(int freeze_user_space)
+{
+	struct task_struct *g, *p;
+	unsigned long end_time;
+	unsigned int todo;
+
+	end_time = jiffies + TIMEOUT;
+	do {
+		todo = 0;
+		read_lock(&tasklist_lock);
+		do_each_thread(g, p) {
+			if (!freezeable(p))
+				continue;
+
+			if (frozen(p))
+				continue;
+
+			if (p->state == TASK_TRACED && frozen(p->parent)) {
+				cancel_freezing(p);
+				continue;
+			}
+			if (freeze_user_space && !is_user_space(p))
+				continue;
+
+			freeze_process(p);
+			if (!freezer_should_skip(p))
+				todo++;
+		} while_each_thread(g, p);
+		read_unlock(&tasklist_lock);
+		yield();			/* Yield is okay here */
+		if (todo && time_after(jiffies, end_time))
+			break;
+	} while (todo);
+
+	if (todo) {
+		/* This does not unfreeze processes that are already frozen
+		 * (we have slightly ugly calling convention in that respect,
+		 * and caller must call thaw_processes() if something fails),
+		 * but it cleans up leftover PF_FREEZE requests.
+		 */
+		printk("\n");
+		printk(KERN_ERR "Stopping %s timed out after %d seconds "
+				"(%d tasks refusing to freeze):\n",
+				freeze_user_space ? "user space processes" :
+					"kernel threads",
+				TIMEOUT / HZ, todo);
+		read_lock(&tasklist_lock);
+		do_each_thread(g, p) {
+			if (freeze_user_space && !is_user_space(p))
+				continue;
+
+			task_lock(p);
+			if (freezeable(p) && !frozen(p) &&
+			    !freezer_should_skip(p))
+				printk(KERN_ERR " %s\n", p->comm);
+
+			cancel_freezing(p);
+			task_unlock(p);
+		} while_each_thread(g, p);
+		read_unlock(&tasklist_lock);
+	}
+
+	return todo;
+}
+
+/**
+ *	freeze_processes - tell processes to enter the refrigerator
+ *
+ *	Returns 0 on success, or the number of processes that didn't freeze,
+ *	although they were told to.
+ */
+int freeze_processes(void)
+{
+	unsigned int nr_unfrozen;
+
+	printk("Stopping tasks ... ");
+	nr_unfrozen = try_to_freeze_tasks(FREEZER_USER_SPACE);
+	if (nr_unfrozen)
+		return nr_unfrozen;
+
+	sys_sync();
+	nr_unfrozen = try_to_freeze_tasks(FREEZER_KERNEL_THREADS);
+	if (nr_unfrozen)
+		return nr_unfrozen;
+
+	printk("done.\n");
+	BUG_ON(in_atomic());
+	return 0;
+}
+
+static void thaw_tasks(int thaw_user_space)
+{
+	struct task_struct *g, *p;
+
+	read_lock(&tasklist_lock);
+	do_each_thread(g, p) {
+		if (!freezeable(p))
+			continue;
+
+		if (is_user_space(p) == !thaw_user_space)
+			continue;
+
+		thaw_process(p);
+	} while_each_thread(g, p);
+	read_unlock(&tasklist_lock);
+}
+
+void thaw_processes(void)
+{
+	printk("Restarting tasks ... ");
+	thaw_tasks(FREEZER_KERNEL_THREADS);
+	thaw_tasks(FREEZER_USER_SPACE);
+	schedule();
+	printk("done.\n");
+}
+
+EXPORT_SYMBOL(refrigerator);
Index: linux-2.6.21-rc7-mm2/kernel/power/process.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/kernel/power/process.c	2007-04-27 21:41:27.000000000 +0200
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,236 +0,0 @@
-/*
- * drivers/power/process.c - Functions for starting/stopping processes on 
- *                           suspend transitions.
- *
- * Originally from swsusp.
- */
-
-
-#undef DEBUG
-
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/suspend.h>
-#include <linux/module.h>
-#include <linux/syscalls.h>
-#include <linux/freezer.h>
-
-/* 
- * Timeout for stopping processes
- */
-#define TIMEOUT	(20 * HZ)
-
-#define FREEZER_KERNEL_THREADS 0
-#define FREEZER_USER_SPACE 1
-
-static inline int freezeable(struct task_struct * p)
-{
-	if ((p == current) ||
-	    (p->flags & PF_NOFREEZE) ||
-	    (p->exit_state != 0))
-		return 0;
-	return 1;
-}
-
-/*
- * freezing is complete, mark current process as frozen
- */
-static inline void frozen_process(void)
-{
-	if (!unlikely(current->flags & PF_NOFREEZE)) {
-		current->flags |= PF_FROZEN;
-		wmb();
-	}
-	clear_tsk_thread_flag(current, TIF_FREEZE);
-}
-
-/* Refrigerator is place where frozen processes are stored :-). */
-void refrigerator(void)
-{
-	/* Hmm, should we be allowed to suspend when there are realtime
-	   processes around? */
-	long save;
-
-	task_lock(current);
-	if (freezing(current)) {
-		frozen_process();
-		task_unlock(current);
-	} else {
-		task_unlock(current);
-		return;
-	}
-	save = current->state;
-	pr_debug("%s entered refrigerator\n", current->comm);
-
-	spin_lock_irq(&current->sighand->siglock);
-	recalc_sigpending(); /* We sent fake signal, clean it up */
-	spin_unlock_irq(&current->sighand->siglock);
-
-	for (;;) {
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		if (!frozen(current))
-			break;
-		schedule();
-	}
-	pr_debug("%s left refrigerator\n", current->comm);
-	current->state = save;
-}
-
-static inline void freeze_process(struct task_struct *p)
-{
-	unsigned long flags;
-
-	if (!freezing(p)) {
-		rmb();
-		if (!frozen(p)) {
-			if (p->state == TASK_STOPPED)
-				force_sig_specific(SIGSTOP, p);
-
-			freeze(p);
-			spin_lock_irqsave(&p->sighand->siglock, flags);
-			signal_wake_up(p, p->state == TASK_STOPPED);
-			spin_unlock_irqrestore(&p->sighand->siglock, flags);
-		}
-	}
-}
-
-static void cancel_freezing(struct task_struct *p)
-{
-	unsigned long flags;
-
-	if (freezing(p)) {
-		pr_debug("  clean up: %s\n", p->comm);
-		do_not_freeze(p);
-		spin_lock_irqsave(&p->sighand->siglock, flags);
-		recalc_sigpending_tsk(p);
-		spin_unlock_irqrestore(&p->sighand->siglock, flags);
-	}
-}
-
-static inline int is_user_space(struct task_struct *p)
-{
-	int ret;
-
-	task_lock(p);
-	ret = p->mm && !(p->flags & PF_BORROWED_MM);
-	task_unlock(p);
-	return ret;
-}
-
-static unsigned int try_to_freeze_tasks(int freeze_user_space)
-{
-	struct task_struct *g, *p;
-	unsigned long end_time;
-	unsigned int todo;
-
-	end_time = jiffies + TIMEOUT;
-	do {
-		todo = 0;
-		read_lock(&tasklist_lock);
-		do_each_thread(g, p) {
-			if (!freezeable(p))
-				continue;
-
-			if (frozen(p))
-				continue;
-
-			if (p->state == TASK_TRACED && frozen(p->parent)) {
-				cancel_freezing(p);
-				continue;
-			}
-			if (freeze_user_space && !is_user_space(p))
-				continue;
-
-			freeze_process(p);
-			if (!freezer_should_skip(p))
-				todo++;
-		} while_each_thread(g, p);
-		read_unlock(&tasklist_lock);
-		yield();			/* Yield is okay here */
-		if (todo && time_after(jiffies, end_time))
-			break;
-	} while (todo);
-
-	if (todo) {
-		/* This does not unfreeze processes that are already frozen
-		 * (we have slightly ugly calling convention in that respect,
-		 * and caller must call thaw_processes() if something fails),
-		 * but it cleans up leftover PF_FREEZE requests.
-		 */
-		printk("\n");
-		printk(KERN_ERR "Stopping %s timed out after %d seconds "
-				"(%d tasks refusing to freeze):\n",
-				freeze_user_space ? "user space processes" :
-					"kernel threads",
-				TIMEOUT / HZ, todo);
-		read_lock(&tasklist_lock);
-		do_each_thread(g, p) {
-			if (freeze_user_space && !is_user_space(p))
-				continue;
-
-			task_lock(p);
-			if (freezeable(p) && !frozen(p) &&
-			    !freezer_should_skip(p))
-				printk(KERN_ERR " %s\n", p->comm);
-
-			cancel_freezing(p);
-			task_unlock(p);
-		} while_each_thread(g, p);
-		read_unlock(&tasklist_lock);
-	}
-
-	return todo;
-}
-
-/**
- *	freeze_processes - tell processes to enter the refrigerator
- *
- *	Returns 0 on success, or the number of processes that didn't freeze,
- *	although they were told to.
- */
-int freeze_processes(void)
-{
-	unsigned int nr_unfrozen;
-
-	printk("Stopping tasks ... ");
-	nr_unfrozen = try_to_freeze_tasks(FREEZER_USER_SPACE);
-	if (nr_unfrozen)
-		return nr_unfrozen;
-
-	sys_sync();
-	nr_unfrozen = try_to_freeze_tasks(FREEZER_KERNEL_THREADS);
-	if (nr_unfrozen)
-		return nr_unfrozen;
-
-	printk("done.\n");
-	BUG_ON(in_atomic());
-	return 0;
-}
-
-static void thaw_tasks(int thaw_user_space)
-{
-	struct task_struct *g, *p;
-
-	read_lock(&tasklist_lock);
-	do_each_thread(g, p) {
-		if (!freezeable(p))
-			continue;
-
-		if (is_user_space(p) == !thaw_user_space)
-			continue;
-
-		thaw_process(p);
-	} while_each_thread(g, p);
-	read_unlock(&tasklist_lock);
-}
-
-void thaw_processes(void)
-{
-	printk("Restarting tasks ... ");
-	thaw_tasks(FREEZER_KERNEL_THREADS);
-	thaw_tasks(FREEZER_USER_SPACE);
-	schedule();
-	printk("done.\n");
-}
-
-EXPORT_SYMBOL(refrigerator);
Index: linux-2.6.21-rc7-mm2/arch/avr32/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/avr32/Kconfig	2007-04-27 01:00:50.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/avr32/Kconfig	2007-04-27 21:44:56.000000000 +0200
@@ -73,6 +73,10 @@ config GENERIC_BUG
 	default y
 	depends on BUG
 
+config FREEZER
+	bool
+	default n
+
 source "init/Kconfig"
 
 menu "System Type and features"
Index: linux-2.6.21-rc7-mm2/kernel/power/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/kernel/power/Kconfig	2007-04-27 21:41:05.000000000 +0200
+++ linux-2.6.21-rc7-mm2/kernel/power/Kconfig	2007-04-27 21:42:52.000000000 +0200
@@ -1,6 +1,7 @@
 config PM
 	bool "Power Management support"
 	depends on !IA64_HP_SIM
+	select FREEZER
 	---help---
 	  "Power Management" means that parts of your computer are shut
 	  off or put into a power conserving "sleep" mode if they are not

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

* Re: [PATCH -mm 1/2] Separate freezer from PM code
  2007-04-27 20:20       ` Jeremy Fitzhardinge
@ 2007-04-27 21:29         ` Rafael J. Wysocki
  2007-04-29  8:43           ` Sam Ravnborg
  0 siblings, 1 reply; 23+ messages in thread
From: Rafael J. Wysocki @ 2007-04-27 21:29 UTC (permalink / raw)
  To: Jeremy Fitzhardinge
  Cc: Andrew Morton, Gautham R Shenoy, Ingo Molnar, Oleg Nesterov,
	Pavel Machek, Pekka Enberg, LKML

On Friday, 27 April 2007 22:20, Jeremy Fitzhardinge wrote:
> Rafael J. Wysocki wrote:
> > Makes sense.  Please have a look at the updated patch below.
> >
> > Sam, does this one look better to you?
> >   
> 
> If freezer.c is in kernel/, then shouldn't the corresponding config var
> be in a non-arch Kconfig file?

Well, I though it would look strange.  Still, I can do that, of course:

---
From: Rafael J. Wysocki <rjw@sisk.pl>

Now that the freezer is used by kprobes, it is no longer a PM-specific piece of
code.  Move the freezer code out of kernel/power and introduce the
CONFIG_FREEZER option that will be chosen automatically if PM or KPROBES is set.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 arch/arm/Kconfig         |    2 
 arch/avr32/Kconfig       |    2 
 arch/avr32/Kconfig.debug |    1 
 arch/blackfin/Kconfig    |    2 
 arch/frv/Kconfig         |    2 
 arch/i386/Kconfig        |    3 
 arch/ia64/Kconfig        |    3 
 arch/mips/Kconfig        |    2 
 arch/powerpc/Kconfig     |    3 
 arch/ppc/Kconfig         |    2 
 arch/s390/Kconfig        |    3 
 arch/sh/Kconfig          |    2 
 arch/sparc64/Kconfig     |    3 
 arch/x86_64/Kconfig      |    3 
 include/linux/freezer.h  |    2 
 kernel/Kconfig.freezer   |    5 
 kernel/Makefile          |    1 
 kernel/freezer.c         |  236 +++++++++++++++++++++++++++++++++++++++++++++++
 kernel/kprobes.c         |    2 
 kernel/power/Kconfig     |    1 
 kernel/power/Makefile    |    2 
 kernel/power/process.c   |  236 -----------------------------------------------
 22 files changed, 279 insertions(+), 239 deletions(-)

Index: linux-2.6.21-rc7-mm2/arch/x86_64/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/x86_64/Kconfig	2007-04-27 21:41:05.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/x86_64/Kconfig	2007-04-27 23:20:43.000000000 +0200
@@ -703,6 +703,8 @@ config GENERIC_PENDING_IRQ
 	depends on GENERIC_HARDIRQS && SMP
 	default y
 
+source "kernel/Kconfig.freezer"
+
 menu "Power management options"
 
 source kernel/power/Kconfig
@@ -791,6 +793,7 @@ source "arch/x86_64/oprofile/Kconfig"
 config KPROBES
 	bool "Kprobes (EXPERIMENTAL)"
 	depends on KALLSYMS && EXPERIMENTAL && MODULES
+	select FREEZER
 	help
 	  Kprobes allows you to trap at almost any kernel address and
 	  execute a callback function.  register_kprobe() establishes
Index: linux-2.6.21-rc7-mm2/arch/avr32/Kconfig.debug
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/avr32/Kconfig.debug	2007-04-27 21:41:05.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/avr32/Kconfig.debug	2007-04-27 21:54:19.000000000 +0200
@@ -12,6 +12,7 @@ menu "Instrumentation Support"
 config KPROBES
 	bool "Kprobes"
 	depends on DEBUG_KERNEL
+	select FREEZER
 	help
 	  Kprobes allows you to trap at almost any kernel address and
           execute a callback function.  register_kprobe() establishes
Index: linux-2.6.21-rc7-mm2/arch/frv/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/frv/Kconfig	2007-04-27 21:41:05.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/frv/Kconfig	2007-04-27 23:13:27.000000000 +0200
@@ -364,6 +364,8 @@ source "drivers/pcmcia/Kconfig"
 #	  sleep-deprived psychotic hacker types can say Y now, everyone else
 #	  should probably wait a while.
 
+source "kernel/Kconfig.freezer"
+
 menu "Power management options"
 source kernel/power/Kconfig
 endmenu
Index: linux-2.6.21-rc7-mm2/arch/i386/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/i386/Kconfig	2007-04-27 21:41:05.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/i386/Kconfig	2007-04-27 23:17:36.000000000 +0200
@@ -912,6 +912,8 @@ config ARCH_ENABLE_MEMORY_HOTPLUG
 	def_bool y
 	depends on HIGHMEM
 
+source "kernel/Kconfig.freezer"
+
 menu "Power management options (ACPI, APM)"
 	depends on !X86_VOYAGER
 
@@ -1218,6 +1220,7 @@ source "arch/i386/oprofile/Kconfig"
 config KPROBES
 	bool "Kprobes (EXPERIMENTAL)"
 	depends on KALLSYMS && EXPERIMENTAL && MODULES
+	select FREEZER
 	help
 	  Kprobes allows you to trap at almost any kernel address and
 	  execute a callback function.  register_kprobe() establishes
Index: linux-2.6.21-rc7-mm2/arch/ia64/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/ia64/Kconfig	2007-04-27 21:41:05.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/ia64/Kconfig	2007-04-27 23:21:40.000000000 +0200
@@ -495,6 +495,8 @@ source "fs/Kconfig.binfmt"
 
 endmenu
 
+source "kernel/Kconfig.freezer"
+
 menu "Power management and ACPI"
 
 source "kernel/power/Kconfig"
@@ -582,6 +584,7 @@ source "arch/ia64/oprofile/Kconfig"
 config KPROBES
 	bool "Kprobes (EXPERIMENTAL)"
 	depends on KALLSYMS && EXPERIMENTAL && MODULES
+	select FREEZER
 	help
 	  Kprobes allows you to trap at almost any kernel address and
 	  execute a callback function.  register_kprobe() establishes
Index: linux-2.6.21-rc7-mm2/arch/powerpc/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/powerpc/Kconfig	2007-04-27 21:41:05.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/powerpc/Kconfig	2007-04-27 23:15:12.000000000 +0200
@@ -552,6 +552,8 @@ config CMDLINE
 	  some command-line options at build time by entering them here.  In
 	  most cases you will need to specify the root device here.
 
+source kernel/Kconfig.freezer
+
 if !44x || BROKEN
 source kernel/power/Kconfig
 endif
@@ -865,6 +867,7 @@ source "arch/powerpc/oprofile/Kconfig"
 config KPROBES
 	bool "Kprobes (EXPERIMENTAL)"
 	depends on !BOOKE && !4xx && KALLSYMS && EXPERIMENTAL && MODULES
+	select FREEZER
 	help
 	  Kprobes allows you to trap at almost any kernel address and
 	  execute a callback function.  register_kprobe() establishes
Index: linux-2.6.21-rc7-mm2/arch/ppc/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/ppc/Kconfig	2007-04-27 21:41:05.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/ppc/Kconfig	2007-04-27 23:15:25.000000000 +0200
@@ -1153,6 +1153,8 @@ config PROC_HARDWARE
 
 source "drivers/zorro/Kconfig"
 
+source "kernel/Kconfig.freezer"
+
 if !44x || BROKEN
 source kernel/power/Kconfig
 endif
Index: linux-2.6.21-rc7-mm2/arch/s390/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/s390/Kconfig	2007-04-27 21:41:05.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/s390/Kconfig	2007-04-27 23:23:19.000000000 +0200
@@ -550,6 +550,8 @@ source "drivers/net/Kconfig"
 
 source "fs/Kconfig"
 
+source "kernel/Kconfig.freezer"
+
 menu "Instrumentation Support"
 
 source "arch/s390/oprofile/Kconfig"
@@ -557,6 +559,7 @@ source "arch/s390/oprofile/Kconfig"
 config KPROBES
 	bool "Kprobes (EXPERIMENTAL)"
 	depends on EXPERIMENTAL && MODULES
+	select FREEZER
 	help
 	  Kprobes allows you to trap at almost any kernel address and
 	  execute a callback function.	register_kprobe() establishes
Index: linux-2.6.21-rc7-mm2/arch/sh/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/sh/Kconfig	2007-04-27 21:41:05.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/sh/Kconfig	2007-04-27 23:23:33.000000000 +0200
@@ -699,6 +699,8 @@ source "fs/Kconfig.binfmt"
 
 endmenu
 
+source "kernel/Kconfig.freezer"
+
 menu "Power management options (EXPERIMENTAL)"
 depends on EXPERIMENTAL
 
Index: linux-2.6.21-rc7-mm2/arch/sparc64/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/sparc64/Kconfig	2007-04-27 21:41:05.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/sparc64/Kconfig	2007-04-27 23:23:44.000000000 +0200
@@ -420,6 +420,8 @@ source "drivers/fc4/Kconfig"
 
 source "fs/Kconfig"
 
+source "kernel/Kconfig.freezer"
+
 menu "Instrumentation Support"
         depends on EXPERIMENTAL
 
@@ -428,6 +430,7 @@ source "arch/sparc64/oprofile/Kconfig"
 config KPROBES
 	bool "Kprobes (EXPERIMENTAL)"
 	depends on KALLSYMS && EXPERIMENTAL && MODULES
+	select FREEZER
 	help
 	  Kprobes allows you to trap at almost any kernel address and
 	  execute a callback function.  register_kprobe() establishes
Index: linux-2.6.21-rc7-mm2/kernel/Makefile
===================================================================
--- linux-2.6.21-rc7-mm2.orig/kernel/Makefile	2007-04-27 21:41:05.000000000 +0200
+++ linux-2.6.21-rc7-mm2/kernel/Makefile	2007-04-27 21:41:28.000000000 +0200
@@ -33,6 +33,7 @@ obj-$(CONFIG_MODULES) += module.o
 obj-$(CONFIG_KALLSYMS) += kallsyms.o
 obj-$(CONFIG_STACK_UNWIND) += unwind.o
 obj-$(CONFIG_PM) += power/
+obj-$(CONFIG_FREEZER) += freezer.o
 obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
 obj-$(CONFIG_KEXEC) += kexec.o
 obj-$(CONFIG_COMPAT) += compat.o
Index: linux-2.6.21-rc7-mm2/kernel/power/Makefile
===================================================================
--- linux-2.6.21-rc7-mm2.orig/kernel/power/Makefile	2007-04-27 21:41:05.000000000 +0200
+++ linux-2.6.21-rc7-mm2/kernel/power/Makefile	2007-04-27 21:41:28.000000000 +0200
@@ -3,7 +3,7 @@ ifeq ($(CONFIG_PM_DEBUG),y)
 EXTRA_CFLAGS	+=	-DDEBUG
 endif
 
-obj-y				:= main.o process.o console.o notify.o
+obj-y				:= main.o console.o notify.o
 obj-$(CONFIG_PM_LEGACY)		+= pm.o
 obj-$(CONFIG_SOFTWARE_SUSPEND)	+= swsusp.o disk.o snapshot.o swap.o user.o
 
Index: linux-2.6.21-rc7-mm2/kernel/kprobes.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/kernel/kprobes.c	2007-04-27 21:41:05.000000000 +0200
+++ linux-2.6.21-rc7-mm2/kernel/kprobes.c	2007-04-27 21:41:28.000000000 +0200
@@ -108,7 +108,7 @@ static int collect_garbage_slots(void);
 static int __kprobes check_safety(void)
 {
 	int ret = 0;
-#if defined(CONFIG_PREEMPT) && defined(CONFIG_PM)
+#ifdef CONFIG_PREEMPT
 	ret = freeze_processes();
 	if (ret == 0) {
 		struct task_struct *p, *q;
Index: linux-2.6.21-rc7-mm2/include/linux/freezer.h
===================================================================
--- linux-2.6.21-rc7-mm2.orig/include/linux/freezer.h	2007-04-27 21:41:27.000000000 +0200
+++ linux-2.6.21-rc7-mm2/include/linux/freezer.h	2007-04-27 23:20:23.000000000 +0200
@@ -2,7 +2,7 @@
 
 #include <linux/sched.h>
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_FREEZER
 /*
  * Check if a process has been frozen
  */
Index: linux-2.6.21-rc7-mm2/arch/arm/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/arm/Kconfig	2007-04-27 21:41:05.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/arm/Kconfig	2007-04-27 23:11:10.000000000 +0200
@@ -925,6 +925,8 @@ config ARTHUR
 
 endmenu
 
+source "kernel/Kconfig.freezer"
+
 menu "Power management options"
 
 source "kernel/power/Kconfig"
Index: linux-2.6.21-rc7-mm2/arch/blackfin/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/blackfin/Kconfig	2007-04-27 21:41:05.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/blackfin/Kconfig	2007-04-27 23:13:09.000000000 +0200
@@ -816,6 +816,8 @@ source "fs/Kconfig.binfmt"
 
 endmenu
 
+source "kernel/Kconfig.freezer"
+
 menu "Power management options"
 source "kernel/power/Kconfig"
 
Index: linux-2.6.21-rc7-mm2/arch/mips/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/mips/Kconfig	2007-04-27 21:41:05.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/mips/Kconfig	2007-04-27 23:22:37.000000000 +0200
@@ -2067,6 +2067,8 @@ source "drivers/pci/hotplug/Kconfig"
 
 endmenu
 
+source "kernel/Kconfig.freezer"
+
 menu "Executable file formats"
 
 source "fs/Kconfig.binfmt"
Index: linux-2.6.21-rc7-mm2/kernel/freezer.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.21-rc7-mm2/kernel/freezer.c	2007-04-27 23:20:23.000000000 +0200
@@ -0,0 +1,236 @@
+/*
+ * linux/kernel/freezer.c
+ *
+ * Generic mechanism for freezing and thawing tasks, originally from swsusp.
+ *
+ * Distributed under the GPLv2
+ */
+
+
+#undef DEBUG
+
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/syscalls.h>
+#include <linux/freezer.h>
+
+/*
+ * Timeout for stopping processes
+ */
+#define TIMEOUT	(20 * HZ)
+
+#define FREEZER_KERNEL_THREADS 0
+#define FREEZER_USER_SPACE 1
+
+static inline int freezeable(struct task_struct * p)
+{
+	if ((p == current) ||
+	    (p->flags & PF_NOFREEZE) ||
+	    (p->exit_state != 0))
+		return 0;
+	return 1;
+}
+
+/*
+ * freezing is complete, mark current process as frozen
+ */
+static inline void frozen_process(void)
+{
+	if (!unlikely(current->flags & PF_NOFREEZE)) {
+		current->flags |= PF_FROZEN;
+		wmb();
+	}
+	clear_tsk_thread_flag(current, TIF_FREEZE);
+}
+
+/* Refrigerator is place where frozen processes are stored :-). */
+void refrigerator(void)
+{
+	/* Hmm, should we be allowed to suspend when there are realtime
+	   processes around? */
+	long save;
+
+	task_lock(current);
+	if (freezing(current)) {
+		frozen_process();
+		task_unlock(current);
+	} else {
+		task_unlock(current);
+		return;
+	}
+	save = current->state;
+	pr_debug("%s entered refrigerator\n", current->comm);
+
+	spin_lock_irq(&current->sighand->siglock);
+	recalc_sigpending(); /* We sent fake signal, clean it up */
+	spin_unlock_irq(&current->sighand->siglock);
+
+	for (;;) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		if (!frozen(current))
+			break;
+		schedule();
+	}
+	pr_debug("%s left refrigerator\n", current->comm);
+	current->state = save;
+}
+
+static inline void freeze_process(struct task_struct *p)
+{
+	unsigned long flags;
+
+	if (!freezing(p)) {
+		rmb();
+		if (!frozen(p)) {
+			if (p->state == TASK_STOPPED)
+				force_sig_specific(SIGSTOP, p);
+
+			freeze(p);
+			spin_lock_irqsave(&p->sighand->siglock, flags);
+			signal_wake_up(p, p->state == TASK_STOPPED);
+			spin_unlock_irqrestore(&p->sighand->siglock, flags);
+		}
+	}
+}
+
+static void cancel_freezing(struct task_struct *p)
+{
+	unsigned long flags;
+
+	if (freezing(p)) {
+		pr_debug("  clean up: %s\n", p->comm);
+		do_not_freeze(p);
+		spin_lock_irqsave(&p->sighand->siglock, flags);
+		recalc_sigpending_tsk(p);
+		spin_unlock_irqrestore(&p->sighand->siglock, flags);
+	}
+}
+
+static inline int is_user_space(struct task_struct *p)
+{
+	int ret;
+
+	task_lock(p);
+	ret = p->mm && !(p->flags & PF_BORROWED_MM);
+	task_unlock(p);
+	return ret;
+}
+
+static unsigned int try_to_freeze_tasks(int freeze_user_space)
+{
+	struct task_struct *g, *p;
+	unsigned long end_time;
+	unsigned int todo;
+
+	end_time = jiffies + TIMEOUT;
+	do {
+		todo = 0;
+		read_lock(&tasklist_lock);
+		do_each_thread(g, p) {
+			if (!freezeable(p))
+				continue;
+
+			if (frozen(p))
+				continue;
+
+			if (p->state == TASK_TRACED && frozen(p->parent)) {
+				cancel_freezing(p);
+				continue;
+			}
+			if (freeze_user_space && !is_user_space(p))
+				continue;
+
+			freeze_process(p);
+			if (!freezer_should_skip(p))
+				todo++;
+		} while_each_thread(g, p);
+		read_unlock(&tasklist_lock);
+		yield();			/* Yield is okay here */
+		if (todo && time_after(jiffies, end_time))
+			break;
+	} while (todo);
+
+	if (todo) {
+		/* This does not unfreeze processes that are already frozen
+		 * (we have slightly ugly calling convention in that respect,
+		 * and caller must call thaw_processes() if something fails),
+		 * but it cleans up leftover PF_FREEZE requests.
+		 */
+		printk("\n");
+		printk(KERN_ERR "Stopping %s timed out after %d seconds "
+				"(%d tasks refusing to freeze):\n",
+				freeze_user_space ? "user space processes" :
+					"kernel threads",
+				TIMEOUT / HZ, todo);
+		read_lock(&tasklist_lock);
+		do_each_thread(g, p) {
+			if (freeze_user_space && !is_user_space(p))
+				continue;
+
+			task_lock(p);
+			if (freezeable(p) && !frozen(p) &&
+			    !freezer_should_skip(p))
+				printk(KERN_ERR " %s\n", p->comm);
+
+			cancel_freezing(p);
+			task_unlock(p);
+		} while_each_thread(g, p);
+		read_unlock(&tasklist_lock);
+	}
+
+	return todo;
+}
+
+/**
+ *	freeze_processes - tell processes to enter the refrigerator
+ *
+ *	Returns 0 on success, or the number of processes that didn't freeze,
+ *	although they were told to.
+ */
+int freeze_processes(void)
+{
+	unsigned int nr_unfrozen;
+
+	printk("Stopping tasks ... ");
+	nr_unfrozen = try_to_freeze_tasks(FREEZER_USER_SPACE);
+	if (nr_unfrozen)
+		return nr_unfrozen;
+
+	sys_sync();
+	nr_unfrozen = try_to_freeze_tasks(FREEZER_KERNEL_THREADS);
+	if (nr_unfrozen)
+		return nr_unfrozen;
+
+	printk("done.\n");
+	BUG_ON(in_atomic());
+	return 0;
+}
+
+static void thaw_tasks(int thaw_user_space)
+{
+	struct task_struct *g, *p;
+
+	read_lock(&tasklist_lock);
+	do_each_thread(g, p) {
+		if (!freezeable(p))
+			continue;
+
+		if (is_user_space(p) == !thaw_user_space)
+			continue;
+
+		thaw_process(p);
+	} while_each_thread(g, p);
+	read_unlock(&tasklist_lock);
+}
+
+void thaw_processes(void)
+{
+	printk("Restarting tasks ... ");
+	thaw_tasks(FREEZER_KERNEL_THREADS);
+	thaw_tasks(FREEZER_USER_SPACE);
+	schedule();
+	printk("done.\n");
+}
+
+EXPORT_SYMBOL(refrigerator);
Index: linux-2.6.21-rc7-mm2/kernel/power/process.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/kernel/power/process.c	2007-04-27 21:41:27.000000000 +0200
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,236 +0,0 @@
-/*
- * drivers/power/process.c - Functions for starting/stopping processes on 
- *                           suspend transitions.
- *
- * Originally from swsusp.
- */
-
-
-#undef DEBUG
-
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/suspend.h>
-#include <linux/module.h>
-#include <linux/syscalls.h>
-#include <linux/freezer.h>
-
-/* 
- * Timeout for stopping processes
- */
-#define TIMEOUT	(20 * HZ)
-
-#define FREEZER_KERNEL_THREADS 0
-#define FREEZER_USER_SPACE 1
-
-static inline int freezeable(struct task_struct * p)
-{
-	if ((p == current) ||
-	    (p->flags & PF_NOFREEZE) ||
-	    (p->exit_state != 0))
-		return 0;
-	return 1;
-}
-
-/*
- * freezing is complete, mark current process as frozen
- */
-static inline void frozen_process(void)
-{
-	if (!unlikely(current->flags & PF_NOFREEZE)) {
-		current->flags |= PF_FROZEN;
-		wmb();
-	}
-	clear_tsk_thread_flag(current, TIF_FREEZE);
-}
-
-/* Refrigerator is place where frozen processes are stored :-). */
-void refrigerator(void)
-{
-	/* Hmm, should we be allowed to suspend when there are realtime
-	   processes around? */
-	long save;
-
-	task_lock(current);
-	if (freezing(current)) {
-		frozen_process();
-		task_unlock(current);
-	} else {
-		task_unlock(current);
-		return;
-	}
-	save = current->state;
-	pr_debug("%s entered refrigerator\n", current->comm);
-
-	spin_lock_irq(&current->sighand->siglock);
-	recalc_sigpending(); /* We sent fake signal, clean it up */
-	spin_unlock_irq(&current->sighand->siglock);
-
-	for (;;) {
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		if (!frozen(current))
-			break;
-		schedule();
-	}
-	pr_debug("%s left refrigerator\n", current->comm);
-	current->state = save;
-}
-
-static inline void freeze_process(struct task_struct *p)
-{
-	unsigned long flags;
-
-	if (!freezing(p)) {
-		rmb();
-		if (!frozen(p)) {
-			if (p->state == TASK_STOPPED)
-				force_sig_specific(SIGSTOP, p);
-
-			freeze(p);
-			spin_lock_irqsave(&p->sighand->siglock, flags);
-			signal_wake_up(p, p->state == TASK_STOPPED);
-			spin_unlock_irqrestore(&p->sighand->siglock, flags);
-		}
-	}
-}
-
-static void cancel_freezing(struct task_struct *p)
-{
-	unsigned long flags;
-
-	if (freezing(p)) {
-		pr_debug("  clean up: %s\n", p->comm);
-		do_not_freeze(p);
-		spin_lock_irqsave(&p->sighand->siglock, flags);
-		recalc_sigpending_tsk(p);
-		spin_unlock_irqrestore(&p->sighand->siglock, flags);
-	}
-}
-
-static inline int is_user_space(struct task_struct *p)
-{
-	int ret;
-
-	task_lock(p);
-	ret = p->mm && !(p->flags & PF_BORROWED_MM);
-	task_unlock(p);
-	return ret;
-}
-
-static unsigned int try_to_freeze_tasks(int freeze_user_space)
-{
-	struct task_struct *g, *p;
-	unsigned long end_time;
-	unsigned int todo;
-
-	end_time = jiffies + TIMEOUT;
-	do {
-		todo = 0;
-		read_lock(&tasklist_lock);
-		do_each_thread(g, p) {
-			if (!freezeable(p))
-				continue;
-
-			if (frozen(p))
-				continue;
-
-			if (p->state == TASK_TRACED && frozen(p->parent)) {
-				cancel_freezing(p);
-				continue;
-			}
-			if (freeze_user_space && !is_user_space(p))
-				continue;
-
-			freeze_process(p);
-			if (!freezer_should_skip(p))
-				todo++;
-		} while_each_thread(g, p);
-		read_unlock(&tasklist_lock);
-		yield();			/* Yield is okay here */
-		if (todo && time_after(jiffies, end_time))
-			break;
-	} while (todo);
-
-	if (todo) {
-		/* This does not unfreeze processes that are already frozen
-		 * (we have slightly ugly calling convention in that respect,
-		 * and caller must call thaw_processes() if something fails),
-		 * but it cleans up leftover PF_FREEZE requests.
-		 */
-		printk("\n");
-		printk(KERN_ERR "Stopping %s timed out after %d seconds "
-				"(%d tasks refusing to freeze):\n",
-				freeze_user_space ? "user space processes" :
-					"kernel threads",
-				TIMEOUT / HZ, todo);
-		read_lock(&tasklist_lock);
-		do_each_thread(g, p) {
-			if (freeze_user_space && !is_user_space(p))
-				continue;
-
-			task_lock(p);
-			if (freezeable(p) && !frozen(p) &&
-			    !freezer_should_skip(p))
-				printk(KERN_ERR " %s\n", p->comm);
-
-			cancel_freezing(p);
-			task_unlock(p);
-		} while_each_thread(g, p);
-		read_unlock(&tasklist_lock);
-	}
-
-	return todo;
-}
-
-/**
- *	freeze_processes - tell processes to enter the refrigerator
- *
- *	Returns 0 on success, or the number of processes that didn't freeze,
- *	although they were told to.
- */
-int freeze_processes(void)
-{
-	unsigned int nr_unfrozen;
-
-	printk("Stopping tasks ... ");
-	nr_unfrozen = try_to_freeze_tasks(FREEZER_USER_SPACE);
-	if (nr_unfrozen)
-		return nr_unfrozen;
-
-	sys_sync();
-	nr_unfrozen = try_to_freeze_tasks(FREEZER_KERNEL_THREADS);
-	if (nr_unfrozen)
-		return nr_unfrozen;
-
-	printk("done.\n");
-	BUG_ON(in_atomic());
-	return 0;
-}
-
-static void thaw_tasks(int thaw_user_space)
-{
-	struct task_struct *g, *p;
-
-	read_lock(&tasklist_lock);
-	do_each_thread(g, p) {
-		if (!freezeable(p))
-			continue;
-
-		if (is_user_space(p) == !thaw_user_space)
-			continue;
-
-		thaw_process(p);
-	} while_each_thread(g, p);
-	read_unlock(&tasklist_lock);
-}
-
-void thaw_processes(void)
-{
-	printk("Restarting tasks ... ");
-	thaw_tasks(FREEZER_KERNEL_THREADS);
-	thaw_tasks(FREEZER_USER_SPACE);
-	schedule();
-	printk("done.\n");
-}
-
-EXPORT_SYMBOL(refrigerator);
Index: linux-2.6.21-rc7-mm2/arch/avr32/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/avr32/Kconfig	2007-04-27 01:00:50.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/avr32/Kconfig	2007-04-27 23:12:42.000000000 +0200
@@ -209,6 +209,8 @@ source "drivers/Kconfig"
 
 source "fs/Kconfig"
 
+source "kernel/Kconfig.freezer"
+
 source "arch/avr32/Kconfig.debug"
 
 source "security/Kconfig"
Index: linux-2.6.21-rc7-mm2/kernel/power/Kconfig
===================================================================
--- linux-2.6.21-rc7-mm2.orig/kernel/power/Kconfig	2007-04-27 21:41:05.000000000 +0200
+++ linux-2.6.21-rc7-mm2/kernel/power/Kconfig	2007-04-27 21:42:52.000000000 +0200
@@ -1,6 +1,7 @@
 config PM
 	bool "Power Management support"
 	depends on !IA64_HP_SIM
+	select FREEZER
 	---help---
 	  "Power Management" means that parts of your computer are shut
 	  off or put into a power conserving "sleep" mode if they are not
Index: linux-2.6.21-rc7-mm2/kernel/Kconfig.freezer
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.21-rc7-mm2/kernel/Kconfig.freezer	2007-04-27 23:06:52.000000000 +0200
@@ -0,0 +1,5 @@
+# Tasks freezer configuration
+
+config FREEZER
+	bool
+	default n



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

* Re: [PATCH -mm 2/2] Introduce freezer flags
  2007-04-27 15:40 ` [PATCH -mm 2/2] Introduce freezer flags Rafael J. Wysocki
  2007-04-27 16:19   ` Sam Ravnborg
@ 2007-04-27 21:40   ` Gautham R Shenoy
  2007-04-27 21:49     ` Rafael J. Wysocki
  2007-04-28  1:34   ` [PATCH -mm] Allow selective freezing of the system for different events Gautham R Shenoy
  2 siblings, 1 reply; 23+ messages in thread
From: Gautham R Shenoy @ 2007-04-27 21:40 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Andrew Morton, Ingo Molnar, Oleg Nesterov, Pavel Machek,
	Pekka Enberg, LKML

On Fri, Apr 27, 2007 at 05:40:16PM +0200, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rjw@sisk.pl>
> 
> Move all of the freezer-related flags to a separate field in task_struct and
> introduce functions to operate them using set_bit() etc.
> 
> 
> Index: linux-2.6.21-rc7-mm2/include/linux/sched.h
> ===================================================================
> --- linux-2.6.21-rc7-mm2.orig/include/linux/sched.h
> +++ linux-2.6.21-rc7-mm2/include/linux/sched.h
> @@ -1006,7 +1006,10 @@ struct task_struct {
>  	/* Deadlock detection and priority inheritance handling */
>  	struct rt_mutex_waiter *pi_blocked_on;
>  #endif
> -
> +#ifdef CONFIG_FREEZER
> +	/* Used by the process freezer, defined in freezer.h */
> +	unsigned int freezer_flags;

unsigned long freezer_flags; ??

Else it throws the following warnings.

include/linux/freezer.h: In function `frozen':
include/linux/freezer.h:22: warning: passing arg 2 of
`constant_test_bit' from incompatible pointer type
include/linux/freezer.h:22: warning: passing arg 2 of
`variable_test_bit' from incompatible pointer type
include/linux/freezer.h: In function `set_frozen_flag':
include/linux/freezer.h:27: warning: passing arg 2 of `set_bit' from
incompatible pointer type
include/linux/freezer.h: In function `clear_frozen_flag':
include/linux/freezer.h:32: warning: passing arg 2 of `clear_bit' from
incompatible pointer type
include/linux/freezer.h: In function `freezing':
include/linux/freezer.h:40: warning: passing arg 2 of
`constant_test_bit' from incompatible pointer type
include/linux/freezer.h:40: warning: passing arg 2 of
`variable_test_bit' from incompatible pointer type
include/linux/freezer.h: In function `freeze':
include/linux/freezer.h:48: warning: passing arg 2 of `set_bit' from
incompatible pointer type
include/linux/freezer.h: In function `clear_freeze_flag':
include/linux/freezer.h:56: warning: passing arg 2 of `clear_bit' from
incompatible pointer type
include/linux/freezer.h: In function `freezer_should_exempt':
include/linux/freezer.h:64: warning: passing arg 2 of
`constant_test_bit' from incompatible pointer type
include/linux/freezer.h:64: warning: passing arg 2 of
`variable_test_bit' from incompatible pointer type
include/linux/freezer.h: In function `freezer_exempt':
include/linux/freezer.h:72: warning: passing arg 2 of `set_bit' from
incompatible pointer type
include/linux/freezer.h: In function `freezer_do_not_count':
include/linux/freezer.h:132: warning: passing arg 2 of `set_bit' from
incompatible pointer type
include/linux/freezer.h: In function `freezer_count':
include/linux/freezer.h:142: warning: passing arg 2 of `clear_bit' from
incompatible pointer type
include/linux/freezer.h: In function `freezer_should_skip':
include/linux/freezer.h:152: warning: passing arg 2 of
`constant_test_bit' from incompatible pointer type
include/linux/freezer.h:152: warning: passing arg 2 of
`variable_test_bit' from incompatible pointer type

Regards
gautham.
-- 
Gautham R Shenoy
Linux Technology Center
IBM India.
"Freedom comes with a price tag of responsibility, which is still a bargain,
because Freedom is priceless!"

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

* Re: [PATCH -mm 2/2] Introduce freezer flags
  2007-04-27 21:49     ` Rafael J. Wysocki
@ 2007-04-27 21:49       ` Gautham R Shenoy
  2007-04-27 22:09       ` Rafael J. Wysocki
  1 sibling, 0 replies; 23+ messages in thread
From: Gautham R Shenoy @ 2007-04-27 21:49 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Andrew Morton, Ingo Molnar, Oleg Nesterov, Pavel Machek,
	Pekka Enberg, LKML

On Fri, Apr 27, 2007 at 11:49:35PM +0200, Rafael J. Wysocki wrote:
> > > -
> > > +#ifdef CONFIG_FREEZER
> > > +	/* Used by the process freezer, defined in freezer.h */
> > > +	unsigned int freezer_flags;
> > 
> > unsigned long freezer_flags; ??
> 
> I guess so.
> 
> > Else it throws the following warnings.
> 
> On which arch is that?  I've tested on x86_64 ...

I compile tested it on i386 with gcc v4.1.2.

> 
> 
> Greetings,
> Rafael

Regards
gautham.
-- 
Gautham R Shenoy
Linux Technology Center
IBM India.
"Freedom comes with a price tag of responsibility, which is still a bargain,
because Freedom is priceless!"

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

* Re: [PATCH -mm 2/2] Introduce freezer flags
  2007-04-27 21:40   ` Gautham R Shenoy
@ 2007-04-27 21:49     ` Rafael J. Wysocki
  2007-04-27 21:49       ` Gautham R Shenoy
  2007-04-27 22:09       ` Rafael J. Wysocki
  0 siblings, 2 replies; 23+ messages in thread
From: Rafael J. Wysocki @ 2007-04-27 21:49 UTC (permalink / raw)
  To: ego
  Cc: Andrew Morton, Ingo Molnar, Oleg Nesterov, Pavel Machek,
	Pekka Enberg, LKML

On Friday, 27 April 2007 23:40, Gautham R Shenoy wrote:
> On Fri, Apr 27, 2007 at 05:40:16PM +0200, Rafael J. Wysocki wrote:
> > From: Rafael J. Wysocki <rjw@sisk.pl>
> > 
> > Move all of the freezer-related flags to a separate field in task_struct and
> > introduce functions to operate them using set_bit() etc.
> > 
> > 
> > Index: linux-2.6.21-rc7-mm2/include/linux/sched.h
> > ===================================================================
> > --- linux-2.6.21-rc7-mm2.orig/include/linux/sched.h
> > +++ linux-2.6.21-rc7-mm2/include/linux/sched.h
> > @@ -1006,7 +1006,10 @@ struct task_struct {
> >  	/* Deadlock detection and priority inheritance handling */
> >  	struct rt_mutex_waiter *pi_blocked_on;
> >  #endif
> > -
> > +#ifdef CONFIG_FREEZER
> > +	/* Used by the process freezer, defined in freezer.h */
> > +	unsigned int freezer_flags;
> 
> unsigned long freezer_flags; ??

I guess so.

> Else it throws the following warnings.

On which arch is that?  I've tested on x86_64 ...

> include/linux/freezer.h: In function `frozen':
> include/linux/freezer.h:22: warning: passing arg 2 of
> `constant_test_bit' from incompatible pointer type
> include/linux/freezer.h:22: warning: passing arg 2 of
> `variable_test_bit' from incompatible pointer type
> include/linux/freezer.h: In function `set_frozen_flag':
> include/linux/freezer.h:27: warning: passing arg 2 of `set_bit' from
> incompatible pointer type
> include/linux/freezer.h: In function `clear_frozen_flag':
> include/linux/freezer.h:32: warning: passing arg 2 of `clear_bit' from
> incompatible pointer type
> include/linux/freezer.h: In function `freezing':
> include/linux/freezer.h:40: warning: passing arg 2 of
> `constant_test_bit' from incompatible pointer type
> include/linux/freezer.h:40: warning: passing arg 2 of
> `variable_test_bit' from incompatible pointer type
> include/linux/freezer.h: In function `freeze':
> include/linux/freezer.h:48: warning: passing arg 2 of `set_bit' from
> incompatible pointer type
> include/linux/freezer.h: In function `clear_freeze_flag':
> include/linux/freezer.h:56: warning: passing arg 2 of `clear_bit' from
> incompatible pointer type
> include/linux/freezer.h: In function `freezer_should_exempt':
> include/linux/freezer.h:64: warning: passing arg 2 of
> `constant_test_bit' from incompatible pointer type
> include/linux/freezer.h:64: warning: passing arg 2 of
> `variable_test_bit' from incompatible pointer type
> include/linux/freezer.h: In function `freezer_exempt':
> include/linux/freezer.h:72: warning: passing arg 2 of `set_bit' from
> incompatible pointer type
> include/linux/freezer.h: In function `freezer_do_not_count':
> include/linux/freezer.h:132: warning: passing arg 2 of `set_bit' from
> incompatible pointer type
> include/linux/freezer.h: In function `freezer_count':
> include/linux/freezer.h:142: warning: passing arg 2 of `clear_bit' from
> incompatible pointer type
> include/linux/freezer.h: In function `freezer_should_skip':
> include/linux/freezer.h:152: warning: passing arg 2 of
> `constant_test_bit' from incompatible pointer type
> include/linux/freezer.h:152: warning: passing arg 2 of
> `variable_test_bit' from incompatible pointer type

Greetings,
Rafael

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

* Re: [PATCH -mm 2/2] Introduce freezer flags
  2007-04-27 22:09       ` Rafael J. Wysocki
@ 2007-04-27 22:07         ` Pavel Machek
  2007-04-27 22:56           ` Rafael J. Wysocki
  0 siblings, 1 reply; 23+ messages in thread
From: Pavel Machek @ 2007-04-27 22:07 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ego, Andrew Morton, Ingo Molnar, Oleg Nesterov, Pekka Enberg, LKML

Hi!

> > > > +#ifdef CONFIG_FREEZER
> > > > +	/* Used by the process freezer, defined in freezer.h */
> > > > +	unsigned int freezer_flags;
> > > 
> > > unsigned long freezer_flags; ??
> > 
> > I guess so.
> 
> Still, on x86_64, for example, we'll waste 4 bytes by using 'unsigned long'
> here, which I wouldn't like to do.
> 
> Is it acceptable to use explicit type casting in set_bit() and friends?

I'm afraid set_bit & friends are only defined on unsigned long. You
can cast, but you may run into some nasty surprise... like damaging
surrounding bytes on 64-bit architectures != x86_64.

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

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

* Re: [PATCH -mm 2/2] Introduce freezer flags
  2007-04-27 21:49     ` Rafael J. Wysocki
  2007-04-27 21:49       ` Gautham R Shenoy
@ 2007-04-27 22:09       ` Rafael J. Wysocki
  2007-04-27 22:07         ` Pavel Machek
  1 sibling, 1 reply; 23+ messages in thread
From: Rafael J. Wysocki @ 2007-04-27 22:09 UTC (permalink / raw)
  To: ego
  Cc: Andrew Morton, Ingo Molnar, Oleg Nesterov, Pavel Machek,
	Pekka Enberg, LKML

On Friday, 27 April 2007 23:49, Rafael J. Wysocki wrote:
> On Friday, 27 April 2007 23:40, Gautham R Shenoy wrote:
> > On Fri, Apr 27, 2007 at 05:40:16PM +0200, Rafael J. Wysocki wrote:
> > > From: Rafael J. Wysocki <rjw@sisk.pl>
> > > 
> > > Move all of the freezer-related flags to a separate field in task_struct and
> > > introduce functions to operate them using set_bit() etc.
> > > 
> > > 
> > > Index: linux-2.6.21-rc7-mm2/include/linux/sched.h
> > > ===================================================================
> > > --- linux-2.6.21-rc7-mm2.orig/include/linux/sched.h
> > > +++ linux-2.6.21-rc7-mm2/include/linux/sched.h
> > > @@ -1006,7 +1006,10 @@ struct task_struct {
> > >  	/* Deadlock detection and priority inheritance handling */
> > >  	struct rt_mutex_waiter *pi_blocked_on;
> > >  #endif
> > > -
> > > +#ifdef CONFIG_FREEZER
> > > +	/* Used by the process freezer, defined in freezer.h */
> > > +	unsigned int freezer_flags;
> > 
> > unsigned long freezer_flags; ??
> 
> I guess so.

Still, on x86_64, for example, we'll waste 4 bytes by using 'unsigned long'
here, which I wouldn't like to do.

Is it acceptable to use explicit type casting in set_bit() and friends?

Rafael

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

* Re: [PATCH -mm 2/2] Introduce freezer flags
  2007-04-27 22:07         ` Pavel Machek
@ 2007-04-27 22:56           ` Rafael J. Wysocki
  2007-04-28  7:07             ` Pavel Machek
  0 siblings, 1 reply; 23+ messages in thread
From: Rafael J. Wysocki @ 2007-04-27 22:56 UTC (permalink / raw)
  To: Pavel Machek
  Cc: ego, Andrew Morton, Ingo Molnar, Oleg Nesterov, Pekka Enberg, LKML

On Saturday, 28 April 2007 00:07, Pavel Machek wrote:
> Hi!
> 
> > > > > +#ifdef CONFIG_FREEZER
> > > > > +	/* Used by the process freezer, defined in freezer.h */
> > > > > +	unsigned int freezer_flags;
> > > > 
> > > > unsigned long freezer_flags; ??
> > > 
> > > I guess so.
> > 
> > Still, on x86_64, for example, we'll waste 4 bytes by using 'unsigned long'
> > here, which I wouldn't like to do.
> > 
> > Is it acceptable to use explicit type casting in set_bit() and friends?
> 
> I'm afraid set_bit & friends are only defined on unsigned long.

On x86_64 they are defined on anything, even on huge bitmaps.

> You can cast, but you may run into some nasty surprise... like damaging
> surrounding bytes on 64-bit architectures != x86_64.

Let's use unsigned long, then, but I'm not really happy with that.

---
From: Rafael J. Wysocki <rjw@sisk.pl>

Move all of the freezer-related flags to a separate field in task_struct and
introduce functions to operate them using set_bit() etc.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 Documentation/power/kernel_threads.txt |    2 -
 Documentation/power/swsusp.txt         |    4 +-
 arch/i386/kernel/apm.c                 |    2 -
 drivers/block/loop.c                   |    2 -
 drivers/char/apm-emulation.c           |    6 +--
 drivers/ieee1394/ieee1394_core.c       |    2 -
 drivers/md/md.c                        |    2 -
 drivers/mmc/card/queue.c               |    3 +
 drivers/mtd/mtd_blkdevs.c              |    3 +
 drivers/scsi/libsas/sas_scsi_host.c    |    2 -
 drivers/scsi/scsi_error.c              |    2 -
 drivers/usb/storage/usb.c              |    2 -
 include/asm-arm/thread_info.h          |    2 -
 include/asm-blackfin/thread_info.h     |    2 -
 include/asm-frv/thread_info.h          |    2 -
 include/asm-i386/thread_info.h         |    2 -
 include/asm-ia64/thread_info.h         |    2 -
 include/asm-mips/thread_info.h         |    2 -
 include/asm-powerpc/thread_info.h      |    2 -
 include/asm-sh/thread_info.h           |    2 -
 include/asm-x86_64/thread_info.h       |    2 -
 include/linux/freezer.h                |   63 +++++++++++++++++++++++++++------
 include/linux/sched.h                  |    8 ++--
 kernel/fork.c                          |    5 ++
 kernel/freezer.c                       |   10 ++---
 kernel/kthread.c                       |    3 +
 kernel/rcutorture.c                    |    4 +-
 kernel/sched.c                         |    2 -
 kernel/softirq.c                       |    2 -
 kernel/softlockup.c                    |    2 -
 kernel/workqueue.c                     |    2 -
 31 files changed, 90 insertions(+), 61 deletions(-)

Index: linux-2.6.21-rc7-mm2/include/linux/sched.h
===================================================================
--- linux-2.6.21-rc7-mm2.orig/include/linux/sched.h	2007-04-27 23:20:23.000000000 +0200
+++ linux-2.6.21-rc7-mm2/include/linux/sched.h	2007-04-28 00:45:20.000000000 +0200
@@ -1006,7 +1006,10 @@ struct task_struct {
 	/* Deadlock detection and priority inheritance handling */
 	struct rt_mutex_waiter *pi_blocked_on;
 #endif
-
+#ifdef CONFIG_FREEZER
+	/* Used by the process freezer, defined in freezer.h */
+	unsigned long freezer_flags;
+#endif
 #ifdef CONFIG_DEBUG_MUTEXES
 	/* mutex deadlock detection */
 	struct mutex_waiter *blocked_on;
@@ -1189,8 +1192,6 @@ static inline void put_task_struct(struc
 #define PF_MEMALLOC	0x00000800	/* Allocating memory */
 #define PF_FLUSHER	0x00001000	/* responsible for disk writeback */
 #define PF_USED_MATH	0x00002000	/* if unset the fpu must be initialized before use */
-#define PF_NOFREEZE	0x00008000	/* this thread should not be frozen */
-#define PF_FROZEN	0x00010000	/* frozen for system suspend */
 #define PF_FSTRANS	0x00020000	/* inside a filesystem transaction */
 #define PF_KSWAPD	0x00040000	/* I am kswapd */
 #define PF_SWAPOFF	0x00080000	/* I am in swapoff */
@@ -1202,7 +1203,6 @@ static inline void put_task_struct(struc
 #define PF_SPREAD_SLAB	0x02000000	/* Spread some slab caches over cpuset */
 #define PF_MEMPOLICY	0x10000000	/* Non-default NUMA mempolicy */
 #define PF_MUTEX_TESTER	0x20000000	/* Thread belongs to the rt mutex tester */
-#define PF_FREEZER_SKIP	0x40000000	/* Freezer should not count it as freezeable */
 
 /*
  * Only the _current_ task can read/write to tsk->flags, but other
Index: linux-2.6.21-rc7-mm2/include/asm-arm/thread_info.h
===================================================================
--- linux-2.6.21-rc7-mm2.orig/include/asm-arm/thread_info.h	2007-04-27 23:20:23.000000000 +0200
+++ linux-2.6.21-rc7-mm2/include/asm-arm/thread_info.h	2007-04-27 23:23:57.000000000 +0200
@@ -147,7 +147,6 @@ extern void iwmmxt_task_switch(struct th
 #define TIF_POLLING_NRFLAG	16
 #define TIF_USING_IWMMXT	17
 #define TIF_MEMDIE		18
-#define TIF_FREEZE		19
 
 #define _TIF_NOTIFY_RESUME	(1 << TIF_NOTIFY_RESUME)
 #define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
@@ -155,7 +154,6 @@ extern void iwmmxt_task_switch(struct th
 #define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
 #define _TIF_POLLING_NRFLAG	(1 << TIF_POLLING_NRFLAG)
 #define _TIF_USING_IWMMXT	(1 << TIF_USING_IWMMXT)
-#define _TIF_FREEZE		(1 << TIF_FREEZE)
 
 /*
  * Change these and you break ASM code in entry-common.S
Index: linux-2.6.21-rc7-mm2/include/asm-blackfin/thread_info.h
===================================================================
--- linux-2.6.21-rc7-mm2.orig/include/asm-blackfin/thread_info.h	2007-04-27 23:20:23.000000000 +0200
+++ linux-2.6.21-rc7-mm2/include/asm-blackfin/thread_info.h	2007-04-27 23:23:57.000000000 +0200
@@ -125,7 +125,6 @@ static inline struct thread_info *curren
 					   TIF_NEED_RESCHED */
 #define TIF_MEMDIE              5
 #define TIF_RESTORE_SIGMASK	6	/* restore signal mask in do_signal() */
-#define TIF_FREEZE              7       /* is freezing for suspend */
 
 /* as above, but as bit values */
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
@@ -134,7 +133,6 @@ static inline struct thread_info *curren
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
 #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 #define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
-#define _TIF_FREEZE             (1<<TIF_FREEZE)
 
 #define _TIF_WORK_MASK		0x0000FFFE	/* work to do on interrupt/exception return */
 
Index: linux-2.6.21-rc7-mm2/include/asm-frv/thread_info.h
===================================================================
--- linux-2.6.21-rc7-mm2.orig/include/asm-frv/thread_info.h	2007-04-27 23:20:23.000000000 +0200
+++ linux-2.6.21-rc7-mm2/include/asm-frv/thread_info.h	2007-04-27 23:23:57.000000000 +0200
@@ -116,7 +116,6 @@ register struct thread_info *__current_t
 #define TIF_RESTORE_SIGMASK	6	/* restore signal mask in do_signal() */
 #define TIF_POLLING_NRFLAG	16	/* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_MEMDIE		17	/* OOM killer killed process */
-#define TIF_FREEZE		18	/* freezing for suspend */
 
 #define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
 #define _TIF_NOTIFY_RESUME	(1 << TIF_NOTIFY_RESUME)
@@ -126,7 +125,6 @@ register struct thread_info *__current_t
 #define _TIF_IRET		(1 << TIF_IRET)
 #define _TIF_RESTORE_SIGMASK	(1 << TIF_RESTORE_SIGMASK)
 #define _TIF_POLLING_NRFLAG	(1 << TIF_POLLING_NRFLAG)
-#define _TIF_FREEZE		(1 << TIF_FREEZE)
 
 #define _TIF_WORK_MASK		0x0000FFFE	/* work to do on interrupt/exception return */
 #define _TIF_ALLWORK_MASK	0x0000FFFF	/* work to do on any return to u-space */
Index: linux-2.6.21-rc7-mm2/include/asm-i386/thread_info.h
===================================================================
--- linux-2.6.21-rc7-mm2.orig/include/asm-i386/thread_info.h	2007-04-27 23:20:23.000000000 +0200
+++ linux-2.6.21-rc7-mm2/include/asm-i386/thread_info.h	2007-04-27 23:23:57.000000000 +0200
@@ -136,7 +136,6 @@ static inline struct thread_info *curren
 #define TIF_MEMDIE		16
 #define TIF_DEBUG		17	/* uses debug registers */
 #define TIF_IO_BITMAP		18	/* uses I/O bitmap */
-#define TIF_FREEZE		19	/* is freezing for suspend */
 
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
 #define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
@@ -150,7 +149,6 @@ static inline struct thread_info *curren
 #define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
 #define _TIF_DEBUG		(1<<TIF_DEBUG)
 #define _TIF_IO_BITMAP		(1<<TIF_IO_BITMAP)
-#define _TIF_FREEZE		(1<<TIF_FREEZE)
 
 /* work to do on interrupt/exception return */
 #define _TIF_WORK_MASK \
Index: linux-2.6.21-rc7-mm2/include/asm-ia64/thread_info.h
===================================================================
--- linux-2.6.21-rc7-mm2.orig/include/asm-ia64/thread_info.h	2007-04-27 23:20:23.000000000 +0200
+++ linux-2.6.21-rc7-mm2/include/asm-ia64/thread_info.h	2007-04-27 23:23:57.000000000 +0200
@@ -89,7 +89,6 @@ struct thread_info {
 #define TIF_MEMDIE		17
 #define TIF_MCA_INIT		18	/* this task is processing MCA or INIT */
 #define TIF_DB_DISABLED		19	/* debug trap disabled for fsyscall */
-#define TIF_FREEZE		20	/* is freezing for suspend */
 
 #define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
 #define _TIF_SYSCALL_AUDIT	(1 << TIF_SYSCALL_AUDIT)
@@ -101,7 +100,6 @@ struct thread_info {
 #define _TIF_POLLING_NRFLAG	(1 << TIF_POLLING_NRFLAG)
 #define _TIF_MCA_INIT		(1 << TIF_MCA_INIT)
 #define _TIF_DB_DISABLED	(1 << TIF_DB_DISABLED)
-#define _TIF_FREEZE		(1 << TIF_FREEZE)
 
 /* "work to do on user-return" bits */
 #define TIF_ALLWORK_MASK	(_TIF_NOTIFY_RESUME|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
Index: linux-2.6.21-rc7-mm2/include/asm-mips/thread_info.h
===================================================================
--- linux-2.6.21-rc7-mm2.orig/include/asm-mips/thread_info.h	2007-04-27 23:20:23.000000000 +0200
+++ linux-2.6.21-rc7-mm2/include/asm-mips/thread_info.h	2007-04-27 23:23:57.000000000 +0200
@@ -118,7 +118,6 @@ register struct thread_info *__current_t
 #define TIF_USEDFPU		16	/* FPU was used by this task this quantum (SMP) */
 #define TIF_POLLING_NRFLAG	17	/* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_MEMDIE		18
-#define TIF_FREEZE		19
 #define TIF_SYSCALL_TRACE	31	/* syscall trace active */
 
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
@@ -130,7 +129,6 @@ register struct thread_info *__current_t
 #define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
 #define _TIF_USEDFPU		(1<<TIF_USEDFPU)
 #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
-#define _TIF_FREEZE		(1<<TIF_FREEZE)
 
 /* work to do on interrupt/exception return */
 #define _TIF_WORK_MASK		(0x0000ffef & ~_TIF_SECCOMP)
Index: linux-2.6.21-rc7-mm2/include/asm-powerpc/thread_info.h
===================================================================
--- linux-2.6.21-rc7-mm2.orig/include/asm-powerpc/thread_info.h	2007-04-27 23:20:23.000000000 +0200
+++ linux-2.6.21-rc7-mm2/include/asm-powerpc/thread_info.h	2007-04-27 23:23:57.000000000 +0200
@@ -122,7 +122,6 @@ static inline struct thread_info *curren
 #define TIF_RESTOREALL		12	/* Restore all regs (implies NOERROR) */
 #define TIF_NOERROR		14	/* Force successful syscall return */
 #define TIF_RESTORE_SIGMASK	15	/* Restore signal mask in do_signal */
-#define TIF_FREEZE		16	/* Freezing for suspend */
 
 /* as above, but as bit values */
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
@@ -139,7 +138,6 @@ static inline struct thread_info *curren
 #define _TIF_RESTOREALL		(1<<TIF_RESTOREALL)
 #define _TIF_NOERROR		(1<<TIF_NOERROR)
 #define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
-#define _TIF_FREEZE		(1<<TIF_FREEZE)
 #define _TIF_SYSCALL_T_OR_A	(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP)
 
 #define _TIF_USER_WORK_MASK	(_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | \
Index: linux-2.6.21-rc7-mm2/include/asm-sh/thread_info.h
===================================================================
--- linux-2.6.21-rc7-mm2.orig/include/asm-sh/thread_info.h	2007-04-27 23:20:23.000000000 +0200
+++ linux-2.6.21-rc7-mm2/include/asm-sh/thread_info.h	2007-04-27 23:23:57.000000000 +0200
@@ -115,7 +115,6 @@ static inline struct thread_info *curren
 #define TIF_USEDFPU		16	/* FPU was used by this task this quantum (SMP) */
 #define TIF_POLLING_NRFLAG	17	/* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_MEMDIE		18
-#define TIF_FREEZE		19
 
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
 #define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
@@ -125,7 +124,6 @@ static inline struct thread_info *curren
 #define _TIF_SINGLESTEP		(1<<TIF_SINGLESTEP)
 #define _TIF_USEDFPU		(1<<TIF_USEDFPU)
 #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
-#define _TIF_FREEZE		(1<<TIF_FREEZE)
 
 #define _TIF_WORK_MASK		0x000000FE	/* work to do on interrupt/exception return */
 #define _TIF_ALLWORK_MASK	0x000000FF	/* work to do on any return to u-space */
Index: linux-2.6.21-rc7-mm2/include/asm-x86_64/thread_info.h
===================================================================
--- linux-2.6.21-rc7-mm2.orig/include/asm-x86_64/thread_info.h	2007-04-27 23:20:23.000000000 +0200
+++ linux-2.6.21-rc7-mm2/include/asm-x86_64/thread_info.h	2007-04-27 23:23:57.000000000 +0200
@@ -122,7 +122,6 @@ static inline struct thread_info *stack_
 #define TIF_MEMDIE		20
 #define TIF_DEBUG		21	/* uses debug registers */
 #define TIF_IO_BITMAP		22	/* uses I/O bitmap */
-#define TIF_FREEZE		23	/* is freezing for suspend */
 
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
 #define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
@@ -138,7 +137,6 @@ static inline struct thread_info *stack_
 #define _TIF_ABI_PENDING	(1<<TIF_ABI_PENDING)
 #define _TIF_DEBUG		(1<<TIF_DEBUG)
 #define _TIF_IO_BITMAP		(1<<TIF_IO_BITMAP)
-#define _TIF_FREEZE		(1<<TIF_FREEZE)
 
 /* work to do on interrupt/exception return */
 #define _TIF_WORK_MASK \
Index: linux-2.6.21-rc7-mm2/include/linux/freezer.h
===================================================================
--- linux-2.6.21-rc7-mm2.orig/include/linux/freezer.h	2007-04-27 23:20:23.000000000 +0200
+++ linux-2.6.21-rc7-mm2/include/linux/freezer.h	2007-04-28 00:45:13.000000000 +0200
@@ -3,12 +3,33 @@
 #include <linux/sched.h>
 
 #ifdef CONFIG_FREEZER
+
+/*
+ *	Per task flags used by the freezer
+ *
+ *	They should not be referred to directly outside of this file.
+ */
+#define TFF_NOFREEZE	0	/* task should not be frozen */
+#define TFF_FREEZE	8	/* task should go to the refrigerator ASAP */
+#define TFF_SKIP	9	/* do not count this task as freezable */
+#define TFF_FROZEN	10	/* task is frozen */
+
 /*
  * Check if a process has been frozen
  */
 static inline int frozen(struct task_struct *p)
 {
-	return p->flags & PF_FROZEN;
+	return test_bit(TFF_FROZEN, &p->freezer_flags);
+}
+
+static inline void set_frozen_flag(struct task_struct *p)
+{
+	set_bit(TFF_FROZEN, &p->freezer_flags);
+}
+
+static inline void clear_frozen_flag(struct task_struct *p)
+{
+	clear_bit(TFF_FROZEN, &p->freezer_flags);
 }
 
 /*
@@ -16,7 +37,7 @@ static inline int frozen(struct task_str
  */
 static inline int freezing(struct task_struct *p)
 {
-	return test_tsk_thread_flag(p, TIF_FREEZE);
+	return test_bit(TFF_FREEZE, &p->freezer_flags);
 }
 
 /*
@@ -24,15 +45,31 @@ static inline int freezing(struct task_s
  */
 static inline void freeze(struct task_struct *p)
 {
-	set_tsk_thread_flag(p, TIF_FREEZE);
+	set_bit(TFF_FREEZE, &p->freezer_flags);
+}
+
+/*
+ * Cancel the previous 'freeze' request
+ */
+static inline void clear_freeze_flag(struct task_struct *p)
+{
+	clear_bit(TFF_FREEZE, &p->freezer_flags);
+}
+
+/*
+ * Check if the task wants to be exempted from freezing
+ */
+static inline int freezer_should_exempt(struct task_struct *p)
+{
+	return test_bit(TFF_NOFREEZE, &p->freezer_flags);
 }
 
 /*
- * Sometimes we may need to cancel the previous 'freeze' request
+ * Tell the freezer to exempt this task from freezing
  */
-static inline void do_not_freeze(struct task_struct *p)
+static inline void freezer_exempt(struct task_struct *p)
 {
-	clear_tsk_thread_flag(p, TIF_FREEZE);
+	set_bit(TFF_NOFREEZE, &p->freezer_flags);
 }
 
 /*
@@ -48,12 +85,12 @@ static inline int thaw_process(struct ta
 {
 	task_lock(p);
 	if (frozen(p)) {
-		p->flags &= ~PF_FROZEN;
+		clear_frozen_flag(p);
 		task_unlock(p);
 		wake_up_process(p);
 		return 1;
 	}
-	clear_tsk_thread_flag(p, TIF_FREEZE);
+	clear_freeze_flag(p);
 	task_unlock(p);
 	return 0;
 }
@@ -92,7 +129,7 @@ static inline int try_to_freeze(void)
 static inline void freezer_do_not_count(void)
 {
 	if (current->mm)
-		current->flags |= PF_FREEZER_SKIP;
+		set_bit(TFF_SKIP, &current->freezer_flags);
 }
 
 /*
@@ -102,7 +139,7 @@ static inline void freezer_do_not_count(
 static inline void freezer_count(void)
 {
 	if (current->mm) {
-		current->flags &= ~PF_FREEZER_SKIP;
+		clear_bit(TFF_SKIP, &current->freezer_flags);
 		try_to_freeze();
 	}
 }
@@ -112,13 +149,17 @@ static inline void freezer_count(void)
  */
 static inline int freezer_should_skip(struct task_struct *p)
 {
-	return !!(p->flags & PF_FREEZER_SKIP);
+	return test_bit(TFF_SKIP, &current->freezer_flags);
 }
 
 #else
 static inline int frozen(struct task_struct *p) { return 0; }
+static inline void set_frozen_flag(struct task_struct *p) {}
+static inline void clear_frozen_flag(struct task_struct *p) {}
 static inline int freezing(struct task_struct *p) { return 0; }
 static inline void freeze(struct task_struct *p) { BUG(); }
+static inline int freezer_should_exempt(struct task_struct *p) { return 0; }
+static inline void freezer_exempt(struct task_struct *p) {}
 static inline int thaw_process(struct task_struct *p) { return 1; }
 
 static inline void refrigerator(void) {}
Index: linux-2.6.21-rc7-mm2/kernel/sched.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/kernel/sched.c	2007-04-27 23:20:23.000000000 +0200
+++ linux-2.6.21-rc7-mm2/kernel/sched.c	2007-04-27 23:23:57.000000000 +0200
@@ -5478,7 +5478,7 @@ migration_call(struct notifier_block *nf
 		p = kthread_create(migration_thread, hcpu, "migration/%d",cpu);
 		if (IS_ERR(p))
 			return NOTIFY_BAD;
-		p->flags |= PF_NOFREEZE;
+		freezer_exempt(p);
 		kthread_bind(p, cpu);
 		/* Must be high prio: stop_machine expects to yield to it. */
 		rq = task_rq_lock(p, &flags);
Index: linux-2.6.21-rc7-mm2/arch/i386/kernel/apm.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/arch/i386/kernel/apm.c	2007-04-27 23:20:23.000000000 +0200
+++ linux-2.6.21-rc7-mm2/arch/i386/kernel/apm.c	2007-04-27 23:23:57.000000000 +0200
@@ -2313,7 +2313,7 @@ static int __init apm_init(void)
 		remove_proc_entry("apm", NULL);
 		return err;
 	}
-	kapmd_task->flags |= PF_NOFREEZE;
+	freezer_exempt(kapmd_task);
 	wake_up_process(kapmd_task);
 
 	if (num_online_cpus() > 1 && !smp ) {
Index: linux-2.6.21-rc7-mm2/drivers/block/loop.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/drivers/block/loop.c	2007-04-27 23:20:23.000000000 +0200
+++ linux-2.6.21-rc7-mm2/drivers/block/loop.c	2007-04-27 23:23:57.000000000 +0200
@@ -582,7 +582,7 @@ static int loop_thread(void *data)
 	 * hence, it mustn't be stopped at all
 	 * because it could be indirectly used during suspension
 	 */
-	current->flags |= PF_NOFREEZE;
+	freezer_exempt(current);
 
 	set_user_nice(current, -20);
 
Index: linux-2.6.21-rc7-mm2/drivers/char/apm-emulation.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/drivers/char/apm-emulation.c	2007-04-27 23:20:23.000000000 +0200
+++ linux-2.6.21-rc7-mm2/drivers/char/apm-emulation.c	2007-04-27 23:23:57.000000000 +0200
@@ -336,7 +336,7 @@ apm_ioctl(struct inode * inode, struct f
 			 * threads.
 			 */
 			flags = current->flags;
-			current->flags |= PF_NOFREEZE;
+			freezer_exempt(current);
 
 			wait_event(apm_suspend_waitqueue,
 				   as->suspend_state == SUSPEND_DONE);
@@ -372,7 +372,7 @@ apm_ioctl(struct inode * inode, struct f
 			 * threads.
 			 */
 			flags = current->flags;
-			current->flags |= PF_NOFREEZE;
+			freezer_exempt(current);
 
 			wait_event_interruptible(apm_suspend_waitqueue,
 					 as->suspend_state == SUSPEND_DONE);
@@ -601,7 +601,7 @@ static int __init apm_init(void)
 		kapmd_tsk = NULL;
 		return ret;
 	}
-	kapmd_tsk->flags |= PF_NOFREEZE;
+	freezer_exempt(kapmd_tsk);
 	wake_up_process(kapmd_tsk);
 
 #ifdef CONFIG_PROC_FS
Index: linux-2.6.21-rc7-mm2/drivers/ieee1394/ieee1394_core.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/drivers/ieee1394/ieee1394_core.c	2007-04-27 23:20:23.000000000 +0200
+++ linux-2.6.21-rc7-mm2/drivers/ieee1394/ieee1394_core.c	2007-04-27 23:23:57.000000000 +0200
@@ -1134,7 +1134,7 @@ static int hpsbpkt_thread(void *__hi)
 	struct list_head tmp;
 	int may_schedule;
 
-	current->flags |= PF_NOFREEZE;
+	freezer_exempt(current);
 
 	while (!kthread_should_stop()) {
 
Index: linux-2.6.21-rc7-mm2/drivers/md/md.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/drivers/md/md.c	2007-04-27 23:20:23.000000000 +0200
+++ linux-2.6.21-rc7-mm2/drivers/md/md.c	2007-04-27 23:23:57.000000000 +0200
@@ -4541,7 +4541,7 @@ static int md_thread(void * arg)
 	 * many dirty RAID5 blocks.
 	 */
 
-	current->flags |= PF_NOFREEZE;
+	freezer_exempt(current);
 	while (!kthread_should_stop()) {
 
 		/* We need to wait INTERRUPTIBLE so that
Index: linux-2.6.21-rc7-mm2/drivers/mmc/card/queue.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/drivers/mmc/card/queue.c	2007-04-27 23:20:23.000000000 +0200
+++ linux-2.6.21-rc7-mm2/drivers/mmc/card/queue.c	2007-04-27 23:23:57.000000000 +0200
@@ -66,7 +66,8 @@ static int mmc_queue_thread(void *d)
 	 * Set iothread to ensure that we aren't put to sleep by
 	 * the process freezing.  We handle suspension ourselves.
 	 */
-	current->flags |= PF_MEMALLOC|PF_NOFREEZE;
+	current->flags |= PF_MEMALLOC;
+	freezer_exempt(current);
 
 	down(&mq->thread_sem);
 	do {
Index: linux-2.6.21-rc7-mm2/drivers/mtd/mtd_blkdevs.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/drivers/mtd/mtd_blkdevs.c	2007-04-27 23:20:23.000000000 +0200
+++ linux-2.6.21-rc7-mm2/drivers/mtd/mtd_blkdevs.c	2007-04-27 23:23:57.000000000 +0200
@@ -81,7 +81,8 @@ static int mtd_blktrans_thread(void *arg
 	struct request_queue *rq = tr->blkcore_priv->rq;
 
 	/* we might get involved when memory gets low, so use PF_MEMALLOC */
-	current->flags |= PF_MEMALLOC | PF_NOFREEZE;
+	current->flags |= PF_MEMALLOC;
+	freezer_exempt(current);
 
 	spin_lock_irq(rq->queue_lock);
 	while (!kthread_should_stop()) {
Index: linux-2.6.21-rc7-mm2/drivers/scsi/libsas/sas_scsi_host.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/drivers/scsi/libsas/sas_scsi_host.c	2007-04-27 23:20:23.000000000 +0200
+++ linux-2.6.21-rc7-mm2/drivers/scsi/libsas/sas_scsi_host.c	2007-04-27 23:23:57.000000000 +0200
@@ -871,7 +871,7 @@ static int sas_queue_thread(void *_sas_h
 	struct sas_ha_struct *sas_ha = _sas_ha;
 	struct scsi_core *core = &sas_ha->core;
 
-	current->flags |= PF_NOFREEZE;
+	freezer_exempt(current);
 
 	complete(&queue_th_comp);
 
Index: linux-2.6.21-rc7-mm2/drivers/scsi/scsi_error.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/drivers/scsi/scsi_error.c	2007-04-27 23:20:23.000000000 +0200
+++ linux-2.6.21-rc7-mm2/drivers/scsi/scsi_error.c	2007-04-27 23:23:57.000000000 +0200
@@ -1536,7 +1536,7 @@ int scsi_error_handler(void *data)
 {
 	struct Scsi_Host *shost = data;
 
-	current->flags |= PF_NOFREEZE;
+	freezer_exempt(current);
 
 	/*
 	 * We use TASK_INTERRUPTIBLE so that the thread is not
Index: linux-2.6.21-rc7-mm2/drivers/usb/storage/usb.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/drivers/usb/storage/usb.c	2007-04-27 23:20:23.000000000 +0200
+++ linux-2.6.21-rc7-mm2/drivers/usb/storage/usb.c	2007-04-27 23:23:57.000000000 +0200
@@ -301,7 +301,7 @@ static int usb_stor_control_thread(void 
 	struct us_data *us = (struct us_data *)__us;
 	struct Scsi_Host *host = us_to_host(us);
 
-	current->flags |= PF_NOFREEZE;
+	freezer_exempt(current);
 
 	for(;;) {
 		try_to_freeze();
Index: linux-2.6.21-rc7-mm2/kernel/fork.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/kernel/fork.c	2007-04-27 23:20:23.000000000 +0200
+++ linux-2.6.21-rc7-mm2/kernel/fork.c	2007-04-27 23:23:57.000000000 +0200
@@ -921,11 +921,14 @@ static inline void copy_flags(unsigned l
 {
 	unsigned long new_flags = p->flags;
 
-	new_flags &= ~(PF_SUPERPRIV | PF_NOFREEZE);
+	new_flags &= ~PF_SUPERPRIV;
 	new_flags |= PF_FORKNOEXEC;
 	if (!(clone_flags & CLONE_PTRACE))
 		p->ptrace = 0;
 	p->flags = new_flags;
+#ifdef CONFIG_FREEZER
+	p->freezer_flags = 0;
+#endif
 }
 
 asmlinkage long sys_set_tid_address(int __user *tidptr)
Index: linux-2.6.21-rc7-mm2/kernel/rcutorture.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/kernel/rcutorture.c	2007-04-27 23:20:23.000000000 +0200
+++ linux-2.6.21-rc7-mm2/kernel/rcutorture.c	2007-04-27 23:23:57.000000000 +0200
@@ -559,7 +559,7 @@ rcu_torture_fakewriter(void *arg)
 
 	VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task started");
 	set_user_nice(current, 19);
-	current->flags |= PF_NOFREEZE;
+	freezer_exempt(current);
 
 	do {
 		schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10);
@@ -590,7 +590,7 @@ rcu_torture_reader(void *arg)
 
 	VERBOSE_PRINTK_STRING("rcu_torture_reader task started");
 	set_user_nice(current, 19);
-	current->flags |= PF_NOFREEZE;
+	freezer_exempt(current);
 
 	do {
 		idx = cur_ops->readlock();
Index: linux-2.6.21-rc7-mm2/kernel/softirq.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/kernel/softirq.c	2007-04-27 23:20:23.000000000 +0200
+++ linux-2.6.21-rc7-mm2/kernel/softirq.c	2007-04-27 23:23:57.000000000 +0200
@@ -490,7 +490,7 @@ void __init softirq_init(void)
 static int ksoftirqd(void * __bind_cpu)
 {
 	set_user_nice(current, 15);
-	current->flags |= PF_NOFREEZE;
+	freezer_exempt(current);
 
 	set_current_state(TASK_INTERRUPTIBLE);
 
Index: linux-2.6.21-rc7-mm2/kernel/softlockup.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/kernel/softlockup.c	2007-04-27 23:20:23.000000000 +0200
+++ linux-2.6.21-rc7-mm2/kernel/softlockup.c	2007-04-27 23:23:57.000000000 +0200
@@ -117,7 +117,7 @@ static int watchdog(void * __bind_cpu)
 	struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
 
 	sched_setscheduler(current, SCHED_FIFO, &param);
-	current->flags |= PF_NOFREEZE;
+	freezer_exempt(current);
 
 	/* initialize timestamp */
 	touch_softlockup_watchdog();
Index: linux-2.6.21-rc7-mm2/kernel/workqueue.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/kernel/workqueue.c	2007-04-27 23:20:23.000000000 +0200
+++ linux-2.6.21-rc7-mm2/kernel/workqueue.c	2007-04-27 23:23:57.000000000 +0200
@@ -291,7 +291,7 @@ static int worker_thread(void *__cwq)
 	DEFINE_WAIT(wait);
 
 	if (!cwq->wq->freezeable)
-		current->flags |= PF_NOFREEZE;
+		freezer_exempt(current);
 
 	for (;;) {
 		prepare_to_wait(&cwq->more_work, &wait, TASK_INTERRUPTIBLE);
Index: linux-2.6.21-rc7-mm2/kernel/freezer.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/kernel/freezer.c	2007-04-27 23:20:23.000000000 +0200
+++ linux-2.6.21-rc7-mm2/kernel/freezer.c	2007-04-27 23:54:02.000000000 +0200
@@ -26,7 +26,7 @@
 static inline int freezeable(struct task_struct * p)
 {
 	if ((p == current) ||
-	    (p->flags & PF_NOFREEZE) ||
+	    freezer_should_exempt(p) ||
 	    (p->exit_state != 0))
 		return 0;
 	return 1;
@@ -37,11 +37,11 @@ static inline int freezeable(struct task
  */
 static inline void frozen_process(void)
 {
-	if (!unlikely(current->flags & PF_NOFREEZE)) {
-		current->flags |= PF_FROZEN;
+	if (!unlikely(freezer_should_exempt(current))) {
+		set_frozen_flag(current);
 		wmb();
 	}
-	clear_tsk_thread_flag(current, TIF_FREEZE);
+	clear_freeze_flag(current);
 }
 
 /* Refrigerator is place where frozen processes are stored :-). */
@@ -100,7 +100,7 @@ static void cancel_freezing(struct task_
 
 	if (freezing(p)) {
 		pr_debug("  clean up: %s\n", p->comm);
-		do_not_freeze(p);
+		clear_freeze_flag(p);
 		spin_lock_irqsave(&p->sighand->siglock, flags);
 		recalc_sigpending_tsk(p);
 		spin_unlock_irqrestore(&p->sighand->siglock, flags);
Index: linux-2.6.21-rc7-mm2/Documentation/power/kernel_threads.txt
===================================================================
--- linux-2.6.21-rc7-mm2.orig/Documentation/power/kernel_threads.txt	2007-04-27 23:20:23.000000000 +0200
+++ linux-2.6.21-rc7-mm2/Documentation/power/kernel_threads.txt	2007-04-27 23:23:57.000000000 +0200
@@ -32,7 +32,7 @@ like this:
 	 */
 	daemonize("usb-storage");
 
-	current->flags |= PF_NOFREEZE;
+	freezer_exempt(current);
 
 from drivers/usb/storage/usb.c::usb_stor_control_thread()
 
Index: linux-2.6.21-rc7-mm2/Documentation/power/swsusp.txt
===================================================================
--- linux-2.6.21-rc7-mm2.orig/Documentation/power/swsusp.txt	2007-04-27 23:20:23.000000000 +0200
+++ linux-2.6.21-rc7-mm2/Documentation/power/swsusp.txt	2007-04-27 23:23:57.000000000 +0200
@@ -152,8 +152,8 @@ add:
        try_to_freeze();
 
 If the thread is needed for writing the image to storage, you should
-instead set the PF_NOFREEZE process flag when creating the thread (and
-be very careful).
+instead use freezer_exempt() to mark the thread as nonfreezable when creating
+it (and be very careful).
 
 
 Q: What is the difference between "platform" and "shutdown"?
Index: linux-2.6.21-rc7-mm2/kernel/kthread.c
===================================================================
--- linux-2.6.21-rc7-mm2.orig/kernel/kthread.c	2007-04-27 23:20:23.000000000 +0200
+++ linux-2.6.21-rc7-mm2/kernel/kthread.c	2007-04-27 23:23:57.000000000 +0200
@@ -13,6 +13,7 @@
 #include <linux/file.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/freezer.h>
 #include <asm/semaphore.h>
 
 static DEFINE_SPINLOCK(kthread_create_lock);
@@ -232,7 +233,7 @@ int kthreadd(void *unused)
 	/* Setup a clean context for our children to inherit. */
 	kthreadd_setup();
 
-	current->flags |= PF_NOFREEZE;
+	freezer_exempt(current);
 
 	for (;;) {
 		set_current_state(TASK_INTERRUPTIBLE);

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

* [PATCH -mm] Allow selective freezing of the system for different events
  2007-04-27 15:40 ` [PATCH -mm 2/2] Introduce freezer flags Rafael J. Wysocki
  2007-04-27 16:19   ` Sam Ravnborg
  2007-04-27 21:40   ` Gautham R Shenoy
@ 2007-04-28  1:34   ` Gautham R Shenoy
  2007-04-28  6:22     ` Andrew Morton
  2007-04-29 17:51     ` Rafael J. Wysocki
  2 siblings, 2 replies; 23+ messages in thread
From: Gautham R Shenoy @ 2007-04-28  1:34 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Andrew Morton, Ingo Molnar, Oleg Nesterov, Pavel Machek,
	Pekka Enberg, LKML

This patch
* Provides an interface to selectively freeze the system for different events.
* Allows tasks to exempt themselves or other tasks from specific freeze
  events.
* Allow nesting of freezer calls. For eg:

	freeze_processes(EVENT_A);
	/* Do something with respect to event A */
	.
	.
	.
	freeze_processes(EVENT_B);
	/* Do something with respect to event B */
	.
	.
	.
	thaw_processes(EVENT_B);
	.
	.
	.
	thaw_processes(EVENT_B);

This type of behaviour would be required when cpu hotplug would start
using the process freezer, where EVENT_A would be SUSPEND and EVENT_B
would be HOTPLUG_CPU.

This patch applies on the top of 2.6.21-rc7-mm2 + Rafael's freezer
changes from http://lkml.org/lkml/2007/4/27/302.

Signed-off-by: Gautham R Shenoy <ego@in.ibm.com>
---
 arch/i386/kernel/apm.c              |    2 -
 drivers/block/loop.c                |    2 -
 drivers/char/apm-emulation.c        |    6 +--
 drivers/ieee1394/ieee1394_core.c    |    2 -
 drivers/md/md.c                     |    2 -
 drivers/mmc/card/queue.c            |    2 -
 drivers/mtd/mtd_blkdevs.c           |    2 -
 drivers/scsi/libsas/sas_scsi_host.c |    2 -
 drivers/scsi/scsi_error.c           |    2 -
 drivers/usb/storage/usb.c           |    2 -
 include/linux/freezer.h             |   44 +++++++++++++++++++-----
 kernel/freezer.c                    |   64 ++++++++++++++++++++++++++++++------
 kernel/kprobes.c                    |    4 +-
 kernel/kthread.c                    |    2 -
 kernel/power/disk.c                 |    4 +-
 kernel/power/main.c                 |    8 ++--
 kernel/power/user.c                 |    6 +--
 kernel/rcutorture.c                 |    4 +-
 kernel/sched.c                      |    2 -
 kernel/softirq.c                    |    2 -
 kernel/softlockup.c                 |    2 -
 kernel/workqueue.c                  |    2 -
 22 files changed, 119 insertions(+), 49 deletions(-)

Index: linux-2.6.21-rc7/include/linux/freezer.h
===================================================================
--- linux-2.6.21-rc7.orig/include/linux/freezer.h
+++ linux-2.6.21-rc7/include/linux/freezer.h
@@ -4,17 +4,27 @@
 
 #ifdef CONFIG_FREEZER
 
+
 /*
  *	Per task flags used by the freezer
  *
  *	They should not be referred to directly outside of this file.
  */
-#define TFF_NOFREEZE	0	/* task should not be frozen */
+#define TFF_FE_SUSPEND	0	/* Do not freeze task for software suspend */
+#define TFF_FE_KPROBES	1	/* Do not freeze task for kprobes */
 #define TFF_FREEZE	8	/* task should go to the refrigerator ASAP */
 #define TFF_SKIP	9	/* do not count this task as freezable */
 #define TFF_FROZEN	10	/* task is frozen */
 
 /*
+ * Codes of different events which use the freezer
+ * These are the only flags that can be referred outside this file
+ */
+#define FE_SUSPEND	(1 << TFF_FE_SUSPEND) /* Software Suspend */
+#define FE_KPROBES	(1 << TFF_FE_KPROBES)	/* Kprobes */
+#define FE_ALL		(FE_SUSPEND | FE_KPROBES) /* All events using freezer */
+
+/*
  * Check if a process has been frozen
  */
 static inline int frozen(struct task_struct *p)
@@ -57,19 +67,29 @@ static inline void clear_freeze_flag(str
 }
 
 /*
- * Check if the task wants to be exempted from freezing
+ * Check if the task wants to be exempted from freezing for
+ * freeze_event.
  */
-static inline int freezer_should_exempt(struct task_struct *p)
+static inline int freezer_should_exempt(struct task_struct *p,
+					unsigned long freeze_event)
 {
-	return test_bit(TFF_NOFREEZE, &p->freezer_flags);
+	return p->freezer_flags & freeze_event;
 }
 
 /*
  * Tell the freezer to exempt this task from freezing
+ * for events in freeze_event_mask.
  */
-static inline void freezer_exempt(struct task_struct *p)
+static inline void freezer_exempt(struct task_struct *p,
+				  unsigned long freeze_event_mask)
+{
+	atomic_set_mask(freeze_event_mask, &p->freezer_flags);
+}
+
+/* Returns the mask of the events for which this process is freezeable */
+static inline unsigned long freezeable_event_mask(struct task_struct *p)
 {
-	set_bit(TFF_NOFREEZE, &p->freezer_flags);
+	return ~p->freezer_flags & FE_ALL;
 }
 
 /*
@@ -96,8 +116,8 @@ static inline int thaw_process(struct ta
 }
 
 extern void refrigerator(void);
-extern int freeze_processes(void);
-extern void thaw_processes(void);
+extern int freeze_processes(unsigned long freeze_event);
+extern void thaw_processes(unsigned long freeze_event);
 
 static inline int try_to_freeze(void)
 {
@@ -160,11 +180,15 @@ static inline int freezing(struct task_s
 static inline void freeze(struct task_struct *p) { BUG(); }
 static inline int freezer_should_exempt(struct task_struct *p) { return 0; }
 static inline void freezer_exempt(struct task_struct *p) {}
+static inline unsigned long freezeable_event_mask(struct task_struct *p)
+{
+	return 0;
+}
 static inline int thaw_process(struct task_struct *p) { return 1; }
 
 static inline void refrigerator(void) {}
-static inline int freeze_processes(void) { BUG(); return 0; }
-static inline void thaw_processes(void) {}
+static inline int freeze_processes(unsigned long) { BUG(); return 0; }
+static inline void thaw_processes(unsigned long) {}
 
 static inline int try_to_freeze(void) { return 0; }
 
Index: linux-2.6.21-rc7/kernel/freezer.c
===================================================================
--- linux-2.6.21-rc7.orig/kernel/freezer.c
+++ linux-2.6.21-rc7/kernel/freezer.c
@@ -23,21 +23,44 @@
 #define FREEZER_KERNEL_THREADS 0
 #define FREEZER_USER_SPACE 1
 
+static DEFINE_MUTEX(freezer_mutex);
+/* Mask of the events for which the system is currently frozen */
+unsigned long system_frozen_event_mask;
+/* The event for which the freeze request has been raised */
+unsigned long current_freezer_event;
+
 static inline int freezeable(struct task_struct * p)
 {
 	if ((p == current) ||
-	    freezer_should_exempt(p) ||
+	    freezer_should_exempt(p, current_freezer_event) ||
 	    (p->exit_state != 0))
 		return 0;
 	return 1;
 }
 
+/* Returns the mask of events for which p is currently frozen */
+static inline unsigned long process_frozen_event_mask(struct task_struct *p)
+{
+	return (freezeable_event_mask(p) & system_frozen_event_mask);
+}
+
+static inline int thawable(struct task_struct *p)
+{
+	if (!freezeable(p))
+		return 0;
+
+	/* Thaw p iff it is frozen for current_freezer_event alone */
+	 if (process_frozen_event_mask(p) & ~current_freezer_event)
+	 	return 0;
+
+	return 1;
+}
 /*
  * freezing is complete, mark current process as frozen
  */
 static inline void frozen_process(void)
 {
-	if (!unlikely(freezer_should_exempt(current))) {
+	if (!unlikely(freezer_should_exempt(current, current_freezer_event))) {
 		set_frozen_flag(current);
 		wmb();
 	}
@@ -185,26 +208,39 @@ static unsigned int try_to_freeze_tasks(
 /**
  *	freeze_processes - tell processes to enter the refrigerator
  *
+ *	@freeze_event : Event that's requesting the services
+ *		        of the process freezer to freeze the system
+ *
  *	Returns 0 on success, or the number of processes that didn't freeze,
  *	although they were told to.
  */
-int freeze_processes(void)
+int freeze_processes(unsigned long freeze_event)
 {
-	unsigned int nr_unfrozen;
+	unsigned int nr_unfrozen = 0;
+
+	mutex_lock(&freezer_mutex);
+	if (system_frozen_event_mask & freeze_event)
+		goto out;
+
+	current_freezer_event = freeze_event;
 
 	printk("Stopping tasks ... ");
 	nr_unfrozen = try_to_freeze_tasks(FREEZER_USER_SPACE);
 	if (nr_unfrozen)
-		return nr_unfrozen;
+		goto out;
 
 	sys_sync();
 	nr_unfrozen = try_to_freeze_tasks(FREEZER_KERNEL_THREADS);
 	if (nr_unfrozen)
-		return nr_unfrozen;
+		goto out;
 
+	system_frozen_event_mask |= current_freezer_event;
 	printk("done.\n");
 	BUG_ON(in_atomic());
-	return 0;
+out:
+	current_freezer_event = 0;
+	mutex_unlock(&freezer_mutex);
+	return nr_unfrozen;
 }
 
 static void thaw_tasks(int thaw_user_space)
@@ -213,7 +249,7 @@ static void thaw_tasks(int thaw_user_spa
 
 	read_lock(&tasklist_lock);
 	do_each_thread(g, p) {
-		if (!freezeable(p))
+		if (!thawable(p))
 			continue;
 
 		if (is_user_space(p) == !thaw_user_space)
@@ -224,13 +260,23 @@ static void thaw_tasks(int thaw_user_spa
 	read_unlock(&tasklist_lock);
 }
 
-void thaw_processes(void)
+void thaw_processes(unsigned long thaw_event)
 {
+	mutex_lock(&freezer_mutex);
+	if (!(system_frozen_event_mask & thaw_event)) {
+		WARN_ON(1);
+		goto out;
+	}
+	current_freezer_event = thaw_event;
 	printk("Restarting tasks ... ");
 	thaw_tasks(FREEZER_KERNEL_THREADS);
 	thaw_tasks(FREEZER_USER_SPACE);
+	system_frozen_event_mask &= ~current_freezer_event;
 	schedule();
 	printk("done.\n");
+out:
+	current_freezer_event = 0;
+	mutex_unlock(&freezer_mutex);
 }
 
 EXPORT_SYMBOL(refrigerator);
Index: linux-2.6.21-rc7/arch/i386/kernel/apm.c
===================================================================
--- linux-2.6.21-rc7.orig/arch/i386/kernel/apm.c
+++ linux-2.6.21-rc7/arch/i386/kernel/apm.c
@@ -2313,7 +2313,7 @@ static int __init apm_init(void)
 		remove_proc_entry("apm", NULL);
 		return err;
 	}
-	freezer_exempt(kapmd_task);
+	freezer_exempt(kapmd_task, FE_ALL);
 	wake_up_process(kapmd_task);
 
 	if (num_online_cpus() > 1 && !smp ) {
Index: linux-2.6.21-rc7/drivers/block/loop.c
===================================================================
--- linux-2.6.21-rc7.orig/drivers/block/loop.c
+++ linux-2.6.21-rc7/drivers/block/loop.c
@@ -582,7 +582,7 @@ static int loop_thread(void *data)
 	 * hence, it mustn't be stopped at all
 	 * because it could be indirectly used during suspension
 	 */
-	freezer_exempt(current);
+	freezer_exempt(current, FE_ALL);
 
 	set_user_nice(current, -20);
 
Index: linux-2.6.21-rc7/drivers/char/apm-emulation.c
===================================================================
--- linux-2.6.21-rc7.orig/drivers/char/apm-emulation.c
+++ linux-2.6.21-rc7/drivers/char/apm-emulation.c
@@ -336,7 +336,7 @@ apm_ioctl(struct inode * inode, struct f
 			 * threads.
 			 */
 			flags = current->flags;
-			freezer_exempt(current);
+			freezer_exempt(current, FE_ALL);
 
 			wait_event(apm_suspend_waitqueue,
 				   as->suspend_state == SUSPEND_DONE);
@@ -372,7 +372,7 @@ apm_ioctl(struct inode * inode, struct f
 			 * threads.
 			 */
 			flags = current->flags;
-			freezer_exempt(current);
+			freezer_exempt(current, FE_ALL);
 
 			wait_event_interruptible(apm_suspend_waitqueue,
 					 as->suspend_state == SUSPEND_DONE);
@@ -601,7 +601,7 @@ static int __init apm_init(void)
 		kapmd_tsk = NULL;
 		return ret;
 	}
-	freezer_exempt(kapmd_tsk);
+	freezer_exempt(kapmd_tsk, FE_ALL);
 	wake_up_process(kapmd_tsk);
 
 #ifdef CONFIG_PROC_FS
Index: linux-2.6.21-rc7/drivers/ieee1394/ieee1394_core.c
===================================================================
--- linux-2.6.21-rc7.orig/drivers/ieee1394/ieee1394_core.c
+++ linux-2.6.21-rc7/drivers/ieee1394/ieee1394_core.c
@@ -1134,7 +1134,7 @@ static int hpsbpkt_thread(void *__hi)
 	struct list_head tmp;
 	int may_schedule;
 
-	freezer_exempt(current);
+	freezer_exempt(current, FE_ALL);
 
 	while (!kthread_should_stop()) {
 
Index: linux-2.6.21-rc7/drivers/md/md.c
===================================================================
--- linux-2.6.21-rc7.orig/drivers/md/md.c
+++ linux-2.6.21-rc7/drivers/md/md.c
@@ -4541,7 +4541,7 @@ static int md_thread(void * arg)
 	 * many dirty RAID5 blocks.
 	 */
 
-	freezer_exempt(current);
+	freezer_exempt(current, FE_ALL);
 	while (!kthread_should_stop()) {
 
 		/* We need to wait INTERRUPTIBLE so that
Index: linux-2.6.21-rc7/drivers/mmc/card/queue.c
===================================================================
--- linux-2.6.21-rc7.orig/drivers/mmc/card/queue.c
+++ linux-2.6.21-rc7/drivers/mmc/card/queue.c
@@ -67,7 +67,7 @@ static int mmc_queue_thread(void *d)
 	 * the process freezing.  We handle suspension ourselves.
 	 */
 	current->flags |= PF_MEMALLOC;
-	freezer_exempt(current);
+	freezer_exempt(current, FE_ALL);
 
 	down(&mq->thread_sem);
 	do {
Index: linux-2.6.21-rc7/drivers/mtd/mtd_blkdevs.c
===================================================================
--- linux-2.6.21-rc7.orig/drivers/mtd/mtd_blkdevs.c
+++ linux-2.6.21-rc7/drivers/mtd/mtd_blkdevs.c
@@ -82,7 +82,7 @@ static int mtd_blktrans_thread(void *arg
 
 	/* we might get involved when memory gets low, so use PF_MEMALLOC */
 	current->flags |= PF_MEMALLOC;
-	freezer_exempt(current);
+	freezer_exempt(current, FE_ALL);
 
 	spin_lock_irq(rq->queue_lock);
 	while (!kthread_should_stop()) {
Index: linux-2.6.21-rc7/drivers/scsi/libsas/sas_scsi_host.c
===================================================================
--- linux-2.6.21-rc7.orig/drivers/scsi/libsas/sas_scsi_host.c
+++ linux-2.6.21-rc7/drivers/scsi/libsas/sas_scsi_host.c
@@ -871,7 +871,7 @@ static int sas_queue_thread(void *_sas_h
 	struct sas_ha_struct *sas_ha = _sas_ha;
 	struct scsi_core *core = &sas_ha->core;
 
-	freezer_exempt(current);
+	freezer_exempt(current, FE_ALL);
 
 	complete(&queue_th_comp);
 
Index: linux-2.6.21-rc7/drivers/scsi/scsi_error.c
===================================================================
--- linux-2.6.21-rc7.orig/drivers/scsi/scsi_error.c
+++ linux-2.6.21-rc7/drivers/scsi/scsi_error.c
@@ -1536,7 +1536,7 @@ int scsi_error_handler(void *data)
 {
 	struct Scsi_Host *shost = data;
 
-	freezer_exempt(current);
+	freezer_exempt(current, FE_ALL);
 
 	/*
 	 * We use TASK_INTERRUPTIBLE so that the thread is not
Index: linux-2.6.21-rc7/drivers/usb/storage/usb.c
===================================================================
--- linux-2.6.21-rc7.orig/drivers/usb/storage/usb.c
+++ linux-2.6.21-rc7/drivers/usb/storage/usb.c
@@ -301,7 +301,7 @@ static int usb_stor_control_thread(void 
 	struct us_data *us = (struct us_data *)__us;
 	struct Scsi_Host *host = us_to_host(us);
 
-	freezer_exempt(current);
+	freezer_exempt(current, FE_ALL);
 
 	for(;;) {
 		try_to_freeze();
Index: linux-2.6.21-rc7/kernel/kthread.c
===================================================================
--- linux-2.6.21-rc7.orig/kernel/kthread.c
+++ linux-2.6.21-rc7/kernel/kthread.c
@@ -233,7 +233,7 @@ int kthreadd(void *unused)
 	/* Setup a clean context for our children to inherit. */
 	kthreadd_setup();
 
-	freezer_exempt(current);
+	freezer_exempt(current, FE_ALL);
 
 	for (;;) {
 		set_current_state(TASK_INTERRUPTIBLE);
Index: linux-2.6.21-rc7/kernel/rcutorture.c
===================================================================
--- linux-2.6.21-rc7.orig/kernel/rcutorture.c
+++ linux-2.6.21-rc7/kernel/rcutorture.c
@@ -559,7 +559,7 @@ rcu_torture_fakewriter(void *arg)
 
 	VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task started");
 	set_user_nice(current, 19);
-	freezer_exempt(current);
+	freezer_exempt(current, FE_ALL);
 
 	do {
 		schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10);
@@ -590,7 +590,7 @@ rcu_torture_reader(void *arg)
 
 	VERBOSE_PRINTK_STRING("rcu_torture_reader task started");
 	set_user_nice(current, 19);
-	freezer_exempt(current);
+	freezer_exempt(current, FE_ALL);
 
 	do {
 		idx = cur_ops->readlock();
Index: linux-2.6.21-rc7/kernel/sched.c
===================================================================
--- linux-2.6.21-rc7.orig/kernel/sched.c
+++ linux-2.6.21-rc7/kernel/sched.c
@@ -5478,7 +5478,7 @@ migration_call(struct notifier_block *nf
 		p = kthread_create(migration_thread, hcpu, "migration/%d",cpu);
 		if (IS_ERR(p))
 			return NOTIFY_BAD;
-		freezer_exempt(p);
+		freezer_exempt(p, FE_ALL);
 		kthread_bind(p, cpu);
 		/* Must be high prio: stop_machine expects to yield to it. */
 		rq = task_rq_lock(p, &flags);
Index: linux-2.6.21-rc7/kernel/softirq.c
===================================================================
--- linux-2.6.21-rc7.orig/kernel/softirq.c
+++ linux-2.6.21-rc7/kernel/softirq.c
@@ -490,7 +490,7 @@ void __init softirq_init(void)
 static int ksoftirqd(void * __bind_cpu)
 {
 	set_user_nice(current, 15);
-	freezer_exempt(current);
+	freezer_exempt(current, FE_ALL);
 
 	set_current_state(TASK_INTERRUPTIBLE);
 
Index: linux-2.6.21-rc7/kernel/softlockup.c
===================================================================
--- linux-2.6.21-rc7.orig/kernel/softlockup.c
+++ linux-2.6.21-rc7/kernel/softlockup.c
@@ -117,7 +117,7 @@ static int watchdog(void * __bind_cpu)
 	struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
 
 	sched_setscheduler(current, SCHED_FIFO, &param);
-	freezer_exempt(current);
+	freezer_exempt(current, FE_ALL);
 
 	/* initialize timestamp */
 	touch_softlockup_watchdog();
Index: linux-2.6.21-rc7/kernel/workqueue.c
===================================================================
--- linux-2.6.21-rc7.orig/kernel/workqueue.c
+++ linux-2.6.21-rc7/kernel/workqueue.c
@@ -291,7 +291,7 @@ static int worker_thread(void *__cwq)
 	DEFINE_WAIT(wait);
 
 	if (!cwq->wq->freezeable)
-		freezer_exempt(current);
+		freezer_exempt(current, FE_ALL);
 
 	for (;;) {
 		prepare_to_wait(&cwq->more_work, &wait, TASK_INTERRUPTIBLE);
Index: linux-2.6.21-rc7/kernel/kprobes.c
===================================================================
--- linux-2.6.21-rc7.orig/kernel/kprobes.c
+++ linux-2.6.21-rc7/kernel/kprobes.c
@@ -109,7 +109,7 @@ static int __kprobes check_safety(void)
 {
 	int ret = 0;
 #ifdef CONFIG_PREEMPT
-	ret = freeze_processes();
+	ret = freeze_processes(FE_KPROBES);
 	if (ret == 0) {
 		struct task_struct *p, *q;
 		do_each_thread(p, q) {
@@ -122,7 +122,7 @@ static int __kprobes check_safety(void)
 		} while_each_thread(p, q);
 	}
 loop_end:
-	thaw_processes();
+	thaw_processes(FE_KPROBES);
 #else
 	synchronize_sched();
 #endif
Index: linux-2.6.21-rc7/kernel/power/disk.c
===================================================================
--- linux-2.6.21-rc7.orig/kernel/power/disk.c
+++ linux-2.6.21-rc7/kernel/power/disk.c
@@ -103,7 +103,7 @@ static inline void platform_finish(void)
 
 static void unprepare_processes(void)
 {
-	thaw_processes();
+	thaw_processes(FE_SUSPEND);
 	pm_restore_console();
 }
 
@@ -112,7 +112,7 @@ static int prepare_processes(void)
 	int error = 0;
 
 	pm_prepare_console();
-	if (freeze_processes()) {
+	if (freeze_processes(FE_SUSPEND)) {
 		error = -EBUSY;
 		unprepare_processes();
 	}
Index: linux-2.6.21-rc7/kernel/power/main.c
===================================================================
--- linux-2.6.21-rc7.orig/kernel/power/main.c
+++ linux-2.6.21-rc7/kernel/power/main.c
@@ -90,9 +90,9 @@ static int suspend_prepare(suspend_state
 	if (error)
 		goto Finish;
 
-	if (freeze_processes()) {
+	if (freeze_processes(FE_SUSPEND)) {
 		error = -EAGAIN;
-		thaw_processes();
+		thaw_processes(FE_SUSPEND);
 		goto Finish;
 	}
 
@@ -133,7 +133,7 @@ static int suspend_prepare(suspend_state
 	resume_console();
  Thaw:
 	suspend_notifier_call_chain(SUSPEND_THAW_PREPARE);
-	thaw_processes();
+	thaw_processes(FE_SUSPEND);
  Finish:
 	pm_restore_console();
 	suspend_notifier_call_chain(SUSPEND_FINISHED);
@@ -185,7 +185,7 @@ static void suspend_finish(suspend_state
 	device_resume();
 	resume_console();
 	suspend_notifier_call_chain(SUSPEND_THAW_PREPARE);
-	thaw_processes();
+	thaw_processes(FE_SUSPEND);
 	pm_restore_console();
 	suspend_notifier_call_chain(SUSPEND_FINISHED);
 }
Index: linux-2.6.21-rc7/kernel/power/user.c
===================================================================
--- linux-2.6.21-rc7.orig/kernel/power/user.c
+++ linux-2.6.21-rc7/kernel/power/user.c
@@ -81,7 +81,7 @@ static void snapshot_unfreeze(struct sna
 		return;
 
 	mutex_lock(&pm_mutex);
-	thaw_processes();
+	thaw_processes(FE_SUSPEND);
 	suspend_notifier_call_chain(SUSPEND_FINISHED);
 	mutex_unlock(&pm_mutex);
 	data->frozen = 0;
@@ -257,8 +257,8 @@ static int snapshot_ioctl(struct inode *
 		if (error)
 			break;
 
-		if (freeze_processes()) {
-			thaw_processes();
+		if (freeze_processes(FE_SUSPEND)) {
+			thaw_processes(FE_SUSPEND);
 			suspend_notifier_call_chain(SUSPEND_FINISHED);
 			error = -EBUSY;
 		}
-- 
Gautham R Shenoy
Linux Technology Center
IBM India.
"Freedom comes with a price tag of responsibility, which is still a bargain,
because Freedom is priceless!"

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

* Re: [PATCH -mm] Allow selective freezing of the system for different events
  2007-04-28  1:34   ` [PATCH -mm] Allow selective freezing of the system for different events Gautham R Shenoy
@ 2007-04-28  6:22     ` Andrew Morton
  2007-04-28  7:45       ` Gautham R Shenoy
  2007-04-29 17:51     ` Rafael J. Wysocki
  1 sibling, 1 reply; 23+ messages in thread
From: Andrew Morton @ 2007-04-28  6:22 UTC (permalink / raw)
  To: ego
  Cc: Rafael J. Wysocki, Ingo Molnar, Oleg Nesterov, Pavel Machek,
	Pekka Enberg, LKML

On Sat, 28 Apr 2007 07:04:46 +0530 Gautham R Shenoy <ego@in.ibm.com> wrote:

> This patch
> * Provides an interface to selectively freeze the system for different events.
> * Allows tasks to exempt themselves or other tasks from specific freeze
>   events.
> * Allow nesting of freezer calls. For eg:
> 
> 	freeze_processes(EVENT_A);
> 	/* Do something with respect to event A */
> 	.
> 	.
> 	.
> 	freeze_processes(EVENT_B);
> 	/* Do something with respect to event B */
> 	.
> 	.
> 	.
> 	thaw_processes(EVENT_B);
> 	.
> 	.
> 	.
> 	thaw_processes(EVENT_B);
> 
> This type of behaviour would be required when cpu hotplug would start
> using the process freezer, where EVENT_A would be SUSPEND and EVENT_B
> would be HOTPLUG_CPU.
> 
> This patch applies on the top of 2.6.21-rc7-mm2 + Rafael's freezer
> changes from http://lkml.org/lkml/2007/4/27/302.

I think I'll duck this.  We have more than enough kthread/freezer/etc work
queued for 2.6.22.  Let's please for now concentrate on reviewing and
testing the existing changes.  Once that has all landed and settled in,
let's start thinking about the next round.



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

* Re: [PATCH -mm 2/2] Introduce freezer flags
  2007-04-27 22:56           ` Rafael J. Wysocki
@ 2007-04-28  7:07             ` Pavel Machek
  0 siblings, 0 replies; 23+ messages in thread
From: Pavel Machek @ 2007-04-28  7:07 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ego, Andrew Morton, Ingo Molnar, Oleg Nesterov, Pekka Enberg, LKML

Hi!

> > > > > > +#ifdef CONFIG_FREEZER
> > > > > > +	/* Used by the process freezer, defined in freezer.h */
> > > > > > +	unsigned int freezer_flags;
> > > > > 
> > > > > unsigned long freezer_flags; ??
> > > > 
> > > > I guess so.
> > > 
> > > Still, on x86_64, for example, we'll waste 4 bytes by using 'unsigned long'
> > > here, which I wouldn't like to do.
> > > 
> > > Is it acceptable to use explicit type casting in set_bit() and friends?
> > 
> > I'm afraid set_bit & friends are only defined on unsigned long.
> 
> On x86_64 they are defined on anything, even on huge bitmaps.
> 
> > You can cast, but you may run into some nasty surprise... like damaging
> > surrounding bytes on 64-bit architectures != x86_64.
> 
> Let's use unsigned long, then, but I'm not really happy with that.

Ask the architecture people, but comments like

/data/l/linux/include/linux/agpgart.h:  long access_flags;      /* long req'd for set_bit --RR */

Make me think long is needed.

 * bitmaps provide bit arrays that consume one or more unsigned
 * longs.  The bitmap interface and available operations are listed
 * here, in bitmap.h

...I'm afraid we need ulongs.
								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] 23+ messages in thread

* Re: [PATCH -mm] Allow selective freezing of the system for different events
  2007-04-28  6:22     ` Andrew Morton
@ 2007-04-28  7:45       ` Gautham R Shenoy
  0 siblings, 0 replies; 23+ messages in thread
From: Gautham R Shenoy @ 2007-04-28  7:45 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Rafael J. Wysocki, Ingo Molnar, Oleg Nesterov, Pavel Machek,
	Pekka Enberg, LKML

On Fri, Apr 27, 2007 at 11:22:22PM -0700, Andrew Morton wrote:
> On Sat, 28 Apr 2007 07:04:46 +0530 Gautham R Shenoy <ego@in.ibm.com> wrote:
> 
> > This patch
> > * Provides an interface to selectively freeze the system for different events.
> > * Allows tasks to exempt themselves or other tasks from specific freeze
> >   events.
> > * Allow nesting of freezer calls. For eg:
> > 
> > 	freeze_processes(EVENT_A);
> > 	/* Do something with respect to event A */
> > 	.
> > 	.
> > 	.
> > 	freeze_processes(EVENT_B);
> > 	/* Do something with respect to event B */
> > 	.
> > 	.
> > 	.
> > 	thaw_processes(EVENT_B);
> > 	.
> > 	.
> > 	.
> > 	thaw_processes(EVENT_B);
> > 
> > This type of behaviour would be required when cpu hotplug would start
> > using the process freezer, where EVENT_A would be SUSPEND and EVENT_B
> > would be HOTPLUG_CPU.
> > 
> > This patch applies on the top of 2.6.21-rc7-mm2 + Rafael's freezer
> > changes from http://lkml.org/lkml/2007/4/27/302.
> 
> I think I'll duck this.  We have more than enough kthread/freezer/etc work
> queued for 2.6.22. 

Sure, not a problem :-)

I just wanted to get a sense, if this was a right way to do it. 
Besides, I am plannning to send it again once I port the cpuhotplug
patches on top of all these changes and get some satisfactory numbers.

> Let's please for now concentrate on reviewing and
> testing the existing changes.  Once that has all landed and settled in,
> let's start thinking about the next round.
> 

Ok.

Thanks and Regards
gautham.
-- 
Gautham R Shenoy
Linux Technology Center
IBM India.
"Freedom comes with a price tag of responsibility, which is still a bargain,
because Freedom is priceless!"

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

* Re: [PATCH -mm 1/2] Separate freezer from PM code
  2007-04-27 21:29         ` Rafael J. Wysocki
@ 2007-04-29  8:43           ` Sam Ravnborg
  0 siblings, 0 replies; 23+ messages in thread
From: Sam Ravnborg @ 2007-04-29  8:43 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Jeremy Fitzhardinge, Andrew Morton, Gautham R Shenoy,
	Ingo Molnar, Oleg Nesterov, Pavel Machek, Pekka Enberg, LKML

On Fri, Apr 27, 2007 at 11:29:34PM +0200, Rafael J. Wysocki wrote:
> On Friday, 27 April 2007 22:20, Jeremy Fitzhardinge wrote:
> > Rafael J. Wysocki wrote:
> > > Makes sense.  Please have a look at the updated patch below.
> > >
> > > Sam, does this one look better to you?
> > >   
> > 
> > If freezer.c is in kernel/, then shouldn't the corresponding config var
> > be in a non-arch Kconfig file?
> 
> Well, I though it would look strange.  Still, I can do that, of course:

It would have been much better to have a single kernel/Kconfig
so you avoided all the arch specific source lines.
But thats not this patch and can come later.

So I'm OK with this one.

	Sam

> 
> ---
> From: Rafael J. Wysocki <rjw@sisk.pl>
> 
> Now that the freezer is used by kprobes, it is no longer a PM-specific piece of
> code.  Move the freezer code out of kernel/power and introduce the
> CONFIG_FREEZER option that will be chosen automatically if PM or KPROBES is set.
> 
> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
> ---
>  arch/arm/Kconfig         |    2 
>  arch/avr32/Kconfig       |    2 
>  arch/avr32/Kconfig.debug |    1 
>  arch/blackfin/Kconfig    |    2 
>  arch/frv/Kconfig         |    2 
>  arch/i386/Kconfig        |    3 
>  arch/ia64/Kconfig        |    3 
>  arch/mips/Kconfig        |    2 
>  arch/powerpc/Kconfig     |    3 
>  arch/ppc/Kconfig         |    2 
>  arch/s390/Kconfig        |    3 
>  arch/sh/Kconfig          |    2 
>  arch/sparc64/Kconfig     |    3 
>  arch/x86_64/Kconfig      |    3 
>  include/linux/freezer.h  |    2 
>  kernel/Kconfig.freezer   |    5 
>  kernel/Makefile          |    1 
>  kernel/freezer.c         |  236 +++++++++++++++++++++++++++++++++++++++++++++++
>  kernel/kprobes.c         |    2 
>  kernel/power/Kconfig     |    1 
>  kernel/power/Makefile    |    2 
>  kernel/power/process.c   |  236 -----------------------------------------------
>  22 files changed, 279 insertions(+), 239 deletions(-)
> 
> Index: linux-2.6.21-rc7-mm2/arch/x86_64/Kconfig
> ===================================================================
> --- linux-2.6.21-rc7-mm2.orig/arch/x86_64/Kconfig	2007-04-27 21:41:05.000000000 +0200
> +++ linux-2.6.21-rc7-mm2/arch/x86_64/Kconfig	2007-04-27 23:20:43.000000000 +0200
> @@ -703,6 +703,8 @@ config GENERIC_PENDING_IRQ
>  	depends on GENERIC_HARDIRQS && SMP
>  	default y
>  
> +source "kernel/Kconfig.freezer"
> +
>  menu "Power management options"
>  
>  source kernel/power/Kconfig
> @@ -791,6 +793,7 @@ source "arch/x86_64/oprofile/Kconfig"
>  config KPROBES
>  	bool "Kprobes (EXPERIMENTAL)"
>  	depends on KALLSYMS && EXPERIMENTAL && MODULES
> +	select FREEZER
>  	help
>  	  Kprobes allows you to trap at almost any kernel address and
>  	  execute a callback function.  register_kprobe() establishes
> Index: linux-2.6.21-rc7-mm2/arch/avr32/Kconfig.debug
> ===================================================================
> --- linux-2.6.21-rc7-mm2.orig/arch/avr32/Kconfig.debug	2007-04-27 21:41:05.000000000 +0200
> +++ linux-2.6.21-rc7-mm2/arch/avr32/Kconfig.debug	2007-04-27 21:54:19.000000000 +0200
> @@ -12,6 +12,7 @@ menu "Instrumentation Support"
>  config KPROBES
>  	bool "Kprobes"
>  	depends on DEBUG_KERNEL
> +	select FREEZER
>  	help
>  	  Kprobes allows you to trap at almost any kernel address and
>            execute a callback function.  register_kprobe() establishes
> Index: linux-2.6.21-rc7-mm2/arch/frv/Kconfig
> ===================================================================
> --- linux-2.6.21-rc7-mm2.orig/arch/frv/Kconfig	2007-04-27 21:41:05.000000000 +0200
> +++ linux-2.6.21-rc7-mm2/arch/frv/Kconfig	2007-04-27 23:13:27.000000000 +0200
> @@ -364,6 +364,8 @@ source "drivers/pcmcia/Kconfig"
>  #	  sleep-deprived psychotic hacker types can say Y now, everyone else
>  #	  should probably wait a while.
>  
> +source "kernel/Kconfig.freezer"
> +
>  menu "Power management options"
>  source kernel/power/Kconfig
>  endmenu
> Index: linux-2.6.21-rc7-mm2/arch/i386/Kconfig
> ===================================================================
> --- linux-2.6.21-rc7-mm2.orig/arch/i386/Kconfig	2007-04-27 21:41:05.000000000 +0200
> +++ linux-2.6.21-rc7-mm2/arch/i386/Kconfig	2007-04-27 23:17:36.000000000 +0200
> @@ -912,6 +912,8 @@ config ARCH_ENABLE_MEMORY_HOTPLUG
>  	def_bool y
>  	depends on HIGHMEM
>  
> +source "kernel/Kconfig.freezer"
> +
>  menu "Power management options (ACPI, APM)"
>  	depends on !X86_VOYAGER
>  
> @@ -1218,6 +1220,7 @@ source "arch/i386/oprofile/Kconfig"
>  config KPROBES
>  	bool "Kprobes (EXPERIMENTAL)"
>  	depends on KALLSYMS && EXPERIMENTAL && MODULES
> +	select FREEZER
>  	help
>  	  Kprobes allows you to trap at almost any kernel address and
>  	  execute a callback function.  register_kprobe() establishes
> Index: linux-2.6.21-rc7-mm2/arch/ia64/Kconfig
> ===================================================================
> --- linux-2.6.21-rc7-mm2.orig/arch/ia64/Kconfig	2007-04-27 21:41:05.000000000 +0200
> +++ linux-2.6.21-rc7-mm2/arch/ia64/Kconfig	2007-04-27 23:21:40.000000000 +0200
> @@ -495,6 +495,8 @@ source "fs/Kconfig.binfmt"
>  
>  endmenu
>  
> +source "kernel/Kconfig.freezer"
> +
>  menu "Power management and ACPI"
>  
>  source "kernel/power/Kconfig"
> @@ -582,6 +584,7 @@ source "arch/ia64/oprofile/Kconfig"
>  config KPROBES
>  	bool "Kprobes (EXPERIMENTAL)"
>  	depends on KALLSYMS && EXPERIMENTAL && MODULES
> +	select FREEZER
>  	help
>  	  Kprobes allows you to trap at almost any kernel address and
>  	  execute a callback function.  register_kprobe() establishes
> Index: linux-2.6.21-rc7-mm2/arch/powerpc/Kconfig
> ===================================================================
> --- linux-2.6.21-rc7-mm2.orig/arch/powerpc/Kconfig	2007-04-27 21:41:05.000000000 +0200
> +++ linux-2.6.21-rc7-mm2/arch/powerpc/Kconfig	2007-04-27 23:15:12.000000000 +0200
> @@ -552,6 +552,8 @@ config CMDLINE
>  	  some command-line options at build time by entering them here.  In
>  	  most cases you will need to specify the root device here.
>  
> +source kernel/Kconfig.freezer
> +
>  if !44x || BROKEN
>  source kernel/power/Kconfig
>  endif
> @@ -865,6 +867,7 @@ source "arch/powerpc/oprofile/Kconfig"
>  config KPROBES
>  	bool "Kprobes (EXPERIMENTAL)"
>  	depends on !BOOKE && !4xx && KALLSYMS && EXPERIMENTAL && MODULES
> +	select FREEZER
>  	help
>  	  Kprobes allows you to trap at almost any kernel address and
>  	  execute a callback function.  register_kprobe() establishes
> Index: linux-2.6.21-rc7-mm2/arch/ppc/Kconfig
> ===================================================================
> --- linux-2.6.21-rc7-mm2.orig/arch/ppc/Kconfig	2007-04-27 21:41:05.000000000 +0200
> +++ linux-2.6.21-rc7-mm2/arch/ppc/Kconfig	2007-04-27 23:15:25.000000000 +0200
> @@ -1153,6 +1153,8 @@ config PROC_HARDWARE
>  
>  source "drivers/zorro/Kconfig"
>  
> +source "kernel/Kconfig.freezer"
> +
>  if !44x || BROKEN
>  source kernel/power/Kconfig
>  endif
> Index: linux-2.6.21-rc7-mm2/arch/s390/Kconfig
> ===================================================================
> --- linux-2.6.21-rc7-mm2.orig/arch/s390/Kconfig	2007-04-27 21:41:05.000000000 +0200
> +++ linux-2.6.21-rc7-mm2/arch/s390/Kconfig	2007-04-27 23:23:19.000000000 +0200
> @@ -550,6 +550,8 @@ source "drivers/net/Kconfig"
>  
>  source "fs/Kconfig"
>  
> +source "kernel/Kconfig.freezer"
> +
>  menu "Instrumentation Support"
>  
>  source "arch/s390/oprofile/Kconfig"
> @@ -557,6 +559,7 @@ source "arch/s390/oprofile/Kconfig"
>  config KPROBES
>  	bool "Kprobes (EXPERIMENTAL)"
>  	depends on EXPERIMENTAL && MODULES
> +	select FREEZER
>  	help
>  	  Kprobes allows you to trap at almost any kernel address and
>  	  execute a callback function.	register_kprobe() establishes
> Index: linux-2.6.21-rc7-mm2/arch/sh/Kconfig
> ===================================================================
> --- linux-2.6.21-rc7-mm2.orig/arch/sh/Kconfig	2007-04-27 21:41:05.000000000 +0200
> +++ linux-2.6.21-rc7-mm2/arch/sh/Kconfig	2007-04-27 23:23:33.000000000 +0200
> @@ -699,6 +699,8 @@ source "fs/Kconfig.binfmt"
>  
>  endmenu
>  
> +source "kernel/Kconfig.freezer"
> +
>  menu "Power management options (EXPERIMENTAL)"
>  depends on EXPERIMENTAL
>  
> Index: linux-2.6.21-rc7-mm2/arch/sparc64/Kconfig
> ===================================================================
> --- linux-2.6.21-rc7-mm2.orig/arch/sparc64/Kconfig	2007-04-27 21:41:05.000000000 +0200
> +++ linux-2.6.21-rc7-mm2/arch/sparc64/Kconfig	2007-04-27 23:23:44.000000000 +0200
> @@ -420,6 +420,8 @@ source "drivers/fc4/Kconfig"
>  
>  source "fs/Kconfig"
>  
> +source "kernel/Kconfig.freezer"
> +
>  menu "Instrumentation Support"
>          depends on EXPERIMENTAL
>  
> @@ -428,6 +430,7 @@ source "arch/sparc64/oprofile/Kconfig"
>  config KPROBES
>  	bool "Kprobes (EXPERIMENTAL)"
>  	depends on KALLSYMS && EXPERIMENTAL && MODULES
> +	select FREEZER
>  	help
>  	  Kprobes allows you to trap at almost any kernel address and
>  	  execute a callback function.  register_kprobe() establishes
> Index: linux-2.6.21-rc7-mm2/kernel/Makefile
> ===================================================================
> --- linux-2.6.21-rc7-mm2.orig/kernel/Makefile	2007-04-27 21:41:05.000000000 +0200
> +++ linux-2.6.21-rc7-mm2/kernel/Makefile	2007-04-27 21:41:28.000000000 +0200
> @@ -33,6 +33,7 @@ obj-$(CONFIG_MODULES) += module.o
>  obj-$(CONFIG_KALLSYMS) += kallsyms.o
>  obj-$(CONFIG_STACK_UNWIND) += unwind.o
>  obj-$(CONFIG_PM) += power/
> +obj-$(CONFIG_FREEZER) += freezer.o
>  obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
>  obj-$(CONFIG_KEXEC) += kexec.o
>  obj-$(CONFIG_COMPAT) += compat.o
> Index: linux-2.6.21-rc7-mm2/kernel/power/Makefile
> ===================================================================
> --- linux-2.6.21-rc7-mm2.orig/kernel/power/Makefile	2007-04-27 21:41:05.000000000 +0200
> +++ linux-2.6.21-rc7-mm2/kernel/power/Makefile	2007-04-27 21:41:28.000000000 +0200
> @@ -3,7 +3,7 @@ ifeq ($(CONFIG_PM_DEBUG),y)
>  EXTRA_CFLAGS	+=	-DDEBUG
>  endif
>  
> -obj-y				:= main.o process.o console.o notify.o
> +obj-y				:= main.o console.o notify.o
>  obj-$(CONFIG_PM_LEGACY)		+= pm.o
>  obj-$(CONFIG_SOFTWARE_SUSPEND)	+= swsusp.o disk.o snapshot.o swap.o user.o
>  
> Index: linux-2.6.21-rc7-mm2/kernel/kprobes.c
> ===================================================================
> --- linux-2.6.21-rc7-mm2.orig/kernel/kprobes.c	2007-04-27 21:41:05.000000000 +0200
> +++ linux-2.6.21-rc7-mm2/kernel/kprobes.c	2007-04-27 21:41:28.000000000 +0200
> @@ -108,7 +108,7 @@ static int collect_garbage_slots(void);
>  static int __kprobes check_safety(void)
>  {
>  	int ret = 0;
> -#if defined(CONFIG_PREEMPT) && defined(CONFIG_PM)
> +#ifdef CONFIG_PREEMPT
>  	ret = freeze_processes();
>  	if (ret == 0) {
>  		struct task_struct *p, *q;
> Index: linux-2.6.21-rc7-mm2/include/linux/freezer.h
> ===================================================================
> --- linux-2.6.21-rc7-mm2.orig/include/linux/freezer.h	2007-04-27 21:41:27.000000000 +0200
> +++ linux-2.6.21-rc7-mm2/include/linux/freezer.h	2007-04-27 23:20:23.000000000 +0200
> @@ -2,7 +2,7 @@
>  
>  #include <linux/sched.h>
>  
> -#ifdef CONFIG_PM
> +#ifdef CONFIG_FREEZER
>  /*
>   * Check if a process has been frozen
>   */
> Index: linux-2.6.21-rc7-mm2/arch/arm/Kconfig
> ===================================================================
> --- linux-2.6.21-rc7-mm2.orig/arch/arm/Kconfig	2007-04-27 21:41:05.000000000 +0200
> +++ linux-2.6.21-rc7-mm2/arch/arm/Kconfig	2007-04-27 23:11:10.000000000 +0200
> @@ -925,6 +925,8 @@ config ARTHUR
>  
>  endmenu
>  
> +source "kernel/Kconfig.freezer"
> +
>  menu "Power management options"
>  
>  source "kernel/power/Kconfig"
> Index: linux-2.6.21-rc7-mm2/arch/blackfin/Kconfig
> ===================================================================
> --- linux-2.6.21-rc7-mm2.orig/arch/blackfin/Kconfig	2007-04-27 21:41:05.000000000 +0200
> +++ linux-2.6.21-rc7-mm2/arch/blackfin/Kconfig	2007-04-27 23:13:09.000000000 +0200
> @@ -816,6 +816,8 @@ source "fs/Kconfig.binfmt"
>  
>  endmenu
>  
> +source "kernel/Kconfig.freezer"
> +
>  menu "Power management options"
>  source "kernel/power/Kconfig"
>  
> Index: linux-2.6.21-rc7-mm2/arch/mips/Kconfig
> ===================================================================
> --- linux-2.6.21-rc7-mm2.orig/arch/mips/Kconfig	2007-04-27 21:41:05.000000000 +0200
> +++ linux-2.6.21-rc7-mm2/arch/mips/Kconfig	2007-04-27 23:22:37.000000000 +0200
> @@ -2067,6 +2067,8 @@ source "drivers/pci/hotplug/Kconfig"
>  
>  endmenu
>  
> +source "kernel/Kconfig.freezer"
> +
>  menu "Executable file formats"
>  
>  source "fs/Kconfig.binfmt"
> Index: linux-2.6.21-rc7-mm2/kernel/freezer.c
> ===================================================================
> --- /dev/null	1970-01-01 00:00:00.000000000 +0000
> +++ linux-2.6.21-rc7-mm2/kernel/freezer.c	2007-04-27 23:20:23.000000000 +0200
> @@ -0,0 +1,236 @@
> +/*
> + * linux/kernel/freezer.c
> + *
> + * Generic mechanism for freezing and thawing tasks, originally from swsusp.
> + *
> + * Distributed under the GPLv2
> + */
> +
> +
> +#undef DEBUG
> +
> +#include <linux/sched.h>
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> +#include <linux/syscalls.h>
> +#include <linux/freezer.h>
> +
> +/*
> + * Timeout for stopping processes
> + */
> +#define TIMEOUT	(20 * HZ)
> +
> +#define FREEZER_KERNEL_THREADS 0
> +#define FREEZER_USER_SPACE 1
> +
> +static inline int freezeable(struct task_struct * p)
> +{
> +	if ((p == current) ||
> +	    (p->flags & PF_NOFREEZE) ||
> +	    (p->exit_state != 0))
> +		return 0;
> +	return 1;
> +}
> +
> +/*
> + * freezing is complete, mark current process as frozen
> + */
> +static inline void frozen_process(void)
> +{
> +	if (!unlikely(current->flags & PF_NOFREEZE)) {
> +		current->flags |= PF_FROZEN;
> +		wmb();
> +	}
> +	clear_tsk_thread_flag(current, TIF_FREEZE);
> +}
> +
> +/* Refrigerator is place where frozen processes are stored :-). */
> +void refrigerator(void)
> +{
> +	/* Hmm, should we be allowed to suspend when there are realtime
> +	   processes around? */
> +	long save;
> +
> +	task_lock(current);
> +	if (freezing(current)) {
> +		frozen_process();
> +		task_unlock(current);
> +	} else {
> +		task_unlock(current);
> +		return;
> +	}
> +	save = current->state;
> +	pr_debug("%s entered refrigerator\n", current->comm);
> +
> +	spin_lock_irq(&current->sighand->siglock);
> +	recalc_sigpending(); /* We sent fake signal, clean it up */
> +	spin_unlock_irq(&current->sighand->siglock);
> +
> +	for (;;) {
> +		set_current_state(TASK_UNINTERRUPTIBLE);
> +		if (!frozen(current))
> +			break;
> +		schedule();
> +	}
> +	pr_debug("%s left refrigerator\n", current->comm);
> +	current->state = save;
> +}
> +
> +static inline void freeze_process(struct task_struct *p)
> +{
> +	unsigned long flags;
> +
> +	if (!freezing(p)) {
> +		rmb();
> +		if (!frozen(p)) {
> +			if (p->state == TASK_STOPPED)
> +				force_sig_specific(SIGSTOP, p);
> +
> +			freeze(p);
> +			spin_lock_irqsave(&p->sighand->siglock, flags);
> +			signal_wake_up(p, p->state == TASK_STOPPED);
> +			spin_unlock_irqrestore(&p->sighand->siglock, flags);
> +		}
> +	}
> +}
> +
> +static void cancel_freezing(struct task_struct *p)
> +{
> +	unsigned long flags;
> +
> +	if (freezing(p)) {
> +		pr_debug("  clean up: %s\n", p->comm);
> +		do_not_freeze(p);
> +		spin_lock_irqsave(&p->sighand->siglock, flags);
> +		recalc_sigpending_tsk(p);
> +		spin_unlock_irqrestore(&p->sighand->siglock, flags);
> +	}
> +}
> +
> +static inline int is_user_space(struct task_struct *p)
> +{
> +	int ret;
> +
> +	task_lock(p);
> +	ret = p->mm && !(p->flags & PF_BORROWED_MM);
> +	task_unlock(p);
> +	return ret;
> +}
> +
> +static unsigned int try_to_freeze_tasks(int freeze_user_space)
> +{
> +	struct task_struct *g, *p;
> +	unsigned long end_time;
> +	unsigned int todo;
> +
> +	end_time = jiffies + TIMEOUT;
> +	do {
> +		todo = 0;
> +		read_lock(&tasklist_lock);
> +		do_each_thread(g, p) {
> +			if (!freezeable(p))
> +				continue;
> +
> +			if (frozen(p))
> +				continue;
> +
> +			if (p->state == TASK_TRACED && frozen(p->parent)) {
> +				cancel_freezing(p);
> +				continue;
> +			}
> +			if (freeze_user_space && !is_user_space(p))
> +				continue;
> +
> +			freeze_process(p);
> +			if (!freezer_should_skip(p))
> +				todo++;
> +		} while_each_thread(g, p);
> +		read_unlock(&tasklist_lock);
> +		yield();			/* Yield is okay here */
> +		if (todo && time_after(jiffies, end_time))
> +			break;
> +	} while (todo);
> +
> +	if (todo) {
> +		/* This does not unfreeze processes that are already frozen
> +		 * (we have slightly ugly calling convention in that respect,
> +		 * and caller must call thaw_processes() if something fails),
> +		 * but it cleans up leftover PF_FREEZE requests.
> +		 */
> +		printk("\n");
> +		printk(KERN_ERR "Stopping %s timed out after %d seconds "
> +				"(%d tasks refusing to freeze):\n",
> +				freeze_user_space ? "user space processes" :
> +					"kernel threads",
> +				TIMEOUT / HZ, todo);
> +		read_lock(&tasklist_lock);
> +		do_each_thread(g, p) {
> +			if (freeze_user_space && !is_user_space(p))
> +				continue;
> +
> +			task_lock(p);
> +			if (freezeable(p) && !frozen(p) &&
> +			    !freezer_should_skip(p))
> +				printk(KERN_ERR " %s\n", p->comm);
> +
> +			cancel_freezing(p);
> +			task_unlock(p);
> +		} while_each_thread(g, p);
> +		read_unlock(&tasklist_lock);
> +	}
> +
> +	return todo;
> +}
> +
> +/**
> + *	freeze_processes - tell processes to enter the refrigerator
> + *
> + *	Returns 0 on success, or the number of processes that didn't freeze,
> + *	although they were told to.
> + */
> +int freeze_processes(void)
> +{
> +	unsigned int nr_unfrozen;
> +
> +	printk("Stopping tasks ... ");
> +	nr_unfrozen = try_to_freeze_tasks(FREEZER_USER_SPACE);
> +	if (nr_unfrozen)
> +		return nr_unfrozen;
> +
> +	sys_sync();
> +	nr_unfrozen = try_to_freeze_tasks(FREEZER_KERNEL_THREADS);
> +	if (nr_unfrozen)
> +		return nr_unfrozen;
> +
> +	printk("done.\n");
> +	BUG_ON(in_atomic());
> +	return 0;
> +}
> +
> +static void thaw_tasks(int thaw_user_space)
> +{
> +	struct task_struct *g, *p;
> +
> +	read_lock(&tasklist_lock);
> +	do_each_thread(g, p) {
> +		if (!freezeable(p))
> +			continue;
> +
> +		if (is_user_space(p) == !thaw_user_space)
> +			continue;
> +
> +		thaw_process(p);
> +	} while_each_thread(g, p);
> +	read_unlock(&tasklist_lock);
> +}
> +
> +void thaw_processes(void)
> +{
> +	printk("Restarting tasks ... ");
> +	thaw_tasks(FREEZER_KERNEL_THREADS);
> +	thaw_tasks(FREEZER_USER_SPACE);
> +	schedule();
> +	printk("done.\n");
> +}
> +
> +EXPORT_SYMBOL(refrigerator);
> Index: linux-2.6.21-rc7-mm2/kernel/power/process.c
> ===================================================================
> --- linux-2.6.21-rc7-mm2.orig/kernel/power/process.c	2007-04-27 21:41:27.000000000 +0200
> +++ /dev/null	1970-01-01 00:00:00.000000000 +0000
> @@ -1,236 +0,0 @@
> -/*
> - * drivers/power/process.c - Functions for starting/stopping processes on 
> - *                           suspend transitions.
> - *
> - * Originally from swsusp.
> - */
> -
> -
> -#undef DEBUG
> -
> -#include <linux/sched.h>
> -#include <linux/interrupt.h>
> -#include <linux/suspend.h>
> -#include <linux/module.h>
> -#include <linux/syscalls.h>
> -#include <linux/freezer.h>
> -
> -/* 
> - * Timeout for stopping processes
> - */
> -#define TIMEOUT	(20 * HZ)
> -
> -#define FREEZER_KERNEL_THREADS 0
> -#define FREEZER_USER_SPACE 1
> -
> -static inline int freezeable(struct task_struct * p)
> -{
> -	if ((p == current) ||
> -	    (p->flags & PF_NOFREEZE) ||
> -	    (p->exit_state != 0))
> -		return 0;
> -	return 1;
> -}
> -
> -/*
> - * freezing is complete, mark current process as frozen
> - */
> -static inline void frozen_process(void)
> -{
> -	if (!unlikely(current->flags & PF_NOFREEZE)) {
> -		current->flags |= PF_FROZEN;
> -		wmb();
> -	}
> -	clear_tsk_thread_flag(current, TIF_FREEZE);
> -}
> -
> -/* Refrigerator is place where frozen processes are stored :-). */
> -void refrigerator(void)
> -{
> -	/* Hmm, should we be allowed to suspend when there are realtime
> -	   processes around? */
> -	long save;
> -
> -	task_lock(current);
> -	if (freezing(current)) {
> -		frozen_process();
> -		task_unlock(current);
> -	} else {
> -		task_unlock(current);
> -		return;
> -	}
> -	save = current->state;
> -	pr_debug("%s entered refrigerator\n", current->comm);
> -
> -	spin_lock_irq(&current->sighand->siglock);
> -	recalc_sigpending(); /* We sent fake signal, clean it up */
> -	spin_unlock_irq(&current->sighand->siglock);
> -
> -	for (;;) {
> -		set_current_state(TASK_UNINTERRUPTIBLE);
> -		if (!frozen(current))
> -			break;
> -		schedule();
> -	}
> -	pr_debug("%s left refrigerator\n", current->comm);
> -	current->state = save;
> -}
> -
> -static inline void freeze_process(struct task_struct *p)
> -{
> -	unsigned long flags;
> -
> -	if (!freezing(p)) {
> -		rmb();
> -		if (!frozen(p)) {
> -			if (p->state == TASK_STOPPED)
> -				force_sig_specific(SIGSTOP, p);
> -
> -			freeze(p);
> -			spin_lock_irqsave(&p->sighand->siglock, flags);
> -			signal_wake_up(p, p->state == TASK_STOPPED);
> -			spin_unlock_irqrestore(&p->sighand->siglock, flags);
> -		}
> -	}
> -}
> -
> -static void cancel_freezing(struct task_struct *p)
> -{
> -	unsigned long flags;
> -
> -	if (freezing(p)) {
> -		pr_debug("  clean up: %s\n", p->comm);
> -		do_not_freeze(p);
> -		spin_lock_irqsave(&p->sighand->siglock, flags);
> -		recalc_sigpending_tsk(p);
> -		spin_unlock_irqrestore(&p->sighand->siglock, flags);
> -	}
> -}
> -
> -static inline int is_user_space(struct task_struct *p)
> -{
> -	int ret;
> -
> -	task_lock(p);
> -	ret = p->mm && !(p->flags & PF_BORROWED_MM);
> -	task_unlock(p);
> -	return ret;
> -}
> -
> -static unsigned int try_to_freeze_tasks(int freeze_user_space)
> -{
> -	struct task_struct *g, *p;
> -	unsigned long end_time;
> -	unsigned int todo;
> -
> -	end_time = jiffies + TIMEOUT;
> -	do {
> -		todo = 0;
> -		read_lock(&tasklist_lock);
> -		do_each_thread(g, p) {
> -			if (!freezeable(p))
> -				continue;
> -
> -			if (frozen(p))
> -				continue;
> -
> -			if (p->state == TASK_TRACED && frozen(p->parent)) {
> -				cancel_freezing(p);
> -				continue;
> -			}
> -			if (freeze_user_space && !is_user_space(p))
> -				continue;
> -
> -			freeze_process(p);
> -			if (!freezer_should_skip(p))
> -				todo++;
> -		} while_each_thread(g, p);
> -		read_unlock(&tasklist_lock);
> -		yield();			/* Yield is okay here */
> -		if (todo && time_after(jiffies, end_time))
> -			break;
> -	} while (todo);
> -
> -	if (todo) {
> -		/* This does not unfreeze processes that are already frozen
> -		 * (we have slightly ugly calling convention in that respect,
> -		 * and caller must call thaw_processes() if something fails),
> -		 * but it cleans up leftover PF_FREEZE requests.
> -		 */
> -		printk("\n");
> -		printk(KERN_ERR "Stopping %s timed out after %d seconds "
> -				"(%d tasks refusing to freeze):\n",
> -				freeze_user_space ? "user space processes" :
> -					"kernel threads",
> -				TIMEOUT / HZ, todo);
> -		read_lock(&tasklist_lock);
> -		do_each_thread(g, p) {
> -			if (freeze_user_space && !is_user_space(p))
> -				continue;
> -
> -			task_lock(p);
> -			if (freezeable(p) && !frozen(p) &&
> -			    !freezer_should_skip(p))
> -				printk(KERN_ERR " %s\n", p->comm);
> -
> -			cancel_freezing(p);
> -			task_unlock(p);
> -		} while_each_thread(g, p);
> -		read_unlock(&tasklist_lock);
> -	}
> -
> -	return todo;
> -}
> -
> -/**
> - *	freeze_processes - tell processes to enter the refrigerator
> - *
> - *	Returns 0 on success, or the number of processes that didn't freeze,
> - *	although they were told to.
> - */
> -int freeze_processes(void)
> -{
> -	unsigned int nr_unfrozen;
> -
> -	printk("Stopping tasks ... ");
> -	nr_unfrozen = try_to_freeze_tasks(FREEZER_USER_SPACE);
> -	if (nr_unfrozen)
> -		return nr_unfrozen;
> -
> -	sys_sync();
> -	nr_unfrozen = try_to_freeze_tasks(FREEZER_KERNEL_THREADS);
> -	if (nr_unfrozen)
> -		return nr_unfrozen;
> -
> -	printk("done.\n");
> -	BUG_ON(in_atomic());
> -	return 0;
> -}
> -
> -static void thaw_tasks(int thaw_user_space)
> -{
> -	struct task_struct *g, *p;
> -
> -	read_lock(&tasklist_lock);
> -	do_each_thread(g, p) {
> -		if (!freezeable(p))
> -			continue;
> -
> -		if (is_user_space(p) == !thaw_user_space)
> -			continue;
> -
> -		thaw_process(p);
> -	} while_each_thread(g, p);
> -	read_unlock(&tasklist_lock);
> -}
> -
> -void thaw_processes(void)
> -{
> -	printk("Restarting tasks ... ");
> -	thaw_tasks(FREEZER_KERNEL_THREADS);
> -	thaw_tasks(FREEZER_USER_SPACE);
> -	schedule();
> -	printk("done.\n");
> -}
> -
> -EXPORT_SYMBOL(refrigerator);
> Index: linux-2.6.21-rc7-mm2/arch/avr32/Kconfig
> ===================================================================
> --- linux-2.6.21-rc7-mm2.orig/arch/avr32/Kconfig	2007-04-27 01:00:50.000000000 +0200
> +++ linux-2.6.21-rc7-mm2/arch/avr32/Kconfig	2007-04-27 23:12:42.000000000 +0200
> @@ -209,6 +209,8 @@ source "drivers/Kconfig"
>  
>  source "fs/Kconfig"
>  
> +source "kernel/Kconfig.freezer"
> +
>  source "arch/avr32/Kconfig.debug"
>  
>  source "security/Kconfig"
> Index: linux-2.6.21-rc7-mm2/kernel/power/Kconfig
> ===================================================================
> --- linux-2.6.21-rc7-mm2.orig/kernel/power/Kconfig	2007-04-27 21:41:05.000000000 +0200
> +++ linux-2.6.21-rc7-mm2/kernel/power/Kconfig	2007-04-27 21:42:52.000000000 +0200
> @@ -1,6 +1,7 @@
>  config PM
>  	bool "Power Management support"
>  	depends on !IA64_HP_SIM
> +	select FREEZER
>  	---help---
>  	  "Power Management" means that parts of your computer are shut
>  	  off or put into a power conserving "sleep" mode if they are not
> Index: linux-2.6.21-rc7-mm2/kernel/Kconfig.freezer
> ===================================================================
> --- /dev/null	1970-01-01 00:00:00.000000000 +0000
> +++ linux-2.6.21-rc7-mm2/kernel/Kconfig.freezer	2007-04-27 23:06:52.000000000 +0200
> @@ -0,0 +1,5 @@
> +# Tasks freezer configuration
> +
> +config FREEZER
> +	bool
> +	default n
> 
> 
> -
> 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/

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

* Re: [PATCH -mm] Allow selective freezing of the system for different events
  2007-04-28  1:34   ` [PATCH -mm] Allow selective freezing of the system for different events Gautham R Shenoy
  2007-04-28  6:22     ` Andrew Morton
@ 2007-04-29 17:51     ` Rafael J. Wysocki
  2007-04-30 19:19       ` Gautham R Shenoy
  1 sibling, 1 reply; 23+ messages in thread
From: Rafael J. Wysocki @ 2007-04-29 17:51 UTC (permalink / raw)
  To: ego
  Cc: Andrew Morton, Ingo Molnar, Oleg Nesterov, Pavel Machek,
	Pekka Enberg, LKML

Hi,

Sorry for the delay.

On Saturday, 28 April 2007 03:34, Gautham R Shenoy wrote:
> This patch
> * Provides an interface to selectively freeze the system for different events.
> * Allows tasks to exempt themselves or other tasks from specific freeze
>   events.
> * Allow nesting of freezer calls. For eg:
> 
> 	freeze_processes(EVENT_A);
> 	/* Do something with respect to event A */
> 	.
> 	.
> 	.
> 	freeze_processes(EVENT_B);
> 	/* Do something with respect to event B */
> 	.
> 	.
> 	.
> 	thaw_processes(EVENT_B);
> 	.
> 	.
> 	.
> 	thaw_processes(EVENT_B);
> 
> This type of behaviour would be required when cpu hotplug would start
> using the process freezer, where EVENT_A would be SUSPEND and EVENT_B
> would be HOTPLUG_CPU.
> 
> This patch applies on the top of 2.6.21-rc7-mm2 + Rafael's freezer
> changes from http://lkml.org/lkml/2007/4/27/302.
> 
> Signed-off-by: Gautham R Shenoy <ego@in.ibm.com>
> ---
>  arch/i386/kernel/apm.c              |    2 -
>  drivers/block/loop.c                |    2 -
>  drivers/char/apm-emulation.c        |    6 +--
>  drivers/ieee1394/ieee1394_core.c    |    2 -
>  drivers/md/md.c                     |    2 -
>  drivers/mmc/card/queue.c            |    2 -
>  drivers/mtd/mtd_blkdevs.c           |    2 -
>  drivers/scsi/libsas/sas_scsi_host.c |    2 -
>  drivers/scsi/scsi_error.c           |    2 -
>  drivers/usb/storage/usb.c           |    2 -
>  include/linux/freezer.h             |   44 +++++++++++++++++++-----
>  kernel/freezer.c                    |   64 ++++++++++++++++++++++++++++++------
>  kernel/kprobes.c                    |    4 +-
>  kernel/kthread.c                    |    2 -
>  kernel/power/disk.c                 |    4 +-
>  kernel/power/main.c                 |    8 ++--
>  kernel/power/user.c                 |    6 +--
>  kernel/rcutorture.c                 |    4 +-
>  kernel/sched.c                      |    2 -
>  kernel/softirq.c                    |    2 -
>  kernel/softlockup.c                 |    2 -
>  kernel/workqueue.c                  |    2 -
>  22 files changed, 119 insertions(+), 49 deletions(-)
> 
> Index: linux-2.6.21-rc7/include/linux/freezer.h
> ===================================================================
> --- linux-2.6.21-rc7.orig/include/linux/freezer.h
> +++ linux-2.6.21-rc7/include/linux/freezer.h
> @@ -4,17 +4,27 @@
>  
>  #ifdef CONFIG_FREEZER
>  
> +
>  /*
>   *	Per task flags used by the freezer
>   *
>   *	They should not be referred to directly outside of this file.
>   */
> -#define TFF_NOFREEZE	0	/* task should not be frozen */
> +#define TFF_FE_SUSPEND	0	/* Do not freeze task for software suspend */
> +#define TFF_FE_KPROBES	1	/* Do not freeze task for kprobes */
>  #define TFF_FREEZE	8	/* task should go to the refrigerator ASAP */
>  #define TFF_SKIP	9	/* do not count this task as freezable */
>  #define TFF_FROZEN	10	/* task is frozen */
>  
>  /*
> + * Codes of different events which use the freezer
> + * These are the only flags that can be referred outside this file
> + */
> +#define FE_SUSPEND	(1 << TFF_FE_SUSPEND) /* Software Suspend */
> +#define FE_KPROBES	(1 << TFF_FE_KPROBES)	/* Kprobes */
> +#define FE_ALL		(FE_SUSPEND | FE_KPROBES) /* All events using freezer */
> +
> +/*
>   * Check if a process has been frozen
>   */
>  static inline int frozen(struct task_struct *p)
> @@ -57,19 +67,29 @@ static inline void clear_freeze_flag(str
>  }
>  
>  /*
> - * Check if the task wants to be exempted from freezing
> + * Check if the task wants to be exempted from freezing for
> + * freeze_event.
>   */
> -static inline int freezer_should_exempt(struct task_struct *p)
> +static inline int freezer_should_exempt(struct task_struct *p,
> +					unsigned long freeze_event)
>  {
> -	return test_bit(TFF_NOFREEZE, &p->freezer_flags);
> +	return p->freezer_flags & freeze_event;
>  }
>  
>  /*
>   * Tell the freezer to exempt this task from freezing
> + * for events in freeze_event_mask.
>   */
> -static inline void freezer_exempt(struct task_struct *p)

I, personally, would introduce

static inline void freezer_exempt_event(struct task_struct *p,
				  unsigned long freeze_event_mask)
{
	atomic_set_mask(freeze_event_mask, &p->freezer_flags);
}

and then

static inline void freezer_exempt(struct task_struct *p)
{
	freezer_exempt_event(p, FE_ALL);
}

The patch would be shorter. ;-)

[In that case I'd probably rename freezer_should_exempt() to
freezer_should_exempt_event(), for symmetry.]

> +static inline void freezer_exempt(struct task_struct *p,
> +				  unsigned long freeze_event_mask)
> +{
> +	atomic_set_mask(freeze_event_mask, &p->freezer_flags);
> +}
> +
> +/* Returns the mask of the events for which this process is freezeable */
> +static inline unsigned long freezeable_event_mask(struct task_struct *p)
>  {
> -	set_bit(TFF_NOFREEZE, &p->freezer_flags);
> +	return ~p->freezer_flags & FE_ALL;
>  }
>  
>  /*
> @@ -96,8 +116,8 @@ static inline int thaw_process(struct ta
>  }
>  
>  extern void refrigerator(void);
> -extern int freeze_processes(void);
> -extern void thaw_processes(void);
> +extern int freeze_processes(unsigned long freeze_event);
> +extern void thaw_processes(unsigned long freeze_event);
>  
>  static inline int try_to_freeze(void)
>  {
> @@ -160,11 +180,15 @@ static inline int freezing(struct task_s
>  static inline void freeze(struct task_struct *p) { BUG(); }
>  static inline int freezer_should_exempt(struct task_struct *p) { return 0; }
>  static inline void freezer_exempt(struct task_struct *p) {}
> +static inline unsigned long freezeable_event_mask(struct task_struct *p)
> +{
> +	return 0;
> +}
>  static inline int thaw_process(struct task_struct *p) { return 1; }
>  
>  static inline void refrigerator(void) {}
> -static inline int freeze_processes(void) { BUG(); return 0; }
> -static inline void thaw_processes(void) {}
> +static inline int freeze_processes(unsigned long) { BUG(); return 0; }
> +static inline void thaw_processes(unsigned long) {}
>  
>  static inline int try_to_freeze(void) { return 0; }
>  
> Index: linux-2.6.21-rc7/kernel/freezer.c
> ===================================================================
> --- linux-2.6.21-rc7.orig/kernel/freezer.c
> +++ linux-2.6.21-rc7/kernel/freezer.c
> @@ -23,21 +23,44 @@
>  #define FREEZER_KERNEL_THREADS 0
>  #define FREEZER_USER_SPACE 1
>  
> +static DEFINE_MUTEX(freezer_mutex);
> +/* Mask of the events for which the system is currently frozen */
> +unsigned long system_frozen_event_mask;
> +/* The event for which the freeze request has been raised */
> +unsigned long current_freezer_event;
> +
>  static inline int freezeable(struct task_struct * p)
>  {
>  	if ((p == current) ||
> -	    freezer_should_exempt(p) ||
> +	    freezer_should_exempt(p, current_freezer_event) ||
>  	    (p->exit_state != 0))
>  		return 0;
>  	return 1;
>  }
>  
> +/* Returns the mask of events for which p is currently frozen */
> +static inline unsigned long process_frozen_event_mask(struct task_struct *p)
> +{
> +	return (freezeable_event_mask(p) & system_frozen_event_mask);
> +}
> +
> +static inline int thawable(struct task_struct *p)
> +{
> +	if (!freezeable(p))
> +		return 0;
> +
> +	/* Thaw p iff it is frozen for current_freezer_event alone */
> +	 if (process_frozen_event_mask(p) & ~current_freezer_event)
> +	 	return 0;
> +
> +	return 1;

I would do

	return !(process_frozen_event_mask(p) & ~current_freezer_event);

> +}
>  /*
>   * freezing is complete, mark current process as frozen
>   */
>  static inline void frozen_process(void)
>  {
> -	if (!unlikely(freezer_should_exempt(current))) {
> +	if (!unlikely(freezer_should_exempt(current, current_freezer_event))) {
>  		set_frozen_flag(current);
>  		wmb();
>  	}
> @@ -185,26 +208,39 @@ static unsigned int try_to_freeze_tasks(
>  /**
>   *	freeze_processes - tell processes to enter the refrigerator
>   *
> + *	@freeze_event : Event that's requesting the services
> + *		        of the process freezer to freeze the system
> + *
>   *	Returns 0 on success, or the number of processes that didn't freeze,
>   *	although they were told to.
>   */
> -int freeze_processes(void)
> +int freeze_processes(unsigned long freeze_event)
>  {
> -	unsigned int nr_unfrozen;
> +	unsigned int nr_unfrozen = 0;
> +
> +	mutex_lock(&freezer_mutex);
> +	if (system_frozen_event_mask & freeze_event)
> +		goto out;
> +
> +	current_freezer_event = freeze_event;
>  
>  	printk("Stopping tasks ... ");
>  	nr_unfrozen = try_to_freeze_tasks(FREEZER_USER_SPACE);
>  	if (nr_unfrozen)
> -		return nr_unfrozen;
> +		goto out;
>  
>  	sys_sync();
>  	nr_unfrozen = try_to_freeze_tasks(FREEZER_KERNEL_THREADS);
>  	if (nr_unfrozen)
> -		return nr_unfrozen;
> +		goto out;
>  
> +	system_frozen_event_mask |= current_freezer_event;
>  	printk("done.\n");
>  	BUG_ON(in_atomic());

The BUG_ON() is still valid if tasks are already frozen for this event.

> -	return 0;
> +out:
> +	current_freezer_event = 0;
> +	mutex_unlock(&freezer_mutex);
> +	return nr_unfrozen;
>  }
>  
>  static void thaw_tasks(int thaw_user_space)
> @@ -213,7 +249,7 @@ static void thaw_tasks(int thaw_user_spa
>  
>  	read_lock(&tasklist_lock);
>  	do_each_thread(g, p) {
> -		if (!freezeable(p))
> +		if (!thawable(p))
>  			continue;
>  
>  		if (is_user_space(p) == !thaw_user_space)
> @@ -224,13 +260,23 @@ static void thaw_tasks(int thaw_user_spa
>  	read_unlock(&tasklist_lock);
>  }
>  
> -void thaw_processes(void)
> +void thaw_processes(unsigned long thaw_event)
>  {
> +	mutex_lock(&freezer_mutex);
> +	if (!(system_frozen_event_mask & thaw_event)) {
> +		WARN_ON(1);

Hmm, I wouldn't use the WARN_ON() here.  There's nothing wrong in calling
this twice in a row as long as we do the sanity checking.  There's even one
case in which that may be convenient, actually.

> +		goto out;
> +	}
> +	current_freezer_event = thaw_event;
>  	printk("Restarting tasks ... ");
>  	thaw_tasks(FREEZER_KERNEL_THREADS);
>  	thaw_tasks(FREEZER_USER_SPACE);
> +	system_frozen_event_mask &= ~current_freezer_event;
>  	schedule();
>  	printk("done.\n");
> +out:
> +	current_freezer_event = 0;
> +	mutex_unlock(&freezer_mutex);
>  }
>  
>  EXPORT_SYMBOL(refrigerator);
> Index: linux-2.6.21-rc7/arch/i386/kernel/apm.c
> ===================================================================
> --- linux-2.6.21-rc7.orig/arch/i386/kernel/apm.c
> +++ linux-2.6.21-rc7/arch/i386/kernel/apm.c
> @@ -2313,7 +2313,7 @@ static int __init apm_init(void)
>  		remove_proc_entry("apm", NULL);
>  		return err;
>  	}
> -	freezer_exempt(kapmd_task);
> +	freezer_exempt(kapmd_task, FE_ALL);
>  	wake_up_process(kapmd_task);
>  
>  	if (num_online_cpus() > 1 && !smp ) {
> Index: linux-2.6.21-rc7/drivers/block/loop.c
> ===================================================================
> --- linux-2.6.21-rc7.orig/drivers/block/loop.c
> +++ linux-2.6.21-rc7/drivers/block/loop.c
> @@ -582,7 +582,7 @@ static int loop_thread(void *data)
>  	 * hence, it mustn't be stopped at all
>  	 * because it could be indirectly used during suspension
>  	 */
> -	freezer_exempt(current);
> +	freezer_exempt(current, FE_ALL);
>  
>  	set_user_nice(current, -20);
>  
> Index: linux-2.6.21-rc7/drivers/char/apm-emulation.c
> ===================================================================
> --- linux-2.6.21-rc7.orig/drivers/char/apm-emulation.c
> +++ linux-2.6.21-rc7/drivers/char/apm-emulation.c
> @@ -336,7 +336,7 @@ apm_ioctl(struct inode * inode, struct f
>  			 * threads.
>  			 */
>  			flags = current->flags;
> -			freezer_exempt(current);
> +			freezer_exempt(current, FE_ALL);
>  
>  			wait_event(apm_suspend_waitqueue,
>  				   as->suspend_state == SUSPEND_DONE);
> @@ -372,7 +372,7 @@ apm_ioctl(struct inode * inode, struct f
>  			 * threads.
>  			 */
>  			flags = current->flags;
> -			freezer_exempt(current);
> +			freezer_exempt(current, FE_ALL);
>  
>  			wait_event_interruptible(apm_suspend_waitqueue,
>  					 as->suspend_state == SUSPEND_DONE);
> @@ -601,7 +601,7 @@ static int __init apm_init(void)
>  		kapmd_tsk = NULL;
>  		return ret;
>  	}
> -	freezer_exempt(kapmd_tsk);
> +	freezer_exempt(kapmd_tsk, FE_ALL);
>  	wake_up_process(kapmd_tsk);
>  
>  #ifdef CONFIG_PROC_FS
> Index: linux-2.6.21-rc7/drivers/ieee1394/ieee1394_core.c
> ===================================================================
> --- linux-2.6.21-rc7.orig/drivers/ieee1394/ieee1394_core.c
> +++ linux-2.6.21-rc7/drivers/ieee1394/ieee1394_core.c
> @@ -1134,7 +1134,7 @@ static int hpsbpkt_thread(void *__hi)
>  	struct list_head tmp;
>  	int may_schedule;
>  
> -	freezer_exempt(current);
> +	freezer_exempt(current, FE_ALL);
>  
>  	while (!kthread_should_stop()) {
>  
> Index: linux-2.6.21-rc7/drivers/md/md.c
> ===================================================================
> --- linux-2.6.21-rc7.orig/drivers/md/md.c
> +++ linux-2.6.21-rc7/drivers/md/md.c
> @@ -4541,7 +4541,7 @@ static int md_thread(void * arg)
>  	 * many dirty RAID5 blocks.
>  	 */
>  
> -	freezer_exempt(current);
> +	freezer_exempt(current, FE_ALL);
>  	while (!kthread_should_stop()) {
>  
>  		/* We need to wait INTERRUPTIBLE so that
> Index: linux-2.6.21-rc7/drivers/mmc/card/queue.c
> ===================================================================
> --- linux-2.6.21-rc7.orig/drivers/mmc/card/queue.c
> +++ linux-2.6.21-rc7/drivers/mmc/card/queue.c
> @@ -67,7 +67,7 @@ static int mmc_queue_thread(void *d)
>  	 * the process freezing.  We handle suspension ourselves.
>  	 */
>  	current->flags |= PF_MEMALLOC;
> -	freezer_exempt(current);
> +	freezer_exempt(current, FE_ALL);
>  
>  	down(&mq->thread_sem);
>  	do {
> Index: linux-2.6.21-rc7/drivers/mtd/mtd_blkdevs.c
> ===================================================================
> --- linux-2.6.21-rc7.orig/drivers/mtd/mtd_blkdevs.c
> +++ linux-2.6.21-rc7/drivers/mtd/mtd_blkdevs.c
> @@ -82,7 +82,7 @@ static int mtd_blktrans_thread(void *arg
>  
>  	/* we might get involved when memory gets low, so use PF_MEMALLOC */
>  	current->flags |= PF_MEMALLOC;
> -	freezer_exempt(current);
> +	freezer_exempt(current, FE_ALL);
>  
>  	spin_lock_irq(rq->queue_lock);
>  	while (!kthread_should_stop()) {
> Index: linux-2.6.21-rc7/drivers/scsi/libsas/sas_scsi_host.c
> ===================================================================
> --- linux-2.6.21-rc7.orig/drivers/scsi/libsas/sas_scsi_host.c
> +++ linux-2.6.21-rc7/drivers/scsi/libsas/sas_scsi_host.c
> @@ -871,7 +871,7 @@ static int sas_queue_thread(void *_sas_h
>  	struct sas_ha_struct *sas_ha = _sas_ha;
>  	struct scsi_core *core = &sas_ha->core;
>  
> -	freezer_exempt(current);
> +	freezer_exempt(current, FE_ALL);
>  
>  	complete(&queue_th_comp);
>  
> Index: linux-2.6.21-rc7/drivers/scsi/scsi_error.c
> ===================================================================
> --- linux-2.6.21-rc7.orig/drivers/scsi/scsi_error.c
> +++ linux-2.6.21-rc7/drivers/scsi/scsi_error.c
> @@ -1536,7 +1536,7 @@ int scsi_error_handler(void *data)
>  {
>  	struct Scsi_Host *shost = data;
>  
> -	freezer_exempt(current);
> +	freezer_exempt(current, FE_ALL);
>  
>  	/*
>  	 * We use TASK_INTERRUPTIBLE so that the thread is not
> Index: linux-2.6.21-rc7/drivers/usb/storage/usb.c
> ===================================================================
> --- linux-2.6.21-rc7.orig/drivers/usb/storage/usb.c
> +++ linux-2.6.21-rc7/drivers/usb/storage/usb.c
> @@ -301,7 +301,7 @@ static int usb_stor_control_thread(void 
>  	struct us_data *us = (struct us_data *)__us;
>  	struct Scsi_Host *host = us_to_host(us);
>  
> -	freezer_exempt(current);
> +	freezer_exempt(current, FE_ALL);
>  
>  	for(;;) {
>  		try_to_freeze();
> Index: linux-2.6.21-rc7/kernel/kthread.c
> ===================================================================
> --- linux-2.6.21-rc7.orig/kernel/kthread.c
> +++ linux-2.6.21-rc7/kernel/kthread.c
> @@ -233,7 +233,7 @@ int kthreadd(void *unused)
>  	/* Setup a clean context for our children to inherit. */
>  	kthreadd_setup();
>  
> -	freezer_exempt(current);
> +	freezer_exempt(current, FE_ALL);
>  
>  	for (;;) {
>  		set_current_state(TASK_INTERRUPTIBLE);
> Index: linux-2.6.21-rc7/kernel/rcutorture.c
> ===================================================================
> --- linux-2.6.21-rc7.orig/kernel/rcutorture.c
> +++ linux-2.6.21-rc7/kernel/rcutorture.c
> @@ -559,7 +559,7 @@ rcu_torture_fakewriter(void *arg)
>  
>  	VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task started");
>  	set_user_nice(current, 19);
> -	freezer_exempt(current);
> +	freezer_exempt(current, FE_ALL);
>  
>  	do {
>  		schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10);
> @@ -590,7 +590,7 @@ rcu_torture_reader(void *arg)
>  
>  	VERBOSE_PRINTK_STRING("rcu_torture_reader task started");
>  	set_user_nice(current, 19);
> -	freezer_exempt(current);
> +	freezer_exempt(current, FE_ALL);
>  
>  	do {
>  		idx = cur_ops->readlock();
> Index: linux-2.6.21-rc7/kernel/sched.c
> ===================================================================
> --- linux-2.6.21-rc7.orig/kernel/sched.c
> +++ linux-2.6.21-rc7/kernel/sched.c
> @@ -5478,7 +5478,7 @@ migration_call(struct notifier_block *nf
>  		p = kthread_create(migration_thread, hcpu, "migration/%d",cpu);
>  		if (IS_ERR(p))
>  			return NOTIFY_BAD;
> -		freezer_exempt(p);
> +		freezer_exempt(p, FE_ALL);
>  		kthread_bind(p, cpu);
>  		/* Must be high prio: stop_machine expects to yield to it. */
>  		rq = task_rq_lock(p, &flags);
> Index: linux-2.6.21-rc7/kernel/softirq.c
> ===================================================================
> --- linux-2.6.21-rc7.orig/kernel/softirq.c
> +++ linux-2.6.21-rc7/kernel/softirq.c
> @@ -490,7 +490,7 @@ void __init softirq_init(void)
>  static int ksoftirqd(void * __bind_cpu)
>  {
>  	set_user_nice(current, 15);
> -	freezer_exempt(current);
> +	freezer_exempt(current, FE_ALL);
>  
>  	set_current_state(TASK_INTERRUPTIBLE);
>  
> Index: linux-2.6.21-rc7/kernel/softlockup.c
> ===================================================================
> --- linux-2.6.21-rc7.orig/kernel/softlockup.c
> +++ linux-2.6.21-rc7/kernel/softlockup.c
> @@ -117,7 +117,7 @@ static int watchdog(void * __bind_cpu)
>  	struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
>  
>  	sched_setscheduler(current, SCHED_FIFO, &param);
> -	freezer_exempt(current);
> +	freezer_exempt(current, FE_ALL);
>  
>  	/* initialize timestamp */
>  	touch_softlockup_watchdog();
> Index: linux-2.6.21-rc7/kernel/workqueue.c
> ===================================================================
> --- linux-2.6.21-rc7.orig/kernel/workqueue.c
> +++ linux-2.6.21-rc7/kernel/workqueue.c
> @@ -291,7 +291,7 @@ static int worker_thread(void *__cwq)
>  	DEFINE_WAIT(wait);
>  
>  	if (!cwq->wq->freezeable)
> -		freezer_exempt(current);
> +		freezer_exempt(current, FE_ALL);
>  
>  	for (;;) {
>  		prepare_to_wait(&cwq->more_work, &wait, TASK_INTERRUPTIBLE);
> Index: linux-2.6.21-rc7/kernel/kprobes.c
> ===================================================================
> --- linux-2.6.21-rc7.orig/kernel/kprobes.c
> +++ linux-2.6.21-rc7/kernel/kprobes.c
> @@ -109,7 +109,7 @@ static int __kprobes check_safety(void)
>  {
>  	int ret = 0;
>  #ifdef CONFIG_PREEMPT
> -	ret = freeze_processes();
> +	ret = freeze_processes(FE_KPROBES);
>  	if (ret == 0) {
>  		struct task_struct *p, *q;
>  		do_each_thread(p, q) {
> @@ -122,7 +122,7 @@ static int __kprobes check_safety(void)
>  		} while_each_thread(p, q);
>  	}
>  loop_end:
> -	thaw_processes();
> +	thaw_processes(FE_KPROBES);
>  #else
>  	synchronize_sched();
>  #endif
> Index: linux-2.6.21-rc7/kernel/power/disk.c
> ===================================================================
> --- linux-2.6.21-rc7.orig/kernel/power/disk.c
> +++ linux-2.6.21-rc7/kernel/power/disk.c
> @@ -103,7 +103,7 @@ static inline void platform_finish(void)
>  
>  static void unprepare_processes(void)
>  {
> -	thaw_processes();
> +	thaw_processes(FE_SUSPEND);
>  	pm_restore_console();
>  }
>  
> @@ -112,7 +112,7 @@ static int prepare_processes(void)
>  	int error = 0;
>  
>  	pm_prepare_console();
> -	if (freeze_processes()) {
> +	if (freeze_processes(FE_SUSPEND)) {
>  		error = -EBUSY;
>  		unprepare_processes();
>  	}
> Index: linux-2.6.21-rc7/kernel/power/main.c
> ===================================================================
> --- linux-2.6.21-rc7.orig/kernel/power/main.c
> +++ linux-2.6.21-rc7/kernel/power/main.c
> @@ -90,9 +90,9 @@ static int suspend_prepare(suspend_state
>  	if (error)
>  		goto Finish;
>  
> -	if (freeze_processes()) {
> +	if (freeze_processes(FE_SUSPEND)) {
>  		error = -EAGAIN;
> -		thaw_processes();
> +		thaw_processes(FE_SUSPEND);
>  		goto Finish;
>  	}
>  
> @@ -133,7 +133,7 @@ static int suspend_prepare(suspend_state
>  	resume_console();
>   Thaw:
>  	suspend_notifier_call_chain(SUSPEND_THAW_PREPARE);
> -	thaw_processes();
> +	thaw_processes(FE_SUSPEND);
>   Finish:
>  	pm_restore_console();
>  	suspend_notifier_call_chain(SUSPEND_FINISHED);
> @@ -185,7 +185,7 @@ static void suspend_finish(suspend_state
>  	device_resume();
>  	resume_console();
>  	suspend_notifier_call_chain(SUSPEND_THAW_PREPARE);
> -	thaw_processes();
> +	thaw_processes(FE_SUSPEND);
>  	pm_restore_console();
>  	suspend_notifier_call_chain(SUSPEND_FINISHED);
>  }
> Index: linux-2.6.21-rc7/kernel/power/user.c
> ===================================================================
> --- linux-2.6.21-rc7.orig/kernel/power/user.c
> +++ linux-2.6.21-rc7/kernel/power/user.c
> @@ -81,7 +81,7 @@ static void snapshot_unfreeze(struct sna
>  		return;
>  
>  	mutex_lock(&pm_mutex);
> -	thaw_processes();
> +	thaw_processes(FE_SUSPEND);
>  	suspend_notifier_call_chain(SUSPEND_FINISHED);
>  	mutex_unlock(&pm_mutex);
>  	data->frozen = 0;
> @@ -257,8 +257,8 @@ static int snapshot_ioctl(struct inode *
>  		if (error)
>  			break;
>  
> -		if (freeze_processes()) {
> -			thaw_processes();
> +		if (freeze_processes(FE_SUSPEND)) {
> +			thaw_processes(FE_SUSPEND);
>  			suspend_notifier_call_chain(SUSPEND_FINISHED);
>  			error = -EBUSY;
>  		}

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

* Re: [PATCH -mm] Allow selective freezing of the system for different events
  2007-04-29 17:51     ` Rafael J. Wysocki
@ 2007-04-30 19:19       ` Gautham R Shenoy
  0 siblings, 0 replies; 23+ messages in thread
From: Gautham R Shenoy @ 2007-04-30 19:19 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Andrew Morton, Ingo Molnar, Oleg Nesterov, Pavel Machek,
	Pekka Enberg, LKML

On Sun, Apr 29, 2007 at 07:51:04PM +0200, Rafael J. Wysocki wrote:
> Hi,
> 
> Sorry for the delay.

No problems! Even I was out for the weekend.

> >  /*
> >   * Tell the freezer to exempt this task from freezing
> > + * for events in freeze_event_mask.
> >   */
> > -static inline void freezer_exempt(struct task_struct *p)
> 
> I, personally, would introduce
> 
> static inline void freezer_exempt_event(struct task_struct *p,
> 				  unsigned long freeze_event_mask)
> {
> 	atomic_set_mask(freeze_event_mask, &p->freezer_flags);
> }
> 
> and then
> 
> static inline void freezer_exempt(struct task_struct *p)
> {
> 	freezer_exempt_event(p, FE_ALL);
> }
> 
> The patch would be shorter. ;-)
> 

Agreed. Will do that.

> [In that case I'd probably rename freezer_should_exempt() to
> freezer_should_exempt_event(), for symmetry.]
> 

Ok. 

> > +
> > +static inline int thawable(struct task_struct *p)
> > +{
> > +	if (!freezeable(p))
> > +		return 0;
> > +
> > +	/* Thaw p iff it is frozen for current_freezer_event alone */
> > +	 if (process_frozen_event_mask(p) & ~current_freezer_event)
> > +	 	return 0;
> > +
> > +	return 1;
> 
> I would do
> 
> 	return !(process_frozen_event_mask(p) & ~current_freezer_event);

I was wondering if the statement
	 if (process_frozen_event_mask(p) & ~current_freezer_event)
	 	return 0;

would be readable in the first place! 
Yeah, we can do what you have suggested.

> > -int freeze_processes(void)
> > +int freeze_processes(unsigned long freeze_event)
> >  {
> > -	unsigned int nr_unfrozen;
> > +	unsigned int nr_unfrozen = 0;
> > +
> > +	mutex_lock(&freezer_mutex);
> > +	if (system_frozen_event_mask & freeze_event)
> > +		goto out;
> > +
> > +	current_freezer_event = freeze_event;
> >  
> >  	printk("Stopping tasks ... ");
> >  	nr_unfrozen = try_to_freeze_tasks(FREEZER_USER_SPACE);
> >  	if (nr_unfrozen)
> > -		return nr_unfrozen;
> > +		goto out;
> >  
> >  	sys_sync();
> >  	nr_unfrozen = try_to_freeze_tasks(FREEZER_KERNEL_THREADS);
> >  	if (nr_unfrozen)
> > -		return nr_unfrozen;
> > +		goto out;
> >  
> > +	system_frozen_event_mask |= current_freezer_event;
> >  	printk("done.\n");
> >  	BUG_ON(in_atomic());
> 
> The BUG_ON() is still valid if tasks are already frozen for this event.

Right! So we would need one more label. How about the following?

	mutex_lock(&freezer_mutex);
	/* check if already frozen for the event */
	if (system_frozen_event_mask & freeze_event)
		goto out_frozen;
		.
		.
		.

out_frozen: 
	BUG_ON(in_atomic());
out:
	current_freezer_event = 0;
	mutex_unlock(&freezer_mutex);
	return nr_unfrozen;
}

> 

> > -void thaw_processes(void)
> > +void thaw_processes(unsigned long thaw_event)
> >  {
> > +	mutex_lock(&freezer_mutex);
> > +	if (!(system_frozen_event_mask & thaw_event)) {
> > +		WARN_ON(1);
> 
> Hmm, I wouldn't use the WARN_ON() here.  There's nothing wrong in calling
> this twice in a row as long as we do the sanity checking.  There's even one
> case in which that may be convenient, actually.

Well, yes. But I put the warn on from the perspective of someone trying
to thaw_processes for the event for which they have not frozen. I hadn't
thought about a double thaw. Will rethink.

Thanks for the Review.
Regards
gautham.
-- 
Gautham R Shenoy
Linux Technology Center
IBM India.
"Freedom comes with a price tag of responsibility, which is still a bargain,
because Freedom is priceless!"

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

end of thread, other threads:[~2007-04-30 19:20 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-04-27 15:37 [PATCH -mm 0/2] Separate freezer from PM code Rafael J. Wysocki
2007-04-27 15:38 ` [PATCH -mm 1/2] " Rafael J. Wysocki
2007-04-27 16:15   ` Sam Ravnborg
2007-04-27 16:25   ` Jeremy Fitzhardinge
2007-04-27 20:20     ` Rafael J. Wysocki
2007-04-27 20:20       ` Jeremy Fitzhardinge
2007-04-27 21:29         ` Rafael J. Wysocki
2007-04-29  8:43           ` Sam Ravnborg
2007-04-27 15:40 ` [PATCH -mm 2/2] Introduce freezer flags Rafael J. Wysocki
2007-04-27 16:19   ` Sam Ravnborg
2007-04-27 16:33     ` Gautham R Shenoy
2007-04-27 21:40   ` Gautham R Shenoy
2007-04-27 21:49     ` Rafael J. Wysocki
2007-04-27 21:49       ` Gautham R Shenoy
2007-04-27 22:09       ` Rafael J. Wysocki
2007-04-27 22:07         ` Pavel Machek
2007-04-27 22:56           ` Rafael J. Wysocki
2007-04-28  7:07             ` Pavel Machek
2007-04-28  1:34   ` [PATCH -mm] Allow selective freezing of the system for different events Gautham R Shenoy
2007-04-28  6:22     ` Andrew Morton
2007-04-28  7:45       ` Gautham R Shenoy
2007-04-29 17:51     ` Rafael J. Wysocki
2007-04-30 19:19       ` Gautham R Shenoy

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).