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

Merge tag 'perf-for-bpf-2020-05-06' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip into bpf-next

CAP_PERFMON for BPF

+145 -4
+4
include/linux/capability.h
··· 251 251 extern bool capable_wrt_inode_uidgid(const struct inode *inode, int cap); 252 252 extern bool file_ns_capable(const struct file *file, struct user_namespace *ns, int cap); 253 253 extern bool ptracer_capable(struct task_struct *tsk, struct user_namespace *ns); 254 + static inline bool perfmon_capable(void) 255 + { 256 + return capable(CAP_PERFMON) || capable(CAP_SYS_ADMIN); 257 + } 254 258 255 259 /* audit system wants to get cap info from files as well */ 256 260 extern int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps);
+7 -1
include/uapi/linux/capability.h
··· 367 367 368 368 #define CAP_AUDIT_READ 37 369 369 370 + /* 371 + * Allow system performance and observability privileged operations 372 + * using perf_events, i915_perf and other kernel subsystems 373 + */ 370 374 371 - #define CAP_LAST_CAP CAP_AUDIT_READ 375 + #define CAP_PERFMON 38 376 + 377 + #define CAP_LAST_CAP CAP_PERFMON 372 378 373 379 #define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP) 374 380
+2 -2
security/selinux/include/classmap.h
··· 27 27 "audit_control", "setfcap" 28 28 29 29 #define COMMON_CAP2_PERMS "mac_override", "mac_admin", "syslog", \ 30 - "wake_alarm", "block_suspend", "audit_read" 30 + "wake_alarm", "block_suspend", "audit_read", "perfmon" 31 31 32 - #if CAP_LAST_CAP > CAP_AUDIT_READ 32 + #if CAP_LAST_CAP > CAP_PERFMON 33 33 #error New capability defined, please update COMMON_CAP2_PERMS. 34 34 #endif 35 35
+4 -1
tools/perf/builtin-stat.c
··· 686 686 break; 687 687 } 688 688 } 689 - if (child_pid != -1) 689 + if (child_pid != -1) { 690 + if (timeout) 691 + kill(child_pid, SIGTERM); 690 692 wait4(child_pid, &status, 0, &stat_config.ru_data); 693 + } 691 694 692 695 if (workload_exec_errno) { 693 696 const char *emsg = str_error_r(workload_exec_errno, msg, sizeof(msg));
+20
tools/perf/util/annotate.c
··· 1821 1821 } 1822 1822 #endif // defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT) 1823 1823 1824 + static int 1825 + symbol__disassemble_bpf_image(struct symbol *sym, 1826 + struct annotate_args *args) 1827 + { 1828 + struct annotation *notes = symbol__annotation(sym); 1829 + struct disasm_line *dl; 1830 + 1831 + args->offset = -1; 1832 + args->line = strdup("to be implemented"); 1833 + args->line_nr = 0; 1834 + dl = disasm_line__new(args); 1835 + if (dl) 1836 + annotation_line__add(&dl->al, &notes->src->source); 1837 + 1838 + free(args->line); 1839 + return 0; 1840 + } 1841 + 1824 1842 /* 1825 1843 * Possibly create a new version of line with tabs expanded. Returns the 1826 1844 * existing or new line, storage is updated if a new line is allocated. If ··· 1938 1920 1939 1921 if (dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO) { 1940 1922 return symbol__disassemble_bpf(sym, args); 1923 + } else if (dso->binary_type == DSO_BINARY_TYPE__BPF_IMAGE) { 1924 + return symbol__disassemble_bpf_image(sym, args); 1941 1925 } else if (dso__is_kcore(dso)) { 1942 1926 kce.kcore_filename = symfs_filename; 1943 1927 kce.addr = map__rip_2objdump(map, sym->start);
+93
tools/perf/util/bpf-event.c
··· 6 6 #include <bpf/libbpf.h> 7 7 #include <linux/btf.h> 8 8 #include <linux/err.h> 9 + #include <linux/string.h> 10 + #include <internal/lib.h> 11 + #include <symbol/kallsyms.h> 9 12 #include "bpf-event.h" 10 13 #include "debug.h" 11 14 #include "dso.h" ··· 293 290 return err ? -1 : 0; 294 291 } 295 292 293 + struct kallsyms_parse { 294 + union perf_event *event; 295 + perf_event__handler_t process; 296 + struct machine *machine; 297 + struct perf_tool *tool; 298 + }; 299 + 300 + static int 301 + process_bpf_image(char *name, u64 addr, struct kallsyms_parse *data) 302 + { 303 + struct machine *machine = data->machine; 304 + union perf_event *event = data->event; 305 + struct perf_record_ksymbol *ksymbol; 306 + int len; 307 + 308 + ksymbol = &event->ksymbol; 309 + 310 + *ksymbol = (struct perf_record_ksymbol) { 311 + .header = { 312 + .type = PERF_RECORD_KSYMBOL, 313 + .size = offsetof(struct perf_record_ksymbol, name), 314 + }, 315 + .addr = addr, 316 + .len = page_size, 317 + .ksym_type = PERF_RECORD_KSYMBOL_TYPE_BPF, 318 + .flags = 0, 319 + }; 320 + 321 + len = scnprintf(ksymbol->name, KSYM_NAME_LEN, "%s", name); 322 + ksymbol->header.size += PERF_ALIGN(len + 1, sizeof(u64)); 323 + memset((void *) event + event->header.size, 0, machine->id_hdr_size); 324 + event->header.size += machine->id_hdr_size; 325 + 326 + return perf_tool__process_synth_event(data->tool, event, machine, 327 + data->process); 328 + } 329 + 330 + static int 331 + kallsyms_process_symbol(void *data, const char *_name, 332 + char type __maybe_unused, u64 start) 333 + { 334 + char disp[KSYM_NAME_LEN]; 335 + char *module, *name; 336 + unsigned long id; 337 + int err = 0; 338 + 339 + module = strchr(_name, '\t'); 340 + if (!module) 341 + return 0; 342 + 343 + /* We are going after [bpf] module ... */ 344 + if (strcmp(module + 1, "[bpf]")) 345 + return 0; 346 + 347 + name = memdup(_name, (module - _name) + 1); 348 + if (!name) 349 + return -ENOMEM; 350 + 351 + name[module - _name] = 0; 352 + 353 + /* .. and only for trampolines and dispatchers */ 354 + if ((sscanf(name, "bpf_trampoline_%lu", &id) == 1) || 355 + (sscanf(name, "bpf_dispatcher_%s", disp) == 1)) 356 + err = process_bpf_image(name, start, data); 357 + 358 + free(name); 359 + return err; 360 + } 361 + 296 362 int perf_event__synthesize_bpf_events(struct perf_session *session, 297 363 perf_event__handler_t process, 298 364 struct machine *machine, 299 365 struct record_opts *opts) 300 366 { 367 + const char *kallsyms_filename = "/proc/kallsyms"; 368 + struct kallsyms_parse arg; 301 369 union perf_event *event; 302 370 __u32 id = 0; 303 371 int err; ··· 377 303 event = malloc(sizeof(event->bpf) + KSYM_NAME_LEN + machine->id_hdr_size); 378 304 if (!event) 379 305 return -1; 306 + 307 + /* Synthesize all the bpf programs in system. */ 380 308 while (true) { 381 309 err = bpf_prog_get_next_id(id, &id); 382 310 if (err) { ··· 411 335 break; 412 336 } 413 337 } 338 + 339 + /* Synthesize all the bpf images - trampolines/dispatchers. */ 340 + if (symbol_conf.kallsyms_name != NULL) 341 + kallsyms_filename = symbol_conf.kallsyms_name; 342 + 343 + arg = (struct kallsyms_parse) { 344 + .event = event, 345 + .process = process, 346 + .machine = machine, 347 + .tool = session->tool, 348 + }; 349 + 350 + if (kallsyms__parse(kallsyms_filename, &arg, kallsyms_process_symbol)) { 351 + pr_err("%s: failed to synthesize bpf images: %s\n", 352 + __func__, strerror(errno)); 353 + } 354 + 414 355 free(event); 415 356 return err; 416 357 }
+1
tools/perf/util/dso.c
··· 191 191 case DSO_BINARY_TYPE__GUEST_KALLSYMS: 192 192 case DSO_BINARY_TYPE__JAVA_JIT: 193 193 case DSO_BINARY_TYPE__BPF_PROG_INFO: 194 + case DSO_BINARY_TYPE__BPF_IMAGE: 194 195 case DSO_BINARY_TYPE__NOT_FOUND: 195 196 ret = -1; 196 197 break;
+1
tools/perf/util/dso.h
··· 40 40 DSO_BINARY_TYPE__GUEST_KCORE, 41 41 DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO, 42 42 DSO_BINARY_TYPE__BPF_PROG_INFO, 43 + DSO_BINARY_TYPE__BPF_IMAGE, 43 44 DSO_BINARY_TYPE__NOT_FOUND, 44 45 }; 45 46
+12
tools/perf/util/machine.c
··· 736 736 return 0; 737 737 } 738 738 739 + static int is_bpf_image(const char *name) 740 + { 741 + return strncmp(name, "bpf_trampoline_", sizeof("bpf_trampoline_") - 1) || 742 + strncmp(name, "bpf_dispatcher_", sizeof("bpf_dispatcher_") - 1); 743 + } 744 + 739 745 static int machine__process_ksymbol_register(struct machine *machine, 740 746 union perf_event *event, 741 747 struct perf_sample *sample __maybe_unused) ··· 765 759 map->start = event->ksymbol.addr; 766 760 map->end = map->start + event->ksymbol.len; 767 761 maps__insert(&machine->kmaps, map); 762 + dso__set_loaded(dso); 763 + 764 + if (is_bpf_image(event->ksymbol.name)) { 765 + dso->binary_type = DSO_BINARY_TYPE__BPF_IMAGE; 766 + dso__set_long_name(dso, "", false); 767 + } 768 768 } 769 769 770 770 sym = symbol__new(map->map_ip(map, map->start),
+1
tools/perf/util/symbol.c
··· 1544 1544 return true; 1545 1545 1546 1546 case DSO_BINARY_TYPE__BPF_PROG_INFO: 1547 + case DSO_BINARY_TYPE__BPF_IMAGE: 1547 1548 case DSO_BINARY_TYPE__NOT_FOUND: 1548 1549 default: 1549 1550 return false;