Re: [PATCH v6 6/6] kselftest: alloc_tag: extend the allocinfo ioctl kselftest
From: Suren Baghdasaryan
Date: Sat Jun 20 2026 - 20:31:58 EST
On Thu, Jun 18, 2026 at 10:36 AM Abhishek Bapat
<abhishekbapat@xxxxxxxxxx> wrote:
>
> 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.
>
> Signed-off-by: Abhishek Bapat <abhishekbapat@xxxxxxxxxx>
Couple of improvement suggestions, but otherwise LGTM.
> ---
> .../alloc_tag/allocinfo_ioctl_test.c | 198 +++++++++++++++++-
> 1 file changed, 197 insertions(+), 1 deletion(-)
>
> diff --git a/tools/testing/selftests/alloc_tag/allocinfo_ioctl_test.c b/tools/testing/selftests/alloc_tag/allocinfo_ioctl_test.c
> index 1ae0291f2245..50755a45d3fe 100644
> --- a/tools/testing/selftests/alloc_tag/allocinfo_ioctl_test.c
> +++ b/tools/testing/selftests/alloc_tag/allocinfo_ioctl_test.c
> @@ -5,6 +5,7 @@
> * Copyright (C) 2026 Google, Inc.
> */
>
> +#include <errno.h>
> #include <fcntl.h>
> #include <stdio.h>
> #include <stdlib.h>
> @@ -313,11 +314,194 @@ 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;
> + bool found;
> + 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_FAIL;
> + goto freemem;
> + }
> +
> + do {
> + found = false;
> + 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_FAIL;
> + 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 = true;
> + break;
> + }
> + }
> +
> + if (found || 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) {
> + 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;
> + }
I know we found the tag filtering by target_size and this might be
seen as unnecessary, but let's take one more final verification step
and check that tag.counter.bytes of the tag we found indeed equals
target_size. For that check you can replace "found" boolean with
"found_tag" pointer and the rest becomes trivial.
> +
> +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;
> +
> + 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_FAIL;
> + 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 result of procfs entries to create the ioctl_filter. Hence we
> + * cannot recycle the run_filter_test function here.
> + */
The above comment is a bit unclear. What do you mean by "recycle the
run_filter_test function"? Also there is no variable called
ioctl_filter. I would change it to "filter later used in ioctl".
> + target_lineno = procfs_entries->tag[0].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;
> + }
You can improve the test to also check if the filtered collection you
retrieved contains the original tag you used to record target_lineno.
> + }
> +
> +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)
> @@ -331,5 +515,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();
> }
> --
> 2.55.0.rc0.786.g65d90a0328-goog
>