BPF List
 help / color / mirror / Atom feed
From: "Alexei Starovoitov" <alexei.starovoitov@gmail.com>
To: "Kumar Kartikeya Dwivedi" <memxor@gmail.com>, <bpf@vger.kernel.org>
Cc: "Andrii Nakryiko" <andrii@kernel.org>,
	"Daniel Borkmann" <daniel@iogearbox.net>,
	"Eduard Zingerman" <eddyz87@gmail.com>,
	"Emil Tsalapatis" <emil@etsalapatis.com>,
	"Ihor Solodrai" <ihor.solodrai@linux.dev>, <kkd@meta.com>,
	<kernel-team@meta.com>
Subject: Re: [PATCH bpf-next v1 00/29] Exceptions - Resource Cleanup - Redux
Date: Wed, 11 Nov 2026 20:33:26 +0000	[thread overview]
Message-ID: <DMSO2CZRMEUE.LE9RG32M5QBN@gmail.com> (raw)
In-Reply-To: <cover.1794399387.git.memxor@gmail.com>

On Wed, Nov 11, 2026 at 04:56 AM Kumar Kartikeya Dwivedi <memxor@gmail.com> wrote:
> This series allows the main program and its subprogs, static and global,
> to throw while holding resources. The unwinder releases the resources of
> every frame it discards.

Agree that we need bpf_throw() from everywhere.
Below is an idea for brainstorming. No code yet.

Drop elaboration in the verifier. Pads instead of descriptors.

Keep the analysis of what a frame holds at a site.
Change what comes out of it: not tables for a C unwinder, but landing pads.
A pad is BPF insns that the verifier adds after the main pass, like guards.
Then throw, cancel and rust panic are one mechanism:
unwind_goto / unwind_exit.

1. One unwinder

  site                                 the verifier emits
  -----------------------------------  ---------------------------------
  call bpf_throw                       r0 = cookie; goto pad
  loop guard, recursion check          may_goto pad
  call / callx of a subprog that may   unwind_goto pad, behind the call
  unwind, no unwind_goto behind it
  helper that runs a callback          unwind_goto pad, behind the call
  (your 'helpers have pads')
  arena load / store / atomic          unwind_goto pad, behind the access.
                                       JIT points the extable entry at it

  pad:  release calls
        r0 = 0
        unwind_exit          main prog: call exception_cb; exit

Every frame leaves through its epilogue. The frame at the site has R0-R9.
A frame that waits in a call has R6-R9 and its stack.
No stack walk, no asm entries, no saved register offsets, no site tables.
No void (*)(void *) wrappers: a pad calls the release kfunc with its type.
A frame of rust keeps its own pads. Nothing is skipped by construction.
Sites that need the same pad share it. Most sites hold nothing.

2. Three questions, answered apart

  WHO        The frame that acquired it since its entry.
  releases   What a callee returns with is the caller's.
             Or the callee that it was MOVED into: the caller keeps no
             live copy behind the call (R6-R9, stack).
             Decided at the call from the state and liveness.
             Nothing provisional. Nothing to settle after the pass.
  WHERE is   The prog's own live place, like your lattice: register,
  the handle spill, stack object, pointer to what the lock is in + delta,
             fixed address, load through a live pointer.
             The prog has to release it later, so the handle is live.
  WHETHER    The pc, when all states at the site agree.
  it is held Otherwise a DROP FLAG, as rustc and clang do it.

3. The drop flag

One hidden byte in the frame. The entry of the subprog zeroes the word.

  flag = 1   behind the insn of THIS frame that brought the resource:
             the acquiring call, the call of a subprog that returns
             with it, or the entry when it was moved in
  flag = 0   at the insn of THIS frame that takes it away:
             the releasing call, or the call that moves it out

        *(u8 *)(r10 - H) = 0
        if r7 == 0 goto skip
        call bpf_task_from_pid
        r6 = r0
        *(u8 *)(r10 - H) = 1
  skip: ... arena access, loop, call foo ...          -> pad
        if r7 == 0 goto out
        *(u8 *)(r10 - H) = 0
        r1 = r6
        call bpf_task_release
  pad:  r1 = *(u8 *)(r10 - H)
        if r1 == 0 goto done
        r1 = r6
        if r1 == 0 goto done
        call bpf_task_release
  done: r0 = 0
        unwind_exit

