[PATCH RFC 05/16] rcuperf: Add PRCU test config files

2018-01-23 Thread lianglihao
From: Lihao Liang 

Use the same config file of TREE.

Signed-off-by: Lihao Liang 
---
 .../selftests/rcutorture/configs/rcuperf/CFLIST  |  1 +
 .../selftests/rcutorture/configs/rcuperf/PRCU| 20 
 .../selftests/rcutorture/configs/rcuperf/PRCU.boot   |  1 +
 3 files changed, 22 insertions(+)
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcuperf/PRCU
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcuperf/PRCU.boot

diff --git a/tools/testing/selftests/rcutorture/configs/rcuperf/CFLIST 
b/tools/testing/selftests/rcutorture/configs/rcuperf/CFLIST
index c9f56cf2..4b80917a 100644
--- a/tools/testing/selftests/rcutorture/configs/rcuperf/CFLIST
+++ b/tools/testing/selftests/rcutorture/configs/rcuperf/CFLIST
@@ -1 +1,2 @@
 TREE
+PRCU
diff --git a/tools/testing/selftests/rcutorture/configs/rcuperf/PRCU 
b/tools/testing/selftests/rcutorture/configs/rcuperf/PRCU
new file mode 100644
index ..a312f671
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcuperf/PRCU
@@ -0,0 +1,20 @@
+CONFIG_SMP=y
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+#CHECK#CONFIG_PREEMPT_RCU=y
+CONFIG_HZ_PERIODIC=n
+CONFIG_NO_HZ_IDLE=y
+CONFIG_NO_HZ_FULL=n
+CONFIG_RCU_FAST_NO_HZ=n
+CONFIG_RCU_TRACE=n
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_RCU_NOCB_CPU=n
+CONFIG_DEBUG_LOCK_ALLOC=n
+CONFIG_PROVE_LOCKING=n
+CONFIG_RCU_BOOST=n
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
+CONFIG_RCU_EXPERT=y
+CONFIG_RCU_TRACE=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcuperf/PRCU.boot 
b/tools/testing/selftests/rcutorture/configs/rcuperf/PRCU.boot
new file mode 100644
index ..7e54ea55
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcuperf/PRCU.boot
@@ -0,0 +1 @@
+rcuperf.perf_type=prcu
-- 
2.14.1.729.g59c0ea183



[PATCH RFC 05/16] rcuperf: Add PRCU test config files

2018-01-23 Thread lianglihao
From: Lihao Liang 

Use the same config file of TREE.

Signed-off-by: Lihao Liang 
---
 .../selftests/rcutorture/configs/rcuperf/CFLIST  |  1 +
 .../selftests/rcutorture/configs/rcuperf/PRCU| 20 
 .../selftests/rcutorture/configs/rcuperf/PRCU.boot   |  1 +
 3 files changed, 22 insertions(+)
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcuperf/PRCU
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcuperf/PRCU.boot

diff --git a/tools/testing/selftests/rcutorture/configs/rcuperf/CFLIST 
b/tools/testing/selftests/rcutorture/configs/rcuperf/CFLIST
index c9f56cf2..4b80917a 100644
--- a/tools/testing/selftests/rcutorture/configs/rcuperf/CFLIST
+++ b/tools/testing/selftests/rcutorture/configs/rcuperf/CFLIST
@@ -1 +1,2 @@
 TREE
+PRCU
diff --git a/tools/testing/selftests/rcutorture/configs/rcuperf/PRCU 
b/tools/testing/selftests/rcutorture/configs/rcuperf/PRCU
new file mode 100644
index ..a312f671
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcuperf/PRCU
@@ -0,0 +1,20 @@
+CONFIG_SMP=y
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+#CHECK#CONFIG_PREEMPT_RCU=y
+CONFIG_HZ_PERIODIC=n
+CONFIG_NO_HZ_IDLE=y
+CONFIG_NO_HZ_FULL=n
+CONFIG_RCU_FAST_NO_HZ=n
+CONFIG_RCU_TRACE=n
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_RCU_NOCB_CPU=n
+CONFIG_DEBUG_LOCK_ALLOC=n
+CONFIG_PROVE_LOCKING=n
+CONFIG_RCU_BOOST=n
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
+CONFIG_RCU_EXPERT=y
+CONFIG_RCU_TRACE=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcuperf/PRCU.boot 
b/tools/testing/selftests/rcutorture/configs/rcuperf/PRCU.boot
new file mode 100644
index ..7e54ea55
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcuperf/PRCU.boot
@@ -0,0 +1 @@
+rcuperf.perf_type=prcu
-- 
2.14.1.729.g59c0ea183



[PATCH RFC 00/16] A new RCU implementation based on a fast consensus protocol

2018-01-23 Thread lianglihao
From: Lihao Liang 

Dear Paul,

This patch set implements a preemptive version of RCU (PRCU) based on the 
following paper:

Fast Consensus Using Bounded Staleness for Scalable Read-mostly Synchronization.
Haibo Chen, Heng Zhang, Ran Liu, Binyu Zang, and Haibing Guan.
IEEE Transactions on Parallel and Distributed Systems (TPDS), 2016.
https://dl.acm.org/citation.cfm?id=3024114.3024143

We have also added preliminary callback-handling support.  Thus, the current 
version
provides APIs prcu_read_lock(), prcu_read_unlock(), synchronize_prcu(), 
call_prcu(),
and prcu_barrier().

This is an experimental patch, so it would be good to have some feedback.

Known shortcoming is that the grace-period version is incremented in 
synchronize_prcu().
If call_prcu() or prcu_barrier() is called but there is no synchronized_prcu() 
invoked,
callbacks cannot be invoked.  Later version should address this issue, e.g. 
adding a
grace-period expedition mechanism.  Others include to use a a hierarchical 
structure,
taking into account the NUMA topology, to send IPI in synchronize_prcu().

We have tested the implementation using rcutorture on both an x86 and ARM64 
machine.
PRCU passed 1h and 3h tests on all the newly added config files except PRCU07 
reported BUG 
in a 1h run.

[ 1593.604201] ---[ end trace b3bae911bec86152 ]---
[ 1594.629450] prcu-torture:torture_onoff task: offlining 14
[ 1594.73] smpboot: CPU 14 is now offline
[ 1594.757732] prcu-torture:torture_onoff task: offlined 14
[ 1597.765149] prcu-torture:torture_onoff task: onlining 11
[ 1597.766795] smpboot: Booting Node 0 Processor 11 APIC 0xb
[ 1597.804102] prcu-torture:torture_onoff task: onlined 11
[ 1599.365098] prcu-torture: rtc: b0277b90 ver: 66358 tfle: 0 rta: 
66358 rtaf: 0 
rtf: 66349 rtmbe: 0 rtbe: 1 rtbke: 0 rtbre: 0 rtbf: 0 rtb: 0 nt: 2233418 
onoff: 191/191:199/199 34,199:59,5102 10403:0 (HZ=1000) barrier: 188/189:1 
cbflood: 225
[ 1599.367946] prcu-torture: !!!
[ 1599.367966] [ cut here ]


We have also compared PRCU with TREE RCU using rcuperf with gp_exp set to true, 
that is
synchronize_rcu_expedited was tested.

The rcuperf results are as follows (average grace-period duration in ms of ten 
10min runs):

16*Intel Xeon CPU@2.4GHz, 16GB memory, Ubuntu Linux 3.13.0-47-generic

CPUs  2   4   8  12  15   16
PRCU   0.141.074.158.02   10.7915.16 
TREE  49.30  104.75  277.55  390.82  620.82  1381.54

64*Cortex-A72 CPU@2.4GHz, 130GB memory, Ubuntu Linux 4.10.0-21.23-generic

CPUs   2   48  16  32   48   6364
PRCU0.23   19.6938.28   63.21   95.41   167.18   252.01   1841.44
TREE  416.73  901.89  1060.86  743.00  920.66  1325.21  1646.20  23806.27

Best wishes,
Lihao.


Lihao Liang (15):
  rcutorture: Add PRCU rcu_torture_ops
  rcutorture: Add PRCU test config files
  rcuperf: Add PRCU rcu_perf_ops
  rcuperf: Add PRCU test config files
  rcuperf: Set gp_exp to true for tests to run
  prcu: Implement call_prcu() API
  prcu: Implement PRCU callback processing
  prcu: Implement prcu_barrier() API
  rcutorture: Test call_prcu() and prcu_barrier()
  rcutorture: Add basic ARM64 support to run scripts
  prcu: Add PRCU Kconfig parameter
  prcu: Comment source code
  rcuperf: Add config files with various CONFIG_NR_CPUS
  rcutorture: Add scripts to run experiments
  Add GPLv2 license

Heng Zhang (1):
  prcu: Add PRCU implementation

 include/linux/interrupt.h  |   3 +
 include/linux/prcu.h   | 122 +
 include/linux/rcupdate.h   |   1 +
 init/Kconfig   |   7 +
 init/main.c|   2 +
 kernel/rcu/Makefile|   1 +
 kernel/rcu/prcu.c  | 497 +
 kernel/rcu/rcuperf.c   |  33 +-
 kernel/rcu/rcutorture.c|  40 +-
 kernel/rcu/tree.c  |   1 +
 kernel/sched/core.c|   2 +
 kernel/time/timer.c|   2 +
 kvm.sh | 452 +++
 run-rcuperf.sh |  26 ++
 .../testing/selftests/rcutorture/bin/functions.sh  |  17 +-
 .../selftests/rcutorture/configs/rcu/CFLIST|   5 +
 .../selftests/rcutorture/configs/rcu/PRCU02|  27 ++
 .../selftests/rcutorture/configs/rcu/PRCU02.boot   |   1 +
 .../selftests/rcutorture/configs/rcu/PRCU03|  23 +
 .../selftests/rcutorture/configs/rcu/PRCU03.boot   |   2 +
 .../selftests/rcutorture/configs/rcu/PRCU06|  26 ++
 .../selftests/rcutorture/configs/rcu/PRCU06.boot   |   5 +
 .../selftests/rcutorture/configs/rcu/PRCU07|  25 ++
 .../selftests/rcutorture/configs/rcu/PRCU07.boot   |   2 +
 

[PATCH RFC 00/16] A new RCU implementation based on a fast consensus protocol

2018-01-23 Thread lianglihao
From: Lihao Liang 

Dear Paul,

This patch set implements a preemptive version of RCU (PRCU) based on the 
following paper:

Fast Consensus Using Bounded Staleness for Scalable Read-mostly Synchronization.
Haibo Chen, Heng Zhang, Ran Liu, Binyu Zang, and Haibing Guan.
IEEE Transactions on Parallel and Distributed Systems (TPDS), 2016.
https://dl.acm.org/citation.cfm?id=3024114.3024143

We have also added preliminary callback-handling support.  Thus, the current 
version
provides APIs prcu_read_lock(), prcu_read_unlock(), synchronize_prcu(), 
call_prcu(),
and prcu_barrier().

This is an experimental patch, so it would be good to have some feedback.

Known shortcoming is that the grace-period version is incremented in 
synchronize_prcu().
If call_prcu() or prcu_barrier() is called but there is no synchronized_prcu() 
invoked,
callbacks cannot be invoked.  Later version should address this issue, e.g. 
adding a
grace-period expedition mechanism.  Others include to use a a hierarchical 
structure,
taking into account the NUMA topology, to send IPI in synchronize_prcu().

We have tested the implementation using rcutorture on both an x86 and ARM64 
machine.
PRCU passed 1h and 3h tests on all the newly added config files except PRCU07 
reported BUG 
in a 1h run.

[ 1593.604201] ---[ end trace b3bae911bec86152 ]---
[ 1594.629450] prcu-torture:torture_onoff task: offlining 14
[ 1594.73] smpboot: CPU 14 is now offline
[ 1594.757732] prcu-torture:torture_onoff task: offlined 14
[ 1597.765149] prcu-torture:torture_onoff task: onlining 11
[ 1597.766795] smpboot: Booting Node 0 Processor 11 APIC 0xb
[ 1597.804102] prcu-torture:torture_onoff task: onlined 11
[ 1599.365098] prcu-torture: rtc: b0277b90 ver: 66358 tfle: 0 rta: 
66358 rtaf: 0 
rtf: 66349 rtmbe: 0 rtbe: 1 rtbke: 0 rtbre: 0 rtbf: 0 rtb: 0 nt: 2233418 
onoff: 191/191:199/199 34,199:59,5102 10403:0 (HZ=1000) barrier: 188/189:1 
cbflood: 225
[ 1599.367946] prcu-torture: !!!
[ 1599.367966] [ cut here ]


We have also compared PRCU with TREE RCU using rcuperf with gp_exp set to true, 
that is
synchronize_rcu_expedited was tested.

The rcuperf results are as follows (average grace-period duration in ms of ten 
10min runs):

16*Intel Xeon CPU@2.4GHz, 16GB memory, Ubuntu Linux 3.13.0-47-generic

CPUs  2   4   8  12  15   16
PRCU   0.141.074.158.02   10.7915.16 
TREE  49.30  104.75  277.55  390.82  620.82  1381.54

64*Cortex-A72 CPU@2.4GHz, 130GB memory, Ubuntu Linux 4.10.0-21.23-generic

CPUs   2   48  16  32   48   6364
PRCU0.23   19.6938.28   63.21   95.41   167.18   252.01   1841.44
TREE  416.73  901.89  1060.86  743.00  920.66  1325.21  1646.20  23806.27

Best wishes,
Lihao.


Lihao Liang (15):
  rcutorture: Add PRCU rcu_torture_ops
  rcutorture: Add PRCU test config files
  rcuperf: Add PRCU rcu_perf_ops
  rcuperf: Add PRCU test config files
  rcuperf: Set gp_exp to true for tests to run
  prcu: Implement call_prcu() API
  prcu: Implement PRCU callback processing
  prcu: Implement prcu_barrier() API
  rcutorture: Test call_prcu() and prcu_barrier()
  rcutorture: Add basic ARM64 support to run scripts
  prcu: Add PRCU Kconfig parameter
  prcu: Comment source code
  rcuperf: Add config files with various CONFIG_NR_CPUS
  rcutorture: Add scripts to run experiments
  Add GPLv2 license

Heng Zhang (1):
  prcu: Add PRCU implementation

 include/linux/interrupt.h  |   3 +
 include/linux/prcu.h   | 122 +
 include/linux/rcupdate.h   |   1 +
 init/Kconfig   |   7 +
 init/main.c|   2 +
 kernel/rcu/Makefile|   1 +
 kernel/rcu/prcu.c  | 497 +
 kernel/rcu/rcuperf.c   |  33 +-
 kernel/rcu/rcutorture.c|  40 +-
 kernel/rcu/tree.c  |   1 +
 kernel/sched/core.c|   2 +
 kernel/time/timer.c|   2 +
 kvm.sh | 452 +++
 run-rcuperf.sh |  26 ++
 .../testing/selftests/rcutorture/bin/functions.sh  |  17 +-
 .../selftests/rcutorture/configs/rcu/CFLIST|   5 +
 .../selftests/rcutorture/configs/rcu/PRCU02|  27 ++
 .../selftests/rcutorture/configs/rcu/PRCU02.boot   |   1 +
 .../selftests/rcutorture/configs/rcu/PRCU03|  23 +
 .../selftests/rcutorture/configs/rcu/PRCU03.boot   |   2 +
 .../selftests/rcutorture/configs/rcu/PRCU06|  26 ++
 .../selftests/rcutorture/configs/rcu/PRCU06.boot   |   5 +
 .../selftests/rcutorture/configs/rcu/PRCU07|  25 ++
 .../selftests/rcutorture/configs/rcu/PRCU07.boot   |   2 +
 .../selftests/rcutorture/configs/rcu/PRCU09

[PATCH RFC 01/16] prcu: Add PRCU implementation

2018-01-23 Thread lianglihao
From: Heng Zhang 

This RCU implementation (PRCU) is based on a fast consensus protocol
published in the following paper:

Fast Consensus Using Bounded Staleness for Scalable Read-mostly Synchronization.
Haibo Chen, Heng Zhang, Ran Liu, Binyu Zang, and Haibing Guan.
IEEE Transactions on Parallel and Distributed Systems (TPDS), 2016.
https://dl.acm.org/citation.cfm?id=3024114.3024143

Signed-off-by: Heng Zhang 
Signed-off-by: Lihao Liang 
---
 include/linux/prcu.h |  37 +++
 kernel/rcu/Makefile  |   2 +-
 kernel/rcu/prcu.c| 125 +++
 kernel/sched/core.c  |   2 +
 4 files changed, 165 insertions(+), 1 deletion(-)
 create mode 100644 include/linux/prcu.h
 create mode 100644 kernel/rcu/prcu.c

diff --git a/include/linux/prcu.h b/include/linux/prcu.h
new file mode 100644
index ..653b4633
--- /dev/null
+++ b/include/linux/prcu.h
@@ -0,0 +1,37 @@
+#ifndef __LINUX_PRCU_H
+#define __LINUX_PRCU_H
+
+#include 
+#include 
+#include 
+
+#define CONFIG_PRCU
+
+struct prcu_local_struct {
+   unsigned int locked;
+   unsigned int online;
+   unsigned long long version;
+};
+
+struct prcu_struct {
+   atomic64_t global_version;
+   atomic_t active_ctr;
+   struct mutex mtx;
+   wait_queue_head_t wait_q;
+};
+
+#ifdef CONFIG_PRCU
+void prcu_read_lock(void);
+void prcu_read_unlock(void);
+void synchronize_prcu(void);
+void prcu_note_context_switch(void);
+
+#else /* #ifdef CONFIG_PRCU */
+
+#define prcu_read_lock() do {} while (0)
+#define prcu_read_unlock() do {} while (0)
+#define synchronize_prcu() do {} while (0)
+#define prcu_note_context_switch() do {} while (0)
+
+#endif /* #ifdef CONFIG_PRCU */
+#endif /* __LINUX_PRCU_H */
diff --git a/kernel/rcu/Makefile b/kernel/rcu/Makefile
index 23803c7d..8791419c 100644
--- a/kernel/rcu/Makefile
+++ b/kernel/rcu/Makefile
@@ -2,7 +2,7 @@
 # and is generally not a function of system call inputs.
 KCOV_INSTRUMENT := n
 
-obj-y += update.o sync.o
+obj-y += update.o sync.o prcu.o
 obj-$(CONFIG_CLASSIC_SRCU) += srcu.o
 obj-$(CONFIG_TREE_SRCU) += srcutree.o
 obj-$(CONFIG_TINY_SRCU) += srcutiny.o
