Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests: line buffer test program's stdout

Patch series "selftests/mm fixes for arm64", v3.

Given my on-going work on large anon folios and contpte mappings, I
decided it would be a good idea to start running mm selftests to help
guard against regressions. However, it soon became clear that I
couldn't get the suite to run cleanly on arm64 with a vanilla v6.5-rc1
kernel (perhaps I'm just doing it wrong??), so got stuck in a rabbit
hole trying to debug and fix all the issues. Some were down to
misconfigurations, but I also found a number of issues with the tests
and even a couple of issues with the kernel.


This patch (of 8):

The selftests runner pipes the test program's stdout to tap_prefix. The
presence of the pipe means that the test program sets its stdout to be
fully buffered (as aposed to line buffered when directly connected to the
terminal). The block buffering means that there is often content in the
buffer at fork() time, which causes the output to end up duplicated. This
was causing problems for mm:cow where test results were duplicated 20-30x.

Solve this by using `stdbuf`, when available to force the test program to
use line buffered mode. This means previously printf'ed results are
flushed out of the program before any fork().

Additionally, explicitly set line buffer mode in ksft_print_header(),
which means that all test programs that use the ksft framework will
benefit even if stdbuf is not present on the system.

[ryan.roberts@arm.com: add setvbuf() to set buffering mode]
Link: https://lkml.kernel.org/r/20230726070655.2713530-1-ryan.roberts@arm.com
Link: https://lkml.kernel.org/r/20230724082522.1202616-1-ryan.roberts@arm.com
Link: https://lkml.kernel.org/r/20230724082522.1202616-2-ryan.roberts@arm.com
Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
Reviewed-by: Mark Brown <broonie@kernel.org>
Cc: David Hildenbrand <david@redhat.com>
Cc: Florent Revest <revest@chromium.org>
Cc: Jérôme Glisse <jglisse@redhat.com>
Cc: John Hubbard <jhubbard@nvidia.com>
Cc: Peter Xu <peterx@redhat.com>
Cc: Shuah Khan <shuah@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Ryan Roberts and committed by
Andrew Morton
58e2847a ea09800b

+38 -2
+24
tools/include/nolibc/stdio.h
··· 21 21 #define EOF (-1) 22 22 #endif 23 23 24 + /* Buffering mode used by setvbuf. */ 25 + #define _IOFBF 0 /* Fully buffered. */ 26 + #define _IOLBF 1 /* Line buffered. */ 27 + #define _IONBF 2 /* No buffering. */ 28 + 24 29 /* just define FILE as a non-empty type. The value of the pointer gives 25 30 * the FD: FILE=~fd for fd>=0 or NULL for fd<0. This way positive FILE 26 31 * are immediately identified as abnormal entries (i.e. possible copies ··· 353 348 void perror(const char *msg) 354 349 { 355 350 fprintf(stderr, "%s%serrno=%d\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "", errno); 351 + } 352 + 353 + static __attribute__((unused)) 354 + int setvbuf(FILE *stream, char *buf, int mode, size_t size) 355 + { 356 + /* 357 + * nolibc does not support buffering so this is a nop. Just check mode 358 + * is valid as required by the spec. 359 + */ 360 + switch (mode) { 361 + case _IOFBF: 362 + case _IOLBF: 363 + case _IONBF: 364 + break; 365 + default: 366 + return EOF; 367 + } 368 + 369 + return 0; 356 370 } 357 371 358 372 /* make sure to include all global symbols */
+9
tools/testing/selftests/kselftest.h
··· 113 113 114 114 static inline void ksft_print_header(void) 115 115 { 116 + /* 117 + * Force line buffering; If stdout is not connected to a terminal, it 118 + * will otherwise default to fully buffered, which can cause output 119 + * duplication if there is content in the buffer when fork()ing. If 120 + * there is a crash, line buffering also means the most recent output 121 + * line will be visible. 122 + */ 123 + setvbuf(stdout, NULL, _IOLBF, 0); 124 + 116 125 if (!(getenv("KSFT_TAP_LEVEL"))) 117 126 printf("TAP version 13\n"); 118 127 }
+5 -2
tools/testing/selftests/kselftest/runner.sh
··· 105 105 echo "# Warning: file $TEST is missing!" 106 106 echo "not ok $test_num $TEST_HDR_MSG" 107 107 else 108 + if [ -x /usr/bin/stdbuf ]; then 109 + stdbuf="/usr/bin/stdbuf --output=L " 110 + fi 108 111 eval kselftest_cmd_args="\$${kselftest_cmd_args_ref:-}" 109 - cmd="./$BASENAME_TEST $kselftest_cmd_args" 112 + cmd="$stdbuf ./$BASENAME_TEST $kselftest_cmd_args" 110 113 if [ ! -x "$TEST" ]; then 111 114 echo "# Warning: file $TEST is not executable" 112 115 113 116 if [ $(head -n 1 "$TEST" | cut -c -2) = "#!" ] 114 117 then 115 118 interpreter=$(head -n 1 "$TEST" | cut -c 3-) 116 - cmd="$interpreter ./$BASENAME_TEST" 119 + cmd="$stdbuf $interpreter ./$BASENAME_TEST" 117 120 else 118 121 echo "not ok $test_num $TEST_HDR_MSG" 119 122 return