Re: [RFC][PATCH -mm 3/3] freezer: Fix problem with kthread_stop

Previous thread: [KJ][PATCH]SPIN_LOCK_UNLOCKED cleanup in drivers/atm, net by Milind Arun Choudhary on Thursday, April 19, 2007 - 5:02 am. (1 message)

Next thread: [KJ][PATCH]SPIN_LOCK_UNLOCKED cleanup in init_task.h by Milind Arun Choudhary on Thursday, April 19, 2007 - 5:13 am. (1 message)
From: Gautham R Shenoy
Date: Thursday, April 19, 2007 - 5:01 am

Hello Everyone, 
Oleg had pointed out some subtle races which could lead to the failure
of the process freezer in the patchset which I had posted earlier.

A couple of these problems seem to be present in the latest -mm(2.6.21-rc6-mm1).

This is an attempt to fix them.

Awaiting you feedback, 
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!"
-

From: Gautham R Shenoy
Date: Thursday, April 19, 2007 - 5:02 am

This patch fixes the race pointed out by Oleg Nesterov.

* Freezer marks a thread as freezeable. 
* The thread now marks itself PF_NOFREEZE causing it to
  freeze on calling try_to_freeze(). Thus the task is frozen, even though
  it doesn't want to.
* Subsequent thaw_processes() will also fail to thaw the task since it is 
  marked PF_NOFREEZE.

Avoid this problem by checking the current task's PF_NOFREEZE status in the 
refrigerator before marking current as frozen.

Signed-off-by: Gautham R Shenoy <ego@in.ibm.com>
---
 kernel/power/process.c |    9 +++++++++
 1 file changed, 9 insertions(+)

