Re: [RFC PATCH 05/12] rcu_txn: Add an hlist edited through transactions

From: Puranjay Mohan

Date: Fri Oct 23 2026 - 14:22:43 EST


On Fri, Oct 16, 2026 at 09:33:12AM -0400, Mathieu Desnoyers wrote:
[...]

> + * - Every node an operation is anchored on must still be in the list as the
> + * transaction leaves it. A single-writer delete leaves no deletion mark:
> + * nothing in a deleted anchor distinguishes it from a live one.

[...]

> +static inline void rcu_txn_hlist_del_rcu(struct rcu_txn_hlist_node *elem)
> +{
> + struct rcu_txn_hlist_node __rcu **ppv = __rcu_txn_hlist_pprev(elem);
> + struct rcu_txn_hlist_node *next = __rcu_txn_hlist_load(&elem->next);
> +
> + rcu_assign_pointer(*ppv, next);
> + if (next)
> + RCU_INIT_POINTER(next->pprev, ppv);
> +}

hlist_del_rcu() poisons pprev, so a double delete faults straight away.
Here pprev keeps pointing at the old slot, so a second del_rcu() quietly
overwrites whatever that slot holds now with the node's stale ->next.
For example, 1 -> 2 -> 3, del_rcu(2), add_behind_rcu(4, 1), del_rcu(2)
leaves 1 -> 3 with node 4 gone, and nothing warns, even with
CONFIG_DEBUG_RCU_TXN. Had 3 been deleted and freed in between, the
second delete would link it back in and write to it.

dcache relies on d_unhashed(), i.e. a NULL pprev, which __d_drop() sets.
Could the _rcu delete and replace clear pprev the way
hlist_del_init_rcu() does, and could there be an
rcu_txn_hlist_unhashed()? For the _prepare forms, del_prepare and
replace_prepare could record pprev -> NULL through
__rcu_txn_hlist_record_pprev(). That costs at most one record, though a
lone delete or replace of a bucket's last node would no longer be a
one-record commit.

Thanks,
Puranjay