Skip to content

lunatik: percpu groups, one object owning one runtime per CPU - #693

Open
lneto wants to merge 3 commits into
masterfrom
claude_percpu_groups
Open

lunatik: percpu groups, one object owning one runtime per CPU#693
lneto wants to merge 3 commits into
masterfrom
claude_percpu_groups

Conversation

@lneto

@lneto lneto commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

A percpu script now registers as a single object that owns one runtime per possible CPU id, allocated with alloc_percpu as the object's private, and lunatik_run resolves it to the instance of the CPU the callback fired on: a plain runtime pays one bit test, so a binding gains dispatch without changing a line. This is the kernel's own shape: one registration, per-CPU data reached through the per-CPU pointer, instead of N registrations filtering by CPU.

env.percpu and the <script>:<cpu> key convention are gone: one table, one key, one lookup. The runner loses the per-CPU loops and the two-phase shutdown that existed only because stopping a percpu script deleted N entries under an iteration that allows deleting only the entry it hands out; the XDP kfunc loses the per-packet scnprintf and second hash lookup. runner.startup refuses a stale _ENV.percpu left by an older runner, in the mold of the existing restore guard.

Dispatch reads the instance with raw_cpu_ptr: from a preemptible context this is the instance of the CPU the caller happened to be on, which is all a migratable caller can ask for, and it avoids the smp_processor_id splat under CONFIG_DEBUG_PREEMPT.

This subsumes the registry split of 9b900f5, which existed to separate two key shapes in one table; the object removes the second shape.

Groundwork for the shared-registration layer that will let netfilter and probe opt into percpu (#675): the exactly-once dispatch becomes structural once there is a single hook per script.

The XDP path has no test suite; it was verified by hand on a veth pair with the remote end in a netns, with a minimal XDP program calling bpf_luaxdp_run: a plain runtime takes every packet on one instance, a percpu script counts them on the instance of the receiving CPU.

🤖 Generated with Claude Code

@lneto
lneto force-pushed the claude_percpu_enforcement branch from e26a81e to 2786065 Compare August 9, 2026 13:43
@lneto
lneto force-pushed the claude_percpu_groups branch 2 times, most recently from 88060fe to b30a91c Compare August 9, 2026 15:00
@lneto
lneto force-pushed the claude_percpu_enforcement branch from 6b5d4e3 to fdb5ccd Compare August 9, 2026 15:09
@lneto
lneto force-pushed the claude_percpu_groups branch from b30a91c to 45edfad Compare August 9, 2026 15:09
@lneto
lneto force-pushed the claude_percpu_enforcement branch from fdb5ccd to 9e474bc Compare August 9, 2026 15:11
@lneto
lneto force-pushed the claude_percpu_groups branch 3 times, most recently from 172cbe9 to a7817c8 Compare August 9, 2026 15:30
@lneto
lneto changed the base branch from claude_percpu_enforcement to master August 9, 2026 15:39
@lneto
lneto force-pushed the claude_percpu_groups branch 7 times, most recently from 11bf6f6 to 816942b Compare August 11, 2026 14:35
lneto and others added 3 commits August 11, 2026 14:41
A percpu object owns one runtime per possible CPU id, allocated with
alloc_percpu, and lunatik_run resolves it to the instance of the CPU
the callback fired on: a plain runtime costs one bit test, so a binding
gains dispatch without changing a line. The caller must hold a
reference across the call, which is what keeps the instances alive.

lunatik_stop splits into closing the state and dropping the reference,
so stopping the set leaves the instances reachable until the last
reference goes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
env.runtimes held plain script names while env.percpu held one
`<script>:<cpu>` key per instance, and every consumer had to know both:
the runner looped over CPU ids to run, stop and list, and the XDP kfunc
built a per-packet key to look the instance up. A percpu script now
registers as one object under its own name, so there is one table, one
key and one lookup, and the dispatch happens inside lunatik_run.

The runner loses the key convention along with the two-phase shutdown
that existed because stopping a percpu script deleted N entries under
an iteration that only allows deleting the entry it hands out.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The failing script counted its runs in _ENV, and the plain run at the
end of the test left the counter at 1: on the next run of the suite the
error fired on the first instance, so the rollback assertion covered
the rollback of nothing. Keying the failure on lunatik.cpu() == 1 needs
no state, and the plain run passes because a plain runtime has no id.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@lneto
lneto force-pushed the claude_percpu_groups branch from 816942b to 8246b0d Compare August 11, 2026 14:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant