]> Git Repo - linux.git/commitdiff
Merge branch 'for-4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq
authorLinus Torvalds <[email protected]>
Tue, 13 Dec 2016 20:59:57 +0000 (12:59 -0800)
committerLinus Torvalds <[email protected]>
Tue, 13 Dec 2016 20:59:57 +0000 (12:59 -0800)
Pull workqueue updates from Tejun Heo:
 "Mostly patches to initialize workqueue subsystem earlier and get rid
  of keventd_up().

  The patches were headed for the last merge cycle but got delayed due
  to a bug found late minute, which is fixed now.

  Also, to help debugging, destroy_workqueue() is more chatty now on a
  sanity check failure."

* 'for-4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq:
  workqueue: move wq_numa_init() to workqueue_init()
  workqueue: remove keventd_up()
  debugobj, workqueue: remove keventd_up() usage
  slab, workqueue: remove keventd_up() usage
  power, workqueue: remove keventd_up() usage
  tty, workqueue: remove keventd_up() usage
  mce, workqueue: remove keventd_up() usage
  workqueue: make workqueue available early during boot
  workqueue: dump workqueue state on sanity check failures in destroy_workqueue()

1  2 
arch/x86/kernel/cpu/mcheck/mce.c
drivers/tty/vt/vt.c
include/linux/workqueue.h
init/main.c
lib/debugobjects.c
mm/slab.c

index 132e1ec67da0021c3457b5d0c7aa072e83d3d1c2,ac27acfeaf7f27d14ba81c0766e9e0e1536909c3..00ef43233e034b0cde9b2adc88b8003ddc42d00b
@@@ -43,7 -43,6 +43,7 @@@
  #include <linux/export.h>
  #include <linux/jump_label.h>
  
 +#include <asm/intel-family.h>
  #include <asm/processor.h>
  #include <asm/traps.h>
  #include <asm/tlbflush.h>
@@@ -136,9 -135,6 +136,9 @@@ void mce_setup(struct mce *m
        m->socketid = cpu_data(m->extcpu).phys_proc_id;
        m->apicid = cpu_data(m->extcpu).initial_apicid;
        rdmsrl(MSR_IA32_MCG_CAP, m->mcgcap);
 +
 +      if (this_cpu_has(X86_FEATURE_INTEL_PPIN))
 +              rdmsrl(MSR_PPIN, m->ppin);
  }
  
  DEFINE_PER_CPU(struct mce, injectm);
