[PATCH RFC bpf-next v1 2/9] bpf: Refactor and generalize optimize_bpf_loop

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The optimize_bpf_loop pass is currently used to transform calls to the
bpf_loop helper function into an inlined instruction sequence which
elides the helper call and does the looping directly and emits the call
to the loop callback.

The future patches for exception propagation for BPF programs will
require similar rewriting which needs access to extra stack space to
spill registers which may be clobbered in the emitted sequence.

We wish to reuse the logic of updating subprog stack depth by tracking
the extra stack depth needed across all rewrites in a subprog in
subseqeunt patches. Hence, refactor the code to make it amenable for
plugging extra rewrite passes over other instructions. Note that the
stack_depth_extra is now set by a max of existing and required extra
stack depth. This allows rewrites to reuse the extra stack depth among
themselves, by figuring the maximum depth needed for a subprog.

Note that we only do one rewrite in one loop iteration, and thus
new_prog is set only once. This can be used to pull out shared updates
of delta, env->prog, etc. into common code that occurs after all cases
of possible rewrites are examined, and if application, performed.

Signed-off-by: Kumar Kartikeya Dwivedi <memxor@xxxxxxxxx>
---
 kernel/bpf/verifier.c | 28 +++++++++++++++++-----------
 1 file changed, 17 insertions(+), 11 deletions(-)

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 693aeddc9fe2..8ecd5df73b07 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -18024,23 +18024,26 @@ static struct bpf_prog *inline_bpf_loop(struct bpf_verifier_env *env,
 	return new_prog;
 }
 
-static bool is_bpf_loop_call(struct bpf_insn *insn)
+static bool is_inlineable_bpf_loop_call(struct bpf_insn *insn,
+					struct bpf_insn_aux_data *aux)
 {
 	return insn->code == (BPF_JMP | BPF_CALL) &&
 		insn->src_reg == 0 &&
-		insn->imm == BPF_FUNC_loop;
+		insn->imm == BPF_FUNC_loop &&
+		aux->loop_inline_state.fit_for_inline;
 }
 
 /* For all sub-programs in the program (including main) check
- * insn_aux_data to see if there are bpf_loop calls that require
- * inlining. If such calls are found the calls are replaced with a
+ * insn_aux_data to see if there are any instructions that need to be
+ * transformed into an instruction sequence. E.g. bpf_loop calls that
+ * require inlining. If such calls are found the calls are replaced with a
  * sequence of instructions produced by `inline_bpf_loop` function and
  * subprog stack_depth is increased by the size of 3 registers.
  * This stack space is used to spill values of the R6, R7, R8.  These
  * registers are used to store the loop bound, counter and context
  * variables.
  */
-static int optimize_bpf_loop(struct bpf_verifier_env *env)
+static int do_misc_rewrites(struct bpf_verifier_env *env)
 {
 	struct bpf_subprog_info *subprogs = env->subprog_info;
 	int i, cur_subprog = 0, cnt, delta = 0;
@@ -18051,13 +18054,14 @@ static int optimize_bpf_loop(struct bpf_verifier_env *env)
 	u16 stack_depth_extra = 0;
 
 	for (i = 0; i < insn_cnt; i++, insn++) {
-		struct bpf_loop_inline_state *inline_state =
-			&env->insn_aux_data[i + delta].loop_inline_state;
+		struct bpf_insn_aux_data *insn_aux = &env->insn_aux_data[i + delta];
+		struct bpf_prog *new_prog = NULL;
 
-		if (is_bpf_loop_call(insn) && inline_state->fit_for_inline) {
-			struct bpf_prog *new_prog;
+		if (is_inlineable_bpf_loop_call(insn, insn_aux)) {
+			struct bpf_loop_inline_state *inline_state = &insn_aux->loop_inline_state;
 
-			stack_depth_extra = BPF_REG_SIZE * 3 + stack_depth_roundup;
+			stack_depth_extra = max_t(u16, stack_depth_extra,
+						  BPF_REG_SIZE * 3 + stack_depth_roundup);
 			new_prog = inline_bpf_loop(env,
 						   i + delta,
 						   -(stack_depth + stack_depth_extra),
@@ -18065,7 +18069,9 @@ static int optimize_bpf_loop(struct bpf_verifier_env *env)
 						   &cnt);
 			if (!new_prog)
 				return -ENOMEM;
+		}
 
+		if (new_prog) {
 			delta     += cnt - 1;
 			env->prog  = new_prog;
 			insn       = new_prog->insnsi + i + delta;
@@ -18876,7 +18882,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr)
 
 	/* instruction rewrites happen after this point */
 	if (ret == 0)
-		ret = optimize_bpf_loop(env);
+		ret = do_misc_rewrites(env);
 
 	if (is_priv) {
 		if (ret == 0)
-- 
2.40.0




[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux