From: Hao Ge <hao.ge@linux.dev>
To: Abhishek Bapat <abhishekbapat@google.com>
Cc: Shuah Khan <skhan@linuxfoundation.org>,
Jonathan Corbet <corbet@lwn.net>,
linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-mm@kvack.org, Sourav Panda <souravpanda@google.com>,
Suren Baghdasaryan <surenb@google.com>,
Andrew Morton <akpm@linux-foundation.org>,
Kent Overstreet <kent.overstreet@linux.dev>
Subject: Re: [PATCH v7 6/6] kselftest: alloc_tag: extend the allocinfo ioctl kselftest
Date: Tue, 7 Jul 2026 11:27:40 +0800 [thread overview]
Message-ID: <4cc47988-49b3-4b73-90ed-a0a16a56a8dc@linux.dev> (raw)
In-Reply-To: <f6bd1ff0257987dbb7512f93595eaa6962c6153b.1783361692.git.abhishekbapat@google.com>
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@google.com>
> ---
> .../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@google.com
was merged ahead of this change.
We might want to consider rebasing this series to resolve the header
conflict.
Thanks
Best Regards
Hao
prev parent reply other threads:[~2026-07-07 3:28 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-06 18:25 [PATCH v7 0/6] alloc_tag: introduce IOCTL-based filtering for MAP Abhishek Bapat
2026-07-06 18:25 ` [PATCH v7 1/6] alloc_tag: add ioctl to /proc/allocinfo Abhishek Bapat
2026-07-06 18:25 ` [PATCH v7 2/6] alloc_tag: add ioctl filters " Abhishek Bapat
2026-07-06 18:25 ` [PATCH v7 3/6] alloc_tag: add size-based filtering to ioctl Abhishek Bapat
2026-07-06 18:25 ` [PATCH v7 4/6] alloc_tag: add accuracy based " Abhishek Bapat
2026-07-06 18:25 ` [PATCH v7 5/6] kselftest: alloc_tag: add kselftest for ioctl interface Abhishek Bapat
2026-07-06 18:25 ` [PATCH v7 6/6] kselftest: alloc_tag: extend the allocinfo ioctl kselftest Abhishek Bapat
2026-07-07 3:27 ` Hao Ge [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4cc47988-49b3-4b73-90ed-a0a16a56a8dc@linux.dev \
--to=hao.ge@linux.dev \
--cc=abhishekbapat@google.com \
--cc=akpm@linux-foundation.org \
--cc=corbet@lwn.net \
--cc=kent.overstreet@linux.dev \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=skhan@linuxfoundation.org \
--cc=souravpanda@google.com \
--cc=surenb@google.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox