]> Git Repo - linux.git/commitdiff
Merge tag 'rcu.2022.12.02a' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck...
authorLinus Torvalds <[email protected]>
Mon, 12 Dec 2022 15:47:15 +0000 (07:47 -0800)
committerLinus Torvalds <[email protected]>
Mon, 12 Dec 2022 15:47:15 +0000 (07:47 -0800)
Pull RCU updates from Paul McKenney:

 - Documentation updates. This is the second in a series from an ongoing
   review of the RCU documentation.

 - Miscellaneous fixes.

 - Introduce a default-off Kconfig option that depends on RCU_NOCB_CPU
   that, on CPUs mentioned in the nohz_full or rcu_nocbs boot-argument
   CPU lists, causes call_rcu() to introduce delays.

   These delays result in significant power savings on nearly idle
   Android and ChromeOS systems. These savings range from a few percent
   to more than ten percent.

   This series also includes several commits that change call_rcu() to a
   new call_rcu_hurry() function that avoids these delays in a few
   cases, for example, where timely wakeups are required. Several of
   these are outside of RCU and thus have acks and reviews from the
   relevant maintainers.

 - Create an srcu_read_lock_nmisafe() and an srcu_read_unlock_nmisafe()
   for architectures that support NMIs, but which do not provide
   NMI-safe this_cpu_inc(). These NMI-safe SRCU functions are required
   by the upcoming lockless printk() work by John Ogness et al.

 - Changes providing minor but important increases in torture test
   coverage for the new RCU polled-grace-period APIs.

 - Changes to torturescript that avoid redundant kernel builds, thus
   providing about a 30% speedup for the torture.sh acceptance test.

* tag 'rcu.2022.12.02a' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu: (49 commits)
  net: devinet: Reduce refcount before grace period
  net: Use call_rcu_hurry() for dst_release()
  workqueue: Make queue_rcu_work() use call_rcu_hurry()
  percpu-refcount: Use call_rcu_hurry() for atomic switch
  scsi/scsi_error: Use call_rcu_hurry() instead of call_rcu()
  rcu/rcutorture: Use call_rcu_hurry() where needed
  rcu/rcuscale: Use call_rcu_hurry() for async reader test
  rcu/sync: Use call_rcu_hurry() instead of call_rcu
  rcuscale: Add laziness and kfree tests
  rcu: Shrinker for lazy rcu
  rcu: Refactor code a bit in rcu_nocb_do_flush_bypass()
  rcu: Make call_rcu() lazy to save power
  rcu: Implement lockdep_rcu_enabled for !CONFIG_DEBUG_LOCK_ALLOC
  srcu: Debug NMI safety even on archs that don't require it
  srcu: Explain the reason behind the read side critical section on GP start
  srcu: Warn when NMI-unsafe API is used in NMI
  arch/s390: Add ARCH_HAS_NMI_SAFE_THIS_CPU_OPS Kconfig option
  arch/loongarch: Add ARCH_HAS_NMI_SAFE_THIS_CPU_OPS Kconfig option
  rcu: Fix __this_cpu_read() lockdep warning in rcu_force_quiescent_state()
  rcu-tasks: Make grace-period-age message human-readable
  ...

1  2 
arch/s390/Kconfig
arch/x86/Kconfig
include/linux/kvm_host.h
include/linux/slab.h
kernel/rcu/tree.c

diff --combined arch/s390/Kconfig
index de575af02ffea3b2c31bc488f8931fa41773a09a,0acdfda332908daa106ea1a3f978ad5a1525f679..48a11deb502c2cecd9cbf8bd3c2ede4e4daa1b82
@@@ -73,6 -73,7 +73,7 @@@ config S39
        select ARCH_HAS_GIGANTIC_PAGE
        select ARCH_HAS_KCOV
        select ARCH_HAS_MEM_ENCRYPT
