Skip to content

Commit

Permalink
freezer: restructure __refrigerator()
Browse files Browse the repository at this point in the history
If another freeze happens before all tasks leave FROZEN state after
being thawed, the freezer can see the existing FROZEN and consider the
tasks to be frozen but they can clear FROZEN without checking the new
freezing().

Oleg suggested restructuring __refrigerator() such that there's single
condition check section inside freezer_lock and sigpending is cleared
afterwards, which fixes the problem and simplifies the code.
Restructure accordingly.

-v2: Frozen loop exited without releasing freezer_lock.  Fixed.

Signed-off-by: Tejun Heo <tj@kernel.org>
Reported-by: Oleg Nesterov <oleg@redhat.com>
Acked-by: Oleg Nesterov <oleg@redhat.com>
Cc: "Rafael J. Wysocki" <rjw@sisk.pl>
  • Loading branch information
Tejun Heo committed Nov 21, 2011
1 parent 96ee6d8 commit 5ece3ea
Showing 1 changed file with 11 additions and 21 deletions.
32 changes: 11 additions & 21 deletions kernel/freezer.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,39 +52,29 @@ bool __refrigerator(bool check_kthr_stop)
/* Hmm, should we be allowed to suspend when there are realtime
processes around? */
bool was_frozen = false;
long save;
long save = current->state;

/*
* No point in checking freezing() again - the caller already did.
* Proceed to enter FROZEN.
*/
spin_lock_irq(&freezer_lock);
repeat:
current->flags |= PF_FROZEN;
spin_unlock_irq(&freezer_lock);

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);

spin_lock_irq(&freezer_lock);
current->flags |= PF_FROZEN;
if (!freezing(current) ||
(check_kthr_stop && kthread_should_stop()))
current->flags &= ~PF_FROZEN;
spin_unlock_irq(&freezer_lock);

if (!(current->flags & PF_FROZEN))
break;
was_frozen = true;
schedule();
}

/* leave FROZEN */
spin_lock_irq(&freezer_lock);
if (freezing(current))
goto repeat;
current->flags &= ~PF_FROZEN;
spin_unlock_irq(&freezer_lock);
spin_lock_irq(&current->sighand->siglock);
recalc_sigpending(); /* We sent fake signal, clean it up */
spin_unlock_irq(&current->sighand->siglock);

pr_debug("%s left refrigerator\n", current->comm);

Expand Down

0 comments on commit 5ece3ea

Please sign in to comment.