Re: [PATCH v7 6/6] kselftest: alloc_tag: extend the allocinfo ioctl kselftest
From: Suren Baghdasaryan
Date: Wed Jul 08 2026 - 12:53:47 EST
On Tue, Jul 7, 2026 at 12:59 PM Abhishek Bapat <abhishekbapat@xxxxxxxxxx> wrote:
>
> On Mon, Jul 6, 2026 at 8:28 PM Hao Ge <hao.ge@xxxxxxxxx> wrote:
> >
> > Hi Abhishek
> >
> >
> > On 2026/7/7 02:25, Abhishek Bapat 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>
> > > ---
> > > .../alloc_tag/allocinfo_ioctl_test.c | 216 +++++++++++++++++-
> > > 1 file changed, 215 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 9ce7b53078b1..092348097204 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>
> > > @@ -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_FAIL;
> > > + 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_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_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_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 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();
> > > }
> >
> >
> > https://sashiko.dev/#/patchset/cover.1783361692.git.abhishekbapat%40google.com
> >
> > Sashiko is really strict, but its warnings are legitimate. I ran the
> > test program on a kernel built without
> >
> > CONFIG_MEM_ALLOC_PROFILING, and here are the results:
> >
> >
> > [root@localhost alloc_tag]# ./allocinfo_ioctl_test
> > 1..4
> > # Failed to open /proc/allocinfo for reading
> > # Error retrieving entries from /proc/allocinfo
> > ok 1 # SKIP Skipping test_filename_filter
> > # Failed to open /proc/allocinfo for reading
> > # Error retrieving entries from /proc/allocinfo
> > ok 2 # SKIP Skipping test_function_filter
> > # Failed to open /proc/allocinfo: No such file or directory
> > not ok 3 test_size_filter
> > # Failed to open /proc/allocinfo for reading
> > # Error retrieving entries from /proc/allocinfo
> > not ok 4 test_lineno_filter
> > # 2 skipped test(s) detected. Consider enabling relevant config options
> > to improve coverage.
> > # Totals: pass:0 fail:2 xfail:0 xpass:0 skip:2 error:0
> > [root@localhost alloc_tag]#
> >
> >
> > Looking at the test log above, some tests that ought to be skipped are
> > flagged as failures.
> >
> > Would it make sense for us to go through all relevant test cases in the
> > codebase,
> >
> > and check if we've missed any logic to skip tests when /proc/allocinfo
> > is missing
> >
> > due to CONFIG_MEM_ALLOC_PROFILING being disabled?
> >
> >
> > BTW, when merging this series into the latest mm-new branch, there will
> > be a minor header file conflict.
> >
> > This is because the series at
> > https://lore.kernel.org/all/20260703-alloc-trylock-v5-15-c87b714e19d3@xxxxxxxxxx
> > was merged ahead of this change.
> >
> > We might want to consider rebasing this series to resolve the header
> > conflict.
> >
> >
> > Thanks
> >
> > Best Regards
> >
> > Hao
> >
> >
>
> Hi Hao,
>
> Thanks for bringing this up, I discussed it with Andrew as well and
> will fix it in the next version. Waiting for Suren's comments before
> posting another version.
I went over the series and it LGTM. Please post the new version and
please use "git format-patch --base=auto" when formatting the patches
to send so that we know which branch the patchset was based on.
Thanks,
Suren.
>
> Thanks!