[PATCH 4/4] alloc_tag: add a test for trace state toggle and filtering
From: Abhishek Bapat
Date: Mon Sep 21 2026 - 17:27:50 EST
Following the introduction of the ALLOCINFO_IOC_TOGGLE_TRACE IOCTL and
ALLOCINFO_FILTER_MASK_TRACE_ON filters for selective memory allocation
tracing, update the kselftests to validate this behaviour.
Introduce `test_tracing_toggle_and_filter`, which validates the
architecture by:
1. Dynamically toggling trace execution ON for a designated allocation.
2. Evaluating that the TRACE_ON filter precisely isolates the active
target across the IOCTL API.
3. Verifying that the targeted allocation correctly reports its
`trace_on` metadata state as 1.
4. Toggling trace execution OFF for the same allocation.
Signed-off-by: Abhishek Bapat <abhishekbapat@xxxxxxxxxx>
---
.../alloc_tag/allocinfo_ioctl_test.c | 111 +++++++++++++++++-
1 file changed, 108 insertions(+), 3 deletions(-)
diff --git a/tools/testing/selftests/alloc_tag/allocinfo_ioctl_test.c b/tools/testing/selftests/alloc_tag/allocinfo_ioctl_test.c
index 74fd64b2370c..3ef7a12fe35b 100644
--- a/tools/testing/selftests/alloc_tag/allocinfo_ioctl_test.c
+++ b/tools/testing/selftests/alloc_tag/allocinfo_ioctl_test.c
@@ -48,6 +48,11 @@ static inline int __allocinfo_get_next(int dev_fd, struct allocinfo_tag_data *pa
return ioctl(dev_fd, ALLOCINFO_IOC_GET_NEXT, params);
}
+static inline int __allocinfo_toggle_trace(int dev_fd, struct allocinfo_toggle_traces *params)
+{
+ return ioctl(dev_fd, ALLOCINFO_IOC_TOGGLE_TRACE, params);
+}
+
static bool match_entry(const struct allocinfo_tag_data *procfs_entry,
const struct allocinfo_tag_data *tag_data,
bool match_bytes, bool match_calls, bool match_lineno,
@@ -289,6 +294,8 @@ static int run_filter_test(const struct allocinfo_filter *filter)
return ret;
}
+static const char *target_test_function = "dup_mm";
+
static int test_filename_filter(void)
{
struct allocinfo_filter filter;
@@ -304,11 +311,10 @@ static int test_filename_filter(void)
static int test_function_filter(void)
{
struct allocinfo_filter filter;
- const char *target_function = "dup_mm";
memset(&filter, 0, sizeof(filter));
filter.mask |= ALLOCINFO_FILTER_MASK_FUNCTION;
- strncpy(filter.fields.function, target_function, ALLOCINFO_STR_SIZE);
+ strncpy(filter.fields.function, target_test_function, ALLOCINFO_STR_SIZE);
return run_filter_test(&filter);
}
@@ -514,11 +520,104 @@ static int test_lineno_filter(void)
return ret;
}
+static enum ioctl_ret toggle_trace(struct allocinfo_tag *target_tag,
+ bool enable)
+{
+ int fd;
+ struct allocinfo_toggle_traces toggle_params;
+
+ fd = open(ALLOCINFO_PROC, O_RDONLY);
+ if (fd < 0) {
+ ksft_print_msg("Failed to open " ALLOCINFO_PROC ": %s\n", strerror(errno));
+ return IOCTL_FAILURE;
+ }
+
+ memset(&toggle_params, 0, sizeof(toggle_params));
+ toggle_params.fields = *target_tag;
+ toggle_params.enable = enable;
+
+ if (__allocinfo_toggle_trace(fd, &toggle_params)) {
+ close(fd);
+ return IOCTL_FAILURE;
+ }
+
+ close(fd);
+ return IOCTL_SUCCESS;
+}
+
+static int test_tracing_toggle_and_filter(void)
+{
+ struct allocinfo_filter filter = { 0 };
+ enum ioctl_ret ioctl_status;
+ int ret = KSFT_PASS;
+ bool initial_state, target_state;
+ struct allocinfo_tag target_tag;
+ struct allocinfo_tag_data_vec *tags = calloc(1, sizeof(*tags));
+
+ if (!tags) {
+ ksft_print_msg("Memory allocation failed.\n");
+ return KSFT_FAIL;
+ }
+
+ filter.mask |= ALLOCINFO_FILTER_MASK_FUNCTION;
+ strncpy(filter.fields.function, target_test_function, ALLOCINFO_STR_SIZE);
+
+ ioctl_status = get_filtered_ioctl_entries(tags, &filter, 0);
+ if (ioctl_status != IOCTL_SUCCESS || tags->count == 0) {
+ ksft_print_msg("Could not retrieve IOCTL entries for %s\n", target_test_function);
+ ret = KSFT_SKIP;
+ goto exit;
+ }
+
+ target_tag = tags->tag[0].tag;
+ initial_state = tags->tag[0].counter.trace_on;
+ target_state = !initial_state;
+
+ ioctl_status = toggle_trace(&target_tag, target_state);
+ if (ioctl_status != IOCTL_SUCCESS) {
+ ksft_print_msg("Failed to toggle tracing\n");
+ ret = KSFT_FAIL;
+ goto exit;
+ }
+
+ filter.mask |= ALLOCINFO_FILTER_MASK_TRACE_ON;
+ filter.tracing = target_state;
+
+ ioctl_status = get_filtered_ioctl_entries(tags, &filter, 0);
+ if (ioctl_status != IOCTL_SUCCESS) {
+ ksft_print_msg("Error retrieving IOCTL entries with trace filter.\n");
+ ret = KSFT_FAIL;
+ goto exit_revert;
+ }
+
+ if (tags->count != 1) {
+ ksft_print_msg("Expected exactly 1 entry, but got %llu\n", tags->count);
+ ret = KSFT_FAIL;
+ goto exit_revert;
+ }
+
+ if (tags->tag[0].counter.trace_on != target_state) {
+ ksft_print_msg("Entry returned by trace filter does not match target state\n");
+ ret = KSFT_FAIL;
+ }
+
+exit_revert:
+ ioctl_status = toggle_trace(&target_tag, initial_state);
+ if (ioctl_status != IOCTL_SUCCESS) {
+ ksft_print_msg("Failed to revert tracing to initial state\n");
+ ret = KSFT_FAIL;
+ }
+
+exit:
+ free(tags);
+ return ret;
+}
+
int main(int argc, char *argv[])
{
int ret;
- ksft_set_plan(4);
+ ksft_set_plan(5);
ret = test_filename_filter();
if (ret == KSFT_SKIP)
@@ -526,6 +625,12 @@ int main(int argc, char *argv[])
else
ksft_test_result(ret == KSFT_PASS, "test_filename_filter\n");
+ ret = test_tracing_toggle_and_filter();
+ if (ret == KSFT_SKIP)
+ ksft_test_result_skip("Skipping test_tracing_toggle_and_filter\n");
+ else
+ ksft_test_result(ret == KSFT_PASS, "test_tracing_toggle_and_filter\n");
+
ret = test_function_filter();
if (ret == KSFT_SKIP)
ksft_test_result_skip("Skipping test_function_filter\n");
--
2.55.0.1082.g2b9226bbc0-goog