bpf: Add missed value to kprobe perf link info
authorJiri Olsa <jolsa@kernel.org>
Wed, 20 Sep 2023 21:31:39 +0000 (23:31 +0200)
committerAndrii Nakryiko <andrii@kernel.org>
Mon, 25 Sep 2023 23:37:44 +0000 (16:37 -0700)
Add missed value to kprobe attached through perf link info to
hold the stats of missed kprobe handler execution.

The kprobe's missed counter gets incremented when kprobe handler
is not executed due to another kprobe running on the same cpu.

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20230920213145.1941596-4-jolsa@kernel.org
include/linux/trace_events.h
include/uapi/linux/bpf.h
kernel/bpf/syscall.c
kernel/trace/bpf_trace.c
kernel/trace/trace_kprobe.c
tools/include/uapi/linux/bpf.h

index 21ae37e49319a13287ef895c51e1362ed20aeca7..5eb88a66eb682cca1aa492788954e9fdb9046d2c 100644 (file)
@@ -761,7 +761,8 @@ struct bpf_raw_event_map *bpf_get_raw_tracepoint(const char *name);
 void bpf_put_raw_tracepoint(struct bpf_raw_event_map *btp);
 int bpf_get_perf_event_info(const struct perf_event *event, u32 *prog_id,
                            u32 *fd_type, const char **buf,
-                           u64 *probe_offset, u64 *probe_addr);
+                           u64 *probe_offset, u64 *probe_addr,
+                           unsigned long *missed);
 int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *prog);
 int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *prog);
 #else
@@ -801,7 +802,7 @@ static inline void bpf_put_raw_tracepoint(struct bpf_raw_event_map *btp)
 static inline int bpf_get_perf_event_info(const struct perf_event *event,
                                          u32 *prog_id, u32 *fd_type,
                                          const char **buf, u64 *probe_offset,
-                                         u64 *probe_addr)
+                                         u64 *probe_addr, unsigned long *missed)
 {
        return -EOPNOTSUPP;
 }
@@ -877,6 +878,7 @@ extern void perf_kprobe_destroy(struct perf_event *event);
 extern int bpf_get_kprobe_info(const struct perf_event *event,
                               u32 *fd_type, const char **symbol,
                               u64 *probe_offset, u64 *probe_addr,
+                              unsigned long *missed,
                               bool perf_type_tracepoint);
 #endif
 #ifdef CONFIG_UPROBE_EVENTS