+       select ARCH_HAS_NMI_SAFE_THIS_CPU_OPS
        select ARCH_HAS_PTE_SPECIAL
        select ARCH_HAS_SCALED_CPUTIME
        select ARCH_HAS_SET_MEMORY
@@@ -568,7 -569,8 +569,7 @@@ config EXPOLINE_FUL
  endchoice
  
  config RELOCATABLE
 -      bool "Build a relocatable kernel"
 -      default y
 +      def_bool y
        help
          This builds a kernel image that retains relocation information
          so it can be loaded at an arbitrary address.
          bootup process.
          The relocations make the kernel image about 15% larger (compressed
          10%), but are discarded at runtime.
 +        Note: this option exists only for documentation purposes, please do
 +        not remove it.
  
  config RANDOMIZE_BASE
        bool "Randomize the address of the kernel image (KASLR)"
 -      depends on RELOCATABLE
        default y
        help
          In support of Kernel Address Space Layout Randomization (KASLR),
diff --combined arch/x86/Kconfig
index 67745ceab0dbc64cbca3e63e94ab92dbf976d571,bcb3190eaa266a08f6ad587eec6c4cf211dd741f..7d11f718ff0c65539a4dcccadf2aa7fde1339d18
@@@ -81,6 -81,7 +81,7 @@@ config X8
        select ARCH_HAS_KCOV                    if X86_64
        select ARCH_HAS_MEM_ENCRYPT
        select ARCH_HAS_MEMBARRIER_SYNC_CORE
+       select ARCH_HAS_NMI_SAFE_THIS_CPU_OPS
        select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
        select ARCH_HAS_PMEM_API                if X86_64
        select ARCH_HAS_PTE_DEVMAP              if X86_64
@@@ -1973,6 -1974,7 +1974,6 @@@ config EF
  config EFI_STUB
        bool "EFI stub support"
        depends on EFI
 -      depends on $(cc-option,-mabi=ms) || X86_32
        select RELOCATABLE
        help
          This kernel feature allows a bzImage to be loaded directly
diff --combined include/linux/kvm_host.h
index 637a60607c7d3a6172463fc8be2523bc8fe6ae30,381b92d146c71f2957b23b85267af13ff4e99f68..915142abdf76100ac62fd1de7ee66a995dfa662e
@@@ -416,7 -416,7 +416,7 @@@ static __always_inline void guest_conte
         */
        if (!context_tracking_guest_enter()) {
                instrumentation_begin();
-               rcu_virt_note_context_switch(smp_processor_id());
+               rcu_virt_note_context_switch();
                instrumentation_end();
        }
  }
@@@ -776,7 -776,6 +776,7 @@@ struct kvm 
        struct srcu_struct srcu;
        struct srcu_struct irq_srcu;
        pid_t userspace_pid;
 +      bool override_halt_poll_ns;
        unsigned int max_halt_poll_ns;
        u32 dirty_ring_size;
        bool vm_bugged;