@@@ -211,12 -207,8 +211,12 @@@ EXPORT_SYMBOL_GPL(mce_inject_log)
  
  static struct notifier_block mce_srao_nb;
  
 +static atomic_t num_notifiers;
 +
  void mce_register_decode_chain(struct notifier_block *nb)
  {
 +      atomic_inc(&num_notifiers);
 +
        /* Ensure SRAO notifier has the highest priority in the decode chain. */
        if (nb != &mce_srao_nb && nb->priority == INT_MAX)
                nb->priority -= 1;
@@@ -227,8 -219,6 +227,8 @@@ EXPORT_SYMBOL_GPL(mce_register_decode_c
  
  void mce_unregister_decode_chain(struct notifier_block *nb)
  {
 +      atomic_dec(&num_notifiers);
 +
        atomic_notifier_chain_unregister(&x86_mce_decoder_chain, nb);
  }
  EXPORT_SYMBOL_GPL(mce_unregister_decode_chain);
@@@ -280,17 -270,17 +280,17 @@@ struct mca_msr_regs msr_ops = 
        .misc   = misc_reg
  };
  
 -static void print_mce(struct mce *m)
 +static void __print_mce(struct mce *m)
  {
 -      int ret = 0;
 -
 -      pr_emerg(HW_ERR "CPU %d: Machine Check Exception: %Lx Bank %d: %016Lx\n",
 -             m->extcpu, m->mcgstatus, m->bank, m->status);
 +      pr_emerg(HW_ERR "CPU %d: Machine Check%s: %Lx Bank %d: %016Lx\n",
 +               m->extcpu,
 +               (m->mcgstatus & MCG_STATUS_MCIP ? " Exception" : ""),
 +               m->mcgstatus, m->bank, m->status);
  
        if (m->ip) {
                pr_emerg(HW_ERR "RIP%s %02x:<%016Lx> ",
                        !(m->mcgstatus & MCG_STATUS_EIPV) ? " !INEXACT!" : "",
 -                              m->cs, m->ip);
 +                      m->cs, m->ip);
  
                if (m->cs == __KERNEL_CS)
                        print_symbol("{%s}", m->ip);
        pr_emerg(HW_ERR "PROCESSOR %u:%x TIME %llu SOCKET %u APIC %x microcode %x\n",
                m->cpuvendor, m->cpuid, m->time, m->socketid, m->apicid,
                cpu_data(m->extcpu).microcode);
 +}
 +
 +static void print_mce(struct mce *m)
 +{
 +      int ret = 0;
 +
 +      __print_mce(m);
  
        /*
         * Print out human-readable details about the MCE error,
@@@ -516,7 -499,7 +516,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);
  }
  
@@@ -586,32 -569,6 +586,32 @@@ static struct notifier_block mce_srao_n
        .priority = INT_MAX,
  };
  
 +static int mce_default_notifier(struct notifier_block *nb, unsigned long val,
 +                              void *data)
 +{
 +      struct mce *m = (struct mce *)data;
 +
 +      if (!m)
 +              return NOTIFY_DONE;
 +
 +      /*
 +       * Run the default notifier if we have only the SRAO
 +       * notifier and us registered.
 +       */
 +      if (atomic_read(&num_notifiers) > 2)
 +              return NOTIFY_DONE;
 +
 +      __print_mce(m);
 +
 +      return NOTIFY_DONE;
 +}
 +
 +static struct notifier_block mce_default_nb = {
 +      .notifier_call  = mce_default_notifier,
 +      /* lowest prio, we want it to run last. */
 +      .priority       = 0,
 +};
 +
  /*
   * Read ADDR and MISC registers.
   */
@@@ -710,15 -667,6 +710,15 @@@ bool machine_check_poll(enum mcp_flags 
  
        mce_gather_info(&m, NULL);
  
 +      /*
 +       * m.tsc was set in mce_setup(). Clear it if not requested.
 +       *
 +       * FIXME: Propagate @flags to mce_gather_info/mce_setup() to avoid
 +       *        that dance.
 +       */
 +      if (!(flags & MCP_TIMESTAMP))
 +              m.tsc = 0;
 +
        for (i = 0; i < mca_cfg.banks; i++) {
                if (!mce_banks[i].ctl || !test_bit(i, *b))
                        continue;
                m.misc = 0;
                m.addr = 0;
                m.bank = i;
 -              m.tsc = 0;
  
                barrier();
                m.status = mce_rdmsrl(msr_ops.status(i));
                if (!(m.status & MCI_STATUS_VAL))
                        continue;
  
 -
                /*
                 * Uncorrected or signalled events are handled by the exception
                 * handler when it is enabled, so don't process those here.
  
                mce_read_aux(&m, i);
  
 -              if (!(flags & MCP_TIMESTAMP))
 -                      m.tsc = 0;
 -
                severity = mce_severity(&m, mca_cfg.tolerant, NULL, false);
  
                if (severity == MCE_DEFERRED_SEVERITY && memory_error(&m))
@@@ -1402,7 -1355,7 +1402,7 @@@ static void mce_timer_fn(unsigned long 
        iv = __this_cpu_read(mce_next_interval);
  
        if (mce_available(this_cpu_ptr(&cpu_info))) {
 -              machine_check_poll(MCP_TIMESTAMP, this_cpu_ptr(&mce_poll_banks));
 +              machine_check_poll(0, this_cpu_ptr(&mce_poll_banks));
  
                if (mce_intel_cmci_poll()) {
                        iv = mce_adjust_timer(iv);
@@@ -1792,14 -1745,6 +1792,14 @@@ static void mce_start_timer(unsigned in
        add_timer_on(t, cpu);
  }
  
 +static void __mcheck_cpu_setup_timer(void)
 +{
 +      struct timer_list *t = this_cpu_ptr(&mce_timer);
 +      unsigned int cpu = smp_processor_id();
 +
 +      setup_pinned_timer(t, mce_timer_fn, cpu);
 +}
 +
  static void __mcheck_cpu_init_timer(void)
  {
        struct timer_list *t = this_cpu_ptr(&mce_timer);
@@@ -1851,7 -1796,7 +1851,7 @@@ void mcheck_cpu_init(struct cpuinfo_x8
        __mcheck_cpu_init_generic();
        __mcheck_cpu_init_vendor(c);
        __mcheck_cpu_init_clear_banks();
 -      __mcheck_cpu_init_timer();
 +      __mcheck_cpu_setup_timer();
  }
  
  /*
@@@ -2193,7 -2138,6 +2193,7 @@@ int __init mcheck_init(void
  {
        mcheck_intel_therm_init();
        mce_register_decode_chain(&mce_srao_nb);
 +      mce_register_decode_chain(&mce_default_nb);
        mcheck_vendor_init_severity();
  
        INIT_WORK(&mce_work, mce_process_work);
@@@ -2311,6 -2255,8 +2311,6 @@@ static struct bus_type mce_subsys = 
  
  DEFINE_PER_CPU(struct device *, mce_device);
  
 -void (*threshold_cpu_callback)(unsigned long action, unsigned int cpu);
 -
  static inline struct mce_bank *attr_to_bank(struct device_attribute *attr)
  {
        return container_of(attr, struct mce_bank, attr);
@@@ -2463,10 -2409,6 +2463,10 @@@ static int mce_device_create(unsigned i
        if (!mce_available(&boot_cpu_data))
                return -EIO;
  
 +      dev = per_cpu(mce_device, cpu);
 +      if (dev)
 +              return 0;
 +
        dev = kzalloc(sizeof *dev, GFP_KERNEL);
        if (!dev)
                return -ENOMEM;
@@@ -2526,25 -2468,28 +2526,25 @@@ static void mce_device_remove(unsigned 
  }
  
  /* Make sure there are no machine checks on offlined CPUs. */
 -static void mce_disable_cpu(void *h)
 +static void mce_disable_cpu(void)
  {
 -      unsigned long action = *(unsigned long *)h;
 -
        if (!mce_available(raw_cpu_ptr(&cpu_info)))
                return;
  
 -      if (!(action & CPU_TASKS_FROZEN))
 +      if (!cpuhp_tasks_frozen)
                cmci_clear();
  
        vendor_disable_error_reporting();
  }
  
 -static void mce_reenable_cpu(void *h)
 +static void mce_reenable_cpu(void)
  {
 -      unsigned long action = *(unsigned long *)h;
        int i;
  
        if (!mce_available(raw_cpu_ptr(&cpu_info)))
                return;
  
 -      if (!(action & CPU_TASKS_FROZEN))
 +      if (!cpuhp_tasks_frozen)
                cmci_reenable();
        for (i = 0; i < mca_cfg.banks; i++) {
                struct mce_bank *b = &mce_banks[i];
        }
  }
  
 -/* Get notified when a cpu comes on/off. Be hotplug friendly. */
 -static int
 -mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
 +static int mce_cpu_dead(unsigned int cpu)
 +{
 +      mce_intel_hcpu_update(cpu);
 +
 +      /* intentionally ignoring frozen here */
 +      if (!cpuhp_tasks_frozen)
 +              cmci_rediscover();
 +      return 0;
 +}
 +
 +static int mce_cpu_online(unsigned int cpu)
  {
 -      unsigned int cpu = (unsigned long)hcpu;
        struct timer_list *t = &per_cpu(mce_timer, cpu);
 +      int ret;
  
 -      switch (action & ~CPU_TASKS_FROZEN) {
 -      case CPU_ONLINE:
 -              mce_device_create(cpu);
 -              if (threshold_cpu_callback)
 -                      threshold_cpu_callback(action, cpu);
 -              break;
 -      case CPU_DEAD:
 -              if (threshold_cpu_callback)
 -                      threshold_cpu_callback(action, cpu);
 -              mce_device_remove(cpu);
 -              mce_intel_hcpu_update(cpu);
 +      mce_device_create(cpu);
  
 -              /* intentionally ignoring frozen here */
 -              if (!(action & CPU_TASKS_FROZEN))
 -                      cmci_rediscover();
 -              break;
 -      case CPU_DOWN_PREPARE:
 -              smp_call_function_single(cpu, mce_disable_cpu, &action, 1);
 -              del_timer_sync(t);
 -              break;
 -      case CPU_DOWN_FAILED:
 -              smp_call_function_single(cpu, mce_reenable_cpu, &action, 1);
 -              mce_start_timer(cpu, t);
 -              break;
 +      ret = mce_threshold_create_device(cpu);
 +      if (ret) {
 +              mce_device_remove(cpu);
 +              return ret;
        }
 -
 -      return NOTIFY_OK;
 +      mce_reenable_cpu();
 +      mce_start_timer(cpu, t);
 +      return 0;
  }
  
 -static struct notifier_block mce_cpu_notifier = {
 -      .notifier_call = mce_cpu_callback,
 -};
 +static int mce_cpu_pre_down(unsigned int cpu)
 +{
 +      struct timer_list *t = &per_cpu(mce_timer, cpu);
 +
 +      mce_disable_cpu();
 +      del_timer_sync(t);
 +      mce_threshold_remove_device(cpu);
 +      mce_device_remove(cpu);
 +      return 0;
 +}
  
  static __init void mce_init_banks(void)
  {
  
  static __init int mcheck_init_device(void)
  {
 +      enum cpuhp_state hp_online;
        int err;
 -      int i = 0;
  
        if (!mce_available(&boot_cpu_data)) {
                err = -EIO;
        if (err)
                goto err_out_mem;
  
 -      cpu_notifier_register_begin();
 -      for_each_online_cpu(i) {
 -              err = mce_device_create(i);
 -              if (err) {
 -                      /*
 -                       * Register notifier anyway (and do not unreg it) so
 -                       * that we don't leave undeleted timers, see notifier
 -                       * callback above.
 -                       */
 -                      __register_hotcpu_notifier(&mce_cpu_notifier);
 -                      cpu_notifier_register_done();
 -                      goto err_device_create;
 -              }
 -      }
 +      err = cpuhp_setup_state(CPUHP_X86_MCE_DEAD, "x86/mce:dead", NULL,
 +                              mce_cpu_dead);
 +      if (err)
 +              goto err_out_mem;
  
 -      __register_hotcpu_notifier(&mce_cpu_notifier);
 -      cpu_notifier_register_done();
 +      err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/mce:online",
 +                              mce_cpu_online, mce_cpu_pre_down);
 +      if (err < 0)
 +              goto err_out_online;
 +      hp_online = err;
  
        register_syscore_ops(&mce_syscore_ops);
  
  
  err_register:
        unregister_syscore_ops(&mce_syscore_ops);
 +      cpuhp_remove_state(hp_online);
  
 -err_device_create:
 -      /*
 -       * We didn't keep track of which devices were created above, but
 -       * even if we had, the set of online cpus might have changed.
 -       * Play safe and remove for every possible cpu, since
 -       * mce_device_remove() will do the right thing.
 -       */
 -      for_each_possible_cpu(i)
 -              mce_device_remove(i);
 +err_out_online:
 +      cpuhp_remove_state(CPUHP_X86_MCE_DEAD);
  
  err_out_mem:
        free_cpumask_var(mce_device_initialized);
diff --combined drivers/tty/vt/vt.c
index 6232644451005159f446d209a44e46c508de6751,95528461a021c79051802dfda5f9bbd2a09da721..4c10a9df3b91f3ea2b1143c41cb530a737a48366
@@@ -315,27 -315,38 +315,27 @@@ void schedule_console_callback(void
        schedule_work(&console_work);
  }
  
 -static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
 +static void con_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
 +              enum con_scroll dir, unsigned int nr)
  {
 -      unsigned short *d, *s;
 +      u16 *clear, *d, *s;
  
 -      if (t+nr >= b)
 +      if (t + nr >= b)
                nr = b - t - 1;
        if (b > vc->vc_rows || t >= b || nr < 1)
                return;
 -      if (con_is_visible(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_UP, nr))
 +      if (con_is_visible(vc) && vc->vc_sw->con_scroll(vc, t, b, dir, nr))
                return;
 -      d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
 -      s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr));
 -      scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row);
 -      scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_video_erase_char,
 -                  vc->vc_size_row * nr);
 -}
  
 -static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
 -{
 -      unsigned short *s;
 -      unsigned int step;
 +      s = clear = (u16 *)(vc->vc_origin + vc->vc_size_row * t);
 +      d = (u16 *)(vc->vc_origin + vc->vc_size_row * (t + nr));
  
 -      if (t+nr >= b)
 -              nr = b - t - 1;
 -      if (b > vc->vc_rows || t >= b || nr < 1)
 -              return;
 -      if (con_is_visible(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_DOWN, nr))
 -              return;
 -      s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
 -      step = vc->vc_cols * nr;
 -      scr_memmovew(s + step, s, (b - t - nr) * vc->vc_size_row);
 -      scr_memsetw(s, vc->vc_video_erase_char, 2 * step);
 +      if (dir == SM_UP) {
 +              clear = s + (b - t - nr) * vc->vc_cols;
 +              swap(s, d);
 +      }
 +      scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row);
 +      scr_memsetw(clear, vc->vc_video_erase_char, vc->vc_size_row * nr);
  }
  
  static void do_update_region(struct vc_data *vc, unsigned long start, int count)
