Skip to content

Commit f9e2bb4

Browse files
committed
Merge tag 'perf-tools-fixes-for-v5.12-2020-03-28' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux
Pull perf tooling fixes from Arnaldo Carvalho de Melo: - Avoid write of uninitialized memory when generating PERF_RECORD_MMAP* records. - Fix 'perf top' BPF support related crash with perf_event_paranoid=3 + kptr_restrict. - Validate raw event with sysfs exported format bits. - Fix waipid on SIGCHLD delivery bugs in 'perf daemon'. - Change to use bash for daemon test on Debian, where the default is dash and thus fails for use of bashisms in this test. - Fix memory leak in vDSO found using ASAN. - Remove now useless (due to the fact that BPF now supports static vars) failing sub test "BPF relocation checker". - Fix auxtrace queue conflict. - Sync linux/kvm.h with the kernel sources. * tag 'perf-tools-fixes-for-v5.12-2020-03-28' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux: perf test: Change to use bash for daemon test perf record: Fix memory leak in vDSO found using ASAN perf test: Remove now useless failing sub test "BPF relocation checker" perf daemon: Return from kill functions perf daemon: Force waipid for all session on SIGCHLD delivery perf top: Fix BPF support related crash with perf_event_paranoid=3 + kptr_restrict perf pmu: Validate raw event with sysfs exported format bits perf synthetic events: Avoid write of uninitialized memory when generating PERF_RECORD_MMAP* records tools headers UAPI: Sync linux/kvm.h with the kernel sources perf synthetic-events: Fix uninitialized 'kernel_thread' variable perf auxtrace: Fix auxtrace queue conflict
2 parents 3fef15f + 1dc481c commit f9e2bb4

File tree

11 files changed

+105
-45
lines changed

11 files changed

+105
-45
lines changed

