Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

timers/migration: Remove locking on group connection

Initializing the tmc's group, the group's number of children and the
group's parent can all be done without locking because:

1) Reading the group's parent and its group mask is done locklessly.

2) The connections prepared for a given CPU hierarchy are visible to the
target CPU once online, thanks to the CPU hotplug enforced memory
ordering.

3) In case of a newly created upper level, the new root and its
connections and initialization are made visible by the CPU which made
the connections. When that CPUs goes idle in the future, the new link
is published by tmigr_inactive_up() through the atomic RmW on
->migr_state.

4) If CPUs were still walking up the active hierarchy, they could observe
the new root earlier. In this case the ordering is enforced by an
early initialization of the group mask and by barriers that maintain
address dependency as explained in:

b729cc1ec21a ("timers/migration: Fix another race between hotplug and idle entry/exit")
de3ced72a792 ("timers/migration: Enforce group initialization visibility to tree walkers")

5) Timers are propagated by a chain of group locking from the bottom to
the top. And while doing so, the tree also propagates groups links
and initialization. Therefore remote expiration, which also relies
on group locking, will observe those links and initialization while
holding the root lock before walking the tree remotely and update
remote timers. This is especially important for migrators in the
active hierarchy that may observe the new root early.

Therefore the locking is unnecessary at initialization. If anything, it
just brings confusion. Remove it.

Signed-off-by: Frederic Weisbecker <frederic@kernel.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://patch.msgid.link/20251024132536.39841-3-frederic@kernel.org

authored by

Frederic Weisbecker and committed by
Thomas Gleixner
fa962035 6c181b56

-10
-10
kernel/time/timer_migration.c
··· 1573 1573 { 1574 1574 struct tmigr_walk data; 1575 1575 1576 - raw_spin_lock_irq(&child->lock); 1577 - raw_spin_lock_nested(&parent->lock, SINGLE_DEPTH_NESTING); 1578 - 1579 1576 if (activate) { 1580 1577 /* 1581 1578 * @child is the old top and @parent the new one. In this ··· 1592 1595 * address dependency that pairs with the READ_ONCE() in __walk_groups(). 1593 1596 */ 1594 1597 smp_store_release(&child->parent, parent); 1595 - 1596 - raw_spin_unlock(&parent->lock); 1597 - raw_spin_unlock_irq(&child->lock); 1598 1598 1599 1599 trace_tmigr_connect_child_parent(child); 1600 1600 ··· 1689 1695 if (i == 0) { 1690 1696 struct tmigr_cpu *tmc = per_cpu_ptr(&tmigr_cpu, cpu); 1691 1697 1692 - raw_spin_lock_irq(&group->lock); 1693 - 1694 1698 tmc->tmgroup = group; 1695 1699 tmc->groupmask = BIT(group->num_children++); 1696 - 1697 - raw_spin_unlock_irq(&group->lock); 1698 1700 1699 1701 trace_tmigr_connect_cpu_parent(tmc); 1700 1702