The stores are unconditional. bpf_res_spin_lock() needs a test of r0 first.
The flag has no handle in it. So there is no register to find at the
acquire, no compare chain at the release, no refresh after a call.
A flag is emitted only where the states at some site disagree.

Identity: a reference carries its origin, as in your set.
A join or a subsumption can pair two references with different origins.
Then the origins go into one set (union-find) and share a flag.
States are joined as today.
Sections become entries of refs[], so they have an origin too.

4. What I hope goes away, in your terms

  tables, unwinder, phases, asm entries,   pads
  registers recovered from prologues
  mirror                                   flag + the prog's own place
  NULL in the lattice                      flag. A pad tests for NULL too
  entry guarded by a scalar                flag
  descriptor per chain of calls            flag in the callee's frame:
                                           'differs by chain' is 'held
                                           on some paths' there
  provisional listings, transfer           move at the call
  other origins are not joined             union-find

What stays: classes, type -> release kfunc, the places, helpers have pads,
the return value of a cancelled prog, the struct_ops hook, the stack in
arena, bpf_throw() reads all registers and slots for liveness.

5. Where I'm looking for ideas.

 a. Several resources of one origin at once. rbtree_search pops nodes
    into an array in a loop that is walked. A flag per origin cannot say
    which.
 b. A callee releases what the caller keeps live, on some paths only.
    try_consume(obj). During the call the pc of the callee tells.
    Behind the call only the callee knows. Maybe: the callee has its own
    flag and returns it in a scratch register at exit and unwind_exit.
    R2 survives exit already for 16 byte returns.
    I think you're doing something like that in your followup patches.


      parent reply	other threads:[~2026-11-11 20:33 UTC|newest]

