Thanks for taking a look! On Fri, Sep 4, 2020 at 1:09 PM Andrii Nakryiko <andrii.nakryiko@xxxxxxxxx> wrote: > > On Thu, Sep 3, 2020 at 3:35 PM Hao Luo <haoluo@xxxxxxxxxx> wrote: > > > > Add bpf_this_cpu_ptr() to help access percpu var on this cpu. This > > helper always returns a valid pointer, therefore no need to check > > returned value for NULL. Also note that all programs run with > > preemption disabled, which means that the returned pointer is stable > > during all the execution of the program. > > > > Signed-off-by: Hao Luo <haoluo@xxxxxxxxxx> > > --- > > looks good, few small things, but otherwise: > > Acked-by: Andrii Nakryiko <andriin@xxxxxx> > [...] > > > > /* eBPF function prototype used by verifier to allow BPF_CALLs from eBPF programs > > diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h > > index d0ec94d5bdbf..e7ca91c697ed 100644 > > --- a/include/uapi/linux/bpf.h > > +++ b/include/uapi/linux/bpf.h > > @@ -3612,6 +3612,19 @@ union bpf_attr { > > * bpf_per_cpu_ptr() must check the returned value. > > * Return > > * A generic pointer pointing to the kernel percpu variable on *cpu*. > > + * > > + * void *bpf_this_cpu_ptr(const void *percpu_ptr) > > + * Description > > + * Take a pointer to a percpu ksym, *percpu_ptr*, and return a > > + * pointer to the percpu kernel variable on this cpu. See the > > + * description of 'ksym' in **bpf_per_cpu_ptr**\ (). > > + * > > + * bpf_this_cpu_ptr() has the same semantic as this_cpu_ptr() in > > + * the kernel. Different from **bpf_per_cpu_ptr**\ (), it would > > + * never return NULL. > > + * Return > > + * A generic pointer pointing to the kernel percpu variable on > > what's "a generic pointer"? is it as opposed to sk_buff pointer or something? > Ack. "A pointer" should be good enough. I wrote "generic pointer" because the per_cpu_ptr() in kernel code is a macro, whose returned value is a typed pointer, IIUC. But here we are missing the type. This is another difference between this helper and per_cpu_ptr(). But this may not matter. > > /* integer value in 'imm' field of BPF_CALL instruction selects which helper > > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c > > index a702600ff581..e070d2abc405 100644 > > --- a/kernel/bpf/verifier.c > > +++ b/kernel/bpf/verifier.c > > @@ -5016,8 +5016,10 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn > > regs[BPF_REG_0].type = PTR_TO_MEM_OR_NULL; > > regs[BPF_REG_0].id = ++env->id_gen; > > regs[BPF_REG_0].mem_size = meta.mem_size; > > - } else if (fn->ret_type == RET_PTR_TO_MEM_OR_BTF_ID_OR_NULL) { > > + } else if (fn->ret_type == RET_PTR_TO_MEM_OR_BTF_ID_OR_NULL || > > + fn->ret_type == RET_PTR_TO_MEM_OR_BTF_ID) { > > const struct btf_type *t; > > + bool not_null = fn->ret_type == RET_PTR_TO_MEM_OR_BTF_ID; > > nit: this is fine, but I'd inline it below > Ack. > > > > mark_reg_known_zero(env, regs, BPF_REG_0); > > t = btf_type_skip_modifiers(btf_vmlinux, meta.ret_btf_id, NULL); > > @@ -5034,10 +5036,12 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn > > tname, PTR_ERR(ret)); > > return -EINVAL; > > } > > - regs[BPF_REG_0].type = PTR_TO_MEM_OR_NULL; > > + regs[BPF_REG_0].type = not_null ? > > + PTR_TO_MEM : PTR_TO_MEM_OR_NULL; > > regs[BPF_REG_0].mem_size = tsize; > > } else { > > - regs[BPF_REG_0].type = PTR_TO_BTF_ID_OR_NULL; > > + regs[BPF_REG_0].type = not_null ? > > + PTR_TO_BTF_ID : PTR_TO_BTF_ID_OR_NULL; > > regs[BPF_REG_0].btf_id = meta.ret_btf_id; > > } > > } else if (fn->ret_type == RET_PTR_TO_BTF_ID_OR_NULL) { > > diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c > > index d474c1530f87..466acf82a9c7 100644 > > --- a/kernel/trace/bpf_trace.c > > +++ b/kernel/trace/bpf_trace.c > > @@ -1160,6 +1160,18 @@ static const struct bpf_func_proto bpf_per_cpu_ptr_proto = { > > .arg2_type = ARG_ANYTHING, > > }; > > > > +BPF_CALL_1(bpf_this_cpu_ptr, const void *, percpu_ptr) > > +{ > > + return (u64)this_cpu_ptr(percpu_ptr); > > see previous comment, this might trigger unnecessary compilation > warnings on 32-bit arches > Ack. Will cast to "unsigned long". Thanks for catching this! > > +} > > + > > +static const struct bpf_func_proto bpf_this_cpu_ptr_proto = { > > + .func = bpf_this_cpu_ptr, > > + .gpl_only = false, > > + .ret_type = RET_PTR_TO_MEM_OR_BTF_ID, > > + .arg1_type = ARG_PTR_TO_PERCPU_BTF_ID, > > +}; > > + > > [...]