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 <[email protected]> --- .../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
