mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 14:53:58 -04:00
The build_id selftest occasionally fails because MADV_PAGEOUT does not guarantee the immediate eviction of the page. The test assumes eviction happens and proceeds without verifying that the page was actually reclaimed, leading to false test failures. Fix the test by retrying the page-out sequence until eviction is successful, instead of relying on a single MADV_PAGEOUT attempt. Signed-off-by: Gregory Bell <grbell@redhat.com> Link: https://lore.kernel.org/r/038bd27c69dd3a16958894fcb19e4fb6fbfe317e.1771338492.git.grbell@redhat.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
150 lines
4.3 KiB
C
150 lines
4.3 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <sys/mman.h>
|
|
#include <unistd.h>
|
|
#include <sdt.h>
|
|
|
|
#ifndef MADV_POPULATE_READ
|
|
#define MADV_POPULATE_READ 22
|
|
#endif
|
|
|
|
#ifndef MADV_PAGEOUT
|
|
#define MADV_PAGEOUT 21
|
|
#endif
|
|
|
|
int __attribute__((weak)) uprobe(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
#define __PASTE(a, b) a##b
|
|
#define PASTE(a, b) __PASTE(a, b)
|
|
|
|
#define NAME(name, idx) PASTE(name, idx)
|
|
|
|
#define DEF(name, idx) int __attribute__((weak)) NAME(name, idx)(void) { return 0; }
|
|
#define CALL(name, idx) NAME(name, idx)();
|
|
|
|
#define F(body, name, idx) body(name, idx)
|
|
|
|
#define F10(body, name, idx) \
|
|
F(body, PASTE(name, idx), 0) F(body, PASTE(name, idx), 1) F(body, PASTE(name, idx), 2) \
|
|
F(body, PASTE(name, idx), 3) F(body, PASTE(name, idx), 4) F(body, PASTE(name, idx), 5) \
|
|
F(body, PASTE(name, idx), 6) F(body, PASTE(name, idx), 7) F(body, PASTE(name, idx), 8) \
|
|
F(body, PASTE(name, idx), 9)
|
|
|
|
#define F100(body, name, idx) \
|
|
F10(body, PASTE(name, idx), 0) F10(body, PASTE(name, idx), 1) F10(body, PASTE(name, idx), 2) \
|
|
F10(body, PASTE(name, idx), 3) F10(body, PASTE(name, idx), 4) F10(body, PASTE(name, idx), 5) \
|
|
F10(body, PASTE(name, idx), 6) F10(body, PASTE(name, idx), 7) F10(body, PASTE(name, idx), 8) \
|
|
F10(body, PASTE(name, idx), 9)
|
|
|
|
#define F1000(body, name, idx) \
|
|
F100(body, PASTE(name, idx), 0) F100(body, PASTE(name, idx), 1) F100(body, PASTE(name, idx), 2) \
|
|
F100(body, PASTE(name, idx), 3) F100(body, PASTE(name, idx), 4) F100(body, PASTE(name, idx), 5) \
|
|
F100(body, PASTE(name, idx), 6) F100(body, PASTE(name, idx), 7) F100(body, PASTE(name, idx), 8) \
|
|
F100(body, PASTE(name, idx), 9)
|
|
|
|
#define F10000(body, name, idx) \
|
|
F1000(body, PASTE(name, idx), 0) F1000(body, PASTE(name, idx), 1) F1000(body, PASTE(name, idx), 2) \
|
|
F1000(body, PASTE(name, idx), 3) F1000(body, PASTE(name, idx), 4) F1000(body, PASTE(name, idx), 5) \
|
|
F1000(body, PASTE(name, idx), 6) F1000(body, PASTE(name, idx), 7) F1000(body, PASTE(name, idx), 8) \
|
|
F1000(body, PASTE(name, idx), 9)
|
|
|
|
F10000(DEF, uprobe_multi_func_, 0)
|
|
F10000(DEF, uprobe_multi_func_, 1)
|
|
F10000(DEF, uprobe_multi_func_, 2)
|
|
F10000(DEF, uprobe_multi_func_, 3)
|
|
F10000(DEF, uprobe_multi_func_, 4)
|
|
|
|
static int bench(void)
|
|
{
|
|
F10000(CALL, uprobe_multi_func_, 0)
|
|
F10000(CALL, uprobe_multi_func_, 1)
|
|
F10000(CALL, uprobe_multi_func_, 2)
|
|
F10000(CALL, uprobe_multi_func_, 3)
|
|
F10000(CALL, uprobe_multi_func_, 4)
|
|
return 0;
|
|
}
|
|
|
|
#define PROBE STAP_PROBE(test, usdt);
|
|
|
|
#define PROBE10 PROBE PROBE PROBE PROBE PROBE \
|
|
PROBE PROBE PROBE PROBE PROBE
|
|
#define PROBE100 PROBE10 PROBE10 PROBE10 PROBE10 PROBE10 \
|
|
PROBE10 PROBE10 PROBE10 PROBE10 PROBE10
|
|
#define PROBE1000 PROBE100 PROBE100 PROBE100 PROBE100 PROBE100 \
|
|
PROBE100 PROBE100 PROBE100 PROBE100 PROBE100
|
|
#define PROBE10000 PROBE1000 PROBE1000 PROBE1000 PROBE1000 PROBE1000 \
|
|
PROBE1000 PROBE1000 PROBE1000 PROBE1000 PROBE1000
|
|
|
|
static int usdt(void)
|
|
{
|
|
PROBE10000
|
|
PROBE10000
|
|
PROBE10000
|
|
PROBE10000
|
|
PROBE10000
|
|
return 0;
|
|
}
|
|
|
|
extern char build_id_start[];
|
|
extern char build_id_end[];
|
|
|
|
int __attribute__((weak)) trigger_uprobe(bool build_id_resident)
|
|
{
|
|
int page_sz = sysconf(_SC_PAGESIZE);
|
|
void *addr;
|
|
|
|
unsigned char vec[1];
|
|
int poll = 0;
|
|
|
|
/* page-align build ID start */
|
|
addr = (void *)((uintptr_t)&build_id_start & ~(page_sz - 1));
|
|
|
|
/* to guarantee MADV_PAGEOUT work reliably, we need to ensure that
|
|
* memory range is mapped into current process, so we unconditionally
|
|
* do MADV_POPULATE_READ, and then MADV_PAGEOUT, if necessary
|
|
*/
|
|
madvise(addr, page_sz, MADV_POPULATE_READ);
|
|
if (!build_id_resident) {
|
|
do {
|
|
madvise(addr, page_sz, MADV_PAGEOUT);
|
|
/* check if page has been evicted */
|
|
mincore(addr, page_sz, vec);
|
|
if (!(vec[0] & 1))
|
|
break;
|
|
/* if page is still resident re-attempt MADV_POPULATE_READ/MADV_PAGEOUT */
|
|
madvise(addr, page_sz, MADV_POPULATE_READ);
|
|
poll++;
|
|
usleep(100);
|
|
} while (poll < 500);
|
|
}
|
|
(void)uprobe();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
if (argc != 2)
|
|
goto error;
|
|
|
|
if (!strcmp("bench", argv[1]))
|
|
return bench();
|
|
if (!strcmp("usdt", argv[1]))
|
|
return usdt();
|
|
if (!strcmp("uprobe-paged-out", argv[1]))
|
|
return trigger_uprobe(false /* page-out build ID */);
|
|
if (!strcmp("uprobe-paged-in", argv[1]))
|
|
return trigger_uprobe(true /* page-in build ID */);
|
|
|
|
error:
|
|
fprintf(stderr, "usage: %s <bench|usdt>\n", argv[0]);
|
|
return -1;
|
|
}
|