@@@ -859,15 -870,10 +859,15 @@@ static int vc_do_resize(struct tty_stru
        if (new_cols == vc->vc_cols && new_rows == vc->vc_rows)
                return 0;
  
 +      if (new_screen_size > (4 << 20))
 +              return -EINVAL;
        newscreen = kmalloc(new_screen_size, GFP_USER);
        if (!newscreen)
                return -ENOMEM;
  
 +      if (vc == sel_cons)
 +              clear_selection();
 +
        old_rows = vc->vc_rows;
        old_row_size = vc->vc_size_row;
  
@@@ -1109,7 -1115,7 +1109,7 @@@ static void lf(struct vc_data *vc
         * if below scrolling region
         */
        if (vc->vc_y + 1 == vc->vc_bottom)
 -              scrup(vc, vc->vc_top, vc->vc_bottom, 1);
 +              con_scroll(vc, vc->vc_top, vc->vc_bottom, SM_UP, 1);
        else if (vc->vc_y < vc->vc_rows - 1) {
                vc->vc_y++;
                vc->vc_pos += vc->vc_size_row;
@@@ -1124,7 -1130,7 +1124,7 @@@ static void ri(struct vc_data *vc
         * if above scrolling region
         */
        if (vc->vc_y == vc->vc_top)
 -              scrdown(vc, vc->vc_top, vc->vc_bottom, 1);
 +              con_scroll(vc, vc->vc_top, vc->vc_bottom, SM_DOWN, 1);
        else if (vc->vc_y > 0) {
                vc->vc_y--;
                vc->vc_pos -= vc->vc_size_row;
@@@ -1170,7 -1176,7 +1170,7 @@@ static void csi_J(struct vc_data *vc, i
                        break;
                case 3: /* erase scroll-back buffer (and whole display) */
                        scr_memsetw(vc->vc_screenbuf, vc->vc_video_erase_char,
 -                                  vc->vc_screenbuf_size >> 1);
 +                                  vc->vc_screenbuf_size);
                        set_origin(vc);
                        if (con_is_visible(vc))
                                update_screen(vc);
@@@ -1620,7 -1626,7 +1620,7 @@@ static void csi_L(struct vc_data *vc, u
                nr = vc->vc_rows - vc->vc_y;
        else if (!nr)
                nr = 1;
 -      scrdown(vc, vc->vc_y, vc->vc_bottom, nr);
 +      con_scroll(vc, vc->vc_y, vc->vc_bottom, SM_DOWN, nr);
        vc->vc_need_wrap = 0;
  }
  
@@@ -1641,7 -1647,7 +1641,7 @@@ static void csi_M(struct vc_data *vc, u
                nr = vc->vc_rows - vc->vc_y;
        else if (!nr)
                nr=1;
 -      scrup(vc, vc->vc_y, vc->vc_bottom, nr);
 +      con_scroll(vc, vc->vc_y, vc->vc_bottom, SM_UP, nr);
        vc->vc_need_wrap = 0;
  }
  
@@@ -3923,10 -3929,6 +3923,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);
  }
@@@ -4284,46 -4286,6 +4280,46 @@@ void vcs_scr_updated(struct vc_data *vc
        notify_update(vc);
  }
  
 +void vc_scrolldelta_helper(struct vc_data *c, int lines,
 +              unsigned int rolled_over, void *base, unsigned int size)
 +{
 +      unsigned long ubase = (unsigned long)base;
 +      ptrdiff_t scr_end = (void *)c->vc_scr_end - base;
 +      ptrdiff_t vorigin = (void *)c->vc_visible_origin - base;
 +      ptrdiff_t origin = (void *)c->vc_origin - base;
 +      int margin = c->vc_size_row * 4;
 +      int from, wrap, from_off, avail;
 +
 +      /* Turn scrollback off */
 +      if (!lines) {
 +              c->vc_visible_origin = c->vc_origin;
 +              return;
 +      }
 +
 +      /* Do we have already enough to allow jumping from 0 to the end? */
 +      if (rolled_over > scr_end + margin) {
 +              from = scr_end;
 +              wrap = rolled_over + c->vc_size_row;
 +      } else {
 +              from = 0;
 +              wrap = size;
 +      }
 +
 +      from_off = (vorigin - from + wrap) % wrap + lines * c->vc_size_row;
 +      avail = (origin - from + wrap) % wrap;
 +
 +      /* Only a little piece would be left? Show all incl. the piece! */
 +      if (avail < 2 * margin)
 +              margin = 0;
 +      if (from_off < margin)
 +              from_off = 0;
 +      if (from_off > avail - margin)
 +              from_off = avail;
 +
 +      c->vc_visible_origin = ubase + (from + from_off) % wrap;
 +}
 +EXPORT_SYMBOL_GPL(vc_scrolldelta_helper);
 +
  /*
   *    Visible symbols for modules
   */
index d4f16cf6281c3980cc5d9cc5ebde7c1bcf40ff57,2cddd38794b2714cb1605a3a341f9cb9348dec3a..a26cc437293cffbd2259951563eafcd8f194c686
@@@ -119,30 -119,18 +119,30 @@@ struct delayed_work 
        int cpu;
  };
  
 -/*
 - * A struct for workqueue attributes.  This can be used to change
 - * attributes of an unbound workqueue.
 +/**
 + * struct workqueue_attrs - A struct for workqueue attributes.
   *
 - * Unlike other fields, ->no_numa isn't a property of a worker_pool.  It
 - * only modifies how apply_workqueue_attrs() select pools and thus doesn't
 - * participate in pool hash calculations or equality comparisons.
 + * This can be used to change attributes of an unbound workqueue.
   */
  struct workqueue_attrs {
 -      int                     nice;           /* nice level */
 -      cpumask_var_t           cpumask;        /* allowed CPUs */
 -      bool                    no_numa;        /* disable NUMA affinity */
 +      /**
 +       * @nice: nice level
 +       */
 +      int nice;
 +
 +      /**
 +       * @cpumask: allowed CPUs
 +       */
 +      cpumask_var_t cpumask;
 +
 +      /**
 +       * @no_numa: disable NUMA affinity
 +       *
 +       * Unlike other fields, ``no_numa`` isn't a property of a worker_pool. It
 +       * only modifies how :c:func:`apply_workqueue_attrs` select pools and thus
 +       * doesn't participate in pool hash calculations or equality comparisons.
 +       */
 +      bool no_numa;
  };
  
  static inline struct delayed_work *to_delayed_work(struct work_struct *work)
@@@ -284,7 -272,7 +284,7 @@@ static inline unsigned int work_static(
  
  /*
   * Workqueue flags and constants.  For details, please refer to
 - * Documentation/workqueue.txt.
 + * Documentation/core-api/workqueue.rst.
   */
  enum {
        WQ_UNBOUND              = 1 << 1, /* not bound to any cpu */
@@@ -382,8 -370,7 +382,8 @@@ __alloc_workqueue_key(const char *fmt, 
   * @args...: args for @fmt
   *
   * Allocate a workqueue with the specified parameters.  For detailed
 - * information on WQ_* flags, please refer to Documentation/workqueue.txt.
 + * information on WQ_* flags, please refer to
 + * Documentation/core-api/workqueue.rst.
   *
   * The __lock_name macro dance is to guarantee that single lock_class_key
   * doesn't end up with different namesm, which isn't allowed by lockdep.
@@@ -603,14 -590,6 +603,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)
  {
@@@ -645,4 -624,7 +637,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 fa201166cba7e9ca4995dab141103c78473ba20e,9af9274525b590f077a518b135d3d1adac9b45f3..23c275cca73a7b9052edc080483a79f49a23db9e
@@@ -448,8 -448,6 +448,8 @@@ void __init parse_early_param(void
        done = 1;
  }
  
 +void __init __weak arch_post_acpi_subsys_init(void) { }
 +
  void __init __weak smp_setup_processor_id(void)
  {
  }
@@@ -553,6 -551,14 +553,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 */
        check_bugs();
  
        acpi_subsystem_init();
 +      arch_post_acpi_subsys_init();
        sfi_init_late();
  
        if (efi_enabled(EFI_RUNTIME_SERVICES)) {
@@@ -983,7 -988,7 +991,7 @@@ static int __ref kernel_init(void *unus
                return 0;
  
        panic("No working init found.  Try passing init= option to kernel. "
 -            "See Linux Documentation/init.txt for guidance.");
 +            "See Linux Documentation/admin-guide/init.rst for guidance.");
  }
  
  static noinline void __init kernel_init_freeable(void)
  
        smp_prepare_cpus(setup_max_cpus);
  
+       workqueue_init();
        do_pre_smp_initcalls();
        lockup_detector_init();
  
diff --combined lib/debugobjects.c
index 056052dc8e911f31f20bd5aff4824c94dd9f5e83,8458ec9d3d9fa83df9502099ea193cdc94ca6e82..04c1ef717fe0c312d876a5388ae12d74d66d412b
@@@ -199,7 -199,7 +199,7 @@@ static void free_object(struct debug_ob
         * initialized:
         */
        if (obj_pool_free > ODEBUG_POOL_SIZE && obj_cache)
-               sched = keventd_up();
+               sched = 1;
        hlist_add_head(&obj->node, &obj_pool);
        obj_pool_free++;
        obj_pool_used--;
@@@ -362,7 -362,6 +362,7 @@@ void debug_object_init(void *addr, stru
  
        __debug_object_init(addr, descr, 0);
  }
 +EXPORT_SYMBOL_GPL(debug_object_init);
  
  /**
   * debug_object_init_on_stack - debug checks when an object on stack is
@@@ -377,7 -376,6 +377,7 @@@ void debug_object_init_on_stack(void *a
  
        __debug_object_init(addr, descr, 1);
  }
 +EXPORT_SYMBOL_GPL(debug_object_init_on_stack);
  
  /**
   * debug_object_activate - debug checks when an object is activated
@@@ -451,7 -449,6 +451,7 @@@ int debug_object_activate(void *addr, s
        }
        return 0;
  }
 +EXPORT_SYMBOL_GPL(debug_object_activate);
  
  /**
   * debug_object_deactivate - debug checks when an object is deactivated
@@@ -499,7 -496,6 +499,7 @@@ void debug_object_deactivate(void *addr
  
        raw_spin_unlock_irqrestore(&db->lock, flags);
  }
 +EXPORT_SYMBOL_GPL(debug_object_deactivate);
  
  /**
   * debug_object_destroy - debug checks when an object is destroyed
@@@ -546,7 -542,6 +546,7 @@@ void debug_object_destroy(void *addr, s
  out_unlock:
        raw_spin_unlock_irqrestore(&db->lock, flags);
  }
 +EXPORT_SYMBOL_GPL(debug_object_destroy);
  
  /**
   * debug_object_free - debug checks when an object is freed
@@@ -587,7 -582,6 +587,7 @@@ void debug_object_free(void *addr, stru
  out_unlock:
        raw_spin_unlock_irqrestore(&db->lock, flags);
  }
 +EXPORT_SYMBOL_GPL(debug_object_free);
  
  /**
   * debug_object_assert_init - debug checks when object should be init-ed
@@@ -632,7 -626,6 +632,7 @@@ void debug_object_assert_init(void *add
  
        raw_spin_unlock_irqrestore(&db->lock, flags);
  }
 +EXPORT_SYMBOL_GPL(debug_object_assert_init);
  
  /**
   * debug_object_active_state - debug checks object usage state machine
@@@ -680,7 -673,6 +680,7 @@@ debug_object_active_state(void *addr, s
  
        raw_spin_unlock_irqrestore(&db->lock, flags);
  }
 +EXPORT_SYMBOL_GPL(debug_object_active_state);
  
  #ifdef CONFIG_DEBUG_OBJECTS_FREE
  static void __debug_check_no_obj_freed(const void *address, unsigned long size)
diff --combined mm/slab.c
index 87b29e76cafdad57eae3a70bf34f1362a4434c53,6508b4dab99d24c2fe3f7e41c9eb18a2b549277f..29bc6c0dedd07020e9f433332f907620239343a5
+++ b/mm/slab.c
@@@ -227,8 -227,6 +227,8 @@@ static void kmem_cache_node_init(struc
        INIT_LIST_HEAD(&parent->slabs_full);
        INIT_LIST_HEAD(&parent->slabs_partial);
        INIT_LIST_HEAD(&parent->slabs_free);
 +      parent->total_slabs = 0;
 +      parent->free_slabs = 0;
        parent->shared = NULL;
        parent->alien = NULL;
        parent->colour_next = 0;
@@@ -552,12 -550,7 +552,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,
@@@ -968,7 -961,7 +963,7 @@@ static int setup_kmem_cache_node(struc
         * guaranteed to be valid until irq is re-enabled, because it will be
         * freed after synchronize_sched().
         */
 -      if (force_change)
 +      if (old_shared && force_change)
                synchronize_sched();
  
  fail:
@@@ -1367,6 -1360,7 +1362,6 @@@ slab_out_of_memory(struct kmem_cache *c
  {
  #if DEBUG
        struct kmem_cache_node *n;
 -      struct page *page;
        unsigned long flags;
        int node;
        static DEFINE_RATELIMIT_STATE(slab_oom_rs, DEFAULT_RATELIMIT_INTERVAL,
                cachep->name, cachep->size, cachep->gfporder);
  
        for_each_kmem_cache_node(cachep, node, n) {
 -              unsigned long active_objs = 0, num_objs = 0, free_objects = 0;
 -              unsigned long active_slabs = 0, num_slabs = 0;
 +              unsigned long total_slabs, free_slabs, free_objs;
  
                spin_lock_irqsave(&n->list_lock, flags);
 -              list_for_each_entry(page, &n->slabs_full, lru) {
 -                      active_objs += cachep->num;
 -                      active_slabs++;
 -              }
 -              list_for_each_entry(page, &n->slabs_partial, lru) {
 -                      active_objs += page->active;
 -                      active_slabs++;
 -              }
 -              list_for_each_entry(page, &n->slabs_free, lru)
 -                      num_slabs++;
 -
 -              free_objects += n->free_objects;
 +              total_slabs = n->total_slabs;
 +              free_slabs = n->free_slabs;
 +              free_objs = n->free_objects;
                spin_unlock_irqrestore(&n->list_lock, flags);
  
 -              num_slabs += active_slabs;
 -              num_objs = num_slabs * cachep->num;
 -              pr_warn("  node %d: slabs: %ld/%ld, objs: %ld/%ld, free: %ld\n",
 -                      node, active_slabs, num_slabs, active_objs, num_objs,
 -                      free_objects);
 +              pr_warn("  node %d: slabs: %ld/%ld, objs: %ld/%ld\n",
 +                      node, total_slabs - free_slabs, total_slabs,
 +                      (total_slabs * cachep->num) - free_objs,
 +                      total_slabs * cachep->num);
        }
  #endif
  }
@@@ -2304,8 -2309,6 +2299,8 @@@ static int drain_freelist(struct kmem_c
  
                page = list_entry(p, struct page, lru);
                list_del(&page->lru);
 +              n->free_slabs--;
 +              n->total_slabs--;
                /*
                 * Safe to drop the lock. The slab is no longer linked
                 * to the cache.
@@@ -2319,7 -2322,7 +2314,7 @@@ out
        return nr_freed;
  }
  
 -int __kmem_cache_shrink(struct kmem_cache *cachep, bool deactivate)
 +int __kmem_cache_shrink(struct kmem_cache *cachep)
  {
        int ret = 0;
        int node;
  
  int __kmem_cache_shutdown(struct kmem_cache *cachep)
  {
 -      return __kmem_cache_shrink(cachep, false);
 +      return __kmem_cache_shrink(cachep);
  }
  
  void __kmem_cache_release(struct kmem_cache *cachep)
@@@ -2740,13 -2743,10 +2735,13 @@@ static void cache_grow_end(struct kmem_
        n = get_node(cachep, page_to_nid(page));
  
        spin_lock(&n->list_lock);
 -      if (!page->active)
 +      n->total_slabs++;
 +      if (!page->active) {
                list_add_tail(&page->lru, &(n->slabs_free));
 -      else
 +              n->free_slabs++;
 +      } else
                fixup_slab_list(cachep, n, page, &list);
 +
        STATS_INC_GROWN(cachep);
        n->free_objects += cachep->num - page->active;
        spin_unlock(&n->list_lock);
@@@ -2891,10 -2891,9 +2886,10 @@@ static noinline struct page *get_valid_
  
        /* Move pfmemalloc slab to the end of list to speed up next search */
        list_del(&page->lru);
 -      if (!page->active)
 +      if (!page->active) {
                list_add_tail(&page->lru, &n->slabs_free);
 -      else
 +              n->free_slabs++;
 +      } else
                list_add_tail(&page->lru, &n->slabs_partial);
  
        list_for_each_entry(page, &n->slabs_partial, lru) {
                        return page;
        }
  
 +      n->free_touched = 1;
        list_for_each_entry(page, &n->slabs_free, lru) {
 -              if (!PageSlabPfmemalloc(page))
 +              if (!PageSlabPfmemalloc(page)) {
 +                      n->free_slabs--;
                        return page;
 +              }
        }
  
        return NULL;
@@@ -2917,18 -2913,16 +2912,18 @@@ static struct page *get_first_slab(stru
  {
        struct page *page;
  
 -      page = list_first_entry_or_null(&n->slabs_partial,
 -                      struct page, lru);
 +      assert_spin_locked(&n->list_lock);
 +      page = list_first_entry_or_null(&n->slabs_partial, struct page, lru);
        if (!page) {
                n->free_touched = 1;
 -              page = list_first_entry_or_null(&n->slabs_free,
 -                              struct page, lru);
 +              page = list_first_entry_or_null(&n->slabs_free, struct page,
 +                                              lru);
 +              if (page)
 +                      n->free_slabs--;
        }
  
        if (sk_memalloc_socks())
 -              return get_valid_first_slab(n, page, pfmemalloc);
 +              page = get_valid_first_slab(n, page, pfmemalloc);
  
        return page;
  }
@@@ -3428,10 -3422,9 +3423,10 @@@ static void free_block(struct kmem_cach
                STATS_DEC_ACTIVE(cachep);
  
                /* fixup slab chains */
 -              if (page->active == 0)
 +              if (page->active == 0) {
                        list_add(&page->lru, &n->slabs_free);
 -              else {
 +                      n->free_slabs++;
 +              } else {
                        /* Unconditionally move a slab to the end of the
                         * partial list on free - maximum time for the
                         * other objects to be freed, too.
  
                page = list_last_entry(&n->slabs_free, struct page, lru);
                list_move(&page->lru, list);
 +              n->free_slabs--;
 +              n->total_slabs--;
        }
  }
  
  #ifdef CONFIG_SLABINFO
  void get_slabinfo(struct kmem_cache *cachep, struct slabinfo *sinfo)
  {
 -      struct page *page;
 -      unsigned long active_objs;
 -      unsigned long num_objs;
 -      unsigned long active_slabs = 0;
 -      unsigned long num_slabs, free_objects = 0, shared_avail = 0;
 -      const char *name;
 -      char *error = NULL;
 +      unsigned long active_objs, num_objs, active_slabs;
 +      unsigned long total_slabs = 0, free_objs = 0, shared_avail = 0;
 +      unsigned long free_slabs = 0;
        int node;
        struct kmem_cache_node *n;
  
 -      active_objs = 0;
 -      num_slabs = 0;
        for_each_kmem_cache_node(cachep, node, n) {
 -
                check_irq_on();
                spin_lock_irq(&n->list_lock);
  
 -              list_for_each_entry(page, &n->slabs_full, lru) {
 -                      if (page->active != cachep->num && !error)
 -                              error = "slabs_full accounting error";
 -                      active_objs += cachep->num;
 -                      active_slabs++;
 -              }
 -              list_for_each_entry(page, &n->slabs_partial, lru) {
 -                      if (page->active == cachep->num && !error)
 -                              error = "slabs_partial accounting error";
 -                      if (!page->active && !error)
 -                              error = "slabs_partial accounting error";
 -                      active_objs += page->active;
 -                      active_slabs++;
 -              }
 -              list_for_each_entry(page, &n->slabs_free, lru) {
 -                      if (page->active && !error)
 -                              error = "slabs_free accounting error";
 -                      num_slabs++;
 -              }
 -              free_objects += n->free_objects;
 +              total_slabs += n->total_slabs;
 +              free_slabs += n->free_slabs;
 +              free_objs += n->free_objects;
 +
                if (n->shared)
                        shared_avail += n->shared->avail;
  
                spin_unlock_irq(&n->list_lock);
        }
 -      num_slabs += active_slabs;
 -      num_objs = num_slabs * cachep->num;
 -      if (num_objs - active_objs != free_objects && !error)
 -              error = "free_objects accounting error";
 -
 -      name = cachep->name;
 -      if (error)
 -              pr_err("slab: cache %s error: %s\n", name, error);
 +      num_objs = total_slabs * cachep->num;
 +      active_slabs = total_slabs - free_slabs;
 +      active_objs = num_objs - free_objs;
  
        sinfo->active_objs = active_objs;
        sinfo->num_objs = num_objs;
        sinfo->active_slabs = active_slabs;
 -      sinfo->num_slabs = num_slabs;
 +      sinfo->num_slabs = total_slabs;
        sinfo->shared_avail = shared_avail;
        sinfo->limit = cachep->limit;
        sinfo->batchcount = cachep->batchcount;
This page took 0.154106 seconds and 4 git commands to generate.