]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
rcu: Warn when srcu_read_lock() is used in an extended quiescent state
authorPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Fri, 24 Jun 2011 03:48:04 +0000 (20:48 -0700)
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Tue, 13 Sep 2011 15:46:40 +0000 (08:46 -0700)
Catch SRCU up to the other variants of RCU by making PROVE_RCU
complain if either srcu_read_lock() or srcu_read_lock_held() are
used from within dyntick-idle mode.

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

index 58971e891f489950102d41f75bea118a22604f23..fcbaee7602346b2b738a44f03d4057a63cfc31d3 100644 (file)
@@ -28,6 +28,7 @@
 #define _LINUX_SRCU_H
 
 #include <linux/mutex.h>
+#include <linux/rcupdate.h>
 
 struct srcu_struct_array {
        int c[2];
@@ -60,18 +61,10 @@ int __init_srcu_struct(struct srcu_struct *sp, const char *name,
        __init_srcu_struct((sp), #sp, &__srcu_key); \
 })
 
-# define srcu_read_acquire(sp) \
-               lock_acquire(&(sp)->dep_map, 0, 0, 2, 1, NULL, _THIS_IP_)
-# define srcu_read_release(sp) \
-               lock_release(&(sp)->dep_map, 1, _THIS_IP_)
-
 #else /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */
 
 int init_srcu_struct(struct srcu_struct *sp);
 
-# define srcu_read_acquire(sp)  do { } while (0)
-# define srcu_read_release(sp)  do { } while (0)
-
 #endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */
 
 void cleanup_srcu_struct(struct srcu_struct *sp);
@@ -90,11 +83,23 @@ long srcu_batches_completed(struct srcu_struct *sp);
  * read-side critical section.  In absence of CONFIG_DEBUG_LOCK_ALLOC,
  * this assumes we are in an SRCU read-side critical section unless it can
  * prove otherwise.
+ *
+ * Note that if the CPU is in an extended quiescent state, for example,
+ * if the CPU is in dyntick-idle mode, then rcu_read_lock_held() returns
+ * false even if the CPU did an rcu_read_lock().  The reason for this is
+ * that RCU ignores CPUs that are in extended quiescent states, so such
+ * a CPU is effectively never in an RCU read-side critical section
+ * regardless of what RCU primitives it invokes.  This state of affairs
+ * is required -- RCU would otherwise need to periodically wake up
+ * dyntick-idle CPUs, which would defeat the whole purpose of dyntick-idle
+ * mode.
  */
 static inline int srcu_read_lock_held(struct srcu_struct *sp)
 {
        if (debug_locks)
                return lock_is_held(&sp->dep_map);
+       if (rcu_check_extended_qs())
+               return 0;
        return 1;
 }
 
@@ -150,7 +155,7 @@ static inline int srcu_read_lock(struct srcu_struct *sp) __acquires(sp)
 {
        int retval = __srcu_read_lock(sp);
 
-       srcu_read_acquire(sp);
+       rcu_lock_acquire(&(sp)->dep_map);
        return retval;
 }
 
@@ -164,7 +169,7 @@ static inline int srcu_read_lock(struct srcu_struct *sp) __acquires(sp)
 static inline void srcu_read_unlock(struct srcu_struct *sp, int idx)
        __releases(sp)
 {
-       srcu_read_release(sp);
+       rcu_lock_release(&(sp)->dep_map);
        __srcu_read_unlock(sp, idx);
 }