]> Git Repo - linux.git/commitdiff
Merge tag 'sysctl-6.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/mcgrof...
authorLinus Torvalds <[email protected]>
Thu, 2 Nov 2023 06:51:41 +0000 (20:51 -1000)
committerLinus Torvalds <[email protected]>
Thu, 2 Nov 2023 06:51:41 +0000 (20:51 -1000)
Pull sysctl updates from Luis Chamberlain:
 "To help make the move of sysctls out of kernel/sysctl.c not incur a
  size penalty sysctl has been changed to allow us to not require the
  sentinel, the final empty element on the sysctl array. Joel Granados
  has been doing all this work. On the v6.6 kernel we got the major
  infrastructure changes required to support this. For v6.7-rc1 we have
  all arch/ and drivers/ modified to remove the sentinel. Both arch and
  driver changes have been on linux-next for a bit less than a month. It
  is worth re-iterating the value:

   - this helps reduce the overall build time size of the kernel and run
     time memory consumed by the kernel by about ~64 bytes per array

   - the extra 64-byte penalty is no longer inncurred now when we move
     sysctls out from kernel/sysctl.c to their own files

  For v6.8-rc1 expect removal of all the sentinels and also then the
  unneeded check for procname == NULL.

  The last two patches are fixes recently merged by Krister Johansen
  which allow us again to use softlockup_panic early on boot. This used
  to work but the alias work broke it. This is useful for folks who want
  to detect softlockups super early rather than wait and spend money on
  cloud solutions with nothing but an eventual hung kernel. Although
  this hadn't gone through linux-next it's also a stable fix, so we
  might as well roll through the fixes now"

* tag 'sysctl-6.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/linux: (23 commits)
  watchdog: move softlockup_panic back to early_param
  proc: sysctl: prevent aliased sysctls from getting passed to init
  intel drm: Remove now superfluous sentinel element from ctl_table array
  Drivers: hv: Remove now superfluous sentinel element from ctl_table array
  raid: Remove now superfluous sentinel element from ctl_table array
  fw loader: Remove the now superfluous sentinel element from ctl_table array
  sgi-xp: Remove the now superfluous sentinel element from ctl_table array
  vrf: Remove the now superfluous sentinel element from ctl_table array
  char-misc: Remove the now superfluous sentinel element from ctl_table array
  infiniband: Remove the now superfluous sentinel element from ctl_table array
  macintosh: Remove the now superfluous sentinel element from ctl_table array
  parport: Remove the now superfluous sentinel element from ctl_table array
  scsi: Remove now superfluous sentinel element from ctl_table array
  tty: Remove now superfluous sentinel element from ctl_table array
  xen: Remove now superfluous sentinel element from ctl_table array
  hpet: Remove now superfluous sentinel element from ctl_table array
  c-sky: Remove now superfluous sentinel element from ctl_talbe array
  powerpc: Remove now superfluous sentinel element from ctl_table arrays
  riscv: Remove now superfluous sentinel element from ctl_table array
  x86/vdso: Remove now superfluous sentinel element from ctl_table array
  ...

1  2 
arch/arm64/kernel/fpsimd.c
arch/arm64/kernel/process.c
arch/s390/kernel/topology.c
arch/x86/kernel/cpu/intel.c
drivers/char/hpet.c
drivers/gpu/drm/i915/i915_perf.c
drivers/md/md.c
drivers/misc/sgi-xp/xpc_main.c
drivers/perf/arm_pmuv3.c
drivers/tty/tty_io.c
fs/proc/proc_sysctl.c

index 5ddc246f1482d6673682d847277ff3f6154a8ca7,9afd0eb0cf88ab08081c7df5bf51754998840db0..1559c706d32d1dd0a69fa74457cc5b34a4937c99
@@@ -589,7 -589,6 +589,6 @@@ static struct ctl_table sve_default_vl_
                .proc_handler   = vec_proc_do_default_vl,
                .extra1         = &vl_info[ARM64_VEC_SVE],
        },
-       { }
  };
  
  static int __init sve_sysctl_init(void)
@@@ -613,7 -612,6 +612,6 @@@ static struct ctl_table sme_default_vl_
                .proc_handler   = vec_proc_do_default_vl,
                .extra1         = &vl_info[ARM64_VEC_SME],
        },
-       { }
  };
  
  static int __init sme_sysctl_init(void)
@@@ -1160,20 -1158,44 +1158,20 @@@ fail
        panic("Cannot allocate percpu memory for EFI SVE save/restore");
  }
  
 -/*
 - * Enable SVE for EL1.
 - * Intended for use by the cpufeatures code during CPU boot.
 - */
 -void sve_kernel_enable(const struct arm64_cpu_capabilities *__always_unused p)
 +void cpu_enable_sve(const struct arm64_cpu_capabilities *__always_unused p)
  {
        write_sysreg(read_sysreg(CPACR_EL1) | CPACR_EL1_ZEN_EL1EN, CPACR_EL1);
        isb();
  }
  
 -/*
 - * Read the pseudo-ZCR used by cpufeatures to identify the supported SVE
 - * vector length.
 - *
 - * Use only if SVE is present.
 - * This function clobbers the SVE vector length.
 - */
 -u64 read_zcr_features(void)
 -{
 -      /*
 -       * Set the maximum possible VL, and write zeroes to all other
 -       * bits to see if they stick.
 -       */
 -      sve_kernel_enable(NULL);
 -      write_sysreg_s(ZCR_ELx_LEN_MASK, SYS_ZCR_EL1);
 -
 -      /* Return LEN value that would be written to get the maximum VL */
 -      return sve_vq_from_vl(sve_get_vl()) - 1;
 -}
 -
  void __init sve_setup(void)
  {
        struct vl_info *info = &vl_info[ARM64_VEC_SVE];
 -      u64 zcr;
        DECLARE_BITMAP(tmp_map, SVE_VQ_MAX);
        unsigned long b;
 +      int max_bit;
  
 -      if (!system_supports_sve())
 +      if (!cpus_have_cap(ARM64_SVE))
                return;
  
        /*
        if (WARN_ON(!test_bit(__vq_to_bit(SVE_VQ_MIN), info->vq_map)))
                set_bit(__vq_to_bit(SVE_VQ_MIN), info->vq_map);
  
 -      zcr = read_sanitised_ftr_reg(SYS_ZCR_EL1);
 -      info->max_vl = sve_vl_from_vq((zcr & ZCR_ELx_LEN_MASK) + 1);
 -
 -      /*
 -       * Sanity-check that the max VL we determined through CPU features
 -       * corresponds properly to sve_vq_map.  If not, do our best:
 -       */
 -      if (WARN_ON(info->max_vl != find_supported_vector_length(ARM64_VEC_SVE,
 -                                                               info->max_vl)))
 -              info->max_vl = find_supported_vector_length(ARM64_VEC_SVE,
 -                                                          info->max_vl);
 +      max_bit = find_first_bit(info->vq_map, SVE_VQ_MAX);
 +      info->max_vl = sve_vl_from_vq(__bit_to_vq(max_bit));
  
        /*
         * For the default VL, pick the maximum supported value <= 64.
@@@ -1263,7 -1294,7 +1261,7 @@@ static void sme_free(struct task_struc
        task->thread.sme_state = NULL;
  }
  
 -void sme_kernel_enable(const struct arm64_cpu_capabilities *__always_unused p)
 +void cpu_enable_sme(const struct arm64_cpu_capabilities *__always_unused p)
  {
        /* Set priority for all PEs to architecturally defined minimum */
        write_sysreg_s(read_sysreg_s(SYS_SMPRI_EL1) & ~SMPRI_EL1_PRIORITY_MASK,
        isb();
  }
  
 -/*
 - * This must be called after sme_kernel_enable(), we rely on the
 - * feature table being sorted to ensure this.
 - */
 -void sme2_kernel_enable(const struct arm64_cpu_capabilities *__always_unused p)
 +void cpu_enable_sme2(const struct arm64_cpu_capabilities *__always_unused p)
  {
 +      /* This must be enabled after SME */
 +      BUILD_BUG_ON(ARM64_SME2 <= ARM64_SME);
 +
        /* Allow use of ZT0 */
        write_sysreg_s(read_sysreg_s(SYS_SMCR_EL1) | SMCR_ELx_EZT0_MASK,
                       SYS_SMCR_EL1);
  }
  
 -/*
 - * This must be called after sme_kernel_enable(), we rely on the
 - * feature table being sorted to ensure this.
 - */
 -void fa64_kernel_enable(const struct arm64_cpu_capabilities *__always_unused p)
 +void cpu_enable_fa64(const struct arm64_cpu_capabilities *__always_unused p)
  {
 +      /* This must be enabled after SME */
 +      BUILD_BUG_ON(ARM64_SME_FA64 <= ARM64_SME);
 +
        /* Allow use of FA64 */
        write_sysreg_s(read_sysreg_s(SYS_SMCR_EL1) | SMCR_ELx_FA64_MASK,
                       SYS_SMCR_EL1);
  }
  
 -/*
 - * Read the pseudo-SMCR used by cpufeatures to identify the supported
 - * vector length.
 - *
 - * Use only if SME is present.
 - * This function clobbers the SME vector length.
 - */
 -u64 read_smcr_features(void)
 -{
 -      sme_kernel_enable(NULL);
 -
 -      /*
 -       * Set the maximum possible VL.
 -       */
 -      write_sysreg_s(read_sysreg_s(SYS_SMCR_EL1) | SMCR_ELx_LEN_MASK,
 -                     SYS_SMCR_EL1);
 -
 -      /* Return LEN value that would be written to get the maximum VL */
 -      return sve_vq_from_vl(sme_get_vl()) - 1;
 -}
 -
  void __init sme_setup(void)
  {
        struct vl_info *info = &vl_info[ARM64_VEC_SME];
 -      u64 smcr;
 -      int min_bit;
 +      int min_bit, max_bit;
  
 -      if (!system_supports_sme())
 +      if (!cpus_have_cap(ARM64_SME))
                return;
  
        /*
         * SME doesn't require any particular vector length be
         * supported but it does require at least one.  We should have
         * disabled the feature entirely while bringing up CPUs but
 -       * let's double check here.
 +       * let's double check here.  The bitmap is SVE_VQ_MAP sized for
 +       * sharing with SVE.
         */
        WARN_ON(bitmap_empty(info->vq_map, SVE_VQ_MAX));
  
        min_bit = find_last_bit(info->vq_map, SVE_VQ_MAX);
        info->min_vl = sve_vl_from_vq(__bit_to_vq(min_bit));
  
 -      smcr = read_sanitised_ftr_reg(SYS_SMCR_EL1);
 -      info->max_vl = sve_vl_from_vq((smcr & SMCR_ELx_LEN_MASK) + 1);
 -
 -      /*
 -       * Sanity-check that the max VL we determined through CPU features
 -       * corresponds properly to sme_vq_map.  If not, do our best:
 -       */
 -      if (WARN_ON(info->max_vl != find_supported_vector_length(ARM64_VEC_SME,
 -                                                               info->max_vl)))
 -              info->max_vl = find_supported_vector_length(ARM64_VEC_SME,
 -                                                          info->max_vl);
 +      max_bit = find_first_bit(info->vq_map, SVE_VQ_MAX);
 +      info->max_vl = sve_vl_from_vq(__bit_to_vq(max_bit));
  
        WARN_ON(info->min_vl > info->max_vl);
  
@@@ -1464,17 -1527,8 +1462,17 @@@ void do_sme_acc(unsigned long esr, stru
   */
  void do_fpsimd_acc(unsigned long esr, struct pt_regs *regs)
  {
 -      /* TODO: implement lazy context saving/restoring */
 -      WARN_ON(1);
 +      /* Even if we chose not to use FPSIMD, the hardware could still trap: */
 +      if (!system_supports_fpsimd()) {
 +              force_signal_inject(SIGILL, ILL_ILLOPC, regs->pc, 0);
 +              return;
 +      }
 +
 +      /*
 +       * When FPSIMD is enabled, we should never take a trap unless something
 +       * has gone very wrong.
 +       */
 +      BUG();
  }
  
  /*
@@@ -1715,23 -1769,13 +1713,23 @@@ void fpsimd_bind_state_to_cpu(struct cp
  void fpsimd_restore_current_state(void)
  {
        /*
 -       * For the tasks that were created before we detected the absence of
 -       * FP/SIMD, the TIF_FOREIGN_FPSTATE could be set via fpsimd_thread_switch(),
 -       * e.g, init. This could be then inherited by the children processes.
 -       * If we later detect that the system doesn't support FP/SIMD,
 -       * we must clear the flag for  all the tasks to indicate that the
 -       * FPSTATE is clean (as we can't have one) to avoid looping for ever in
 -       * do_notify_resume().
 +       * TIF_FOREIGN_FPSTATE is set on the init task and copied by
 +       * arch_dup_task_struct() regardless of whether FP/SIMD is detected.
 +       * Thus user threads can have this set even when FP/SIMD hasn't been
 +       * detected.
 +       *
 +       * When FP/SIMD is detected, begin_new_exec() will set
 +       * TIF_FOREIGN_FPSTATE via flush_thread() -> fpsimd_flush_thread(),
 +       * and fpsimd_thread_switch() will set TIF_FOREIGN_FPSTATE when
 +       * switching tasks. We detect FP/SIMD before we exec the first user
 +       * process, ensuring this has TIF_FOREIGN_FPSTATE set and
 +       * do_notify_resume() will call fpsimd_restore_current_state() to
 +       * install the user FP/SIMD context.
 +       *
 +       * When FP/SIMD is not detected, nothing else will clear or set
 +       * TIF_FOREIGN_FPSTATE prior to the first return to userspace, and
 +       * we must clear TIF_FOREIGN_FPSTATE to avoid do_notify_resume()
 +       * looping forever calling fpsimd_restore_current_state().
         */
        if (!system_supports_fpsimd()) {
                clear_thread_flag(TIF_FOREIGN_FPSTATE);
@@@ -2064,13 -2108,6 +2062,13 @@@ static inline void fpsimd_hotplug_init(
  static inline void fpsimd_hotplug_init(void) { }
  #endif
  
 +void cpu_enable_fpsimd(const struct arm64_cpu_capabilities *__always_unused p)
 +{
 +      unsigned long enable = CPACR_EL1_FPEN_EL1EN | CPACR_EL1_FPEN_EL0EN;
 +      write_sysreg(read_sysreg(CPACR_EL1) | enable, CPACR_EL1);
 +      isb();
 +}
 +
  /*
   * FP/SIMD support code initialisation.
   */
index 657ea273c0f9b2597e1be5cb73bb289699fd1e20,610e13c3d41b38cdf60af824d868ff7e82e6f36f..7387b68c745b21344370af4598c5d738953c3595
@@@ -454,7 -454,7 +454,7 @@@ static void ssbs_thread_switch(struct t
         * If all CPUs implement the SSBS extension, then we just need to
         * context-switch the PSTATE field.
         */
 -      if (cpus_have_const_cap(ARM64_SSBS))
 +      if (alternative_has_cap_unlikely(ARM64_SSBS))
                return;
  
        spectre_v4_enable_task_mitigation(next);
@@@ -724,7 -724,6 +724,6 @@@ static struct ctl_table tagged_addr_sys
                .extra1         = SYSCTL_ZERO,
                .extra2         = SYSCTL_ONE,
        },
-       { }
  };
  
  static int __init tagged_addr_init(void)
index 66bda6a8f918c27badbe1ba6077d65a542928460,be8467b2595399ac10c608cf878026a932559de5..89e91b8ce842c54f9e7eca11be568533fba8ced5
@@@ -522,7 -522,7 +522,7 @@@ static struct sched_domain_topology_lev
        { cpu_coregroup_mask, cpu_core_flags, SD_INIT_NAME(MC) },
        { cpu_book_mask, SD_INIT_NAME(BOOK) },
        { cpu_drawer_mask, SD_INIT_NAME(DRAWER) },
 -      { cpu_cpu_mask, SD_INIT_NAME(DIE) },
 +      { cpu_cpu_mask, SD_INIT_NAME(PKG) },
        { NULL, },
  };
  
@@@ -636,7 -636,6 +636,6 @@@ static struct ctl_table topology_ctl_ta
                .mode           = 0644,
                .proc_handler   = topology_ctl_handler,
        },
-       { },
  };
  
  static int __init topology_init(void)
index 55efadb0e9986a9e2b66bd848d1c24a6aca90b2e,d9bb53f49a4df8dceb4c0d6f0869b7b2bb1430b3..a927a8fc962448035f041c8b17f45ffb6bb9e079
@@@ -314,6 -314,19 +314,6 @@@ static void early_init_intel(struct cpu
                setup_clear_cpu_cap(X86_FEATURE_PGE);
        }
  
 -      if (c->cpuid_level >= 0x00000001) {
 -              u32 eax, ebx, ecx, edx;
 -
 -              cpuid(0x00000001, &eax, &ebx, &ecx, &edx);
 -              /*
 -               * If HTT (EDX[28]) is set EBX[16:23] contain the number of
 -               * apicids which are reserved per package. Store the resulting
 -               * shift value for the package management code.
 -               */
 -              if (edx & (1U << 28))
 -                      c->x86_coreid_bits = get_count_order((ebx >> 16) & 0xff);
 -      }
 -
        check_memory_type_self_snoop_errata(c);
  
        /*
@@@ -1003,7 -1016,6 +1003,6 @@@ static struct ctl_table sld_sysctls[] 
                .extra1         = SYSCTL_ZERO,
                .extra2         = SYSCTL_ONE,
        },
-       {}
  };
  
  static int __init sld_mitigate_sysctl_init(void)
diff --combined drivers/char/hpet.c
index 3b2159416e624a6a1320b80667806dc9c47211ee,f09c79081b01b387345558af20f99b73e385cfde..e1deb7a69b8a27b807196f176b96c4e5e9b210df
  static DEFINE_MUTEX(hpet_mutex); /* replaces BKL */
  static u32 hpet_nhpet, hpet_max_freq = HPET_USER_FREQ;
  
 -/* This clocksource driver currently only works on ia64 */
 -#ifdef CONFIG_IA64
 -static void __iomem *hpet_mctr;
 -
 -static u64 read_hpet(struct clocksource *cs)
 -{
 -      return (u64)read_counter((void __iomem *)hpet_mctr);
 -}
 -
 -static struct clocksource clocksource_hpet = {
 -      .name           = "hpet",
 -      .rating         = 250,
 -      .read           = read_hpet,
 -      .mask           = CLOCKSOURCE_MASK(64),
 -      .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 -};
 -static struct clocksource *hpet_clocksource;
 -#endif
 -
  /* A lock for concurrent access by app and isr hpet activity. */
  static DEFINE_SPINLOCK(hpet_lock);
  
@@@ -709,7 -728,6 +709,6 @@@ static struct ctl_table hpet_table[] = 
         .mode = 0644,
         .proc_handler = proc_dointvec,
         },