diff --git a/kernel/rcu/prcu.c b/kernel/rcu/prcu.c
new file mode 100644
index ..a00b9420
--- /dev/null
+++ b/kernel/rcu/prcu.c
@@ -0,0 +1,125 @@
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+DEFINE_PER_CPU_SHARED_ALIGNED(struct prcu_local_struct, prcu_local);
+
+struct prcu_struct global_prcu = {
+   .global_version = ATOMIC64_INIT(0),
+   .active_ctr = ATOMIC_INIT(0),
+   .mtx = __MUTEX_INITIALIZER(global_prcu.mtx),
+   .wait_q = __WAIT_QUEUE_HEAD_INITIALIZER(global_prcu.wait_q)
+};
+struct prcu_struct *prcu = _prcu;
+
+static inline void prcu_report(struct prcu_local_struct *local)
+{
+   unsigned long long global_version;
+   unsigned long long local_version;
+
+   global_version = atomic64_read(>global_version);
+   local_version = local->version;
+   if (global_version > local_version)
+   cmpxchg(>version, local_version, global_version);
+}
+
+void prcu_read_lock(void)
+{
+   struct prcu_local_struct *local;
+
+   local = get_cpu_ptr(_local);
+   if (!local->online) {
+   WRITE_ONCE(local->online, 1);
+   smp_mb();
+   }
+
+   local->locked++;
+   put_cpu_ptr(_local);
+}
+EXPORT_SYMBOL(prcu_read_lock);
+
+void prcu_read_unlock(void)
+{
+   int locked;
+   struct prcu_local_struct *local;
+
+   barrier();
+   local = get_cpu_ptr(_local);
+   locked = local->locked;
+   if (locked) {
+   local->locked--;
+   if (locked == 1)
+   prcu_report(local);
+   put_cpu_ptr(_local);
+   } else {
+   put_cpu_ptr(_local);
+   if (!atomic_dec_return(>active_ctr))
+   wake_up(>wait_q);
+   }
+}
+EXPORT_SYMBOL(prcu_read_unlock);
+
+static void prcu_handler(void *info)
+{
+   struct prcu_local_struct *local;
+
+   local = this_cpu_ptr(_local);
+   if (!local->locked)
+   WRITE_ONCE(local->version, 
atomic64_read(>global_version));
+}
+
+void synchronize_prcu(void)
+{
+   int cpu;
+   cpumask_t cpus;
+   unsigned long long version;
+   struct prcu_local_struct *local;
+
+   version = atomic64_add_return(1, >global_version);
+   mutex_lock(>mtx);
+
+   local = get_cpu_ptr(_local);
+   local->version = version;
+   put_cpu_ptr(_local);
+
+   cpumask_clear();
+   for_each_possible_cpu(cpu) {
+   local = per_cpu_ptr(_local, cpu);
+   if (!READ_ONCE(local->online))
+   continue;
+   if (READ_ONCE(local->version) < version) {
+   smp_call_function_single(cpu, prcu_handler, NULL, 0);
+   cpumask_set_cpu(cpu, );
+   }
+   }

[PATCH RFC 01/16] prcu: Add PRCU implementation

2018-01-23 Thread lianglihao
From: Heng Zhang 

This RCU implementation (PRCU) is based on a fast consensus protocol
published in the following paper:

Fast Consensus Using Bounded Staleness for Scalable Read-mostly Synchronization.
Haibo Chen, Heng Zhang, Ran Liu, Binyu Zang, and Haibing Guan.
IEEE Transactions on Parallel and Distributed Systems (TPDS), 2016.
https://dl.acm.org/citation.cfm?id=3024114.3024143

Signed-off-by: Heng Zhang 
Signed-off-by: Lihao Liang 
---
 include/linux/prcu.h |  37 +++
 kernel/rcu/Makefile  |   2 +-
 kernel/rcu/prcu.c| 125 +++
 kernel/sched/core.c  |   2 +
 4 files changed, 165 insertions(+), 1 deletion(-)
 create mode 100644 include/linux/prcu.h
 create mode 100644 kernel/rcu/prcu.c

diff --git a/include/linux/prcu.h b/include/linux/prcu.h
new file mode 100644
index ..653b4633
--- /dev/null
+++ b/include/linux/prcu.h
@@ -0,0 +1,37 @@
+#ifndef __LINUX_PRCU_H
+#define __LINUX_PRCU_H
+
+#include 
+#include 
+#include 
+
+#define CONFIG_PRCU
+
+struct prcu_local_struct {
+   unsigned int locked;
+   unsigned int online;
+   unsigned long long version;
+};
+
+struct prcu_struct {
+   atomic64_t global_version;
+   atomic_t active_ctr;
+   struct mutex mtx;
+   wait_queue_head_t wait_q;
+};
+
+#ifdef CONFIG_PRCU
+void prcu_read_lock(void);
+void prcu_read_unlock(void);
+void synchronize_prcu(void);
+void prcu_note_context_switch(void);
+
+#else /* #ifdef CONFIG_PRCU */
+
+#define prcu_read_lock() do {} while (0)
+#define prcu_read_unlock() do {} while (0)
+#define synchronize_prcu() do {} while (0)
+#define prcu_note_context_switch() do {} while (0)
+
+#endif /* #ifdef CONFIG_PRCU */
+#endif /* __LINUX_PRCU_H */
diff --git a/kernel/rcu/Makefile b/kernel/rcu/Makefile
index 23803c7d..8791419c 100644
--- a/kernel/rcu/Makefile
+++ b/kernel/rcu/Makefile
@@ -2,7 +2,7 @@
 # and is generally not a function of system call inputs.
 KCOV_INSTRUMENT := n
 
-obj-y += update.o sync.o
+obj-y += update.o sync.o prcu.o
 obj-$(CONFIG_CLASSIC_SRCU) += srcu.o
 obj-$(CONFIG_TREE_SRCU) += srcutree.o
 obj-$(CONFIG_TINY_SRCU) += srcutiny.o
diff --git a/kernel/rcu/prcu.c b/kernel/rcu/prcu.c
new file mode 100644
index ..a00b9420
--- /dev/null
+++ b/kernel/rcu/prcu.c
@@ -0,0 +1,125 @@
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+DEFINE_PER_CPU_SHARED_ALIGNED(struct prcu_local_struct, prcu_local);
+
+struct prcu_struct global_prcu = {
+   .global_version = ATOMIC64_INIT(0),
+   .active_ctr = ATOMIC_INIT(0),
+   .mtx = __MUTEX_INITIALIZER(global_prcu.mtx),
+   .wait_q = __WAIT_QUEUE_HEAD_INITIALIZER(global_prcu.wait_q)
+};
+struct prcu_struct *prcu = _prcu;
+
+static inline void prcu_report(struct prcu_local_struct *local)
+{
+   unsigned long long global_version;
+   unsigned long long local_version;
+
+   global_version = atomic64_read(>global_version);
+   local_version = local->version;
+   if (global_version > local_version)
+   cmpxchg(>version, local_version, global_version);
+}
+
+void prcu_read_lock(void)
+{
+   struct prcu_local_struct *local;
+
+   local = get_cpu_ptr(_local);
+   if (!local->online) {
+   WRITE_ONCE(local->online, 1);
+   smp_mb();
+   }
+
+   local->locked++;
+   put_cpu_ptr(_local);
+}
+EXPORT_SYMBOL(prcu_read_lock);
+
+void prcu_read_unlock(void)
+{
+   int locked;
+   struct prcu_local_struct *local;
+
+   barrier();
+   local = get_cpu_ptr(_local);
+   locked = local->locked;
+   if (locked) {
+   local->locked--;
+   if (locked == 1)
+   prcu_report(local);
+   put_cpu_ptr(_local);
+   } else {
+   put_cpu_ptr(_local);
+   if (!atomic_dec_return(>active_ctr))
+   wake_up(>wait_q);
+   }
+}
+EXPORT_SYMBOL(prcu_read_unlock);
+
+static void prcu_handler(void *info)
+{
+   struct prcu_local_struct *local;
+
+   local = this_cpu_ptr(_local);
+   if (!local->locked)
+   WRITE_ONCE(local->version, 
atomic64_read(>global_version));
+}
+
+void synchronize_prcu(void)
+{
+   int cpu;
+   cpumask_t cpus;
+   unsigned long long version;
+   struct prcu_local_struct *local;
+
+   version = atomic64_add_return(1, >global_version);
+   mutex_lock(>mtx);
+
+   local = get_cpu_ptr(_local);
+   local->version = version;
+   put_cpu_ptr(_local);
+
+   cpumask_clear();
+   for_each_possible_cpu(cpu) {
+   local = per_cpu_ptr(_local, cpu);
+   if (!READ_ONCE(local->online))
+   continue;
+   if (READ_ONCE(local->version) < version) {
+   smp_call_function_single(cpu, prcu_handler, NULL, 0);
+   cpumask_set_cpu(cpu, );
+   }
+   }
+
+   for_each_cpu(cpu, ) {
+   local = 

[PATCH RFC 04/16] rcuperf: Add PRCU rcu_perf_ops

2018-01-23 Thread lianglihao
From: Lihao Liang 

Signed-off-by: Lihao Liang 
---
 kernel/rcu/rcuperf.c | 31 ++-
 1 file changed, 30 insertions(+), 1 deletion(-)

diff --git a/kernel/rcu/rcuperf.c b/kernel/rcu/rcuperf.c
index a4a86fb4..ea80fa3e 100644
--- a/kernel/rcu/rcuperf.c
+++ b/kernel/rcu/rcuperf.c
@@ -28,6 +28,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -304,6 +305,34 @@ static bool __maybe_unused torturing_tasks(void)
 
 #endif /* #else #ifdef CONFIG_TASKS_RCU */
 
+/*
+ * Definitions for prcu perf testing.
+ */
+
+static int prcu_perf_read_lock(void) __acquires(RCU)
+{
+   prcu_read_lock();
+   return 0;
+}
+
+static void prcu_perf_read_unlock(int idx) __releases(RCU)
+{
+   prcu_read_unlock();
+}
+
+static struct rcu_perf_ops prcu_ops = {
+   .ptype  = PRCU_FLAVOR,
+   .init   = rcu_sync_perf_init,
+   .readlock   = prcu_perf_read_lock,
+   .readunlock = prcu_perf_read_unlock,
+   .started= rcu_no_completed,
+   .completed  = rcu_no_completed,
+   .exp_completed  = rcu_no_completed,
+   .sync   = synchronize_prcu,
+   .exp_sync   = synchronize_prcu,
+   .name   = "prcu"
+};
+
 /*
  * If performance tests complete, wait for shutdown to commence.
  */
@@ -554,7 +583,7 @@ rcu_perf_init(void)
long i;
int firsterr = 0;
static struct rcu_perf_ops *perf_ops[] = {
-   _ops, _bh_ops, _ops, _ops,
+   _ops, _bh_ops, _ops, _ops, _ops,
RCUPERF_TASKS_OPS
};
 
-- 
2.14.1.729.g59c0ea183



[PATCH RFC 02/16] rcutorture: Add PRCU rcu_torture_ops

2018-01-23 Thread lianglihao
From: Lihao Liang 

Reviewed-by: Heng Zhang 
Signed-off-by: Lihao Liang 
---
 include/linux/rcupdate.h |  1 +
 kernel/rcu/rcutorture.c  | 40 +++-
 2 files changed, 40 insertions(+), 1 deletion(-)

diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index e1e5d002..12df9709 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -84,6 +84,7 @@ enum rcutorture_type {
RCU_SCHED_FLAVOR,
RCU_TASKS_FLAVOR,
SRCU_FLAVOR,
+   PRCU_FLAVOR,
INVALID_RCU_FLAVOR
 };
 
diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c
index ae6e574d..7d65bf0c 100644
--- a/kernel/rcu/rcutorture.c
+++ b/kernel/rcu/rcutorture.c
@@ -46,6 +46,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -768,6 +769,43 @@ static bool __maybe_unused torturing_tasks(void)
 
 #endif /* #else #ifdef CONFIG_TASKS_RCU */
 
+/*
+ * Definitions for prcu torture testing.
+ */
+
+static int prcu_torture_read_lock(void) __acquires(RCU)
+{
+   prcu_read_lock();
+   return 0;
+}
+
+static void prcu_torture_read_unlock(int idx) __releases(RCU)
+{
+   prcu_read_unlock();
+}
+
+static struct rcu_torture_ops prcu_ops = {
+   .ttype  = PRCU_FLAVOR,
+   .init   = rcu_sync_torture_init,
+   .readlock   = prcu_torture_read_lock,
+   .read_delay = rcu_read_delay,  /* just reuse rcu's version. */
+   .readunlock = prcu_torture_read_unlock,
+   .started= rcu_no_completed,
+   .completed  = rcu_no_completed,
+   .deferred_free  = NULL,
+   .sync   = synchronize_prcu,
+   .exp_sync   = synchronize_prcu,
+   .get_state  = NULL,
+   .cond_sync  = NULL,
+   .call   = NULL,
+   .cb_barrier = NULL,
+   .fqs= NULL,
+   .stats  = NULL,
+   .irq_capable= 1,
+   .can_boost  = 0,
+   .name   = "prcu"
+};
+
 /*
  * RCU torture priority-boost testing.  Runs one real-time thread per
  * CPU for moderate bursts, repeatedly registering RCU callbacks and
@@ -1764,7 +1802,7 @@ rcu_torture_init(void)
int firsterr = 0;
static struct rcu_torture_ops *torture_ops[] = {
_ops, _bh_ops, _busted_ops, _ops, _ops,
-   _ops, RCUTORTURE_TASKS_OPS
+   _ops, _ops, RCUTORTURE_TASKS_OPS
};
 
if (!torture_init_begin(torture_type, verbose, _runnable))
-- 
2.14.1.729.g59c0ea183



[PATCH RFC 04/16] rcuperf: Add PRCU rcu_perf_ops

2018-01-23 Thread lianglihao
From: Lihao Liang 

Signed-off-by: Lihao Liang 
---
 kernel/rcu/rcuperf.c | 31 ++-
 1 file changed, 30 insertions(+), 1 deletion(-)

diff --git a/kernel/rcu/rcuperf.c b/kernel/rcu/rcuperf.c
index a4a86fb4..ea80fa3e 100644
--- a/kernel/rcu/rcuperf.c
+++ b/kernel/rcu/rcuperf.c
@@ -28,6 +28,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -304,6 +305,34 @@ static bool __maybe_unused torturing_tasks(void)
 
 #endif /* #else #ifdef CONFIG_TASKS_RCU */
 
+/*
+ * Definitions for prcu perf testing.
+ */
+
+static int prcu_perf_read_lock(void) __acquires(RCU)
+{
+   prcu_read_lock();
+   return 0;
+}
+
+static void prcu_perf_read_unlock(int idx) __releases(RCU)
+{
+   prcu_read_unlock();
+}
+
+static struct rcu_perf_ops prcu_ops = {
+   .ptype  = PRCU_FLAVOR,
+   .init   = rcu_sync_perf_init,
+   .readlock   = prcu_perf_read_lock,
+   .readunlock = prcu_perf_read_unlock,
+   .started= rcu_no_completed,
+   .completed  = rcu_no_completed,
+   .exp_completed  = rcu_no_completed,
+   .sync   = synchronize_prcu,
+   .exp_sync   = synchronize_prcu,
+   .name   = "prcu"
+};
+
 /*
  * If performance tests complete, wait for shutdown to commence.
  */
@@ -554,7 +583,7 @@ rcu_perf_init(void)
long i;
int firsterr = 0;
static struct rcu_perf_ops *perf_ops[] = {
-   _ops, _bh_ops, _ops, _ops,
+   _ops, _bh_ops, _ops, _ops, _ops,
RCUPERF_TASKS_OPS
};
 
-- 
2.14.1.729.g59c0ea183



[PATCH RFC 02/16] rcutorture: Add PRCU rcu_torture_ops

2018-01-23 Thread lianglihao
From: Lihao Liang 

Reviewed-by: Heng Zhang 
Signed-off-by: Lihao Liang 
---
 include/linux/rcupdate.h |  1 +
 kernel/rcu/rcutorture.c  | 40 +++-
 2 files changed, 40 insertions(+), 1 deletion(-)

diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index e1e5d002..12df9709 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -84,6 +84,7 @@ enum rcutorture_type {
RCU_SCHED_FLAVOR,
RCU_TASKS_FLAVOR,
SRCU_FLAVOR,
+   PRCU_FLAVOR,
INVALID_RCU_FLAVOR
 };
 
diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c
index ae6e574d..7d65bf0c 100644
--- a/kernel/rcu/rcutorture.c
+++ b/kernel/rcu/rcutorture.c
@@ -46,6 +46,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -768,6 +769,43 @@ static bool __maybe_unused torturing_tasks(void)
 
 #endif /* #else #ifdef CONFIG_TASKS_RCU */
 
+/*
+ * Definitions for prcu torture testing.
+ */
+
+static int prcu_torture_read_lock(void) __acquires(RCU)
+{
+   prcu_read_lock();
+   return 0;
+}
+
+static void prcu_torture_read_unlock(int idx) __releases(RCU)
+{
+   prcu_read_unlock();
+}
+
+static struct rcu_torture_ops prcu_ops = {
+   .ttype  = PRCU_FLAVOR,
+   .init   = rcu_sync_torture_init,
+   .readlock   = prcu_torture_read_lock,
+   .read_delay = rcu_read_delay,  /* just reuse rcu's version. */
+   .readunlock = prcu_torture_read_unlock,
+   .started= rcu_no_completed,
+   .completed  = rcu_no_completed,
+   .deferred_free  = NULL,
+   .sync   = synchronize_prcu,
+   .exp_sync   = synchronize_prcu,
+   .get_state  = NULL,
+   .cond_sync  = NULL,
+   .call   = NULL,
+   .cb_barrier = NULL,
+   .fqs= NULL,
+   .stats  = NULL,
+   .irq_capable= 1,
+   .can_boost  = 0,
+   .name   = "prcu"
+};
+
 /*
  * RCU torture priority-boost testing.  Runs one real-time thread per
  * CPU for moderate bursts, repeatedly registering RCU callbacks and
@@ -1764,7 +1802,7 @@ rcu_torture_init(void)
int firsterr = 0;
static struct rcu_torture_ops *torture_ops[] = {
_ops, _bh_ops, _busted_ops, _ops, _ops,
-   _ops, RCUTORTURE_TASKS_OPS
+   _ops, _ops, RCUTORTURE_TASKS_OPS
};
 
if (!torture_init_begin(torture_type, verbose, _runnable))
-- 
2.14.1.729.g59c0ea183



[PATCH RFC 16/16] Add GPLv2 license

2018-01-23 Thread lianglihao
From: Lihao Liang 

Signed-off-by: Lihao Liang 
---
 include/linux/prcu.h | 4 
 kernel/rcu/prcu.c| 4 
 2 files changed, 8 insertions(+)

diff --git a/include/linux/prcu.h b/include/linux/prcu.h
index 9f740985..9fa74dac 100644
--- a/include/linux/prcu.h
+++ b/include/linux/prcu.h
@@ -4,6 +4,10 @@
  *
  * Authors: Heng Zhang 
  *  Lihao Liang 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
  */
 
 #ifndef __LINUX_PRCU_H
diff --git a/kernel/rcu/prcu.c b/kernel/rcu/prcu.c
index ef2c7730..06375ee6 100644
--- a/kernel/rcu/prcu.c
+++ b/kernel/rcu/prcu.c
@@ -10,6 +10,10 @@
  *
  * Authors: Heng Zhang 
  *  Lihao Liang 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
  */
 
 #include 
-- 
2.14.1.729.g59c0ea183



[PATCH RFC 12/16] prcu: Add PRCU Kconfig parameter

2018-01-23 Thread lianglihao
From: Lihao Liang 

Signed-off-by: Lihao Liang 
---
 include/linux/prcu.h | 14 ++
 init/Kconfig |  7 +++
 kernel/rcu/Makefile  |  3 ++-
 3 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/include/linux/prcu.h b/include/linux/prcu.h
index cce967fd..bb20fa40 100644
--- a/include/linux/prcu.h
+++ b/include/linux/prcu.h
@@ -7,8 +7,7 @@
 #include 
 #include 
 
-#define CONFIG_PRCU
-
+#ifdef CONFIG_PRCU
 struct prcu_version_head {
unsigned long long version;
struct prcu_version_head *next;
@@ -48,7 +47,6 @@ struct prcu_struct {
struct completion barrier_completion;
 };
 
-#ifdef CONFIG_PRCU
 void prcu_read_lock(void);
 void prcu_read_unlock(void);
 void synchronize_prcu(void);
@@ -62,11 +60,11 @@ void prcu_check_callbacks(void);
 
 #else /* #ifdef CONFIG_PRCU */
 
-#define prcu_read_lock() do {} while (0)
-#define prcu_read_unlock() do {} while (0)
-#define synchronize_prcu() do {} while (0)
-#define call_prcu() do {} while (0)
-#define prcu_barrier() do {} while (0)
+#define prcu_read_lock rcu_read_lock
+#define prcu_read_unlock rcu_read_unlock
+#define synchronize_prcu synchronize_rcu
+#define call_prcu call_rcu
+#define prcu_barrier rcu_barrier
 #define prcu_init() do {} while (0)
 #define prcu_note_context_switch() do {} while (0)
 #define prcu_pending() 0
diff --git a/init/Kconfig b/init/Kconfig
index 1d3475fc..c1fd80f9 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -565,6 +565,13 @@ config TASKS_RCU
  only voluntary context switch (not preemption!), idle, and
  user-mode execution as quiescent states.
 
+config PRCU
+   bool
+   default y
+   help
+ This option selects the PRCU implementation based on a fast
+ consensus protocol.
+
 config RCU_STALL_COMMON
def_bool ( TREE_RCU || PREEMPT_RCU || RCU_TRACE )
help
diff --git a/kernel/rcu/Makefile b/kernel/rcu/Makefile
index 8791419c..9074b395 100644
--- a/kernel/rcu/Makefile
+++ b/kernel/rcu/Makefile
@@ -2,7 +2,7 @@
 # and is generally not a function of system call inputs.
 KCOV_INSTRUMENT := n
 
-obj-y += update.o sync.o prcu.o
+obj-y += update.o sync.o
 obj-$(CONFIG_CLASSIC_SRCU) += srcu.o
 obj-$(CONFIG_TREE_SRCU) += srcutree.o
 obj-$(CONFIG_TINY_SRCU) += srcutiny.o
@@ -12,4 +12,5 @@ obj-$(CONFIG_TREE_RCU) += tree.o
 obj-$(CONFIG_PREEMPT_RCU) += tree.o
 obj-$(CONFIG_TREE_RCU_TRACE) += tree_trace.o
 obj-$(CONFIG_TINY_RCU) += tiny.o
+obj-$(CONFIG_PRCU) += prcu.o
 obj-$(CONFIG_RCU_NEED_SEGCBLIST) += rcu_segcblist.o
-- 
2.14.1.729.g59c0ea183



[PATCH RFC 16/16] Add GPLv2 license

2018-01-23 Thread lianglihao
From: Lihao Liang 

Signed-off-by: Lihao Liang 
---
 include/linux/prcu.h | 4 
 kernel/rcu/prcu.c| 4 
 2 files changed, 8 insertions(+)

diff --git a/include/linux/prcu.h b/include/linux/prcu.h
index 9f740985..9fa74dac 100644
--- a/include/linux/prcu.h
+++ b/include/linux/prcu.h
@@ -4,6 +4,10 @@
  *
  * Authors: Heng Zhang 
  *  Lihao Liang 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
  */
 
 #ifndef __LINUX_PRCU_H
diff --git a/kernel/rcu/prcu.c b/kernel/rcu/prcu.c
index ef2c7730..06375ee6 100644
--- a/kernel/rcu/prcu.c
+++ b/kernel/rcu/prcu.c
@@ -10,6 +10,10 @@
  *
  * Authors: Heng Zhang 
  *  Lihao Liang 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
  */
 
 #include 
-- 
2.14.1.729.g59c0ea183



[PATCH RFC 12/16] prcu: Add PRCU Kconfig parameter

2018-01-23 Thread lianglihao
From: Lihao Liang 

Signed-off-by: Lihao Liang 
---
 include/linux/prcu.h | 14 ++
 init/Kconfig |  7 +++
 kernel/rcu/Makefile  |  3 ++-
 3 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/include/linux/prcu.h b/include/linux/prcu.h
index cce967fd..bb20fa40 100644
--- a/include/linux/prcu.h
+++ b/include/linux/prcu.h
@@ -7,8 +7,7 @@
 #include 
 #include 
 
-#define CONFIG_PRCU
-
+#ifdef CONFIG_PRCU
 struct prcu_version_head {
unsigned long long version;
struct prcu_version_head *next;
@@ -48,7 +47,6 @@ struct prcu_struct {
struct completion barrier_completion;
 };
 
-#ifdef CONFIG_PRCU
 void prcu_read_lock(void);
 void prcu_read_unlock(void);
 void synchronize_prcu(void);
@@ -62,11 +60,11 @@ void prcu_check_callbacks(void);
 
 #else /* #ifdef CONFIG_PRCU */
 
-#define prcu_read_lock() do {} while (0)
-#define prcu_read_unlock() do {} while (0)
-#define synchronize_prcu() do {} while (0)
-#define call_prcu() do {} while (0)
-#define prcu_barrier() do {} while (0)
+#define prcu_read_lock rcu_read_lock
+#define prcu_read_unlock rcu_read_unlock
+#define synchronize_prcu synchronize_rcu
+#define call_prcu call_rcu
+#define prcu_barrier rcu_barrier
 #define prcu_init() do {} while (0)
 #define prcu_note_context_switch() do {} while (0)
 #define prcu_pending() 0
diff --git a/init/Kconfig b/init/Kconfig
index 1d3475fc..c1fd80f9 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -565,6 +565,13 @@ config TASKS_RCU
  only voluntary context switch (not preemption!), idle, and
  user-mode execution as quiescent states.
 
+config PRCU
+   bool
+   default y
+   help
+ This option selects the PRCU implementation based on a fast
+ consensus protocol.
+
 config RCU_STALL_COMMON
def_bool ( TREE_RCU || PREEMPT_RCU || RCU_TRACE )
help
diff --git a/kernel/rcu/Makefile b/kernel/rcu/Makefile
index 8791419c..9074b395 100644
--- a/kernel/rcu/Makefile
+++ b/kernel/rcu/Makefile
@@ -2,7 +2,7 @@
 # and is generally not a function of system call inputs.
 KCOV_INSTRUMENT := n
 
-obj-y += update.o sync.o prcu.o
+obj-y += update.o sync.o
 obj-$(CONFIG_CLASSIC_SRCU) += srcu.o
 obj-$(CONFIG_TREE_SRCU) += srcutree.o
 obj-$(CONFIG_TINY_SRCU) += srcutiny.o
@@ -12,4 +12,5 @@ obj-$(CONFIG_TREE_RCU) += tree.o
 obj-$(CONFIG_PREEMPT_RCU) += tree.o
 obj-$(CONFIG_TREE_RCU_TRACE) += tree_trace.o
 obj-$(CONFIG_TINY_RCU) += tiny.o
+obj-$(CONFIG_PRCU) += prcu.o
 obj-$(CONFIG_RCU_NEED_SEGCBLIST) += rcu_segcblist.o
-- 
2.14.1.729.g59c0ea183



[PATCH RFC 03/16] rcutorture: Add PRCU test config files

2018-01-23 Thread lianglihao
From: Lihao Liang 

Use the same config files as TREE02, TREE03, TREE06, TREE07, and TREE09.

Signed-off-by: Lihao Liang 
---
 .../selftests/rcutorture/configs/rcu/CFLIST|  5 
 .../selftests/rcutorture/configs/rcu/PRCU02| 27 ++
 .../selftests/rcutorture/configs/rcu/PRCU02.boot   |  1 +
 .../selftests/rcutorture/configs/rcu/PRCU03| 23 ++
 .../selftests/rcutorture/configs/rcu/PRCU03.boot   |  2 ++
 .../selftests/rcutorture/configs/rcu/PRCU06| 26 +
 .../selftests/rcutorture/configs/rcu/PRCU06.boot   |  5 
 .../selftests/rcutorture/configs/rcu/PRCU07| 25 
 .../selftests/rcutorture/configs/rcu/PRCU07.boot   |  2 ++
 .../selftests/rcutorture/configs/rcu/PRCU09| 19 +++
 .../selftests/rcutorture/configs/rcu/PRCU09.boot   |  1 +
 11 files changed, 136 insertions(+)
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcu/PRCU02
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcu/PRCU02.boot
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcu/PRCU03
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcu/PRCU03.boot
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcu/PRCU06
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcu/PRCU06.boot
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcu/PRCU07
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcu/PRCU07.boot
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcu/PRCU09
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcu/PRCU09.boot

diff --git a/tools/testing/selftests/rcutorture/configs/rcu/CFLIST 
b/tools/testing/selftests/rcutorture/configs/rcu/CFLIST
index a3a1a05a..7359e194 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/CFLIST
+++ b/tools/testing/selftests/rcutorture/configs/rcu/CFLIST
@@ -1,3 +1,8 @@
+PRCU02
+PRCU03
+PRCU06
+PRCU07
+PRCU09
 TREE01
 TREE02
 TREE03
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/PRCU02 
b/tools/testing/selftests/rcutorture/configs/rcu/PRCU02
new file mode 100644
index ..5f532f05
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/PRCU02
@@ -0,0 +1,27 @@
+CONFIG_SMP=y
+CONFIG_NR_CPUS=8
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+CONFIG_PRCU=y
+#CHECK#CONFIG_PREEMPT_RCU=y
+CONFIG_HZ_PERIODIC=n
+CONFIG_NO_HZ_IDLE=y
+CONFIG_NO_HZ_FULL=n
+CONFIG_RCU_FAST_NO_HZ=n
+CONFIG_RCU_TRACE=n
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_RCU_FANOUT=3
+CONFIG_RCU_FANOUT_LEAF=3
+CONFIG_RCU_NOCB_CPU=n
+CONFIG_DEBUG_LOCK_ALLOC=y
+CONFIG_PROVE_LOCKING=n
+CONFIG_RCU_BOOST=n
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
+CONFIG_RCU_EXPERT=y
+CONFIG_RCU_TORTURE_TEST_SLOW_CLEANUP=y
+CONFIG_RCU_TORTURE_TEST_SLOW_INIT=y
+CONFIG_RCU_TORTURE_TEST_SLOW_PREINIT=y
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/PRCU02.boot 
b/tools/testing/selftests/rcutorture/configs/rcu/PRCU02.boot
new file mode 100644
index ..6c5e626f
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/PRCU02.boot
@@ -0,0 +1 @@
+rcutorture.torture_type=prcu
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/PRCU03 
b/tools/testing/selftests/rcutorture/configs/rcu/PRCU03
new file mode 100644
index ..869cadc8
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/PRCU03
@@ -0,0 +1,23 @@
+CONFIG_SMP=y
+CONFIG_NR_CPUS=16
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+CONFIG_PRCU=y
+#CHECK#CONFIG_PREEMPT_RCU=y
+CONFIG_HZ_PERIODIC=y
+CONFIG_NO_HZ_IDLE=n
+CONFIG_NO_HZ_FULL=n
+CONFIG_RCU_TRACE=y
+CONFIG_HOTPLUG_CPU=y
+CONFIG_RCU_FANOUT=2
+CONFIG_RCU_FANOUT_LEAF=2
+CONFIG_RCU_NOCB_CPU=n
+CONFIG_DEBUG_LOCK_ALLOC=n
+CONFIG_RCU_BOOST=y
+CONFIG_RCU_KTHREAD_PRIO=2
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
+CONFIG_RCU_EXPERT=y
+CONFIG_RCU_TORTURE_TEST_SLOW_CLEANUP=y
+CONFIG_RCU_TORTURE_TEST_SLOW_INIT=y
+CONFIG_RCU_TORTURE_TEST_SLOW_PREINIT=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/PRCU03.boot 
b/tools/testing/selftests/rcutorture/configs/rcu/PRCU03.boot
new file mode 100644
index ..0be10cba
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/PRCU03.boot
@@ -0,0 +1,2 @@
+rcutorture.onoff_interval=1 rcutorture.onoff_holdoff=30
+rcutorture.torture_type=prcu
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/PRCU06 
b/tools/testing/selftests/rcutorture/configs/rcu/PRCU06
new file mode 100644
index ..b1480963
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/PRCU06
@@ -0,0 +1,26 @@
+CONFIG_SMP=y
+CONFIG_NR_CPUS=8
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+CONFIG_PRCU=y
+#CHECK#CONFIG_TREE_RCU=y
+CONFIG_HZ_PERIODIC=n
+CONFIG_NO_HZ_IDLE=y
+CONFIG_NO_HZ_FULL=n
+CONFIG_RCU_FAST_NO_HZ=n

[PATCH RFC 03/16] rcutorture: Add PRCU test config files

2018-01-23 Thread lianglihao
From: Lihao Liang 

Use the same config files as TREE02, TREE03, TREE06, TREE07, and TREE09.

Signed-off-by: Lihao Liang 
---
 .../selftests/rcutorture/configs/rcu/CFLIST|  5 
 .../selftests/rcutorture/configs/rcu/PRCU02| 27 ++
 .../selftests/rcutorture/configs/rcu/PRCU02.boot   |  1 +
 .../selftests/rcutorture/configs/rcu/PRCU03| 23 ++
 .../selftests/rcutorture/configs/rcu/PRCU03.boot   |  2 ++
 .../selftests/rcutorture/configs/rcu/PRCU06| 26 +
 .../selftests/rcutorture/configs/rcu/PRCU06.boot   |  5 
 .../selftests/rcutorture/configs/rcu/PRCU07| 25 
 .../selftests/rcutorture/configs/rcu/PRCU07.boot   |  2 ++
 .../selftests/rcutorture/configs/rcu/PRCU09| 19 +++
 .../selftests/rcutorture/configs/rcu/PRCU09.boot   |  1 +
 11 files changed, 136 insertions(+)
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcu/PRCU02
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcu/PRCU02.boot
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcu/PRCU03
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcu/PRCU03.boot
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcu/PRCU06
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcu/PRCU06.boot
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcu/PRCU07
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcu/PRCU07.boot
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcu/PRCU09
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcu/PRCU09.boot

diff --git a/tools/testing/selftests/rcutorture/configs/rcu/CFLIST 
b/tools/testing/selftests/rcutorture/configs/rcu/CFLIST
index a3a1a05a..7359e194 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/CFLIST
+++ b/tools/testing/selftests/rcutorture/configs/rcu/CFLIST
@@ -1,3 +1,8 @@
+PRCU02
+PRCU03
+PRCU06
+PRCU07
+PRCU09
 TREE01
 TREE02
 TREE03
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/PRCU02 
b/tools/testing/selftests/rcutorture/configs/rcu/PRCU02
new file mode 100644
index ..5f532f05
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/PRCU02
@@ -0,0 +1,27 @@
+CONFIG_SMP=y
+CONFIG_NR_CPUS=8
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+CONFIG_PRCU=y
+#CHECK#CONFIG_PREEMPT_RCU=y
+CONFIG_HZ_PERIODIC=n
+CONFIG_NO_HZ_IDLE=y
+CONFIG_NO_HZ_FULL=n
+CONFIG_RCU_FAST_NO_HZ=n
+CONFIG_RCU_TRACE=n
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_RCU_FANOUT=3
+CONFIG_RCU_FANOUT_LEAF=3
+CONFIG_RCU_NOCB_CPU=n
+CONFIG_DEBUG_LOCK_ALLOC=y
+CONFIG_PROVE_LOCKING=n
+CONFIG_RCU_BOOST=n
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
+CONFIG_RCU_EXPERT=y
+CONFIG_RCU_TORTURE_TEST_SLOW_CLEANUP=y
+CONFIG_RCU_TORTURE_TEST_SLOW_INIT=y
+CONFIG_RCU_TORTURE_TEST_SLOW_PREINIT=y
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/PRCU02.boot 
b/tools/testing/selftests/rcutorture/configs/rcu/PRCU02.boot
new file mode 100644
index ..6c5e626f
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/PRCU02.boot
@@ -0,0 +1 @@
+rcutorture.torture_type=prcu
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/PRCU03 
b/tools/testing/selftests/rcutorture/configs/rcu/PRCU03
new file mode 100644
index ..869cadc8
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/PRCU03
@@ -0,0 +1,23 @@
+CONFIG_SMP=y
+CONFIG_NR_CPUS=16
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+CONFIG_PRCU=y
+#CHECK#CONFIG_PREEMPT_RCU=y
+CONFIG_HZ_PERIODIC=y
+CONFIG_NO_HZ_IDLE=n
+CONFIG_NO_HZ_FULL=n
+CONFIG_RCU_TRACE=y
+CONFIG_HOTPLUG_CPU=y
+CONFIG_RCU_FANOUT=2
+CONFIG_RCU_FANOUT_LEAF=2
+CONFIG_RCU_NOCB_CPU=n
+CONFIG_DEBUG_LOCK_ALLOC=n
+CONFIG_RCU_BOOST=y
+CONFIG_RCU_KTHREAD_PRIO=2
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
+CONFIG_RCU_EXPERT=y
+CONFIG_RCU_TORTURE_TEST_SLOW_CLEANUP=y
+CONFIG_RCU_TORTURE_TEST_SLOW_INIT=y
+CONFIG_RCU_TORTURE_TEST_SLOW_PREINIT=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/PRCU03.boot 
b/tools/testing/selftests/rcutorture/configs/rcu/PRCU03.boot
new file mode 100644
index ..0be10cba
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/PRCU03.boot
@@ -0,0 +1,2 @@
+rcutorture.onoff_interval=1 rcutorture.onoff_holdoff=30
+rcutorture.torture_type=prcu
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/PRCU06 
b/tools/testing/selftests/rcutorture/configs/rcu/PRCU06
new file mode 100644
index ..b1480963
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/PRCU06
@@ -0,0 +1,26 @@
+CONFIG_SMP=y
+CONFIG_NR_CPUS=8
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+CONFIG_PRCU=y
+#CHECK#CONFIG_TREE_RCU=y
+CONFIG_HZ_PERIODIC=n
+CONFIG_NO_HZ_IDLE=y
+CONFIG_NO_HZ_FULL=n
+CONFIG_RCU_FAST_NO_HZ=n
+CONFIG_RCU_TRACE=n
+CONFIG_HOTPLUG_CPU=n

[PATCH RFC 10/16] rcutorture: Test call_prcu() and prcu_barrier()

2018-01-23 Thread lianglihao
From: Lihao Liang 

Signed-off-by: Lihao Liang 
---
 kernel/rcu/prcu.c   | 4 +++-
 kernel/rcu/rcutorture.c | 4 ++--
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/kernel/rcu/prcu.c b/kernel/rcu/prcu.c
index 2664d091..49cb70e6 100644
--- a/kernel/rcu/prcu.c
+++ b/kernel/rcu/prcu.c
@@ -179,8 +179,10 @@ void call_prcu(struct rcu_head *head, rcu_callback_t func)
 
/* Use GFP_ATOMIC with IRQs disabled */
vhp = kmalloc(sizeof(struct prcu_version_head), GFP_ATOMIC);
-   if (!vhp)
+   if (!vhp) {
+   WARN_ON(1);
return;
+   }
 
head->func = func;
head->next = NULL;
diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c
index 7d65bf0c..9215ebb0 100644
--- a/kernel/rcu/rcutorture.c
+++ b/kernel/rcu/rcutorture.c
@@ -797,8 +797,8 @@ static struct rcu_torture_ops prcu_ops = {
.exp_sync   = synchronize_prcu,
.get_state  = NULL,
.cond_sync  = NULL,
-   .call   = NULL,
-   .cb_barrier = NULL,
+   .call   = call_prcu,
+   .cb_barrier = prcu_barrier,
.fqs= NULL,
.stats  = NULL,
.irq_capable= 1,
-- 
2.14.1.729.g59c0ea183



[PATCH RFC 10/16] rcutorture: Test call_prcu() and prcu_barrier()

2018-01-23 Thread lianglihao
From: Lihao Liang 

Signed-off-by: Lihao Liang 
---
 kernel/rcu/prcu.c   | 4 +++-
 kernel/rcu/rcutorture.c | 4 ++--
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/kernel/rcu/prcu.c b/kernel/rcu/prcu.c
index 2664d091..49cb70e6 100644
--- a/kernel/rcu/prcu.c
+++ b/kernel/rcu/prcu.c
@@ -179,8 +179,10 @@ void call_prcu(struct rcu_head *head, rcu_callback_t func)
 
/* Use GFP_ATOMIC with IRQs disabled */
vhp = kmalloc(sizeof(struct prcu_version_head), GFP_ATOMIC);
-   if (!vhp)
+   if (!vhp) {
+   WARN_ON(1);
return;
+   }
 
head->func = func;
head->next = NULL;
diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c
index 7d65bf0c..9215ebb0 100644
--- a/kernel/rcu/rcutorture.c
+++ b/kernel/rcu/rcutorture.c
@@ -797,8 +797,8 @@ static struct rcu_torture_ops prcu_ops = {
.exp_sync   = synchronize_prcu,
.get_state  = NULL,
.cond_sync  = NULL,
-   .call   = NULL,
-   .cb_barrier = NULL,
+   .call   = call_prcu,
+   .cb_barrier = prcu_barrier,
.fqs= NULL,
.stats  = NULL,
.irq_capable= 1,
-- 
2.14.1.729.g59c0ea183



[PATCH RFC 08/16] prcu: Implement PRCU callback processing

2018-01-23 Thread lianglihao
From: Lihao Liang 

Currently, PRCU core processing only consists of callback processing
in prcu_process_callbacks(), which is triggered by the scheduling-clock
interrupt.

Reviewed-by: Heng Zhang 
Signed-off-by: Lihao Liang 
---
 include/linux/interrupt.h |  3 ++
 include/linux/prcu.h  |  8 +
 kernel/rcu/prcu.c | 86 +++
 kernel/rcu/tree.c |  1 +
 kernel/time/timer.c   |  2 ++
 5 files changed, 100 insertions(+)

diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 0991f973..f05ef62a 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -456,6 +456,9 @@ enum
SCHED_SOFTIRQ,
HRTIMER_SOFTIRQ, /* Unused, but kept as tools rely on the
numbering. Sigh! */
+#ifdef CONFIG_PRCU
+   PRCU_SOFTIRQ,
+#endif
RCU_SOFTIRQ,/* Preferable RCU should always be the last softirq */
 
NR_SOFTIRQS
diff --git a/include/linux/prcu.h b/include/linux/prcu.h
index e5e09c9b..4e7d5d65 100644
--- a/include/linux/prcu.h
+++ b/include/linux/prcu.h
@@ -31,11 +31,13 @@ struct prcu_local_struct {
unsigned int locked;
unsigned int online;
unsigned long long version;
+   unsigned long long cb_version;
struct prcu_cblist cblist;
 };
 
 struct prcu_struct {
atomic64_t global_version;
+   atomic64_t cb_version;
atomic_t active_ctr;
struct mutex mtx;
wait_queue_head_t wait_q;
@@ -48,6 +50,9 @@ void synchronize_prcu(void);
 void call_prcu(struct rcu_head *head, rcu_callback_t func);
 void prcu_init(void);
 void prcu_note_context_switch(void);
+int prcu_pending(void);
+void invoke_prcu_core(void);
+void prcu_check_callbacks(void);
 
 #else /* #ifdef CONFIG_PRCU */
 
@@ -57,6 +62,9 @@ void prcu_note_context_switch(void);
 #define call_prcu() do {} while (0)
 #define prcu_init() do {} while (0)
 #define prcu_note_context_switch() do {} while (0)
+#define prcu_pending() 0
+#define invoke_prcu_core() do {} while (0)
+#define prcu_check_callbacks() do {} while (0)
 
 #endif /* #ifdef CONFIG_PRCU */
 #endif /* __LINUX_PRCU_H */
diff --git a/kernel/rcu/prcu.c b/kernel/rcu/prcu.c
index f198285c..373039c5 100644
--- a/kernel/rcu/prcu.c
+++ b/kernel/rcu/prcu.c
@@ -1,6 +1,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -11,6 +12,7 @@ DEFINE_PER_CPU_SHARED_ALIGNED(struct prcu_local_struct, 
prcu_local);
 
 struct prcu_struct global_prcu = {
.global_version = ATOMIC64_INIT(0),
+   .cb_version = ATOMIC64_INIT(0),
.active_ctr = ATOMIC_INIT(0),
.mtx = __MUTEX_INITIALIZER(global_prcu.mtx),
.wait_q = __WAIT_QUEUE_HEAD_INITIALIZER(global_prcu.wait_q)
@@ -27,6 +29,35 @@ static void prcu_cblist_init(struct prcu_cblist *rclp)
rclp->len = 0;
 }
 
+/*
+ * Dequeue the oldest rcu_head structure from the specified callback list;
+ * store the callback grace period version number into the version pointer.
+ */
+static struct rcu_head *prcu_cblist_dequeue(struct prcu_cblist *rclp)
+{
+   struct rcu_head *rhp;
+   struct prcu_version_head *vhp;
+
+   rhp = rclp->head;
+   if (!rhp) {
+   WARN_ON(vhp);
+   WARN_ON(rclp->len);
+   return NULL;
+   }
+
+   vhp = rclp->version_head;
+   rclp->version_head = vhp->next;
+   rclp->head = rhp->next;
+   rclp->len--;
+
+   if (!rclp->head) {
+   rclp->tail = >head;
+   rclp->version_tail = >version_head;
+   }
+
+   return rhp;
+}
+
 static inline void prcu_report(struct prcu_local_struct *local)
 {
unsigned long long global_version;
@@ -117,6 +148,7 @@ void synchronize_prcu(void)
if (atomic_read(>active_ctr))
wait_event(prcu->wait_q, !atomic_read(>active_ctr));
 
+   atomic64_set(>cb_version, version);
mutex_unlock(>mtx);
 }
 EXPORT_SYMBOL(synchronize_prcu);
@@ -166,6 +198,58 @@ void call_prcu(struct rcu_head *head, rcu_callback_t func)
 }
 EXPORT_SYMBOL(call_prcu);
 
+int prcu_pending(void)
+{
+   struct prcu_local_struct *local = get_cpu_ptr(_local);
+   unsigned long long cb_version = local->cb_version;
+   struct prcu_cblist *rclp = >cblist;
+
+   put_cpu_ptr(_local);
+   return cb_version < atomic64_read(>cb_version) && rclp->head;
+}
+
+void invoke_prcu_core(void)
+{
+   if (cpu_online(smp_processor_id()))
+   raise_softirq(PRCU_SOFTIRQ);
+}
+
+void prcu_check_callbacks(void)
+{
+   if (prcu_pending())
+   invoke_prcu_core();
+}
+
+static __latent_entropy void prcu_process_callbacks(struct softirq_action 
*unused)
+{
+   unsigned long flags;
+   unsigned long long cb_version;
+   struct prcu_local_struct *local;
+   struct prcu_cblist *rclp;
+   struct rcu_head *rhp;
+   struct prcu_version_head *vhp;
+
+   if 

[PATCH RFC 08/16] prcu: Implement PRCU callback processing

2018-01-23 Thread lianglihao
From: Lihao Liang 

Currently, PRCU core processing only consists of callback processing
in prcu_process_callbacks(), which is triggered by the scheduling-clock
interrupt.

Reviewed-by: Heng Zhang 
Signed-off-by: Lihao Liang 
---
 include/linux/interrupt.h |  3 ++
 include/linux/prcu.h  |  8 +
 kernel/rcu/prcu.c | 86 +++
 kernel/rcu/tree.c |  1 +
 kernel/time/timer.c   |  2 ++
 5 files changed, 100 insertions(+)

diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 0991f973..f05ef62a 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -456,6 +456,9 @@ enum
SCHED_SOFTIRQ,
HRTIMER_SOFTIRQ, /* Unused, but kept as tools rely on the
numbering. Sigh! */
+#ifdef CONFIG_PRCU
+   PRCU_SOFTIRQ,
+#endif
RCU_SOFTIRQ,/* Preferable RCU should always be the last softirq */
 
NR_SOFTIRQS
diff --git a/include/linux/prcu.h b/include/linux/prcu.h
index e5e09c9b..4e7d5d65 100644
--- a/include/linux/prcu.h
+++ b/include/linux/prcu.h
@@ -31,11 +31,13 @@ struct prcu_local_struct {
unsigned int locked;
unsigned int online;
unsigned long long version;
+   unsigned long long cb_version;
struct prcu_cblist cblist;
 };
 
 struct prcu_struct {
atomic64_t global_version;
+   atomic64_t cb_version;
atomic_t active_ctr;
struct mutex mtx;
wait_queue_head_t wait_q;
@@ -48,6 +50,9 @@ void synchronize_prcu(void);
 void call_prcu(struct rcu_head *head, rcu_callback_t func);
 void prcu_init(void);
 void prcu_note_context_switch(void);
+int prcu_pending(void);
+void invoke_prcu_core(void);
+void prcu_check_callbacks(void);
 
 #else /* #ifdef CONFIG_PRCU */
 
@@ -57,6 +62,9 @@ void prcu_note_context_switch(void);
 #define call_prcu() do {} while (0)
 #define prcu_init() do {} while (0)
 #define prcu_note_context_switch() do {} while (0)
+#define prcu_pending() 0
+#define invoke_prcu_core() do {} while (0)
+#define prcu_check_callbacks() do {} while (0)
 
 #endif /* #ifdef CONFIG_PRCU */
 #endif /* __LINUX_PRCU_H */
diff --git a/kernel/rcu/prcu.c b/kernel/rcu/prcu.c
index f198285c..373039c5 100644
--- a/kernel/rcu/prcu.c
+++ b/kernel/rcu/prcu.c
@@ -1,6 +1,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -11,6 +12,7 @@ DEFINE_PER_CPU_SHARED_ALIGNED(struct prcu_local_struct, 
prcu_local);
 
 struct prcu_struct global_prcu = {
.global_version = ATOMIC64_INIT(0),
+   .cb_version = ATOMIC64_INIT(0),
.active_ctr = ATOMIC_INIT(0),
.mtx = __MUTEX_INITIALIZER(global_prcu.mtx),
.wait_q = __WAIT_QUEUE_HEAD_INITIALIZER(global_prcu.wait_q)
@@ -27,6 +29,35 @@ static void prcu_cblist_init(struct prcu_cblist *rclp)
rclp->len = 0;
 }
 
+/*
+ * Dequeue the oldest rcu_head structure from the specified callback list;
+ * store the callback grace period version number into the version pointer.
+ */
+static struct rcu_head *prcu_cblist_dequeue(struct prcu_cblist *rclp)
+{
+   struct rcu_head *rhp;
+   struct prcu_version_head *vhp;
+
+   rhp = rclp->head;
+   if (!rhp) {
+   WARN_ON(vhp);
+   WARN_ON(rclp->len);
+   return NULL;
+   }
+
+   vhp = rclp->version_head;
+   rclp->version_head = vhp->next;
+   rclp->head = rhp->next;
+   rclp->len--;
+
+   if (!rclp->head) {
+   rclp->tail = >head;
+   rclp->version_tail = >version_head;
+   }
+
+   return rhp;
+}
+
 static inline void prcu_report(struct prcu_local_struct *local)
 {
unsigned long long global_version;
@@ -117,6 +148,7 @@ void synchronize_prcu(void)
if (atomic_read(>active_ctr))
wait_event(prcu->wait_q, !atomic_read(>active_ctr));
 
+   atomic64_set(>cb_version, version);
mutex_unlock(>mtx);
 }
 EXPORT_SYMBOL(synchronize_prcu);
@@ -166,6 +198,58 @@ void call_prcu(struct rcu_head *head, rcu_callback_t func)
 }
 EXPORT_SYMBOL(call_prcu);
 
+int prcu_pending(void)
+{
+   struct prcu_local_struct *local = get_cpu_ptr(_local);
+   unsigned long long cb_version = local->cb_version;
+   struct prcu_cblist *rclp = >cblist;
+
+   put_cpu_ptr(_local);
+   return cb_version < atomic64_read(>cb_version) && rclp->head;
+}
+
+void invoke_prcu_core(void)
+{
+   if (cpu_online(smp_processor_id()))
+   raise_softirq(PRCU_SOFTIRQ);
+}
+
+void prcu_check_callbacks(void)
+{
+   if (prcu_pending())
+   invoke_prcu_core();
+}
+
+static __latent_entropy void prcu_process_callbacks(struct softirq_action 
*unused)
+{
+   unsigned long flags;
+   unsigned long long cb_version;
+   struct prcu_local_struct *local;
+   struct prcu_cblist *rclp;
+   struct rcu_head *rhp;
+   struct prcu_version_head *vhp;
+
+   if (cpu_is_offline(smp_processor_id()))
+   return;
+
+

[PATCH RFC 15/16] rcutorture: Add scripts to run experiments

2018-01-23 Thread lianglihao
From: Lihao Liang 

Signed-off-by: Lihao Liang 
---
 kvm.sh | 452 +
 run-rcuperf.sh |  26 
 2 files changed, 478 insertions(+)
 create mode 100755 kvm.sh
 create mode 100755 run-rcuperf.sh

diff --git a/kvm.sh b/kvm.sh
new file mode 100755
index ..3b3c1b69
--- /dev/null
+++ b/kvm.sh
@@ -0,0 +1,452 @@
+#!/bin/bash
+#
+# Run a series of 14 tests under KVM.  These are not particularly
+# well-selected or well-tuned, but are the current set.  Run from the
+# top level of the source tree.
+#
+# Edit the definitions below to set the locations of the various directories,
+# as well as the test duration.
+#
+# Usage: kvm.sh [ options ]
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, you can access it online at
+# http://www.gnu.org/licenses/gpl-2.0.html.
+#
+# Copyright (C) IBM Corporation, 2011
+#
+# Authors: Paul E. McKenney 
+
+scriptname=$0
+args="$*"
+
+T=/tmp/kvm.sh.$$
+trap 'rm -rf $T' 0
+mkdir $T
+
+dur=$((30*60))
+dryrun=""
+KVM="`pwd`/tools/testing/selftests/rcutorture"; export KVM
+PATH=${KVM}/bin:$PATH; export PATH
+TORTURE_DEFCONFIG=defconfig
+TORTURE_BOOT_IMAGE=""
+TORTURE_INITRD="$KVM/initrd"; export TORTURE_INITRD
+TORTURE_KMAKE_ARG=""
+TORTURE_SHUTDOWN_GRACE=180
+TORTURE_SUITE=rcu
+resdir=""
+configs=""
+cpus=0
+ds=`date +%Y.%m.%d-%H:%M:%S`
+jitter="-1"
+
+. functions.sh
+
+usage () {
+   echo "Usage: $scriptname optional arguments:"
+   echo "   --bootargs kernel-boot-arguments"
+   echo "   --bootimage relative-path-to-kernel-boot-image"
+   echo "   --buildonly"
+   echo "   --configs \"config-file list w/ repeat factor (3*TINY01)\""
+   echo "   --cpus N"
+   echo "   --datestamp string"
+   echo "   --defconfig string"
+   echo "   --dryrun sched|script"
+   echo "   --duration minutes"
+   echo "   --interactive"
+   echo "   --jitter N [ maxsleep (us) [ maxspin (us) ] ]"
+   echo "   --kmake-arg kernel-make-arguments"
+   echo "   --mac nn:nn:nn:nn:nn:nn"
+   echo "   --no-initrd"
+   echo "   --qemu-args qemu-system-..."
+   echo "   --qemu-cmd qemu-system-..."
+   echo "   --results absolute-pathname"
+   echo "   --torture rcu"
+   exit 1
+}
+
+while test $# -gt 0
+do
+   case "$1" in
+   --bootargs|--bootarg)
+   checkarg --bootargs "(list of kernel boot arguments)" "$#" "$2" 
'.*' '^--'
+   TORTURE_BOOTARGS="$2"
+   shift
+   ;;
+   --bootimage)
+   checkarg --bootimage "(relative path to kernel boot image)" 
"$#" "$2" '[a-zA-Z0-9][a-zA-Z0-9_]*' '^--'
+   TORTURE_BOOT_IMAGE="$2"
+   shift
+   ;;
+   --buildonly)
+   TORTURE_BUILDONLY=1
+   ;;
+   --configs|--config)
+   checkarg --configs "(list of config files)" "$#" "$2" '^[^/]*$' 
'^--'
+   configs="$2"
+   shift
+   ;;
+   --cpus)
+   checkarg --cpus "(number)" "$#" "$2" '^[0-9]*$' '^--'
+   cpus=$2
+   shift
+   ;;
+   --datestamp)
+   checkarg --datestamp "(relative pathname)" "$#" "$2" '^[^/]*$' 
'^--'
+   ds=$2
+   shift
+   ;;
+   --defconfig)
+   checkarg --defconfig "defconfigtype" "$#" "$2" '^[^/][^/]*$' 
'^--'
+   TORTURE_DEFCONFIG=$2
+   shift
+   ;;
+   --dryrun)
+   checkarg --dryrun "sched|script" $# "$2" 'sched\|script' '^--'
+   dryrun=$2
+   shift
+   ;;
+   --duration)
+   checkarg --duration "(minutes)" $# "$2" '^[0-9]*$' '^error'
+   dur=$(($2*60))
+   shift
+   ;;
+   --interactive)
+   TORTURE_QEMU_INTERACTIVE=1; export TORTURE_QEMU_INTERACTIVE
+   ;;
+   --jitter)
+   checkarg --jitter "(# threads [ sleep [ spin ] ])" $# "$2" 
'^-\{,1\}[0-9]\+\( \+[0-9]\+\)\{,2\} *$' '^error$'
+   jitter="$2"
+   shift
+   ;;
+   --kmake-arg)
+   checkarg --kmake-arg "(kernel make arguments)" $# "$2" '.*' 
'^error$'
+   