Thread overview: 58+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-11 12:56 [PATCH bpf-next v1 00/29] Exceptions - Resource Cleanup - Redux Kumar Kartikeya Dwivedi
2026-11-11 12:56 ` [PATCH bpf-next v1 01/29] bpf: Record where JITs save callee-saved registers Kumar Kartikeya Dwivedi
2026-11-11 12:57 ` [PATCH bpf-next v1 02/29] bpf: Add bpf_throw_unwind() and an arch entry hook Kumar Kartikeya Dwivedi
2026-11-11 14:45   ` sashiko-bot
2026-11-11 12:57 ` [PATCH bpf-next v1 03/29] bpf, x86: Capture registers in a native bpf_throw() entry Kumar Kartikeya Dwivedi
2026-11-11 12:57 ` [PATCH bpf-next v1 04/29] bpf, arm64: " Kumar Kartikeya Dwivedi
2026-11-11 12:57 ` [PATCH bpf-next v1 05/29] bpf: Restore callee-saved registers from unwound frames Kumar Kartikeya Dwivedi
2026-11-11 14:41   ` sashiko-bot
2026-11-11 12:57 ` [PATCH bpf-next v1 06/29] bpf: Keep last insn's aux data in add_hidden_subprog() Kumar Kartikeya Dwivedi
2026-11-11 14:38   ` sashiko-bot
2026-11-11 12:57 ` [PATCH bpf-next v1 07/29] bpf: Add one allocator for hidden stack slots Kumar Kartikeya Dwivedi
2026-11-11 14:04   ` bot+bpf-ci
2026-11-11 15:15   ` sashiko-bot
2026-11-11 12:57 ` [PATCH bpf-next v1 08/29] bpf: Add flags and release kfuncs to the dtor registry Kumar Kartikeya Dwivedi
2026-11-11 13:33   ` bot+bpf-ci
2026-11-11 15:36   ` sashiko-bot
2026-11-11 12:57 ` [PATCH bpf-next v1 09/29] bpf: Register cleanup destructors for more types Kumar Kartikeya Dwivedi
2026-11-11 14:04   ` bot+bpf-ci
2026-11-11 15:00   ` sashiko-bot
2026-11-11 12:57 ` [PATCH bpf-next v1 10/29] bpf: Record where JITed frames keep the BPF stack Kumar Kartikeya Dwivedi
2026-11-11 12:57 ` [PATCH bpf-next v1 11/29] bpf: Give every reference an owner frame Kumar Kartikeya Dwivedi
2026-11-11 13:33   ` bot+bpf-ci
2026-11-11 12:57 ` [PATCH bpf-next v1 12/29] bpf: Release resources in hidden slots on bpf_throw() Kumar Kartikeya Dwivedi
2026-11-11 14:04   ` bot+bpf-ci
2026-11-11 15:30   ` sashiko-bot
2026-11-11 12:57 ` [PATCH bpf-next v1 13/29] bpf: Track held resources in hidden stack slots Kumar Kartikeya Dwivedi
2026-11-11 14:04   ` bot+bpf-ci
2026-11-11 16:12   ` sashiko-bot
2026-11-11 12:57 ` [PATCH bpf-next v1 14/29] bpf: Describe held resources at throw sites Kumar Kartikeya Dwivedi
2026-11-11 14:04   ` bot+bpf-ci
2026-11-11 12:57 ` [PATCH bpf-next v1 15/29] bpf: Describe handles in registers " Kumar Kartikeya Dwivedi
2026-11-11 14:04   ` bot+bpf-ci
2026-11-11 16:11   ` sashiko-bot
2026-11-11 12:57 ` [PATCH bpf-next v1 16/29] bpf: Describe locks " Kumar Kartikeya Dwivedi
2026-11-11 14:04   ` bot+bpf-ci
2026-11-11 16:04   ` sashiko-bot
2026-11-11 12:57 ` [PATCH bpf-next v1 17/29] bpf: Apply hidden slot limits only when a slot is needed Kumar Kartikeya Dwivedi
2026-11-11 16:31   ` sashiko-bot
2026-11-11 12:57 ` [PATCH bpf-next v1 18/29] bpf: Allow a callee to leave resources with its caller Kumar Kartikeya Dwivedi
2026-11-11 14:04   ` bot+bpf-ci
2026-11-11 16:41   ` sashiko-bot
2026-11-11 12:57 ` [PATCH bpf-next v1 19/29] bpf: Allow a callee to release its caller's resources Kumar Kartikeya Dwivedi
2026-11-11 17:02   ` sashiko-bot
2026-11-11 12:57 ` [PATCH bpf-next v1 20/29] bpf: Transfer a reference to the callee that releases it Kumar Kartikeya Dwivedi
2026-11-11 14:04   ` bot+bpf-ci
2026-11-11 16:57   ` sashiko-bot
2026-11-11 12:57 ` [PATCH bpf-next v1 21/29] bpf: Support callx when a callee releases resources Kumar Kartikeya Dwivedi
2026-11-11 14:04   ` bot+bpf-ci
2026-11-11 17:13   ` sashiko-bot
2026-11-11 12:57 ` [PATCH bpf-next v1 22/29] selftests/bpf: Test rejected throws that hold resources Kumar Kartikeya Dwivedi
2026-11-11 12:57 ` [PATCH bpf-next v1 23/29] selftests/bpf: Test resource cleanup on bpf_throw() Kumar Kartikeya Dwivedi
2026-11-11 12:57 ` [PATCH bpf-next v1 24/29] selftests/bpf: Test cleanup of handles on the stack Kumar Kartikeya Dwivedi
2026-11-11 12:57 ` [PATCH bpf-next v1 25/29] selftests/bpf: Test cleanup of handles in registers Kumar Kartikeya Dwivedi
2026-11-11 12:57 ` [PATCH bpf-next v1 26/29] selftests/bpf: Test callees releasing caller resources Kumar Kartikeya Dwivedi
2026-11-11 12:57 ` [PATCH bpf-next v1 27/29] selftests/bpf: Test resources a callee leaves with its caller Kumar Kartikeya Dwivedi
2026-11-11 12:57 ` [PATCH bpf-next v1 28/29] selftests/bpf: Test cleanup of locks described at sites Kumar Kartikeya Dwivedi
2026-11-11 12:57 ` [PATCH bpf-next v1 29/29] selftests/bpf: Test callee releases through callx Kumar Kartikeya Dwivedi
2026-11-11 20:33 ` Alexei Starovoitov [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=DMSO2CZRMEUE.LE9RG32M5QBN@gmail.com \
    --to=alexei.starovoitov@gmail.com \
    --cc=andrii@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=eddyz87@gmail.com \
    --cc=emil@etsalapatis.com \
    --cc=ihor.solodrai@linux.dev \
    --cc=kernel-team@meta.com \
    --cc=kkd@meta.com \
    --cc=memxor@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox