1. 14 Feb, 2024 3 commits
    • Frederic Weisbecker's avatar
      rcu/nocb: Make IRQs disablement symmetric · b913c3fe
      Frederic Weisbecker authored
      Currently IRQs are disabled on call_rcu() and then depending on the
      context:
      
      * If the CPU is in nocb mode:
      
         - If the callback is enqueued in the bypass list, IRQs are re-enabled
           implictly by rcu_nocb_try_bypass()
      
         - If the callback is enqueued in the normal list, IRQs are re-enabled
           implicitly by __call_rcu_nocb_wake()
      
      * If the CPU is NOT in nocb mode, IRQs are reenabled explicitly from call_rcu()
      
      This makes the code a bit hard to follow, especially as it interleaves
      with nocb locking.
      
      To make the IRQ flags coverage clearer and also in order to prepare for
      moving all the nocb enqueue code to its own function, always re-enable
      the IRQ flags explicitly from call_rcu().
      Reviewed-by: default avatarNeeraj Upadhyay (AMD) <neeraj.iitr10@gmail.com>
      Signed-off-by: default avatarFrederic Weisbecker <frederic@kernel.org>
      Reviewed-by: default avatarPaul E. McKenney <paulmck@kernel.org>
      Signed-off-by: default avatarBoqun Feng <boqun.feng@gmail.com>
      b913c3fe
    • Frederic Weisbecker's avatar
      rcu/nocb: Remove needless full barrier after callback advancing · 1e8e6951
      Frederic Weisbecker authored
      A full barrier is issued from nocb_gp_wait() upon callbacks advancing
      to order grace period completion with callbacks execution.
      
      However these two events are already ordered by the
      smp_mb__after_unlock_lock() barrier within the call to
      raw_spin_lock_rcu_node() that is necessary for callbacks advancing to
      happen.
      
      The following litmus test shows the kind of guarantee that this barrier
      provides:
      
      	C smp_mb__after_unlock_lock
      
      	{}
      
      	// rcu_gp_cleanup()
      	P0(spinlock_t *rnp_lock, int *gpnum)
      	{
      		// Grace period cleanup increase gp sequence number
      		spin_lock(rnp_lock);
      		WRITE_ONCE(*gpnum, 1);
      		spin_unlock(rnp_lock);
      	}
      
      	// nocb_gp_wait()
      	P1(spinlock_t *rnp_lock, spinlock_t *nocb_lock, int *gpnum, int *cb_ready)
      	{
      		int r1;
      
      		// Call rcu_advance_cbs() from nocb_gp_wait()
      		spin_lock(nocb_lock);
      		spin_lock(rnp_lock);
      		smp_mb__after_unlock_lock();
      		r1 = READ_ONCE(*gpnum);
      		WRITE_ONCE(*cb_ready, 1);
      		spin_unlock(rnp_lock);
      		spin_unlock(nocb_lock);
      	}
      
      	// nocb_cb_wait()
      	P2(spinlock_t *nocb_lock, int *cb_ready, int *cb_executed)
      	{
      		int r2;
      
      		// rcu_do_batch() -> rcu_segcblist_extract_done_cbs()
      		spin_lock(nocb_lock);
      		r2 = READ_ONCE(*cb_ready);
      		spin_unlock(nocb_lock);
      
      		// Actual callback execution
      		WRITE_ONCE(*cb_executed, 1);
      	}
      
      	P3(int *cb_executed, int *gpnum)
      	{
      		int r3;
      
      		WRITE_ONCE(*cb_executed, 2);
      		smp_mb();
      		r3 = READ_ONCE(*gpnum);
      	}
      
      	exists (1:r1=1 /\ 2:r2=1 /\ cb_executed=2 /\ 3:r3=0) (* Bad outcome. *)
      
      Here the bad outcome only occurs if the smp_mb__after_unlock_lock() is
      removed. This barrier orders the grace period completion against
      callbacks advancing and even later callbacks invocation, thanks to the
      opportunistic propagation via the ->nocb_lock to nocb_cb_wait().
      
      Therefore the smp_mb() placed after callbacks advancing can be safely
      removed.
      Signed-off-by: default avatarFrederic Weisbecker <frederic@kernel.org>
      Reviewed-by: default avatarPaul E. McKenney <paulmck@kernel.org>
      Signed-off-by: default avatarBoqun Feng <boqun.feng@gmail.com>
      1e8e6951
    • Frederic Weisbecker's avatar
      rcu/nocb: Remove needless LOAD-ACQUIRE · ca16265a
      Frederic Weisbecker authored
      The LOAD-ACQUIRE access performed on rdp->nocb_cb_sleep advertizes
      ordering callback execution against grace period completion. However
      this is contradicted by the following:
      
      * This LOAD-ACQUIRE doesn't pair with anything. The only counterpart
        barrier that can be found is the smp_mb() placed after callbacks
        advancing in nocb_gp_wait(). However the barrier is placed _after_
        ->nocb_cb_sleep write.
      
      * Callbacks can be concurrently advanced between the LOAD-ACQUIRE on
        ->nocb_cb_sleep and the call to rcu_segcblist_extract_done_cbs() in
        rcu_do_batch(), making any ordering based on ->nocb_cb_sleep broken.
      
      * Both rcu_segcblist_extract_done_cbs() and rcu_advance_cbs() are called
        under the nocb_lock, the latter hereby providing already the desired
        ACQUIRE semantics.
      
      Therefore it is safe to access ->nocb_cb_sleep with a simple compiler
      barrier.
      Signed-off-by: default avatarFrederic Weisbecker <frederic@kernel.org>
      Reviewed-by: default avatarPaul E. McKenney <paulmck@kernel.org>
      Signed-off-by: default avatarBoqun Feng <boqun.feng@gmail.com>
      ca16265a
  2. 29 Jan, 2024 1 commit
  3. 28 Jan, 2024 7 commits
  4. 27 Jan, 2024 9 commits
  5. 26 Jan, 2024 20 commits