Merge branch 'for-4.9' into for-4.10
authorTejun Heo <tj@kernel.org>
Wed, 19 Oct 2016 16:12:40 +0000 (12:12 -0400)
committerTejun Heo <tj@kernel.org>
Wed, 19 Oct 2016 16:12:40 +0000 (12:12 -0400)
1  2 
arch/x86/kernel/cpu/mcheck/mce.c
drivers/tty/vt/vt.c
include/linux/workqueue.h
init/main.c
kernel/workqueue.c
mm/slab.c

index a7fdf453d895bab87d785f193471269fba4fbdd0,675b7d8cde0a5251da789d8da715f44ed1bf38d4..ac27acfeaf7f27d14ba81c0766e9e0e1536909c3
@@@ -41,7 -41,6 +41,7 @@@
  #include <linux/debugfs.h>
  #include <linux/irq_work.h>
  #include <linux/export.h>
 +#include <linux/jump_label.h>
  
  #include <asm/processor.h>
  #include <asm/traps.h>
@@@ -293,13 -292,6 +293,13 @@@ static void print_mce(struct mce *m
        if (m->misc)
                pr_cont("MISC %llx ", m->misc);
  
 +      if (mce_flags.smca) {
 +              if (m->synd)
 +                      pr_cont("SYND %llx ", m->synd);
 +              if (m->ipid)
 +                      pr_cont("IPID %llx ", m->ipid);
 +      }
 +
        pr_cont("\n");
        /*
         * Note this output is parsed by external tools and old fields
@@@ -499,7 -491,7 +499,7 @@@ int mce_available(struct cpuinfo_x86 *c
  
  static void mce_schedule_work(void)
  {
-       if (!mce_gen_pool_empty() && keventd_up())
+       if (!mce_gen_pool_empty())
                schedule_work(&mce_work);
  }
  
@@@ -576,7 -568,6 +576,7 @@@ static void mce_read_aux(struct mce *m
  {
        if (m->status & MCI_STATUS_MISCV)
                m->misc = mce_rdmsrl(msr_ops.misc(i));
 +
        if (m->status & MCI_STATUS_ADDRV) {
                m->addr = mce_rdmsrl(msr_ops.addr(i));
  
                        m->addr >>= shift;
                        m->addr <<= shift;
                }
 +
 +              /*
 +               * Extract [55:<lsb>] where lsb is the least significant
 +               * *valid* bit of the address bits.
 +               */
 +              if (mce_flags.smca) {
 +                      u8 lsb = (m->addr >> 56) & 0x3f;
 +
 +                      m->addr &= GENMASK_ULL(55, lsb);
 +              }
 +      }
 +
 +      if (mce_flags.smca) {
 +              m->ipid = mce_rdmsrl(MSR_AMD64_SMCA_MCx_IPID(i));
 +
 +              if (m->status & MCI_STATUS_SYNDV)
 +                      m->synd = mce_rdmsrl(MSR_AMD64_SMCA_MCx_SYND(i));
        }
  }
  
@@@ -1659,6 -1633,17 +1659,6 @@@ static int __mcheck_cpu_apply_quirks(st
  
                if (c->x86 == 6 && c->x86_model == 45)
                        quirk_no_way_out = quirk_sandybridge_ifu;
 -              /*
 -               * MCG_CAP.MCG_SER_P is necessary but not sufficient to know
 -               * whether this processor will actually generate recoverable
 -               * machine checks. Check to see if this is an E7 model Xeon.
 -               * We can't do a model number check because E5 and E7 use the
 -               * same model number. E5 doesn't support recovery, E7 does.
 -               */
 -              if (mca_cfg.recovery || (mca_cfg.ser &&
 -                      !strncmp(c->x86_model_id,
 -                               "Intel(R) Xeon(R) CPU E7-", 24)))
 -                      set_cpu_cap(c, X86_FEATURE_MCE_RECOVERY);
        }
        if (cfg->monarch_timeout < 0)
                cfg->monarch_timeout = 0;