-       {}
  };
  
  static struct ctl_table_header *sysctl_header;
@@@ -888,6 -906,17 +887,6 @@@ int hpet_alloc(struct hpet_data *hdp
  
        hpetp->hp_delta = hpet_calibrate(hpetp);
  
 -/* This clocksource driver currently only works on ia64 */
 -#ifdef CONFIG_IA64
 -      if (!hpet_clocksource) {
 -              hpet_mctr = (void __iomem *)&hpetp->hp_hpet->hpet_mc;
 -              clocksource_hpet.archdata.fsys_mmio = hpet_mctr;
 -              clocksource_register_hz(&clocksource_hpet, hpetp->hp_tick_freq);
 -              hpetp->hp_clocksource = &clocksource_hpet;
 -              hpet_clocksource = &clocksource_hpet;
 -      }
 -#endif
 -
        return 0;
  }
  
index 7178f298b3e61785b4f8f0503327978446531105,23e769aa214ce24c2a950e409c1d34fd91d68333..2f3ecd7d4804a20d77cc6b5d612431a631814b3a
  #include "gt/intel_gt.h"
  #include "gt/intel_gt_clock_utils.h"
  #include "gt/intel_gt_mcr.h"
 +#include "gt/intel_gt_print.h"
  #include "gt/intel_gt_regs.h"
  #include "gt/intel_lrc.h"
  #include "gt/intel_lrc_reg.h"
@@@ -483,7 -482,8 +483,7 @@@ static void oa_report_id_clear(struct i
  static bool oa_report_ctx_invalid(struct i915_perf_stream *stream, void *report)
  {
        return !(oa_report_id(stream, report) &
 -             stream->perf->gen8_valid_ctx_bit) &&
 -             GRAPHICS_VER(stream->perf->i915) <= 11;
 +             stream->perf->gen8_valid_ctx_bit);
  }
  
  static u64 oa_timestamp(struct i915_perf_stream *stream, void *report)