[PATCH RFC 13/16] prcu: Comment source code

2018-01-23 Thread lianglihao
From: Lihao Liang 

Signed-off-by: Lihao Liang 
---
 include/linux/prcu.h |  73 -
 kernel/rcu/prcu.c| 178 +++
 2 files changed, 225 insertions(+), 26 deletions(-)

diff --git a/include/linux/prcu.h b/include/linux/prcu.h
index bb20fa40..9f740985 100644
--- a/include/linux/prcu.h
+++ b/include/linux/prcu.h
@@ -1,3 +1,11 @@
+/*
+ * Read-Copy Update mechanism for mutual exclusion (PRCU version).
+ * PRCU public definitions.
+ *
+ * Authors: Heng Zhang 
+ *  Lihao Liang 
+ */
+
 #ifndef __LINUX_PRCU_H
 #define __LINUX_PRCU_H
 
@@ -8,12 +16,26 @@
 #include 
 
 #ifdef CONFIG_PRCU
+
+/*
+ * Simple list structure of callback versions.
+ *
+ * Note: Ideally, we would like to add the version field
+ * to the rcu_head struct.  But if we do so, other users of
+ * rcu_head in the Linux kernel will complain hard and loudly.
+ */
 struct prcu_version_head {
unsigned long long version;
struct prcu_version_head *next;
 };
 