@@@ -1241,18 -1240,8 +1241,18 @@@ int kvm_vcpu_write_guest(struct kvm_vcp
  void kvm_vcpu_mark_page_dirty(struct kvm_vcpu *vcpu, gfn_t gfn);
  
  /**
 - * kvm_gfn_to_pfn_cache_init - prepare a cached kernel mapping and HPA for a
 - *                             given guest physical address.
 + * kvm_gpc_init - initialize gfn_to_pfn_cache.
 + *
 + * @gpc:         struct gfn_to_pfn_cache object.
 + *
 + * This sets up a gfn_to_pfn_cache by initializing locks.  Note, the cache must
 + * be zero-allocated (or zeroed by the caller before init).
 + */
 +void kvm_gpc_init(struct gfn_to_pfn_cache *gpc);
 +
 +/**
 + * kvm_gpc_activate - prepare a cached kernel mapping and HPA for a given guest
 + *                    physical address.
   *
   * @kvm:         pointer to kvm instance.
   * @gpc:         struct gfn_to_pfn_cache object.
   * kvm_gfn_to_pfn_cache_check() to ensure that the cache is valid before
   * accessing the target page.
   */
 -int kvm_gfn_to_pfn_cache_init(struct kvm *kvm, struct gfn_to_pfn_cache *gpc,
 -                            struct kvm_vcpu *vcpu, enum pfn_cache_usage usage,
 -                            gpa_t gpa, unsigned long len);
 +int kvm_gpc_activate(struct kvm *kvm, struct gfn_to_pfn_cache *gpc,
 +                   struct kvm_vcpu *vcpu, enum pfn_cache_usage usage,
 +                   gpa_t gpa, unsigned long len);
  
  /**
   * kvm_gfn_to_pfn_cache_check - check validity of a gfn_to_pfn_cache.
@@@ -1335,7 -1324,7 +1335,7 @@@ int kvm_gfn_to_pfn_cache_refresh(struc
  void kvm_gfn_to_pfn_cache_unmap(struct kvm *kvm, struct gfn_to_pfn_cache *gpc);
  
  /**
 - * kvm_gfn_to_pfn_cache_destroy - destroy and unlink a gfn_to_pfn_cache.
 + * kvm_gpc_deactivate - deactivate and unlink a gfn_to_pfn_cache.
   *
   * @kvm:         pointer to kvm instance.
   * @gpc:         struct gfn_to_pfn_cache object.
   * This removes a cache from the @kvm's list to be processed on MMU notifier
   * invocation.
   */
 -void kvm_gfn_to_pfn_cache_destroy(struct kvm *kvm, struct gfn_to_pfn_cache *gpc);
 +void kvm_gpc_deactivate(struct kvm *kvm, struct gfn_to_pfn_cache *gpc);
  
  void kvm_sigset_activate(struct kvm_vcpu *vcpu);
  void kvm_sigset_deactivate(struct kvm_vcpu *vcpu);
@@@ -1401,8 -1390,6 +1401,8 @@@ int kvm_vm_ioctl_enable_cap(struct kvm 
                            struct kvm_enable_cap *cap);
  long kvm_arch_vm_ioctl(struct file *filp,
                       unsigned int ioctl, unsigned long arg);
 +long kvm_arch_vm_compat_ioctl(struct file *filp, unsigned int ioctl,
 +                            unsigned long arg);
  
  int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu);
  int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu);
diff --combined include/linux/slab.h
index 45efc6c553b826101da7855a4573dfe66c845ae4,487418c7ea8cdc036eed184f8b3db160e4814d1a..e7534a7b2daf9678c4fb815be7d69a670ae55ba3
   * rcu_read_lock before reading the address, then rcu_read_unlock after
   * taking the spinlock within the structure expected at that address.
   *
+  * Note that it is not possible to acquire a lock within a structure
+  * allocated with SLAB_TYPESAFE_BY_RCU without first acquiring a reference
+  * as described above.  The reason is that SLAB_TYPESAFE_BY_RCU pages
+  * are not zeroed before being given to the slab, which means that any
+  * locks must be initialized after each and every kmem_struct_alloc().
+  * Alternatively, make the ctor passed to kmem_cache_create() initialize
+  * the locks at page-allocation time, as is done in __i915_request_ctor(),
+  * sighand_ctor(), and anon_vma_ctor().  Such a ctor permits readers
+  * to safely acquire those ctor-initialized locks under rcu_read_lock()
+  * protection.
+  *
   * Note that SLAB_TYPESAFE_BY_RCU was originally named SLAB_DESTROY_BY_RCU.
   */
  /* Defer freeing slabs to RCU */
