]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'pm/linux-next'
authorStephen Rothwell <sfr@canb.auug.org.au>
Tue, 15 Nov 2011 01:06:32 +0000 (12:06 +1100)
committerStephen Rothwell <sfr@canb.auug.org.au>
Tue, 15 Nov 2011 01:06:37 +0000 (12:06 +1100)
12 files changed:
1  2 
arch/arm/mach-shmobile/pm-sh7372.c
arch/m68k/include/asm/thread_info.h
fs/btrfs/disk-io.c
fs/gfs2/log.c
fs/gfs2/quota.c
include/linux/freezer.h
include/linux/sched.h
kernel/exit.c
kernel/fork.c
kernel/freezer.c
kernel/kthread.c
mm/backing-dev.c

Simple merge
Simple merge
Simple merge
diff --cc fs/gfs2/log.c
Simple merge
diff --cc fs/gfs2/quota.c
Simple merge
index a5386e3ee756d6c85981b033dc0000deebfa59b7,09570ac22be6063d2efe1cd1e11f8aa39ab02cff..a9dccc6dbb246ca1302470f39f861cff43385b6e
@@@ -52,24 -40,23 +40,23 @@@ extern int freeze_processes(void)
  extern int freeze_kernel_threads(void);
  extern void thaw_processes(void);
  
- static inline int try_to_freeze(void)
+ static inline bool try_to_freeze(void)
  {
-       if (freezing(current)) {
-               refrigerator();
-               return 1;
-       } else
-               return 0;
+       might_sleep();
+       if (likely(!freezing(current)))
+               return false;
+       return __refrigerator(false);
  }
  
- extern bool freeze_task(struct task_struct *p, bool sig_only);
- extern void cancel_freezing(struct task_struct *p);
+ extern bool freeze_task(struct task_struct *p);
 -extern bool set_freezable(void);
++extern bool __set_freezable(bool with_signal);
  
  #ifdef CONFIG_CGROUP_FREEZER
- extern int cgroup_freezing_or_frozen(struct task_struct *task);
+ extern bool cgroup_freezing(struct task_struct *task);
  #else /* !CONFIG_CGROUP_FREEZER */
- static inline int cgroup_freezing_or_frozen(struct task_struct *task)
+ static inline bool cgroup_freezing(struct task_struct *task)
  {
-       return 0;
+       return false;
  }
  #endif /* !CONFIG_CGROUP_FREEZER */
  
@@@ -117,23 -104,6 +104,23 @@@ static inline int freezer_should_skip(s
        return !!(p->flags & PF_FREEZER_SKIP);
  }
  
- static inline void set_freezable(void)
 +/*
 + * Tell the freezer that the current task should be frozen by it
 + */
-       current->flags &= ~PF_NOFREEZE;
++static inline bool set_freezable(void)
 +{
- static inline void set_freezable_with_signal(void)
++      return __set_freezable(false);
 +}
 +
 +/*
 + * Tell the freezer that the current task should be frozen by it and that it
 + * should send a fake signal to the task to freeze it.
 + */
-       current->flags &= ~(PF_NOFREEZE | PF_FREEZER_NOSIG);
++static inline bool set_freezable_with_signal(void)
 +{
++      return __set_freezable(true);
 +}
 +
  /*
   * Freezer-friendly wrappers around wait_event_interruptible(),
   * wait_event_killable() and wait_event_interruptible_timeout(), originally
                __retval = wait_event_interruptible_timeout(wq,         \
                                (condition) || freezing(current),       \
                                __retval);                              \
-       } while (try_to_freeze());                                      \
+               if (__retval <= 0 || (condition))                       \
+                       break;                                          \
+               try_to_freeze();                                        \
+       }                                                               \
        __retval;                                                       \
  })
  #else /* !CONFIG_FREEZER */
- static inline int frozen(struct task_struct *p) { return 0; }
- static inline int freezing(struct task_struct *p) { return 0; }
- static inline void set_freeze_flag(struct task_struct *p) {}
- static inline void clear_freeze_flag(struct task_struct *p) {}
- static inline int thaw_process(struct task_struct *p) { return 1; }
+ static inline bool frozen(struct task_struct *p) { return false; }
+ static inline bool freezing(struct task_struct *p) { return false; }
++static inline void __thaw_task(struct task_struct *t) {}
  
