Add hazptr reader and synchronize operations so that synchronize
latency can be measured alongside RCU and SRCU.

Use a small set of objects so readers do not always protect the
same target.  Each reader protects the object selected by its CPU,
while the updater round-robins through the objects.

Use hazptr_synchronize() for both normal and expedited scale
operations, since hazptr has no separate expedited operation.

Link: https://lore.kernel.org/lkml/[email protected]/
Signed-off-by: Kunwu Chan <[email protected]>
---
 kernel/rcu/rcuscale.c | 70 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 69 insertions(+), 1 deletion(-)

diff --git a/kernel/rcu/rcuscale.c b/kernel/rcu/rcuscale.c
index 1097ec15879c..5aca31c3c01d 100644
--- a/kernel/rcu/rcuscale.c
+++ b/kernel/rcu/rcuscale.c
@@ -39,6 +39,7 @@
 #include <linux/torture.h>
 #include <linux/vmalloc.h>
 #include <linux/rcupdate_trace.h>
+#include <linux/hazptr.h>
 #include <linux/sched/debug.h>
 
 #include "rcu.h"
@@ -418,6 +419,71 @@ static struct rcu_scale_ops tasks_tracing_ops = {
 
 #endif // #else // #ifdef CONFIG_TASKS_TRACE_RCU
 
+#if IS_ENABLED(CONFIG_HAZPTR_TORTURE_TEST)
+
+#define HAZPTR_SCALE_NR_OBJS 8
+static int hazptr_scale_obj[HAZPTR_SCALE_NR_OBJS];
+static atomic_t hazptr_scale_sync_idx = ATOMIC_INIT(0);
+
+struct hazptr_scale_state {
+       struct hazptr_ctx ctx;
+       void *addr;
+};
+static DEFINE_PER_CPU(struct hazptr_scale_state, hazptr_scale_state);
+
+static int hazptr_scale_read_lock(void)
+{
+       struct hazptr_scale_state *state = this_cpu_ptr(&hazptr_scale_state);
+       int idx = smp_processor_id() % HAZPTR_SCALE_NR_OBJS;
+       void *ptr = &hazptr_scale_obj[idx];
+
+       state->addr = hazptr_acquire(&state->ctx, &ptr);
+       return 0;
+}
+
+static void hazptr_scale_read_unlock(int idx)
+{
+       struct hazptr_scale_state *state = this_cpu_ptr(&hazptr_scale_state);
+
+       hazptr_release(&state->ctx, state->addr);
+}
+
+static unsigned long hazptr_scale_completed(void)
+{
+       return 0;
+}
+
+static void hazptr_scale_sync(void)
+{
+       int idx = atomic_fetch_inc(&hazptr_scale_sync_idx) % 
HAZPTR_SCALE_NR_OBJS;
+
+       hazptr_synchronize(&hazptr_scale_obj[idx]);
+}
+
+static void hazptr_scale_sync_exp(void)
+{
+       int idx = atomic_fetch_inc(&hazptr_scale_sync_idx) % 
HAZPTR_SCALE_NR_OBJS;
+
+       hazptr_synchronize(&hazptr_scale_obj[idx]);
+}
+
+static struct rcu_scale_ops hazptr_scale_ops = {
+       .ptype          = 0,
+       .readlock       = hazptr_scale_read_lock,
+       .readunlock     = hazptr_scale_read_unlock,
+       .get_gp_seq     = hazptr_scale_completed,
+       .gp_diff        = NULL,
+       .exp_completed  = hazptr_scale_completed,
+       .sync           = hazptr_scale_sync,
+       .exp_sync       = hazptr_scale_sync_exp,
+       .name           = "hazptr",
+};
+
+#define HAZPTR_SCALE_OPS &hazptr_scale_ops,
+#else
+#define HAZPTR_SCALE_OPS
+#endif
+
 static unsigned long rcuscale_seq_diff(unsigned long new, unsigned long old)
 {
        if (!cur_ops->gp_diff)
@@ -1110,7 +1176,9 @@ rcu_scale_init(void)
        long i;
        long j;
        static struct rcu_scale_ops *scale_ops[] = {
-               &rcu_ops, &srcu_ops, &srcud_ops, TASKS_OPS TASKS_RUDE_OPS 
TASKS_TRACING_OPS
+               &rcu_ops, &srcu_ops, &srcud_ops,
+               TASKS_OPS TASKS_RUDE_OPS TASKS_TRACING_OPS
+               HAZPTR_SCALE_OPS
        };
 
        if (!torture_init_begin(scale_type, verbose))
-- 
2.43.0


Reply via email to