]> nv-tegra.nvidia Code Review - linux-2.6.git/blobdiff - kernel/srcu.c
printk: do not handle non-sleepable notification in console_cpu_notify
[linux-2.6.git] / kernel / srcu.c
index b0aeeaf22ce49c8c76098aac5224b1f4c44d4c4d..73ce23feaea9d27fb79d36b23fba4ad9e8c428aa 100644 (file)
 #include <linux/preempt.h>
 #include <linux/rcupdate.h>
 #include <linux/sched.h>
-#include <linux/slab.h>
 #include <linux/smp.h>
+#include <linux/delay.h>
 #include <linux/srcu.h>
 
+static int init_srcu_struct_fields(struct srcu_struct *sp)
+{
+       sp->completed = 0;
+       mutex_init(&sp->mutex);
+       sp->per_cpu_ref = alloc_percpu(struct srcu_struct_array);
+       return sp->per_cpu_ref ? 0 : -ENOMEM;
+}
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+
+int __init_srcu_struct(struct srcu_struct *sp, const char *name,
+                      struct lock_class_key *key)
+{
+       /* Don't re-initialize a lock while it is held. */
+       debug_check_no_locks_freed((void *)sp, sizeof(*sp));
+       lockdep_init_map(&sp->dep_map, name, key, 0);
+       return init_srcu_struct_fields(sp);
+}
+EXPORT_SYMBOL_GPL(__init_srcu_struct);
+
+#else /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */
+
 /**
  * init_srcu_struct - initialize a sleep-RCU structure
  * @sp: structure to initialize.
  */
 int init_srcu_struct(struct srcu_struct *sp)
 {
-       sp->completed = 0;
-       mutex_init(&sp->mutex);
-       sp->per_cpu_ref = alloc_percpu(struct srcu_struct_array);
-       return (sp->per_cpu_ref ? 0 : -ENOMEM);
+       return init_srcu_struct_fields(sp);
 }
+EXPORT_SYMBOL_GPL(init_srcu_struct);
+
+#endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */
 
 /*
  * srcu_readers_active_idx -- returns approximate number of readers
@@ -97,16 +119,14 @@ void cleanup_srcu_struct(struct srcu_struct *sp)
        free_percpu(sp->per_cpu_ref);
        sp->per_cpu_ref = NULL;
 }
+EXPORT_SYMBOL_GPL(cleanup_srcu_struct);
 
-/**
- * srcu_read_lock - register a new reader for an SRCU-protected structure.
- * @sp: srcu_struct in which to register the new reader.
- *
+/*
  * Counts the new reader in the appropriate per-CPU element of the
  * srcu_struct.  Must be called from process context.
  * Returns an index that must be passed to the matching srcu_read_unlock().
  */
-int srcu_read_lock(struct srcu_struct *sp)
+int __srcu_read_lock(struct srcu_struct *sp)
 {
        int idx;
 
@@ -118,40 +138,37 @@ int srcu_read_lock(struct srcu_struct *sp)
        preempt_enable();
        return idx;
 }
+EXPORT_SYMBOL_GPL(__srcu_read_lock);
 
-/**
- * srcu_read_unlock - unregister a old reader from an SRCU-protected structure.
- * @sp: srcu_struct in which to unregister the old reader.
- * @idx: return value from corresponding srcu_read_lock().
- *
+/*
  * Removes the count for the old reader from the appropriate per-CPU
  * element of the srcu_struct.  Note that this may well be a different
  * CPU than that which was incremented by the corresponding srcu_read_lock().
  * Must be called from process context.
  */
-void srcu_read_unlock(struct srcu_struct *sp, int idx)
+void __srcu_read_unlock(struct srcu_struct *sp, int idx)
 {
        preempt_disable();
        srcu_barrier();  /* ensure compiler won't misorder critical section. */
        per_cpu_ptr(sp->per_cpu_ref, smp_processor_id())->c[idx]--;
        preempt_enable();
 }
+EXPORT_SYMBOL_GPL(__srcu_read_unlock);
 
-/**
- * synchronize_srcu - wait for prior SRCU read-side critical-section completion
- * @sp: srcu_struct with which to synchronize.
- *
- * Flip the completed counter, and wait for the old count to drain to zero.
- * As with classic RCU, the updater must use some separate means of
- * synchronizing concurrent updates.  Can block; must be called from
- * process context.
- *
- * Note that it is illegal to call synchornize_srcu() from the corresponding
- * SRCU read-side critical section; doing so will result in deadlock.
- * However, it is perfectly legal to call synchronize_srcu() on one
- * srcu_struct from some other srcu_struct's read-side critical section.
+/*
+ * We use an adaptive strategy for synchronize_srcu() and especially for
+ * synchronize_srcu_expedited().  We spin for a fixed time period
+ * (defined below) to allow SRCU readers to exit their read-side critical
+ * sections.  If there are still some readers after 10 microseconds,
+ * we repeatedly block for 1-millisecond time periods.  This approach
+ * has done well in testing, so there is no need for a config parameter.
  */
