+/*
+ * Using a two-subphases algorithm for architectures with smaller than 64-bit
+ * long-size to ensure we do not encounter an overflow bug.
+ */
+
+#if (BITS_PER_LONG < 64)
+void synchronize_rcu(void)
+{
+ unsigned long was_online;
+
+ was_online = rcu_reader.ctr;
+
+ /* All threads should read qparity before accessing data structure
+ * where new ptr points to.
+ */
+ /* Write new ptr before changing the qparity */
+ smp_mb();
+
+ /*
+ * Mark the writer thread offline to make sure we don't wait for
+ * our own quiescent state. This allows using synchronize_rcu() in
+ * threads registered as readers.
+ */
+ if (was_online)
+ STORE_SHARED(rcu_reader.ctr, 0);
+
+ mutex_lock(&rcu_gp_lock);
+
+ if (list_empty(®istry))
+ goto out;
+
+ /*
+ * Wait for previous parity to be empty of readers.
+ */
+ update_counter_and_wait(); /* 0 -> 1, wait readers in parity 0 */
+
+ /*
+ * Must finish waiting for quiescent state for parity 0 before
+ * committing next rcu_gp_ctr update to memory. Failure to do so could
+ * result in the writer waiting forever while new readers are always
+ * accessing data (no progress). Enforce compiler-order of load
+ * rcu_reader ctr before store to rcu_gp_ctr.
+ */
+ barrier();
+
+ /*
+ * Adding a smp_mb() which is _not_ formally required, but makes the
+ * model easier to understand. It does not have a big performance impact
+ * anyway, given this is the write-side.
+ */
+ smp_mb();
+
+ /*
+ * Wait for previous parity to be empty of readers.
+ */
+ update_counter_and_wait(); /* 1 -> 0, wait readers in parity 1 */
+out:
+ mutex_unlock(&rcu_gp_lock);
+
+ /*
+ * Finish waiting for reader threads before letting the old ptr being
+ * freed.
+ */
+ if (was_online)
+ _STORE_SHARED(rcu_reader.ctr, LOAD_SHARED(rcu_gp_ctr));
+ smp_mb();
+}
+#else /* !(BITS_PER_LONG < 64) */