Skip to content

Commit

Permalink
PM / Hibernate: Fix s2disk regression related to freezing workqueues
Browse files Browse the repository at this point in the history
Commit 2aede85

  PM / Hibernate: Freeze kernel threads after preallocating memory

introduced a mechanism by which kernel threads were frozen after
the preallocation of hibernate image memory to avoid problems with
frozen kernel threads not responding to memory freeing requests.
However, it overlooked the s2disk code path in which the
SNAPSHOT_CREATE_IMAGE ioctl was run directly after SNAPSHOT_FREE,
which caused freeze_workqueues_begin() to BUG(), because it saw
that worqueues had been already frozen.

Although in principle this issue might be addressed by removing
the relevant BUG_ON() from freeze_workqueues_begin(), that would
reintroduce the very problem that commit 2aede85
attempted to avoid into that particular code path.  For this reason,
to fix the issue at hand, introduce thaw_kernel_threads() and make
the SNAPSHOT_FREE ioctl execute it.

Special thanks to Srivatsa S. Bhat for detailed analysis of the
problem.

Reported-and-tested-by: Jiri Slaby <jslaby@suse.cz>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Acked-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
Cc: stable@kernel.org
  • Loading branch information
Rafael J. Wysocki committed Jan 29, 2012
1 parent 0a96265 commit 181e9bd
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 0 deletions.
2 changes: 2 additions & 0 deletions include/linux/freezer.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ extern bool __refrigerator(bool check_kthr_stop);
extern int freeze_processes(void);
extern int freeze_kernel_threads(void);
extern void thaw_processes(void);
extern void thaw_kernel_threads(void);

static inline bool try_to_freeze(void)
{
Expand Down Expand Up @@ -174,6 +175,7 @@ static inline bool __refrigerator(bool check_kthr_stop) { return false; }
static inline int freeze_processes(void) { return -ENOSYS; }
static inline int freeze_kernel_threads(void) { return -ENOSYS; }
static inline void thaw_processes(void) {}
static inline void thaw_kernel_threads(void) {}

static inline bool try_to_freeze(void) { return false; }

Expand Down
19 changes: 19 additions & 0 deletions kernel/power/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -188,3 +188,22 @@ void thaw_processes(void)
printk("done.\n");
}

void thaw_kernel_threads(void)
{
struct task_struct *g, *p;

pm_nosig_freezing = false;
printk("Restarting kernel threads ... ");

thaw_workqueues();

read_lock(&tasklist_lock);
do_each_thread(g, p) {
if (p->flags & (PF_KTHREAD | PF_WQ_WORKER))
__thaw_task(p);
} while_each_thread(g, p);
read_unlock(&tasklist_lock);

schedule();
printk("done.\n");
}
9 changes: 9 additions & 0 deletions kernel/power/user.c
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,15 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
swsusp_free();
memset(&data->handle, 0, sizeof(struct snapshot_handle));
data->ready = 0;
/*
* It is necessary to thaw kernel threads here, because
* SNAPSHOT_CREATE_IMAGE may be invoked directly after
* SNAPSHOT_FREE. In that case, if kernel threads were not
* thawed, the preallocation of memory carried out by
* hibernation_snapshot() might run into problems (i.e. it
* might fail or even deadlock).
*/
thaw_kernel_threads();
break;

case SNAPSHOT_PREF_IMAGE_SIZE:
Expand Down

0 comments on commit 181e9bd

Please sign in to comment.