@@@ -2095,7 -2080,6 +2095,7 @@@ void mce_disable_bank(int bank
   * mce=bootlog Log MCEs from before booting. Disabled by default on AMD.
   * mce=nobootlog Don't log MCEs from before booting.
   * mce=bios_cmci_threshold Don't program the CMCI threshold
 + * mce=recovery force enable memcpy_mcsafe()
   */
  static int __init mcheck_enable(char *str)
  {
@@@ -2692,14 -2676,8 +2692,14 @@@ static int __init mcheck_debugfs_init(v
  static int __init mcheck_debugfs_init(void) { return -EINVAL; }
  #endif
  
 +DEFINE_STATIC_KEY_FALSE(mcsafe_key);
 +EXPORT_SYMBOL_GPL(mcsafe_key);
 +
  static int __init mcheck_late_init(void)
  {
 +      if (mca_cfg.recovery)
 +              static_branch_inc(&mcsafe_key);
 +
        mcheck_debugfs_init();
  
        /*
diff --combined drivers/tty/vt/vt.c
index 06fb39c1d6dd5e06fb7541030d881d9999813771,f76ad4c1fc4c772bc62c409d63229519b966dc07..95528461a021c79051802dfda5f9bbd2a09da721
@@@ -1312,12 -1312,12 +1312,12 @@@ static int vc_t416_color(struct vc_dat
        if (i > vc->vc_npar)
                return i;
  
 -      if (vc->vc_par[i] == 5 && i < vc->vc_npar) {
 -              /* 256 colours -- ubiquitous */
 +      if (vc->vc_par[i] == 5 && i + 1 <= vc->vc_npar) {
 +              /* 256 colours */
                i++;
                rgb_from_256(vc->vc_par[i], &c);
 -      } else if (vc->vc_par[i] == 2 && i <= vc->vc_npar + 3) {
 -              /* 24 bit -- extremely rare */
 +      } else if (vc->vc_par[i] == 2 && i + 3 <= vc->vc_npar) {
 +              /* 24 bit */
                c.r = vc->vc_par[i + 1];
                c.g = vc->vc_par[i + 2];
                c.b = vc->vc_par[i + 3];
@@@ -1415,11 -1415,6 +1415,11 @@@ static void csi_m(struct vc_data *vc
                                (vc->vc_color & 0x0f);
                        break;
                default:
 +                      if (vc->vc_par[i] >= 90 && vc->vc_par[i] <= 107) {
 +                              if (vc->vc_par[i] < 100)
 +                                      vc->vc_intensity = 2;
 +                              vc->vc_par[i] -= 60;
 +                      }
                        if (vc->vc_par[i] >= 30 && vc->vc_par[i] <= 37)
                                vc->vc_color = color_table[vc->vc_par[i] - 30]
                                        | (vc->vc_color & 0xf0);
@@@ -3187,11 -3182,11 +3187,11 @@@ static int do_bind_con_driver(const str
  
        pr_info("Console: switching ");
        if (!deflt)
 -              printk("consoles %d-%d ", first+1, last+1);
 +              printk(KERN_CONT "consoles %d-%d ", first+1, last+1);
        if (j >= 0) {
                struct vc_data *vc = vc_cons[j].d;
  
 -              printk("to %s %s %dx%d\n",
 +              printk(KERN_CONT "to %s %s %dx%d\n",
                       vc->vc_can_do_color ? "colour" : "mono",
                       desc, vc->vc_cols, vc->vc_rows);
  
                        update_screen(vc);
                }
        } else
 -              printk("to %s\n", desc);
 +              printk(KERN_CONT "to %s\n", desc);
  
        retval = 0;
  err:
@@@ -3929,10 -3924,6 +3929,6 @@@ void unblank_screen(void
   */
  static void blank_screen_t(unsigned long dummy)
  {
-       if (unlikely(!keventd_up())) {
-               mod_timer(&console_timer, jiffies + (blankinterval * HZ));
-               return;
-       }
        blank_timer_expired = 1;
        schedule_work(&console_work);
  }
index fc6e22186405873d1d2cb6c66281f8b53ed0d823,56417133c6729bd940c9190f46d79c2af5279db9..2cddd38794b2714cb1605a3a341f9cb9348dec3a
@@@ -442,7 -442,6 +442,7 @@@ extern int schedule_on_each_cpu(work_fu
  int execute_in_process_context(work_func_t fn, struct execute_work *);
  
  extern bool flush_work(struct work_struct *work);
 +extern bool cancel_work(struct work_struct *work);
  extern bool cancel_work_sync(struct work_struct *work);
  
  extern bool flush_delayed_work(struct delayed_work *dwork);
@@@ -590,14 -589,6 +590,6 @@@ static inline bool schedule_delayed_wor
        return queue_delayed_work(system_wq, dwork, delay);
  }
  
- /**
-  * keventd_up - is workqueue initialized yet?
-  */
- static inline bool keventd_up(void)
- {
-       return system_wq != NULL;
- }
  #ifndef CONFIG_SMP
  static inline long work_on_cpu(int cpu, long (*fn)(void *), void *arg)
  {
@@@ -632,4 -623,7 +624,7 @@@ int workqueue_online_cpu(unsigned int c
  int workqueue_offline_cpu(unsigned int cpu);
  #endif
  
+ int __init workqueue_init_early(void);
+ int __init workqueue_init(void);
  #endif
diff --combined init/main.c
index 2858be732f6d25dd8431cd994645c8c6af3828c2,5c4fd68a867140dee2d8fcff3ebd4a435cacbcbb..9af9274525b590f077a518b135d3d1adac9b45f3
@@@ -551,6 -551,14 +551,14 @@@ asmlinkage __visible void __init start_
                 "Interrupts were enabled *very* early, fixing it\n"))
                local_irq_disable();
        idr_init_cache();
+       /*
+        * Allow workqueue creation and work item queueing/cancelling
+        * early.  Work item execution depends on kthreads and starts after
+        * workqueue_init().
+        */
+       workqueue_init_early();
        rcu_init();
  
        /* trace_printk() and trace points may be used after this */
@@@ -789,7 -797,6 +797,7 @@@ int __init_or_module do_one_initcall(in
        }
        WARN(msgbuf[0], "initcall %pF returned with %s\n", fn, msgbuf);
  
 +      add_latent_entropy();
        return ret;
  }
  
@@@ -1006,6 -1013,8 +1014,8 @@@ static noinline void __init kernel_init
  
        smp_prepare_cpus(setup_max_cpus);
  
+       workqueue_init();
        do_pre_smp_initcalls();
        lockup_detector_init();
  
diff --combined kernel/workqueue.c
index 479d840db286efa01febf1dddf56ec0b28a29731,c56479b4884b6da321ef5cdad17ca75d8fb08229..1d9fb6543a66a26c3094f8f2d05ab4447782dadd
@@@ -290,6 -290,8 +290,8 @@@ module_param_named(disable_numa, wq_dis
  static bool wq_power_efficient = IS_ENABLED(CONFIG_WQ_POWER_EFFICIENT_DEFAULT);
  module_param_named(power_efficient, wq_power_efficient, bool, 0444);
  
+ static bool wq_online;                        /* can kworkers be created yet? */
  static bool wq_numa_enabled;          /* unbound NUMA affinity enabled */
  
  /* buf for wq_update_unbound_numa_attrs(), protected by CPU hotplug exclusion */
@@@ -2583,6 -2585,9 +2585,9 @@@ void flush_workqueue(struct workqueue_s
        };
        int next_color;
  
+       if (WARN_ON(!wq_online))
+               return;
        lock_map_acquire(&wq->lockdep_map);
        lock_map_release(&wq->lockdep_map);
  
@@@ -2843,6 -2848,9 +2848,9 @@@ bool flush_work(struct work_struct *wor
  {
        struct wq_barrier barr;
  
+       if (WARN_ON(!wq_online))
+               return false;
        lock_map_acquire(&work->lockdep_map);
        lock_map_release(&work->lockdep_map);
  
@@@ -2913,7 -2921,13 +2921,13 @@@ static bool __cancel_work_timer(struct 
        mark_work_canceling(work);
        local_irq_restore(flags);
  
-       flush_work(work);
+       /*
+        * This allows canceling during early boot.  We know that @work
+        * isn't executing.
+        */
+       if (wq_online)
+               flush_work(work);
        clear_work_data(work);
  
        /*
@@@ -2974,31 -2988,6 +2988,31 @@@ bool flush_delayed_work(struct delayed_
  }
  EXPORT_SYMBOL(flush_delayed_work);
  
 +static bool __cancel_work(struct work_struct *work, bool is_dwork)
 +{
 +      unsigned long flags;
 +      int ret;
 +
 +      do {
 +              ret = try_to_grab_pending(work, is_dwork, &flags);
 +      } while (unlikely(ret == -EAGAIN));
 +
 +      if (unlikely(ret < 0))
 +              return false;
 +
 +      set_work_pool_and_clear_pending(work, get_work_pool_id(work));
 +      local_irq_restore(flags);
 +      return ret;
 +}
 +
 +/*
 + * See cancel_delayed_work()
 + */
 +bool cancel_work(struct work_struct *work)
 +{
 +      return __cancel_work(work, false);
 +}
 +
  /**
   * cancel_delayed_work - cancel a delayed work
   * @dwork: delayed_work to cancel
   */
  bool cancel_delayed_work(struct delayed_work *dwork)
  {
 -      unsigned long flags;
 -      int ret;
 -
 -      do {
 -              ret = try_to_grab_pending(&dwork->work, true, &flags);
 -      } while (unlikely(ret == -EAGAIN));
 -
 -      if (unlikely(ret < 0))
 -              return false;
 -
 -      set_work_pool_and_clear_pending(&dwork->work,
 -                                      get_work_pool_id(&dwork->work));
 -      local_irq_restore(flags);
 -      return ret;
 +      return __cancel_work(&dwork->work, true);
  }
  EXPORT_SYMBOL(cancel_delayed_work);
  
@@@ -3364,7 -3366,7 +3378,7 @@@ static struct worker_pool *get_unbound_
                goto fail;
  
        /* create and start the initial worker */
-       if (!create_worker(pool))
+       if (wq_online && !create_worker(pool))
                goto fail;
  
        /* install */
@@@ -3429,6 -3431,7 +3443,7 @@@ static void pwq_adjust_max_active(struc
  {
        struct workqueue_struct *wq = pwq->wq;
        bool freezable = wq->flags & WQ_FREEZABLE;
+       unsigned long flags;
  
        /* for @wq->saved_max_active */
        lockdep_assert_held(&wq->mutex);
        if (!freezable && pwq->max_active == wq->saved_max_active)
                return;
  
-       spin_lock_irq(&pwq->pool->lock);
+       /* this function can be called during early boot w/ irq disabled */
+       spin_lock_irqsave(&pwq->pool->lock, flags);
  
        /*
         * During [un]freezing, the caller is responsible for ensuring that
                pwq->max_active = 0;
        }
  
-       spin_unlock_irq(&pwq->pool->lock);
+       spin_unlock_irqrestore(&pwq->pool->lock, flags);
  }
  
  /* initialize newly alloced @pwq which is associated with @wq and @pool */
@@@ -4033,6 -4037,7 +4049,7 @@@ void destroy_workqueue(struct workqueue
                for (i = 0; i < WORK_NR_COLORS; i++) {
                        if (WARN_ON(pwq->nr_in_flight[i])) {
                                mutex_unlock(&wq->mutex);
+                               show_workqueue_state();
                                return;
                        }
                }
                    WARN_ON(pwq->nr_active) ||
                    WARN_ON(!list_empty(&pwq->delayed_works))) {
                        mutex_unlock(&wq->mutex);
+                       show_workqueue_state();
                        return;
                }
        }
@@@ -4261,7 -4267,7 +4279,7 @@@ void print_worker_info(const char *log_
         * This function is called without any synchronization and @task
         * could be in any state.  Be careful with dereferences.
         */
 -      worker = probe_kthread_data(task);
 +      worker = kthread_probe_data(task);
  
        /*
         * Carefully copy the associated workqueue's workfn and name.  Keep
@@@ -5467,7 -5473,17 +5485,17 @@@ static void __init wq_numa_init(void
        wq_numa_enabled = true;
  }
  
- static int __init init_workqueues(void)
+ /**
+  * workqueue_init_early - early init for workqueue subsystem
+  *
+  * This is the first half of two-staged workqueue subsystem initialization
+  * and invoked as soon as the bare basics - memory allocation, cpumasks and
+  * idr are up.  It sets up all the data structures and system workqueues
+  * and allows early boot code to create workqueues and queue/cancel work
+  * items.  Actual work item execution starts only after kthreads can be
+  * created and scheduled right before early initcalls.
+  */
+ int __init workqueue_init_early(void)
  {
        int std_nice[NR_STD_WORKER_POOLS] = { 0, HIGHPRI_NICE_LEVEL };
        int i, cpu;
  
        pwq_cache = KMEM_CACHE(pool_workqueue, SLAB_PANIC);
  
-       wq_numa_init();
        /* initialize CPU pools */
        for_each_possible_cpu(cpu) {
                struct worker_pool *pool;
                }
        }
  
-       /* create the initial worker */
-       for_each_online_cpu(cpu) {
-               struct worker_pool *pool;
-               for_each_cpu_worker_pool(pool, cpu) {
-                       pool->flags &= ~POOL_DISASSOCIATED;
-                       BUG_ON(!create_worker(pool));
-               }
-       }
        /* create default unbound and ordered wq attrs */
        for (i = 0; i < NR_STD_WORKER_POOLS; i++) {
                struct workqueue_attrs *attrs;
               !system_power_efficient_wq ||
               !system_freezable_power_efficient_wq);
  
+       return 0;
+ }
+ /**
+  * workqueue_init - bring workqueue subsystem fully online
+  *
+  * This is the latter half of two-staged workqueue subsystem initialization
+  * and invoked as soon as kthreads can be created and scheduled.
+  * Workqueues have been created and work items queued on them, but there
+  * are no kworkers executing the work items yet.  Populate the worker pools
+  * with the initial workers and enable future kworker creations.
+  */
+ int __init workqueue_init(void)
+ {
+       struct workqueue_struct *wq;
+       struct worker_pool *pool;
+       int cpu, bkt;
+       /*
+        * It'd be simpler to initialize NUMA in workqueue_init_early() but
+        * CPU to node mapping may not be available that early on some
+        * archs such as power and arm64.  As per-cpu pools created
+        * previously could be missing node hint and unbound pools NUMA
+        * affinity, fix them up.
+        */
+       wq_numa_init();
+       mutex_lock(&wq_pool_mutex);
+       for_each_possible_cpu(cpu) {
+               for_each_cpu_worker_pool(pool, cpu) {
+                       pool->node = cpu_to_node(cpu);
+               }
+       }
+       list_for_each_entry(wq, &workqueues, list)
+               wq_update_unbound_numa(wq, smp_processor_id(), true);
+       mutex_unlock(&wq_pool_mutex);
+       /* create the initial workers */
+       for_each_online_cpu(cpu) {
+               for_each_cpu_worker_pool(pool, cpu) {
+                       pool->flags &= ~POOL_DISASSOCIATED;
+                       BUG_ON(!create_worker(pool));
+               }
+       }
+       hash_for_each(unbound_pool_hash, bkt, pool, hash_node)
+               BUG_ON(!create_worker(pool));
+       wq_online = true;
        wq_watchdog_init();
  
        return 0;
  }
- early_initcall(init_workqueues);
diff --combined mm/slab.c
index 090fb26b3a39b4feba105650f2a663f5c9972064,dc69b6b625b10643ac6e77431a2bf1c167daef2a..6508b4dab99d24c2fe3f7e41c9eb18a2b549277f
+++ b/mm/slab.c
@@@ -550,12 -550,7 +550,7 @@@ static void start_cpu_timer(int cpu
  {
        struct delayed_work *reap_work = &per_cpu(slab_reap_work, cpu);
  
-       /*
-        * When this gets called from do_initcalls via cpucache_init(),
-        * init_workqueues() has already run, so keventd will be setup
-        * at that time.
-        */
-       if (keventd_up() && reap_work->work.func == NULL) {
+       if (reap_work->work.func == NULL) {
                init_reap_node(cpu);
                INIT_DEFERRABLE_WORK(reap_work, cache_reap);
                schedule_delayed_work_on(cpu, reap_work,
@@@ -886,7 -881,6 +881,7 @@@ static int init_cache_node(struct kmem_
        return 0;
  }
  
 +#if (defined(CONFIG_NUMA) && defined(CONFIG_MEMORY_HOTPLUG)) || defined(CONFIG_SMP)
  /*
   * Allocates and initializes node for a node on each slab cache, used for
   * either memory or cpu hotplug.  If memory is being hot-added, the kmem_cache_node
@@@ -909,7 -903,6 +904,7 @@@ static int init_cache_node_node(int nod
  
        return 0;
  }
 +#endif
  
  static int setup_kmem_cache_node(struct kmem_cache *cachep,
                                int node, gfp_t gfp, bool force_change)
@@@ -977,8 -970,6 +972,8 @@@ fail
        return ret;
  }
  
 +#ifdef CONFIG_SMP
 +
  static void cpuup_canceled(long cpu)
  {
        struct kmem_cache *cachep;
        return -ENOMEM;
  }
  
 -static int cpuup_callback(struct notifier_block *nfb,
 -                                  unsigned long action, void *hcpu)
 +int slab_prepare_cpu(unsigned int cpu)
  {
 -      long cpu = (long)hcpu;
 -      int err = 0;
 +      int err;
  
 -      switch (action) {
 -      case CPU_UP_PREPARE:
 -      case CPU_UP_PREPARE_FROZEN:
 -              mutex_lock(&slab_mutex);
 -              err = cpuup_prepare(cpu);
 -              mutex_unlock(&slab_mutex);
 -              break;
 -      case CPU_ONLINE:
 -      case CPU_ONLINE_FROZEN:
 -              start_cpu_timer(cpu);
 -              break;
 -#ifdef CONFIG_HOTPLUG_CPU
 -      case CPU_DOWN_PREPARE:
 -      case CPU_DOWN_PREPARE_FROZEN:
 -              /*
 -               * Shutdown cache reaper. Note that the slab_mutex is
 -               * held so that if cache_reap() is invoked it cannot do
 -               * anything expensive but will only modify reap_work
 -               * and reschedule the timer.
 -              */
 -              cancel_delayed_work_sync(&per_cpu(slab_reap_work, cpu));
 -              /* Now the cache_reaper is guaranteed to be not running. */
 -              per_cpu(slab_reap_work, cpu).work.func = NULL;
 -              break;
 -      case CPU_DOWN_FAILED:
 -      case CPU_DOWN_FAILED_FROZEN:
 -              start_cpu_timer(cpu);
 -              break;
 -      case CPU_DEAD:
 -      case CPU_DEAD_FROZEN:
 -              /*
 -               * Even if all the cpus of a node are down, we don't free the
 -               * kmem_cache_node of any cache. This to avoid a race between
 -               * cpu_down, and a kmalloc allocation from another cpu for
 -               * memory from the node of the cpu going down.  The node
 -               * structure is usually allocated from kmem_cache_create() and
 -               * gets destroyed at kmem_cache_destroy().
 -               */
 -              /* fall through */
 +      mutex_lock(&slab_mutex);
 +      err = cpuup_prepare(cpu);
 +      mutex_unlock(&slab_mutex);
 +      return err;
 +}
 +
 +/*
 + * This is called for a failed online attempt and for a successful
 + * offline.
 + *
 + * Even if all the cpus of a node are down, we don't free the
 + * kmem_list3 of any cache. This to avoid a race between cpu_down, and
 + * a kmalloc allocation from another cpu for memory from the node of
 + * the cpu going down.  The list3 structure is usually allocated from
 + * kmem_cache_create() and gets destroyed at kmem_cache_destroy().
 + */
 +int slab_dead_cpu(unsigned int cpu)
 +{
 +      mutex_lock(&slab_mutex);
 +      cpuup_canceled(cpu);
 +      mutex_unlock(&slab_mutex);
 +      return 0;
 +}
  #endif
 -      case CPU_UP_CANCELED:
 -      case CPU_UP_CANCELED_FROZEN:
 -              mutex_lock(&slab_mutex);
 -              cpuup_canceled(cpu);
 -              mutex_unlock(&slab_mutex);
 -              break;
 -      }
 -      return notifier_from_errno(err);
 +
 +static int slab_online_cpu(unsigned int cpu)
 +{
 +      start_cpu_timer(cpu);
 +      return 0;
  }
  
 -static struct notifier_block cpucache_notifier = {
 -      &cpuup_callback, NULL, 0
 -};
 +static int slab_offline_cpu(unsigned int cpu)
 +{
 +      /*
 +       * Shutdown cache reaper. Note that the slab_mutex is held so
 +       * that if cache_reap() is invoked it cannot do anything
 +       * expensive but will only modify reap_work and reschedule the
 +       * timer.
 +       */
 +      cancel_delayed_work_sync(&per_cpu(slab_reap_work, cpu));
 +      /* Now the cache_reaper is guaranteed to be not running. */
 +      per_cpu(slab_reap_work, cpu).work.func = NULL;
 +      return 0;
 +}
  
  #if defined(CONFIG_NUMA) && defined(CONFIG_MEMORY_HOTPLUG)
  /*
@@@ -1329,6 -1331,12 +1324,6 @@@ void __init kmem_cache_init_late(void
        /* Done! */
        slab_state = FULL;
  
 -      /*
 -       * Register a cpu startup notifier callback that initializes
 -       * cpu_cache_get for all new cpus
 -       */
 -      register_cpu_notifier(&cpucache_notifier);
 -
  #ifdef CONFIG_NUMA
        /*
         * Register a memory hotplug callback that initializes and frees
  
  static int __init cpucache_init(void)
  {
 -      int cpu;
 +      int ret;
  
        /*
         * Register the timers that return unneeded pages to the page allocator
         */
 -      for_each_online_cpu(cpu)
 -              start_cpu_timer(cpu);
 +      ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "SLAB online",
 +                              slab_online_cpu, slab_offline_cpu);
 +      WARN_ON(ret < 0);
  
        /* Done! */
        slab_state = FULL;