@@@ -470,12 -481,35 +481,12 @@@ void *__kmalloc_node(size_t size, gfp_
  void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t flags, int node) __assume_slab_alignment
                                                                         __malloc;
  
 -#ifdef CONFIG_TRACING
  void *kmalloc_trace(struct kmem_cache *s, gfp_t flags, size_t size)
                    __assume_kmalloc_alignment __alloc_size(3);
  
  void *kmalloc_node_trace(struct kmem_cache *s, gfp_t gfpflags,
                         int node, size_t size) __assume_kmalloc_alignment
                                                __alloc_size(4);
 -#else /* CONFIG_TRACING */
 -/* Save a function call when CONFIG_TRACING=n */
 -static __always_inline __alloc_size(3)
 -void *kmalloc_trace(struct kmem_cache *s, gfp_t flags, size_t size)
 -{
 -      void *ret = kmem_cache_alloc(s, flags);
 -
 -      ret = kasan_kmalloc(s, ret, size, flags);
 -      return ret;
 -}
 -
 -static __always_inline __alloc_size(4)
 -void *kmalloc_node_trace(struct kmem_cache *s, gfp_t gfpflags,
 -                       int node, size_t size)
 -{
 -      void *ret = kmem_cache_alloc_node(s, gfpflags, node);
 -
 -      ret = kasan_kmalloc(s, ret, size, gfpflags);
 -      return ret;
 -}
 -#endif /* CONFIG_TRACING */
 -
  void *kmalloc_large(size_t size, gfp_t flags) __assume_page_alignment
                                              __alloc_size(1);
  
diff --combined kernel/rcu/tree.c
index 93416afebd59c7a34ad134136817e8eeceaed4a4,d7764ffda6e522f7fe415b95c6f28bd206d91701..d04f2192f02c93b84d4c704d07542307696e544f
@@@ -301,12 -301,6 +301,6 @@@ static bool rcu_dynticks_in_eqs(int sna
        return !(snap & RCU_DYNTICKS_IDX);
  }
  
- /* Return true if the specified CPU is currently idle from an RCU viewpoint.  */
- bool rcu_is_idle_cpu(int cpu)
- {
-       return rcu_dynticks_in_eqs(rcu_dynticks_snap(cpu));
- }
  /*
   * Return true if the CPU corresponding to the specified rcu_data
   * structure has spent some time in an extended quiescent state since
@@@ -1403,32 -1397,30 +1397,32 @@@ static void rcu_poll_gp_seq_end(unsigne
  // where caller does not hold the root rcu_node structure's lock.
  static void rcu_poll_gp_seq_start_unlocked(unsigned long *snap)
  {
 +      unsigned long flags;
        struct rcu_node *rnp = rcu_get_root();
  
        if (rcu_init_invoked()) {
                lockdep_assert_irqs_enabled();
 -              raw_spin_lock_irq_rcu_node(rnp);
 +              raw_spin_lock_irqsave_rcu_node(rnp, flags);
        }
        rcu_poll_gp_seq_start(snap);
        if (rcu_init_invoked())
 -              raw_spin_unlock_irq_rcu_node(rnp);
 +              raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
  }
  
  // Make the polled API aware of the end of a grace period, but where
  // caller does not hold the root rcu_node structure's lock.
  static void rcu_poll_gp_seq_end_unlocked(unsigned long *snap)
  {
 +      unsigned long flags;
        struct rcu_node *rnp = rcu_get_root();
  
        if (rcu_init_invoked()) {
                lockdep_assert_irqs_enabled();
 -              raw_spin_lock_irq_rcu_node(rnp);
 +              raw_spin_lock_irqsave_rcu_node(rnp, flags);
        }
        rcu_poll_gp_seq_end(snap);
        if (rcu_init_invoked())
 -              raw_spin_unlock_irq_rcu_node(rnp);
 +              raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
  }
  
  /*
@@@ -2108,7 -2100,7 +2102,7 @@@ int rcutree_dying_cpu(unsigned int cpu
        if (!IS_ENABLED(CONFIG_HOTPLUG_CPU))
                return 0;
  
-       blkd = !!(rnp->qsmask & rdp->grpmask);
+       blkd = !!(READ_ONCE(rnp->qsmask) & rdp->grpmask);
        trace_rcu_grace_period(rcu_state.name, READ_ONCE(rnp->gp_seq),
                               blkd ? TPS("cpuofl-bgp") : TPS("cpuofl"));
        return 0;
@@@ -2418,7 -2410,7 +2412,7 @@@ void rcu_force_quiescent_state(void
        struct rcu_node *rnp_old = NULL;
  
        /* Funnel through hierarchy to reduce memory contention. */
