]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
bpf: Allow sleepable programs to use tail calls
authorJiri Olsa <jolsa@kernel.org>
Fri, 30 Jan 2026 08:12:07 +0000 (09:12 +0100)
committerAlexei Starovoitov <ast@kernel.org>
Fri, 30 Jan 2026 20:17:47 +0000 (12:17 -0800)
Allowing sleepable programs to use tail calls.

Making sure we can't mix sleepable and non-sleepable bpf programs
in tail call map (BPF_MAP_TYPE_PROG_ARRAY) and allowing it to be
used in sleepable programs.

Sleepable programs can be preempted and sleep which might bring
new source of race conditions, but both direct and indirect tail
calls should not be affected.

Direct tail calls work by patching direct jump to callee into bpf
caller program, so no problem there. We atomically switch from nop
to jump instruction.

Indirect tail call reads the callee from the map and then jumps to
it. The callee bpf program can't disappear (be released) from the
caller, because it is executed under rcu lock (rcu_read_lock_trace).

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Acked-by: Leon Hwang <leon.hwang@linux.dev>
Link: https://lore.kernel.org/r/20260130081208.1130204-2-jolsa@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
include/linux/bpf.h
kernel/bpf/core.c
kernel/bpf/verifier.c

index 5524f9429e7626166615757a640863a89617020a..3b0ceb75907523ba663f12d283bab31e7e1180e6 100644 (file)
@@ -287,6 +287,7 @@ struct bpf_map_owner {
        enum bpf_prog_type type;
        bool jited;
        bool xdp_has_frags;
+       bool sleepable;
        u64 storage_cookie[MAX_BPF_CGROUP_STORAGE_TYPE];
        const struct btf_type *attach_func_proto;
        enum bpf_attach_type expected_attach_type;
index e0b8a8a5aaa91f3f5755222b2d648f2543a16abb..5ebece600aebaa9d24bafc951cac50c464208ecf 100644 (file)
@@ -2401,6 +2401,7 @@ static bool __bpf_prog_map_compatible(struct bpf_map *map,
                map->owner->type  = prog_type;
                map->owner->jited = fp->jited;
                map->owner->xdp_has_frags = aux->xdp_has_frags;
+               map->owner->sleepable = fp->sleepable;
                map->owner->expected_attach_type = fp->expected_attach_type;
                map->owner->attach_func_proto = aux->attach_func_proto;
                for_each_cgroup_storage_type(i) {
@@ -2412,7 +2413,8 @@ static bool __bpf_prog_map_compatible(struct bpf_map *map,
        } else {
                ret = map->owner->type  == prog_type &&
                      map->owner->jited == fp->jited &&
-                     map->owner->xdp_has_frags == aux->xdp_has_frags;
+                     map->owner->xdp_has_frags == aux->xdp_has_frags &&
+                     map->owner->sleepable == fp->sleepable;
                if (ret &&
                    map->map_type == BPF_MAP_TYPE_PROG_ARRAY &&
                    map->owner->expected_attach_type != fp->expected_attach_type)
index e7ff8394e0dadc89501302b37d4fb95501629dab..f185ebc6748d970dbf8efc1b3a7c27cd65a1b3b3 100644 (file)
@@ -21386,6 +21386,7 @@ static int check_map_prog_compatibility(struct bpf_verifier_env *env,
                case BPF_MAP_TYPE_STACK:
                case BPF_MAP_TYPE_ARENA:
                case BPF_MAP_TYPE_INSN_ARRAY:
+               case BPF_MAP_TYPE_PROG_ARRAY:
                        break;
                default:
                        verbose(env,