index 1da5b1bcce710e6cf585da2bb736f92a8ddb0668..70bfa997e8963b5d4fc583144651b660a3d8ffc9 100644 (file)
@@ -6548,6 +6548,7 @@ struct bpf_link_info {
                                        __u32 name_len;
                                        __u32 offset; /* offset from func_name */
                                        __u64 addr;
+                                       __u64 missed;
                                } kprobe; /* BPF_PERF_EVENT_KPROBE, BPF_PERF_EVENT_KRETPROBE */
                                struct {
                                        __aligned_u64 tp_name;   /* in/out */
index 85c1d908f70f82aca4d3aca275ea6738d4f9f62d..6b5280f14a53e921c18da58ab978e37265bf21b4 100644 (file)
@@ -3374,7 +3374,7 @@ static void bpf_perf_link_dealloc(struct bpf_link *link)
 static int bpf_perf_link_fill_common(const struct perf_event *event,
                                     char __user *uname, u32 ulen,
                                     u64 *probe_offset, u64 *probe_addr,
-                                    u32 *fd_type)
+                                    u32 *fd_type, unsigned long *missed)
 {
        const char *buf;
        u32 prog_id;
@@ -3385,7 +3385,7 @@ static int bpf_perf_link_fill_common(const struct perf_event *event,
                return -EINVAL;
 
        err = bpf_get_perf_event_info(event, &prog_id, fd_type, &buf,
-                                     probe_offset, probe_addr);
+                                     probe_offset, probe_addr, missed);
        if (err)
                return err;
        if (!uname)
@@ -3408,6 +3408,7 @@ static int bpf_perf_link_fill_common(const struct perf_event *event,
 static int bpf_perf_link_fill_kprobe(const struct perf_event *event,
                                     struct bpf_link_info *info)
 {
+       unsigned long missed;
        char __user *uname;
        u64 addr, offset;
        u32 ulen, type;
@@ -3416,7 +3417,7 @@ static int bpf_perf_link_fill_kprobe(const struct perf_event *event,
        uname = u64_to_user_ptr(info->perf_event.kprobe.func_name);
        ulen = info->perf_event.kprobe.name_len;
        err = bpf_perf_link_fill_common(event, uname, ulen, &offset, &addr,
-                                       &type);
+                                       &type, &missed);
        if (err)
                return err;
        if (type == BPF_FD_TYPE_KRETPROBE)
@@ -3425,6 +3426,7 @@ static int bpf_perf_link_fill_kprobe(const struct perf_event *event,
                info->perf_event.type = BPF_PERF_EVENT_KPROBE;
 
        info->perf_event.kprobe.offset = offset;
+       info->perf_event.kprobe.missed = missed;
        if (!kallsyms_show_value(current_cred()))
                addr = 0;
        info->perf_event.kprobe.addr = addr;
@@ -3444,7 +3446,7 @@ static int bpf_perf_link_fill_uprobe(const struct perf_event *event,
        uname = u64_to_user_ptr(info->perf_event.uprobe.file_name);
        ulen = info->perf_event.uprobe.name_len;
        err = bpf_perf_link_fill_common(event, uname, ulen, &offset, &addr,
-                                       &type);
+                                       &type, NULL);
        if (err)
                return err;
 
@@ -3480,7 +3482,7 @@ static int bpf_perf_link_fill_tracepoint(const struct perf_event *event,
        uname = u64_to_user_ptr(info->perf_event.tracepoint.tp_name);
        ulen = info->perf_event.tracepoint.name_len;
        info->perf_event.type = BPF_PERF_EVENT_TRACEPOINT;
-       return bpf_perf_link_fill_common(event, uname, ulen, NULL, NULL, NULL);
+       return bpf_perf_link_fill_common(event, uname, ulen, NULL, NULL, NULL, NULL);
 }
 
 static int bpf_perf_link_fill_perf_event(const struct perf_event *event,
@@ -4813,7 +4815,7 @@ static int bpf_task_fd_query(const union bpf_attr *attr,
 
                err = bpf_get_perf_event_info(event, &prog_id, &fd_type,
                                              &buf, &probe_offset,
-                                             &probe_addr);
+                                             &probe_addr, NULL);
                if (!err)
                        err = bpf_task_fd_query_copy(attr, uattr, prog_id,
                                                     fd_type, buf,
index 6aec6e7d612ab5859c0d7ef11adb2cf2c8c36462..f6a7d25249496916d0b5e1e9234340c629d5c156 100644 (file)
@@ -2384,7 +2384,8 @@ int bpf_probe_unregister(struct bpf_raw_event_map *btp, struct bpf_prog *prog)
 
 int bpf_get_perf_event_info(const struct perf_event *event, u32 *prog_id,
                            u32 *fd_type, const char **buf,
-                           u64 *probe_offset, u64 *probe_addr)
+                           u64 *probe_offset, u64 *probe_addr,
+                           unsigned long *missed)
 {
        bool is_tracepoint, is_syscall_tp;
        struct bpf_prog *prog;
@@ -2419,7 +2420,7 @@ int bpf_get_perf_event_info(const struct perf_event *event, u32 *prog_id,
 #ifdef CONFIG_KPROBE_EVENTS
                if (flags & TRACE_EVENT_FL_KPROBE)
                        err = bpf_get_kprobe_info(event, fd_type, buf,
-                                                 probe_offset, probe_addr,
+                                                 probe_offset, probe_addr, missed,
                                                  event->attr.type == PERF_TYPE_TRACEPOINT);
 #endif
 #ifdef CONFIG_UPROBE_EVENTS
index 3d7a180a84272e891458c5274daa2897a91f867c..961a78ffd6d275b0b336b00e2c95113c20b5154c 100644 (file)
@@ -1189,6 +1189,12 @@ static const struct file_operations kprobe_events_ops = {
        .write          = probes_write,
 };
 
+static unsigned long trace_kprobe_missed(struct trace_kprobe *tk)
+{
+       return trace_kprobe_is_return(tk) ?
+               tk->rp.kp.nmissed + tk->rp.nmissed : tk->rp.kp.nmissed;
+}
+
 /* Probes profiling interfaces */
 static int probes_profile_seq_show(struct seq_file *m, void *v)
 {
@@ -1200,8 +1206,7 @@ static int probes_profile_seq_show(struct seq_file *m, void *v)
                return 0;
 
        tk = to_trace_kprobe(ev);
-       nmissed = trace_kprobe_is_return(tk) ?
-               tk->rp.kp.nmissed + tk->rp.nmissed : tk->rp.kp.nmissed;
+       nmissed = trace_kprobe_missed(tk);
        seq_printf(m, "  %-44s %15lu %15lu\n",
                   trace_probe_name(&tk->tp),
                   trace_kprobe_nhit(tk),
@@ -1547,7 +1552,8 @@ NOKPROBE_SYMBOL(kretprobe_perf_func);
 
 int bpf_get_kprobe_info(const struct perf_event *event, u32 *fd_type,
                        const char **symbol, u64 *probe_offset,
-                       u64 *probe_addr, bool perf_type_tracepoint)
+                       u64 *probe_addr, unsigned long *missed,
+                       bool perf_type_tracepoint)
 {
        const char *pevent = trace_event_name(event->tp_event);
        const char *group = event->tp_event->class->system;
@@ -1566,6 +1572,8 @@ int bpf_get_kprobe_info(const struct perf_event *event, u32 *fd_type,
        *probe_addr = kallsyms_show_value(current_cred()) ?
                      (unsigned long)tk->rp.kp.addr : 0;
        *symbol = tk->symbol;
+       if (missed)
+               *missed = trace_kprobe_missed(tk);
        return 0;
 }
 #endif /* CONFIG_PERF_EVENTS */
index 1da5b1bcce710e6cf585da2bb736f92a8ddb0668..70bfa997e8963b5d4fc583144651b660a3d8ffc9 100644 (file)
@@ -6548,6 +6548,7 @@ struct bpf_link_info {
                                        __u32 name_len;
                                        __u32 offset; /* offset from func_name */
                                        __u64 addr;
+                                       __u64 missed;
                                } kprobe; /* BPF_PERF_EVENT_KPROBE, BPF_PERF_EVENT_KRETPROBE */
                                struct {
                                        __aligned_u64 tp_name;   /* in/out */