-/* Simple unsegmented callback list for PRCU. */
+/*
+ * Simple unsegmented callback list for PRCU.
+ *
+ * Note: Since we can't add a new version field to rcu_head,
+ * we have to make our own callback list for PRCU instead of
+ * using the existing rcu_cblist. Sigh!
+ */
 struct prcu_cblist {
struct rcu_head *head;
struct rcu_head **tail;
@@ -27,31 +49,47 @@ struct prcu_cblist {
.version_head = NULL, .version_tail = _head, \
 }
 
+/*
+ * PRCU's per-CPU state.
+ */
 struct prcu_local_struct {
-   unsigned int locked;
-   unsigned int online;
-   unsigned long long version;
-   unsigned long long cb_version;
-   struct rcu_head barrier_head;
-   struct prcu_cblist cblist;
+   unsigned int locked;   /* Nesting level of PRCU read-side */
+  /*  critcal sections */
+   unsigned int online;   /* Indicates whether a context-switch */
+  /*  has occurred on this CPU */
+   unsigned long long version;/* Local grace-period version */
+   unsigned long long cb_version; /* Local callback version */
+   struct rcu_head barrier_head;  /* PRCU callback list */
+   struct prcu_cblist cblist; /* PRCU callback version list */
 };
 
+/*
+ * PRCU's global state.
+ */
 struct prcu_struct {
-   atomic64_t global_version;
-   atomic64_t cb_version;
-   atomic_t active_ctr;
-   atomic_t barrier_cpu_count;
-   struct mutex mtx;
-   struct mutex barrier_mtx;
-   wait_queue_head_t wait_q;
-   struct completion barrier_completion;
+   atomic64_t global_version;/* Global grace-period version */
+   atomic64_t cb_version;/* Global callback version */
+   atomic_t active_ctr;  /* Outstanding PRCU tasks */
+ /*  being context-switched */
+   atomic_t barrier_cpu_count;   /* # CPUs waiting on 
prcu_barrier() */
+   struct mutex mtx; /* Serialize synchronize_prcu() */
+   struct mutex barrier_mtx; /* Serialize prcu_barrier() */
+   wait_queue_head_t wait_q; /* Wait for synchronize_prcu() */
+   struct completion barrier_completion; /* Wait for prcu_barrier() */
 };
 
+/*
+ * PRCU APIs.
+ */
 void prcu_read_lock(void);
 void prcu_read_unlock(void);
 void synchronize_prcu(void);
 void call_prcu(struct rcu_head *head, rcu_callback_t func);
 void prcu_barrier(void);
+
+/*
+ * Internal non-public functions.
+ */
 void prcu_init(void);
 void prcu_note_context_switch(void);
 int prcu_pending(void);
@@ -60,11 +98,16 @@ void prcu_check_callbacks(void);
 
 #else /* #ifdef CONFIG_PRCU */
 
+/*
+ * If CONFIG_PRCU is not defined,
+ * map its APIs to RCU's counterparts.
+ */
 #define prcu_read_lock rcu_read_lock
 #define prcu_read_unlock rcu_read_unlock
 #define synchronize_prcu synchronize_rcu
 #define call_prcu call_rcu
 #define prcu_barrier rcu_barrier
+
 #define prcu_init() do {} while (0)
 #define prcu_note_context_switch() do {} while (0)
 #define prcu_pending() 0
diff --git a/kernel/rcu/prcu.c b/kernel/rcu/prcu.c
index 49cb70e6..ef2c7730 100644
--- a/kernel/rcu/prcu.c
+++ b/kernel/rcu/prcu.c
@@ -1,3 +1,17 @@
+/*
+ * Read-Copy Update mechanism for mutual exclusion (PRCU version).
+ * This PRCU implementation is based on a fast consensus protocol
+ * published in the following paper:
+ *
+ * Fast Consensus Using Bounded Staleness for Scalable Read-mostly 
Synchronization.
+ * Haibo Chen, Heng Zhang, Ran Liu, Binyu Zang, and Haibing Guan.
+ * IEEE Transactions on Parallel and Distributed Systems (TPDS), 2016.
+ * https://dl.acm.org/citation.cfm?id=3024114.3024143
+ *
+ * Authors: Heng Zhang 
+ *  Lihao Liang 
+ */
+
 #include 
 #include 
 #include 

[PATCH RFC 09/16] prcu: Implement prcu_barrier() API

2018-01-23 Thread lianglihao
From: Lihao Liang 

This is PRCU's counterpart of RCU's rcu_barrier() API.

Reviewed-by: Heng Zhang 
Signed-off-by: Lihao Liang 
---
 include/linux/prcu.h |  7 ++
 kernel/rcu/prcu.c| 63 
 2 files changed, 70 insertions(+)

diff --git a/include/linux/prcu.h b/include/linux/prcu.h
index 4e7d5d65..cce967fd 100644
--- a/include/linux/prcu.h
+++ b/include/linux/prcu.h
@@ -5,6 +5,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #define CONFIG_PRCU
 
@@ -32,6 +33,7 @@ struct prcu_local_struct {
unsigned int online;
unsigned long long version;
unsigned long long cb_version;
+   struct rcu_head barrier_head;
struct prcu_cblist cblist;
 };
 
@@ -39,8 +41,11 @@ struct prcu_struct {
atomic64_t global_version;
atomic64_t cb_version;
atomic_t active_ctr;
+   atomic_t barrier_cpu_count;
struct mutex mtx;
+   struct mutex barrier_mtx;
wait_queue_head_t wait_q;
+   struct completion barrier_completion;
 };
 
 #ifdef CONFIG_PRCU
@@ -48,6 +53,7 @@ void prcu_read_lock(void);
 void prcu_read_unlock(void);
 void synchronize_prcu(void);
 void call_prcu(struct rcu_head *head, rcu_callback_t func);
+void prcu_barrier(void);
 void prcu_init(void);
 void prcu_note_context_switch(void);
 int prcu_pending(void);
@@ -60,6 +66,7 @@ void prcu_check_callbacks(void);
 #define prcu_read_unlock() do {} while (0)
 #define synchronize_prcu() do {} while (0)
 #define call_prcu() do {} while (0)
+#define prcu_barrier() do {} while (0)
 #define prcu_init() do {} while (0)
 #define prcu_note_context_switch() do {} while (0)
 #define prcu_pending() 0
diff --git a/kernel/rcu/prcu.c b/kernel/rcu/prcu.c
index 373039c5..2664d091 100644
--- a/kernel/rcu/prcu.c
+++ b/kernel/rcu/prcu.c
@@ -15,6 +15,7 @@ struct prcu_struct global_prcu = {
.cb_version = ATOMIC64_INIT(0),
.active_ctr = ATOMIC_INIT(0),
.mtx = __MUTEX_INITIALIZER(global_prcu.mtx),
+   .barrier_mtx = __MUTEX_INITIALIZER(global_prcu.barrier_mtx),
.wait_q = __WAIT_QUEUE_HEAD_INITIALIZER(global_prcu.wait_q)
 };
 struct prcu_struct *prcu = _prcu;
@@ -250,6 +251,68 @@ static __latent_entropy void prcu_process_callbacks(struct 
softirq_action *unuse
local_irq_restore(flags);
 }
 
+/*
+ * PRCU callback function for prcu_barrier().
+ * If we are last, wake up the task executing prcu_barrier().
+ */
+static void prcu_barrier_callback(struct rcu_head *rhp)
+{
+   if (atomic_dec_and_test(>barrier_cpu_count))
+   complete(>barrier_completion);
+}
+
+/*
+ * Called with preemption disabled, and from cross-cpu IRQ context.
+ */
+static void prcu_barrier_func(void *info)
+{
+   struct prcu_local_struct *local = this_cpu_ptr(_local);
+
+   atomic_inc(>barrier_cpu_count);
+   call_prcu(>barrier_head, prcu_barrier_callback);
+}
+
+/* Waiting for all PRCU callbacks to complete. */
+void prcu_barrier(void)
+{
+   int cpu;
+
+   /* Take mutex to serialize concurrent prcu_barrier() requests. */
+   mutex_lock(>barrier_mtx);
+
+   /*
+* Initialize the count to one rather than to zero in order to
+* avoid a too-soon return to zero in case of a short grace period
+* (or preemption of this task).
+*/
+   init_completion(>barrier_completion);
+   atomic_set(>barrier_cpu_count, 1);
+
+   /*
+* Register a new callback on each CPU using IPI to prevent races
+* with call_prcu(). When that callback is invoked, we will know
+* that all of the corresponding CPU's preceding callbacks have
+* been invoked.
+*/
+   for_each_possible_cpu(cpu)
+   smp_call_function_single(cpu, prcu_barrier_func, NULL, 1);
+
+   /* Decrement the count as we initialize it to one. */
+   if (atomic_dec_and_test(>barrier_cpu_count))
+   complete(>barrier_completion);
+
+   /*
+* Now that we have an prcu_barrier_callback() callback on each
+* CPU, and thus each counted, remove the initial count.
+* Wait for all prcu_barrier_callback() callbacks to be invoked.
+*/
+   wait_for_completion(>barrier_completion);
+
+   /* Other rcu_barrier() invocations can now safely proceed. */
+   mutex_unlock(>barrier_mtx);
+}
+EXPORT_SYMBOL(prcu_barrier);
+
 void prcu_init_local_struct(int cpu)
 {
struct prcu_local_struct *local;
-- 
2.14.1.729.g59c0ea183



[PATCH RFC 15/16] rcutorture: Add scripts to run experiments

2018-01-23 Thread lianglihao
From: Lihao Liang 

Signed-off-by: Lihao Liang 
---
 kvm.sh | 452 +
 run-rcuperf.sh |  26 
 2 files changed, 478 insertions(+)
 create mode 100755 kvm.sh
 create mode 100755 run-rcuperf.sh

diff --git a/kvm.sh b/kvm.sh
new file mode 100755
index ..3b3c1b69
--- /dev/null
+++ b/kvm.sh
@@ -0,0 +1,452 @@
+#!/bin/bash
+#
+# Run a series of 14 tests under KVM.  These are not particularly
+# well-selected or well-tuned, but are the current set.  Run from the
+# top level of the source tree.
+#
+# Edit the definitions below to set the locations of the various directories,
+# as well as the test duration.
+#
+# Usage: kvm.sh [ options ]
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, you can access it online at
+# http://www.gnu.org/licenses/gpl-2.0.html.
+#
+# Copyright (C) IBM Corporation, 2011
+#
+# Authors: Paul E. McKenney 
+
+scriptname=$0
+args="$*"
+
+T=/tmp/kvm.sh.$$
+trap 'rm -rf $T' 0
+mkdir $T
+
+dur=$((30*60))
+dryrun=""
+KVM="`pwd`/tools/testing/selftests/rcutorture"; export KVM
+PATH=${KVM}/bin:$PATH; export PATH
+TORTURE_DEFCONFIG=defconfig
+TORTURE_BOOT_IMAGE=""
+TORTURE_INITRD="$KVM/initrd"; export TORTURE_INITRD
+TORTURE_KMAKE_ARG=""
+TORTURE_SHUTDOWN_GRACE=180
+TORTURE_SUITE=rcu
+resdir=""
+configs=""
+cpus=0
+ds=`date +%Y.%m.%d-%H:%M:%S`
+jitter="-1"
+
+. functions.sh
+
+usage () {
+   echo "Usage: $scriptname optional arguments:"
+   echo "   --bootargs kernel-boot-arguments"
+   echo "   --bootimage relative-path-to-kernel-boot-image"
+   echo "   --buildonly"
+   echo "   --configs \"config-file list w/ repeat factor (3*TINY01)\""
+   echo "   --cpus N"
+   echo "   --datestamp string"
+   echo "   --defconfig string"
+   echo "   --dryrun sched|script"
+   echo "   --duration minutes"
+   echo "   --interactive"
+   echo "   --jitter N [ maxsleep (us) [ maxspin (us) ] ]"
+   echo "   --kmake-arg kernel-make-arguments"
+   echo "   --mac nn:nn:nn:nn:nn:nn"
+   echo "   --no-initrd"
+   echo "   --qemu-args qemu-system-..."
+   echo "   --qemu-cmd qemu-system-..."
+   echo "   --results absolute-pathname"
+   echo "   --torture rcu"
+   exit 1
+}
+
+while test $# -gt 0
+do
+   case "$1" in
+   --bootargs|--bootarg)
+   checkarg --bootargs "(list of kernel boot arguments)" "$#" "$2" 
'.*' '^--'
+   TORTURE_BOOTARGS="$2"
+   shift
+   ;;
+   --bootimage)
+   checkarg --bootimage "(relative path to kernel boot image)" 
"$#" "$2" '[a-zA-Z0-9][a-zA-Z0-9_]*' '^--'
+   TORTURE_BOOT_IMAGE="$2"
+   shift
+   ;;
+   --buildonly)
+   TORTURE_BUILDONLY=1
+   ;;
+   --configs|--config)
+   checkarg --configs "(list of config files)" "$#" "$2" '^[^/]*$' 
'^--'
+   configs="$2"
+   shift
+   ;;
+   --cpus)
+   checkarg --cpus "(number)" "$#" "$2" '^[0-9]*$' '^--'
+   cpus=$2
+   shift
+   ;;
+   --datestamp)
+   checkarg --datestamp "(relative pathname)" "$#" "$2" '^[^/]*$' 
'^--'
+   ds=$2
+   shift
+   ;;
+   --defconfig)
+   checkarg --defconfig "defconfigtype" "$#" "$2" '^[^/][^/]*$' 
'^--'
+   TORTURE_DEFCONFIG=$2
+   shift
+   ;;
+   --dryrun)
+   checkarg --dryrun "sched|script" $# "$2" 'sched\|script' '^--'
+   dryrun=$2
+   shift
+   ;;
+   --duration)
+   checkarg --duration "(minutes)" $# "$2" '^[0-9]*$' '^error'
+   dur=$(($2*60))
+   shift
+   ;;
+   --interactive)
+   TORTURE_QEMU_INTERACTIVE=1; export TORTURE_QEMU_INTERACTIVE
+   ;;
+   --jitter)
+   checkarg --jitter "(# threads [ sleep [ spin ] ])" $# "$2" 
'^-\{,1\}[0-9]\+\( \+[0-9]\+\)\{,2\} *$' '^error$'
+   jitter="$2"
+   shift
+   ;;
+   --kmake-arg)
+   checkarg --kmake-arg "(kernel make arguments)" $# "$2" '.*' 
'^error$'
+   TORTURE_KMAKE_ARG="$2"
+   shift
+   ;;
+   --mac)
+  

