Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpf: Introducte bpf_this_cpu_ptr()

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@google.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Andrii Nakryiko <andriin@fb.com>
Link: https://lore.kernel.org/bpf/20200929235049.2533242-6-haoluo@google.com

authored by

Hao Luo and committed by
Alexei Starovoitov
63d9b80d eaa6bcb7

+52 -3
+2
include/linux/bpf.h
··· 309 309 RET_PTR_TO_ALLOC_MEM_OR_NULL, /* returns a pointer to dynamically allocated memory or NULL */ 310 310 RET_PTR_TO_BTF_ID_OR_NULL, /* returns a pointer to a btf_id or NULL */ 311 311 RET_PTR_TO_MEM_OR_BTF_ID_OR_NULL, /* returns a pointer to a valid memory or a btf_id or NULL */ 312 + RET_PTR_TO_MEM_OR_BTF_ID, /* returns a pointer to a valid memory or a btf_id */ 312 313 }; 313 314 314 315 /* eBPF function prototype used by verifier to allow BPF_CALLs from eBPF programs ··· 1833 1832 extern const struct bpf_func_proto bpf_copy_from_user_proto; 1834 1833 extern const struct bpf_func_proto bpf_snprintf_btf_proto; 1835 1834 extern const struct bpf_func_proto bpf_per_cpu_ptr_proto; 1835 + extern const struct bpf_func_proto bpf_this_cpu_ptr_proto; 1836 1836 1837 1837 const struct bpf_func_proto *bpf_tracing_func_proto( 1838 1838 enum bpf_func_id func_id, const struct bpf_prog *prog);
+13
include/uapi/linux/bpf.h
··· 3703 3703 * Return 3704 3704 * A pointer pointing to the kernel percpu variable on *cpu*, or 3705 3705 * NULL, if *cpu* is invalid. 3706 + * 3707 + * void *bpf_this_cpu_ptr(const void *percpu_ptr) 3708 + * Description 3709 + * Take a pointer to a percpu ksym, *percpu_ptr*, and return a 3710 + * pointer to the percpu kernel variable on this cpu. See the 3711 + * description of 'ksym' in **bpf_per_cpu_ptr**\ (). 3712 + * 3713 + * bpf_this_cpu_ptr() has the same semantic as this_cpu_ptr() in 3714 + * the kernel. Different from **bpf_per_cpu_ptr**\ (), it would 3715 + * never return NULL. 3716 + * Return 3717 + * A pointer pointing to the kernel percpu variable on this cpu. 3706 3718 */ 3707 3719 #define __BPF_FUNC_MAPPER(FN) \ 3708 3720 FN(unspec), \ ··· 3871 3859 FN(skb_cgroup_classid), \ 3872 3860 FN(redirect_neigh), \ 3873 3861 FN(bpf_per_cpu_ptr), \ 3862 + FN(bpf_this_cpu_ptr), \ 3874 3863 /* */ 3875 3864 3876 3865 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
+14
kernel/bpf/helpers.c
··· 639 639 .arg2_type = ARG_ANYTHING, 640 640 }; 641 641 642 + BPF_CALL_1(bpf_this_cpu_ptr, const void *, percpu_ptr) 643 + { 644 + return (unsigned long)this_cpu_ptr((const void __percpu *)percpu_ptr); 645 + } 646 + 647 + const struct bpf_func_proto bpf_this_cpu_ptr_proto = { 648 + .func = bpf_this_cpu_ptr, 649 + .gpl_only = false, 650 + .ret_type = RET_PTR_TO_MEM_OR_BTF_ID, 651 + .arg1_type = ARG_PTR_TO_PERCPU_BTF_ID, 652 + }; 653 + 642 654 const struct bpf_func_proto bpf_get_current_task_proto __weak; 643 655 const struct bpf_func_proto bpf_probe_read_user_proto __weak; 644 656 const struct bpf_func_proto bpf_probe_read_user_str_proto __weak; ··· 719 707 return &bpf_jiffies64_proto; 720 708 case BPF_FUNC_bpf_per_cpu_ptr: 721 709 return &bpf_per_cpu_ptr_proto; 710 + case BPF_FUNC_bpf_this_cpu_ptr: 711 + return &bpf_this_cpu_ptr_proto; 722 712 default: 723 713 break; 724 714 }
+8 -3
kernel/bpf/verifier.c
··· 5128 5128 regs[BPF_REG_0].type = PTR_TO_MEM_OR_NULL; 5129 5129 regs[BPF_REG_0].id = ++env->id_gen; 5130 5130 regs[BPF_REG_0].mem_size = meta.mem_size; 5131 - } else if (fn->ret_type == RET_PTR_TO_MEM_OR_BTF_ID_OR_NULL) { 5131 + } else if (fn->ret_type == RET_PTR_TO_MEM_OR_BTF_ID_OR_NULL || 5132 + fn->ret_type == RET_PTR_TO_MEM_OR_BTF_ID) { 5132 5133 const struct btf_type *t; 5133 5134 5134 5135 mark_reg_known_zero(env, regs, BPF_REG_0); ··· 5147 5146 tname, PTR_ERR(ret)); 5148 5147 return -EINVAL; 5149 5148 } 5150 - regs[BPF_REG_0].type = PTR_TO_MEM_OR_NULL; 5149 + regs[BPF_REG_0].type = 5150 + fn->ret_type == RET_PTR_TO_MEM_OR_BTF_ID ? 5151 + PTR_TO_MEM : PTR_TO_MEM_OR_NULL; 5151 5152 regs[BPF_REG_0].mem_size = tsize; 5152 5153 } else { 5153 - regs[BPF_REG_0].type = PTR_TO_BTF_ID_OR_NULL; 5154 + regs[BPF_REG_0].type = 5155 + fn->ret_type == RET_PTR_TO_MEM_OR_BTF_ID ? 5156 + PTR_TO_BTF_ID : PTR_TO_BTF_ID_OR_NULL; 5154 5157 regs[BPF_REG_0].btf_id = meta.ret_btf_id; 5155 5158 } 5156 5159 } else if (fn->ret_type == RET_PTR_TO_BTF_ID_OR_NULL) {
+2
kernel/trace/bpf_trace.c
··· 1329 1329 return &bpf_snprintf_btf_proto; 1330 1330 case BPF_FUNC_bpf_per_cpu_ptr: 1331 1331 return &bpf_per_cpu_ptr_proto; 1332 + case BPF_FUNC_bpf_this_cpu_ptr: 1333 + return &bpf_this_cpu_ptr_proto; 1332 1334 default: 1333 1335 return NULL; 1334 1336 }
+13
tools/include/uapi/linux/bpf.h
··· 3703 3703 * Return 3704 3704 * A pointer pointing to the kernel percpu variable on *cpu*, or 3705 3705 * NULL, if *cpu* is invalid. 3706 + * 3707 + * void *bpf_this_cpu_ptr(const void *percpu_ptr) 3708 + * Description 3709 + * Take a pointer to a percpu ksym, *percpu_ptr*, and return a 3710 + * pointer to the percpu kernel variable on this cpu. See the 3711 + * description of 'ksym' in **bpf_per_cpu_ptr**\ (). 3712 + * 3713 + * bpf_this_cpu_ptr() has the same semantic as this_cpu_ptr() in 3714 + * the kernel. Different from **bpf_per_cpu_ptr**\ (), it would 3715 + * never return NULL. 3716 + * Return 3717 + * A pointer pointing to the kernel percpu variable on this cpu. 3706 3718 */ 3707 3719 #define __BPF_FUNC_MAPPER(FN) \ 3708 3720 FN(unspec), \ ··· 3871 3859 FN(skb_cgroup_classid), \ 3872 3860 FN(redirect_neigh), \ 3873 3861 FN(bpf_per_cpu_ptr), \ 3862 + FN(bpf_this_cpu_ptr), \ 3874 3863 /* */ 3875 3864 3876 3865 /* integer value in 'imm' field of BPF_CALL instruction selects which helper