Skip to content

Commit 783b8f0

Browse files
anakryikoAlexei Starovoitov
authored andcommitted
libbpf: Don't attach perf_buffer to offline/missing CPUs
It's quite common on some systems to have more CPUs enlisted as "possible", than there are (and could ever be) present/online CPUs. In such cases, perf_buffer creationg will fail due to inability to create perf event on missing CPU with error like this: libbpf: failed to open perf buffer event on cpu #16: No such device This patch fixes the logic of perf_buffer__new() to ignore CPUs that are missing or currently offline. In rare cases where user explicitly listed specific CPUs to connect to, behavior is unchanged: libbpf will try to open perf event buffer on specified CPU(s) anyways. Fixes: fb84b82 ("libbpf: add perf buffer API") Signed-off-by: Andrii Nakryiko <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent 65bc4c4 commit 783b8f0

File tree

1 file changed

+25
-7
lines changed

1 file changed

+25
-7
lines changed

tools/lib/bpf/libbpf.c

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5946,7 +5946,7 @@ struct perf_buffer {
59465946
size_t mmap_size;
59475947
struct perf_cpu_buf **cpu_bufs;
59485948
struct epoll_event *events;
5949-
int cpu_cnt;
5949+
int cpu_cnt; /* number of allocated CPU buffers */
59505950
int epoll_fd; /* perf event FD */
59515951
int map_fd; /* BPF_MAP_TYPE_PERF_EVENT_ARRAY BPF map FD */
59525952
};
@@ -6080,11 +6080,13 @@ perf_buffer__new_raw(int map_fd, size_t page_cnt,
60806080
static struct perf_buffer *__perf_buffer__new(int map_fd, size_t page_cnt,
60816081
struct perf_buffer_params *p)
60826082
{
6083+
const char *online_cpus_file = "/sys/devices/system/cpu/online";
60836084
struct bpf_map_info map = {};
60846085
char msg[STRERR_BUFSIZE];
60856086
struct perf_buffer *pb;
6087+
bool *online = NULL;
60866088
__u32 map_info_len;
6087-
int err, i;
6089+
int err, i, j, n;
60886090

60896091
if (page_cnt & (page_cnt - 1)) {
60906092
pr_warn("page count should be power of two, but is %zu\n",
@@ -6153,20 +6155,32 @@ static struct perf_buffer *__perf_buffer__new(int map_fd, size_t page_cnt,
61536155
goto error;
61546156
}
61556157

6156-
for (i = 0; i < pb->cpu_cnt; i++) {
6158+
err = parse_cpu_mask_file(online_cpus_file, &online, &n);
6159+
if (err) {
6160+
pr_warn("failed to get online CPU mask: %d\n", err);
6161+
goto error;
6162+
}
6163+
6164+
for (i = 0, j = 0; i < pb->cpu_cnt; i++) {
61576165
struct perf_cpu_buf *cpu_buf;
61586166
int cpu, map_key;
61596167

61606168
cpu = p->cpu_cnt > 0 ? p->cpus[i] : i;
61616169
map_key = p->cpu_cnt > 0 ? p->map_keys[i] : i;
61626170

6171+
/* in case user didn't explicitly requested particular CPUs to
6172+
* be attached to, skip offline/not present CPUs
6173+
*/
6174+
if (p->cpu_cnt <= 0 && (cpu >= n || !online[cpu]))
6175+
continue;
6176+
61636177
cpu_buf = perf_buffer__open_cpu_buf(pb, p->attr, cpu, map_key);
61646178
if (IS_ERR(cpu_buf)) {
61656179
err = PTR_ERR(cpu_buf);
61666180
goto error;
61676181
}
61686182

6169-
pb->cpu_bufs[i] = cpu_buf;
6183+
pb->cpu_bufs[j] = cpu_buf;
61706184

61716185
err = bpf_map_update_elem(pb->map_fd, &map_key,
61726186
&cpu_buf->fd, 0);
@@ -6178,21 +6192,25 @@ static struct perf_buffer *__perf_buffer__new(int map_fd, size_t page_cnt,
61786192
goto error;
61796193
}
61806194

6181-
pb->events[i].events = EPOLLIN;
6182-
pb->events[i].data.ptr = cpu_buf;
6195+
pb->events[j].events = EPOLLIN;
6196+
pb->events[j].data.ptr = cpu_buf;
61836197
if (epoll_ctl(pb->epoll_fd, EPOLL_CTL_ADD, cpu_buf->fd,
6184-
&pb->events[i]) < 0) {
6198+
&pb->events[j]) < 0) {
61856199
err = -errno;
61866200
pr_warn("failed to epoll_ctl cpu #%d perf FD %d: %s\n",
61876201
cpu, cpu_buf->fd,
61886202
libbpf_strerror_r(err, msg, sizeof(msg)));
61896203
goto error;
61906204
}
6205+
j++;
61916206
}
6207+
pb->cpu_cnt = j;
6208+
free(online);
61926209

61936210
return pb;
61946211

61956212
error:
6213+
free(online);
61966214
if (pb)
61976215
perf_buffer__free(pb);
61986216
return ERR_PTR(err);

0 commit comments

Comments
 (0)