-       rnp = __this_cpu_read(rcu_data.mynode);
+       rnp = raw_cpu_read(rcu_data.mynode);
        for (; rnp != NULL; rnp = rnp->parent) {
                ret = (READ_ONCE(rcu_state.gp_flags) & RCU_GP_FLAG_FQS) ||
                       !raw_spin_trylock(&rnp->fqslock);
@@@ -2730,47 -2722,8 +2724,8 @@@ static void check_cb_ovld(struct rcu_da
        raw_spin_unlock_rcu_node(rnp);
  }
  
- /**
-  * call_rcu() - Queue an RCU callback for invocation after a grace period.
-  * @head: structure to be used for queueing the RCU updates.
-  * @func: actual callback function to be invoked after the grace period
-  *
-  * The callback function will be invoked some time after a full grace
-  * period elapses, in other words after all pre-existing RCU read-side
-  * critical sections have completed.  However, the callback function
-  * might well execute concurrently with RCU read-side critical sections
-  * that started after call_rcu() was invoked.
-  *
-  * RCU read-side critical sections are delimited by rcu_read_lock()
-  * and rcu_read_unlock(), and may be nested.  In addition, but only in
-  * v5.0 and later, regions of code across which interrupts, preemption,
-  * or softirqs have been disabled also serve as RCU read-side critical
-  * sections.  This includes hardware interrupt handlers, softirq handlers,
-  * and NMI handlers.
-  *
-  * Note that all CPUs must agree that the grace period extended beyond
-  * all pre-existing RCU read-side critical section.  On systems with more
-  * than one CPU, this means that when "func()" is invoked, each CPU is
-  * guaranteed to have executed a full memory barrier since the end of its
-  * last RCU read-side critical section whose beginning preceded the call
-  * to call_rcu().  It also means that each CPU executing an RCU read-side
-  * critical section that continues beyond the start of "func()" must have
-  * executed a memory barrier after the call_rcu() but before the beginning
-  * of that RCU read-side critical section.  Note that these guarantees
-  * include CPUs that are offline, idle, or executing in user mode, as
-  * well as CPUs that are executing in the kernel.
-  *
-  * Furthermore, if CPU A invoked call_rcu() and CPU B invoked the
-  * resulting RCU callback function "func()", then both CPU A and CPU B are
-  * guaranteed to execute a full memory barrier during the time interval
-  * between the call to call_rcu() and the invocation of "func()" -- even
-  * if CPU A and CPU B are the same CPU (but again only if the system has
-  * more than one CPU).
-  *
-  * Implementation of these memory-ordering guarantees is described here:
-  * Documentation/RCU/Design/Memory-Ordering/Tree-RCU-Memory-Ordering.rst.
-  */
- void call_rcu(struct rcu_head *head, rcu_callback_t func)
+ static void
+ __call_rcu_common(struct rcu_head *head, rcu_callback_t func, bool lazy)
  {
        static atomic_t doublefrees;
        unsigned long flags;
        }
  
        check_cb_ovld(rdp);
-       if (rcu_nocb_try_bypass(rdp, head, &was_alldone, flags))
+       if (rcu_nocb_try_bypass(rdp, head, &was_alldone, flags, lazy))
                return; // Enqueued onto ->nocb_bypass, so just leave.
        // If no-CBs CPU gets here, rcu_nocb_try_bypass() acquired ->nocb_lock.
        rcu_segcblist_enqueue(&rdp->cblist, head);
                local_irq_restore(flags);
        }
  }