-void synchronize_srcu(struct srcu_struct *sp)
+#define SYNCHRONIZE_SRCU_READER_DELAY 10
+
+/*
+ * Helper function for synchronize_srcu() and synchronize_srcu_expedited().
+ */
+static void __synchronize_srcu(struct srcu_struct *sp, void (*sync_func)(void))
 {
        int idx;
 
@@ -173,7 +190,7 @@ void synchronize_srcu(struct srcu_struct *sp)
                return;
        }
 
-       synchronize_sched();  /* Force memory barrier on all CPUs. */
+       sync_func();  /* Force memory barrier on all CPUs. */
 
        /*
         * The preceding synchronize_sched() ensures that any CPU that
@@ -190,20 +207,26 @@ void synchronize_srcu(struct srcu_struct *sp)
        idx = sp->completed & 0x1;
        sp->completed++;
 
-       synchronize_sched();  /* Force memory barrier on all CPUs. */
+       sync_func();  /* Force memory barrier on all CPUs. */
 
        /*
         * At this point, because of the preceding synchronize_sched(),
         * all srcu_read_lock() calls using the old counters have completed.
         * Their corresponding critical sections might well be still
         * executing, but the srcu_read_lock() primitives themselves
-        * will have finished executing.
+        * will have finished executing.  We initially give readers
+        * an arbitrarily chosen 10 microseconds to get out of their
+        * SRCU read-side critical sections, then loop waiting 1/HZ
+        * seconds per iteration.  The 10-microsecond value has done
+        * very well in testing.
         */
 
+       if (srcu_readers_active_idx(sp, idx))
+               udelay(SYNCHRONIZE_SRCU_READER_DELAY);
        while (srcu_readers_active_idx(sp, idx))
                schedule_timeout_interruptible(1);
 
-       synchronize_sched();  /* Force memory barrier on all CPUs. */
+       sync_func();  /* Force memory barrier on all CPUs. */
 
        /*
         * The preceding synchronize_sched() forces all srcu_read_unlock()
@@ -236,6 +259,47 @@ void synchronize_srcu(struct srcu_struct *sp)
        mutex_unlock(&sp->mutex);
 }
 
+/**
+ * synchronize_srcu - wait for prior SRCU read-side critical-section completion
+ * @sp: srcu_struct with which to synchronize.
+ *
+ * Flip the completed counter, and wait for the old count to drain to zero.
+ * As with classic RCU, the updater must use some separate means of
+ * synchronizing concurrent updates.  Can block; must be called from
+ * process context.
+ *
+ * Note that it is illegal to call synchronize_srcu() from the corresponding
+ * SRCU read-side critical section; doing so will result in deadlock.
+ * However, it is perfectly legal to call synchronize_srcu() on one
+ * srcu_struct from some other srcu_struct's read-side critical section.
+ */
+void synchronize_srcu(struct srcu_struct *sp)
+{
+       __synchronize_srcu(sp, synchronize_sched);
+}
+EXPORT_SYMBOL_GPL(synchronize_srcu);
+
+/**
+ * synchronize_srcu_expedited - like synchronize_srcu, but less patient
+ * @sp: srcu_struct with which to synchronize.
+ *
+ * Flip the completed counter, and wait for the old count to drain to zero.
+ * As with classic RCU, the updater must use some separate means of
+ * synchronizing concurrent updates.  Can block; must be called from
+ * process context.
+ *
+ * Note that it is illegal to call synchronize_srcu_expedited()
+ * from the corresponding SRCU read-side critical section; doing so
+ * will result in deadlock.  However, it is perfectly legal to call
+ * synchronize_srcu_expedited() on one srcu_struct from some other
+ * srcu_struct's read-side critical section.
+ */
+void synchronize_srcu_expedited(struct srcu_struct *sp)
+{
+       __synchronize_srcu(sp, synchronize_sched_expedited);
+}
+EXPORT_SYMBOL_GPL(synchronize_srcu_expedited);
+
 /**
  * srcu_batches_completed - return batches completed.
  * @sp: srcu_struct on which to report batch completion.
@@ -248,10 +312,4 @@ long srcu_batches_completed(struct srcu_struct *sp)
 {
        return sp->completed;
 }
-
-EXPORT_SYMBOL_GPL(init_srcu_struct);
-EXPORT_SYMBOL_GPL(cleanup_srcu_struct);
-EXPORT_SYMBOL_GPL(srcu_read_lock);
-EXPORT_SYMBOL_GPL(srcu_read_unlock);
-EXPORT_SYMBOL_GPL(synchronize_srcu);
 EXPORT_SYMBOL_GPL(srcu_batches_completed);