[PATCH RFC 13/16] prcu: Comment source code

2018-01-23 Thread lianglihao
From: Lihao Liang 

Signed-off-by: Lihao Liang 
---
 include/linux/prcu.h |  73 -
 kernel/rcu/prcu.c| 178 +++
 2 files changed, 225 insertions(+), 26 deletions(-)

diff --git a/include/linux/prcu.h b/include/linux/prcu.h
index bb20fa40..9f740985 100644
--- a/include/linux/prcu.h
+++ b/include/linux/prcu.h
@@ -1,3 +1,11 @@
+/*
+ * Read-Copy Update mechanism for mutual exclusion (PRCU version).
+ * PRCU public definitions.
+ *
+ * Authors: Heng Zhang 
+ *  Lihao Liang 
+ */
+
 #ifndef __LINUX_PRCU_H
 #define __LINUX_PRCU_H
 
@@ -8,12 +16,26 @@
 #include 
 
 #ifdef CONFIG_PRCU
+
+/*
+ * Simple list structure of callback versions.
+ *
+ * Note: Ideally, we would like to add the version field
+ * to the rcu_head struct.  But if we do so, other users of
+ * rcu_head in the Linux kernel will complain hard and loudly.
+ */
 struct prcu_version_head {
unsigned long long version;
struct prcu_version_head *next;
 };
 