- EXPORT_SYMBOL_GPL(call_rcu);
  
+ #ifdef CONFIG_RCU_LAZY
+ /**
+  * call_rcu_hurry() - Queue RCU callback for invocation after grace period, and
+  * flush all lazy callbacks (including the new one) to the main ->cblist while
+  * doing so.
+  *
+  * @head: structure to be used for queueing the RCU updates.
+  * @func: actual callback function to be invoked after the grace period
+  *
+  * The callback function will be invoked some time after a full grace
+  * period elapses, in other words after all pre-existing RCU read-side
+  * critical sections have completed.
+  *
+  * Use this API instead of call_rcu() if you don't want the callback to be
+  * invoked after very long periods of time, which can happen on systems without
+  * memory pressure and on systems which are lightly loaded or mostly idle.
+  * This function will cause callbacks to be invoked sooner than later at the
+  * expense of extra power. Other than that, this function is identical to, and
+  * reuses call_rcu()'s logic. Refer to call_rcu() for more details about memory
+  * ordering and other functionality.
+  */
+ void call_rcu_hurry(struct rcu_head *head, rcu_callback_t func)
+ {
+       return __call_rcu_common(head, func, false);
+ }
+ EXPORT_SYMBOL_GPL(call_rcu_hurry);
+ #endif
+ /**
+  * call_rcu() - Queue an RCU callback for invocation after a grace period.
+  * By default the callbacks are 'lazy' and are kept hidden from the main
+  * ->cblist to prevent starting of grace periods too soon.
+  * If you desire grace periods to start very soon, use call_rcu_hurry().
+  *
+  * @head: structure to be used for queueing the RCU updates.
+  * @func: actual callback function to be invoked after the grace period
+  *
+  * The callback function will be invoked some time after a full grace
+  * period elapses, in other words after all pre-existing RCU read-side
+  * critical sections have completed.  However, the callback function
+  * might well execute concurrently with RCU read-side critical sections
+  * that started after call_rcu() was invoked.
+  *
+  * RCU read-side critical sections are delimited by rcu_read_lock()
+  * and rcu_read_unlock(), and may be nested.  In addition, but only in
+  * v5.0 and later, regions of code across which interrupts, preemption,
+  * or softirqs have been disabled also serve as RCU read-side critical
+  * sections.  This includes hardware interrupt handlers, softirq handlers,
+  * and NMI handlers.
+  *
+  * Note that all CPUs must agree that the grace period extended beyond
+  * all pre-existing RCU read-side critical section.  On systems with more
+  * than one CPU, this means that when "func()" is invoked, each CPU is
+  * guaranteed to have executed a full memory barrier since the end of its
+  * last RCU read-side critical section whose beginning preceded the call
+  * to call_rcu().  It also means that each CPU executing an RCU read-side
+  * critical section that continues beyond the start of "func()" must have
+  * executed a memory barrier after the call_rcu() but before the beginning
+  * of that RCU read-side critical section.  Note that these guarantees
+  * include CPUs that are offline, idle, or executing in user mode, as
+  * well as CPUs that are executing in the kernel.
+  *
+  * Furthermore, if CPU A invoked call_rcu() and CPU B invoked the
+  * resulting RCU callback function "func()", then both CPU A and CPU B are
+  * guaranteed to execute a full memory barrier during the time interval
+  * between the call to call_rcu() and the invocation of "func()" -- even
+  * if CPU A and CPU B are the same CPU (but again only if the system has
+  * more than one CPU).
+  *
+  * Implementation of these memory-ordering guarantees is described here:
+  * Documentation/RCU/Design/Memory-Ordering/Tree-RCU-Memory-Ordering.rst.
+  */
+ void call_rcu(struct rcu_head *head, rcu_callback_t func)
+ {
+       return __call_rcu_common(head, func, IS_ENABLED(CONFIG_RCU_LAZY));
+ }
+ EXPORT_SYMBOL_GPL(call_rcu);
  
  /* Maximum number of jiffies to wait before draining a batch. */
  #define KFREE_DRAIN_JIFFIES (5 * HZ)
