On Tue, Sep 22, 2026 at 03:09:49PM +0800, Kunwu Chan wrote:
> Add hazptr reader and synchronize operations so that synchronize
> latency can be measured alongside RCU and SRCU.
> 
> The read side acquires the hazard pointer in readlock() and holds
> it until readunlock(), matching the RCU/SRCU reader model.  The
> address of a static object serves as the synchronize target, which
> is stable and never reclaimed.  Both normal and expedited sync map
> to hazptr_synchronize(), since hazptr has no expedited concept.
> 
> Signed-off-by: Kunwu Chan <[email protected]>
> ---
>  kernel/rcu/rcuscale.c | 65 ++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 64 insertions(+), 1 deletion(-)
> 
> diff --git a/kernel/rcu/rcuscale.c b/kernel/rcu/rcuscale.c
> index 1097ec15879c..072ddf9526c3 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,66 @@ static struct rcu_scale_ops tasks_tracing_ops = {
>  
>  #endif // #else // #ifdef CONFIG_TASKS_TRACE_RCU
>  
> +#if IS_ENABLED(CONFIG_HAZPTR_TORTURE_TEST)
> +
> +static int hazptr_scale_obj; /* Stable, non-NULL, never reclaimed. */

You can probaly make hazptr_scale_obj an arrary, and let an updater
either randomly or round-robin select an object to wait, it'll reflect
better to a real world workload.

> +static void *hazptr_scale_ptr = &hazptr_scale_obj;
> +
> +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);
> +
> +     preempt_disable();

I think you can drop the preempt_disable() and preempt_enable() below,
since the new hazptr_acquire()/hazptr_release() work without them (i.e.
the hazptr acquisition no longer requires preemption disable).

Regards,
Boqun

> +     state->addr = hazptr_acquire(&state->ctx, &hazptr_scale_ptr);
> +     return 0;
> +}
> +
> +static void hazptr_scale_read_unlock(int idx)
> +{
> +     struct hazptr_scale_state *state = this_cpu_ptr(&hazptr_scale_state);
> +
> +     udelay(10);
> +     hazptr_release(&state->ctx, state->addr);
> +     preempt_enable();
> +}
> +
> +static unsigned long hazptr_scale_completed(void)
> +{
> +     return 0;
> +}
> +
> +static void hazptr_scale_sync(void)
> +{
> +     hazptr_synchronize(hazptr_scale_ptr);
> +}
> +
> +static void hazptr_scale_sync_exp(void)
> +{
> +     hazptr_synchronize(hazptr_scale_ptr);
> +}
> +
> +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,
> +     .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 +1171,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