- static inline void refrigerator(void) {}
+ 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) {}
Simple merge
diff --cc kernel/exit.c
Simple merge
diff --cc kernel/fork.c
Simple merge
index 7be56c53439723bb1f95ff43b6cb620ef1524193,9815b8d1eed5536e312c561a0c066578e359bd51..2589a61de44c9d8d33adc441948e4146b0c13a28
@@@ -9,21 -9,45 +9,45 @@@
  #include <linux/export.h>
  #include <linux/syscalls.h>
  #include <linux/freezer.h>
+ #include <linux/kthread.h>
  
- /*
-  * freezing is complete, mark current process as frozen
+ /* total number of freezing conditions in effect */
+ atomic_t system_freezing_cnt = ATOMIC_INIT(0);
+ EXPORT_SYMBOL(system_freezing_cnt);
+ /* indicate whether PM freezing is in effect, protected by pm_mutex */
+ bool pm_freezing;
+ bool pm_nosig_freezing;
+ /* protects freezing and frozen transitions */
+ static DEFINE_SPINLOCK(freezer_lock);
+ /**
+  * freezing_slow_path - slow path for testing whether a task needs to be frozen
+  * @p: task to be tested
+  *
+  * This function is called by freezing() if system_freezing_cnt isn't zero
+  * and tests whether @p needs to enter and stay in frozen state.  Can be
+  * called under any context.  The freezers are responsible for ensuring the
+  * target tasks see the updated state.
   */
static inline void frozen_process(void)
bool freezing_slow_path(struct task_struct *p)
  {
-       if (!unlikely(current->flags & PF_NOFREEZE)) {
-               current->flags |= PF_FROZEN;
-               smp_wmb();
-       }
-       clear_freeze_flag(current);
+       if (p->flags & PF_NOFREEZE)
+               return false;
+       if (pm_nosig_freezing || cgroup_freezing(p))
+               return true;
 -      if (pm_freezing && !(p->flags & PF_KTHREAD))
++      if (pm_freezing && !(p->flags & PF_FREEZER_NOSIG))
+               return true;
+       return false;
  }
+ EXPORT_SYMBOL(freezing_slow_path);
  
  /* Refrigerator is place where frozen processes are stored :-). */
void refrigerator(void)
bool __refrigerator(bool check_kthr_stop)
  {
        /* Hmm, should we be allowed to suspend when there are realtime
           processes around? */
                schedule();
        }
  
-       /* Remove the accounting blocker */
-       current->flags &= ~PF_FREEZING;
++      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);
-       __set_current_state(save);
+       /*
+        * Restore saved task state before returning.  The mb'd version
+        * needs to be used; otherwise, it might silently break
+        * synchronization which depends on ordered task state change.
+        */
+       set_current_state(save);
+       return was_frozen;
  }
- EXPORT_SYMBOL(refrigerator);
+ EXPORT_SYMBOL(__refrigerator);
  
  static void fake_signal_wake_up(struct task_struct *p)
  {
  }
  
  /**
-  *    freeze_task - send a freeze request to given task
-  *    @p: task to send the request to
-  *    @sig_only: if set, the request will only be sent if the task has the
-  *            PF_FREEZER_NOSIG flag unset
-  *    Return value: 'false', if @sig_only is set and the task has
-  *            PF_FREEZER_NOSIG set or the task is frozen, 'true', otherwise
+  * freeze_task - send a freeze request to given task
+  * @p: task to send the request to
   *
-  *    The freeze request is sent by setting the tasks's TIF_FREEZE flag and
-  *    either sending a fake signal to it or waking it up, depending on whether
-  *    or not it has PF_FREEZER_NOSIG set.  If @sig_only is set and the task
-  *    has PF_FREEZER_NOSIG set (ie. it is a typical kernel thread), its
-  *    TIF_FREEZE flag will not be set.
+  * If @p is freezing, the freeze request is sent by setting %TIF_FREEZE
+  * flag and either sending a fake signal to it or waking it up, depending
+  * on whether it has %PF_FREEZER_NOSIG set.
+  *
+  * RETURNS:
+  * %false, if @p is not freezing or already frozen; %true, otherwise
   */
