mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
bpf: Save DFS postorder numbers for program instructions
Dominator intersections and SCEV worklist scheduling need to compare
instructions by their DFS postorder rank. Save per-instruction
postorder numbers alongside the existing postorder sequence.
This commit modifies bpf_compute_postorder() to actually do the DFS
traversal, instead of scheduling traversal of all siblings at once.
Consider a graph:
A -> B
A -> C
C -> B
Old result: C, B, A
DFS result: B, C, A
Fixes: efcda22aa5 ("bpf: compute instructions postorder per subprogram")
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261009-scev-minimal-rebase-v3-21-bcba9bc53ac9@gmail.com
This commit is contained in:
parent
89e72f81a4
commit
f414d20879
|
|
@ -1036,6 +1036,7 @@ struct bpf_verifier_env {
|
|||
* see bpf_subprog_info->postorder_start.
|
||||
*/
|
||||
int *insn_postorder;
|
||||
int *postorder_nums;
|
||||
int cur_stack;
|
||||
/* current position in the insn_postorder vector */
|
||||
int cur_postorder;
|
||||
|
|
|
|||
|
|
@ -767,6 +767,11 @@ int bpf_check_cfg(struct bpf_verifier_env *env)
|
|||
return ret;
|
||||
}
|
||||
|
||||
struct dfs_state {
|
||||
u32 traversed:1;
|
||||
u32 next_succ:31;
|
||||
};
|
||||
|
||||
/*
|
||||
* For each subprogram 'i' fill array env->cfg.insn_subprogram sub-range
|
||||
* [env->subprog_info[i].postorder_start, env->subprog_info[i+1].postorder_start)
|
||||
|
|
@ -774,43 +779,52 @@ int bpf_check_cfg(struct bpf_verifier_env *env)
|
|||
*/
|
||||
int bpf_compute_postorder(struct bpf_verifier_env *env)
|
||||
{
|
||||
u32 cur_postorder, i, top, stack_sz, s;
|
||||
int *stack = NULL, *postorder = NULL, *state = NULL;
|
||||
struct bpf_iarray *succ;
|
||||
int *stack = NULL, *postorder = NULL, *postorder_nums = NULL;
|
||||
int subprog_idx, stack_sz, cur, s, cur_postorder, start;
|
||||
struct dfs_state *state = NULL;
|
||||
struct bpf_iarray *succ = NULL;
|
||||
|
||||
postorder_nums = kvzalloc_objs(int, env->prog->len, GFP_KERNEL_ACCOUNT);
|
||||
postorder = kvzalloc_objs(int, env->prog->len, GFP_KERNEL_ACCOUNT);
|
||||
state = kvzalloc_objs(int, env->prog->len, GFP_KERNEL_ACCOUNT);
|
||||
stack = kvzalloc_objs(int, env->prog->len, GFP_KERNEL_ACCOUNT);
|
||||
if (!postorder || !state || !stack) {
|
||||
state = kvzalloc_objs(struct dfs_state, env->prog->len, GFP_KERNEL_ACCOUNT);
|
||||
if (!postorder_nums || !postorder || !stack || !state) {
|
||||
kvfree(postorder_nums);
|
||||
kvfree(postorder);
|
||||
kvfree(state);
|
||||
kvfree(stack);
|
||||
kvfree(state);
|
||||
return -ENOMEM;
|
||||
}
|
||||
cur_postorder = 0;
|
||||
for (i = 0; i < env->subprog_cnt; i++) {
|
||||
env->subprog_info[i].postorder_start = cur_postorder;
|
||||
stack[0] = env->subprog_info[i].start;
|
||||
for (subprog_idx = 0; subprog_idx < env->subprog_cnt; subprog_idx++) {
|
||||
start = env->subprog_info[subprog_idx].start;
|
||||
env->subprog_info[subprog_idx].postorder_start = cur_postorder;
|
||||
stack[0] = start;
|
||||
stack_sz = 1;
|
||||
state[start].traversed = true;
|
||||
do {
|
||||
top = stack[stack_sz - 1];
|
||||
state[top] |= DISCOVERED;
|
||||
if (state[top] & EXPLORED) {
|
||||
postorder[cur_postorder++] = top;
|
||||
cur = stack[stack_sz - 1];
|
||||
succ = bpf_insn_successors(env, cur);
|
||||
if (state[cur].next_succ == succ->cnt) {
|
||||
postorder_nums[cur] = cur_postorder;
|
||||
postorder[cur_postorder] = cur;
|
||||
cur_postorder++;
|
||||
stack_sz--;
|
||||
continue;
|
||||
}
|
||||
succ = bpf_insn_successors(env, top);
|
||||
for (s = 0; s < succ->cnt; ++s) {
|
||||
if (!state[succ->items[s]]) {
|
||||
stack[stack_sz++] = succ->items[s];
|
||||
state[succ->items[s]] |= DISCOVERED;
|
||||
}
|
||||
s = succ->items[state[cur].next_succ];
|
||||
if (!state[s].traversed) {
|
||||
state[s].traversed = true;
|
||||
state[s].next_succ = 0;
|
||||
stack[stack_sz] = s;
|
||||
stack_sz++;
|
||||
continue;
|
||||
}
|
||||
state[top] |= EXPLORED;
|
||||
state[cur].next_succ++;
|
||||
} while (stack_sz);
|
||||
}
|
||||
env->subprog_info[i].postorder_start = cur_postorder;
|
||||
env->subprog_info[subprog_idx].postorder_start = cur_postorder;
|
||||
env->cfg.postorder_nums = postorder_nums;
|
||||
env->cfg.insn_postorder = postorder;
|
||||
env->cfg.cur_postorder = cur_postorder;
|
||||
kvfree(stack);
|
||||
|
|
|
|||
|
|
@ -398,5 +398,7 @@ int bpf_prune_dead_branches(struct bpf_verifier_env *env)
|
|||
/* recompute postorder, since CFG has changed */
|
||||
kvfree(env->cfg.insn_postorder);
|
||||
env->cfg.insn_postorder = NULL;
|
||||
kvfree(env->cfg.postorder_nums);
|
||||
env->cfg.postorder_nums = NULL;
|
||||
return bpf_compute_postorder(env);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23221,6 +23221,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr,
|
|||
vfree(env->insn_aux_data);
|
||||
kvfree(env->fd_array);
|
||||
bpf_stack_liveness_free(env);
|
||||
kvfree(env->cfg.postorder_nums);
|
||||
kvfree(env->cfg.insn_postorder);
|
||||
kvfree(env->scc_info);
|
||||
kvfree(env->succ);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user