Merge tag 'sched-core-2021-02-17' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 21 Feb 2021 20:35:04 +0000 (12:35 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 21 Feb 2021 20:35:04 +0000 (12:35 -0800)
Pull scheduler updates from Ingo Molnar:
 "Core scheduler updates:

   - Add CONFIG_PREEMPT_DYNAMIC: this in its current form adds the
     preempt=none/voluntary/full boot options (default: full), to allow
     distros to build a PREEMPT kernel but fall back to close to
     PREEMPT_VOLUNTARY (or PREEMPT_NONE) runtime scheduling behavior via
     a boot time selection.

     There's also the /debug/sched_debug switch to do this runtime.

     This feature is implemented via runtime patching (a new variant of
     static calls).

     The scope of the runtime patching can be best reviewed by looking
     at the sched_dynamic_update() function in kernel/sched/core.c.

     ( Note that the dynamic none/voluntary mode isn't 100% identical,
       for example preempt-RCU is available in all cases, plus the
       preempt count is maintained in all models, which has runtime
       overhead even with the code patching. )

     The PREEMPT_VOLUNTARY/PREEMPT_NONE models, used by the vast
     majority of distributions, are supposed to be unaffected.

   - Fix ignored rescheduling after rcu_eqs_enter(). This is a bug that
     was found via rcutorture triggering a hang. The bug is that
     rcu_idle_enter() may wake up a NOCB kthread, but this happens after
     the last generic need_resched() check. Some cpuidle drivers fix it
     by chance but many others don't.

     In true 2020 fashion the original bug fix has grown into a 5-patch
     scheduler/RCU fix series plus another 16 RCU patches to address the
     underlying issue of missed preemption events. These are the initial
     fixes that should fix current incarnations of the bug.

   - Clean up rbtree usage in the scheduler, by providing & using the
     following consistent set of rbtree APIs:

       partial-order; less() based:
         - rb_add(): add a new entry to the rbtree
         - rb_add_cached(): like rb_add(), but for a rb_root_cached

       total-order; cmp() based:
         - rb_find(): find an entry in an rbtree
         - rb_find_add(): find an entry, and add if not found

         - rb_find_first(): find the first (leftmost) matching entry
         - rb_next_match(): continue from rb_find_first()
         - rb_for_each(): iterate a sub-tree using the previous two

   - Improve the SMP/NUMA load-balancer: scan for an idle sibling in a
     single pass. This is a 4-commit series where each commit improves
     one aspect of the idle sibling scan logic.

   - Improve the cpufreq cooling driver by getting the effective CPU
     utilization metrics from the scheduler

   - Improve the fair scheduler's active load-balancing logic by
     reducing the number of active LB attempts & lengthen the
     load-balancing interval. This improves stress-ng mmapfork
     performance.

   - Fix CFS's estimated utilization (util_est) calculation bug that can
     result in too high utilization values

  Misc updates & fixes:

   - Fix the HRTICK reprogramming & optimization feature

   - Fix SCHED_SOFTIRQ raising race & warning in the CPU offlining code

   - Reduce dl_add_task_root_domain() overhead

   - Fix uprobes refcount bug

   - Process pending softirqs in flush_smp_call_function_from_idle()

   - Clean up task priority related defines, remove *USER_*PRIO and
     USER_PRIO()

   - Simplify the sched_init_numa() deduplication sort

   - Documentation updates

   - Fix EAS bug in update_misfit_status(), which degraded the quality
     of energy-balancing

   - Smaller cleanups"

* tag 'sched-core-2021-02-17' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (51 commits)
  sched,x86: Allow !PREEMPT_DYNAMIC
  entry/kvm: Explicitly flush pending rcuog wakeup before last rescheduling point
  entry: Explicitly flush pending rcuog wakeup before last rescheduling point
  rcu/nocb: Trigger self-IPI on late deferred wake up before user resume
  rcu/nocb: Perform deferred wake up before last idle's need_resched() check
  rcu: Pull deferred rcuog wake up to rcu_eqs_enter() callers
  sched/features: Distinguish between NORMAL and DEADLINE hrtick
  sched/features: Fix hrtick reprogramming
  sched/deadline: Reduce rq lock contention in dl_add_task_root_domain()
  uprobes: (Re)add missing get_uprobe() in __find_uprobe()
  smp: Process pending softirqs in flush_smp_call_function_from_idle()
  sched: Harden PREEMPT_DYNAMIC
  static_call: Allow module use without exposing static_call_key
  sched: Add /debug/sched_preempt
  preempt/dynamic: Support dynamic preempt with preempt= boot option
  preempt/dynamic: Provide irqentry_exit_cond_resched() static call
  preempt/dynamic: Provide preempt_schedule[_notrace]() static calls
  preempt/dynamic: Provide cond_resched() and might_resched() static calls
  preempt: Introduce CONFIG_PREEMPT_DYNAMIC
  static_call: Provide DEFINE_STATIC_CALL_RET0()
  ...

13 files changed:
1  2 
Documentation/admin-guide/kernel-parameters.txt
arch/Kconfig
arch/powerpc/platforms/cell/spufs/sched.c
arch/x86/Kconfig
include/asm-generic/vmlinux.lds.h
include/linux/rcupdate.h
init/Kconfig
kernel/events/core.c
kernel/locking/rtmutex.c
kernel/rcu/tree.c
kernel/rcu/tree.h
kernel/rcu/tree_plugin.h
kernel/sched/core.c

diff --cc arch/Kconfig
Simple merge
Simple merge
Simple merge
@@@ -112,12 -110,10 +112,14 @@@ static inline void rcu_user_exit(void) 
  
  #ifdef CONFIG_RCU_NOCB_CPU
  void rcu_init_nohz(void);
 +int rcu_nocb_cpu_offload(int cpu);
 +int rcu_nocb_cpu_deoffload(int cpu);
+ void rcu_nocb_flush_deferred_wakeup(void);
  #else /* #ifdef CONFIG_RCU_NOCB_CPU */
  static inline void rcu_init_nohz(void) { }
 +static inline int rcu_nocb_cpu_offload(int cpu) { return -EINVAL; }
 +static inline int rcu_nocb_cpu_deoffload(int cpu) { return 0; }
+ static inline void rcu_nocb_flush_deferred_wakeup(void) { }
  #endif /* #else #ifdef CONFIG_RCU_NOCB_CPU */
  
  /**
diff --cc init/Kconfig
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -2280,201 -2186,19 +2285,208 @@@ static void do_nocb_deferred_wakeup_tim
   * This means we do an inexact common-case check.  Note that if
   * we miss, ->nocb_timer will eventually clean things up.
   */
- static void do_nocb_deferred_wakeup(struct rcu_data *rdp)
+ static bool do_nocb_deferred_wakeup(struct rcu_data *rdp)
  {
        if (rcu_nocb_need_deferred_wakeup(rdp))
-               do_nocb_deferred_wakeup_common(rdp);
+               return do_nocb_deferred_wakeup_common(rdp);
+       return false;
+ }
+ void rcu_nocb_flush_deferred_wakeup(void)
+ {
+       do_nocb_deferred_wakeup(this_cpu_ptr(&rcu_data));
  }
+ EXPORT_SYMBOL_GPL(rcu_nocb_flush_deferred_wakeup);
  
 +static int rdp_offload_toggle(struct rcu_data *rdp,
 +                             bool offload, unsigned long flags)
 +      __releases(rdp->nocb_lock)
 +{
 +      struct rcu_segcblist *cblist = &rdp->cblist;
 +      struct rcu_data *rdp_gp = rdp->nocb_gp_rdp;
 +      bool wake_gp = false;
 +
 +      rcu_segcblist_offload(cblist, offload);
 +
 +      if (rdp->nocb_cb_sleep)
 +              rdp->nocb_cb_sleep = false;
 +      rcu_nocb_unlock_irqrestore(rdp, flags);
 +
 +      /*
 +       * Ignore former value of nocb_cb_sleep and force wake up as it could
 +       * have been spuriously set to false already.
 +       */
 +      swake_up_one(&rdp->nocb_cb_wq);
 +
 +      raw_spin_lock_irqsave(&rdp_gp->nocb_gp_lock, flags);
 +      if (rdp_gp->nocb_gp_sleep) {
 +              rdp_gp->nocb_gp_sleep = false;
 +              wake_gp = true;
 +      }
 +      raw_spin_unlock_irqrestore(&rdp_gp->nocb_gp_lock, flags);
 +
 +      if (wake_gp)
 +              wake_up_process(rdp_gp->nocb_gp_kthread);
 +
 +      return 0;
 +}
 +
 +static int __rcu_nocb_rdp_deoffload(struct rcu_data *rdp)
 +{
 +      struct rcu_segcblist *cblist = &rdp->cblist;
 +      unsigned long flags;
 +      int ret;
 +
 +      pr_info("De-offloading %d\n", rdp->cpu);
 +
 +      rcu_nocb_lock_irqsave(rdp, flags);
 +      /*
 +       * If there are still pending work offloaded, the offline
 +       * CPU won't help much handling them.
 +       */
 +      if (cpu_is_offline(rdp->cpu) && !rcu_segcblist_empty(&rdp->cblist)) {
 +              rcu_nocb_unlock_irqrestore(rdp, flags);
 +              return -EBUSY;
 +      }
 +
 +      ret = rdp_offload_toggle(rdp, false, flags);
 +      swait_event_exclusive(rdp->nocb_state_wq,
 +                            !rcu_segcblist_test_flags(cblist, SEGCBLIST_KTHREAD_CB |
 +                                                      SEGCBLIST_KTHREAD_GP));
 +      rcu_nocb_lock_irqsave(rdp, flags);
 +      /* Make sure nocb timer won't stay around */
 +      WRITE_ONCE(rdp->nocb_defer_wakeup, RCU_NOCB_WAKE_OFF);
 +      rcu_nocb_unlock_irqrestore(rdp, flags);
 +      del_timer_sync(&rdp->nocb_timer);
 +
 +      /*
 +       * Flush bypass. While IRQs are disabled and once we set
 +       * SEGCBLIST_SOFTIRQ_ONLY, no callback is supposed to be
 +       * enqueued on bypass.
 +       */
 +      rcu_nocb_lock_irqsave(rdp, flags);
 +      rcu_nocb_flush_bypass(rdp, NULL, jiffies);
 +      rcu_segcblist_set_flags(cblist, SEGCBLIST_SOFTIRQ_ONLY);
 +      /*
 +       * With SEGCBLIST_SOFTIRQ_ONLY, we can't use
 +       * rcu_nocb_unlock_irqrestore() anymore. Theoretically we
 +       * could set SEGCBLIST_SOFTIRQ_ONLY with cb unlocked and IRQs
 +       * disabled now, but let's be paranoid.
 +       */
 +      raw_spin_unlock_irqrestore(&rdp->nocb_lock, flags);
 +
 +      return ret;
 +}
 +
 +static long rcu_nocb_rdp_deoffload(void *arg)
 +{
 +      struct rcu_data *rdp = arg;
 +
 +      WARN_ON_ONCE(rdp->cpu != raw_smp_processor_id());
 +      return __rcu_nocb_rdp_deoffload(rdp);
 +}
 +
 +int rcu_nocb_cpu_deoffload(int cpu)
 +{
 +      struct rcu_data *rdp = per_cpu_ptr(&rcu_data, cpu);
 +      int ret = 0;
 +
 +      if (rdp == rdp->nocb_gp_rdp) {
 +              pr_info("Can't deoffload an rdp GP leader (yet)\n");
 +              return -EINVAL;
 +      }
 +      mutex_lock(&rcu_state.barrier_mutex);
 +      cpus_read_lock();
 +      if (rcu_segcblist_is_offloaded(&rdp->cblist)) {
 +              if (cpu_online(cpu))
 +                      ret = work_on_cpu(cpu, rcu_nocb_rdp_deoffload, rdp);
 +              else
 +                      ret = __rcu_nocb_rdp_deoffload(rdp);
 +              if (!ret)
 +                      cpumask_clear_cpu(cpu, rcu_nocb_mask);
 +      }
 +      cpus_read_unlock();
 +      mutex_unlock(&rcu_state.barrier_mutex);
 +
 +      return ret;
 +}
 +EXPORT_SYMBOL_GPL(rcu_nocb_cpu_deoffload);
 +
 +static int __rcu_nocb_rdp_offload(struct rcu_data *rdp)
 +{
 +      struct rcu_segcblist *cblist = &rdp->cblist;
 +      unsigned long flags;
 +      int ret;
 +
 +      /*
 +       * For now we only support re-offload, ie: the rdp must have been
 +       * offloaded on boot first.
 +       */
 +      if (!rdp->nocb_gp_rdp)
 +              return -EINVAL;
 +
 +      pr_info("Offloading %d\n", rdp->cpu);
 +      /*
 +       * Can't use rcu_nocb_lock_irqsave() while we are in
 +       * SEGCBLIST_SOFTIRQ_ONLY mode.
 +       */
 +      raw_spin_lock_irqsave(&rdp->nocb_lock, flags);
 +      /* Re-enable nocb timer */
 +      WRITE_ONCE(rdp->nocb_defer_wakeup, RCU_NOCB_WAKE_NOT);
 +      /*
 +       * We didn't take the nocb lock while working on the
 +       * rdp->cblist in SEGCBLIST_SOFTIRQ_ONLY mode.
 +       * Every modifications that have been done previously on
 +       * rdp->cblist must be visible remotely by the nocb kthreads
 +       * upon wake up after reading the cblist flags.
 +       *
 +       * The layout against nocb_lock enforces that ordering:
 +       *
 +       *  __rcu_nocb_rdp_offload()   nocb_cb_wait()/nocb_gp_wait()
 +       * -------------------------   ----------------------------
 +       *      WRITE callbacks           rcu_nocb_lock()
 +       *      rcu_nocb_lock()           READ flags
 +       *      WRITE flags               READ callbacks
 +       *      rcu_nocb_unlock()         rcu_nocb_unlock()
 +       */
 +      ret = rdp_offload_toggle(rdp, true, flags);
 +      swait_event_exclusive(rdp->nocb_state_wq,
 +                            rcu_segcblist_test_flags(cblist, SEGCBLIST_KTHREAD_CB) &&
 +                            rcu_segcblist_test_flags(cblist, SEGCBLIST_KTHREAD_GP));
 +
 +      return ret;
 +}
 +
 +static long rcu_nocb_rdp_offload(void *arg)
 +{
 +      struct rcu_data *rdp = arg;
 +
 +      WARN_ON_ONCE(rdp->cpu != raw_smp_processor_id());
 +      return __rcu_nocb_rdp_offload(rdp);
 +}
 +
 +int rcu_nocb_cpu_offload(int cpu)
 +{
 +      struct rcu_data *rdp = per_cpu_ptr(&rcu_data, cpu);
 +      int ret = 0;
 +
 +      mutex_lock(&rcu_state.barrier_mutex);
 +      cpus_read_lock();
 +      if (!rcu_segcblist_is_offloaded(&rdp->cblist)) {
 +              if (cpu_online(cpu))
 +                      ret = work_on_cpu(cpu, rcu_nocb_rdp_offload, rdp);
 +              else
 +                      ret = __rcu_nocb_rdp_offload(rdp);
 +              if (!ret)
 +                      cpumask_set_cpu(cpu, rcu_nocb_mask);
 +      }
 +      cpus_read_unlock();
 +      mutex_unlock(&rcu_state.barrier_mutex);
 +
 +      return ret;
 +}
 +EXPORT_SYMBOL_GPL(rcu_nocb_cpu_offload);
 +
  void __init rcu_init_nohz(void)
  {
        int cpu;
Simple merge