On Sat, Sep 19, 2026 at 05:41:06PM +0100, Bradley Morgan wrote:
> On 19 September 2026 01:00:29 BST, "Paul E. McKenney" <[email protected]>
> wrote:
> >From: Mathieu Desnoyers <[email protected]>
> >
> >This API provides existence guarantees of objects through Hazard
> >Pointers [1] (hazptr).
> >
> >Its main benefit over RCU is that it allows fast reclaim of
> >HP-protected pointers without needing to wait for a grace period.
> >
> >This implementation has 4 statically allocated hazard pointer slots per
> >cpu for the fast path, and relies on a on-stack backup slot allocated by
> >the hazard pointer user as fallback in case no per-cpu slot is
> >available.
> >
> >It integrates with the scheduler to migrate per-CPU slots to the backup
> >slot on context switch. This ensures that the per-CPU slots won't be
> >used by blocked or preempted tasks holding on hazard pointers for a long
> >time.
> >
> >References:
> >
> >[1]: M. M. Michael, "Hazard pointers: safe memory reclamation for
> > lock-free objects," in IEEE Transactions on Parallel and
> > Distributed Systems, vol. 15, no. 6, pp. 491-504, June 2004
>
> Sorry for the quick reply, could we add some sort of a maintainers entry
> here?
>
> I feel as when in like 10 years, there's a huge bug in hazptr, and mat
> can't respond cuz he changes email, then that's not good.
Maged's hazard-pointers implementation works just fine, within its area
of applicability. As I recall, Boqun and/or Mathieu departed from
it a bit to simplify the lockdep use case. From the perspective of
this one use case, this simplification is more a restriction than bug.
But Maged would no doubt be quick to point out that from the perspective
of other use cases, this is a bug rather than a simplification. So it
will likely need to be fixed sooner rather than later.
And Maged is aware of this effort, in fact, I had lunch with him earlier
this week [1]. Every time that I have asked, he has indicated that he
has absolutely no interest in becoming a Linux-kernel maintainer. ;-)
Which is fair, given that Maged has other fish to fry.
Thanx, Paul
[1]
https://cppcon2026.sched.com/event/2RT65/interesting-upcoming-low-latency-networking-concurrency-and-parallelism-features-from-kona-2025-croydon-2026-and-brno-2026
> >Link: https://lpc.events/event/19/contributions/2082/
> >Link:
> >https://lore.kernel.org/lkml/j3scdl5iymjlxavomgc6u5ndg3svhab6ga23dr36o4f5mt333w@7xslvq6b6hmv/
> >Link: https://lpc.events/event/18/contributions/1731/
> >Signed-off-by: Mathieu Desnoyers <[email protected]>
> >Cc: Nicholas Piggin <[email protected]>
> >Cc: Michael Ellerman <[email protected]>
> >Cc: Greg Kroah-Hartman <[email protected]>
> >Cc: Sebastian Andrzej Siewior <[email protected]>
> >Cc: "Paul E. McKenney" <[email protected]>
> >Cc: Will Deacon <[email protected]>
> >Cc: Peter Zijlstra <[email protected]>
> >Cc: Boqun Feng <[email protected]>
> >Cc: Alan Stern <[email protected]>
> >Cc: John Stultz <[email protected]>
> >Cc: Linus Torvalds <[email protected]>
> >Cc: Andrew Morton <[email protected]>
> >Cc: Frederic Weisbecker <[email protected]>
> >Cc: Joel Fernandes <[email protected]>
> >Cc: Josh Triplett <[email protected]>
> >Cc: Uladzislau Rezki <[email protected]>
> >Cc: Steven Rostedt <[email protected]>
> >Cc: Lai Jiangshan <[email protected]>
> >Cc: Zqiang <[email protected]>
> >Cc: Ingo Molnar <[email protected]>
> >Cc: Waiman Long <[email protected]>
> >Cc: Mark Rutland <[email protected]>
> >Cc: Thomas Gleixner <[email protected]>
> >Cc: Vlastimil Babka <[email protected]>
> >Cc: [email protected]
> >Cc: Mateusz Guzik <[email protected]>
> >Cc: Jonas Oberhauser <[email protected]>
> >Cc: <[email protected]>
> >Cc: <[email protected]>
> >Cc: <[email protected]>
> >Signed-off-by: Paul E. McKenney <[email protected]>
> >---
> > include/linux/hazptr.h | 197 +++++++++++++++++++++++++++++++++
> > init/main.c | 2 +
> > kernel/Makefile | 2 +-
> > kernel/hazptr.c | 242 +++++++++++++++++++++++++++++++++++++++++
> > kernel/sched/core.c | 2 +
> > 5 files changed, 444 insertions(+), 1 deletion(-)
> > create mode 100644 include/linux/hazptr.h
> > create mode 100644 kernel/hazptr.c
> >
> >diff --git a/include/linux/hazptr.h b/include/linux/hazptr.h
> >new file mode 100644
> >index 000000000000..b121f7779cda
> >--- /dev/null
> >+++ b/include/linux/hazptr.h
> >@@ -0,0 +1,197 @@
> >+// SPDX-License-Identifier: LGPL-2.1-or-later
> >+//
> >+// SPDX-FileCopyrightText: 2024 Mathieu Desnoyers
> ><[email protected]>
> >+
> >+#ifndef _LINUX_HAZPTR_H
> >+#define _LINUX_HAZPTR_H
> >+
> >+/*
> >+ * hazptr: Hazard Pointers
> >+ *
> >+ * This API provides existence guarantees of objects through hazard
> >+ * pointers.
> >+ *
> >+ * Its main benefit over RCU is that it allows fast reclaim of
> >+ * HP-protected pointers without needing to wait for a grace period.
> >+ *
> >+ * References:
> >+ *
> >+ * [1]: M. M. Michael, "Hazard pointers: safe memory reclamation for
> >+ * lock-free objects," in IEEE Transactions on Parallel and
> >+ * Distributed Systems, vol. 15, no. 6, pp. 491-504, June 2004
> >+ */
> >+
> >+#include <linux/percpu.h>
> >+#include <linux/types.h>
> >+#include <linux/cleanup.h>
> >+#include <linux/sched.h>
> >+
> >+/* 4 slots (each sizeof(hazptr_slot_item)) fit in a single 64-byte cache
> >line. */
> >+#define NR_HAZPTR_PERCPU_SLOTS 4
> >+#define HAZPTR_WILDCARD ((void *) 0x1UL)
> >+
> >+/*
> >+ * Hazard pointer slot.
> >+ */
> >+struct hazptr_slot {
> >+ void *addr;
> >+};
> >+
> >+struct hazptr_overflow_list;
> >+
> >+struct hazptr_backup_slot {
> >+ struct hlist_node overflow_node;
> >+ struct hazptr_slot slot;
> >+ /* Overflow list where the backup slot is added. */
> >+ struct hazptr_overflow_list *overflow_list;
> >+};
> >+
> >+struct hazptr_ctx {
> >+ struct hazptr_slot *slot;
> >+ /* Backup slot in case all per-CPU slots are used. */
> >+ struct hazptr_backup_slot backup_slot;
> >+ struct hlist_node preempt_node;
> >+};
> >+
> >+struct hazptr_slot_ctx {
> >+ struct hazptr_ctx *ctx;
> >+};
> >+
> >+struct hazptr_slot_item {
> >+ struct hazptr_slot slot;
> >+ struct hazptr_slot_ctx ctx;
> >+};
> >+
> >+struct hazptr_percpu_slots {
> >+ struct hazptr_slot_item items[NR_HAZPTR_PERCPU_SLOTS];
> >+} ____cacheline_aligned;
> >+
> >+DECLARE_PER_CPU(struct hazptr_percpu_slots, hazptr_percpu_slots);
> >+
> >+void *__hazptr_acquire(struct hazptr_ctx *ctx, void * const *addr_p);
> >+
> >+/*
> >+ * hazptr_synchronize: Wait until @addr is released from all slots.
> >+ *
> >+ * Wait to observe that each slot contains a value that differs from
> >+ * @addr before returning.
> >+ * Should be called from preemptible context.
> >+ */
> >+void hazptr_synchronize(void *addr);
> >+
> >+/*
> >+ * hazptr_chain_backup_slot: Chain backup slot into overflow list.
> >+ *
> >+ * Set backup slot address to @addr, and chain it into the overflow
> >+ * list.
> >+ */
> >+struct hazptr_slot *hazptr_chain_backup_slot(struct hazptr_ctx *ctx);
> >+
> >+/*
> >+ * hazptr_unchain_backup_slot: Unchain backup slot from overflow list.
> >+ */
> >+void hazptr_unchain_backup_slot(struct hazptr_ctx *ctx);
> >+
> >+static inline
> >+bool hazptr_slot_is_backup(struct hazptr_ctx *ctx, struct hazptr_slot *slot)
> >+{
> >+ return slot == &ctx->backup_slot.slot;
> >+}
> >+
> >+static inline
> >+void hazptr_note_context_switch(void)
> >+{
> >+ struct hazptr_percpu_slots *percpu_slots =
> >this_cpu_ptr(&hazptr_percpu_slots);
> >+ unsigned int idx;
> >+
> >+ for (idx = 0; idx < NR_HAZPTR_PERCPU_SLOTS; idx++) {
> >+ struct hazptr_slot_item *item = &percpu_slots->items[idx];
> >+ struct hazptr_slot *slot = &item->slot, *backup_slot;
> >+ struct hazptr_ctx *ctx;
> >+
> >+ if (!slot->addr)
> >+ continue;
> >+ ctx = item->ctx.ctx;
> >+ backup_slot = hazptr_chain_backup_slot(ctx);
> >+ /*
> >+ * Move hazard pointer from the per-CPU slot to the
> >+ * backup slot. This requires hazard pointer
> >+ * synchronize to iterate on per-CPU slots with
> >+ * load-acquire before iterating on the overflow list.
> >+ */
> >+ WRITE_ONCE(backup_slot->addr, slot->addr);
> >+ /*
> >+ * store-release orders store to backup slot addr before
> >+ * store to per-CPU slot addr.
> >+ */
> >+ smp_store_release(&slot->addr, NULL);
> >+ /* Use the backup slot for context. */
> >+ ctx->slot = backup_slot;
> >+ }
> >+}
> >+
> >+/*
> >+ * hazptr_acquire: Load pointer at address and protect with hazard pointer.
> >+ *
> >+ * Load @addr_p, and protect the loaded pointer with hazard pointer.
> >+ * When using hazptr_acquire from interrupt handlers, the acquired slots
> >+ * need to be released before returning from the interrupt handler.
> >+ *
> >+ * Returns a non-NULL protected address if the loaded pointer is non-NULL.
> >+ * Returns NULL if the loaded pointer is NULL.
> >+ *
> >+ * On success the protected hazptr slot is stored in @ctx->slot.
> >+ */
> >+static inline
> >+void *hazptr_acquire(struct hazptr_ctx *ctx, void * const *addr_p)
> >+{
> >+ struct hazptr_percpu_slots *percpu_slots;
> >+ struct hazptr_slot_item *slot_item;
> >+ struct hazptr_slot *slot;
> >+ void *addr;
> >+
> >+ guard(preempt)();
> >+ percpu_slots = this_cpu_ptr(&hazptr_percpu_slots);
> >+ slot_item = &percpu_slots->items[0];
> >+ slot = &slot_item->slot;
> >+ if (unlikely(slot->addr))
> >+ return __hazptr_acquire(ctx, addr_p);
> >+ WRITE_ONCE(slot->addr, HAZPTR_WILDCARD); /* Store B */
> >+
> >+ /* Memory ordering: Store B before Load A. */
> >+ smp_mb();
> >+
> >+ /*
> >+ * Load @addr_p after storing wildcard to the hazard pointer slot.
> >+ */
> >+ addr = READ_ONCE(*addr_p); /* Load A */
> >+
> >+ /*
> >+ * We don't care about ordering of Store C. It will simply
> >+ * replace the wildcard by a more specific address. If addr is
> >+ * NULL, we simply store NULL into the slot.
> >+ */
> >+ WRITE_ONCE(slot->addr, addr); /* Store C */
> >+ slot_item->ctx.ctx = ctx;
> >+ ctx->slot = slot;
> >+ return addr;
> >+}
> >+
> >+/* Release the protected hazard pointer from @slot. */
> >+static inline
> >+void hazptr_release(struct hazptr_ctx *ctx, void *addr)
> >+{
> >+ struct hazptr_slot *slot;
> >+
> >+ if (!addr)
> >+ return;
> >+ guard(preempt)();
> >+ slot = ctx->slot;
> >+ smp_store_release(&slot->addr, NULL);
> >+ if (unlikely(hazptr_slot_is_backup(ctx, slot)))
> >+ hazptr_unchain_backup_slot(ctx);
> >+}
> >+
> >+void hazptr_init(void);
> >+
> >+#endif /* _LINUX_HAZPTR_H */
> >diff --git a/init/main.c b/init/main.c
> >index 2613d3f9b3ce..d9d936707c19 100644
> >--- a/init/main.c
> >+++ b/init/main.c
> >@@ -108,6 +108,7 @@
> > #include <linux/time_namespace.h>
> > #include <linux/unaligned.h>
> > #include <linux/vdso_datastore.h>
> >+#include <linux/hazptr.h>
> > #include <net/net_namespace.h>
> >
> > #include <asm/io.h>
> >@@ -1075,6 +1076,7 @@ void start_kernel(void)
> > workqueue_init_early();
> >
> > rcu_init();
> >+ hazptr_init();
> > kvfree_rcu_init();
> >
> > /* Trace events are available after this */
> >diff --git a/kernel/Makefile b/kernel/Makefile
> >index 1e1a31673577..8961c8660d0d 100644
> >--- a/kernel/Makefile
> >+++ b/kernel/Makefile
> >@@ -7,7 +7,7 @@ obj-y = fork.o exec_domain.o exec_state.o panic.o \
> > cpu.o exit.o softirq.o resource.o \
> > sysctl.o capability.o ptrace.o user.o \
> > signal.o sys.o umh.o workqueue.o pid.o task_work.o \
> >- extable.o params.o \
> >+ extable.o params.o hazptr.o \
> > kthread.o sys_ni.o nsproxy.o nstree.o nscommon.o \
> > notifier.o ksysfs.o cred.o reboot.o \
> > async.o range.o smpboot.o ucount.o regset.o ksyms_common.o
> >diff --git a/kernel/hazptr.c b/kernel/hazptr.c
> >new file mode 100644
> >index 000000000000..a9d3d68a1525
> >--- /dev/null
> >+++ b/kernel/hazptr.c
> >@@ -0,0 +1,242 @@
> >+// SPDX-License-Identifier: LGPL-2.1-or-later
> >+//
> >+// SPDX-FileCopyrightText: 2024 Mathieu Desnoyers
> ><[email protected]>
> >+
> >+/*
> >+ * hazptr: Hazard Pointers
> >+ */
> >+
> >+#include <linux/hazptr.h>
> >+#include <linux/percpu.h>
> >+#include <linux/spinlock.h>
> >+#include <linux/mutex.h>
> >+#include <linux/list.h>
> >+#include <linux/export.h>
> >+
> >+struct hazptr_overflow_list {
> >+ raw_spinlock_t lock; /* Lock protecting overflow list and
> >list generation. */
> >+ struct hlist_head head; /* Overflow list head. */
> >+ uint64_t gen; /* Overflow list generation. */
> >+};
> >+
> >+/*
> >+ * Flip between two lists to guarantee list scan forward progress even
> >+ * with frequent generation counter increments. The list additions are
> >+ * always done on a different list than the one used for scan. The scan
> >+ * successively iterates on both lists. Therefore, only list removals
> >+ * can cause the iteration to retry, and the number of removals is
> >+ * limited to the number of list elements.
> >+ */
> >+struct hazptr_overflow_list_flip {
> >+ struct mutex lock; /* Mutex protecting add_idx from
> >concurrent updates. */
> >+ unsigned int add_idx; /* Index of current flip-list to add
> >to. */
> >+ struct hazptr_overflow_list array[2];
> >+};
> >+
> >+static DEFINE_PER_CPU(struct hazptr_overflow_list_flip,
> >percpu_overflow_list_flip);
> >+
> >+DEFINE_PER_CPU(struct hazptr_percpu_slots, hazptr_percpu_slots);
> >+EXPORT_PER_CPU_SYMBOL_GPL(hazptr_percpu_slots);
> >+
> >+static
> >+struct hazptr_slot *hazptr_get_free_percpu_slot(struct hazptr_ctx *ctx)
> >+{
> >+ struct hazptr_percpu_slots *percpu_slots =
> >this_cpu_ptr(&hazptr_percpu_slots);
> >+ unsigned int idx;
> >+
> >+ for (idx = 0; idx < NR_HAZPTR_PERCPU_SLOTS; idx++) {
> >+ struct hazptr_slot_item *item = &percpu_slots->items[idx];
> >+ struct hazptr_slot *slot = &item->slot;
> >+
> >+ if (!slot->addr) {
> >+ item->ctx.ctx = ctx;
> >+ return slot;
> >+ }
> >+ }
> >+ /* All slots are in use. */
> >+ return NULL;
> >+}
> >+
> >+/*
> >+ * Hazard pointer acquire slow path.
> >+ * Called with preemption disabled.
> >+ */
> >+void *__hazptr_acquire(struct hazptr_ctx *ctx, void * const *addr_p)
> >+{
> >+ struct hazptr_slot *slot = hazptr_get_free_percpu_slot(ctx);
> >+ void *addr;
> >+
> >+ /*
> >+ * If all the per-CPU slots are already in use, fallback
> >+ * to the backup slot.
> >+ */
> >+ if (unlikely(!slot))
> >+ slot = hazptr_chain_backup_slot(ctx);
> >+ WRITE_ONCE(slot->addr, HAZPTR_WILDCARD); /* Store B */
> >+
> >+ /* Memory ordering: Store B before Load A. */
> >+ smp_mb();
> >+
> >+ /*
> >+ * Load @addr_p after storing wildcard to the hazard pointer slot.
> >+ */
> >+ addr = READ_ONCE(*addr_p); /* Load A */
> >+
> >+ /*
> >+ * We don't care about ordering of Store C. It will simply
> >+ * replace the wildcard by a more specific address. If addr is
> >+ * NULL, we simply store NULL into the slot.
> >+ */
> >+ WRITE_ONCE(slot->addr, addr); /* Store C */
> >+ ctx->slot = slot;
> >+ if (!addr && hazptr_slot_is_backup(ctx, slot))
> >+ hazptr_unchain_backup_slot(ctx);
> >+ return addr;
> >+}
> >+EXPORT_SYMBOL_GPL(__hazptr_acquire);
> >+
> >+/*
> >+ * Perform piecewise iteration on overflow list waiting until "addr" is
> >+ * not present. Raw spinlock is released and taken between each list
> >+ * item and busy loop iteration. The overflow list generation is checked
> >+ * each time the lock is taken to validate that the list has not changed
> >+ * before resuming iteration or busy wait. If the generation has
> >+ * changed, retry the entire list traversal.
> >+ */
> >+static
> >+void hazptr_synchronize_overflow_list(struct hazptr_overflow_list
> >*overflow_list, void *addr)
> >+{
> >+ struct hazptr_backup_slot *backup_slot;
> >+ uint64_t snapshot_gen;
> >+ unsigned long flags;
> >+
> >+ raw_spin_lock_irqsave(&overflow_list->lock, flags);
> >+retry:
> >+ snapshot_gen = overflow_list->gen;
> >+ hlist_for_each_entry(backup_slot, &overflow_list->head, overflow_node) {
> >+ /* Busy-wait if node is found. */
> >+ for (;;) {
> >+ void *load_addr =
> >smp_load_acquire(&backup_slot->slot.addr); /* Load B */
> >+
> >+ if (load_addr != addr && load_addr != HAZPTR_WILDCARD)
> >+ break;
> >+ raw_spin_unlock_irqrestore(&overflow_list->lock, flags);
> >+ cpu_relax();
> >+ raw_spin_lock_irqsave(&overflow_list->lock, flags);
> >+ if (overflow_list->gen != snapshot_gen)
> >+ goto retry;
> >+ }
> >+ raw_spin_unlock_irqrestore(&overflow_list->lock, flags);
> >+ /*
> >+ * Release raw spinlock, validate generation after
> >+ * re-acquiring the lock.
> >+ */
> >+ raw_spin_lock_irqsave(&overflow_list->lock, flags);
> >+ if (overflow_list->gen != snapshot_gen)
> >+ goto retry;
> >+ }
> >+ raw_spin_unlock_irqrestore(&overflow_list->lock, flags);
> >+}
> >+
> >+static
> >+void hazptr_synchronize_cpu_slots(int cpu, void *addr)
> >+{
> >+ struct hazptr_percpu_slots *percpu_slots =
> >per_cpu_ptr(&hazptr_percpu_slots, cpu);
> >+ unsigned int idx;
> >+
> >+ for (idx = 0; idx < NR_HAZPTR_PERCPU_SLOTS; idx++) {
> >+ struct hazptr_slot_item *item = &percpu_slots->items[idx];
> >+
> >+ /* Busy-wait if node is found. */
> >+ smp_cond_load_acquire(&item->slot.addr, VAL != addr && VAL !=
> >HAZPTR_WILDCARD); /* Load B */
> >+ }
> >+}
> >+
> >+/*
> >+ * hazptr_synchronize: Wait until @addr is released from all slots.
> >+ *
> >+ * Wait to observe that each slot contains a value that differs from
> >+ * @addr before returning.
> >+ * Should be called from preemptible context.
> >+ */
> >+void hazptr_synchronize(void *addr)
> >+{
> >+ int cpu;
> >+
> >+ /*
> >+ * Busy-wait should only be done from preemptible context.
> >+ */
> >+ lockdep_assert_preemption_enabled();
> >+
> >+ /*
> >+ * Store A precedes hazptr_scan(): it unpublishes addr (sets it to
> >+ * NULL or to a different value), and thus hides it from hazard
> >+ * pointer readers.
> >+ */
> >+ if (!addr)
> >+ return;
> >+ /* Memory ordering: Store A before Load B. */
> >+ smp_mb();
> >+ /* Scan all CPUs slots. */
> >+ for_each_possible_cpu(cpu) {
> >+ struct hazptr_overflow_list_flip *overflow_list_flip =
> >per_cpu_ptr(&percpu_overflow_list_flip, cpu);
> >+ unsigned int scan_idx;
> >+
> >+ /* Scan CPU slots. */
> >+ hazptr_synchronize_cpu_slots(cpu, addr);
> >+
> >+ /*
> >+ * Scan backup slots in percpu overflow lists.
> >+ * Forward progress is guaranteed by scanning one list
> >+ * while new elements are added into the other list.
> >+ */
> >+ guard(mutex)(&overflow_list_flip->lock);
> >+ scan_idx = overflow_list_flip->add_idx ^ 1;
> >+
> >hazptr_synchronize_overflow_list(&overflow_list_flip->array[scan_idx], addr);
> >+ /* Flip current list. */
> >+ WRITE_ONCE(overflow_list_flip->add_idx, scan_idx);
> >+
> >hazptr_synchronize_overflow_list(&overflow_list_flip->array[scan_idx ^ 1],
> >addr);
> >+ }
> >+}
> >+EXPORT_SYMBOL_GPL(hazptr_synchronize);
> >+
> >+struct hazptr_slot *hazptr_chain_backup_slot(struct hazptr_ctx *ctx)
> >+{
> >+ struct hazptr_overflow_list_flip *overflow_list_flip =
> >this_cpu_ptr(&percpu_overflow_list_flip);
> >+ unsigned int list_idx = READ_ONCE(overflow_list_flip->add_idx);
> >+ struct hazptr_overflow_list *overflow_list =
> >&overflow_list_flip->array[list_idx];
> >+ struct hazptr_slot *slot = &ctx->backup_slot.slot;
> >+
> >+ slot->addr = NULL;
> >+ guard(raw_spinlock_irqsave)(&overflow_list->lock);
> >+ overflow_list->gen++;
> >+ hlist_add_head(&ctx->backup_slot.overflow_node, &overflow_list->head);
> >+ ctx->backup_slot.overflow_list = overflow_list;
> >+ return slot;
> >+}
> >+EXPORT_SYMBOL_GPL(hazptr_chain_backup_slot);
> >+
> >+void hazptr_unchain_backup_slot(struct hazptr_ctx *ctx)
> >+{
> >+ struct hazptr_overflow_list *overflow_list =
> >ctx->backup_slot.overflow_list;
> >+
> >+ guard(raw_spinlock_irqsave)(&overflow_list->lock);
> >+ overflow_list->gen++;
> >+ hlist_del(&ctx->backup_slot.overflow_node);
> >+}
> >+EXPORT_SYMBOL_GPL(hazptr_unchain_backup_slot);
> >+
> >+void __init hazptr_init(void)
> >+{
> >+ int cpu;
> >+
> >+ for_each_possible_cpu(cpu) {
> >+ struct hazptr_overflow_list_flip *overflow_list_flip =
> >per_cpu_ptr(&percpu_overflow_list_flip, cpu);
> >+
> >+ mutex_init(&overflow_list_flip->lock);
> >+ for (int i = 0; i < 2; i++) {
> >+ raw_spin_lock_init(&overflow_list_flip->array[i].lock);
> >+ INIT_HLIST_HEAD(&overflow_list_flip->array[i].head);
> >+ }
> >+ }
> >+}
> >diff --git a/kernel/sched/core.c b/kernel/sched/core.c
> >index f78275192036..b77152edafd9 100644
> >--- a/kernel/sched/core.c
> >+++ b/kernel/sched/core.c
> >@@ -59,6 +59,7 @@
> > #include <linux/profile.h>
> > #include <linux/psi.h>
> > #include <linux/rcuwait_api.h>
> >+#include <linux/hazptr.h>
> > #include <linux/rseq.h>
> > #include <linux/sched/wake_q.h>
> > #include <linux/scs.h>
> >@@ -7123,6 +7124,7 @@ static void __sched notrace __schedule(int sched_mode)
> > local_irq_disable();
> > rcu_note_context_switch(preempt);
> > migrate_disable_switch(rq, prev);
> >+ hazptr_note_context_switch();
> >
> > /*
> > * Make sure that signal_pending_state()->signal_pending() below
> >
>
> --- Thanks!
> "I'm not a very positive person" - Linus torvalds