mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
perf test: In forked mode add check that fds aren't leaked
When a test is forked no file descriptors should be open, however, parent ones may have been inherited - in particular those of the pipes of other forked child test processes. Add a loop to clean-up/close those file descriptors prior to running the test. At the end of the test assert that no additional file descriptors are present as this would indicate a file descriptor leak. Signed-off-by: Ian Rogers <irogers@google.com> Link: https://lore.kernel.org/r/20250624190326.2038704-6-irogers@google.com Signed-off-by: Namhyung Kim <namhyung@kernel.org>
This commit is contained in:
parent
e793e2c0f1
commit
e9846f5ead
1 changed files with 69 additions and 0 deletions
|
@ -4,6 +4,7 @@
|
||||||
*
|
*
|
||||||
* Builtin regression testing command: ever growing number of sanity tests
|
* Builtin regression testing command: ever growing number of sanity tests
|
||||||
*/
|
*/
|
||||||
|
#include <ctype.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#ifdef HAVE_BACKTRACE_SUPPORT
|
#ifdef HAVE_BACKTRACE_SUPPORT
|
||||||
|
@ -159,6 +160,71 @@ static struct test_workload *workloads[] = {
|
||||||
#define test_suite__for_each_test_case(suite, idx) \
|
#define test_suite__for_each_test_case(suite, idx) \
|
||||||
for (idx = 0; (suite)->test_cases && (suite)->test_cases[idx].name != NULL; idx++)
|
for (idx = 0; (suite)->test_cases && (suite)->test_cases[idx].name != NULL; idx++)
|
||||||
|
|
||||||
|
static void close_parent_fds(void)
|
||||||
|
{
|
||||||
|
DIR *dir = opendir("/proc/self/fd");
|
||||||
|
struct dirent *ent;
|
||||||
|
|
||||||
|
while ((ent = readdir(dir))) {
|
||||||
|
char *end;
|
||||||
|
long fd;
|
||||||
|
|
||||||
|
if (ent->d_type != DT_LNK)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!isdigit(ent->d_name[0]))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
fd = strtol(ent->d_name, &end, 10);
|
||||||
|
if (*end)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (fd <= 3 || fd == dirfd(dir))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
closedir(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void check_leaks(void)
|
||||||
|
{
|
||||||
|
DIR *dir = opendir("/proc/self/fd");
|
||||||
|
struct dirent *ent;
|
||||||
|
int leaks = 0;
|
||||||
|
|
||||||
|
while ((ent = readdir(dir))) {
|
||||||
|
char path[PATH_MAX];
|
||||||
|
char *end;
|
||||||
|
long fd;
|
||||||
|
ssize_t len;
|
||||||
|
|
||||||
|
if (ent->d_type != DT_LNK)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!isdigit(ent->d_name[0]))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
fd = strtol(ent->d_name, &end, 10);
|
||||||
|
if (*end)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (fd <= 3 || fd == dirfd(dir))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
leaks++;
|
||||||
|
len = readlinkat(dirfd(dir), ent->d_name, path, sizeof(path));
|
||||||
|
if (len > 0 && (size_t)len < sizeof(path))
|
||||||
|
path[len] = '\0';
|
||||||
|
else
|
||||||
|
strncpy(path, ent->d_name, sizeof(path));
|
||||||
|
pr_err("Leak of file descriptor %s that opened: '%s'\n", ent->d_name, path);
|
||||||
|
}
|
||||||
|
closedir(dir);
|
||||||
|
if (leaks)
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
static int test_suite__num_test_cases(const struct test_suite *t)
|
static int test_suite__num_test_cases(const struct test_suite *t)
|
||||||
{
|
{
|
||||||
int num;
|
int num;
|
||||||
|
@ -256,6 +322,8 @@ static int run_test_child(struct child_process *process)
|
||||||
struct child_test *child = container_of(process, struct child_test, process);
|
struct child_test *child = container_of(process, struct child_test, process);
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
close_parent_fds();
|
||||||
|
|
||||||
err = sigsetjmp(run_test_jmp_buf, 1);
|
err = sigsetjmp(run_test_jmp_buf, 1);
|
||||||
if (err) {
|
if (err) {
|
||||||
/* Received signal. */
|
/* Received signal. */
|
||||||
|
@ -271,6 +339,7 @@ static int run_test_child(struct child_process *process)
|
||||||
err = test_function(child->test, child->test_case_num)(child->test, child->test_case_num);
|
err = test_function(child->test, child->test_case_num)(child->test, child->test_case_num);
|
||||||
pr_debug("---- end(%d) ----\n", err);
|
pr_debug("---- end(%d) ----\n", err);
|
||||||
|
|
||||||
|
check_leaks();
|
||||||
err_out:
|
err_out:
|
||||||
fflush(NULL);
|
fflush(NULL);
|
||||||
for (size_t i = 0; i < ARRAY_SIZE(signals); i++)
|
for (size_t i = 0; i < ARRAY_SIZE(signals); i++)
|
||||||
|
|
Loading…
Add table
Reference in a new issue