tools/include/uapi/linux/kvm.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,6 +1154,7 @@ struct kvm_x86_mce {
11541154
#define KVM_XEN_HVM_CONFIG_HYPERCALL_MSR (1 << 0)
11551155
#define KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL (1 << 1)
11561156
#define KVM_XEN_HVM_CONFIG_SHARED_INFO (1 << 2)
1157+
#define KVM_XEN_HVM_CONFIG_RUNSTATE (1 << 3)
11571158

11581159
struct kvm_xen_hvm_config {
11591160
__u32 flags;
@@ -1621,12 +1622,24 @@ struct kvm_xen_vcpu_attr {
16211622
union {
16221623
__u64 gpa;
16231624
__u64 pad[8];
1625+
struct {
1626+
__u64 state;
1627+
__u64 state_entry_time;
1628+
__u64 time_running;
1629+
__u64 time_runnable;
1630+
__u64 time_blocked;
1631+
__u64 time_offline;
1632+
} runstate;
16241633
} u;
16251634
};
16261635

16271636
/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO */
16281637
#define KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO 0x0
16291638
#define KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO 0x1
1639+
#define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR 0x2
1640+
#define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_CURRENT 0x3
1641+
#define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_DATA 0x4
1642+
#define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADJUST 0x5
16301643

16311644
/* Secure Encrypted Virtualization command */
16321645
enum sev_cmd_id {

tools/perf/builtin-daemon.c

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -402,35 +402,42 @@ static pid_t handle_signalfd(struct daemon *daemon)
402402
int status;
403403
pid_t pid;
404404

405+
/*
406+
* Take signal fd data as pure signal notification and check all
407+
* the sessions state. The reason is that multiple signals can get
408+
* coalesced in kernel and we can receive only single signal even
409+
* if multiple SIGCHLD were generated.
410+
*/
405411
err = read(daemon->signal_fd, &si, sizeof(struct signalfd_siginfo));
406-
if (err != sizeof(struct signalfd_siginfo))
412+
if (err != sizeof(struct signalfd_siginfo)) {
413+
pr_err("failed to read signal fd\n");
407414
return -1;
415+
}
408416

409417
list_for_each_entry(session, &daemon->sessions, list) {
418+
if (session->pid == -1)
419+
continue;
410420

411-
if (session->pid != (int) si.ssi_pid)
421+
pid = waitpid(session->pid, &status, WNOHANG);
422+
if (pid <= 0)
412423
continue;
413424

414-
pid = waitpid(session->pid, &status, 0);
415-
if (pid == session->pid) {
416-
if (WIFEXITED(status)) {
417-
pr_info("session '%s' exited, status=%d\n",
418-
session->name, WEXITSTATUS(status));
419-
} else if (WIFSIGNALED(status)) {
420-
pr_info("session '%s' killed (signal %d)\n",
421-
session->name, WTERMSIG(status));
422-
} else if (WIFSTOPPED(status)) {
423-
pr_info("session '%s' stopped (signal %d)\n",
424-
session->name, WSTOPSIG(status));
425-
} else {
426-
pr_info("session '%s' Unexpected status (0x%x)\n",
427-
session->name, status);
428-
}
425+
if (WIFEXITED(status)) {
426+
pr_info("session '%s' exited, status=%d\n",
427+
session->name, WEXITSTATUS(status));
428+
} else if (WIFSIGNALED(status)) {
429+
pr_info("session '%s' killed (signal %d)\n",
430+
session->name, WTERMSIG(status));
431+
} else if (WIFSTOPPED(status)) {
432+
pr_info("session '%s' stopped (signal %d)\n",
433+
session->name, WSTOPSIG(status));
434+
} else {
435+
pr_info("session '%s' Unexpected status (0x%x)\n",
436+
session->name, status);
429437
}
430438

431439
session->state = KILL;
432440
session->pid = -1;
433-
return pid;
434441
}
435442

436443
return 0;
@@ -443,7 +450,6 @@ static int daemon_session__wait(struct daemon_session *session, struct daemon *d
443450
.fd = daemon->signal_fd,
444451
.events = POLLIN,
445452
};
446-
pid_t wpid = 0, pid = session->pid;
447453
time_t start;
448454

449455
start = time(NULL);
@@ -452,15 +458,15 @@ static int daemon_session__wait(struct daemon_session *session, struct daemon *d
452458
int err = poll(&pollfd, 1, 1000);
453459

454460
if (err > 0) {
455-
wpid = handle_signalfd(daemon);
461+
handle_signalfd(daemon);
456462
} else if (err < 0) {
457463
perror("failed: poll\n");
458464
return -1;
459465
}
460466

461467
if (start + secs < time(NULL))
462468
return -1;
463-
} while (wpid != pid);
469+
} while (session->pid != -1);
464470

465471
return 0;
466472
}
@@ -902,7 +908,9 @@ static void daemon_session__kill(struct daemon_session *session,
902908
daemon_session__signal(session, SIGKILL);
903909
break;
904910
default:
905-
break;
911+
pr_err("failed to wait for session %s\n",
912+
session->name);
913+
return;
906914
}
907915
how++;
908916

@@ -955,7 +963,8 @@ static void daemon__kill(struct daemon *daemon)
955963
daemon__signal(daemon, SIGKILL);
956964
break;
957965
default:
958-
break;
966+
pr_err("failed to wait for sessions\n");
967+
return;
959968
}
960969
how++;
961970

@@ -1344,7 +1353,7 @@ static int __cmd_start(struct daemon *daemon, struct option parent_options[],
13441353
close(sock_fd);
13451354
if (conf_fd != -1)
13461355
close(conf_fd);
1347-
if (conf_fd != -1)
1356+
if (signal_fd != -1)
13481357
close(signal_fd);
13491358

13501359
pr_info("daemon exited\n");

tools/perf/tests/bpf.c

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ static struct {
8686
.msg_load_fail = "check your vmlinux setting?",
8787
.target_func = &epoll_pwait_loop,
8888
.expect_result = (NR_ITERS + 1) / 2,
89-
.pin = true,
89+
.pin = true,
9090
},
9191
#ifdef HAVE_BPF_PROLOGUE
9292
{
@@ -99,13 +99,6 @@ static struct {
9999
.expect_result = (NR_ITERS + 1) / 4,
100100
},
101101
#endif
102-
{
103-
.prog_id = LLVM_TESTCASE_BPF_RELOCATION,
104-
.desc = "BPF relocation checker",
105-
.name = "[bpf_relocation_test]",
106-
.msg_compile_fail = "fix 'perf test LLVM' first",
107-
.msg_load_fail = "libbpf error when dealing with relocation",
108-
},
109102
};
110103

111104
static int do_test(struct bpf_object *obj, int (*func)(void),

tools/perf/tests/shell/daemon.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#!/bin/sh
1+
#!/bin/bash
22
# daemon operations
33
# SPDX-License-Identifier: GPL-2.0
44

tools/perf/util/auxtrace.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -298,10 +298,6 @@ static int auxtrace_queues__queue_buffer(struct auxtrace_queues *queues,
298298
queue->set = true;
299299
queue->tid = buffer->tid;
300300
queue->cpu = buffer->cpu;
301-
} else if (buffer->cpu != queue->cpu || buffer->tid != queue->tid) {
302-
pr_err("auxtrace queue conflict: cpu %d, tid %d vs cpu %d, tid %d\n",
303-
queue->cpu, queue->tid, buffer->cpu, buffer->tid);
304-
return -EINVAL;
305301
}
306302

307303
buffer->buffer_nr = queues->next_buffer_nr++;

tools/perf/util/bpf-event.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -196,25 +196,32 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session,
196196
}
197197

198198
if (info_linear->info_len < offsetof(struct bpf_prog_info, prog_tags)) {
199+
free(info_linear);
199200
pr_debug("%s: the kernel is too old, aborting\n", __func__);
200201
return -2;
201202
}
202203

203204
info = &info_linear->info;
205+
if (!info->jited_ksyms) {
206+
free(info_linear);
207+
return -1;
208+
}
204209

205210
/* number of ksyms, func_lengths, and tags should match */
206211
sub_prog_cnt = info->nr_jited_ksyms;
207212
if (sub_prog_cnt != info->nr_prog_tags ||
208-
sub_prog_cnt != info->nr_jited_func_lens)
213+
sub_prog_cnt != info->nr_jited_func_lens) {
214+
free(info_linear);
209215
return -1;
216+
}
210217

211218
/* check BTF func info support */
212219
if (info->btf_id && info->nr_func_info && info->func_info_rec_size) {
213220
/* btf func info number should be same as sub_prog_cnt */
214221
if (sub_prog_cnt != info->nr_func_info) {
215222
pr_debug("%s: mismatch in BPF sub program count and BTF function info count, aborting\n", __func__);
216-
err = -1;
217-
goto out;
223+
free(info_linear);
224+
return -1;
218225
}
219226
if (btf__get_from_id(info->btf_id, &btf)) {
220227
pr_debug("%s: failed to get BTF of id %u, aborting\n", __func__, info->btf_id);

tools/perf/util/parse-events.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,9 @@ __add_event(struct list_head *list, int *idx,
356356
struct perf_cpu_map *cpus = pmu ? perf_cpu_map__get(pmu->cpus) :
357357
cpu_list ? perf_cpu_map__new(cpu_list) : NULL;
358358

359+
if (pmu && attr->type == PERF_TYPE_RAW)
360+
perf_pmu__warn_invalid_config(pmu, attr->config, name);
361+
359362
if (init_attr)
360363
event_attr_init(attr);
361364

tools/perf/util/pmu.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1812,3 +1812,36 @@ int perf_pmu__caps_parse(struct perf_pmu *pmu)
18121812

18131813
return nr_caps;
18141814
}
1815+
1816+
void perf_pmu__warn_invalid_config(struct perf_pmu *pmu, __u64 config,
1817+
char *name)
1818+
{
1819+
struct perf_pmu_format *format;
1820+
__u64 masks = 0, bits;
1821+
char buf[100];
1822+
unsigned int i;
1823+
1824+
list_for_each_entry(format, &pmu->format, list) {
1825+
if (format->value != PERF_PMU_FORMAT_VALUE_CONFIG)
1826+
continue;
1827+
1828+
for_each_set_bit(i, format->bits, PERF_PMU_FORMAT_BITS)
1829+
masks |= 1ULL << i;
1830+
}
1831+
1832+
/*
1833+
* Kernel doesn't export any valid format bits.
1834+
*/
1835+
if (masks == 0)
1836+
return;
1837+
1838+
bits = config & ~masks;
1839+
if (bits == 0)
1840+
return;
1841+
1842+
bitmap_scnprintf((unsigned long *)&bits, sizeof(bits) * 8, buf, sizeof(buf));
1843+
1844+
pr_warning("WARNING: event '%s' not valid (bits %s of config "
1845+
"'%llx' not supported by kernel)!\n",
1846+
name ?: "N/A", buf, config);
1847+
}

tools/perf/util/pmu.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,4 +123,7 @@ int perf_pmu__convert_scale(const char *scale, char **end, double *sval);
123123

124124
int perf_pmu__caps_parse(struct perf_pmu *pmu);
125125

126+
void perf_pmu__warn_invalid_config(struct perf_pmu *pmu, __u64 config,
127+
char *name);
128+
126129
#endif /* __PMU_H */

tools/perf/util/synthetic-events.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,7 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
424424

425425
while (!io.eof) {
426426
static const char anonstr[] = "//anon";
427-
size_t size;
427+
size_t size, aligned_size;
428428

429429
/* ensure null termination since stack will be reused. */
430430
event->mmap2.filename[0] = '\0';
@@ -484,11 +484,12 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
484484
}
485485

486486
size = strlen(event->mmap2.filename) + 1;
487-
size = PERF_ALIGN(size, sizeof(u64));
487+
aligned_size = PERF_ALIGN(size, sizeof(u64));
488488
event->mmap2.len -= event->mmap.start;
489489
event->mmap2.header.size = (sizeof(event->mmap2) -
490-
(sizeof(event->mmap2.filename) - size));
491-
memset(event->mmap2.filename + size, 0, machine->id_hdr_size);
490+
(sizeof(event->mmap2.filename) - aligned_size));
491+
memset(event->mmap2.filename + size, 0, machine->id_hdr_size +
492+
(aligned_size - size));
492493
event->mmap2.header.size += machine->id_hdr_size;
493494
event->mmap2.pid = tgid;
494495
event->mmap2.tid = pid;
@@ -758,7 +759,7 @@ static int __event__synthesize_thread(union perf_event *comm_event,
758759
for (i = 0; i < n; i++) {
759760
char *end;
760761
pid_t _pid;
761-
bool kernel_thread;
762+
bool kernel_thread = false;
762763

763764
_pid = strtol(dirent[i]->d_name, &end, 10);
764765
if (*end)

0 commit comments

Comments
 (0)