Files
linux/tools/perf/tests/openat-syscall-tp-fields.c
Ian Rogers ab24487aaa perf evlist: Add reference count checking
Now the evlist is reference counted, add reference count checking so
that gets and puts are paired and easy to debug. Reference count
checking is documented here:
https://perfwiki.github.io/main/reference-count-checking/

This large patch is adding accessors to evlist functions and switching
to their use. There was some minor renaming as evlist__mmap is now an
accessor to the mmap variable, and the original evlist__mmap is
renamed to evlist__do_mmap.

Signed-off-by: Ian Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alice Rogers <alice.mei.rogers@gmail.com>
Cc: Dapeng Mi <dapeng1.mi@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@linaro.org>
Cc: Leo Yan <leo.yan@linux.dev>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Richter <tmricht@linux.ibm.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
2026-06-30 10:17:11 -07:00

164 lines
3.7 KiB
C

// SPDX-License-Identifier: GPL-2.0
#include <stdbool.h>
#include <linux/err.h>
#include <linux/string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "evlist.h"
#include "evsel.h"
#include "thread_map.h"
#include "record.h"
#include "tests.h"
#include "debug.h"
#include "util/mmap.h"
#include <errno.h>
#include <perf/mmap.h>
#include "util/sample.h"
#ifndef O_DIRECTORY
#define O_DIRECTORY 00200000
#endif
#ifndef AT_FDCWD
#define AT_FDCWD -100
#endif
static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused,
int subtest __maybe_unused)
{
struct record_opts opts = {
.target = {
.uses_mmap = true,
},
.no_buffering = true,
.freq = 1,
.mmap_pages = 256,
.raw_samples = true,
};
const char *filename = "/etc/passwd";
int flags = O_RDONLY | O_DIRECTORY;
struct evlist *evlist = evlist__new();
struct evsel *evsel;
int ret = TEST_FAIL, err, i, nr_events = 0, nr_polls = 0;
char sbuf[STRERR_BUFSIZE];
if (evlist == NULL) {
pr_debug("%s: evlist__new\n", __func__);
goto out;
}
evsel = evsel__newtp("syscalls", "sys_enter_openat");
if (IS_ERR(evsel)) {
pr_debug("%s: evsel__newtp\n", __func__);
ret = PTR_ERR(evsel) == -EACCES ? TEST_SKIP : TEST_FAIL;
goto out_put_evlist;
}
evlist__add(evlist, evsel);
err = evlist__create_maps(evlist, &opts.target);
if (err < 0) {
pr_debug("%s: evlist__create_maps\n", __func__);
goto out_put_evlist;
}
evsel__config(evsel, &opts, NULL);
perf_thread_map__set_pid(evlist__core(evlist)->threads, 0, getpid());
err = evlist__open(evlist);
if (err < 0) {
pr_debug("perf_evlist__open: %s\n",
str_error_r(errno, sbuf, sizeof(sbuf)));
goto out_put_evlist;
}
err = evlist__do_mmap(evlist, UINT_MAX);
if (err < 0) {
pr_debug("evlist__mmap: %s\n",
str_error_r(errno, sbuf, sizeof(sbuf)));
goto out_put_evlist;
}
evlist__enable(evlist);
/*
* Generate the event:
*/
openat(AT_FDCWD, filename, flags);
while (1) {
int before = nr_events;
for (i = 0; i < evlist__core(evlist)->nr_mmaps; i++) {
union perf_event *event;
struct mmap *md;
md = &evlist__mmap(evlist)[i];
if (perf_mmap__read_init(&md->core) < 0)
continue;
while ((event = perf_mmap__read_event(&md->core)) != NULL) {
const u32 type = event->header.type;
int tp_flags;
struct perf_sample sample;
++nr_events;
if (type != PERF_RECORD_SAMPLE) {
perf_mmap__consume(&md->core);
continue;
}
perf_sample__init(&sample, /*all=*/false);
err = evsel__parse_sample(evsel, event, &sample);
if (err) {
pr_debug("Can't parse sample, err = %d\n", err);
perf_sample__exit(&sample);
goto out_put_evlist;
}
tp_flags = perf_sample__intval(&sample, "flags");
perf_sample__exit(&sample);
/* C library wrapper may set additional flags,
access mode must be unchanged */
if ((tp_flags & O_ACCMODE) != (flags & O_ACCMODE) ||
(tp_flags & flags) != flags) {
pr_debug("%s: Expected flags=%#x, got %#x\n",
__func__, flags, tp_flags);
goto out_put_evlist;
}
goto out_ok;
}
perf_mmap__read_done(&md->core);
}
if (nr_events == before)
evlist__poll(evlist, 10);
if (++nr_polls > 5) {
pr_debug("%s: no events!\n", __func__);
goto out_put_evlist;
}
}
out_ok:
ret = TEST_OK;
out_put_evlist:
evlist__put(evlist);
out:
return ret;
}
static struct test_case tests__syscall_openat_tp_fields[] = {
TEST_CASE_REASON("syscalls:sys_enter_openat event fields",
syscall_openat_tp_fields,
"permissions"),
{ .name = NULL, }
};
struct test_suite suite__syscall_openat_tp_fields = {
.desc = "syscalls:sys_enter_openat event fields",
.test_cases = tests__syscall_openat_tp_fields,
};