@@@ -3509,7 -3538,7 +3540,7 @@@ void synchronize_rcu(void
                if (rcu_gp_is_expedited())
                        synchronize_rcu_expedited();
                else
-                       wait_rcu_gp(call_rcu);
+                       wait_rcu_gp(call_rcu_hurry);
                return;
        }
  
@@@ -3896,6 -3925,8 +3927,8 @@@ static void rcu_barrier_entrain(struct 
  {
        unsigned long gseq = READ_ONCE(rcu_state.barrier_sequence);
        unsigned long lseq = READ_ONCE(rdp->barrier_seq_snap);
+       bool wake_nocb = false;
+       bool was_alldone = false;
  
        lockdep_assert_held(&rcu_state.barrier_lock);
        if (rcu_seq_state(lseq) || !rcu_seq_state(gseq) || rcu_seq_ctr(lseq) != rcu_seq_ctr(gseq))
        rdp->barrier_head.func = rcu_barrier_callback;
        debug_rcu_head_queue(&rdp->barrier_head);
        rcu_nocb_lock(rdp);
-       WARN_ON_ONCE(!rcu_nocb_flush_bypass(rdp, NULL, jiffies));
+       /*
+        * Flush bypass and wakeup rcuog if we add callbacks to an empty regular
+        * queue. This way we don't wait for bypass timer that can reach seconds
+        * if it's fully lazy.
+        */
+       was_alldone = rcu_rdp_is_offloaded(rdp) && !rcu_segcblist_pend_cbs(&rdp->cblist);
+       WARN_ON_ONCE(!rcu_nocb_flush_bypass(rdp, NULL, jiffies, false));
+       wake_nocb = was_alldone && rcu_segcblist_pend_cbs(&rdp->cblist);
        if (rcu_segcblist_entrain(&rdp->cblist, &rdp->barrier_head)) {
                atomic_inc(&rcu_state.barrier_cpu_count);
        } else {
                rcu_barrier_trace(TPS("IRQNQ"), -1, rcu_state.barrier_sequence);
        }
        rcu_nocb_unlock(rdp);
+       if (wake_nocb)
+               wake_nocb_gp(rdp, false);
        smp_store_release(&rdp->barrier_seq_snap, gseq);
  }
  
@@@ -4278,8 -4318,6 +4320,6 @@@ void rcu_report_dead(unsigned int cpu
        // Do any dangling deferred wakeups.
        do_nocb_deferred_wakeup(rdp);
  
-       /* QS for any half-done expedited grace period. */
-       rcu_report_exp_rdp(rdp);
        rcu_preempt_deferred_qs(current);
  
        /* Remove outgoing CPU from mask in the leaf rcu_node structure. */
@@@ -4327,7 -4365,7 +4367,7 @@@ void rcutree_migrate_callbacks(int cpu
        my_rdp = this_cpu_ptr(&rcu_data);
        my_rnp = my_rdp->mynode;
        rcu_nocb_lock(my_rdp); /* irqs already disabled. */
-       WARN_ON_ONCE(!rcu_nocb_flush_bypass(my_rdp, NULL, jiffies));
+       WARN_ON_ONCE(!rcu_nocb_flush_bypass(my_rdp, NULL, jiffies, false));
        raw_spin_lock_rcu_node(my_rnp); /* irqs already disabled. */
        /* Leverage recent GPs and set GP for new callbacks. */
        needwake = rcu_advance_cbs(my_rnp, rdp) ||
This page took 0.119224 seconds and 4 git commands to generate.