rcu: Make rcu_seq_diff() more exact
authorPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Sat, 9 Jun 2018 08:22:20 +0000 (01:22 -0700)
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Thu, 12 Jul 2018 22:39:23 +0000 (15:39 -0700)
The current implementatation of rcu_seq_diff() follows tradition in
providing a rough-and-ready approximation of the number of elapsed grace
periods between the two rcu_seq values.  However, this difference is
used to flag RCU-failure "near misses", which can be a valuable debugging
aid, so more exactitude would be an improvement.  This commit therefore
improves the accuracy of rcu_seq_diff().

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
kernel/rcu/rcu.h

index 89f13ff..d5e0294 100644 (file)
@@ -158,7 +158,20 @@ static inline bool rcu_seq_new_gp(unsigned long old, unsigned long new)
  */
 static inline unsigned long rcu_seq_diff(unsigned long new, unsigned long old)
 {
-       return (new - old) >> RCU_SEQ_CTR_SHIFT;
+       unsigned long rnd_diff;
+
+       if (old == new)
+               return 0;
+       /*
+        * Compute the number of grace periods (still shifted up), plus
+        * one if either of new and old is not an exact grace period.
+        */
+       rnd_diff = (new & ~RCU_SEQ_STATE_MASK) -
+                  ((old + RCU_SEQ_STATE_MASK) & ~RCU_SEQ_STATE_MASK) +
+                  ((new & RCU_SEQ_STATE_MASK) || (old & RCU_SEQ_STATE_MASK));
+       if (ULONG_CMP_GE(RCU_SEQ_STATE_MASK, rnd_diff))
+               return 1; /* Definitely no grace period has elapsed. */
+       return ((rnd_diff - RCU_SEQ_STATE_MASK - 1) >> RCU_SEQ_CTR_SHIFT) + 2;
 }
 
 /*