- bool freeze_task(struct task_struct *p, bool sig_only)
+ bool freeze_task(struct task_struct *p)
  {
-       /*
-        * We first check if the task is freezing and next if it has already
-        * been frozen to avoid the race with frozen_process() which first marks
-        * the task as frozen and next clears its TIF_FREEZE.
-        */
-       if (!freezing(p)) {
-               smp_rmb();
-               if (frozen(p))
-                       return false;
-               if (!sig_only || should_send_signal(p))
-                       set_freeze_flag(p);
-               else
-                       return false;
+       unsigned long flags;
+       spin_lock_irqsave(&freezer_lock, flags);
+       if (!freezing(p) || frozen(p)) {
+               spin_unlock_irqrestore(&freezer_lock, flags);
+               return false;
        }
  
-       if (should_send_signal(p)) {
 -      if (!(p->flags & PF_KTHREAD)) {
++      if (!(p->flags & PF_FREEZER_NOSIG)) {
                fake_signal_wake_up(p);
                /*
                 * fake_signal_wake_up() goes through p's scheduler
@@@ -124,43 -136,36 +140,47 @@@ void __thaw_task(struct task_struct *p
  {
        unsigned long flags;
  
-       if (freezing(p)) {
-               pr_debug("  clean up: %s\n", p->comm);
-               clear_freeze_flag(p);
-               spin_lock_irqsave(&p->sighand->siglock, flags);
-               recalc_sigpending_and_wake(p);
-               spin_unlock_irqrestore(&p->sighand->siglock, flags);
-       }
- }
- static int __thaw_process(struct task_struct *p)
- {
+       /*
+        * Clear freezing and kick @p if FROZEN.  Clearing is guaranteed to
+        * be visible to @p as waking up implies wmb.  Waking up inside
+        * freezer_lock also prevents wakeups from leaking outside
+        * refrigerator.
++       *
++       * If !FROZEN, @p hasn't reached refrigerator, recalc sigpending to
++       * avoid leaving dangling TIF_SIGPENDING behind.
+        */
+       spin_lock_irqsave(&freezer_lock, flags);
 -      if (frozen(p))
 +      if (frozen(p)) {
-               p->flags &= ~PF_FROZEN;
-               return 1;
+               wake_up_process(p);
++      } else {
++              spin_lock(&p->sighand->siglock);
++              recalc_sigpending_and_wake(p);
++              spin_unlock(&p->sighand->siglock);
 +      }
-       clear_freeze_flag(p);
-       return 0;
+       spin_unlock_irqrestore(&freezer_lock, flags);
  }
  
- /*
-  * Wake up a frozen process
+ /**
 - * set_freezable - make %current freezable
++ * __set_freezable - make %current freezable
++ * @with_signal: do we want %TIF_SIGPENDING for notification too?
   *
-  * task_lock() is needed to prevent the race with refrigerator() which may
-  * occur if the freezing of tasks fails.  Namely, without the lock, if the
-  * freezing of tasks failed, thaw_tasks() might have run before a task in
-  * refrigerator() could call frozen_process(), in which case the task would be
-  * frozen and no one would thaw it.
+  * Mark %current freezable and enter refrigerator if necessary.
   */
- int thaw_process(struct task_struct *p)
 -bool set_freezable(void)
++bool __set_freezable(bool with_signal)
  {
-       task_lock(p);
-       if (__thaw_process(p) == 1) {
-               task_unlock(p);
-               wake_up_process(p);
-               return 1;
-       }
-       task_unlock(p);
-       return 0;
+       might_sleep();
+       /*
+        * Modify flags while holding freezer_lock.  This ensures the
+        * freezer notices that we aren't frozen yet or the freezing
+        * condition is visible to try_to_freeze() below.
+        */
+       spin_lock_irq(&freezer_lock);
+       current->flags &= ~PF_NOFREEZE;
++      if (with_signal)
++              current->flags &= ~PF_FREEZER_NOSIG;
+       spin_unlock_irq(&freezer_lock);
+       return try_to_freeze();
  }
- EXPORT_SYMBOL(thaw_process);
 -EXPORT_SYMBOL(set_freezable);
++EXPORT_SYMBOL(__set_freezable);
Simple merge
Simple merge