Index: linux-2.6.21-rc6/kernel/power/process.c
===================================================================
--- linux-2.6.21-rc6.orig/kernel/power/process.c
+++ linux-2.6.21-rc6/kernel/power/process.c
@@ -41,6 +41,15 @@ void refrigerator(void)
 
 	task_lock(current);
 	if (freezing(current)) {
+		/* check if we had marked ourself PF_NOFREEZE
+		 * *after* the freezer did the freezeable() check
+		 * on us.
+		 */
+		if (current->flags & PF_NOFREEZE) {
+			clear_tsk_thread_flag(current, TIF_FREEZE);
+			task_unlock(current);
+			return;
+		}
 		frozen_process(current);
 		task_unlock(current);
 	} else {
-- 
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!"
-

From: Rafael J. Wysocki
Date: Thursday, April 19, 2007 - 2:39 pm

Hi,


Looks good, although I'm not sure if we don't need to call recalc_sigpending()
for tasks that turn out to be PF_NOFREEZE.

Greetings,
Rafael
-

From: Oleg Nesterov
Date: Friday, April 20, 2007 - 11:02 am

I agree, we should clear TIF_SIGPENDING. It is not so critical for user-space
tasks, but for the kernel thread it may remain pending forever, causing subtle
failures.

Gautham, isn't it possible to make a more simpler patch ? Just add PF_NOFREEZE
check to frozen_process,

	static inline void frozen_process(struct task_struct *p)
	{
		if (!unlikely(current->flags & PF_NOFREEZE)) {
			p->flags |= PF_FROZEN;
			wmb();
		}
		clear_tsk_thread_flag(p, TIF_FREEZE);
	}

No?

Oleg.

-

From: Gautham R Shenoy
Date: Monday, April 23, 2007 - 3:26 am

Actually yes. The idea anyway was to check one last time before declaring
ourselves as frozen. So I thought the best place was inside refrigerator since
we are already holding the task_lock there.
I wasn't too sure about calling recalc_sigpending(), but now that you
mention it, I agree, this would be a nicer way to do it.

Btw, since frozen_process is currently being called only from
refrigerator, I am wondering if we still need the struct task_struct *p
parameter there. It's very unlikely that some other task would mark a
particular task as frozen. No?

Anyways, Andrew, Could you please replace the earlier sent patch titled
"fix_pf_nofreeze_and_freezeable_race.patch" with the following one?

Thanks and Regards
gautham.

-->
This patch fixes the race pointed out by Oleg Nesterov.

* Freezer marks a thread as freezeable.
* The thread now marks itself PF_NOFREEZE causing it to
  freeze on calling try_to_freeze(). Thus the task is frozen, even though
  it doesn't want to.
* Subsequent thaw_processes() will also fail to thaw the task since it is
  marked PF_NOFREEZE.

Avoid this problem by checking the task's PF_NOFREEZE status in 
frozen_processes() before marking the task as frozen.

Signed-off-by: Gautham R Shenoy <ego@in.ibm.com>
---
 include/linux/freezer.h |    6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

Index: linux-2.6.21-rc6/include/linux/freezer.h
===================================================================
--- linux-2.6.21-rc6.orig/include/linux/freezer.h
+++ linux-2.6.21-rc6/include/linux/freezer.h
@@ -57,8 +57,10 @@ static inline int thaw_process(struct ta
  */
 static inline void frozen_process(struct task_struct *p)
 {
-	p->flags |= PF_FROZEN;
-	wmb();
+	if (!unlikely(p->flags & PF_NOFREEZE)) {
+		p->flags |= PF_FROZEN;
+		wmb();
+	}
 	clear_tsk_thread_flag(p, TIF_FREEZE);
 }
 
-- 
Gautham R Shenoy
Linux Technology Center
IBM India.
"Freedom comes with a price tag of responsibility, which is still a bargain,
because ...
From: Oleg Nesterov
Date: Monday, April 23, 2007 - 10:49 am

I agree. Only "current" can set PF_FROZEN anyway. I also think it is better
to move this function into kernel/power/process.c, no need to export it in
freezer.h. It is special, should be called from refrigerator() with task_lock()

On the second thought, this patch doesn't help if the thread never
calls try_to_freeze() exactly because it marks itself PF_NOFREEZE.

Perhaps it is better to cancel freezing in soon-to-be-introduced
freezer_exempt().

In any case I agree, this one is better than current
	fix_pf_nofreeze_and_freezeable_race.patch

Oleg.

-

From: Gautham R Shenoy
Date: Thursday, April 19, 2007 - 5:04 am

Threads which wait for completion on a frozen thread might result in 
causing the freezer to fail, if the waiting thread is freezeable.

There are some well known cases where it's preferable to temporarily thaw
the frozen process, finish the wait for completion and allow both the 
processes to call try_to_freeze. 

kthread_stop is one such case. flush_workqueue might be another. 

This patch attempts to address such a situation with a fix for kthread_stop.

Strictly experimental. Compile tested on i386.

Signed-off-by: Gautham R Shenoy <ego@in.ibm.com>

---
 include/asm-arm/thread_info.h      |    2 
 include/asm-blackfin/thread_info.h |    4 +
 include/asm-frv/thread_info.h      |    4 +
 include/asm-i386/thread_info.h     |    4 +
 include/asm-ia64/thread_info.h     |    4 +
 include/asm-mips/thread_info.h     |    2 
 include/asm-powerpc/thread_info.h  |    4 +
 include/asm-sh/thread_info.h       |    2 
 include/asm-x86_64/thread_info.h   |    4 +
 include/linux/freezer.h            |    4 +
 kernel/kthread.c                   |    4 +
 kernel/power/process.c             |   81 ++++++++++++++++++++++++++++++++++++-
 12 files changed, 118 insertions(+), 1 deletion(-)

Index: linux-2.6.21-rc6/kernel/power/process.c
===================================================================
--- linux-2.6.21-rc6.orig/kernel/power/process.c
+++ linux-2.6.21-rc6/kernel/power/process.c
@@ -23,6 +23,16 @@
 #define FREEZER_KERNEL_THREADS 0
 #define FREEZER_USER_SPACE 1
 
+struct freezer_status_struct {
+	spinlock_t lock;
+	int count;
+};
+
+static struct freezer_status_struct freezer_status = {
+				.lock = SPIN_LOCK_UNLOCKED,
+				.count = 0,
+			};
+
 static inline int freezeable(struct task_struct * p)
 {
 	if ((p == current) ||
@@ -45,7 +55,8 @@ void refrigerator(void)
 		 * *after* the freezer did the freezeable() check
 		 * on us.
 		 */
-		if (current->flags & PF_NOFREEZE) {
+		if ((current->flags & PF_NOFREEZE) ||
+		    test_tsk_thread_flag(current, ...
From: Andrew Morton
Date: Thursday, April 19, 2007 - 2:31 pm

On Thu, 19 Apr 2007 17:34:19 +0530


flush_workqueue() just needs to die.  I think there are (almost) no


Rather than doing <whatever you did>, perhaps we could make the freezing
process a dual-pass thing.  On pass 1, mark all the threads as "we'll be
freezing you soon" and on the second pass, do the actual freezing.  Then,
in problematic places such as kthread_stop() we can look to see if we'll
soon be asked to freeze and if so, run try_to_freeze().

Of course, running try_to_freeze() in kthread_stop() would be very wrong,
so we'd actually need to do it in callers, preferably via a new
kthread_stop_freezeable() wrapper.

And the two-pass-freeze thing is of course racy.  It's also unnecessary:
setting a flag on every task in the machine is equivalent to setting a
global variable.  So perhaps just use a global variable?

int kthread_stop_freezeable(struct task_struct *k)
{
	if (freeze_state == ABOUT_TO_START) {
		wait_for(freeze_state == STARTED);
		try_to_freeze();
	}
	kthread_stop(k);
}

which is theoretically racy if another freeze_processes() starts




hm, all this duplication is unpleasing.  We could do something similar to
include/linux/buffer_head.h:BH_PrivateStart here: get all architectures to
define a TIF_COMMON_STUFF_STARTS_HERE then include asm-generic/whatever.h
which defines all the flags which every architecture must define, as
TIF_COMMON_STUFF_STARTS_HERE+0, TIF_COMMON_STUFF_STARTS_HERE+1, etc.


-

From: Rafael J. Wysocki
Date: Friday, April 20, 2007 - 1:54 am

Hmm, can't we do something like this instead:

---
 kernel/kthread.c |   10 ++++++++++
 1 file changed, 10 insertions(+)

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
@@ -13,6 +13,7 @@
 #include <linux/file.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/freezer.h>
 #include <asm/semaphore.h>
 
 /*
@@ -232,6 +233,15 @@ int kthread_stop(struct task_struct *k)
 
 	/* Now set kthread_should_stop() to true, and wake it up. */
 	kthread_stop_info.k = k;
+	if (!(current->flags & PF_NOFREEZE)) {
+		/* If we are freezable, the freezer will wait for us */
+		task_lock(k);
+		k->flags |= PF_NOFREEZE;
+		if (frozen(k))
+			k->flags &= ~PF_FROZEN;
+
+		task_unlock(k);
+	}
 	wake_up_process(k);
 	put_task_struct(k);
 
-

From: Gautham R Shenoy
Date: Friday, April 20, 2007 - 4:05 am

Yes, we can do this for now since the tasks have only two freeze states,
namely Freezeable and Non Freezeable. 
But with more events like cpu-hotplug and kprobes using the process
freezer, the simple check

	if(!(current->flags & PF_NOFREEZE))

may not suffice and something like
	if(!(current->flags & PFE_ALL & global_freeze_mask))
 	/* global_freeze_mask is the mask of the events for which the system
	  is freezing. */

appears to be racy. Not that we cannot work it out ;-)

However, I was attempting to solve the generic problem where
A waits on B and B is frozen. If A is freezeable (under one of the
events) then the freezer will fail. So a solution would be for A to
somehow inform B of the dependency and postpone it's freezing.

Since akpm mentioned that flush_workqueue() needs to go, I guess, I am
ok with fixing only kthread_stop/kthread_should_stop for the moment.

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!"
-

From: Rafael J. Wysocki
Date: Friday, April 20, 2007 - 4:59 am

Actually, I thought about it for a while.  The thread that is going to stop
another one may temporarily mark itself as freezable in all cases, which
will have no effect on it, since it's not going to cally try_to_freeze(), but
will make the freezer wait for it.  Next, after returning from
wait_for_completion(), it should restore its old freezability status and that

Well, I think it might be simpler to consider each case separately.  This way

Sure. :-)

BTW, if it turns out that we need to introduce yet another freezer-related
TIF_ flag, it may be acceptable (?) to move all of the freezer-related flags
into a separate member of task_struct (eg. freezer_flags) that can only be
manipulated under task_lock().

I mean, we already have four of them (PF_NOFREEZE, PF_FROZEN,
PF_FREEZER_SKIP, TIF_FREEZE), and you will need to introduce two more for
the freezer-based CPU hotplug, so if yet another one is needed, that will make
up almost a separate u8 field ...

Greetings,
Rafael
-

From: Gautham R Shenoy
Date: Friday, April 20, 2007 - 5:26 am

But that will have no affect if the thread to be stopped is already
frozen. The only affect might be that now, freezer will fail whether
the thread that is going to stop another one was freezeable or not.

Concern is whether we can somehow complete these wait_for_completion()'s in 


I am perfectly ok with it. But I am not sure if everybody would agree to have

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!"
-

From: Rafael J. Wysocki
Date: Friday, April 20, 2007 - 5:50 am

To be precise, I was thinking about something like this (in pseudo-code):

	kthread_stop_info.k = k;
	save_freezable_status(current);
	set_always_freezable(current);
	/* Now, we know that the freezer will wait for us, although we're not
	 * really going to freeze
	 */
	task_lock(k);
	k->flags |= PF_NOFREEZE;
	if (frozen(k))
		k->flags &= ~PF_FROZEN;

	task_unlock(k);
	wake_up_process(k);
	put_task_struct(k);

	/* Once it dies, reset stop ptr, gather result and we're done. */
	wait_for_completion(&kthread_stop_info.done);

Well, I'm not sure either, but I guess the most practical way to learn it is to
send a patch. ;-)

Greetings,
Rafael


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

From: Andrew Morton
Date: Friday, April 20, 2007 - 10:30 am

On Fri, 20 Apr 2007 17:56:09 +0530

OK by me.  You might want to consider making that fields's locking protocol
be set_bit(), clear_bit(), etc rather than task_lock().
-

From: Ingo Molnar
Date: Friday, April 20, 2007 - 11:31 am

is OK to me too, the extra field isnt a problem.

	Ingo
-

From: Rafael J. Wysocki
Date: Friday, April 20, 2007 - 2:13 pm

OK, so I'll try to prepare a patch introducing it over the weekend. :-)

Greetings,
Rafael
-

From: Rafael J. Wysocki
Date: Sunday, April 22, 2007 - 12:28 pm

Hi,

The following three patches are related to the separation of the freezer flags
from process/threadinfo flags.

The first patch separates the freezer from the PM code, because it's no longer
a PM-specific piece of code.  This also makes the second patch look better.

The second patch introduces the freezer_flags field of task_struct, present
only if the freezer is compiled in.  All of the freezer-related flags per-task
flags are moved to this field and auxiliary functions for operating them are
defined in freezer.h .  This overlaps with the Gautham's work to some extent,
but I think it's better to introduce these changes independently of the CPU
hotplug code.

The third patch is a bonus. ;-)

Greetings,
Rafael

-

From: Rafael J. Wysocki
Date: Sunday, April 22, 2007 - 12:40 pm

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

Fix the problem with kthread_stop() that causes the freezer to fail if a
freezable thread is attempting to stop a frozen one and that may cause the
freezer to fail if the thread being stopped is freezable and
try_to_freeze_tasks() is running concurrently with kthread_stop().

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 kernel/kthread.c |    9 +++++++++
 1 file changed, 9 insertions(+)

Index: linux-2.6.21-rc6-mm1/kernel/kthread.c
===================================================================
--- linux-2.6.21-rc6-mm1.orig/kernel/kthread.c	2007-04-09 15:23:48.000000000 +0200
+++ linux-2.6.21-rc6-mm1/kernel/kthread.c	2007-04-22 19:05:29.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>
 
 /*
@@ -232,6 +233,14 @@ int kthread_stop(struct task_struct *k)
 
 	/* Now set kthread_should_stop() to true, and wake it up. */
 	kthread_stop_info.k = k;
+	if (!freezer_should_exempt(current)) {
+		/* We are freezable, so we must make sure that the thread being
+		 * stopped is not frozen and will not be frozen until it dies
+		 */
+		freezer_exempt(k);
+		if (frozen(k))
+			clear_frozen_flag(k);
+	}
 	wake_up_process(k);
 	put_task_struct(k);
 
-

From: Pavel Machek
Date: Monday, April 23, 2007 - 3:40 am

Do we need to take some locks to access other process' flags? Or do
frozen_exempt() etc take enough locks, already?
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
-

From: Rafael J. Wysocki
Date: Monday, April 23, 2007 - 12:50 pm

Hi,



After the previous patch we only use set_bit(), clear_bit() and test_bit() to
access freezer_falgs, so no special locking is needed to protect them.

Greetings,
Rafael
-

From: Gautham R Shenoy
Date: Monday, April 23, 2007 - 5:35 am

I'm trying hard to convince myself that this will work. May be I am
missing something here, but I find a potential race window (very small though) 
when k is entering the refrigerator.

Here's how.

kthread_stop(k)					k->refrigerator()
---------------------------------------------------------------------
						task_lock(k);
						1) check_if_exempted();
						/* not exempted. So 
						 * we will freeze
						 * ourself.
						 */
2) freezer_exempt(k);

3) if(frozen(k))
/* No, we're not yet frozen. So we
 * don't clear_frozen_flag(k) here
 */
						4) frozen_process(k);
						   task_unlock(k);
						
						5) for(;;) {
						 set_current_state(UNINTERRUPTIBLE);
						  if(!frozen_process(k))
						  /* k is frozen. We
						   * don't break :( 
						   */
						 
						  	schedule();

Thus the freezer can still fail, no?


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!"
-

From: Oleg Nesterov
Date: Monday, April 23, 2007 - 12:03 pm

Well, probably I missed something, but why can't we do

	if (!freezer_should_exempt(current)) {
		freezer_exempt(k);
		thaw_process(k);
	}
?

thaw_process(k) is properly serialized with refrigerator(), and it checks
frozen(k). We can make an extra wake_up, but this should not matter.

Rafael, please check the recent changes in kthread.c, kthread_stop() was
reworked, we don't have kthread_stop_info any longer.

Oleg.

-

From: Rafael J. Wysocki
Date: Monday, April 23, 2007 - 1:05 pm

OK, I will, thanks.

Greetings,
Rafael
-

From: Rafael J. Wysocki
Date: Monday, April 23, 2007 - 12:55 pm

Yes, that's correct.  We need to take task_lock() to avoid the race with
refrigerator().

I'll fix the patch.

BTW, I think I should rediff the entire series against -mm with your patch from
http://lkml.org/lkml/2007/4/23/98 applied.

Greetings,
Rafael

-

From: Oleg Nesterov
Date: Monday, April 23, 2007 - 1:46 pm

Even if we use thaw_task() ?

Even if I am wrong, I think we should not use task_lock() for the freezing
related code, except in freezer.[ch]

Note also that without CONFIG_FREEZER freezer_should_exempt() == 0, so we
will do unneeded task_lock/task_unlock.

Oleg.

-

From: Gautham R Shenoy
Date: Monday, April 23, 2007 - 2:16 pm

I don't think so. As you correctly pointed out, thaw_task() is race free

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!"
-

From: Rafael J. Wysocki
Date: Monday, April 23, 2007 - 2:30 pm

Agreed.

Rafael
-

From: Rafael J. Wysocki
Date: Sunday, April 22, 2007 - 12:39 pm

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         |    6 +--
 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                |   65 ++++++++++++++++++++++++++-------
 include/linux/sched.h                  |    8 ++--
 kernel/fork.c                          |    2 -
 kernel/freezer.c                       |    2 -
 kernel/rcutorture.c                    |    4 +-
 kernel/sched.c                         |    2 -
 kernel/softirq.c                       |    2 -
 kernel/softlockup.c                    |    2 -
 kernel/workqueue.c                     |    2 -
 30 files changed, 83 insertions(+), 58 deletions(-)

Index: linux-2.6.21-rc6-mm1/include/linux/sched.h
===================================================================
--- linux-2.6.21-rc6-mm1.orig/include/linux/sched.h	2007-04-22 19:37:42.000000000 +0200
+++ ...
From: Paul Jackson
Date: Sunday, April 22, 2007 - 2:14 pm

It's getting time I learned what this freezer thing is.

What would you suggest I read?

I looked in include/linux/freezer.h and didn't see any explanations.
I found one Documenation file, power/kernel_threads.txt, that explained
the interaction of freezing and kernel threads.  I looked in the
comments for various 2.6.21-rc6-mm1 freezer* patches, and saw various
interesting details.

But I couldn't find any documentation telling me what a freezer was,
or what a refrigerator is.

Did I miss something?

-- 
                  I won't rest till it's the best ...
                  Programmer, Linux Scalability
                  Paul Jackson <pj@sgi.com> 1.925.600.0401
-

From: Rafael J. Wysocki
Date: Sunday, April 22, 2007 - 3:14 pm

Well, unfortunately not.  The freezer is not separately documented, mainly
because (1) for a long time it's been a part of the suspend code and no one
else used it, and (2) because it's been changing a lot recently and it's been
a 'moving target' from the documentation point of view.

I'll try to explain how it works.

In short, we use the freezer to make tasks enter a specific function, called
the refrigerator, and stay there until they are let out.  This is done by
calling freeze_processes() (in 2.6.21-rc7 it is located in
kernel/power/process.c) that executes try_to_freeze_tasks() separately for
userland processes and kernel threads (the sync() in between is needed by
the suspend code).  try_to_freeze_tasks() sets the FREEZE flag (TIF_FREEZE in
2.6.21-rc7) for each freezable (I'll explain what that means in a while) task
and sends a fake signal to it.

Userland processes then go to get_signal_to_deliver(), where they execute
try_to_freeze() (defined in include/linux/freezer.h) and call refrigerator()
(in kernel/power/process.c), since the FREEZE flag is set.  In refrigerator()
they reset the FREEZE flag and set the FROZEN flag (in 2.6.21-rc7 it is a
process flag defined in sched.h).  Next, they loop in refrigerator() until
someone resets the FROZEN flag for them.  Then we say that they are 'frozen'.

Kernel threads don't call get_signal_to_deliver(), so they have to execute
try_to_freeze() directly to go to the refrigerator.  Moreover, kernel threads
may not want to go there at all, in which case they should set the NOFREEZE
flag (in 2.6.21-rc7 it is a process flag defined in sched.h), that makes
try_to_freeze_tasks() ignore them.

Apart from the kernel threads that have the NOFREEZE flag set,
try_to_freeze_tasks() ignores the task that's running it (its current task)
and the tasks that have exit_state different from 0.  They all are regarded
as 'not freezable'.

Of course, kernel threads that declare themselves as not freezable, by setting
the NOFREEZE flag, should be ...
From: Paul Jackson
Date: Sunday, April 22, 2007 - 3:31 pm

Ok - thanks.  Good explanation of how it works.

One more question - why would I want to do this?

Is this like something that would be useful on a laptop, to suspend
activity and reduce battery drain, while preserving the current state
of ones sessions and avoiding having to logout or shutdown?

Or are there other good uses for this?

Is it useful for quietting a system down before doing hot plug or
unplug of key components, such as processors and memory?

Thanks.

-- 
                  I won't rest till it's the best ...
                  Programmer, Linux Scalability
                  Paul Jackson <pj@sgi.com> 1.925.600.0401
-

From: Satyam Sharma
Date: Sunday, April 22, 2007 - 8:18 pm

Yes, the original purpose for the inclusion of the freezer code was to
support suspend-resume (mainly for laptops, but suspend-resume could

Yes, the freezer is (proposed to be, at least) moving on from being
merely a suspend-resume-only thing to other usage scenarios, such as
kprobes and hotlpug.
-

From: Satyam Sharma
Date: Sunday, April 22, 2007 - 9:09 pm

Aren't NOFREEZE and SKIP doing the same thing? One of them appears
superfluous. I'm looking at 21-rc6-mm1 and vfork(2) seems to be its
only user. Seeing how vfork(2) used it, can't the call to
freezer_do_not_count() be replaced with a call to freezer_exempt()?
Similarly, the freezer_count() after the wait_for_completion might
just as well be a clear of the NOFREEZE bit followed by a
try_to_freeze(). Could you please explain the rationale behind the
SKIP flag?

I do see that SKIP seems to be relevant for only userspace threads and
presumably only kernel threads are allowed to set NOFREEZE, but why
this distinction between the two?



This definitely needs to be undo_freeze() or unfreeze().

frozen_process() sounds like what frozen() is supposed to do. This
could instead be mark_task_frozen(), or even mark_frozen(), because
only the current task can ever mark *itself* frozen before freezing

These could be called freezer_skip() and freezer_do_not_skip(). Better
to stick to consistent naming / terminology.

Cheers,
Satyam
-

From: Gautham R Shenoy
Date: Monday, April 23, 2007 - 7:19 am

Hi Satyam, 

The difference between the NOFREEZE and the SKIP flag is a subtle one.

When a task (say p) sets it's NOFREEZE flag, it tells the freezer not to
consider it for freezing. Which means freezeable(p) will return 0.
So the freezer will not even mark it for freezing. 

However, when a task sets it SKIP flag, it tells the freezer - "I might
block at a safe place. So when you are counting the processes which
have been marked as freezeable, but have not frozen yet, please don't
count me in. IOW, please skip me."  
Thus such a task can still be marked for freezing.

The typical usage is 
freezer_do_not_count(current);
/* currents goes to an uninterruptible sleep, like wait_for_completion. */
freezer_count(current);

Once the task wakes up from it's uninterruptible sleep, it will 
call freezer_count which in turn calls try_to_freeze.
If the task was marked for freezing, it will be frozen now.

You may want to check the thread http://lkml.org/lkml/2007/2/18/47 

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!"
-

From: Rafael J. Wysocki
Date: Monday, April 23, 2007 - 11:49 am

Very well explained.  Thanks!

Greetings,
Rafael

-

From: Rafael J. Wysocki
Date: Monday, April 23, 2007 - 12:06 pm

Hi,


Well, I agree that the names are not the best ones, but I'd like to avoid
changing the existing names in this particular patch.

We can change them later, on top of it.

Greetings,
Rafael
-

From: Gautham R Shenoy
Date: Monday, April 23, 2007 - 6:17 am

We may want to rename do_not_freeze to something else. It kind of
looks weird calling do_not_freeze(p) after setting the frozen flag!


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!"
-

From: Rafael J. Wysocki
Date: Monday, April 23, 2007 - 12:57 pm

Hmm, I wanted to avoid changing the existing names in this patch, but in this
particular case you are obviously right.  I'll change that to
clear_freeze_flag().

Greetings,
Rafael
-

From: Oleg Nesterov
Date: Monday, April 23, 2007 - 3:23 pm

OK, but you forgot to clear p->freezer_flags on copy_process()->dup_task_struct()
path ?

Oleg.

-

From: Rafael J. Wysocki
Date: Monday, April 23, 2007 - 3:40 pm

Yes, thanks for pointing that out.

Should I clear it in dup_task_struct() or is there a better place?
-

From: Gautham R Shenoy
Date: Monday, April 23, 2007 - 3:41 pm

That reminds me, shouldn't we set the child's TFF_FREEZE flag if the parent

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!"
-

From: Rafael J. Wysocki
Date: Monday, April 23, 2007 - 3:55 pm

Well, usually we'll want to freeze the child too in such cases, but I'm not
sure if that's always true.

Greetings,
Rafael
-

From: Oleg Nesterov
Date: Monday, April 23, 2007 - 3:55 pm

I personally think we should do this in dup_task_struct(). In fact, I believe
it is better to replace the

	*tsk = *orig;

with some helper (like setup_thread_stack() below), and that helper clears
->freezer_flags. Say, copy_task_struct().

Oleg.

-

From: Rafael J. Wysocki
Date: Monday, April 23, 2007 - 4:10 pm

Hmm, wouldn't that be overkill?  copy_task_struct() would have to do
*tsk = *orig anyway, and we only need to clear one field apart from this.

Some other fields are cleared towards the end of dup_task_struct(), so perhaps
we could clear freezer_flags in there too?

Rafael
-

From: Oleg Nesterov
Date: Monday, April 23, 2007 - 4:19 pm

Yes. And I strongly believe it is bad we don't have the helper which does some
random stuf like "p->did_exec = 0".

The same for thread_info. Could you answer quickly where do we clear TIF_FREEZE
currently? We don't.

Oleg.

-

From: Rafael J. Wysocki
Date: Tuesday, April 24, 2007 - 4:32 am

Right.

That said, I think the right thing to do would be to add just one line
'freezer_flags = 0' to dup_task_struct() directly in this patch and then
move all of the random stuff (including this line) to the helper in a separate
patch.

I mean, the introduction of the helper seems to be logically unrelated to the
other things this patch does, so it should go in another patch IMHO.

Greetings,
Rafael
-

From: Rafael J. Wysocki
Date: Sunday, April 22, 2007 - 12:33 pm

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         |    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         |  224 +++++++++++++++++++++++++++++++++++++++++++++++
 kernel/kprobes.c         |    2 
 kernel/power/Makefile    |    2 
 kernel/power/process.c   |  224 -----------------------------------------------
 19 files changed, 296 insertions(+), 227 deletions(-)

Index: linux-2.6.21-rc6-mm1/arch/x86_64/Kconfig
===================================================================
--- linux-2.6.21-rc6-mm1.orig/arch/x86_64/Kconfig	2007-04-22 14:14:44.000000000 +0200
+++ linux-2.6.21-rc6-mm1/arch/x86_64/Kconfig	2007-04-22 14:16:03.000000000 +0200
@@ -695,6 +695,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-rc6-mm1/arch/avr32/Kconfig.debug
===================================================================
--- linux-2.6.21-rc6-mm1.orig/arch/avr32/Kconfig.debug	2007-04-22 14:14:44.000000000 +0200
+++ linux-2.6.21-rc6-mm1/arch/avr32/Kconfig.debug	2007-04-22 14:16:03.000000000 +0200
@@ -17,3 +17,8 @@ config ...
From: Oleg Nesterov
Date: Friday, April 20, 2007 - 2:20 pm

No, we can't change k->flags, k owns its ->flags, and it is not atomic.

Rafael, may I suggest you to document task_lock() in thaw_process() ? This
looks really confusing, as if task_lock() protects "p->flags &= ~PF_FROZEN".

Actually, task_lock() is needed to prevent the race with refrigerator()
when the freezing fails, but this is not obvious.

Oleg.

-

From: Rafael J. Wysocki
Date: Friday, April 20, 2007 - 2:45 pm

Yes, but if we move PF_FROZEN to a separate field in task_struct with

Sure, I will.

Greetings,
Rafael
-

From: Gautham R Shenoy
Date: Friday, April 20, 2007 - 3:46 am

We can do that. Just that the freezer will now have to wait for 2 sets
of ack's instead of 1 set before declaring the system as frozen.

But the whole point of the patch was so that a thread A can tell
a thread B that it's dependent on the latter, and hence would like
to postpone B's freezing for some time. So I am thinking if we can

Well, even then we'll need to ensure that a thread would not call
kthread_stop_freezeable() with any locks held. That would mean more




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!"
-

From: Pavel Machek
Date: Saturday, April 21, 2007 - 2:37 am

I'll take audits over 200 new lines of code ;-). (And it should be
reasonably simple to audit; person doing kthread_stop() ->
ktrhread_stop_freezeable() should look after locks).
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
-

From: Oleg Nesterov
Date: Friday, April 20, 2007 - 2:12 pm

I think this can work if it is used only in kthread_stop(). But what if
another task wants to do hold_freezer_for_task(p) ? freezer_status.count
is recursive, but TIF_FREEZER_HELD is not. IOW, I believe this is not
generic enough.

Also, you are planning to add different freezing states (FE_HOTPLUG_CPU,
FE_SUSPEND, etc). In that case each of them needs a separate .count, because
it should be negative when try_to_freeze_tasks() returns. Now consider
the case when we are doing freeze_processes(FE_A | FE_B) ...

Oleg.

-

From: Gautham R Shenoy
Date: Monday, April 23, 2007 - 3:38 am

This can race with hold_freezer_for_task() calling thaw_process. Earlier
thaw_process(p) was called only after the process 'p' was frozen.
Now with hold_freezer_for_task(), we can as well call thaw_process(p)
when 'p' is in the freezing stage. Hence the task_lock.

Yes. If more than one tasks want another task to be temporarily thawed, this

So can't we in that case find out the weight of the freeze_event variable and

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!"
-

From: Oleg Nesterov
Date: Monday, April 23, 2007 - 11:39 am

hold_freezer_for_task()->thaw_process(p) will wake up the task. Or the
caller of refrigerator will notice "!frozen()". Note that refrigerator()
sets PF_FROZEN under task_lock().

In fact we have the same issue when thaw_tasks()->thaw_process(p) happens

Probably yes... but if we are speaking about kthrad_stop() only, this could
be afaics solved in more simple way, as Rafael suggests.

Oleg.

-

From: Gautham R Shenoy
Date: Monday, April 23, 2007 - 1:34 pm

I agree on this one. kthread_stop appears to be the only valid place
where such a correction is required. So Rafael's approach makes sense
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!"
-

Previous thread: [KJ][PATCH]SPIN_LOCK_UNLOCKED cleanup in drivers/atm, net by Milind Arun Choudhary on Thursday, April 19, 2007 - 5:02 am. (1 message)

Next thread: [KJ][PATCH]SPIN_LOCK_UNLOCKED cleanup in init_task.h by Milind Arun Choudhary on Thursday, April 19, 2007 - 5:13 am. (1 message)