@@@ -543,9 -543,10 +543,9 @@@ static bool oa_buffer_check_unlocked(st
  {
        u32 gtt_offset = i915_ggtt_offset(stream->oa_buffer.vma);
        int report_size = stream->oa_buffer.format->size;
 -      u32 head, tail, read_tail;
 +      u32 tail, hw_tail;
        unsigned long flags;
        bool pollin;
 -      u32 hw_tail;
        u32 partial_report_size;
  
        /* We have to consider the (unlikely) possibility that read() errors
        spin_lock_irqsave(&stream->oa_buffer.ptr_lock, flags);
  
        hw_tail = stream->perf->ops.oa_hw_tail_read(stream);
 +      hw_tail -= gtt_offset;
  
        /* The tail pointer increases in 64 byte increments, not in report_size
         * steps. Also the report size may not be a power of 2. Compute
        /* Subtract partial amount off the tail */
        hw_tail = OA_TAKEN(hw_tail, partial_report_size);
  
 -      /* NB: The head we observe here might effectively be a little
 -       * out of date. If a read() is in progress, the head could be
 -       * anywhere between this head and stream->oa_buffer.tail.
 -       */
 -      head = stream->oa_buffer.head - gtt_offset;
 -      read_tail = stream->oa_buffer.tail - gtt_offset;
 -
        tail = hw_tail;
  
        /* Walk the stream backward until we find a report with report
         * memory in the order they were written to.
         * If not : (╯°□°)╯︵ ┻━┻
         */
 -      while (OA_TAKEN(tail, read_tail) >= report_size) {
 +      while (OA_TAKEN(tail, stream->oa_buffer.tail) >= report_size) {
                void *report = stream->oa_buffer.vaddr + tail;
  
                if (oa_report_id(stream, report) ||
            __ratelimit(&stream->perf->tail_pointer_race))
                drm_notice(&stream->uncore->i915->drm,
                           "unlanded report(s) head=0x%x tail=0x%x hw_tail=0x%x\n",
 -               head, tail, hw_tail);
 +               stream->oa_buffer.head, tail, hw_tail);
  
 -      stream->oa_buffer.tail = gtt_offset + tail;
 +      stream->oa_buffer.tail = tail;
  
        pollin = OA_TAKEN(stream->oa_buffer.tail,
                          stream->oa_buffer.head) >= report_size;
@@@ -746,6 -753,13 +746,6 @@@ static int gen8_append_oa_reports(struc
  
        spin_unlock_irqrestore(&stream->oa_buffer.ptr_lock, flags);
  
 -      /*
 -       * NB: oa_buffer.head/tail include the gtt_offset which we don't want
 -       * while indexing relative to oa_buf_base.
 -       */
 -      head -= gtt_offset;
 -      tail -= gtt_offset;
 -
        /*
         * An out of bounds or misaligned head or tail pointer implies a driver
         * bug since we validate + align the tail pointers we read from the
                 * We removed the gtt_offset for the copy loop above, indexing
                 * relative to oa_buf_base so put back here...
                 */
 -              head += gtt_offset;
                intel_uncore_write(uncore, oaheadptr,
 -                                 head & GEN12_OAG_OAHEADPTR_MASK);
 +                                 (head + gtt_offset) & GEN12_OAG_OAHEADPTR_MASK);
                stream->oa_buffer.head = head;
  
                spin_unlock_irqrestore(&stream->oa_buffer.ptr_lock, flags);
@@@ -1027,6 -1042,12 +1027,6 @@@ static int gen7_append_oa_reports(struc
  
        spin_unlock_irqrestore(&stream->oa_buffer.ptr_lock, flags);
  
 -      /* NB: oa_buffer.head/tail include the gtt_offset which we don't want
 -       * while indexing relative to oa_buf_base.
 -       */
 -      head -= gtt_offset;
 -      tail -= gtt_offset;
 -
        /* An out of bounds or misaligned head or tail pointer implies a driver
         * bug since we validate + align the tail pointers we read from the
         * hardware and we are in full control of the head pointer which should
        if (start_offset != *offset) {
                spin_lock_irqsave(&stream->oa_buffer.ptr_lock, flags);
  
 -              /* We removed the gtt_offset for the copy loop above, indexing
 -               * relative to oa_buf_base so put back here...
 -               */
 -              head += gtt_offset;
 -
                intel_uncore_write(uncore, GEN7_OASTATUS2,
 -                                 (head & GEN7_OASTATUS2_HEAD_MASK) |
 +                                 ((head + gtt_offset) & GEN7_OASTATUS2_HEAD_MASK) |
                                   GEN7_OASTATUS2_MEM_SELECT_GGTT);
                stream->oa_buffer.head = head;
  
@@@ -1649,6 -1675,13 +1649,6 @@@ static void i915_oa_stream_destroy(stru
  
        free_oa_buffer(stream);
  
 -      /*
 -       * Wa_16011777198:dg2: Unset the override of GUCRC mode to enable rc6.
 -       */
 -      if (stream->override_gucrc)
 -              drm_WARN_ON(&gt->i915->drm,
 -                          intel_guc_slpc_unset_gucrc_mode(&gt->uc.guc.slpc));
 -
        intel_uncore_forcewake_put(stream->uncore, FORCEWAKE_ALL);
        intel_engine_pm_put(stream->engine);
  
        free_noa_wait(stream);
  
        if (perf->spurious_report_rs.missed) {
 -              drm_notice(&gt->i915->drm,
 -                         "%d spurious OA report notices suppressed due to ratelimiting\n",
 -                         perf->spurious_report_rs.missed);
 +              gt_notice(gt, "%d spurious OA report notices suppressed due to ratelimiting\n",
 +                        perf->spurious_report_rs.missed);
        }
  }
  
@@@ -1677,7 -1711,7 +1677,7 @@@ static void gen7_init_oa_buffer(struct 
         */
        intel_uncore_write(uncore, GEN7_OASTATUS2, /* head */
                           gtt_offset | GEN7_OASTATUS2_MEM_SELECT_GGTT);
 -      stream->oa_buffer.head = gtt_offset;
 +      stream->oa_buffer.head = 0;
  
        intel_uncore_write(uncore, GEN7_OABUFFER, gtt_offset);
  
                           gtt_offset | OABUFFER_SIZE_16M);
  
        /* Mark that we need updated tail pointers to read from... */
 -      stream->oa_buffer.tail = gtt_offset;
 +      stream->oa_buffer.tail = 0;
  
        spin_unlock_irqrestore(&stream->oa_buffer.ptr_lock, flags);
  
@@@ -1719,7 -1753,7 +1719,7 @@@ static void gen8_init_oa_buffer(struct 
  
        intel_uncore_write(uncore, GEN8_OASTATUS, 0);
        intel_uncore_write(uncore, GEN8_OAHEADPTR, gtt_offset);
 -      stream->oa_buffer.head = gtt_offset;
 +      stream->oa_buffer.head = 0;
  
        intel_uncore_write(uncore, GEN8_OABUFFER_UDW, 0);
  
        intel_uncore_write(uncore, GEN8_OATAILPTR, gtt_offset & GEN8_OATAILPTR_MASK);
  
        /* Mark that we need updated tail pointers to read from... */
 -      stream->oa_buffer.tail = gtt_offset;
 +      stream->oa_buffer.tail = 0;
  
        /*
         * Reset state used to recognise context switches, affecting which
@@@ -1773,7 -1807,7 +1773,7 @@@ static void gen12_init_oa_buffer(struc
        intel_uncore_write(uncore, __oa_regs(stream)->oa_status, 0);
        intel_uncore_write(uncore, __oa_regs(stream)->oa_head_ptr,
                           gtt_offset & GEN12_OAG_OAHEADPTR_MASK);
 -      stream->oa_buffer.head = gtt_offset;
 +      stream->oa_buffer.head = 0;
  
        /*
         * PRM says:
                           gtt_offset & GEN12_OAG_OATAILPTR_MASK);
  
        /* Mark that we need updated tail pointers to read from... */
 -      stream->oa_buffer.tail = gtt_offset;
 +      stream->oa_buffer.tail = 0;
  
        /*
         * Reset state used to recognise context switches, affecting which
@@@ -1851,7 -1885,7 +1851,7 @@@ static int alloc_oa_buffer(struct i915_
         */
        ret = i915_vma_pin(vma, 0, SZ_16M, PIN_GLOBAL | PIN_HIGH);
        if (ret) {
 -              drm_err(&gt->i915->drm, "Failed to pin OA buffer %d\n", ret);
 +              gt_err(gt, "Failed to pin OA buffer %d\n", ret);
                goto err_unref;
        }
  
@@@ -3193,10 -3227,11 +3193,10 @@@ get_sseu_config(struct intel_sseu *out_
   */
  u32 i915_perf_oa_timestamp_frequency(struct drm_i915_private *i915)
  {
 -      /*
 -       * Wa_18013179988:dg2
 -       * Wa_14015846243:mtl
 -       */
 -      if (IS_DG2(i915) || IS_METEORLAKE(i915)) {
 +      struct intel_gt *gt = to_gt(i915);
 +
 +      /* Wa_18013179988 */
 +      if (IS_DG2(i915) || IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 71))) {
                intel_wakeref_t wakeref;
                u32 reg, shift;
  
@@@ -3237,6 -3272,7 +3237,6 @@@ static int i915_oa_stream_init(struct i
        struct drm_i915_private *i915 = stream->perf->i915;
        struct i915_perf *perf = stream->perf;
        struct i915_perf_group *g;
 -      struct intel_gt *gt;
        int ret;
  
        if (!props->engine) {
                        "OA engine not specified\n");
                return -EINVAL;
        }
 -      gt = props->engine->gt;
        g = props->engine->oa_group;
  
        /*
        intel_engine_pm_get(stream->engine);
        intel_uncore_forcewake_get(stream->uncore, FORCEWAKE_ALL);
  
 -      /*
 -       * Wa_16011777198:dg2: GuC resets render as part of the Wa. This causes
 -       * OA to lose the configuration state. Prevent this by overriding GUCRC
 -       * mode.
 -       */
 -      if (intel_uc_uses_guc_rc(&gt->uc) &&
 -          (IS_DG2_GRAPHICS_STEP(gt->i915, G10, STEP_A0, STEP_C0) ||
 -           IS_DG2_GRAPHICS_STEP(gt->i915, G11, STEP_A0, STEP_B0))) {
 -              ret = intel_guc_slpc_override_gucrc_mode(&gt->uc.guc.slpc,
 -                                                       SLPC_GUCRC_MODE_GUCRC_NO_RC6);
 -              if (ret) {
 -                      drm_dbg(&stream->perf->i915->drm,
 -                              "Unable to override gucrc mode\n");
 -                      goto err_gucrc;
 -              }
 -
 -              stream->override_gucrc = true;
 -      }
 -
        ret = alloc_oa_buffer(stream);
        if (ret)
                goto err_oa_buf_alloc;
@@@ -3380,6 -3436,10 +3380,6 @@@ err_enable
        free_oa_buffer(stream);
  
  err_oa_buf_alloc:
 -      if (stream->override_gucrc)
 -              intel_guc_slpc_unset_gucrc_mode(&gt->uc.guc.slpc);
 -
 -err_gucrc:
        intel_uncore_forcewake_put(stream->uncore, FORCEWAKE_ALL);
        intel_engine_pm_put(stream->engine);
  
@@@ -4163,7 -4223,7 +4163,7 @@@ static int read_properties_unlocked(str
         * C6 disable in BIOS. Fail if Media C6 is enabled on steppings where OAM
         * does not work as expected.
         */
 -      if (IS_MTL_MEDIA_STEP(props->engine->i915, STEP_A0, STEP_C0) &&
 +      if (IS_MEDIA_GT_IP_STEP(props->engine->gt, IP_VER(13, 0), STEP_A0, STEP_C0) &&
            props->engine->oa_group->type == TYPE_OAM &&
            intel_check_bios_c6_setup(&props->engine->gt->rc6)) {
                drm_dbg(&perf->i915->drm,
@@@ -4479,7 -4539,7 +4479,7 @@@ static bool xehp_is_valid_b_counter_add
  
  static bool gen12_is_valid_mux_addr(struct i915_perf *perf, u32 addr)
  {
 -      if (IS_METEORLAKE(perf->i915))
 +      if (GRAPHICS_VER_FULL(perf->i915) >= IP_VER(12, 70))
                return reg_in_range_table(addr, mtl_oa_mux_regs);
        else
                return reg_in_range_table(addr, gen12_oa_mux_regs);
@@@ -4836,7 -4896,6 +4836,6 @@@ static struct ctl_table oa_table[] = 
         .extra1 = SYSCTL_ZERO,
         .extra2 = &oa_sample_rate_hard_limit,
         },
-       {}
  };
  
  static u32 num_perf_groups_per_gt(struct intel_gt *gt)
@@@ -5046,7 -5105,6 +5045,7 @@@ static void i915_perf_init_info(struct 
                perf->gen8_valid_ctx_bit = BIT(16);
                break;
        case 12:
 +              perf->gen8_valid_ctx_bit = BIT(16);
                /*
                 * Calculate offset at runtime in oa_pin_context for gen12 and
                 * cache the value in perf->ctx_oactxctrl_offset.
@@@ -5273,9 -5331,16 +5272,9 @@@ int i915_perf_ioctl_version(struct drm_
         * C6 disable in BIOS. If Media C6 is enabled in BIOS, return version 6
         * to indicate that OA media is not supported.
         */
 -      if (IS_MTL_MEDIA_STEP(i915, STEP_A0, STEP_C0)) {
 -              struct intel_gt *gt;
 -              int i;
 -
 -              for_each_gt(gt, i915, i) {
 -                      if (gt->type == GT_MEDIA &&
 -                          intel_check_bios_c6_setup(&gt->rc6))
 -                              return 6;
 -              }
 -      }
 +      if (IS_MEDIA_GT_IP_STEP(i915->media_gt, IP_VER(13, 0), STEP_A0, STEP_C0) &&
 +          intel_check_bios_c6_setup(&i915->media_gt->rc6))
 +              return 6;
  
        return 7;
  }
diff --combined drivers/md/md.c
index 411121a72df99f6d5bde99a9b9ad35a448edf876,3bdff9e0318801755702e95a818bf0362601feff..4ee4593c874a769b96b36696aa50cbc806cb8385
@@@ -91,18 -91,6 +91,18 @@@ static void mddev_detach(struct mddev *
  static void export_rdev(struct md_rdev *rdev, struct mddev *mddev);
  static void md_wakeup_thread_directly(struct md_thread __rcu *thread);
  
 +enum md_ro_state {
 +      MD_RDWR,
 +      MD_RDONLY,
 +      MD_AUTO_READ,
 +      MD_MAX_STATE
 +};
 +
 +static bool md_is_rdwr(struct mddev *mddev)
 +{
 +      return (mddev->ro == MD_RDWR);
 +}
 +
  /*
   * Default number of read corrections we'll attempt on an rdev
   * before ejecting it from the array. We divide the read error
@@@ -218,7 -206,8 +218,7 @@@ static int rdev_need_serial(struct md_r
   * 1. rdev is the first device which return true from rdev_enable_serial.
   * 2. rdev is NULL, means we want to enable serialization for all rdevs.
   */
 -void mddev_create_serial_pool(struct mddev *mddev, struct md_rdev *rdev,
 -                            bool is_suspend)
 +void mddev_create_serial_pool(struct mddev *mddev, struct md_rdev *rdev)
  {
        int ret = 0;
  
            !test_bit(CollisionCheck, &rdev->flags))
                return;
  
 -      if (!is_suspend)
 -              mddev_suspend(mddev);
 -
        if (!rdev)
                ret = rdevs_init_serial(mddev);
        else
                ret = rdev_init_serial(rdev);
        if (ret)
 -              goto abort;
 +              return;
  
        if (mddev->serial_info_pool == NULL) {
                /*
                        pr_err("can't alloc memory pool for serialization\n");
                }
        }
 -
 -abort:
 -      if (!is_suspend)
 -              mddev_resume(mddev);
  }
  
  /*
   * 2. when bitmap is destroyed while policy is not enabled.
   * 3. for disable policy, the pool is destroyed only when no rdev needs it.
   */
 -void mddev_destroy_serial_pool(struct mddev *mddev, struct md_rdev *rdev,
 -                             bool is_suspend)
 +void mddev_destroy_serial_pool(struct mddev *mddev, struct md_rdev *rdev)
  {
        if (rdev && !test_bit(CollisionCheck, &rdev->flags))
                return;
                struct md_rdev *temp;
                int num = 0; /* used to track if other rdevs need the pool */
  
 -              if (!is_suspend)
 -                      mddev_suspend(mddev);
                rdev_for_each(temp, mddev) {
                        if (!rdev) {
                                if (!mddev->serialize_policy ||
                        mempool_destroy(mddev->serial_info_pool);
                        mddev->serial_info_pool = NULL;
                }
 -              if (!is_suspend)
 -                      mddev_resume(mddev);
        }
  }
  
@@@ -304,7 -305,6 +304,6 @@@ static struct ctl_table raid_table[] = 
                .mode           = S_IRUGO|S_IWUSR,
                .proc_handler   = proc_dointvec,
        },
-       { }
  };
  
  static int start_readonly;
@@@ -345,10 -345,6 +344,10 @@@ EXPORT_SYMBOL_GPL(md_new_event)
  static LIST_HEAD(all_mddevs);
  static DEFINE_SPINLOCK(all_mddevs_lock);
  
 +static bool is_md_suspended(struct mddev *mddev)
 +{
 +      return percpu_ref_is_dying(&mddev->active_io);
 +}
  /* Rather than calling directly into the personality make_request function,
   * IO requests come here first so that we can check if the device is
   * being suspended pending a reconfiguration.
@@@ -362,11 -358,11 +361,11 @@@ static bool is_suspended(struct mddev *
                return true;
        if (bio_data_dir(bio) != WRITE)
                return false;
 -      if (mddev->suspend_lo >= mddev->suspend_hi)
 +      if (READ_ONCE(mddev->suspend_lo) >= READ_ONCE(mddev->suspend_hi))
                return false;
 -      if (bio->bi_iter.bi_sector >= mddev->suspend_hi)
 +      if (bio->bi_iter.bi_sector >= READ_ONCE(mddev->suspend_hi))
                return false;
 -      if (bio_end_sector(bio) < mddev->suspend_lo)
 +      if (bio_end_sector(bio) < READ_ONCE(mddev->suspend_lo))
                return false;
        return true;
  }
@@@ -434,73 -430,42 +433,73 @@@ static void md_submit_bio(struct bio *b
        md_handle_request(mddev, bio);
  }
  
 -/* mddev_suspend makes sure no new requests are submitted
 - * to the device, and that any requests that have been submitted
 - * are completely handled.
 - * Once mddev_detach() is called and completes, the module will be
 - * completely unused.
 +/*
 + * Make sure no new requests are submitted to the device, and any requests that
 + * have been submitted are completely handled.
   */
 -void mddev_suspend(struct mddev *mddev)
 +int mddev_suspend(struct mddev *mddev, bool interruptible)
  {
 -      struct md_thread *thread = rcu_dereference_protected(mddev->thread,
 -                      lockdep_is_held(&mddev->reconfig_mutex));
 +      int err = 0;
  
 -      WARN_ON_ONCE(thread && current == thread->tsk);
 -      if (mddev->suspended++)
 -              return;
 -      wake_up(&mddev->sb_wait);
 -      set_bit(MD_ALLOW_SB_UPDATE, &mddev->flags);
 -      percpu_ref_kill(&mddev->active_io);
 +      /*
 +       * hold reconfig_mutex to wait for normal io will deadlock, because
 +       * other context can't update super_block, and normal io can rely on
 +       * updating super_block.
 +       */
 +      lockdep_assert_not_held(&mddev->reconfig_mutex);
  
 -      if (mddev->pers->prepare_suspend)
 -              mddev->pers->prepare_suspend(mddev);
 +      if (interruptible)
 +              err = mutex_lock_interruptible(&mddev->suspend_mutex);
 +      else
 +              mutex_lock(&mddev->suspend_mutex);
 +      if (err)
 +              return err;
  
 -      wait_event(mddev->sb_wait, percpu_ref_is_zero(&mddev->active_io));
 -      clear_bit_unlock(MD_ALLOW_SB_UPDATE, &mddev->flags);
 -      wait_event(mddev->sb_wait, !test_bit(MD_UPDATING_SB, &mddev->flags));
 +      if (mddev->suspended) {
 +              WRITE_ONCE(mddev->suspended, mddev->suspended + 1);
 +              mutex_unlock(&mddev->suspend_mutex);
 +              return 0;
 +      }
 +
 +      percpu_ref_kill(&mddev->active_io);
 +      if (interruptible)
 +              err = wait_event_interruptible(mddev->sb_wait,
 +                              percpu_ref_is_zero(&mddev->active_io));
 +      else
 +              wait_event(mddev->sb_wait,
 +                              percpu_ref_is_zero(&mddev->active_io));
 +      if (err) {
 +              percpu_ref_resurrect(&mddev->active_io);
 +              mutex_unlock(&mddev->suspend_mutex);
 +              return err;
 +      }
 +
 +      /*
 +       * For raid456, io might be waiting for reshape to make progress,
 +       * allow new reshape to start while waiting for io to be done to
 +       * prevent deadlock.
 +       */
 +      WRITE_ONCE(mddev->suspended, mddev->suspended + 1);
  
        del_timer_sync(&mddev->safemode_timer);
        /* restrict memory reclaim I/O during raid array is suspend */
        mddev->noio_flag = memalloc_noio_save();
 +
 +      mutex_unlock(&mddev->suspend_mutex);
 +      return 0;
  }
  EXPORT_SYMBOL_GPL(mddev_suspend);
  
  void mddev_resume(struct mddev *mddev)
  {
 -      lockdep_assert_held(&mddev->reconfig_mutex);
 -      if (--mddev->suspended)
 +      lockdep_assert_not_held(&mddev->reconfig_mutex);
 +
 +      mutex_lock(&mddev->suspend_mutex);
 +      WRITE_ONCE(mddev->suspended, mddev->suspended - 1);
 +      if (mddev->suspended) {
 +              mutex_unlock(&mddev->suspend_mutex);
                return;
 +      }
  
        /* entred the memalloc scope from mddev_suspend() */
        memalloc_noio_restore(mddev->noio_flag);
        set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
        md_wakeup_thread(mddev->thread);
        md_wakeup_thread(mddev->sync_thread); /* possibly kick off a reshape */
 +
 +      mutex_unlock(&mddev->suspend_mutex);
  }
  EXPORT_SYMBOL_GPL(mddev_resume);
  
@@@ -652,63 -615,34 +651,63 @@@ static inline struct mddev *mddev_get(s
  
  static void mddev_delayed_delete(struct work_struct *ws);
  
 +static void __mddev_put(struct mddev *mddev)
 +{
 +      if (mddev->raid_disks || !list_empty(&mddev->disks) ||
 +          mddev->ctime || mddev->hold_active)
 +              return;
 +
 +      /* Array is not configured at all, and not held active, so destroy it */
 +      set_bit(MD_DELETED, &mddev->flags);
 +
 +      /*
 +       * Call queue_work inside the spinlock so that flush_workqueue() after
 +       * mddev_find will succeed in waiting for the work to be done.
 +       */
 +      queue_work(md_misc_wq, &mddev->del_work);
 +}
 +
  void mddev_put(struct mddev *mddev)
  {
        if (!atomic_dec_and_lock(&mddev->active, &all_mddevs_lock))
                return;
 -      if (!mddev->raid_disks && list_empty(&mddev->disks) &&
 -          mddev->ctime == 0 && !mddev->hold_active) {
 -              /* Array is not configured at all, and not held active,
 -               * so destroy it */
 -              set_bit(MD_DELETED, &mddev->flags);
  
 -              /*
 -               * Call queue_work inside the spinlock so that
 -               * flush_workqueue() after mddev_find will succeed in waiting
 -               * for the work to be done.
 -               */
 -              INIT_WORK(&mddev->del_work, mddev_delayed_delete);
 -              queue_work(md_misc_wq, &mddev->del_work);
 -      }
 +      __mddev_put(mddev);
        spin_unlock(&all_mddevs_lock);
  }
  
  static void md_safemode_timeout(struct timer_list *t);
 +static void md_start_sync(struct work_struct *ws);
 +
 +static void active_io_release(struct percpu_ref *ref)
 +{
 +      struct mddev *mddev = container_of(ref, struct mddev, active_io);
 +
 +      wake_up(&mddev->sb_wait);
 +}
 +
 +static void no_op(struct percpu_ref *r) {}
  
 -void mddev_init(struct mddev *mddev)
 +int mddev_init(struct mddev *mddev)
  {
 +
 +      if (percpu_ref_init(&mddev->active_io, active_io_release,
 +                          PERCPU_REF_ALLOW_REINIT, GFP_KERNEL))
 +              return -ENOMEM;
 +
 +      if (percpu_ref_init(&mddev->writes_pending, no_op,
 +                          PERCPU_REF_ALLOW_REINIT, GFP_KERNEL)) {
 +              percpu_ref_exit(&mddev->active_io);
 +              return -ENOMEM;
 +      }
 +
 +      /* We want to start with the refcount at zero */
 +      percpu_ref_put(&mddev->writes_pending);
 +
        mutex_init(&mddev->open_mutex);
        mutex_init(&mddev->reconfig_mutex);
        mutex_init(&mddev->sync_mutex);
 +      mutex_init(&mddev->suspend_mutex);
        mutex_init(&mddev->bitmap_info.mutex);
        INIT_LIST_HEAD(&mddev->disks);
        INIT_LIST_HEAD(&mddev->all_mddevs);
        mddev->resync_min = 0;
        mddev->resync_max = MaxSector;
        mddev->level = LEVEL_NONE;
 +
 +      INIT_WORK(&mddev->sync_work, md_start_sync);
 +      INIT_WORK(&mddev->del_work, mddev_delayed_delete);
 +
 +      return 0;
  }
  EXPORT_SYMBOL_GPL(mddev_init);
  
 +void mddev_destroy(struct mddev *mddev)
 +{
 +      percpu_ref_exit(&mddev->active_io);
 +      percpu_ref_exit(&mddev->writes_pending);
 +}
 +EXPORT_SYMBOL_GPL(mddev_destroy);
 +
  static struct mddev *mddev_find_locked(dev_t unit)
  {
        struct mddev *mddev;
@@@ -785,16 -707,13 +784,16 @@@ static struct mddev *mddev_alloc(dev_t 
        new = kzalloc(sizeof(*new), GFP_KERNEL);
        if (!new)
                return ERR_PTR(-ENOMEM);
 -      mddev_init(new);
 +
 +      error = mddev_init(new);
 +      if (error)
 +              goto out_free_new;
  
        spin_lock(&all_mddevs_lock);
        if (unit) {
                error = -EEXIST;
                if (mddev_find_locked(unit))
 -                      goto out_free_new;
 +                      goto out_destroy_new;
                new->unit = unit;
                if (MAJOR(unit) == MD_MAJOR)
                        new->md_minor = MINOR(unit);
                error = -ENODEV;
                new->unit = mddev_alloc_unit();
                if (!new->unit)
 -                      goto out_free_new;
 +                      goto out_destroy_new;
                new->md_minor = MINOR(new->unit);
                new->hold_active = UNTIL_STOP;
        }
        list_add(&new->all_mddevs, &all_mddevs);
        spin_unlock(&all_mddevs_lock);
        return new;
 -out_free_new:
 +
 +out_destroy_new:
        spin_unlock(&all_mddevs_lock);
 +      mddev_destroy(new);
 +out_free_new:
        kfree(new);
        return ERR_PTR(error);
  }
@@@ -828,7 -744,6 +827,7 @@@ static void mddev_free(struct mddev *md
        list_del(&mddev->all_mddevs);
        spin_unlock(&all_mddevs_lock);
  
 +      mddev_destroy(mddev);
        kfree(mddev);
  }
  
@@@ -2496,7 -2411,7 +2495,7 @@@ static int bind_rdev_to_array(struct md
        pr_debug("md: bind<%s>\n", b);
  
        if (mddev->raid_disks)
 -              mddev_create_serial_pool(mddev, rdev, false);
 +              mddev_create_serial_pool(mddev, rdev);
  
        if ((err = kobject_add(&rdev->kobj, &mddev->kobj, "dev-%s", b)))
                goto fail;
@@@ -2536,7 -2451,8 +2535,7 @@@ static void export_rdev(struct md_rdev 
        if (test_bit(AutoDetected, &rdev->flags))
                md_autodetect_dev(rdev->bdev->bd_dev);
  #endif
 -      blkdev_put(rdev->bdev,
 -                 test_bit(Holder, &rdev->flags) ? rdev : &claim_rdev);
 +      bdev_release(rdev->bdev_handle);
        rdev->bdev = NULL;
        kobject_put(&rdev->kobj);
  }
@@@ -2548,7 -2464,7 +2547,7 @@@ static void md_kick_rdev_from_array(str
        bd_unlink_disk_holder(rdev->bdev, rdev->mddev->gendisk);
        list_del_rcu(&rdev->same_set);
        pr_debug("md: unbind<%pg>\n", rdev->bdev);
 -      mddev_destroy_serial_pool(rdev->mddev, rdev, false);
 +      mddev_destroy_serial_pool(rdev->mddev, rdev);
        rdev->mddev = NULL;
        sysfs_remove_link(&rdev->kobj, "block");
        sysfs_put(rdev->sysfs_state);
@@@ -2878,7 -2794,11 +2877,7 @@@ static int add_bound_rdev(struct md_rde
                 */
                super_types[mddev->major_version].
                        validate_super(mddev, rdev);
 -              if (add_journal)
 -                      mddev_suspend(mddev);
                err = mddev->pers->hot_add_disk(mddev, rdev);
 -              if (add_journal)
 -                      mddev_resume(mddev);
                if (err) {
                        md_kick_rdev_from_array(rdev);
                        return err;
@@@ -3015,11 -2935,11 +3014,11 @@@ state_store(struct md_rdev *rdev, cons
                }
        } else if (cmd_match(buf, "writemostly")) {
                set_bit(WriteMostly, &rdev->flags);
 -              mddev_create_serial_pool(rdev->mddev, rdev, false);
 +              mddev_create_serial_pool(rdev->mddev, rdev);
                need_update_sb = true;
                err = 0;
        } else if (cmd_match(buf, "-writemostly")) {
 -              mddev_destroy_serial_pool(rdev->mddev, rdev, false);
 +              mddev_destroy_serial_pool(rdev->mddev, rdev);
                clear_bit(WriteMostly, &rdev->flags);
                need_update_sb = true;
                err = 0;
@@@ -3631,7 -3551,6 +3630,7 @@@ rdev_attr_store(struct kobject *kobj, s
        struct rdev_sysfs_entry *entry = container_of(attr, struct rdev_sysfs_entry, attr);
        struct md_rdev *rdev = container_of(kobj, struct md_rdev, kobj);
        struct kernfs_node *kn = NULL;
 +      bool suspend = false;
        ssize_t rv;
        struct mddev *mddev = rdev->mddev;
  
                return -EIO;
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
 +      if (!mddev)
 +              return -ENODEV;
  
 -      if (entry->store == state_store && cmd_match(page, "remove"))
 -              kn = sysfs_break_active_protection(kobj, attr);
 +      if (entry->store == state_store) {
 +              if (cmd_match(page, "remove"))
 +                      kn = sysfs_break_active_protection(kobj, attr);
 +              if (cmd_match(page, "remove") || cmd_match(page, "re-add") ||
 +                  cmd_match(page, "writemostly") ||
 +                  cmd_match(page, "-writemostly"))
 +                      suspend = true;
 +      }
  
 -      rv = mddev ? mddev_lock(mddev) : -ENODEV;
 +      rv = suspend ? mddev_suspend_and_lock(mddev) : mddev_lock(mddev);
        if (!rv) {
                if (rdev->mddev == NULL)
                        rv = -ENODEV;
                else
                        rv = entry->store(rdev, page, length);
 -              mddev_unlock(mddev);
 +              suspend ? mddev_unlock_and_resume(mddev) : mddev_unlock(mddev);
        }
  
        if (kn)
@@@ -3721,6 -3632,7 +3720,6 @@@ EXPORT_SYMBOL_GPL(md_rdev_init)
  static struct md_rdev *md_import_device(dev_t newdev, int super_format, int super_minor)
  {
        struct md_rdev *rdev;
 -      struct md_rdev *holder;
        sector_t size;
        int err;
  
        if (err)
                goto out_clear_rdev;
  
 -      if (super_format == -2) {
 -              holder = &claim_rdev;
 -      } else {
 -              holder = rdev;
 -              set_bit(Holder, &rdev->flags);
 -      }
 -
 -      rdev->bdev = blkdev_get_by_dev(newdev, BLK_OPEN_READ | BLK_OPEN_WRITE,
 -                                     holder, NULL);
 -      if (IS_ERR(rdev->bdev)) {
 +      rdev->bdev_handle = bdev_open_by_dev(newdev,
 +                      BLK_OPEN_READ | BLK_OPEN_WRITE,
 +                      super_format == -2 ? &claim_rdev : rdev, NULL);
 +      if (IS_ERR(rdev->bdev_handle)) {
                pr_warn("md: could not open device unknown-block(%u,%u).\n",
                        MAJOR(newdev), MINOR(newdev));
 -              err = PTR_ERR(rdev->bdev);
 +              err = PTR_ERR(rdev->bdev_handle);
                goto out_clear_rdev;
        }
 +      rdev->bdev = rdev->bdev_handle->bdev;
  
        kobject_init(&rdev->kobj, &rdev_ktype);
  
        return rdev;
  
  out_blkdev_put:
 -      blkdev_put(rdev->bdev, holder);
 +      bdev_release(rdev->bdev_handle);
  out_clear_rdev:
        md_rdev_clear(rdev);
  out_free_rdev:
@@@ -3956,12 -3873,12 +3955,12 @@@ level_store(struct mddev *mddev, const 
        if (slen == 0 || slen >= sizeof(clevel))
                return -EINVAL;
  
 -      rv = mddev_lock(mddev);
 +      rv = mddev_suspend_and_lock(mddev);
        if (rv)
                return rv;
  
        if (mddev->pers == NULL) {
 -              strncpy(mddev->clevel, buf, slen);
 +              memcpy(mddev->clevel, buf, slen);
                if (mddev->clevel[slen-1] == '\n')
                        slen--;
                mddev->clevel[slen] = 0;
        }
  
        /* Now find the new personality */
 -      strncpy(clevel, buf, slen);
 +      memcpy(clevel, buf, slen);
        if (clevel[slen-1] == '\n')
                slen--;
        clevel[slen] = 0;
        }
  
        /* Looks like we have a winner */
 -      mddev_suspend(mddev);
        mddev_detach(mddev);
  
        spin_lock(&mddev->lock);
        blk_set_stacking_limits(&mddev->queue->limits);
        pers->run(mddev);
        set_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags);
 -      mddev_resume(mddev);
        if (!mddev->thread)
                md_update_sb(mddev, 1);
        sysfs_notify_dirent_safe(mddev->sysfs_level);
        md_new_event();
        rv = len;
  out_unlock:
 -      mddev_unlock(mddev);
 +      mddev_unlock_and_resume(mddev);
        return rv;
  }
  
@@@ -4448,18 -4367,6 +4447,18 @@@ array_state_store(struct mddev *mddev, 
        int err = 0;
        enum array_state st = match_word(buf, array_states);
  
 +      /* No lock dependent actions */
 +      switch (st) {
 +      case suspended:         /* not supported yet */
 +      case write_pending:     /* cannot be set */
 +      case active_idle:       /* cannot be set */
 +      case broken:            /* cannot be set */
 +      case bad_word:
 +              return -EINVAL;
 +      default:
 +              break;
 +      }
 +
        if (mddev->pers && (st == active || st == clean) &&
            mddev->ro != MD_RDONLY) {
                /* don't take reconfig_mutex when toggling between
        err = mddev_lock(mddev);
        if (err)
                return err;
 -      err = -EINVAL;
 -      switch(st) {
 -      case bad_word:
 -              break;
 -      case clear:
 -              /* stopping an active array */
 -              err = do_md_stop(mddev, 0, NULL);
 -              break;
 +
 +      switch (st) {
        case inactive:
 -              /* stopping an active array */
 +              /* stop an active array, return 0 otherwise */
                if (mddev->pers)
                        err = do_md_stop(mddev, 2, NULL);
 -              else
 -                      err = 0; /* already inactive */
                break;
 -      case suspended:
 -              break; /* not supported yet */
 +      case clear:
 +              err = do_md_stop(mddev, 0, NULL);
 +              break;
        case readonly:
                if (mddev->pers)
                        err = md_set_readonly(mddev, NULL);
                        err = do_md_run(mddev);
                }
                break;
 -      case write_pending:
 -      case active_idle:
 -      case broken:
 -              /* these cannot be set */
 +      default:
 +              err = -EINVAL;
                break;
        }
  
@@@ -4618,7 -4534,7 +4617,7 @@@ new_dev_store(struct mddev *mddev, cons
            minor != MINOR(dev))
                return -EOVERFLOW;
  
 -      err = mddev_lock(mddev);
 +      err = mddev_suspend_and_lock(mddev);
        if (err)
                return err;
        if (mddev->persistent) {
                rdev = md_import_device(dev, -1, -1);
  
        if (IS_ERR(rdev)) {
 -              mddev_unlock(mddev);
 +              mddev_unlock_and_resume(mddev);
                return PTR_ERR(rdev);
        }
        err = bind_rdev_to_array(rdev, mddev);
   out:
        if (err)
                export_rdev(rdev, mddev);
 -      mddev_unlock(mddev);
 +      mddev_unlock_and_resume(mddev);
        if (!err)
                md_new_event();
        return err ? err : len;
@@@ -4781,7 -4697,7 +4780,7 @@@ metadata_store(struct mddev *mddev, con
                size_t namelen = len-9;
                if (namelen >= sizeof(mddev->metadata_type))
                        namelen = sizeof(mddev->metadata_type)-1;
 -              strncpy(mddev->metadata_type, buf+9, namelen);
 +              memcpy(mddev->metadata_type, buf+9, namelen);
                mddev->metadata_type[namelen] = 0;
                if (namelen && mddev->metadata_type[namelen-1] == '\n')
                        mddev->metadata_type[--namelen] = 0;
@@@ -4955,7 -4871,6 +4954,7 @@@ action_store(struct mddev *mddev, cons
                /* A write to sync_action is enough to justify
                 * canceling read-auto mode
                 */
 +              flush_work(&mddev->sync_work);
                mddev->ro = MD_RDWR;
                md_wakeup_thread(mddev->sync_thread);
        }
@@@ -5212,8 -5127,7 +5211,8 @@@ __ATTR(sync_max, S_IRUGO|S_IWUSR, max_s
  static ssize_t
  suspend_lo_show(struct mddev *mddev, char *page)
  {
 -      return sprintf(page, "%llu\n", (unsigned long long)mddev->suspend_lo);
 +      return sprintf(page, "%llu\n",
 +                     (unsigned long long)READ_ONCE(mddev->suspend_lo));
  }
  
  static ssize_t
@@@ -5228,14 -5142,21 +5227,14 @@@ suspend_lo_store(struct mddev *mddev, c
        if (new != (sector_t)new)
                return -EINVAL;
  
 -      err = mddev_lock(mddev);
 +      err = mddev_suspend(mddev, true);
        if (err)
                return err;
 -      err = -EINVAL;
 -      if (mddev->pers == NULL ||
 -          mddev->pers->quiesce == NULL)
 -              goto unlock;
 -      mddev_suspend(mddev);
 -      mddev->suspend_lo = new;
 +
 +      WRITE_ONCE(mddev->suspend_lo, new);
        mddev_resume(mddev);
  
 -      err = 0;
 -unlock:
 -      mddev_unlock(mddev);
 -      return err ?: len;
 +      return len;
  }
  static struct md_sysfs_entry md_suspend_lo =
  __ATTR(suspend_lo, S_IRUGO|S_IWUSR, suspend_lo_show, suspend_lo_store);
  static ssize_t
  suspend_hi_show(struct mddev *mddev, char *page)
  {
 -      return sprintf(page, "%llu\n", (unsigned long long)mddev->suspend_hi);
 +      return sprintf(page, "%llu\n",
 +                     (unsigned long long)READ_ONCE(mddev->suspend_hi));
  }
  
  static ssize_t
@@@ -5259,14 -5179,21 +5258,14 @@@ suspend_hi_store(struct mddev *mddev, c
        if (new != (sector_t)new)
                return -EINVAL;
  
 -      err = mddev_lock(mddev);
 +      err = mddev_suspend(mddev, true);
        if (err)
                return err;
 -      err = -EINVAL;
 -      if (mddev->pers == NULL)
 -              goto unlock;
  
 -      mddev_suspend(mddev);
 -      mddev->suspend_hi = new;
 +      WRITE_ONCE(mddev->suspend_hi, new);
        mddev_resume(mddev);
  
 -      err = 0;
 -unlock:
 -      mddev_unlock(mddev);
 -      return err ?: len;
 +      return len;
  }
  static struct md_sysfs_entry md_suspend_hi =
  __ATTR(suspend_hi, S_IRUGO|S_IWUSR, suspend_hi_show, suspend_hi_store);
@@@ -5513,7 -5440,7 +5512,7 @@@ serialize_policy_store(struct mddev *md
        if (value == mddev->serialize_policy)
                return len;
  
 -      err = mddev_lock(mddev);
 +      err = mddev_suspend_and_lock(mddev);
        if (err)
                return err;
        if (mddev->pers == NULL || (mddev->pers->level != 1)) {
                goto unlock;
        }
  
 -      mddev_suspend(mddev);
        if (value)
 -              mddev_create_serial_pool(mddev, NULL, true);
 +              mddev_create_serial_pool(mddev, NULL);
        else
 -              mddev_destroy_serial_pool(mddev, NULL, true);
 +              mddev_destroy_serial_pool(mddev, NULL);
        mddev->serialize_policy = value;
 -      mddev_resume(mddev);
  unlock:
 -      mddev_unlock(mddev);
 +      mddev_unlock_and_resume(mddev);
        return err ?: len;
  }
  
@@@ -5667,6 -5596,21 +5666,6 @@@ static void mddev_delayed_delete(struc
        kobject_put(&mddev->kobj);
  }
  
 -static void no_op(struct percpu_ref *r) {}
 -
 -int mddev_init_writes_pending(struct mddev *mddev)
 -{
 -      if (mddev->writes_pending.percpu_count_ptr)
 -              return 0;
 -      if (percpu_ref_init(&mddev->writes_pending, no_op,
 -                          PERCPU_REF_ALLOW_REINIT, GFP_KERNEL) < 0)
 -              return -ENOMEM;
 -      /* We want to start with the refcount at zero */
 -      percpu_ref_put(&mddev->writes_pending);
 -      return 0;
 -}
 -EXPORT_SYMBOL_GPL(mddev_init_writes_pending);
 -
  struct mddev *md_alloc(dev_t dev, char *name)
  {
        /*
@@@ -5838,6 -5782,12 +5837,6 @@@ static void md_safemode_timeout(struct 
  }
  
  static int start_dirty_degraded;
 -static void active_io_release(struct percpu_ref *ref)
 -{
 -      struct mddev *mddev = container_of(ref, struct mddev, active_io);
 -
 -      wake_up(&mddev->sb_wait);
 -}
  
  int md_run(struct mddev *mddev)
  {
                nowait = nowait && bdev_nowait(rdev->bdev);
        }
  
 -      err = percpu_ref_init(&mddev->active_io, active_io_release,
 -                              PERCPU_REF_ALLOW_REINIT, GFP_KERNEL);
 -      if (err)
 -              return err;
 -
        if (!bioset_initialized(&mddev->bio_set)) {
                err = bioset_init(&mddev->bio_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS);
                if (err)
 -                      goto exit_active_io;
 +                      return err;
        }
        if (!bioset_initialized(&mddev->sync_set)) {
                err = bioset_init(&mddev->sync_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS);
@@@ -6118,6 -6073,8 +6117,6 @@@ exit_sync_set
        bioset_exit(&mddev->sync_set);
  exit_bio_set:
        bioset_exit(&mddev->bio_set);
 -exit_active_io:
 -      percpu_ref_exit(&mddev->active_io);
        return err;
  }
  EXPORT_SYMBOL_GPL(md_run);
@@@ -6291,7 -6248,7 +6290,7 @@@ static void __md_stop_writes(struct mdd
        }
        /* disable policy to guarantee rdevs free resources for serialization */
        mddev->serialize_policy = 0;
 -      mddev_destroy_serial_pool(mddev, NULL, true);
 +      mddev_destroy_serial_pool(mddev, NULL);
  }
  
  void md_stop_writes(struct mddev *mddev)
@@@ -6333,6 -6290,7 +6332,6 @@@ static void __md_stop(struct mddev *mdd
        module_put(pers->owner);
        clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
  
 -      percpu_ref_exit(&mddev->active_io);
        bioset_exit(&mddev->bio_set);
        bioset_exit(&mddev->sync_set);
        bioset_exit(&mddev->io_clone_set);
@@@ -6347,6 -6305,7 +6346,6 @@@ void md_stop(struct mddev *mddev
         */
        __md_stop_writes(mddev);
        __md_stop(mddev);
 -      percpu_ref_exit(&mddev->writes_pending);
  }
  
  EXPORT_SYMBOL_GPL(md_stop);
@@@ -6583,13 -6542,13 +6582,13 @@@ static void autorun_devices(int part
                if (IS_ERR(mddev))
                        break;
  
 -              if (mddev_lock(mddev))
 +              if (mddev_suspend_and_lock(mddev))
                        pr_warn("md: %s locked, cannot run\n", mdname(mddev));
                else if (mddev->raid_disks || mddev->major_version
                         || !list_empty(&mddev->disks)) {
                        pr_warn("md: %s already running, cannot run %pg\n",
                                mdname(mddev), rdev0->bdev);
 -                      mddev_unlock(mddev);
 +                      mddev_unlock_and_resume(mddev);
                } else {
                        pr_debug("md: created %s\n", mdname(mddev));
                        mddev->persistent = 1;
                                        export_rdev(rdev, mddev);
                        }
                        autorun_array(mddev);
 -                      mddev_unlock(mddev);
 +                      mddev_unlock_and_resume(mddev);
                }
                /* on success, candidates will be empty, on error
                 * it won't...
@@@ -7149,6 -7108,7 +7148,6 @@@ static int set_bitmap_file(struct mdde
                        struct bitmap *bitmap;
  
                        bitmap = md_bitmap_create(mddev, -1);
 -                      mddev_suspend(mddev);
                        if (!IS_ERR(bitmap)) {
                                mddev->bitmap = bitmap;
                                err = md_bitmap_load(mddev);
                                md_bitmap_destroy(mddev);
                                fd = -1;
                        }
 -                      mddev_resume(mddev);
                } else if (fd < 0) {
 -                      mddev_suspend(mddev);
                        md_bitmap_destroy(mddev);
 -                      mddev_resume(mddev);
                }
        }
        if (fd < 0) {
@@@ -7448,6 -7411,7 +7447,6 @@@ static int update_array_info(struct mdd
                        mddev->bitmap_info.space =
                                mddev->bitmap_info.default_space;
                        bitmap = md_bitmap_create(mddev, -1);
 -                      mddev_suspend(mddev);
                        if (!IS_ERR(bitmap)) {
                                mddev->bitmap = bitmap;
                                rv = md_bitmap_load(mddev);
                                rv = PTR_ERR(bitmap);
                        if (rv)
                                md_bitmap_destroy(mddev);
 -                      mddev_resume(mddev);
                } else {
                        /* remove the bitmap */
                        if (!mddev->bitmap) {
                                module_put(md_cluster_mod);
                                mddev->safemode_delay = DEFAULT_SAFEMODE_DELAY;
                        }
 -                      mddev_suspend(mddev);
                        md_bitmap_destroy(mddev);
 -                      mddev_resume(mddev);
                        mddev->bitmap_info.offset = 0;
                }
        }
@@@ -7550,20 -7517,6 +7549,20 @@@ static inline bool md_ioctl_valid(unsig
        }
  }
  
 +static bool md_ioctl_need_suspend(unsigned int cmd)
 +{
 +      switch (cmd) {
 +      case ADD_NEW_DISK:
 +      case HOT_ADD_DISK:
 +      case HOT_REMOVE_DISK:
 +      case SET_BITMAP_FILE:
 +      case SET_ARRAY_INFO:
 +              return true;
 +      default:
 +              return false;
 +      }
 +}
 +
  static int __md_set_array_info(struct mddev *mddev, void __user *argp)
  {
        mdu_array_info_t info;
@@@ -7692,12 -7645,7 +7691,12 @@@ static int md_ioctl(struct block_devic
                mutex_unlock(&mddev->open_mutex);
                sync_blockdev(bdev);
        }
 -      err = mddev_lock(mddev);
 +
 +      if (!md_is_rdwr(mddev))
 +              flush_work(&mddev->sync_work);
 +
 +      err = md_ioctl_need_suspend(cmd) ? mddev_suspend_and_lock(mddev) :
 +                                         mddev_lock(mddev);
        if (err) {
                pr_debug("md: ioctl lock interrupted, reason %d, cmd %d\n",
                         err, cmd);
@@@ -7825,10 -7773,7 +7824,10 @@@ unlock
        if (mddev->hold_active == UNTIL_IOCTL &&
            err != -EINVAL)
                mddev->hold_active = 0;
 -      mddev_unlock(mddev);
 +
 +      md_ioctl_need_suspend(cmd) ? mddev_unlock_and_resume(mddev) :
 +                                   mddev_unlock(mddev);
 +
  out:
        if(did_set_md_closing)
                clear_bit(MD_CLOSING, &mddev->flags);
@@@ -7940,6 -7885,7 +7939,6 @@@ static void md_free_disk(struct gendis
  {
        struct mddev *mddev = disk->private_data;
  
 -      percpu_ref_exit(&mddev->writes_pending);
        mddev_free(mddev);
  }
  
@@@ -8255,46 -8201,105 +8254,46 @@@ static int status_resync(struct seq_fil
  }
  
  static void *md_seq_start(struct seq_file *seq, loff_t *pos)
 +      __acquires(&all_mddevs_lock)
  {
 -      struct list_head *tmp;
 -      loff_t l = *pos;
 -      struct mddev *mddev;
 +      struct md_personality *pers;
  
 -      if (l == 0x10000) {
 -              ++*pos;
 -              return (void *)2;
 -      }
 -      if (l > 0x10000)
 -              return NULL;
 -      if (!l--)
 -              /* header */
 -              return (void*)1;
 +      seq_puts(seq, "Personalities : ");
 +      spin_lock(&pers_lock);
 +      list_for_each_entry(pers, &pers_list, list)
 +              seq_printf(seq, "[%s] ", pers->name);
 +
 +      spin_unlock(&pers_lock);
 +      seq_puts(seq, "\n");
 +      seq->poll_event = atomic_read(&md_event_count);
  
        spin_lock(&all_mddevs_lock);
 -      list_for_each(tmp,&all_mddevs)
 -              if (!l--) {
 -                      mddev = list_entry(tmp, struct mddev, all_mddevs);
 -                      if (!mddev_get(mddev))
 -                              continue;
 -                      spin_unlock(&all_mddevs_lock);
 -                      return mddev;
 -              }
 -      spin_unlock(&all_mddevs_lock);
 -      if (!l--)
 -              return (void*)2;/* tail */
 -      return NULL;
 +
 +      return seq_list_start(&all_mddevs, *pos);
  }
  
  static void *md_seq_next(struct seq_file *seq, void *v, loff_t *pos)
  {
 -      struct list_head *tmp;
 -      struct mddev *next_mddev, *mddev = v;
 -      struct mddev *to_put = NULL;
 -
 -      ++*pos;
 -      if (v == (void*)2)
 -              return NULL;
 -
 -      spin_lock(&all_mddevs_lock);
 -      if (v == (void*)1) {
 -              tmp = all_mddevs.next;
 -      } else {
 -              to_put = mddev;
 -              tmp = mddev->all_mddevs.next;
 -      }
 -
 -      for (;;) {
 -              if (tmp == &all_mddevs) {
 -                      next_mddev = (void*)2;
 -                      *pos = 0x10000;
 -                      break;
 -              }
 -              next_mddev = list_entry(tmp, struct mddev, all_mddevs);
 -              if (mddev_get(next_mddev))
 -                      break;
 -              mddev = next_mddev;
 -              tmp = mddev->all_mddevs.next;
 -      }
 -      spin_unlock(&all_mddevs_lock);
 -
 -      if (to_put)
 -              mddev_put(to_put);
 -      return next_mddev;
 -
 +      return seq_list_next(v, &all_mddevs, pos);
  }
  
  static void md_seq_stop(struct seq_file *seq, void *v)
 +      __releases(&all_mddevs_lock)
  {
 -      struct mddev *mddev = v;
 -
 -      if (mddev && v != (void*)1 && v != (void*)2)
 -              mddev_put(mddev);
 +      status_unused(seq);
 +      spin_unlock(&all_mddevs_lock);
  }
  
  static int md_seq_show(struct seq_file *seq, void *v)
  {
 -      struct mddev *mddev = v;
 +      struct mddev *mddev = list_entry(v, struct mddev, all_mddevs);
        sector_t sectors;
        struct md_rdev *rdev;
  
 -      if (v == (void*)1) {
 -              struct md_personality *pers;
 -              seq_printf(seq, "Personalities : ");
 -              spin_lock(&pers_lock);
 -              list_for_each_entry(pers, &pers_list, list)
 -                      seq_printf(seq, "[%s] ", pers->name);
 -
 -              spin_unlock(&pers_lock);
 -              seq_printf(seq, "\n");
 -              seq->poll_event = atomic_read(&md_event_count);
 -              return 0;
 -      }
 -      if (v == (void*)2) {
 -              status_unused(seq);
 +      if (!mddev_get(mddev))
                return 0;
 -      }
  
 +      spin_unlock(&all_mddevs_lock);
        spin_lock(&mddev->lock);
        if (mddev->pers || mddev->raid_disks || !list_empty(&mddev->disks)) {
                seq_printf(seq, "%s : %sactive", mdname(mddev),
                seq_printf(seq, "\n");
        }
        spin_unlock(&mddev->lock);
 +      spin_lock(&all_mddevs_lock);
 +      if (atomic_dec_and_test(&mddev->active))
 +              __mddev_put(mddev);
  
        return 0;
  }
@@@ -8567,7 -8569,6 +8566,7 @@@ bool md_write_start(struct mddev *mddev
        BUG_ON(mddev->ro == MD_RDONLY);
        if (mddev->ro == MD_AUTO_READ) {
                /* need to switch to read/write */
 +              flush_work(&mddev->sync_work);
                mddev->ro = MD_RDWR;
                set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
                md_wakeup_thread(mddev->thread);
@@@ -9153,90 -9154,12 +9152,90 @@@ void md_do_sync(struct md_thread *threa
        spin_unlock(&mddev->lock);
  
        wake_up(&resync_wait);
 -      wake_up(&mddev->sb_wait);
        md_wakeup_thread(mddev->thread);
        return;
  }
  EXPORT_SYMBOL_GPL(md_do_sync);
  
 +static bool rdev_removeable(struct md_rdev *rdev)
 +{
 +      /* rdev is not used. */
 +      if (rdev->raid_disk < 0)
 +              return false;
 +
 +      /* There are still inflight io, don't remove this rdev. */
 +      if (atomic_read(&rdev->nr_pending))
 +              return false;
 +
 +      /*
 +       * An error occurred but has not yet been acknowledged by the metadata
 +       * handler, don't remove this rdev.
 +       */
 +      if (test_bit(Blocked, &rdev->flags))
 +              return false;
 +
 +      /* Fautly rdev is not used, it's safe to remove it. */
 +      if (test_bit(Faulty, &rdev->flags))
 +              return true;
 +
 +      /* Journal disk can only be removed if it's faulty. */
 +      if (test_bit(Journal, &rdev->flags))
 +              return false;
 +
 +      /*
 +       * 'In_sync' is cleared while 'raid_disk' is valid, which means
 +       * replacement has just become active from pers->spare_active(), and
 +       * then pers->hot_remove_disk() will replace this rdev with replacement.
 +       */
 +      if (!test_bit(In_sync, &rdev->flags))
 +              return true;
 +
 +      return false;
 +}
 +
 +static bool rdev_is_spare(struct md_rdev *rdev)
 +{
 +      return !test_bit(Candidate, &rdev->flags) && rdev->raid_disk >= 0 &&
 +             !test_bit(In_sync, &rdev->flags) &&
 +             !test_bit(Journal, &rdev->flags) &&
 +             !test_bit(Faulty, &rdev->flags);
 +}
 +
 +static bool rdev_addable(struct md_rdev *rdev)
 +{
 +      /* rdev is already used, don't add it again. */
 +      if (test_bit(Candidate, &rdev->flags) || rdev->raid_disk >= 0 ||
 +          test_bit(Faulty, &rdev->flags))
 +              return false;
 +
 +      /* Allow to add journal disk. */
 +      if (test_bit(Journal, &rdev->flags))
 +              return true;
 +
 +      /* Allow to add if array is read-write. */
 +      if (md_is_rdwr(rdev->mddev))
 +              return true;
 +
 +      /*
 +       * For read-only array, only allow to readd a rdev. And if bitmap is
 +       * used, don't allow to readd a rdev that is too old.
 +       */
 +      if (rdev->saved_raid_disk >= 0 && !test_bit(Bitmap_sync, &rdev->flags))
 +              return true;
 +
 +      return false;
 +}
 +
 +static bool md_spares_need_change(struct mddev *mddev)
 +{
 +      struct md_rdev *rdev;
 +
 +      rdev_for_each(rdev, mddev)
 +              if (rdev_removeable(rdev) || rdev_addable(rdev))
 +                      return true;
 +      return false;
 +}
 +
  static int remove_and_add_spares(struct mddev *mddev,
                                 struct md_rdev *this)
  {
                synchronize_rcu();
        rdev_for_each(rdev, mddev) {
                if ((this == NULL || rdev == this) &&
 -                  rdev->raid_disk >= 0 &&
 -                  !test_bit(Blocked, &rdev->flags) &&
 -                  ((test_bit(RemoveSynchronized, &rdev->flags) ||
 -                   (!test_bit(In_sync, &rdev->flags) &&
 -                    !test_bit(Journal, &rdev->flags))) &&
 -                  atomic_read(&rdev->nr_pending)==0)) {
 +                  (test_bit(RemoveSynchronized, &rdev->flags) ||
 +                   rdev_removeable(rdev))) {
                        if (mddev->pers->hot_remove_disk(
                                    mddev, rdev) == 0) {
                                sysfs_unlink_rdev(mddev, rdev);
        rdev_for_each(rdev, mddev) {
                if (this && this != rdev)
                        continue;
 -              if (test_bit(Candidate, &rdev->flags))
 -                      continue;
 -              if (rdev->raid_disk >= 0 &&
 -                  !test_bit(In_sync, &rdev->flags) &&
 -                  !test_bit(Journal, &rdev->flags) &&
 -                  !test_bit(Faulty, &rdev->flags))
 +              if (rdev_is_spare(rdev))
                        spares++;
 -              if (rdev->raid_disk >= 0)
 -                      continue;
 -              if (test_bit(Faulty, &rdev->flags))
 +              if (!rdev_addable(rdev))
                        continue;
 -              if (!test_bit(Journal, &rdev->flags)) {
 -                      if (!md_is_rdwr(mddev) &&
 -                          !(rdev->saved_raid_disk >= 0 &&
 -                            !test_bit(Bitmap_sync, &rdev->flags)))
 -                              continue;
 -
 +              if (!test_bit(Journal, &rdev->flags))
                        rdev->recovery_offset = 0;
 -              }
                if (mddev->pers->hot_add_disk(mddev, rdev) == 0) {
                        /* failure here is OK */
                        sysfs_link_rdev(mddev, rdev);
@@@ -9313,86 -9253,9 +9312,86 @@@ no_add
        return spares;
  }
  
 +static bool md_choose_sync_action(struct mddev *mddev, int *spares)
 +{
 +      /* Check if reshape is in progress first. */
 +      if (mddev->reshape_position != MaxSector) {
 +              if (mddev->pers->check_reshape == NULL ||
 +                  mddev->pers->check_reshape(mddev) != 0)
 +                      return false;
 +
 +              set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
 +              clear_bit(MD_RECOVERY_RECOVER, &mddev->recovery);
 +              return true;
 +      }
 +
 +      /*
 +       * Remove any failed drives, then add spares if possible. Spares are
 +       * also removed and re-added, to allow the personality to fail the
 +       * re-add.
 +       */
 +      *spares = remove_and_add_spares(mddev, NULL);
 +      if (*spares) {
 +              clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
 +              clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
 +              clear_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);
 +
 +              /* Start new recovery. */
 +              set_bit(MD_RECOVERY_RECOVER, &mddev->recovery);
 +              return true;
 +      }
 +
 +      /* Check if recovery is in progress. */
 +      if (mddev->recovery_cp < MaxSector) {
 +              set_bit(MD_RECOVERY_SYNC, &mddev->recovery);
 +              clear_bit(MD_RECOVERY_RECOVER, &mddev->recovery);
 +              return true;
 +      }
 +
 +      /* Delay to choose resync/check/repair in md_do_sync(). */
 +      if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
 +              return true;
 +
 +      /* Nothing to be done */
 +      return false;
 +}
 +
  static void md_start_sync(struct work_struct *ws)
  {
 -      struct mddev *mddev = container_of(ws, struct mddev, del_work);
 +      struct mddev *mddev = container_of(ws, struct mddev, sync_work);
 +      int spares = 0;
 +      bool suspend = false;
 +
 +      if (md_spares_need_change(mddev))
 +              suspend = true;
 +
 +      suspend ? mddev_suspend_and_lock_nointr(mddev) :
 +                mddev_lock_nointr(mddev);
 +
 +      if (!md_is_rdwr(mddev)) {
 +              /*
 +               * On a read-only array we can:
 +               * - remove failed devices
 +               * - add already-in_sync devices if the array itself is in-sync.
 +               * As we only add devices that are already in-sync, we can
 +               * activate the spares immediately.
 +               */
 +              remove_and_add_spares(mddev, NULL);
 +              goto not_running;
 +      }
 +
 +      if (!md_choose_sync_action(mddev, &spares))
 +              goto not_running;
 +
 +      if (!mddev->pers->sync_request)
 +              goto not_running;
 +
 +      /*
 +       * We are adding a device or devices to an array which has the bitmap
 +       * stored on all devices. So make sure all bitmap pages get written.
 +       */
 +      if (spares)
 +              md_bitmap_write_all(mddev->bitmap);
  
        rcu_assign_pointer(mddev->sync_thread,
                           md_register_thread(md_do_sync, mddev, "resync"));
                pr_warn("%s: could not start resync thread...\n",
                        mdname(mddev));
                /* leave the spares where they are, it shouldn't hurt */
 -              clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
 -              clear_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
 -              clear_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);
 -              clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
 -              clear_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
 -              wake_up(&resync_wait);
 -              if (test_and_clear_bit(MD_RECOVERY_RECOVER,
 -                                     &mddev->recovery))
 -                      if (mddev->sysfs_action)
 -                              sysfs_notify_dirent_safe(mddev->sysfs_action);
 -      } else
 -              md_wakeup_thread(mddev->sync_thread);
 +              goto not_running;
 +      }
 +
 +      suspend ? mddev_unlock_and_resume(mddev) : mddev_unlock(mddev);
 +      md_wakeup_thread(mddev->sync_thread);
        sysfs_notify_dirent_safe(mddev->sysfs_action);
        md_new_event();
 +      return;
 +
 +not_running:
 +      clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
 +      clear_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
 +      clear_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);
 +      clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
 +      clear_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
 +      suspend ? mddev_unlock_and_resume(mddev) : mddev_unlock(mddev);
 +
 +      wake_up(&resync_wait);
 +      if (test_and_clear_bit(MD_RECOVERY_RECOVER, &mddev->recovery) &&
 +          mddev->sysfs_action)
 +              sysfs_notify_dirent_safe(mddev->sysfs_action);
  }
  
  /*
   */
  void md_check_recovery(struct mddev *mddev)
  {
 -      if (test_bit(MD_ALLOW_SB_UPDATE, &mddev->flags) && mddev->sb_flags) {
 -              /* Write superblock - thread that called mddev_suspend()
 -               * holds reconfig_mutex for us.
 -               */
 -              set_bit(MD_UPDATING_SB, &mddev->flags);
 -              smp_mb__after_atomic();
 -              if (test_bit(MD_ALLOW_SB_UPDATE, &mddev->flags))
 -                      md_update_sb(mddev, 0);
 -              clear_bit_unlock(MD_UPDATING_SB, &mddev->flags);
 -              wake_up(&mddev->sb_wait);
 -      }
 -
 -      if (is_md_suspended(mddev))
 +      if (READ_ONCE(mddev->suspended))
                return;
  
        if (mddev->bitmap)
                return;
  
        if (mddev_trylock(mddev)) {
 -              int spares = 0;
                bool try_set_sync = mddev->safemode != 0;
  
                if (!mddev->external && mddev->safemode == 1)
  
                if (!md_is_rdwr(mddev)) {
                        struct md_rdev *rdev;
 +
 +                      if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) {
 +                              /* sync_work already queued. */
 +                              clear_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
 +                              goto unlock;
 +                      }
 +
                        if (!mddev->external && mddev->in_sync)
 -                              /* 'Blocked' flag not needed as failed devices
 +                              /*
 +                               * 'Blocked' flag not needed as failed devices
                                 * will be recorded if array switched to read/write.
                                 * Leaving it set will prevent the device
                                 * from being removed.
                                 */
                                rdev_for_each(rdev, mddev)
                                        clear_bit(Blocked, &rdev->flags);
 -                      /* On a read-only array we can:
 -                       * - remove failed devices
 -                       * - add already-in_sync devices if the array itself
 -                       *   is in-sync.
 -                       * As we only add devices that are already in-sync,
 -                       * we can activate the spares immediately.
 -                       */
 -                      remove_and_add_spares(mddev, NULL);
 -                      /* There is no thread, but we need to call
 +
 +                      /*
 +                       * There is no thread, but we need to call
                         * ->spare_active and clear saved_raid_disk
                         */
                        set_bit(MD_RECOVERY_INTR, &mddev->recovery);
                        md_reap_sync_thread(mddev);
 +
 +                      /*
 +                       * Let md_start_sync() to remove and add rdevs to the
 +                       * array.
 +                       */
 +                      if (md_spares_need_change(mddev)) {
 +                              set_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
 +                              queue_work(md_misc_wq, &mddev->sync_work);
 +                      }
 +
                        clear_bit(MD_RECOVERY_RECOVER, &mddev->recovery);
                        clear_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
                        clear_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags);
 +
                        goto unlock;
                }
  
                clear_bit(MD_RECOVERY_INTR, &mddev->recovery);
                clear_bit(MD_RECOVERY_DONE, &mddev->recovery);
  
 -              if (!test_and_clear_bit(MD_RECOVERY_NEEDED, &mddev->recovery) ||
 -                  test_bit(MD_RECOVERY_FROZEN, &mddev->recovery))
 -                      goto not_running;
 -              /* no recovery is running.
 -               * remove any failed drives, then
 -               * add spares if possible.
 -               * Spares are also removed and re-added, to allow
 -               * the personality to fail the re-add.
 -               */
 -
 -              if (mddev->reshape_position != MaxSector) {
 -                      if (mddev->pers->check_reshape == NULL ||
 -                          mddev->pers->check_reshape(mddev) != 0)
 -                              /* Cannot proceed */
 -                              goto not_running;
 -                      set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
 -                      clear_bit(MD_RECOVERY_RECOVER, &mddev->recovery);
 -              } else if ((spares = remove_and_add_spares(mddev, NULL))) {
 -                      clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
 -                      clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
 -                      clear_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);
 -                      set_bit(MD_RECOVERY_RECOVER, &mddev->recovery);
 -              } else if (mddev->recovery_cp < MaxSector) {
 -                      set_bit(MD_RECOVERY_SYNC, &mddev->recovery);
 -                      clear_bit(MD_RECOVERY_RECOVER, &mddev->recovery);
 -              } else if (!test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
 -                      /* nothing to be done ... */
 -                      goto not_running;
 -
 -              if (mddev->pers->sync_request) {
 -                      if (spares) {
 -                              /* We are adding a device or devices to an array
 -                               * which has the bitmap stored on all devices.
 -                               * So make sure all bitmap pages get written
 -                               */
 -                              md_bitmap_write_all(mddev->bitmap);
 -                      }
 -                      INIT_WORK(&mddev->del_work, md_start_sync);
 -                      queue_work(md_misc_wq, &mddev->del_work);
 -                      goto unlock;
 -              }
 -      not_running:
 -              if (!mddev->sync_thread) {
 +              if (test_and_clear_bit(MD_RECOVERY_NEEDED, &mddev->recovery) &&
 +                  !test_bit(MD_RECOVERY_FROZEN, &mddev->recovery)) {
 +                      queue_work(md_misc_wq, &mddev->sync_work);
 +              } else {
                        clear_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
                        wake_up(&resync_wait);
 -                      if (test_and_clear_bit(MD_RECOVERY_RECOVER,
 -                                             &mddev->recovery))
 -                              if (mddev->sysfs_action)
 -                                      sysfs_notify_dirent_safe(mddev->sysfs_action);
                }
 +
        unlock:
                wake_up(&mddev->sb_wait);
                mddev_unlock(mddev);
index cc71395782b666abbe2b3c8fb6c32d9fd1892581,3186421e82c377999f962cbf36084cbda378f01e..61b66e318488cd5b5ab6378fe800351a4e458aa0
@@@ -110,7 -110,6 +110,6 @@@ static struct ctl_table xpc_sys_xpc_hb[
         .proc_handler = proc_dointvec_minmax,
         .extra1 = &xpc_hb_check_min_interval,
         .extra2 = &xpc_hb_check_max_interval},
-       {}
  };
  static struct ctl_table xpc_sys_xpc[] = {
        {
         .proc_handler = proc_dointvec_minmax,
         .extra1 = &xpc_disengage_min_timelimit,
         .extra2 = &xpc_disengage_max_timelimit},
-       {}
  };
  
  static struct ctl_table_header *xpc_sysctl;
@@@ -1155,6 -1153,36 +1153,6 @@@ xpc_die_deactivate(void
  static int
  xpc_system_die(struct notifier_block *nb, unsigned long event, void *_die_args)
  {
 -#ifdef CONFIG_IA64            /* !!! temporary kludge */
 -      switch (event) {
 -      case DIE_MACHINE_RESTART:
 -      case DIE_MACHINE_HALT:
 -              xpc_die_deactivate();
 -              break;
 -
 -      case DIE_KDEBUG_ENTER:
 -              /* Should lack of heartbeat be ignored by other partitions? */
 -              if (!xpc_kdebug_ignore)
 -                      break;
 -
 -              fallthrough;
 -      case DIE_MCA_MONARCH_ENTER:
 -      case DIE_INIT_MONARCH_ENTER:
 -              xpc_arch_ops.offline_heartbeat();
 -              break;
 -
 -      case DIE_KDEBUG_LEAVE:
 -              /* Is lack of heartbeat being ignored by other partitions? */
 -              if (!xpc_kdebug_ignore)
 -                      break;
 -
 -              fallthrough;
 -      case DIE_MCA_MONARCH_LEAVE:
 -      case DIE_INIT_MONARCH_LEAVE:
 -              xpc_arch_ops.online_heartbeat();
 -              break;
 -      }
 -#else
        struct die_args *die_args = _die_args;
  
        switch (event) {
        default:
                xpc_die_deactivate();
        }
 -#endif
  
        return NOTIFY_DONE;
  }
diff --combined drivers/perf/arm_pmuv3.c
index 4f6923ad45897cd767c42821eaa33b6fc067a8d7,c0307b9181c321191c3e00a7c4b085e09c2c53cd..18b91b56af1d467ceb155cd8ce89739a2df1c240
@@@ -1126,7 -1126,7 +1126,7 @@@ static void __armv8pmu_probe_pmu(void *
                             pmceid, ARMV8_PMUV3_MAX_COMMON_EVENTS);
  
        /* store PMMIR register for sysfs */
 -      if (is_pmuv3p4(pmuver) && (pmceid_raw[1] & BIT(31)))
 +      if (is_pmuv3p4(pmuver))
                cpu_pmu->reg_pmmir = read_pmmir();
        else
                cpu_pmu->reg_pmmir = 0;
@@@ -1175,7 -1175,6 +1175,6 @@@ static struct ctl_table armv8_pmu_sysct
                .extra1         = SYSCTL_ZERO,
                .extra2         = SYSCTL_ONE,
        },
-       { }
  };
  
  static void armv8_pmu_register_sysctl_table(void)
  }
  
  static int armv8_pmu_init(struct arm_pmu *cpu_pmu, char *name,
 -                        int (*map_event)(struct perf_event *event),
 -                        const struct attribute_group *events,
 -                        const struct attribute_group *format,
 -                        const struct attribute_group *caps)
 +                        int (*map_event)(struct perf_event *event))
  {
        int ret = armv8pmu_probe_pmu(cpu_pmu);
        if (ret)
  
        cpu_pmu->name                   = name;
        cpu_pmu->map_event              = map_event;
 -      cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_EVENTS] = events ?
 -                      events : &armv8_pmuv3_events_attr_group;
 -      cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] = format ?
 -                      format : &armv8_pmuv3_format_attr_group;
 -      cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_CAPS] = caps ?
 -                      caps : &armv8_pmuv3_caps_attr_group;
 -
 +      cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_EVENTS] = &armv8_pmuv3_events_attr_group;
 +      cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] = &armv8_pmuv3_format_attr_group;
 +      cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_CAPS] = &armv8_pmuv3_caps_attr_group;
        armv8_pmu_register_sysctl_table();
        return 0;
  }
  
 -static int armv8_pmu_init_nogroups(struct arm_pmu *cpu_pmu, char *name,
 -                                 int (*map_event)(struct perf_event *event))
 -{
 -      return armv8_pmu_init(cpu_pmu, name, map_event, NULL, NULL, NULL);
 -}
 -
  #define PMUV3_INIT_SIMPLE(name)                                               \
  static int name##_pmu_init(struct arm_pmu *cpu_pmu)                   \
  {                                                                     \
 -      return armv8_pmu_init_nogroups(cpu_pmu, #name, armv8_pmuv3_map_event);\
 +      return armv8_pmu_init(cpu_pmu, #name, armv8_pmuv3_map_event);   \
  }
  
  PMUV3_INIT_SIMPLE(armv8_pmuv3)
@@@ -1250,37 -1262,44 +1249,37 @@@ PMUV3_INIT_SIMPLE(armv8_nvidia_denver
  
  static int armv8_a35_pmu_init(struct arm_pmu *cpu_pmu)
  {
 -      return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a35",
 -                                     armv8_a53_map_event);
 +      return armv8_pmu_init(cpu_pmu, "armv8_cortex_a35", armv8_a53_map_event);
  }
  
  static int armv8_a53_pmu_init(struct arm_pmu *cpu_pmu)
  {
 -      return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a53",
 -                                     armv8_a53_map_event);
 +      return armv8_pmu_init(cpu_pmu, "armv8_cortex_a53", armv8_a53_map_event);
  }
  
  static int armv8_a57_pmu_init(struct arm_pmu *cpu_pmu)
  {
 -      return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a57",
 -                                     armv8_a57_map_event);
 +      return armv8_pmu_init(cpu_pmu, "armv8_cortex_a57", armv8_a57_map_event);
  }
  
  static int armv8_a72_pmu_init(struct arm_pmu *cpu_pmu)
  {
 -      return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a72",
 -                                     armv8_a57_map_event);
 +      return armv8_pmu_init(cpu_pmu, "armv8_cortex_a72", armv8_a57_map_event);
  }
  
  static int armv8_a73_pmu_init(struct arm_pmu *cpu_pmu)
  {
 -      return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a73",
 -                                     armv8_a73_map_event);
 +      return armv8_pmu_init(cpu_pmu, "armv8_cortex_a73", armv8_a73_map_event);
  }
  
  static int armv8_thunder_pmu_init(struct arm_pmu *cpu_pmu)
  {
 -      return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cavium_thunder",
 -                                     armv8_thunder_map_event);
 +      return armv8_pmu_init(cpu_pmu, "armv8_cavium_thunder", armv8_thunder_map_event);
  }
  
  static int armv8_vulcan_pmu_init(struct arm_pmu *cpu_pmu)
  {
 -      return armv8_pmu_init_nogroups(cpu_pmu, "armv8_brcm_vulcan",
 -                                     armv8_vulcan_map_event);
 +      return armv8_pmu_init(cpu_pmu, "armv8_brcm_vulcan", armv8_vulcan_map_event);
  }
  
  static const struct of_device_id armv8_pmu_of_device_ids[] = {
diff --combined drivers/tty/tty_io.c
index d13d2f2e76c7095a73d86a4391cb23f513ac8b5a,b3ae062912f54506a0fcfc432b408265ee96a033..0216a468b438d3259874190c3af49a74cd584c79
@@@ -818,7 -818,7 +818,7 @@@ static void tty_update_time(struct tty_
        spin_lock(&tty->files_lock);
        list_for_each_entry(priv, &tty->tty_files, list) {
                struct inode *inode = file_inode(priv->file);
 -              struct timespec64 *time = mtime ? &inode->i_mtime : &inode->i_atime;
 +              struct timespec64 time = mtime ? inode_get_mtime(inode) : inode_get_atime(inode);
  
                /*
                 * We only care if the two values differ in anything other than the
                 * the time of the tty device, otherwise it could be construded as a
                 * security leak to let userspace know the exact timing of the tty.
                 */
 -              if ((sec ^ time->tv_sec) & ~7)
 -                      time->tv_sec = sec;
 +              if ((sec ^ time.tv_sec) & ~7) {
 +                      if (mtime)
 +                              inode_set_mtime(inode, sec, 0);
 +                      else
 +                              inode_set_atime(inode, sec, 0);
 +              }
        }
        spin_unlock(&tty->files_lock);
  }
@@@ -3612,7 -3608,6 +3612,6 @@@ static struct ctl_table tty_table[] = 
                .extra1         = SYSCTL_ZERO,
                .extra2         = SYSCTL_ONE,
        },
-       { }
  };
  
  /*
diff --combined fs/proc/proc_sysctl.c
index bc9a2db89cfa5b2841d573f8c9838209108febeb,de484195f49fe8a431d7369a106fb348e3dfb222..8064ea76f80b50dd66484e3d93ed2ee5fad23ddc
@@@ -465,7 -465,7 +465,7 @@@ static struct inode *proc_sys_make_inod
        head->count++;
        spin_unlock(&sysctl_lock);
  
 -      inode->i_mtime = inode->i_atime = inode_set_ctime_current(inode);
 +      simple_inode_init_ts(inode);
        inode->i_mode = table->mode;
        if (!S_ISDIR(table->mode)) {
                inode->i_mode |= S_IFREG;
@@@ -1576,7 -1576,6 +1576,6 @@@ static const struct sysctl_alias sysctl
        {"hung_task_panic",                     "kernel.hung_task_panic" },
        {"numa_zonelist_order",                 "vm.numa_zonelist_order" },
        {"softlockup_all_cpu_backtrace",        "kernel.softlockup_all_cpu_backtrace" },
-       {"softlockup_panic",                    "kernel.softlockup_panic" },
        { }
  };
  
@@@ -1592,6 -1591,13 +1591,13 @@@ static const char *sysctl_find_alias(ch
        return NULL;
  }
  
+ bool sysctl_is_alias(char *param)
+ {
+       const char *alias = sysctl_find_alias(param);
+       return alias != NULL;
+ }
  /* Set sysctl value passed on kernel command line. */
  static int process_sysctl_arg(char *param, char *val,
                               const char *unused, void *arg)
This page took 0.251455 seconds and 4 git commands to generate.