Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754367AbbGACXr (ORCPT ); Tue, 30 Jun 2015 22:23:47 -0400 Received: from szxga03-in.huawei.com ([119.145.14.66]:62799 "EHLO szxga03-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752475AbbGACPs (ORCPT ); Tue, 30 Jun 2015 22:15:48 -0400 From: Wang Nan To: , , , , , , , , , , CC: , , , , Subject: [RFC PATCH v10 39/50] bpf tools: Load a program with different instance using preprocessor Date: Wed, 1 Jul 2015 02:14:27 +0000 Message-ID: <1435716878-189507-40-git-send-email-wangnan0@huawei.com> X-Mailer: git-send-email 1.8.3.4 In-Reply-To: <1435716878-189507-1-git-send-email-wangnan0@huawei.com> References: <1435716878-189507-1-git-send-email-wangnan0@huawei.com> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [10.107.197.200] X-CFilter-Loop: Reflected X-Mirapoint-Virus-RAPID-Raw: score=unknown(0), refid=str=0001.0A020205.55934D45.0102,ss=1,re=0.000,recu=0.000,reip=0.000,cl=1,cld=1,fgs=0, ip=0.0.0.0, so=2013-05-26 15:14:31, dmn=2013-03-21 17:37:32 X-Mirapoint-Loop-Id: 7fc54096668d54b76d13fcce2aa77fb5 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 6647 Lines: 242 In this patch, caller of libbpf is able to control the loaded programs by installing a preprocessor callback for a BPF program. With preprocessor, different instances can be created from one BPF program. This patch will be used by perf to generate different prologue for different 'struct probe_trace_event' instances matched by one 'struct perf_probe_event'. bpf_program__set_prep() is added to support this function. Caller should pass libbpf the number of instance should be created and a preprocessor function which will be called when doing real loading. The callback should return instructions arrays for each instances. nr_instance and instance_fds are appended into bpf_programs to support multiple instances. bpf_program__get_nth_fd() is introduced for read fd of instances. Old interface bpf_program__get_fd() won't work for program which has preprocessor hooked. Signed-off-by: Wang Nan Signed-off-by: He Kuang --- tools/lib/bpf/libbpf.c | 135 +++++++++++++++++++++++++++++++++++++++++++++++-- tools/lib/bpf/libbpf.h | 22 ++++++++ 2 files changed, 152 insertions(+), 5 deletions(-) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 540ac558..518372c 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -100,6 +100,10 @@ struct bpf_program { int fd; + int nr_instance; + int *instance_fds; + bpf_program_prep_t preprocessor; + struct bpf_object *obj; void *priv; bpf_program_clear_priv_t clear_priv; @@ -156,6 +160,19 @@ static void bpf_program__unload(struct bpf_program *prog) return; zclose(prog->fd); + + if (prog->preprocessor) { + int i; + + if (prog->nr_instance <= 0) + pr_warning("Internal error when unloading: instance is %d\n", + prog->nr_instance); + else + for (i = 0; i < prog->nr_instance; i++) + zclose(prog->instance_fds[i]); + prog->nr_instance = -1; + zfree(&prog->instance_fds); + } } static void bpf_program__clear(struct bpf_program *prog) @@ -231,6 +248,8 @@ bpf_program__new(struct bpf_object *obj, void *data, size_t size, prog->idx = idx; prog->fd = -1; prog->obj = obj; + prog->nr_instance = -1; + prog->instance_fds = NULL; return prog; out: @@ -788,13 +807,57 @@ static int bpf_program__load(struct bpf_program *prog, char *license, u32 kern_version) { - int err, fd; + int err = 0, fd, i; + + if (!prog->preprocessor) { + err = load_program(prog->insns, prog->insns_cnt, + license, kern_version, &fd); + if (!err) + prog->fd = fd; + goto out; + } - err = load_program(prog->insns, prog->insns_cnt, - license, kern_version, &fd); - if (!err) - prog->fd = fd; + if (prog->nr_instance <= 0 || !prog->instance_fds) { + pr_warning("Internal error when loading '%s'\n", + prog->section_name); + return -EINVAL; + } + + for (i = 0; i < prog->nr_instance; i++) { + struct bpf_prog_prep_result result; + bpf_program_prep_t preprocessor = prog->preprocessor; + + bzero(&result, sizeof(result)); + err = preprocessor(prog, i, prog->insns, + prog->insns_cnt, &result); + if (err) { + pr_warning("Preprocessing %dth instance of program '%s' failed\n", + i, prog->section_name); + goto out; + } + + if (!result.new_insn_ptr || !result.new_insn_cnt) { + pr_debug("Skip loading %dth instance of program '%s'\n", + i, prog->section_name); + prog->instance_fds[i] = -1; + continue; + } + err = load_program(result.new_insn_ptr, + result.new_insn_cnt, + license, kern_version, &fd); + + if (err) { + pr_warning("Loading %dth instance of program '%s' failed\n", + i, prog->section_name); + goto out; + } + + if (result.pfd) + *result.pfd = fd; + prog->instance_fds[i] = fd; + } +out: if (err) pr_warning("failed to load program '%s'\n", prog->section_name); @@ -1044,6 +1107,68 @@ int bpf_program__get_fd(struct bpf_program *prog, int *pfd) if (!pfd) return -EINVAL; + if (prog->preprocessor) { + pr_warning("Invalid using bpf_program__get_fd() on program %s\n", + prog->section_name); + return -EINVAL; + } + *pfd = prog->fd; return 0; } + +int bpf_program__set_prep(struct bpf_program *prog, int nr_instance, + bpf_program_prep_t prep) +{ + int *instance_fds; + + if (nr_instance <= 0 || !prep) + return -EINVAL; + + instance_fds = malloc(sizeof(int) * nr_instance); + if (!instance_fds) { + pr_warning("alloc memory failed for instance of fds\n"); + return -ENOMEM; + } + + /* fill all fd with -1 */ + memset(instance_fds, 0xff, sizeof(int) * nr_instance); + + prog->nr_instance = nr_instance; + prog->instance_fds = instance_fds; + prog->preprocessor = prep; + return 0; +} + +int bpf_program__get_nth_fd(struct bpf_program *prog, int n, int *pfd) +{ + int fd; + + if (!pfd) + return -EINVAL; + + if (!prog->preprocessor || + prog->nr_instance <= 0 || + !prog->instance_fds) { + + pr_warning("Invalid using bpf_program__get_nth_fd() on program %s\n", + prog->section_name); + return -EINVAL; + } + + if (n >= prog->nr_instance || n < 0) { + pr_warning("Can't get the %dth fd from program %s: only %d instances\n", + n, prog->section_name, prog->nr_instance); + return -EINVAL; + } + + fd = prog->instance_fds[n]; + if (fd < 0) { + pr_warning("%dth instance of program '%s' is invalid\n", + n, prog->section_name); + return -EEXIST; + } + + *pfd = fd; + return 0; +} diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 1cd17a2..a815215 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -69,6 +69,28 @@ int bpf_program__get_title(struct bpf_program *prog, int bpf_program__get_fd(struct bpf_program *prog, int *pfd); +struct bpf_insn; +struct bpf_prog_prep_result { + /* + * If not NULL, load new instruction array. + * If set to NULL, don't load this instance. + */ + struct bpf_insn *new_insn_ptr; + int new_insn_cnt; + + /* If not NULL, result fd is set to it */ + int *pfd; +}; + +typedef int (*bpf_program_prep_t)(struct bpf_program *, int n, + struct bpf_insn *, int insn_cnt, + struct bpf_prog_prep_result *res); + +int bpf_program__set_prep(struct bpf_program *prog, int nr_instance, + bpf_program_prep_t prep); + +int bpf_program__get_nth_fd(struct bpf_program *prog, int n, int *pfd); + /* * We don't need __attribute__((packed)) now since it is * unnecessary for 'bpf_map_def' because they are all aligned. -- 1.8.3.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/