mirror of
https://github.com/torvalds/linux.git
synced 2026-09-12 20:53:03 +02:00
kselftest: alloc_tag: extend the allocinfo ioctl kselftest
Add the following 2 scenarios to the allocinfo ioctl kselftest: 1. Validate size based filtering 2. Validate lineno based filtering The first test uses "do_init_module" as the candidate function for the test. This is because the associated site will only allocate memory when a kernel module is loaded. The return value of get_content_id() changes every time modules are loaded or unloaded. Hence, as long as get_content_id() values at the start and the end of the test are the same, the memory allocated by the do_init_module call site should also remain the same. Consequently, the test can assume consistency between the value returned by the ioctl and the procfs resulting in less flakiness. Link: https://lore.kernel.org/e5171926b48802531284c1cb5f04734017141341.1783532853.git.abhishekbapat@google.com Signed-off-by: Abhishek Bapat <abhishekbapat@google.com> Tested-by: Hao Ge <hao.ge@linux.dev> Acked-by: Hao Ge <hao.ge@linux.dev> Cc: Jonathan Corbet <corbet@lwn.net> Cc: Kent Overstreet <kent.overstreet@linux.dev> Cc: Sourav Panda <souravpanda@google.com> Cc: Suren Baghdasaryan <surenb@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
parent
2f252a7a6c
commit
923690d809
|
|
@ -5,6 +5,7 @@
|
|||
* Copyright (C) 2026 Google, Inc.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
|
@ -312,11 +313,212 @@ static int test_function_filter(void)
|
|||
return run_filter_test(&filter);
|
||||
}
|
||||
|
||||
static int test_size_filter(void)
|
||||
{
|
||||
int fd;
|
||||
struct allocinfo_tag_data_vec *tags = malloc(sizeof(*tags));
|
||||
struct allocinfo_tag_data_vec *procfs_entries = malloc(sizeof(*procfs_entries));
|
||||
struct allocinfo_filter filter;
|
||||
int ret = KSFT_PASS;
|
||||
__u64 target_size, i, pos;
|
||||
struct allocinfo_tag_data *found_tag = NULL;
|
||||
const char *target_function = "do_init_module";
|
||||
struct allocinfo_content_id start_cont_id, end_cont_id;
|
||||
int retry = 0;
|
||||
const int max_retries = 10;
|
||||
|
||||
if (!tags || !procfs_entries) {
|
||||
ksft_print_msg("Memory allocation failed.\n");
|
||||
ret = KSFT_FAIL;
|
||||
goto freemem;
|
||||
}
|
||||
|
||||
fd = open(ALLOCINFO_PROC, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
ksft_print_msg("Failed to open " ALLOCINFO_PROC ": %s\n", strerror(errno));
|
||||
ret = KSFT_SKIP;
|
||||
goto freemem;
|
||||
}
|
||||
|
||||
do {
|
||||
found_tag = NULL;
|
||||
pos = 0;
|
||||
|
||||
if (__allocinfo_get_content_id(fd, &start_cont_id)) {
|
||||
ksft_print_msg("allocinfo_get_content_id failed\n");
|
||||
ret = KSFT_FAIL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
memset(&filter, 0, sizeof(filter));
|
||||
filter.mask |= ALLOCINFO_FILTER_MASK_FUNCTION;
|
||||
strncpy(filter.fields.function, target_function, ALLOCINFO_STR_SIZE);
|
||||
|
||||
if (get_filtered_procfs_entries(procfs_entries, &filter)) {
|
||||
ksft_print_msg("Error retrieving entries from " ALLOCINFO_PROC "\n");
|
||||
ret = KSFT_SKIP;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (procfs_entries->count == 0) {
|
||||
ksft_print_msg("Function %s not found in procfs\n", target_function);
|
||||
ret = KSFT_SKIP;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
target_size = procfs_entries->tag[0].counter.bytes;
|
||||
|
||||
memset(&filter, 0, sizeof(filter));
|
||||
filter.mask |= ALLOCINFO_FILTER_MASK_MIN_SIZE | ALLOCINFO_FILTER_MASK_MAX_SIZE;
|
||||
filter.min_size = target_size;
|
||||
filter.max_size = target_size;
|
||||
|
||||
while (1) {
|
||||
struct allocinfo_get_at get_at_params;
|
||||
|
||||
memset(&get_at_params, 0, sizeof(get_at_params));
|
||||
memcpy(&get_at_params.filter, &filter, sizeof(filter));
|
||||
get_at_params.pos = pos;
|
||||
|
||||
if (__allocinfo_get_at(fd, &get_at_params))
|
||||
break;
|
||||
|
||||
tags->count = 0;
|
||||
memcpy(&tags->tag[tags->count++], &get_at_params.data,
|
||||
sizeof(get_at_params.data));
|
||||
|
||||
while (tags->count < VEC_MAX_ENTRIES &&
|
||||
__allocinfo_get_next(fd, &tags->tag[tags->count]) == 0)
|
||||
tags->count++;
|
||||
|
||||
for (i = 0; i < tags->count; i++) {
|
||||
if (strcmp(tags->tag[i].tag.function, target_function) == 0) {
|
||||
found_tag = &tags->tag[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found_tag || tags->count < VEC_MAX_ENTRIES)
|
||||
break;
|
||||
|
||||
pos += tags->count;
|
||||
}
|
||||
|
||||
if (__allocinfo_get_content_id(fd, &end_cont_id)) {
|
||||
ksft_print_msg("allocinfo_get_content_id failed\n");
|
||||
ret = KSFT_FAIL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (start_cont_id.id == end_cont_id.id)
|
||||
break;
|
||||
|
||||
ksft_print_msg("Module load detected during size verification, retrying...\n");
|
||||
} while (retry++ < max_retries);
|
||||
|
||||
if (start_cont_id.id == end_cont_id.id && !found_tag) {
|
||||
ksft_print_msg("Entry with function %s not found in IOCTL results\n",
|
||||
target_function);
|
||||
ret = KSFT_FAIL;
|
||||
} else if (start_cont_id.id != end_cont_id.id) {
|
||||
ksft_print_msg("Failed to match content_ids for procfs and IOCTL, skipping...\n");
|
||||
ret = KSFT_SKIP;
|
||||
} else if (found_tag && found_tag->counter.bytes != target_size) {
|
||||
ksft_print_msg("IOCTL entry size %llu does not match target size %llu\n",
|
||||
found_tag->counter.bytes, target_size);
|
||||
ret = KSFT_FAIL;
|
||||
}
|
||||
|
||||
exit:
|
||||
close(fd);
|
||||
freemem:
|
||||
free(tags);
|
||||
free(procfs_entries);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int test_lineno_filter(void)
|
||||
{
|
||||
struct allocinfo_tag_data_vec *tags = malloc(sizeof(*tags));
|
||||
struct allocinfo_tag_data_vec *procfs_entries = malloc(sizeof(*procfs_entries));
|
||||
struct allocinfo_filter filter;
|
||||
enum ioctl_ret ioctl_status;
|
||||
int ret = KSFT_PASS;
|
||||
__u64 target_lineno, i;
|
||||
struct allocinfo_tag_data *target_tag;
|
||||
bool found = false;
|
||||
|
||||
if (!tags || !procfs_entries) {
|
||||
ksft_print_msg("Memory allocation failed.\n");
|
||||
ret = KSFT_FAIL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
memset(&filter, 0, sizeof(filter));
|
||||
|
||||
if (get_filtered_procfs_entries(procfs_entries, &filter)) {
|
||||
ksft_print_msg("Error retrieving entries from " ALLOCINFO_PROC "\n");
|
||||
ret = KSFT_SKIP;
|
||||
goto exit;
|
||||
}
|
||||
if (procfs_entries->count == 0) {
|
||||
ksft_print_msg("Could not retrieve procfs entries\n");
|
||||
ret = KSFT_SKIP;
|
||||
goto exit;
|
||||
}
|
||||
/*
|
||||
* We depend on the procfs results to determine the line number for the filter before
|
||||
* making the ioctl query. Hence, we cannot reuse run_filter_test here.
|
||||
*/
|
||||
target_tag = &procfs_entries->tag[0];
|
||||
target_lineno = target_tag->tag.lineno;
|
||||
|
||||
filter.mask |= ALLOCINFO_FILTER_MASK_LINENO;
|
||||
filter.fields.lineno = target_lineno;
|
||||
|
||||
ioctl_status = get_filtered_ioctl_entries(tags, &filter, 0);
|
||||
if (ioctl_status == IOCTL_INVALID_DATA) {
|
||||
ksft_print_msg("Trouble retrieving valid IOCTL entries, skipping.\n");
|
||||
ret = KSFT_SKIP;
|
||||
goto exit;
|
||||
}
|
||||
if (ioctl_status == IOCTL_FAILURE) {
|
||||
ksft_print_msg("Error retrieving IOCTL entries.\n");
|
||||
ret = KSFT_FAIL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
for (i = 0; i < tags->count; i++) {
|
||||
if (tags->tag[i].tag.lineno != target_lineno) {
|
||||
ksft_print_msg("IOCTL entry %llu has incorrect lineno %llu.\n",
|
||||
i, tags->tag[i].tag.lineno);
|
||||
ret = KSFT_FAIL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (strncmp(tags->tag[i].tag.function, target_tag->tag.function,
|
||||
ALLOCINFO_STR_SIZE) == 0 &&
|
||||
strncmp(tags->tag[i].tag.filename, target_tag->tag.filename,
|
||||
ALLOCINFO_STR_SIZE) == 0)
|
||||
found = true;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
ksft_print_msg("Original procfs entry not found in IOCTL lineno filter results.\n");
|
||||
ret = KSFT_FAIL;
|
||||
}
|
||||
|
||||
exit:
|
||||
free(tags);
|
||||
free(procfs_entries);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ret;
|
||||
|
||||
ksft_set_plan(2);
|
||||
ksft_set_plan(4);
|
||||
|
||||
ret = test_filename_filter();
|
||||
if (ret == KSFT_SKIP)
|
||||
|
|
@ -330,5 +532,17 @@ int main(int argc, char *argv[])
|
|||
else
|
||||
ksft_test_result(ret == KSFT_PASS, "test_function_filter\n");
|
||||
|
||||
ret = test_size_filter();
|
||||
if (ret == KSFT_SKIP)
|
||||
ksft_test_result_skip("Skipping test_size_filter\n");
|
||||
else
|
||||
ksft_test_result(ret == KSFT_PASS, "test_size_filter\n");
|
||||
|
||||
ret = test_lineno_filter();
|
||||
if (ret == KSFT_SKIP)
|
||||
ksft_test_result_skip("Skipping test_lineno_filter\n");
|
||||
else
|
||||
ksft_test_result(ret == KSFT_PASS, "test_lineno_filter\n");
|
||||
|
||||
ksft_finished();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user