> diff --git a/mm/bpf_memcontrol.c b/mm/bpf_memcontrol.c
> index 716df49d76477..92f35ba66309e 100644
> --- a/mm/bpf_memcontrol.c
> +++ b/mm/bpf_memcontrol.c
> @@ -6,6 +6,7 @@
>   */
>
>  #include <linux/memcontrol.h>
> +#include <linux/swap.h>
>  #include <linux/bpf.h>
>
>  __bpf_kfunc_start_defs();

[ ... ]

> +/**
> + * bpf_proactive_reclaim - proactively reclaim memory from a memory
> + *                         cgroup
> + * @memcg: the target memory cgroup to reclaim from
> + * @size:  the amount of memory to reclaim, in bytes, clamped to
> + *         MEMCG_CHARGE_BATCH (64 pages)
> + *
> + * Trigger one proactive reclaim pass on @memcg, similar to a write to
> + * memory.reclaim, but without retrying until @size is reached.
> + *
> + * @size is clamped so that one call is a bounded unit of work, matching
> + * the memory.high workqueue fallback in high_work_func(). To reclaim
> + * more, call this kfunc repeatedly instead of passing a larger @size.
> + *
> + * This kfunc is restricted to BPF_PROG_TYPE_SYSCALL to ensure it runs
> + * in a clean process context. The SYSCALL program can schedule the
> + * actual reclaim work via bpf_wq or timers, which also execute in
> + * safe process context (workqueue, task_work).

Does the kernel-doc accurately describe when this kfunc can be called?

The doc says "bpf_wq or timers" can call this kfunc and attributes "safe
process context (workqueue, task_work)" to both. bpf_timer callbacks run
in softirq context (HRTIMER_MODE_REL_SOFT in kernel/bpf/helpers.c), not
process context, and the verifier rejects the documented pattern:

kernel/bpf/verifier.c:is_async_cb_sleepable() {
    /* bpf_timer callbacks are never sleepable. */
    if (bpf_helper_call(insn) && insn->imm == BPF_FUNC_timer_set_callback)
            return false;

which then causes check_kfunc_call() to reject the KF_SLEEPABLE kfunc:

    if (sleepable && !in_sleepable(env)) {
            verbose(env, "program must be sleepable to call sleepable kfunc 
%s\n", func_name);
            return -EACCES;

So a bpf_timer callback calling bpf_proactive_reclaim() fails verification
regardless of the program being marked sleepable.

The commit message says "A SYSCALL program can still drive reclaim
asynchronously through bpf_wq or task_work callbacks", and the block
comment above BTF_KFUNCS_START(bpf_memcontrol_reclaim_kfuncs) says "The
bpf_wq and task_work callbacks that a SYSCALL program schedules run as the
same program type". Only the kernel-doc substitutes "timers" for
task_work, so the three descriptions disagree.

The follow-up selftest (5ed7b6799588 "selftests/bpf: Add memcg async
reclaim test") demonstrates the actual constraint: its bpf_timer callback
wq_timer_cb() only calls bpf_wq_start()/bpf_timer_start(), and
bpf_proactive_reclaim() is called solely from the bpf_wq callback
reclaim_work_fn().

Could "or timers" be dropped (or reworded to "a bpf_timer callback can
only kick a bpf_wq; the kfunc itself must be called from the bpf_wq or
task_work callback") so the kernel-doc matches both the verifier and the
other two descriptions in the patch?

> + *
> + * When reclaim is driven from a bpf_wq, call this kfunc once per
> + * callback and requeue the same work item for the next batch rather
> + * than looping inside the callback: a long-running callback stalls
> + * other work on the shared workqueue, and because lru_lock is held with
> + * interrupts disabled the resulting contention also delays IPI
> + * handling. Give each target memcg its own bpf_wq item, so that
> + * reclaiming one memcg neither serializes behind nor piles up on top of
> + * another. Deciding whether to submit the next batch is up to the BPF
> + * program, which can stop at any point, e.g. once the target cgroup is
> + * dying.

[ ... ]


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/33864052510

Reply via email to