-/* Simple unsegmented callback list for PRCU. */
+/*
+ * Simple unsegmented callback list for PRCU.
+ *
+ * Note: Since we can't add a new version field to rcu_head,
+ * we have to make our own callback list for PRCU instead of
+ * using the existing rcu_cblist. Sigh!
+ */
 struct prcu_cblist {
struct rcu_head *head;
struct rcu_head **tail;
@@ -27,31 +49,47 @@ struct prcu_cblist {
.version_head = NULL, .version_tail = _head, \
 }
 
+/*
+ * PRCU's per-CPU state.
+ */
 struct prcu_local_struct {
-   unsigned int locked;
-   unsigned int online;
-   unsigned long long version;
-   unsigned long long cb_version;
-   struct rcu_head barrier_head;
-   struct prcu_cblist cblist;
+   unsigned int locked;   /* Nesting level of PRCU read-side */
+  /*  critcal sections */
+   unsigned int online;   /* Indicates whether a context-switch */
+  /*  has occurred on this CPU */
+   unsigned long long version;/* Local grace-period version */
+   unsigned long long cb_version; /* Local callback version */
+   struct rcu_head barrier_head;  /* PRCU callback list */
+   struct prcu_cblist cblist; /* PRCU callback version list */
 };
 
+/*
+ * PRCU's global state.
+ */
 struct prcu_struct {
-   atomic64_t global_version;
-   atomic64_t cb_version;
-   atomic_t active_ctr;
-   atomic_t barrier_cpu_count;
-   struct mutex mtx;
-   struct mutex barrier_mtx;
-   wait_queue_head_t wait_q;
-   struct completion barrier_completion;
+   atomic64_t global_version;/* Global grace-period version */
+   atomic64_t cb_version;/* Global callback version */
+   atomic_t active_ctr;  /* Outstanding PRCU tasks */
+ /*  being context-switched */
+   atomic_t barrier_cpu_count;   /* # CPUs waiting on 
prcu_barrier() */
+   struct mutex mtx; /* Serialize synchronize_prcu() */
+   struct mutex barrier_mtx; /* Serialize prcu_barrier() */
+   wait_queue_head_t wait_q; /* Wait for synchronize_prcu() */
+   struct completion barrier_completion; /* Wait for prcu_barrier() */
 };
 
+/*
+ * PRCU APIs.
+ */
 void prcu_read_lock(void);
 void prcu_read_unlock(void);
 void synchronize_prcu(void);
 void call_prcu(struct rcu_head *head, rcu_callback_t func);
 void prcu_barrier(void);
+
+/*
+ * Internal non-public functions.
+ */
 void prcu_init(void);
 void prcu_note_context_switch(void);
 int prcu_pending(void);
@@ -60,11 +98,16 @@ void prcu_check_callbacks(void);
 
 #else /* #ifdef CONFIG_PRCU */
 
+/*
+ * If CONFIG_PRCU is not defined,
+ * map its APIs to RCU's counterparts.
+ */
 #define prcu_read_lock rcu_read_lock
 #define prcu_read_unlock rcu_read_unlock
 #define synchronize_prcu synchronize_rcu
 #define call_prcu call_rcu
 #define prcu_barrier rcu_barrier
+
 #define prcu_init() do {} while (0)
 #define prcu_note_context_switch() do {} while (0)
 #define prcu_pending() 0
diff --git a/kernel/rcu/prcu.c b/kernel/rcu/prcu.c
index 49cb70e6..ef2c7730 100644
--- a/kernel/rcu/prcu.c
+++ b/kernel/rcu/prcu.c
@@ -1,3 +1,17 @@
+/*
+ * Read-Copy Update mechanism for mutual exclusion (PRCU version).
+ * This PRCU implementation is based on a fast consensus protocol
+ * published in the following paper:
+ *
+ * Fast Consensus Using Bounded Staleness for Scalable Read-mostly 
Synchronization.
+ * Haibo Chen, Heng Zhang, Ran Liu, Binyu Zang, and Haibing Guan.
+ * IEEE Transactions on Parallel and Distributed Systems (TPDS), 2016.
+ * https://dl.acm.org/citation.cfm?id=3024114.3024143
+ *
+ * Authors: Heng Zhang 
+ *  Lihao Liang 
+ */
+
 #include 
 #include 
 #include 
@@ -8,8 +22,16 @@
 
 #include "rcu.h"
 
+/* Data structures. */
+
+/*
+ * Initialize PRCU's per-CPU local structure.
+ */
 

[PATCH RFC 09/16] prcu: Implement prcu_barrier() API

2018-01-23 Thread lianglihao
From: Lihao Liang 

This is PRCU's counterpart of RCU's rcu_barrier() API.

Reviewed-by: Heng Zhang 
Signed-off-by: Lihao Liang 
---
 include/linux/prcu.h |  7 ++
 kernel/rcu/prcu.c| 63 
 2 files changed, 70 insertions(+)

diff --git a/include/linux/prcu.h b/include/linux/prcu.h
index 4e7d5d65..cce967fd 100644
--- a/include/linux/prcu.h
+++ b/include/linux/prcu.h
@@ -5,6 +5,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #define CONFIG_PRCU
 
@@ -32,6 +33,7 @@ struct prcu_local_struct {
unsigned int online;
unsigned long long version;
unsigned long long cb_version;
+   struct rcu_head barrier_head;
struct prcu_cblist cblist;
 };
 
@@ -39,8 +41,11 @@ struct prcu_struct {
atomic64_t global_version;
atomic64_t cb_version;
atomic_t active_ctr;
+   atomic_t barrier_cpu_count;
struct mutex mtx;
+   struct mutex barrier_mtx;
wait_queue_head_t wait_q;
+   struct completion barrier_completion;
 };
 
 #ifdef CONFIG_PRCU
@@ -48,6 +53,7 @@ void prcu_read_lock(void);
 void prcu_read_unlock(void);
 void synchronize_prcu(void);
 void call_prcu(struct rcu_head *head, rcu_callback_t func);
+void prcu_barrier(void);
 void prcu_init(void);
 void prcu_note_context_switch(void);
 int prcu_pending(void);
@@ -60,6 +66,7 @@ void prcu_check_callbacks(void);
 #define prcu_read_unlock() do {} while (0)
 #define synchronize_prcu() do {} while (0)
 #define call_prcu() do {} while (0)
+#define prcu_barrier() do {} while (0)
 #define prcu_init() do {} while (0)
 #define prcu_note_context_switch() do {} while (0)
 #define prcu_pending() 0
diff --git a/kernel/rcu/prcu.c b/kernel/rcu/prcu.c
index 373039c5..2664d091 100644
--- a/kernel/rcu/prcu.c
+++ b/kernel/rcu/prcu.c
@@ -15,6 +15,7 @@ struct prcu_struct global_prcu = {
.cb_version = ATOMIC64_INIT(0),
.active_ctr = ATOMIC_INIT(0),
.mtx = __MUTEX_INITIALIZER(global_prcu.mtx),
+   .barrier_mtx = __MUTEX_INITIALIZER(global_prcu.barrier_mtx),
.wait_q = __WAIT_QUEUE_HEAD_INITIALIZER(global_prcu.wait_q)
 };
 struct prcu_struct *prcu = _prcu;
@@ -250,6 +251,68 @@ static __latent_entropy void prcu_process_callbacks(struct 
softirq_action *unuse
local_irq_restore(flags);
 }
 
+/*
+ * PRCU callback function for prcu_barrier().
+ * If we are last, wake up the task executing prcu_barrier().
+ */
+static void prcu_barrier_callback(struct rcu_head *rhp)
+{
+   if (atomic_dec_and_test(>barrier_cpu_count))
+   complete(>barrier_completion);
+}
+
+/*
+ * Called with preemption disabled, and from cross-cpu IRQ context.
+ */
+static void prcu_barrier_func(void *info)
+{
+   struct prcu_local_struct *local = this_cpu_ptr(_local);
+
+   atomic_inc(>barrier_cpu_count);
+   call_prcu(>barrier_head, prcu_barrier_callback);
+}
+
+/* Waiting for all PRCU callbacks to complete. */
+void prcu_barrier(void)
+{
+   int cpu;
+
+   /* Take mutex to serialize concurrent prcu_barrier() requests. */
+   mutex_lock(>barrier_mtx);
+
+   /*
+* Initialize the count to one rather than to zero in order to
+* avoid a too-soon return to zero in case of a short grace period
+* (or preemption of this task).
+*/
+   init_completion(>barrier_completion);
+   atomic_set(>barrier_cpu_count, 1);
+
+   /*
+* Register a new callback on each CPU using IPI to prevent races
+* with call_prcu(). When that callback is invoked, we will know
+* that all of the corresponding CPU's preceding callbacks have
+* been invoked.
+*/
+   for_each_possible_cpu(cpu)
+   smp_call_function_single(cpu, prcu_barrier_func, NULL, 1);
+
+   /* Decrement the count as we initialize it to one. */
+   if (atomic_dec_and_test(>barrier_cpu_count))
+   complete(>barrier_completion);
+
+   /*
+* Now that we have an prcu_barrier_callback() callback on each
+* CPU, and thus each counted, remove the initial count.
+* Wait for all prcu_barrier_callback() callbacks to be invoked.
+*/
+   wait_for_completion(>barrier_completion);
+
+   /* Other rcu_barrier() invocations can now safely proceed. */
+   mutex_unlock(>barrier_mtx);
+}
+EXPORT_SYMBOL(prcu_barrier);
+
 void prcu_init_local_struct(int cpu)
 {
struct prcu_local_struct *local;
-- 
2.14.1.729.g59c0ea183



[PATCH RFC 06/16] rcuperf: Set gp_exp to true for tests to run

2018-01-23 Thread lianglihao
From: Lihao Liang 

Signed-off-by: Lihao Liang 
---
 kernel/rcu/rcuperf.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel/rcu/rcuperf.c b/kernel/rcu/rcuperf.c
index ea80fa3e..baccc123 100644
--- a/kernel/rcu/rcuperf.c
+++ b/kernel/rcu/rcuperf.c
@@ -60,7 +60,7 @@ MODULE_AUTHOR("Paul E. McKenney 
");
 #define VERBOSE_PERFOUT_ERRSTRING(s) \
do { if (verbose) pr_alert("%s" PERF_FLAG "!!! %s\n", perf_type, s); } 
while (0)
 
-torture_param(bool, gp_exp, false, "Use expedited GP wait primitives");
+torture_param(bool, gp_exp, true, "Use expedited GP wait primitives");
 torture_param(int, holdoff, 10, "Holdoff time before test start (s)");
 torture_param(int, nreaders, -1, "Number of RCU reader threads");
 torture_param(int, nwriters, -1, "Number of RCU updater threads");
-- 
2.14.1.729.g59c0ea183



[PATCH RFC 11/16] rcutorture: Add basic ARM64 support to run scripts

2018-01-23 Thread lianglihao
From: Lihao Liang 

This commit adds support of the qemu command qemu-system-aarch64
to rcutorture.

Signed-off-by: Lihao Liang 
---
 tools/testing/selftests/rcutorture/bin/functions.sh | 17 +++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/rcutorture/bin/functions.sh 
b/tools/testing/selftests/rcutorture/bin/functions.sh
index 1426a9b9..4a24b873 100644
--- a/tools/testing/selftests/rcutorture/bin/functions.sh
+++ b/tools/testing/selftests/rcutorture/bin/functions.sh
@@ -111,6 +111,9 @@ identify_boot_image () {
qemu-system-x86_64|qemu-system-i386)
echo arch/x86/boot/bzImage
;;
+   qemu-system-aarch64)
+   echo arch/arm64/boot/Image
+   ;;
*)
echo vmlinux
;;
@@ -133,6 +136,9 @@ identify_qemu () {
elif echo $u | grep -q "Intel 80386"
then
echo qemu-system-i386
+   elif echo $u | grep -q aarch64
+   then
+   echo qemu-system-aarch64
elif uname -a | grep -q ppc64
then
echo qemu-system-ppc64
@@ -151,16 +157,20 @@ identify_qemu () {
 # Output arguments for the qemu "-append" string based on CPU type
 # and the TORTURE_QEMU_INTERACTIVE environment variable.
 identify_qemu_append () {
+   local console=ttyS0
case "$1" in
qemu-system-x86_64|qemu-system-i386)
echo noapic selinux=0 initcall_debug debug
;;
+   qemu-system-aarch64)
+   console=ttyAMA0
+   ;;
esac
if test -n "$TORTURE_QEMU_INTERACTIVE"
then
echo root=/dev/sda
else
-   echo console=ttyS0
+   echo console=$console
fi
 }
 
@@ -172,6 +182,9 @@ identify_qemu_args () {
case "$1" in
qemu-system-x86_64|qemu-system-i386)
;;
+   qemu-system-arm|qemu-system-aarch64)
+   echo -machine virt,gic-version=host -cpu host
+   ;;
qemu-system-ppc64)
echo -enable-kvm -M pseries -nodefaults
echo -device spapr-vscsi
@@ -229,7 +242,7 @@ specify_qemu_cpus () {
echo $2
else
case "$1" in
-   qemu-system-x86_64|qemu-system-i386)
+   qemu-system-x86_64|qemu-system-i386|qemu-system-aarch64)
echo $2 -smp $3
;;
qemu-system-ppc64)
-- 
2.14.1.729.g59c0ea183



[PATCH RFC 06/16] rcuperf: Set gp_exp to true for tests to run

2018-01-23 Thread lianglihao
From: Lihao Liang 

Signed-off-by: Lihao Liang 
---
 kernel/rcu/rcuperf.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel/rcu/rcuperf.c b/kernel/rcu/rcuperf.c
index ea80fa3e..baccc123 100644
--- a/kernel/rcu/rcuperf.c
+++ b/kernel/rcu/rcuperf.c
@@ -60,7 +60,7 @@ MODULE_AUTHOR("Paul E. McKenney 
");
 #define VERBOSE_PERFOUT_ERRSTRING(s) \
do { if (verbose) pr_alert("%s" PERF_FLAG "!!! %s\n", perf_type, s); } 
while (0)
 
-torture_param(bool, gp_exp, false, "Use expedited GP wait primitives");
+torture_param(bool, gp_exp, true, "Use expedited GP wait primitives");
 torture_param(int, holdoff, 10, "Holdoff time before test start (s)");
 torture_param(int, nreaders, -1, "Number of RCU reader threads");
 torture_param(int, nwriters, -1, "Number of RCU updater threads");
-- 
2.14.1.729.g59c0ea183



[PATCH RFC 11/16] rcutorture: Add basic ARM64 support to run scripts

2018-01-23 Thread lianglihao
From: Lihao Liang 

This commit adds support of the qemu command qemu-system-aarch64
to rcutorture.

Signed-off-by: Lihao Liang 
---
 tools/testing/selftests/rcutorture/bin/functions.sh | 17 +++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/rcutorture/bin/functions.sh 
b/tools/testing/selftests/rcutorture/bin/functions.sh
index 1426a9b9..4a24b873 100644
--- a/tools/testing/selftests/rcutorture/bin/functions.sh
+++ b/tools/testing/selftests/rcutorture/bin/functions.sh
@@ -111,6 +111,9 @@ identify_boot_image () {
qemu-system-x86_64|qemu-system-i386)
echo arch/x86/boot/bzImage
;;
+   qemu-system-aarch64)
+   echo arch/arm64/boot/Image
+   ;;
*)
echo vmlinux
;;
@@ -133,6 +136,9 @@ identify_qemu () {
elif echo $u | grep -q "Intel 80386"
then
echo qemu-system-i386
+   elif echo $u | grep -q aarch64
+   then
+   echo qemu-system-aarch64
elif uname -a | grep -q ppc64
then
echo qemu-system-ppc64
@@ -151,16 +157,20 @@ identify_qemu () {
 # Output arguments for the qemu "-append" string based on CPU type
 # and the TORTURE_QEMU_INTERACTIVE environment variable.
 identify_qemu_append () {
+   local console=ttyS0
case "$1" in
qemu-system-x86_64|qemu-system-i386)
echo noapic selinux=0 initcall_debug debug
;;
+   qemu-system-aarch64)
+   console=ttyAMA0
+   ;;
esac
if test -n "$TORTURE_QEMU_INTERACTIVE"
then
echo root=/dev/sda
else
-   echo console=ttyS0
+   echo console=$console
fi
 }
 
@@ -172,6 +182,9 @@ identify_qemu_args () {
case "$1" in
qemu-system-x86_64|qemu-system-i386)
;;
+   qemu-system-arm|qemu-system-aarch64)
+   echo -machine virt,gic-version=host -cpu host
+   ;;
qemu-system-ppc64)
echo -enable-kvm -M pseries -nodefaults
echo -device spapr-vscsi
@@ -229,7 +242,7 @@ specify_qemu_cpus () {
echo $2
else
case "$1" in
-   qemu-system-x86_64|qemu-system-i386)
+   qemu-system-x86_64|qemu-system-i386|qemu-system-aarch64)
echo $2 -smp $3
;;
qemu-system-ppc64)
-- 
2.14.1.729.g59c0ea183



[PATCH RFC 07/16] prcu: Implement call_prcu() API

2018-01-23 Thread lianglihao
From: Lihao Liang 

This is PRCU's counterpart of RCU's call_rcu() API.

Reviewed-by: Heng Zhang 
Signed-off-by: Lihao Liang 
---
 include/linux/prcu.h | 25 
 init/main.c  |  2 ++
 kernel/rcu/prcu.c| 67 +---
 3 files changed, 91 insertions(+), 3 deletions(-)

diff --git a/include/linux/prcu.h b/include/linux/prcu.h
index 653b4633..e5e09c9b 100644
--- a/include/linux/prcu.h
+++ b/include/linux/prcu.h
@@ -2,15 +2,36 @@
 #define __LINUX_PRCU_H
 
 #include 
+#include 
 #include 
 #include 
 
 #define CONFIG_PRCU
 
+struct prcu_version_head {
+   unsigned long long version;
+   struct prcu_version_head *next;
+};
+
+/* Simple unsegmented callback list for PRCU. */
+struct prcu_cblist {
+   struct rcu_head *head;
+   struct rcu_head **tail;
+   struct prcu_version_head *version_head;
+   struct prcu_version_head **version_tail;
+   long len;
+};
+
+#define PRCU_CBLIST_INITIALIZER(n) { \
+   .head = NULL, .tail = , \
+   .version_head = NULL, .version_tail = _head, \
+}
+
 struct prcu_local_struct {
unsigned int locked;
unsigned int online;
unsigned long long version;
+   struct prcu_cblist cblist;
 };
 
 struct prcu_struct {
@@ -24,6 +45,8 @@ struct prcu_struct {
 void prcu_read_lock(void);
 void prcu_read_unlock(void);
 void synchronize_prcu(void);
+void call_prcu(struct rcu_head *head, rcu_callback_t func);
+void prcu_init(void);
 void prcu_note_context_switch(void);
 
 #else /* #ifdef CONFIG_PRCU */
@@ -31,6 +54,8 @@ void prcu_note_context_switch(void);
 #define prcu_read_lock() do {} while (0)
 #define prcu_read_unlock() do {} while (0)
 #define synchronize_prcu() do {} while (0)
+#define call_prcu() do {} while (0)
+#define prcu_init() do {} while (0)
 #define prcu_note_context_switch() do {} while (0)
 
 #endif /* #ifdef CONFIG_PRCU */
diff --git a/init/main.c b/init/main.c
index f8665104..4925964e 100644
--- a/init/main.c
+++ b/init/main.c
@@ -38,6 +38,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -574,6 +575,7 @@ asmlinkage __visible void __init start_kernel(void)
workqueue_init_early();
 
rcu_init();
+   prcu_init();
 
/* Trace events are available after this */
trace_init();
diff --git a/kernel/rcu/prcu.c b/kernel/rcu/prcu.c
index a00b9420..f198285c 100644
--- a/kernel/rcu/prcu.c
+++ b/kernel/rcu/prcu.c
@@ -1,11 +1,12 @@
 #include 
-#include 
 #include 
-#include 
+#include 
 #include 
-
+#include 
 #include 
 
+#include "rcu.h"
+
 DEFINE_PER_CPU_SHARED_ALIGNED(struct prcu_local_struct, prcu_local);
 
 struct prcu_struct global_prcu = {
@@ -16,6 +17,16 @@ struct prcu_struct global_prcu = {
 };
 struct prcu_struct *prcu = _prcu;
 
+/* Initialize simple callback list. */
+static void prcu_cblist_init(struct prcu_cblist *rclp)
+{
+   rclp->head = NULL;
+   rclp->tail = >head;
+   rclp->version_head = NULL;
+   rclp->version_tail = >version_head;
+   rclp->len = 0;
+}
+
 static inline void prcu_report(struct prcu_local_struct *local)
 {
unsigned long long global_version;
@@ -123,3 +134,53 @@ void prcu_note_context_switch(void)
prcu_report(local);
put_cpu_ptr(_local);
 }
+
+void call_prcu(struct rcu_head *head, rcu_callback_t func)
+{
+   unsigned long flags;
+   struct prcu_local_struct *local;
+   struct prcu_cblist *rclp;
+   struct prcu_version_head *vhp;
+
+   debug_rcu_head_queue(head);
+
+   /* Use GFP_ATOMIC with IRQs disabled */
+   vhp = kmalloc(sizeof(struct prcu_version_head), GFP_ATOMIC);
+   if (!vhp)
+   return;
+
+   head->func = func;
+   head->next = NULL;
+   vhp->next = NULL;
+
+   local_irq_save(flags);
+   local = this_cpu_ptr(_local);
+   vhp->version = local->version;
+   rclp = >cblist;
+   rclp->len++;
+   *rclp->tail = head;
+   rclp->tail = >next;
+   *rclp->version_tail = vhp;
+   rclp->version_tail = >next;
+   local_irq_restore(flags);
+}
+EXPORT_SYMBOL(call_prcu);
+
+void prcu_init_local_struct(int cpu)
+{
+   struct prcu_local_struct *local;
+
+   local = per_cpu_ptr(_local, cpu);
+   local->locked = 0;
+   local->online = 0;
+   local->version = 0;
+   prcu_cblist_init(>cblist);
+}
+
+void __init prcu_init(void)
+{
+   int cpu;
+
+   for_each_possible_cpu(cpu)
+   prcu_init_local_struct(cpu);
+}
-- 
2.14.1.729.g59c0ea183



[PATCH RFC 07/16] prcu: Implement call_prcu() API

2018-01-23 Thread lianglihao
From: Lihao Liang 

This is PRCU's counterpart of RCU's call_rcu() API.

Reviewed-by: Heng Zhang 
Signed-off-by: Lihao Liang 
---
 include/linux/prcu.h | 25 
 init/main.c  |  2 ++
 kernel/rcu/prcu.c| 67 +---
 3 files changed, 91 insertions(+), 3 deletions(-)

diff --git a/include/linux/prcu.h b/include/linux/prcu.h
index 653b4633..e5e09c9b 100644
--- a/include/linux/prcu.h
+++ b/include/linux/prcu.h
@@ -2,15 +2,36 @@
 #define __LINUX_PRCU_H
 
 #include 
+#include 
 #include 
 #include 
 
 #define CONFIG_PRCU
 
+struct prcu_version_head {
+   unsigned long long version;
+   struct prcu_version_head *next;
+};
+
+/* Simple unsegmented callback list for PRCU. */
+struct prcu_cblist {
+   struct rcu_head *head;
+   struct rcu_head **tail;
+   struct prcu_version_head *version_head;
+   struct prcu_version_head **version_tail;
+   long len;
+};
+
+#define PRCU_CBLIST_INITIALIZER(n) { \
+   .head = NULL, .tail = , \
+   .version_head = NULL, .version_tail = _head, \
+}
+
 struct prcu_local_struct {
unsigned int locked;
unsigned int online;
unsigned long long version;
+   struct prcu_cblist cblist;
 };
 
 struct prcu_struct {
@@ -24,6 +45,8 @@ struct prcu_struct {
 void prcu_read_lock(void);
 void prcu_read_unlock(void);
 void synchronize_prcu(void);
+void call_prcu(struct rcu_head *head, rcu_callback_t func);
+void prcu_init(void);
 void prcu_note_context_switch(void);
 
 #else /* #ifdef CONFIG_PRCU */
@@ -31,6 +54,8 @@ void prcu_note_context_switch(void);
 #define prcu_read_lock() do {} while (0)
 #define prcu_read_unlock() do {} while (0)
 #define synchronize_prcu() do {} while (0)
+#define call_prcu() do {} while (0)
+#define prcu_init() do {} while (0)
 #define prcu_note_context_switch() do {} while (0)
 
 #endif /* #ifdef CONFIG_PRCU */
diff --git a/init/main.c b/init/main.c
index f8665104..4925964e 100644
--- a/init/main.c
+++ b/init/main.c
@@ -38,6 +38,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -574,6 +575,7 @@ asmlinkage __visible void __init start_kernel(void)
workqueue_init_early();
 
rcu_init();
+   prcu_init();
 
/* Trace events are available after this */
trace_init();
diff --git a/kernel/rcu/prcu.c b/kernel/rcu/prcu.c
index a00b9420..f198285c 100644
--- a/kernel/rcu/prcu.c
+++ b/kernel/rcu/prcu.c
@@ -1,11 +1,12 @@
 #include 
-#include 
 #include 
-#include 
+#include 
 #include 
-
+#include 
 #include 
 
+#include "rcu.h"
+
 DEFINE_PER_CPU_SHARED_ALIGNED(struct prcu_local_struct, prcu_local);
 
 struct prcu_struct global_prcu = {
@@ -16,6 +17,16 @@ struct prcu_struct global_prcu = {
 };
 struct prcu_struct *prcu = _prcu;
 
+/* Initialize simple callback list. */
+static void prcu_cblist_init(struct prcu_cblist *rclp)
+{
+   rclp->head = NULL;
+   rclp->tail = >head;
+   rclp->version_head = NULL;
+   rclp->version_tail = >version_head;
+   rclp->len = 0;
+}
+
 static inline void prcu_report(struct prcu_local_struct *local)
 {
unsigned long long global_version;
@@ -123,3 +134,53 @@ void prcu_note_context_switch(void)
prcu_report(local);
put_cpu_ptr(_local);
 }
+
+void call_prcu(struct rcu_head *head, rcu_callback_t func)
+{
+   unsigned long flags;
+   struct prcu_local_struct *local;
+   struct prcu_cblist *rclp;
+   struct prcu_version_head *vhp;
+
+   debug_rcu_head_queue(head);
+
+   /* Use GFP_ATOMIC with IRQs disabled */
+   vhp = kmalloc(sizeof(struct prcu_version_head), GFP_ATOMIC);
+   if (!vhp)
+   return;
+
+   head->func = func;
+   head->next = NULL;
+   vhp->next = NULL;
+
+   local_irq_save(flags);
+   local = this_cpu_ptr(_local);
+   vhp->version = local->version;
+   rclp = >cblist;
+   rclp->len++;
+   *rclp->tail = head;
+   rclp->tail = >next;
+   *rclp->version_tail = vhp;
+   rclp->version_tail = >next;
+   local_irq_restore(flags);
+}
+EXPORT_SYMBOL(call_prcu);
+
+void prcu_init_local_struct(int cpu)
+{
+   struct prcu_local_struct *local;
+
+   local = per_cpu_ptr(_local, cpu);
+   local->locked = 0;
+   local->online = 0;
+   local->version = 0;
+   prcu_cblist_init(>cblist);
+}
+
+void __init prcu_init(void)
+{
+   int cpu;
+
+   for_each_possible_cpu(cpu)
+   prcu_init_local_struct(cpu);
+}
-- 
2.14.1.729.g59c0ea183



[PATCH RFC 14/16] rcuperf: Add config files with various CONFIG_NR_CPUS

2018-01-23 Thread lianglihao
From: Lihao Liang 

Signed-off-by: Lihao Liang 
---
 .../selftests/rcutorture/configs/rcuperf/PRCU-12| 21 +
 .../rcutorture/configs/rcuperf/PRCU-12.boot |  1 +
 .../selftests/rcutorture/configs/rcuperf/PRCU-14| 21 +
 .../rcutorture/configs/rcuperf/PRCU-14.boot |  1 +
 .../selftests/rcutorture/configs/rcuperf/PRCU-15| 21 +
 .../rcutorture/configs/rcuperf/PRCU-15.boot |  1 +
 .../selftests/rcutorture/configs/rcuperf/PRCU-16| 21 +
 .../rcutorture/configs/rcuperf/PRCU-16.boot |  1 +
 .../selftests/rcutorture/configs/rcuperf/PRCU-2 | 21 +
 .../rcutorture/configs/rcuperf/PRCU-2.boot  |  1 +
 .../selftests/rcutorture/configs/rcuperf/PRCU-32| 21 +
 .../rcutorture/configs/rcuperf/PRCU-32.boot |  1 +
 .../selftests/rcutorture/configs/rcuperf/PRCU-4 | 21 +
 .../rcutorture/configs/rcuperf/PRCU-4.boot  |  1 +
 .../selftests/rcutorture/configs/rcuperf/PRCU-48| 21 +
 .../rcutorture/configs/rcuperf/PRCU-48.boot |  1 +
 .../selftests/rcutorture/configs/rcuperf/PRCU-56| 21 +
 .../rcutorture/configs/rcuperf/PRCU-56.boot |  1 +
 .../selftests/rcutorture/configs/rcuperf/PRCU-60| 21 +
 .../rcutorture/configs/rcuperf/PRCU-60.boot |  1 +
 .../selftests/rcutorture/configs/rcuperf/PRCU-62| 21 +
 .../rcutorture/configs/rcuperf/PRCU-62.boot |  1 +
 .../selftests/rcutorture/configs/rcuperf/PRCU-64| 21 +
 .../rcutorture/configs/rcuperf/PRCU-64.boot |  1 +
 .../selftests/rcutorture/configs/rcuperf/PRCU-8 | 21 +
 .../rcutorture/configs/rcuperf/PRCU-8.boot  |  1 +
 .../selftests/rcutorture/configs/rcuperf/TREE-12| 21 +
 .../selftests/rcutorture/configs/rcuperf/TREE-14| 21 +
 .../selftests/rcutorture/configs/rcuperf/TREE-15| 21 +
 .../selftests/rcutorture/configs/rcuperf/TREE-16| 21 +
 .../selftests/rcutorture/configs/rcuperf/TREE-2 | 21 +
 .../selftests/rcutorture/configs/rcuperf/TREE-32| 21 +
 .../selftests/rcutorture/configs/rcuperf/TREE-4 | 21 +
 .../selftests/rcutorture/configs/rcuperf/TREE-48| 21 +
 .../selftests/rcutorture/configs/rcuperf/TREE-56| 21 +
 .../selftests/rcutorture/configs/rcuperf/TREE-60| 21 +
 .../selftests/rcutorture/configs/rcuperf/TREE-62| 21 +
 .../selftests/rcutorture/configs/rcuperf/TREE-64| 21 +
 .../selftests/rcutorture/configs/rcuperf/TREE-8 | 21 +
 39 files changed, 559 insertions(+)
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-12
 create mode 100644 
tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-12.boot
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-14
 create mode 100644 
tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-14.boot
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-15
 create mode 100644 
tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-15.boot
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-16
 create mode 100644 
tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-16.boot
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-2
 create mode 100644 
tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-2.boot
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-32
 create mode 100644 
tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-32.boot
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-4
 create mode 100644 
tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-4.boot
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-48
 create mode 100644 
tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-48.boot
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-56
 create mode 100644 
tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-56.boot
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-60
 create mode 100644 
tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-60.boot
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-62
 create mode 100644 
tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-62.boot
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-64
 create mode 100644 
tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-64.boot
 create mode 100644 

[PATCH RFC 14/16] rcuperf: Add config files with various CONFIG_NR_CPUS

2018-01-23 Thread lianglihao
From: Lihao Liang 

Signed-off-by: Lihao Liang 
---
 .../selftests/rcutorture/configs/rcuperf/PRCU-12| 21 +
 .../rcutorture/configs/rcuperf/PRCU-12.boot |  1 +
 .../selftests/rcutorture/configs/rcuperf/PRCU-14| 21 +
 .../rcutorture/configs/rcuperf/PRCU-14.boot |  1 +
 .../selftests/rcutorture/configs/rcuperf/PRCU-15| 21 +
 .../rcutorture/configs/rcuperf/PRCU-15.boot |  1 +
 .../selftests/rcutorture/configs/rcuperf/PRCU-16| 21 +
 .../rcutorture/configs/rcuperf/PRCU-16.boot |  1 +
 .../selftests/rcutorture/configs/rcuperf/PRCU-2 | 21 +
 .../rcutorture/configs/rcuperf/PRCU-2.boot  |  1 +
 .../selftests/rcutorture/configs/rcuperf/PRCU-32| 21 +
 .../rcutorture/configs/rcuperf/PRCU-32.boot |  1 +
 .../selftests/rcutorture/configs/rcuperf/PRCU-4 | 21 +
 .../rcutorture/configs/rcuperf/PRCU-4.boot  |  1 +
 .../selftests/rcutorture/configs/rcuperf/PRCU-48| 21 +
 .../rcutorture/configs/rcuperf/PRCU-48.boot |  1 +
 .../selftests/rcutorture/configs/rcuperf/PRCU-56| 21 +
 .../rcutorture/configs/rcuperf/PRCU-56.boot |  1 +
 .../selftests/rcutorture/configs/rcuperf/PRCU-60| 21 +
 .../rcutorture/configs/rcuperf/PRCU-60.boot |  1 +
 .../selftests/rcutorture/configs/rcuperf/PRCU-62| 21 +
 .../rcutorture/configs/rcuperf/PRCU-62.boot |  1 +
 .../selftests/rcutorture/configs/rcuperf/PRCU-64| 21 +
 .../rcutorture/configs/rcuperf/PRCU-64.boot |  1 +
 .../selftests/rcutorture/configs/rcuperf/PRCU-8 | 21 +
 .../rcutorture/configs/rcuperf/PRCU-8.boot  |  1 +
 .../selftests/rcutorture/configs/rcuperf/TREE-12| 21 +
 .../selftests/rcutorture/configs/rcuperf/TREE-14| 21 +
 .../selftests/rcutorture/configs/rcuperf/TREE-15| 21 +
 .../selftests/rcutorture/configs/rcuperf/TREE-16| 21 +
 .../selftests/rcutorture/configs/rcuperf/TREE-2 | 21 +
 .../selftests/rcutorture/configs/rcuperf/TREE-32| 21 +
 .../selftests/rcutorture/configs/rcuperf/TREE-4 | 21 +
 .../selftests/rcutorture/configs/rcuperf/TREE-48| 21 +
 .../selftests/rcutorture/configs/rcuperf/TREE-56| 21 +
 .../selftests/rcutorture/configs/rcuperf/TREE-60| 21 +
 .../selftests/rcutorture/configs/rcuperf/TREE-62| 21 +
 .../selftests/rcutorture/configs/rcuperf/TREE-64| 21 +
 .../selftests/rcutorture/configs/rcuperf/TREE-8 | 21 +
 39 files changed, 559 insertions(+)
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-12
 create mode 100644 
tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-12.boot
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-14
 create mode 100644 
tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-14.boot
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-15
 create mode 100644 
tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-15.boot
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-16
 create mode 100644 
tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-16.boot
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-2
 create mode 100644 
tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-2.boot
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-32
 create mode 100644 
tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-32.boot
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-4
 create mode 100644 
tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-4.boot
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-48
 create mode 100644 
tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-48.boot
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-56
 create mode 100644 
tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-56.boot
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-60
 create mode 100644 
tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-60.boot
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-62
 create mode 100644 
tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-62.boot
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-64
 create mode 100644 
tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-64.boot
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcuperf/PRCU-8
 create 

[PATCH v3] rcutorture: Add basic ARM64 support to run scripts

2018-01-12 Thread lianglihao
From: Lihao Liang 

This commit adds support of the qemu command qemu-system-aarch64
to rcutorture.

Signed-off-by: Lihao Liang 
---

Comparing to the previous version, this patch lifts the limitation of
maximum 8 CPUs of option "-M virt" by adding "gic-version=host" to it.
This allows qemu to use the maximum CPU number supported by the actual
hardware.

This commit is against RCU's git branch rcu/dev

commit 505b61b2ec1d ("EXP: rcu: Add debugging info to other assertion")


 tools/testing/selftests/rcutorture/bin/functions.sh | 17 +++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/rcutorture/bin/functions.sh 
b/tools/testing/selftests/rcutorture/bin/functions.sh
index 07a1377..65f6655 100644
--- a/tools/testing/selftests/rcutorture/bin/functions.sh
+++ b/tools/testing/selftests/rcutorture/bin/functions.sh
@@ -136,6 +136,9 @@ identify_boot_image () {
qemu-system-x86_64|qemu-system-i386)
echo arch/x86/boot/bzImage
;;
+   qemu-system-aarch64)
+   echo arch/arm64/boot/Image
+   ;;
*)
echo vmlinux
;;
@@ -158,6 +161,9 @@ identify_qemu () {
elif echo $u | grep -q "Intel 80386"
then
echo qemu-system-i386
+   elif echo $u | grep -q aarch64
+   then
+   echo qemu-system-aarch64
elif uname -a | grep -q ppc64
then
echo qemu-system-ppc64
@@ -176,16 +182,20 @@ identify_qemu () {
 # Output arguments for the qemu "-append" string based on CPU type
 # and the TORTURE_QEMU_INTERACTIVE environment variable.
 identify_qemu_append () {
+   local console=ttyS0
case "$1" in
qemu-system-x86_64|qemu-system-i386)
echo noapic selinux=0 initcall_debug debug
;;
+   qemu-system-aarch64)
+   console=ttyAMA0
+   ;;
esac
if test -n "$TORTURE_QEMU_INTERACTIVE"
then
echo root=/dev/sda
else
-   echo console=ttyS0
+   echo console=$console
fi
 }
 
@@ -197,6 +207,9 @@ identify_qemu_args () {
case "$1" in
qemu-system-x86_64|qemu-system-i386)
;;
+   qemu-system-aarch64)
+   echo -machine virt,gic-version=host -cpu host
+   ;;
qemu-system-ppc64)
echo -enable-kvm -M pseries -nodefaults
echo -device spapr-vscsi
@@ -254,7 +267,7 @@ specify_qemu_cpus () {
echo $2
else
case "$1" in
-   qemu-system-x86_64|qemu-system-i386)
+   qemu-system-x86_64|qemu-system-i386|qemu-system-aarch64)
echo $2 -smp $3
;;
qemu-system-ppc64)
-- 
2.7.4



[PATCH v3] rcutorture: Add basic ARM64 support to run scripts

2018-01-12 Thread lianglihao
From: Lihao Liang 

This commit adds support of the qemu command qemu-system-aarch64
to rcutorture.

Signed-off-by: Lihao Liang 
---

Comparing to the previous version, this patch lifts the limitation of
maximum 8 CPUs of option "-M virt" by adding "gic-version=host" to it.
This allows qemu to use the maximum CPU number supported by the actual
hardware.

This commit is against RCU's git branch rcu/dev

commit 505b61b2ec1d ("EXP: rcu: Add debugging info to other assertion")


 tools/testing/selftests/rcutorture/bin/functions.sh | 17 +++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/rcutorture/bin/functions.sh 
b/tools/testing/selftests/rcutorture/bin/functions.sh
index 07a1377..65f6655 100644
--- a/tools/testing/selftests/rcutorture/bin/functions.sh
+++ b/tools/testing/selftests/rcutorture/bin/functions.sh
@@ -136,6 +136,9 @@ identify_boot_image () {
qemu-system-x86_64|qemu-system-i386)
echo arch/x86/boot/bzImage
;;
+   qemu-system-aarch64)
+   echo arch/arm64/boot/Image
+   ;;
*)
echo vmlinux
;;
@@ -158,6 +161,9 @@ identify_qemu () {
elif echo $u | grep -q "Intel 80386"
then
echo qemu-system-i386
+   elif echo $u | grep -q aarch64
+   then
+   echo qemu-system-aarch64
elif uname -a | grep -q ppc64
then
echo qemu-system-ppc64
@@ -176,16 +182,20 @@ identify_qemu () {
 # Output arguments for the qemu "-append" string based on CPU type
 # and the TORTURE_QEMU_INTERACTIVE environment variable.
 identify_qemu_append () {
+   local console=ttyS0
case "$1" in
qemu-system-x86_64|qemu-system-i386)
echo noapic selinux=0 initcall_debug debug
;;
+   qemu-system-aarch64)
+   console=ttyAMA0
+   ;;
esac
if test -n "$TORTURE_QEMU_INTERACTIVE"
then
echo root=/dev/sda
else
-   echo console=ttyS0
+   echo console=$console
fi
 }
 
@@ -197,6 +207,9 @@ identify_qemu_args () {
case "$1" in
qemu-system-x86_64|qemu-system-i386)
;;
+   qemu-system-aarch64)
+   echo -machine virt,gic-version=host -cpu host
+   ;;
qemu-system-ppc64)
echo -enable-kvm -M pseries -nodefaults
echo -device spapr-vscsi
@@ -254,7 +267,7 @@ specify_qemu_cpus () {
echo $2
else
case "$1" in
-   qemu-system-x86_64|qemu-system-i386)
+   qemu-system-x86_64|qemu-system-i386|qemu-system-aarch64)
echo $2 -smp $3
;;
qemu-system-ppc64)
-- 
2.7.4



[PATCH v2] rcutorture: Add basic ARM64 support to run scripts

2017-12-12 Thread lianglihao
From: Lihao Liang 

This commit adds support of the qemu command qemu-system-aarch64
to rcutorture.

Signed-off-by: Lihao Liang 
---
This commit is against RCU's git tree rcu/dev branch

commit 505b61b2ec1d ("EXP: rcu: Add debugging info to other assertion")

Note that the max CPUs supported by qemu machine 'virt' is 8 so the value of
CONFIG_NR_CPUS in some test configuration files needs to be adjusted.

 tools/testing/selftests/rcutorture/bin/functions.sh | 17 +++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/rcutorture/bin/functions.sh 
b/tools/testing/selftests/rcutorture/bin/functions.sh
index 07a1377..0541d10 100644
--- a/tools/testing/selftests/rcutorture/bin/functions.sh
+++ b/tools/testing/selftests/rcutorture/bin/functions.sh
@@ -136,6 +136,9 @@ identify_boot_image () {
qemu-system-x86_64|qemu-system-i386)
echo arch/x86/boot/bzImage
;;
+   qemu-system-aarch64)
+   echo arch/arm64/boot/Image
+   ;;
*)
echo vmlinux
;;
@@ -158,6 +161,9 @@ identify_qemu () {
elif echo $u | grep -q "Intel 80386"
then
echo qemu-system-i386
+   elif echo $u | grep -q aarch64
+   then
+   echo qemu-system-aarch64
elif uname -a | grep -q ppc64
then
echo qemu-system-ppc64
@@ -176,16 +182,20 @@ identify_qemu () {
 # Output arguments for the qemu "-append" string based on CPU type
 # and the TORTURE_QEMU_INTERACTIVE environment variable.
 identify_qemu_append () {
+   local console=ttyS0
case "$1" in
qemu-system-x86_64|qemu-system-i386)
echo noapic selinux=0 initcall_debug debug
;;
+   qemu-system-aarch64)
+   console=ttyAMA0
+   ;;
esac
if test -n "$TORTURE_QEMU_INTERACTIVE"
then
echo root=/dev/sda
else
-   echo console=ttyS0
+   echo console=$console
fi
 }
 
@@ -197,6 +207,9 @@ identify_qemu_args () {
case "$1" in
qemu-system-x86_64|qemu-system-i386)
;;
+   qemu-system-aarch64)
+   echo -M virt -cpu host
+   ;;
qemu-system-ppc64)
echo -enable-kvm -M pseries -nodefaults
echo -device spapr-vscsi
@@ -254,7 +267,7 @@ specify_qemu_cpus () {
echo $2
else
case "$1" in
-   qemu-system-x86_64|qemu-system-i386)
+   qemu-system-x86_64|qemu-system-i386|qemu-system-aarch64)
echo $2 -smp $3
;;
qemu-system-ppc64)
-- 
2.7.4



[PATCH v2] rcutorture: Add basic ARM64 support to run scripts

2017-12-12 Thread lianglihao
From: Lihao Liang 

This commit adds support of the qemu command qemu-system-aarch64
to rcutorture.

Signed-off-by: Lihao Liang 
---
This commit is against RCU's git tree rcu/dev branch

commit 505b61b2ec1d ("EXP: rcu: Add debugging info to other assertion")

Note that the max CPUs supported by qemu machine 'virt' is 8 so the value of
CONFIG_NR_CPUS in some test configuration files needs to be adjusted.

 tools/testing/selftests/rcutorture/bin/functions.sh | 17 +++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/rcutorture/bin/functions.sh 
b/tools/testing/selftests/rcutorture/bin/functions.sh
index 07a1377..0541d10 100644
--- a/tools/testing/selftests/rcutorture/bin/functions.sh
+++ b/tools/testing/selftests/rcutorture/bin/functions.sh
@@ -136,6 +136,9 @@ identify_boot_image () {
qemu-system-x86_64|qemu-system-i386)
echo arch/x86/boot/bzImage
;;
+   qemu-system-aarch64)
+   echo arch/arm64/boot/Image
+   ;;
*)
echo vmlinux
;;
@@ -158,6 +161,9 @@ identify_qemu () {
elif echo $u | grep -q "Intel 80386"
then
echo qemu-system-i386
+   elif echo $u | grep -q aarch64
+   then
+   echo qemu-system-aarch64
elif uname -a | grep -q ppc64
then
echo qemu-system-ppc64
@@ -176,16 +182,20 @@ identify_qemu () {
 # Output arguments for the qemu "-append" string based on CPU type
 # and the TORTURE_QEMU_INTERACTIVE environment variable.
 identify_qemu_append () {
+   local console=ttyS0
case "$1" in
qemu-system-x86_64|qemu-system-i386)
echo noapic selinux=0 initcall_debug debug
;;
+   qemu-system-aarch64)
+   console=ttyAMA0
+   ;;
esac
if test -n "$TORTURE_QEMU_INTERACTIVE"
then
echo root=/dev/sda
else
-   echo console=ttyS0
+   echo console=$console
fi
 }
 
@@ -197,6 +207,9 @@ identify_qemu_args () {
case "$1" in
qemu-system-x86_64|qemu-system-i386)
;;
+   qemu-system-aarch64)
+   echo -M virt -cpu host
+   ;;
qemu-system-ppc64)
echo -enable-kvm -M pseries -nodefaults
echo -device spapr-vscsi
@@ -254,7 +267,7 @@ specify_qemu_cpus () {
echo $2
else
case "$1" in
-   qemu-system-x86_64|qemu-system-i386)
+   qemu-system-x86_64|qemu-system-i386|qemu-system-aarch64)
echo $2 -smp $3
;;
qemu-system-ppc64)
-- 
2.7.4



[PATCH] rcutorture: Add basic ARM64 support to run scripts

2017-12-08 Thread lianglihao
From: Lihao Liang 

This commit adds support of the qemu command qemu-system-aarch64
to rcutorture. Use the following command to run:

  ./kvm.sh --qemu-cmd qemu-system-aarch64

Signed-off-by: Lihao Liang 
---

The max CPUs supported by qemu machine 'virt' is 8 so the value of
CONFIG_NR_CPUS in some test configuration files needs to be adjusted.

 tools/testing/selftests/rcutorture/bin/functions.sh | 18 +-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/rcutorture/bin/functions.sh 
b/tools/testing/selftests/rcutorture/bin/functions.sh
index 07a1377..5ffe4fe 100644
--- a/tools/testing/selftests/rcutorture/bin/functions.sh
+++ b/tools/testing/selftests/rcutorture/bin/functions.sh
@@ -136,6 +136,9 @@ identify_boot_image () {
qemu-system-x86_64|qemu-system-i386)
echo arch/x86/boot/bzImage
;;
+   qemu-system-aarch64)
+   echo arch/arm64/boot/Image
+   ;;
*)
echo vmlinux
;;
@@ -185,7 +188,14 @@ identify_qemu_append () {
then
echo root=/dev/sda
else
-   echo console=ttyS0
+   case "$1" in
+   qemu-system-aarch64)
+   echo console=ttyAMA0
+   ;;
+   *)
+   echo console=ttyS0
+   ;;
+   esac
fi
 }
 
@@ -197,6 +207,9 @@ identify_qemu_args () {
case "$1" in
qemu-system-x86_64|qemu-system-i386)
;;
+   qemu-system-aarch64)
+   echo -M virt -cpu host
+   ;;
qemu-system-ppc64)
echo -enable-kvm -M pseries -nodefaults
echo -device spapr-vscsi
@@ -257,6 +270,9 @@ specify_qemu_cpus () {
qemu-system-x86_64|qemu-system-i386)
echo $2 -smp $3
;;
+   qemu-system-aarch64)
+   echo $2 -smp $3
+   ;;
qemu-system-ppc64)
nt="`lscpu | grep '^NUMA node0' | sed -e 
's/^[^,]*,\([0-9]*\),.*$/\1/'`"
echo $2 -smp cores=`expr \( $3 + $nt - 1 \) / 
$nt`,threads=$nt
-- 
2.7.4



[PATCH] rcutorture: Add basic ARM64 support to run scripts

2017-12-08 Thread lianglihao
From: Lihao Liang 

This commit adds support of the qemu command qemu-system-aarch64
to rcutorture. Use the following command to run:

  ./kvm.sh --qemu-cmd qemu-system-aarch64

Signed-off-by: Lihao Liang 
---

The max CPUs supported by qemu machine 'virt' is 8 so the value of
CONFIG_NR_CPUS in some test configuration files needs to be adjusted.

 tools/testing/selftests/rcutorture/bin/functions.sh | 18 +-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/rcutorture/bin/functions.sh 
b/tools/testing/selftests/rcutorture/bin/functions.sh
index 07a1377..5ffe4fe 100644
--- a/tools/testing/selftests/rcutorture/bin/functions.sh
+++ b/tools/testing/selftests/rcutorture/bin/functions.sh
@@ -136,6 +136,9 @@ identify_boot_image () {
qemu-system-x86_64|qemu-system-i386)
echo arch/x86/boot/bzImage
;;
+   qemu-system-aarch64)
+   echo arch/arm64/boot/Image
+   ;;
*)
echo vmlinux
;;
@@ -185,7 +188,14 @@ identify_qemu_append () {
then
echo root=/dev/sda
else
-   echo console=ttyS0
+   case "$1" in
+   qemu-system-aarch64)
+   echo console=ttyAMA0
+   ;;
+   *)
+   echo console=ttyS0
+   ;;
+   esac
fi
 }
 
@@ -197,6 +207,9 @@ identify_qemu_args () {
case "$1" in
qemu-system-x86_64|qemu-system-i386)
;;
+   qemu-system-aarch64)
+   echo -M virt -cpu host
+   ;;
qemu-system-ppc64)
echo -enable-kvm -M pseries -nodefaults
echo -device spapr-vscsi
@@ -257,6 +270,9 @@ specify_qemu_cpus () {
qemu-system-x86_64|qemu-system-i386)
echo $2 -smp $3
;;
+   qemu-system-aarch64)
+   echo $2 -smp $3
+   ;;
qemu-system-ppc64)
nt="`lscpu | grep '^NUMA node0' | sed -e 
's/^[^,]*,\([0-9]*\),.*$/\1/'`"
echo $2 -smp cores=`expr \( $3 + $nt - 1 \) / 
$nt`,threads=$nt
-- 
2.7.4



[PATCH 2/2] rcutorture: Add tests of param usage warnings

2017-12-06 Thread lianglihao
From: Lihao Liang 

Test the first patch of this patch series

Signed-off-by: Lihao Liang 
---

This patch is for testing purposes only and is not intended to be merged.
It seems that the scripts didn’t pick up the lines in BUSTED02.boot that
set the value of gp_normal and gp_exp. But when I hard-coded gp_normal to
true in rcutorture.c, it did print out "rcu_torture_writer3: gp_sync
without primitives" as expected.


 kernel/rcu/rcutorture.c| 14 --
 tools/testing/selftests/rcutorture/configs/rcu/BUSTED02|  7 +++
 .../testing/selftests/rcutorture/configs/rcu/BUSTED02.boot |  1 +
 tools/testing/selftests/rcutorture/configs/rcu/CFLIST  |  2 ++
 4 files changed, 18 insertions(+), 6 deletions(-)
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcu/BUSTED02
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcu/BUSTED02.boot

diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c
index d2abebd..233be41 100644
--- a/kernel/rcu/rcutorture.c
+++ b/kernel/rcu/rcutorture.c
@@ -465,10 +465,12 @@ static void rcu_busted_torture_deferred_free(struct 
rcu_torture *p)
rcu_torture_cb(>rtort_rcu);
 }
 
+#if 0
 static void synchronize_rcu_busted(void)
 {
/* This is a deliberate bug for testing purposes only! */
 }
+#endif
 
 static void
 call_rcu_busted(struct rcu_head *head, rcu_callback_t func)
@@ -486,8 +488,8 @@ static struct rcu_torture_ops rcu_busted_ops = {
.started= rcu_no_completed,
.completed  = rcu_no_completed,
.deferred_free  = rcu_busted_torture_deferred_free,
-   .sync   = synchronize_rcu_busted,
-   .exp_sync   = synchronize_rcu_busted,
+   .sync   = NULL,
+   .exp_sync   = NULL,
.call   = call_rcu_busted,
.cb_barrier = NULL,
.fqs= NULL,
@@ -939,13 +941,13 @@ rcu_torture_writer(void *arg)
pr_alert("%s: gp_sync without primitives.\n", __func__);
if (gp_normal == gp_exp) {
if (!cur_ops->sync)
-   pr_alert("%s: gp_sync without primitives.\n", __func__);
+   pr_alert("%s 1: gp_sync without primitives.\n", 
__func__);
if (!cur_ops->exp_sync)
-   pr_alert("%s: gp_exp without primitives.\n", __func__);
+   pr_alert("%s 2: gp_exp without primitives.\n", 
__func__);
} else if (gp_normal && !cur_ops->sync) {
-   pr_alert("%s: gp_sync without primitives.\n", __func__);
+   pr_alert("%s 3: gp_sync without primitives.\n", __func__);
} else if (gp_exp && !cur_ops->exp_sync) {
-   pr_alert("%s: gp_exp without primitives.\n", __func__);
+   pr_alert("%s 4: gp_exp without primitives.\n", __func__);
}
if (WARN_ONCE(nsynctypes == 0,
  "rcu_torture_writer: No update-side primitives.\n")) {
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/BUSTED02 
b/tools/testing/selftests/rcutorture/configs/rcu/BUSTED02
new file mode 100644
index 000..48d8a24
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/BUSTED02
@@ -0,0 +1,7 @@
+CONFIG_RCU_TRACE=n
+CONFIG_SMP=y
+CONFIG_NR_CPUS=4
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/BUSTED02.boot 
b/tools/testing/selftests/rcutorture/configs/rcu/BUSTED02.boot
new file mode 100644
index 000..40cf978
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/BUSTED02.boot
@@ -0,0 +1 @@
+rcutorture.torture_type=busted rcutorture.gp_normal=true 
rcutorture.gp_sync=false
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/CFLIST 
b/tools/testing/selftests/rcutorture/configs/rcu/CFLIST
index 6a0b9f6..e91f8b5 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/CFLIST
+++ b/tools/testing/selftests/rcutorture/configs/rcu/CFLIST
@@ -16,3 +16,5 @@ TINY02
 TASKS01
 TASKS02
 TASKS03
+BUSTED
+BUSTED02
-- 
2.7.4



[PATCH 0/2] rcutorture: Add parameter usage warnings

2017-12-06 Thread lianglihao
From: Lihao Liang 

Hi Paul,

Please find a patch series that adds rcutorture parameter usage warnings
against your git branch rcu/dev

commit e2c83bca7e80 ("EXP: rcu: Add ->boost_tasks to assertion")

Patch no.1 contains the actual changes. Patch no.2 is for testing purposes only
and is not intended to be merged. It seems that the scripts didn’t pick up the
lines in BUSTED02.boot that set the value of gp_normal and gp_exp. But when I
hard-coded gp_normal to true in rcutorture.c, it did print out
"rcu_torture_writer3: gp_sync without primitives" as expected.

It may be better to have more informative warning messages for the new if-else 
blocks
in patch no.1. Feel free to revise them.

Please let me know if you have any questions.

Many thanks,
Lihao.


Lihao Liang (2):
  rcutorture: Add param usage warnings
  rcutorture: Add tests of param usage warnings

 kernel/rcu/rcutorture.c  | 16 ++--
 tools/testing/selftests/rcutorture/configs/rcu/BUSTED02  |  7 +++
 .../selftests/rcutorture/configs/rcu/BUSTED02.boot   |  1 +
 tools/testing/selftests/rcutorture/configs/rcu/CFLIST|  2 ++
 4 files changed, 24 insertions(+), 2 deletions(-)
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcu/BUSTED02
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcu/BUSTED02.boot

-- 
2.7.4



[PATCH 0/2] rcutorture: Add parameter usage warnings

2017-12-06 Thread lianglihao
From: Lihao Liang 

Hi Paul,

Please find a patch series that adds rcutorture parameter usage warnings
against your git branch rcu/dev

commit e2c83bca7e80 ("EXP: rcu: Add ->boost_tasks to assertion")

Patch no.1 contains the actual changes. Patch no.2 is for testing purposes only
and is not intended to be merged. It seems that the scripts didn’t pick up the
lines in BUSTED02.boot that set the value of gp_normal and gp_exp. But when I
hard-coded gp_normal to true in rcutorture.c, it did print out
"rcu_torture_writer3: gp_sync without primitives" as expected.

It may be better to have more informative warning messages for the new if-else 
blocks
in patch no.1. Feel free to revise them.

Please let me know if you have any questions.

Many thanks,
Lihao.


Lihao Liang (2):
  rcutorture: Add param usage warnings
  rcutorture: Add tests of param usage warnings

 kernel/rcu/rcutorture.c  | 16 ++--
 tools/testing/selftests/rcutorture/configs/rcu/BUSTED02  |  7 +++
 .../selftests/rcutorture/configs/rcu/BUSTED02.boot   |  1 +
 tools/testing/selftests/rcutorture/configs/rcu/CFLIST|  2 ++
 4 files changed, 24 insertions(+), 2 deletions(-)
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcu/BUSTED02
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcu/BUSTED02.boot

-- 
2.7.4



[PATCH 2/2] rcutorture: Add tests of param usage warnings

2017-12-06 Thread lianglihao
From: Lihao Liang 

Test the first patch of this patch series

Signed-off-by: Lihao Liang 
---

This patch is for testing purposes only and is not intended to be merged.
It seems that the scripts didn’t pick up the lines in BUSTED02.boot that
set the value of gp_normal and gp_exp. But when I hard-coded gp_normal to
true in rcutorture.c, it did print out "rcu_torture_writer3: gp_sync
without primitives" as expected.


 kernel/rcu/rcutorture.c| 14 --
 tools/testing/selftests/rcutorture/configs/rcu/BUSTED02|  7 +++
 .../testing/selftests/rcutorture/configs/rcu/BUSTED02.boot |  1 +
 tools/testing/selftests/rcutorture/configs/rcu/CFLIST  |  2 ++
 4 files changed, 18 insertions(+), 6 deletions(-)
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcu/BUSTED02
 create mode 100644 tools/testing/selftests/rcutorture/configs/rcu/BUSTED02.boot

diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c
index d2abebd..233be41 100644
--- a/kernel/rcu/rcutorture.c
+++ b/kernel/rcu/rcutorture.c
@@ -465,10 +465,12 @@ static void rcu_busted_torture_deferred_free(struct 
rcu_torture *p)
rcu_torture_cb(>rtort_rcu);
 }
 
+#if 0
 static void synchronize_rcu_busted(void)
 {
/* This is a deliberate bug for testing purposes only! */
 }
+#endif
 
 static void
 call_rcu_busted(struct rcu_head *head, rcu_callback_t func)
@@ -486,8 +488,8 @@ static struct rcu_torture_ops rcu_busted_ops = {
.started= rcu_no_completed,
.completed  = rcu_no_completed,
.deferred_free  = rcu_busted_torture_deferred_free,
-   .sync   = synchronize_rcu_busted,
-   .exp_sync   = synchronize_rcu_busted,
+   .sync   = NULL,
+   .exp_sync   = NULL,
.call   = call_rcu_busted,
.cb_barrier = NULL,
.fqs= NULL,
@@ -939,13 +941,13 @@ rcu_torture_writer(void *arg)
pr_alert("%s: gp_sync without primitives.\n", __func__);
if (gp_normal == gp_exp) {
if (!cur_ops->sync)
-   pr_alert("%s: gp_sync without primitives.\n", __func__);
+   pr_alert("%s 1: gp_sync without primitives.\n", 
__func__);
if (!cur_ops->exp_sync)
-   pr_alert("%s: gp_exp without primitives.\n", __func__);
+   pr_alert("%s 2: gp_exp without primitives.\n", 
__func__);
} else if (gp_normal && !cur_ops->sync) {
-   pr_alert("%s: gp_sync without primitives.\n", __func__);
+   pr_alert("%s 3: gp_sync without primitives.\n", __func__);
} else if (gp_exp && !cur_ops->exp_sync) {
-   pr_alert("%s: gp_exp without primitives.\n", __func__);
+   pr_alert("%s 4: gp_exp without primitives.\n", __func__);
}
if (WARN_ONCE(nsynctypes == 0,
  "rcu_torture_writer: No update-side primitives.\n")) {
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/BUSTED02 
b/tools/testing/selftests/rcutorture/configs/rcu/BUSTED02
new file mode 100644
index 000..48d8a24
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/BUSTED02
@@ -0,0 +1,7 @@
+CONFIG_RCU_TRACE=n
+CONFIG_SMP=y
+CONFIG_NR_CPUS=4
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/BUSTED02.boot 
b/tools/testing/selftests/rcutorture/configs/rcu/BUSTED02.boot
new file mode 100644
index 000..40cf978
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/BUSTED02.boot
@@ -0,0 +1 @@
+rcutorture.torture_type=busted rcutorture.gp_normal=true 
rcutorture.gp_sync=false
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/CFLIST 
b/tools/testing/selftests/rcutorture/configs/rcu/CFLIST
index 6a0b9f6..e91f8b5 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/CFLIST
+++ b/tools/testing/selftests/rcutorture/configs/rcu/CFLIST
@@ -16,3 +16,5 @@ TINY02
 TASKS01
 TASKS02
 TASKS03
+BUSTED
+BUSTED02
-- 
2.7.4



[PATCH 1/2] rcutorture: Add usage warnings for parameters gp_normal and gp_exp

2017-12-06 Thread lianglihao
From: Lihao Liang 

In rcu_torture_fakewriter(), when param gp_normal is equal to
gp_exp (even when they are false), both cur_ops->sync() and
cur_ops->exp_sync() may be invoked. This commit checks that
if any of them is NULL, it will print out a warning message.
It also emits a warning if gp_normal is true but cur_ops->sync()
is NULL.

Signed-off-by: Lihao Liang 
---

I think the last else-if block is redundant and I choose to include it
for completeness. In addition, it may be better to have more informative
warning messages for the new if-else blocks. Feel free to revise them.

 kernel/rcu/rcutorture.c | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c
index d1b64dc..d2abebd 100644
--- a/kernel/rcu/rcutorture.c
+++ b/kernel/rcu/rcutorture.c
@@ -937,6 +937,16 @@ rcu_torture_writer(void *arg)
synctype[nsynctypes++] = RTWS_SYNC;
else if (gp_sync && !cur_ops->sync)
pr_alert("%s: gp_sync without primitives.\n", __func__);
+   if (gp_normal == gp_exp) {
+   if (!cur_ops->sync)
+   pr_alert("%s: gp_sync without primitives.\n", __func__);
+   if (!cur_ops->exp_sync)
+   pr_alert("%s: gp_exp without primitives.\n", __func__);
+   } else if (gp_normal && !cur_ops->sync) {
+   pr_alert("%s: gp_sync without primitives.\n", __func__);
+   } else if (gp_exp && !cur_ops->exp_sync) {
+   pr_alert("%s: gp_exp without primitives.\n", __func__);
+   }
if (WARN_ONCE(nsynctypes == 0,
  "rcu_torture_writer: No update-side primitives.\n")) {
/*
-- 
2.7.4



[PATCH 1/2] rcutorture: Add usage warnings for parameters gp_normal and gp_exp

2017-12-06 Thread lianglihao
From: Lihao Liang 

In rcu_torture_fakewriter(), when param gp_normal is equal to
gp_exp (even when they are false), both cur_ops->sync() and
cur_ops->exp_sync() may be invoked. This commit checks that
if any of them is NULL, it will print out a warning message.
It also emits a warning if gp_normal is true but cur_ops->sync()
is NULL.

Signed-off-by: Lihao Liang 
---

I think the last else-if block is redundant and I choose to include it
for completeness. In addition, it may be better to have more informative
warning messages for the new if-else blocks. Feel free to revise them.

 kernel/rcu/rcutorture.c | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c
index d1b64dc..d2abebd 100644
--- a/kernel/rcu/rcutorture.c
+++ b/kernel/rcu/rcutorture.c
@@ -937,6 +937,16 @@ rcu_torture_writer(void *arg)
synctype[nsynctypes++] = RTWS_SYNC;
else if (gp_sync && !cur_ops->sync)
pr_alert("%s: gp_sync without primitives.\n", __func__);
+   if (gp_normal == gp_exp) {
+   if (!cur_ops->sync)
+   pr_alert("%s: gp_sync without primitives.\n", __func__);
+   if (!cur_ops->exp_sync)
+   pr_alert("%s: gp_exp without primitives.\n", __func__);
+   } else if (gp_normal && !cur_ops->sync) {
+   pr_alert("%s: gp_sync without primitives.\n", __func__);
+   } else if (gp_exp && !cur_ops->exp_sync) {
+   pr_alert("%s: gp_exp without primitives.\n", __func__);
+   }
if (WARN_ONCE(nsynctypes == 0,
  "rcu_torture_writer: No update-side primitives.\n")) {
/*
-- 
2.7.4