On Thu, May 22, 2025 at 06:38:52PM +0100, Mark Brown wrote:
> The kselftest framework uses the string logged when a test result is
> reported as the unique identifier for a test, using it to track test
> results between runs. The cow test completely fails to follow this pattern,
> it runs test functions repeatedly with various parameters with each result
> report from those functions being a string logging an error message which
> is fixed between runs.
>
> Since the code already logs each test uniquely before it starts refactor
> to also print this to a buffer, then use that name as the test result.
> This isn't especially pretty but is relatively straightforward and is a
> great help to tooling.
>
> Signed-off-by: Mark Brown
> ---
> tools/testing/selftests/mm/cow.c | 333
> +--
> 1 file changed, 217 insertions(+), 116 deletions(-)
>
> diff --git a/tools/testing/selftests/mm/cow.c
> b/tools/testing/selftests/mm/cow.c
> index e70cd3d900cc..a97f5ef79f17 100644
> --- a/tools/testing/selftests/mm/cow.c
> +++ b/tools/testing/selftests/mm/cow.c
> @@ -112,9 +112,12 @@ struct comm_pipes {
>
> static int setup_comm_pipes(struct comm_pipes *comm_pipes)
> {
> - if (pipe(comm_pipes->child_ready) < 0)
> + if (pipe(comm_pipes->child_ready) < 0) {
> + ksft_perror("pipe()");
> return -errno;
> + }
> if (pipe(comm_pipes->parent_ready) < 0) {
> + ksft_perror("pipe()");
> close(comm_pipes->child_ready[0]);
> close(comm_pipes->child_ready[1]);
> return -errno;
> @@ -207,13 +210,14 @@ static void do_test_cow_in_parent(char *mem, size_t
> size, bool do_mprotect,
>
> ret = setup_comm_pipes(&comm_pipes);
> if (ret) {
> - ksft_test_result_fail("pipe() failed\n");
> + log_test_result(KSFT_FAIL);
> return;
> }
>
> ret = fork();
> if (ret < 0) {
> - ksft_test_result_fail("fork() failed\n");
> + ksft_perror("fork() failed");
> + log_test_result(KSFT_FAIL);
> goto close_comm_pipes;
> } else if (!ret) {
> exit(fn(mem, size, &comm_pipes));
> @@ -228,9 +232,18 @@ static void do_test_cow_in_parent(char *mem, size_t
> size, bool do_mprotect,
>* write-faults by directly mapping pages writable.
>*/
> ret = mprotect(mem, size, PROT_READ);
> - ret |= mprotect(mem, size, PROT_READ|PROT_WRITE);
> if (ret) {
> - ksft_test_result_fail("mprotect() failed\n");
> + ksft_perror("mprotect() failed");
> + log_test_result(KSFT_FAIL);
> + write(comm_pipes.parent_ready[1], "0", 1);
> + wait(&ret);
> + goto close_comm_pipes;
> + }
> +
> + ret = mprotect(mem, size, PROT_READ|PROT_WRITE);
> + if (ret) {
> + ksft_perror("mprotect() failed");
> + log_test_result(KSFT_FAIL);
> write(comm_pipes.parent_ready[1], "0", 1);
> wait(&ret);
> goto close_comm_pipes;
> @@ -248,16 +261,16 @@ static void do_test_cow_in_parent(char *mem, size_t
> size, bool do_mprotect,
> ret = -EINVAL;
>
> if (!ret) {
> - ksft_test_result_pass("No leak from parent into child\n");
> + log_test_result(KSFT_PASS);
> } else if (xfail) {
> /*
>* With hugetlb, some vmsplice() tests are currently expected to
>* fail because (a) harder to fix and (b) nobody really cares.
>* Flag them as expected failure for now.
>*/
> - ksft_test_result_xfail("Leak from parent into child\n");
> + log_test_result(KSFT_XFAIL);
> } else {
> - ksft_test_result_fail("Leak from parent into child\n");
> + log_test_result(KSFT_FAIL);
> }
> close_comm_pipes:
> close_comm_pipes(&comm_pipes);
> @@ -306,26 +319,29 @@ static void do_test_vmsplice_in_parent(char *mem,
> size_t size,
>
> ret = setup_comm_pipes(&comm_pipes);
> if (ret) {
> - ksft_test_result_fail("pipe() failed\n");
> + log_test_result(KSFT_FAIL);
> goto free;
> }
>
> if (pipe(fds) < 0) {
> - ksft_test_result_fail("pipe() failed\n");
> + ksft_perror("pipe() failed");
> + log_test_result(KSFT_FAIL);
> goto close_comm_pipes;
> }
>
> if (before_fork) {
> transferred = vmsplice(fds[1], &iov, 1, 0);
> if (transferred <= 0) {
> - ksft_test_result_fail("vmsplice() failed\n");
> + ksft_print_msg("vmsplice() failed\n");
> + log_test_result(KSFT_FAIL);
>