diff mbox series

[v2] mtest06/mmap1: rewrite to newlib

Message ID 0e62adebbb4e5c8e3aa28440f860234b937d3e56.1543219161.git.jstancek@redhat.com
State Accepted
Headers show
Series [v2] mtest06/mmap1: rewrite to newlib | expand

Commit Message

Jan Stancek Nov. 26, 2018, 8:21 a.m. UTC
Fixes: #165

This patch is aiming to rewrite mtest06/mmap1 from scratch,
to address sporadic failures in #165.

Main difference is that it uses only one signal handler and no
synchronization between threads, no sched_yield calls.

Instead each mmap/munmap increases a map/unmap counter. Upon hitting
SIGSEGV or when comparing read value, these counter values are used
to determine state of mapped area as observed by first thread.
This isn't 100% accurrate as first thread might be faster than the
check, but it allows second thread to race against map/unmap for
its entire duration.

Signed-off-by: Jan Stancek <jstancek@redhat.com>
---
Changes in v2:
  - add suggestion by Li to write/check for 'b'
  - drop parameter from runtest file

 runtest/mm                           |   2 +-
 testcases/kernel/mem/mtest06/mmap1.c | 676 +++++++++++++----------------------
 2 files changed, 250 insertions(+), 428 deletions(-)
 rewrite testcases/kernel/mem/mtest06/mmap1.c (93%)

Comments

Li Wang Nov. 27, 2018, 6:37 a.m. UTC | #1
On Mon, Nov 26, 2018 at 4:21 PM Jan Stancek <jstancek@redhat.com> wrote:

> +static void sig_handler(int signal, siginfo_t *info,
> +       LTP_ATTRIBUTE_UNUSED void *ut)
> +{
> +       int ar_m, ar_u;
> +
> +       switch (signal) {
> +       case SIGSEGV:
> +               /* if we hit SIGSEGV between map/unmap, something is wrong */
> +               ar_u = tst_atomic_load(&unmapcnt);
> +               ar_m = tst_atomic_load(&mapcnt);
> +               if (was_area_mapped(br_map, br_unmap, ar_m, ar_u)) {
> +                       tst_res(TFAIL, "got sigsegv while mapped");
> +                       _exit(TFAIL);

why not use tst_brk() here?

> +               }
> +
> +               mapped_sigsegv_count++;
> +               longjmp(jmpbuf, 1);
> +               break;
> +       default:
> +               tst_res(TFAIL, "Unexpected signal - %d, addr: %p, exiting\n",
> +                       signal, info->si_addr);
> +               _exit(TBROK);

tst_brk() ?

> +       }
> +}
> +
> +void *map_write_unmap(void *ptr)
> +{
> +       long *args = ptr;
> +       void *tmp;

remove tmp pointer?

Beside these tiny issues, patch v2 looks good to me.

Reviewed-by: Li Wang <liwang@redhat.com>

--
Regards,
Li Wang
Jan Stancek Nov. 27, 2018, 8:54 a.m. UTC | #2
----- Original Message -----
> On Mon, Nov 26, 2018 at 4:21 PM Jan Stancek <jstancek@redhat.com> wrote:
> 
> > +static void sig_handler(int signal, siginfo_t *info,
> > +       LTP_ATTRIBUTE_UNUSED void *ut)
> > +{
> > +       int ar_m, ar_u;
> > +
> > +       switch (signal) {
> > +       case SIGSEGV:
> > +               /* if we hit SIGSEGV between map/unmap, something is wrong
> > */
> > +               ar_u = tst_atomic_load(&unmapcnt);
> > +               ar_m = tst_atomic_load(&mapcnt);
> > +               if (was_area_mapped(br_map, br_unmap, ar_m, ar_u)) {
> > +                       tst_res(TFAIL, "got sigsegv while mapped");
> > +                       _exit(TFAIL);
> 
> why not use tst_brk() here?

Because it calls exit(), which is not advised to do in signal handler.
(doc/test-writing-guidelines.txt, line 841)

> 
> > +               }
> > +
> > +               mapped_sigsegv_count++;
> > +               longjmp(jmpbuf, 1);
> > +               break;
> > +       default:
> > +               tst_res(TFAIL, "Unexpected signal - %d, addr: %p,
> > exiting\n",
> > +                       signal, info->si_addr);
> > +               _exit(TBROK);
> 
> tst_brk() ?
> 
> > +       }
> > +}
> > +
> > +void *map_write_unmap(void *ptr)
> > +{
> > +       long *args = ptr;
> > +       void *tmp;
> 
> remove tmp pointer?

It introduces warning in safe_munmap(), because map_address is volatile.
That is why I kept 'tmp'.

> 
> Beside these tiny issues, patch v2 looks good to me.
> 
> Reviewed-by: Li Wang <liwang@redhat.com>

Thanks,
Jan

> 
> --
> Regards,
> Li Wang
>
Cyril Hrubis Nov. 29, 2018, 1:44 p.m. UTC | #3
Hi!
> Instead each mmap/munmap increases a map/unmap counter. Upon hitting
> SIGSEGV or when comparing read value, these counter values are used
> to determine state of mapped area as observed by first thread.
> This isn't 100% accurrate as first thread might be faster than the
> check, but it allows second thread to race against map/unmap for
> its entire duration.

Looks good to me, using atomic counters and comparing values before and
after we access the memory is very clever as well. You can add my
Reviewed-by.

Very minor comments below.

> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) 2018 Jan Stancek. All rights reserved.
> + */
> +/*
> + * Test: Spawn 2 threads. First thread maps, writes and unmaps
> + * an area. Second thread tries to read from it. Second thread
> + * races against first thread. There is no synchronization
> + * between threads, but each mmap/munmap increases a counter
> + * that is checked to determine when has read occurred. If a read
> + * hit SIGSEGV in between mmap/munmap it is a failure. If a read
> + * between mmap/munmap worked, then its value must match expected
> + * value.
> + */
> +#include <errno.h>
> +#include <float.h>
> +#include <pthread.h>
> +#include <sched.h>
> +#include <setjmp.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include "tst_test.h"
> +#include "tst_safe_pthread.h"
> +
> +#define DISTANT_MMAP_SIZE (64*1024*1024)
> +#define TEST_FILENAME "ashfile"
> +
> +/* seconds remaining before reaching timeout */
> +#define STOP_THRESHOLD 10
> +
> +#define PROGRESS_SEC 3
> +
> +static int file_size = 1024;
> +static int num_iter = 5000;
> +static float exec_time = 0.05; /* default is 3 min */
> +
> +static void *distant_area;
> +static char *str_exec_time;
> +static jmp_buf jmpbuf;
> +static volatile unsigned char *map_address;
> +static unsigned long page_sz;
> +
> +static unsigned long mapped_sigsegv_count;
> +static unsigned long map_count;
> +static unsigned long threads_spawned;
> +static unsigned long data_matched;
> +static unsigned long repeated_reads;
> +
> +/* sequence id for each map/unmap performed */
> +static int mapcnt, unmapcnt;
> +/* stored sequence id before making read attempt */
> +static int br_map, br_unmap;
> +
> +static struct tst_option options[] = {
> +	{"x:", &str_exec_time, "Exec time (hours)"},
> +	{NULL, NULL, NULL}
> +};
> +
> +/* compare "before read" counters  with "after read" counters */
> +static inline int was_area_mapped(int br_m, int br_u, int ar_m, int ar_u)
> +{
> +	return (br_m == ar_m && br_u == ar_u && br_m > br_u);
> +}

Since the br_map and br_unmap are global I would consider passing only
the values after to this function.

> +static void sig_handler(int signal, siginfo_t *info,
> +	LTP_ATTRIBUTE_UNUSED void *ut)
> +{
> +	int ar_m, ar_u;
> +
> +	switch (signal) {
> +	case SIGSEGV:
> +		/* if we hit SIGSEGV between map/unmap, something is wrong */
> +		ar_u = tst_atomic_load(&unmapcnt);
> +		ar_m = tst_atomic_load(&mapcnt);
> +		if (was_area_mapped(br_map, br_unmap, ar_m, ar_u)) {
> +			tst_res(TFAIL, "got sigsegv while mapped");
> +			_exit(TFAIL);
> +		}
> +
> +		mapped_sigsegv_count++;
> +		longjmp(jmpbuf, 1);
> +		break;
> +	default:
> +		tst_res(TFAIL, "Unexpected signal - %d, addr: %p, exiting\n",
> +			signal, info->si_addr);
> +		_exit(TBROK);
> +	}
> +}
> +
> +void *map_write_unmap(void *ptr)
> +{
> +	long *args = ptr;
> +	void *tmp;
> +	int i, j;
> +
> +	for (i = 0; i < num_iter; i++) {
> +		map_address = SAFE_MMAP(distant_area,
> +			(size_t) file_size, PROT_WRITE | PROT_READ,
> +			MAP_SHARED, (int)args[0], 0);
> +		tst_atomic_inc(&mapcnt);
> +
> +		for (j = 0; j < file_size; j++)
> +			map_address[j] = 'b';
> +
> +		tmp = (void *)map_address;
> +		tst_atomic_inc(&unmapcnt);
> +		SAFE_MUNMAP(tmp, file_size);
> +
> +		map_count++;
> +	}
> +
> +	return NULL;
> +}
> +
> +void *read_mem(LTP_ATTRIBUTE_UNUSED void *ptr)
> +{
> +	int i, j, ar_map, ar_unmap;
> +	unsigned char c;
> +
> +	for (i = 0; i < num_iter; i++) {
> +		if (setjmp(jmpbuf) == 1)
> +			continue;
> +
> +		for (j = 0; j < file_size; j++) {
> +read_again:
> +			br_map = tst_atomic_load(&mapcnt);
> +			br_unmap = tst_atomic_load(&unmapcnt);
> +
> +			c = map_address[j];
> +
> +			ar_unmap = tst_atomic_load(&unmapcnt);
> +			ar_map = tst_atomic_load(&mapcnt);
> +
> +			/*
> +			 * Read above is racing against munmap and mmap
> +			 * in other thread. While the address might be valid
> +			 * the mapping could be in various stages of being
> +			 * 'ready'. We only check the value, if we can be sure
> +			 * read hapenned in between single mmap and munmap as
> +			 * observed by first thread.
> +			 */
> +			if (was_area_mapped(br_map, br_unmap, ar_map,
> +				ar_unmap)) {
> +				switch (c) {
> +				case 'a':
> +					repeated_reads++;
> +					goto read_again;
> +				case 'b':
> +					data_matched++;
> +					break;
> +				default:
> +					tst_res(TFAIL, "value[%d] is %c", j, c);
> +					break;
> +				}
> +			}
> +		}
> +	}
> +
> +	return NULL;
> +}
> +
> +int mkfile(int size)
> +{
> +	int fd, i;
> +
> +	fd = SAFE_OPEN(TEST_FILENAME, O_RDWR | O_CREAT, 0600);
> +	SAFE_UNLINK(TEST_FILENAME);
> +
> +	for (i = 0; i < size; i++)
> +		SAFE_WRITE(1, fd, "a", 1);
> +	SAFE_WRITE(1, fd, "\0", 1);
> +
> +	if (fsync(fd) == -1)
> +		tst_brk(TBROK | TERRNO, "fsync()");
> +
> +	return fd;
> +}
> +
> +static void setup(void)
> +{
> +	struct sigaction sigptr;
> +
> +	page_sz = getpagesize();
> +
> +	/*
> +	 * Used as hint for mmap thread, so it doesn't interfere
> +	 * with other potential (temporary) mappings from libc
> +	 */
> +	distant_area = SAFE_MMAP(0, DISTANT_MMAP_SIZE, PROT_WRITE | PROT_READ,
> +			MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
> +	SAFE_MUNMAP(distant_area, (size_t)DISTANT_MMAP_SIZE);
> +	distant_area += DISTANT_MMAP_SIZE / 2;
> +
> +	if (tst_parse_float(str_exec_time, &exec_time, 0, FLT_MAX)) {
> +		tst_brk(TBROK, "Invalid number for exec_time '%s'",
> +			str_exec_time);
> +	}
> +
> +	sigptr.sa_sigaction = sig_handler;
> +	sigemptyset(&sigptr.sa_mask);
> +	sigptr.sa_flags = SA_SIGINFO | SA_NODEFER;
> +	SAFE_SIGACTION(SIGSEGV, &sigptr, NULL);
> +
> +	tst_set_timeout((int)(exec_time * 3600));
> +}
> +
> +static void run(void)
> +{
> +	pthread_t thid[2];
> +	long chld_args[1];
> +	int remaining = tst_timeout_remaining();
> +	int elapsed = 0;
> +
> +	while (tst_timeout_remaining() > STOP_THRESHOLD) {
> +		int fd = mkfile(file_size);
> +
> +		tst_atomic_store(0, &mapcnt);
> +		tst_atomic_store(0, &unmapcnt);
> +
> +		chld_args[0] = fd;

I would have just casted the fd here to long or intptr_t (to make sure
compiler padds it with zeroes) then to (void*) and passed the value
directly, i.e. (void*)(inptr_t)fd and then back in the thread we do
fd = (intptr_t)ptr.

> +		SAFE_PTHREAD_CREATE(&thid[0], NULL, map_write_unmap, chld_args);
> +		SAFE_PTHREAD_CREATE(&thid[1], NULL, read_mem, chld_args);
> +		threads_spawned += 2;
> +
> +		SAFE_PTHREAD_JOIN(thid[0], NULL);
> +		SAFE_PTHREAD_JOIN(thid[1], NULL);
> +
> +		close(fd);
> +
> +		if (remaining - tst_timeout_remaining() > PROGRESS_SEC) {
> +			remaining = tst_timeout_remaining();
> +			elapsed += PROGRESS_SEC;
> +			tst_res(TINFO, "[%d] mapped: %lu, sigsegv hit: %lu, "
> +				"threads spawned: %lu",	elapsed, map_count,
> +				mapped_sigsegv_count, threads_spawned);
> +			tst_res(TINFO, "[%d] repeated_reads: %ld, "
> +				"data_matched: %lu", elapsed, repeated_reads,
> +				data_matched);
> +		}
> +	}
> +	tst_res(TPASS, "System survived.");
> +}
> +
> +static struct tst_test test = {
> +	.test_all = run,
> +	.setup = setup,
> +	.options = options,
> +	.needs_tmpdir = 1,
> +};
> -- 
> 1.8.3.1
> 
> 
> -- 
> Mailing list info: https://lists.linux.it/listinfo/ltp
Jan Stancek Nov. 30, 2018, 9:46 a.m. UTC | #4
----- Original Message -----
> Hi!
> > Instead each mmap/munmap increases a map/unmap counter. Upon hitting
> > SIGSEGV or when comparing read value, these counter values are used
> > to determine state of mapped area as observed by first thread.
> > This isn't 100% accurrate as first thread might be faster than the
> > check, but it allows second thread to race against map/unmap for
> > its entire duration.
> 
> Looks good to me, using atomic counters and comparing values before and
> after we access the memory is very clever as well. You can add my
> Reviewed-by.
> 
> Very minor comments below.
> > +/* compare "before read" counters  with "after read" counters */
> > +static inline int was_area_mapped(int br_m, int br_u, int ar_m, int ar_u)
> > +{
> > +	return (br_m == ar_m && br_u == ar_u && br_m > br_u);
> > +}
> 
> Since the br_map and br_unmap are global I would consider passing only
> the values after to this function.

Hi,

I find it more clear if it doesn't depend on globals. Since it's inlined
there should be no penalty, so I kept it as is.

> > +
> > +void *read_mem(LTP_ATTRIBUTE_UNUSED void *ptr)
> > +{
> > +	int i, j, ar_map, ar_unmap;
> > +	unsigned char c;
> > +
> > +	for (i = 0; i < num_iter; i++) {
> > +		if (setjmp(jmpbuf) == 1)
> > +			continue;

I made 'i' volatile, since longjmp could clobber it.

> > +static void run(void)
> > +{
> > +	pthread_t thid[2];
> > +	long chld_args[1];
> > +	int remaining = tst_timeout_remaining();
> > +	int elapsed = 0;
> > +
> > +	while (tst_timeout_remaining() > STOP_THRESHOLD) {
> > +		int fd = mkfile(file_size);
> > +
> > +		tst_atomic_store(0, &mapcnt);
> > +		tst_atomic_store(0, &unmapcnt);
> > +
> > +		chld_args[0] = fd;
> 
> I would have just casted the fd here to long or intptr_t (to make sure
> compiler padds it with zeroes) then to (void*) and passed the value
> directly, i.e. (void*)(inptr_t)fd and then back in the thread we do
> fd = (intptr_t)ptr.

I changed this to pass int ptr directly, which requires no casts AFAICT.

... and pushed.

Thanks,
Jan
Naresh Kamboju Feb. 4, 2019, 8:34 a.m. UTC | #5
FYI,

mtest06/mmap1.c fails intermittently on arm64 devices due to timeout reason.
The current timeout set as 15 minutes
export LTP_TIMEOUT_MUL=3

Test case output:
-----------------------
tst_test.c:1085: INFO: Timeout per run is 0h 15m 00s
tst_test.c:1085: INFO: Timeout per run is 0h 09m 00s
mmap1.c:234: INFO: [3] mapped: 15000, sigsegv hit: 11375, threads spawned: 6
mmap1.c:237: INFO: [3] repeated_reads: 67, data_matched: 3440667
mmap1.c:234: INFO: [6] mapped: 30000, sigsegv hit: 21256, threads spawned: 12
mmap1.c:237: INFO: [6] repeated_reads: 2530, data_matched: 8455962
mmap1.c:234: INFO: [9] mapped: 40000, sigsegv hit: 28215, threads spawned: 16
mmap1.c:237: INFO: [9] repeated_reads: 4413, data_matched: 11314629
mmap1.c:234: INFO: [12] mapped: 55000, sigsegv hit: 38454, threads spawned: 22
mmap1.c:237: INFO: [12] repeated_reads: 9285, data_matched: 15892633
mmap1.c:234: INFO: [15] mapped: 60000, sigsegv hit: 42462, threads spawned: 24
mmap1.c:237: INFO: [15] repeated_reads: 11993, data_matched: 16723333
mmap1.c:234: INFO: [18] mapped: 65000, sigsegv hit: 46272, threads spawned: 26
mmap1.c:237: INFO: [18] repeated_reads: 11993, data_matched: 18043857
mmap1.c:234: INFO: [21] mapped: 80000, sigsegv hit: 58736, threads spawned: 32
mmap1.c:237: INFO: [21] repeated_reads: 14467, data_matched: 20310080
mmap1.c:234: INFO: [24] mapped: 85000, sigsegv hit: 62747, threads spawned: 34
mmap1.c:237: INFO: [24] repeated_reads: 14467, data_matched: 21065412
mmap1.c:234: INFO: [27] mapped: 95000, sigsegv hit: 67177, threads spawned: 38
mmap1.c:237: INFO: [27] repeated_reads: 14467, data_matched: 26278412
mmap1.c:234: INFO: [30] mapped: 110000, sigsegv hit: 75318, threads spawned: 44
mmap1.c:237: INFO: [30] repeated_reads: 18749, data_matched: 32880471
mmap1.c:234: INFO: [33] mapped: 130000, sigsegv hit: 86435, threads spawned: 52
mmap1.c:237: INFO: [33] repeated_reads: 20987, data_matched: 41628336
mmap1.c:234: INFO: [36] mapped: 150000, sigsegv hit: 95359, threads spawned: 60
mmap1.c:237: INFO: [36] repeated_reads: 20987, data_matched: 52762236
mmap1.c:234: INFO: [39] mapped: 175000, sigsegv hit: 107473, threads spawned: 70
mmap1.c:237: INFO: [39] repeated_reads: 20987, data_matched: 65170250
mmap1.c:234: INFO: [42] mapped: 195000, sigsegv hit: 115860, threads spawned: 78
mmap1.c:237: INFO: [42] repeated_reads: 24446, data_matched: 76553410
mmap1.c:234: INFO: [45] mapped: 220000, sigsegv hit: 130868, threads spawned: 88
mmap1.c:237: INFO: [45] repeated_reads: 28657, data_matched: 86358966
mmap1.c:234: INFO: [48] mapped: 245000, sigsegv hit: 145435, threads spawned: 98
mmap1.c:237: INFO: [48] repeated_reads: 34613, data_matched: 96820804
mmap1.c:234: INFO: [51] mapped: 260000, sigsegv hit: 154934, threads
spawned: 104
mmap1.c:237: INFO: [51] repeated_reads: 38042, data_matched: 102281865
mmap1.c:234: INFO: [54] mapped: 280000, sigsegv hit: 168403, threads
spawned: 112
mmap1.c:237: INFO: [54] repeated_reads: 44799, data_matched: 108884699
mmap1.c:234: INFO: [57] mapped: 305000, sigsegv hit: 188132, threads
spawned: 122
mmap1.c:237: INFO: [57] repeated_reads: 48995, data_matched: 113829351
mmap1.c:234: INFO: [60] mapped: 315000, sigsegv hit: 196457, threads
spawned: 126
mmap1.c:237: INFO: [60] repeated_reads: 51657, data_matched: 115444681
mmap1.c:234: INFO: [63] mapped: 330000, sigsegv hit: 208077, threads
spawned: 132
mmap1.c:237: INFO: [63] repeated_reads: 51657, data_matched: 118910807
mmap1.c:234: INFO: [66] mapped: 335000, sigsegv hit: 211847, threads
spawned: 134
mmap1.c:237: INFO: [66] repeated_reads: 51657, data_matched: 119936305
mmap1.c:234: INFO: [69] mapped: 355000, sigsegv hit: 225809, threads
spawned: 142
mmap1.c:237: INFO: [69] repeated_reads: 58357, data_matched: 125691672
mmap1.c:234: INFO: [72] mapped: 365000, sigsegv hit: 233748, threads
spawned: 146
mmap1.c:237: INFO: [72] repeated_reads: 63594, data_matched: 127682094
mmap1.c:234: INFO: [75] mapped: 375000, sigsegv hit: 240935, threads
spawned: 150
mmap1.c:237: INFO: [75] repeated_reads: 65813, data_matched: 130436913
mmap1.c:234: INFO: [78] mapped: 395000, sigsegv hit: 256994, threads
spawned: 158
mmap1.c:237: INFO: [78] repeated_reads: 68240, data_matched: 134313071
mmap1.c:234: INFO: [81] mapped: 400000, sigsegv hit: 260739, threads
spawned: 160
mmap1.c:237: INFO: [81] repeated_reads: 68240, data_matched: 135483078
mmap1.c:234: INFO: [84] mapped: 405000, sigsegv hit: 263510, threads
spawned: 162
mmap1.c:237: INFO: [84] repeated_reads: 68240, data_matched: 137744513
mmap1.c:234: INFO: [87] mapped: 415000, sigsegv hit: 271049, threads
spawned: 166
mmap1.c:237: INFO: [87] repeated_reads: 70071, data_matched: 140167936
mmap1.c:234: INFO: [90] mapped: 430000, sigsegv hit: 282504, threads
spawned: 172
mmap1.c:237: INFO: [90] repeated_reads: 74335, data_matched: 143263860
mmap1.c:234: INFO: [93] mapped: 435000, sigsegv hit: 286623, threads
spawned: 174
mmap1.c:237: INFO: [93] repeated_reads: 76581, data_matched: 144114430
mmap1.c:234: INFO: [96] mapped: 445000, sigsegv hit: 292401, threads
spawned: 178
mmap1.c:237: INFO: [96] repeated_reads: 78725, data_matched: 148160778
mmap1.c:234: INFO: [99] mapped: 450000, sigsegv hit: 296192, threads
spawned: 180
mmap1.c:237: INFO: [99] repeated_reads: 78725, data_matched: 149328825
mmap1.c:234: INFO: [102] mapped: 460000, sigsegv hit: 304280, threads
spawned: 184
mmap1.c:237: INFO: [102] repeated_reads: 78725, data_matched: 151183014
mmap1.c:234: INFO: [105] mapped: 465000, sigsegv hit: 308364, threads
spawned: 186
mmap1.c:237: INFO: [105] repeated_reads: 78725, data_matched: 152036389
Test timeouted, sending SIGKILL!
tst_test.c:1125: INFO: If you are running on slow machine, try
exporting LTP_TIMEOUT_MUL > 1
tst_test.c:1126: BROK: Test killed! (timeout?)

Test results comparison,
https://qa-reports.linaro.org/lkft/linux-mainline-oe/tests/ltp-mm-tests/mtest06

Any chance to minimize the test run time ?

Best regards
Naresh Kamboju


On Fri, 30 Nov 2018 at 15:16, Jan Stancek <jstancek@redhat.com> wrote:
>
>
>
> ----- Original Message -----
> > Hi!
> > > Instead each mmap/munmap increases a map/unmap counter. Upon hitting
> > > SIGSEGV or when comparing read value, these counter values are used
> > > to determine state of mapped area as observed by first thread.
> > > This isn't 100% accurrate as first thread might be faster than the
> > > check, but it allows second thread to race against map/unmap for
> > > its entire duration.
> >
> > Looks good to me, using atomic counters and comparing values before and
> > after we access the memory is very clever as well. You can add my
> > Reviewed-by.
> >
> > Very minor comments below.
> > > +/* compare "before read" counters  with "after read" counters */
> > > +static inline int was_area_mapped(int br_m, int br_u, int ar_m, int ar_u)
> > > +{
> > > +   return (br_m == ar_m && br_u == ar_u && br_m > br_u);
> > > +}
> >
> > Since the br_map and br_unmap are global I would consider passing only
> > the values after to this function.
>
> Hi,
>
> I find it more clear if it doesn't depend on globals. Since it's inlined
> there should be no penalty, so I kept it as is.
>
> > > +
> > > +void *read_mem(LTP_ATTRIBUTE_UNUSED void *ptr)
> > > +{
> > > +   int i, j, ar_map, ar_unmap;
> > > +   unsigned char c;
> > > +
> > > +   for (i = 0; i < num_iter; i++) {
> > > +           if (setjmp(jmpbuf) == 1)
> > > +                   continue;
>
> I made 'i' volatile, since longjmp could clobber it.
>
> > > +static void run(void)
> > > +{
> > > +   pthread_t thid[2];
> > > +   long chld_args[1];
> > > +   int remaining = tst_timeout_remaining();
> > > +   int elapsed = 0;
> > > +
> > > +   while (tst_timeout_remaining() > STOP_THRESHOLD) {
> > > +           int fd = mkfile(file_size);
> > > +
> > > +           tst_atomic_store(0, &mapcnt);
> > > +           tst_atomic_store(0, &unmapcnt);
> > > +
> > > +           chld_args[0] = fd;
> >
> > I would have just casted the fd here to long or intptr_t (to make sure
> > compiler padds it with zeroes) then to (void*) and passed the value
> > directly, i.e. (void*)(inptr_t)fd and then back in the thread we do
> > fd = (intptr_t)ptr.
>
> I changed this to pass int ptr directly, which requires no casts AFAICT.
>
> ... and pushed.
>
> Thanks,
> Jan
>
> --
> Mailing list info: https://lists.linux.it/listinfo/ltp
Jan Stancek Feb. 4, 2019, 9:05 a.m. UTC | #6
----- Original Message -----
> FYI,
> 
> mtest06/mmap1.c fails intermittently on arm64 devices due to timeout reason.
> The current timeout set as 15 minutes
> export LTP_TIMEOUT_MUL=3
> 
> Test case output:
> -----------------------
> tst_test.c:1085: INFO: Timeout per run is 0h 15m 00s
> tst_test.c:1085: INFO: Timeout per run is 0h 09m 00s
> mmap1.c:234: INFO: [3] mapped: 15000, sigsegv hit: 11375, threads spawned: 6
> mmap1.c:237: INFO: [3] repeated_reads: 67, data_matched: 3440667
> mmap1.c:234: INFO: [6] mapped: 30000, sigsegv hit: 21256, threads spawned: 12
> mmap1.c:237: INFO: [6] repeated_reads: 2530, data_matched: 8455962
> mmap1.c:234: INFO: [9] mapped: 40000, sigsegv hit: 28215, threads spawned: 16
> mmap1.c:237: INFO: [9] repeated_reads: 4413, data_matched: 11314629
> mmap1.c:234: INFO: [12] mapped: 55000, sigsegv hit: 38454, threads spawned:
> 22
> mmap1.c:237: INFO: [12] repeated_reads: 9285, data_matched: 15892633
> mmap1.c:234: INFO: [15] mapped: 60000, sigsegv hit: 42462, threads spawned:
> 24
> mmap1.c:237: INFO: [15] repeated_reads: 11993, data_matched: 16723333
> mmap1.c:234: INFO: [18] mapped: 65000, sigsegv hit: 46272, threads spawned:
> 26
> mmap1.c:237: INFO: [18] repeated_reads: 11993, data_matched: 18043857
> mmap1.c:234: INFO: [21] mapped: 80000, sigsegv hit: 58736, threads spawned:
> 32
> mmap1.c:237: INFO: [21] repeated_reads: 14467, data_matched: 20310080
> mmap1.c:234: INFO: [24] mapped: 85000, sigsegv hit: 62747, threads spawned:
> 34
> mmap1.c:237: INFO: [24] repeated_reads: 14467, data_matched: 21065412
> mmap1.c:234: INFO: [27] mapped: 95000, sigsegv hit: 67177, threads spawned:
> 38
> mmap1.c:237: INFO: [27] repeated_reads: 14467, data_matched: 26278412
> mmap1.c:234: INFO: [30] mapped: 110000, sigsegv hit: 75318, threads spawned:
> 44
> mmap1.c:237: INFO: [30] repeated_reads: 18749, data_matched: 32880471
> mmap1.c:234: INFO: [33] mapped: 130000, sigsegv hit: 86435, threads spawned:
> 52
> mmap1.c:237: INFO: [33] repeated_reads: 20987, data_matched: 41628336
> mmap1.c:234: INFO: [36] mapped: 150000, sigsegv hit: 95359, threads spawned:
> 60
> mmap1.c:237: INFO: [36] repeated_reads: 20987, data_matched: 52762236
> mmap1.c:234: INFO: [39] mapped: 175000, sigsegv hit: 107473, threads spawned:
> 70
> mmap1.c:237: INFO: [39] repeated_reads: 20987, data_matched: 65170250
> mmap1.c:234: INFO: [42] mapped: 195000, sigsegv hit: 115860, threads spawned:
> 78
> mmap1.c:237: INFO: [42] repeated_reads: 24446, data_matched: 76553410
> mmap1.c:234: INFO: [45] mapped: 220000, sigsegv hit: 130868, threads spawned:
> 88
> mmap1.c:237: INFO: [45] repeated_reads: 28657, data_matched: 86358966
> mmap1.c:234: INFO: [48] mapped: 245000, sigsegv hit: 145435, threads spawned:
> 98
> mmap1.c:237: INFO: [48] repeated_reads: 34613, data_matched: 96820804
> mmap1.c:234: INFO: [51] mapped: 260000, sigsegv hit: 154934, threads
> spawned: 104
> mmap1.c:237: INFO: [51] repeated_reads: 38042, data_matched: 102281865
> mmap1.c:234: INFO: [54] mapped: 280000, sigsegv hit: 168403, threads
> spawned: 112
> mmap1.c:237: INFO: [54] repeated_reads: 44799, data_matched: 108884699
> mmap1.c:234: INFO: [57] mapped: 305000, sigsegv hit: 188132, threads
> spawned: 122
> mmap1.c:237: INFO: [57] repeated_reads: 48995, data_matched: 113829351
> mmap1.c:234: INFO: [60] mapped: 315000, sigsegv hit: 196457, threads
> spawned: 126
> mmap1.c:237: INFO: [60] repeated_reads: 51657, data_matched: 115444681
> mmap1.c:234: INFO: [63] mapped: 330000, sigsegv hit: 208077, threads
> spawned: 132
> mmap1.c:237: INFO: [63] repeated_reads: 51657, data_matched: 118910807
> mmap1.c:234: INFO: [66] mapped: 335000, sigsegv hit: 211847, threads
> spawned: 134
> mmap1.c:237: INFO: [66] repeated_reads: 51657, data_matched: 119936305
> mmap1.c:234: INFO: [69] mapped: 355000, sigsegv hit: 225809, threads
> spawned: 142
> mmap1.c:237: INFO: [69] repeated_reads: 58357, data_matched: 125691672
> mmap1.c:234: INFO: [72] mapped: 365000, sigsegv hit: 233748, threads
> spawned: 146
> mmap1.c:237: INFO: [72] repeated_reads: 63594, data_matched: 127682094
> mmap1.c:234: INFO: [75] mapped: 375000, sigsegv hit: 240935, threads
> spawned: 150
> mmap1.c:237: INFO: [75] repeated_reads: 65813, data_matched: 130436913
> mmap1.c:234: INFO: [78] mapped: 395000, sigsegv hit: 256994, threads
> spawned: 158
> mmap1.c:237: INFO: [78] repeated_reads: 68240, data_matched: 134313071
> mmap1.c:234: INFO: [81] mapped: 400000, sigsegv hit: 260739, threads
> spawned: 160
> mmap1.c:237: INFO: [81] repeated_reads: 68240, data_matched: 135483078
> mmap1.c:234: INFO: [84] mapped: 405000, sigsegv hit: 263510, threads
> spawned: 162
> mmap1.c:237: INFO: [84] repeated_reads: 68240, data_matched: 137744513
> mmap1.c:234: INFO: [87] mapped: 415000, sigsegv hit: 271049, threads
> spawned: 166
> mmap1.c:237: INFO: [87] repeated_reads: 70071, data_matched: 140167936
> mmap1.c:234: INFO: [90] mapped: 430000, sigsegv hit: 282504, threads
> spawned: 172
> mmap1.c:237: INFO: [90] repeated_reads: 74335, data_matched: 143263860
> mmap1.c:234: INFO: [93] mapped: 435000, sigsegv hit: 286623, threads
> spawned: 174
> mmap1.c:237: INFO: [93] repeated_reads: 76581, data_matched: 144114430
> mmap1.c:234: INFO: [96] mapped: 445000, sigsegv hit: 292401, threads
> spawned: 178
> mmap1.c:237: INFO: [96] repeated_reads: 78725, data_matched: 148160778
> mmap1.c:234: INFO: [99] mapped: 450000, sigsegv hit: 296192, threads
> spawned: 180
> mmap1.c:237: INFO: [99] repeated_reads: 78725, data_matched: 149328825
> mmap1.c:234: INFO: [102] mapped: 460000, sigsegv hit: 304280, threads
> spawned: 184
> mmap1.c:237: INFO: [102] repeated_reads: 78725, data_matched: 151183014
> mmap1.c:234: INFO: [105] mapped: 465000, sigsegv hit: 308364, threads
> spawned: 186
> mmap1.c:237: INFO: [105] repeated_reads: 78725, data_matched: 152036389
> Test timeouted, sending SIGKILL!
> tst_test.c:1125: INFO: If you are running on slow machine, try
> exporting LTP_TIMEOUT_MUL > 1
> tst_test.c:1126: BROK: Test killed! (timeout?)
> 
> Test results comparison,
> https://qa-reports.linaro.org/lkft/linux-mainline-oe/tests/ltp-mm-tests/mtest06
> 
> Any chance to minimize the test run time ?

Default is 3 minutes, but it appears to be getting stuck before that.
In [1], the output stopped after ~12-15 seconds, followed by timeout.

So either timeout arrived early (which seems unlikely) or test was stuck on something.

[1] https://qa-reports.linaro.org/lkft/linux-mainline-oe/build/v5.0-rc5/testrun/594677/log
Jan Stancek Feb. 5, 2019, 6:46 a.m. UTC | #7
----- Original Message -----
> 
> 
> 
> ----- Original Message -----
> > FYI,
> > 
> > mtest06/mmap1.c fails intermittently on arm64 devices due to timeout
> > reason.
> > The current timeout set as 15 minutes
> > export LTP_TIMEOUT_MUL=3
> > 
> > Test case output:
> > -----------------------
> > tst_test.c:1085: INFO: Timeout per run is 0h 15m 00s
> > tst_test.c:1085: INFO: Timeout per run is 0h 09m 00s
> > mmap1.c:234: INFO: [3] mapped: 15000, sigsegv hit: 11375, threads spawned:
> > 6
> > mmap1.c:237: INFO: [3] repeated_reads: 67, data_matched: 3440667
> > mmap1.c:234: INFO: [6] mapped: 30000, sigsegv hit: 21256, threads spawned:
> > 12
> > mmap1.c:237: INFO: [6] repeated_reads: 2530, data_matched: 8455962
> > mmap1.c:234: INFO: [9] mapped: 40000, sigsegv hit: 28215, threads spawned:
> > 16
> > mmap1.c:237: INFO: [9] repeated_reads: 4413, data_matched: 11314629
> > mmap1.c:234: INFO: [12] mapped: 55000, sigsegv hit: 38454, threads spawned:
> > 22
> > mmap1.c:237: INFO: [12] repeated_reads: 9285, data_matched: 15892633
> > mmap1.c:234: INFO: [15] mapped: 60000, sigsegv hit: 42462, threads spawned:
> > 24
> > mmap1.c:237: INFO: [15] repeated_reads: 11993, data_matched: 16723333
> > mmap1.c:234: INFO: [18] mapped: 65000, sigsegv hit: 46272, threads spawned:
> > 26
> > mmap1.c:237: INFO: [18] repeated_reads: 11993, data_matched: 18043857
> > mmap1.c:234: INFO: [21] mapped: 80000, sigsegv hit: 58736, threads spawned:
> > 32
> > mmap1.c:237: INFO: [21] repeated_reads: 14467, data_matched: 20310080
> > mmap1.c:234: INFO: [24] mapped: 85000, sigsegv hit: 62747, threads spawned:
> > 34
> > mmap1.c:237: INFO: [24] repeated_reads: 14467, data_matched: 21065412
> > mmap1.c:234: INFO: [27] mapped: 95000, sigsegv hit: 67177, threads spawned:
> > 38
> > mmap1.c:237: INFO: [27] repeated_reads: 14467, data_matched: 26278412
> > mmap1.c:234: INFO: [30] mapped: 110000, sigsegv hit: 75318, threads
> > spawned:
> > 44
> > mmap1.c:237: INFO: [30] repeated_reads: 18749, data_matched: 32880471
> > mmap1.c:234: INFO: [33] mapped: 130000, sigsegv hit: 86435, threads
> > spawned:
> > 52
> > mmap1.c:237: INFO: [33] repeated_reads: 20987, data_matched: 41628336
> > mmap1.c:234: INFO: [36] mapped: 150000, sigsegv hit: 95359, threads
> > spawned:
> > 60
> > mmap1.c:237: INFO: [36] repeated_reads: 20987, data_matched: 52762236
> > mmap1.c:234: INFO: [39] mapped: 175000, sigsegv hit: 107473, threads
> > spawned:
> > 70
> > mmap1.c:237: INFO: [39] repeated_reads: 20987, data_matched: 65170250
> > mmap1.c:234: INFO: [42] mapped: 195000, sigsegv hit: 115860, threads
> > spawned:
> > 78
> > mmap1.c:237: INFO: [42] repeated_reads: 24446, data_matched: 76553410
> > mmap1.c:234: INFO: [45] mapped: 220000, sigsegv hit: 130868, threads
> > spawned:
> > 88
> > mmap1.c:237: INFO: [45] repeated_reads: 28657, data_matched: 86358966
> > mmap1.c:234: INFO: [48] mapped: 245000, sigsegv hit: 145435, threads
> > spawned:
> > 98
> > mmap1.c:237: INFO: [48] repeated_reads: 34613, data_matched: 96820804
> > mmap1.c:234: INFO: [51] mapped: 260000, sigsegv hit: 154934, threads
> > spawned: 104
> > mmap1.c:237: INFO: [51] repeated_reads: 38042, data_matched: 102281865
> > mmap1.c:234: INFO: [54] mapped: 280000, sigsegv hit: 168403, threads
> > spawned: 112
> > mmap1.c:237: INFO: [54] repeated_reads: 44799, data_matched: 108884699
> > mmap1.c:234: INFO: [57] mapped: 305000, sigsegv hit: 188132, threads
> > spawned: 122
> > mmap1.c:237: INFO: [57] repeated_reads: 48995, data_matched: 113829351
> > mmap1.c:234: INFO: [60] mapped: 315000, sigsegv hit: 196457, threads
> > spawned: 126
> > mmap1.c:237: INFO: [60] repeated_reads: 51657, data_matched: 115444681
> > mmap1.c:234: INFO: [63] mapped: 330000, sigsegv hit: 208077, threads
> > spawned: 132
> > mmap1.c:237: INFO: [63] repeated_reads: 51657, data_matched: 118910807
> > mmap1.c:234: INFO: [66] mapped: 335000, sigsegv hit: 211847, threads
> > spawned: 134
> > mmap1.c:237: INFO: [66] repeated_reads: 51657, data_matched: 119936305
> > mmap1.c:234: INFO: [69] mapped: 355000, sigsegv hit: 225809, threads
> > spawned: 142
> > mmap1.c:237: INFO: [69] repeated_reads: 58357, data_matched: 125691672
> > mmap1.c:234: INFO: [72] mapped: 365000, sigsegv hit: 233748, threads
> > spawned: 146
> > mmap1.c:237: INFO: [72] repeated_reads: 63594, data_matched: 127682094
> > mmap1.c:234: INFO: [75] mapped: 375000, sigsegv hit: 240935, threads
> > spawned: 150
> > mmap1.c:237: INFO: [75] repeated_reads: 65813, data_matched: 130436913
> > mmap1.c:234: INFO: [78] mapped: 395000, sigsegv hit: 256994, threads
> > spawned: 158
> > mmap1.c:237: INFO: [78] repeated_reads: 68240, data_matched: 134313071
> > mmap1.c:234: INFO: [81] mapped: 400000, sigsegv hit: 260739, threads
> > spawned: 160
> > mmap1.c:237: INFO: [81] repeated_reads: 68240, data_matched: 135483078
> > mmap1.c:234: INFO: [84] mapped: 405000, sigsegv hit: 263510, threads
> > spawned: 162
> > mmap1.c:237: INFO: [84] repeated_reads: 68240, data_matched: 137744513
> > mmap1.c:234: INFO: [87] mapped: 415000, sigsegv hit: 271049, threads
> > spawned: 166
> > mmap1.c:237: INFO: [87] repeated_reads: 70071, data_matched: 140167936
> > mmap1.c:234: INFO: [90] mapped: 430000, sigsegv hit: 282504, threads
> > spawned: 172
> > mmap1.c:237: INFO: [90] repeated_reads: 74335, data_matched: 143263860
> > mmap1.c:234: INFO: [93] mapped: 435000, sigsegv hit: 286623, threads
> > spawned: 174
> > mmap1.c:237: INFO: [93] repeated_reads: 76581, data_matched: 144114430
> > mmap1.c:234: INFO: [96] mapped: 445000, sigsegv hit: 292401, threads
> > spawned: 178
> > mmap1.c:237: INFO: [96] repeated_reads: 78725, data_matched: 148160778
> > mmap1.c:234: INFO: [99] mapped: 450000, sigsegv hit: 296192, threads
> > spawned: 180
> > mmap1.c:237: INFO: [99] repeated_reads: 78725, data_matched: 149328825
> > mmap1.c:234: INFO: [102] mapped: 460000, sigsegv hit: 304280, threads
> > spawned: 184
> > mmap1.c:237: INFO: [102] repeated_reads: 78725, data_matched: 151183014
> > mmap1.c:234: INFO: [105] mapped: 465000, sigsegv hit: 308364, threads
> > spawned: 186
> > mmap1.c:237: INFO: [105] repeated_reads: 78725, data_matched: 152036389
> > Test timeouted, sending SIGKILL!
> > tst_test.c:1125: INFO: If you are running on slow machine, try
> > exporting LTP_TIMEOUT_MUL > 1
> > tst_test.c:1126: BROK: Test killed! (timeout?)
> > 
> > Test results comparison,
> > https://qa-reports.linaro.org/lkft/linux-mainline-oe/tests/ltp-mm-tests/mtest06
> > 
> > Any chance to minimize the test run time ?
> 
> Default is 3 minutes, but it appears to be getting stuck before that.
> In [1], the output stopped after ~12-15 seconds, followed by timeout.
> 
> So either timeout arrived early (which seems unlikely) or test was stuck on
> something.

I've been running it in loop over night, but no luck reproducing on my arm64 with 4.18.
Is it possible for you to try reproducing the hang and attaching gdb?

> 
> [1]
> https://qa-reports.linaro.org/lkft/linux-mainline-oe/build/v5.0-rc5/testrun/594677/log
> 
> 
> --
> Mailing list info: https://lists.linux.it/listinfo/ltp
>
diff mbox series

Patch

diff --git a/runtest/mm b/runtest/mm
index 76d2335622df..a09f39c1e02c 100644
--- a/runtest/mm
+++ b/runtest/mm
@@ -14,7 +14,7 @@  mtest01w mtest01 -p80 -w
 
 #test for race conditions
 mtest05   mmstress
-mtest06   mmap1 -x 0.05
+mtest06   mmap1
 mtest06_2 mmap2 -x 0.002 -a -p
 mtest06_3 mmap3 -x 0.002 -p
 # Remains diabled till the infinite loop problem is solved
diff --git a/testcases/kernel/mem/mtest06/mmap1.c b/testcases/kernel/mem/mtest06/mmap1.c
dissimilarity index 93%
index 80889676d96a..91c050949673 100644
--- a/testcases/kernel/mem/mtest06/mmap1.c
+++ b/testcases/kernel/mem/mtest06/mmap1.c
@@ -1,427 +1,249 @@ 
-/******************************************************************************/
-/*									      */
-/* Copyright (c) International Business Machines  Corp., 2001		      */
-/* Copyright (c) 2001 Manoj Iyer <manjo@austin.ibm.com>                       */
-/* Copyright (c) 2003 Robbie Williamson <robbiew@us.ibm.com>                  */
-/* Copyright (c) 2004 Paul Larson <plars@linuxtestproject.org>                */
-/* Copyright (c) 2007 <rsalveti@linux.vnet.ibm.com>                           */
-/* Copyright (c) 2007 Suzuki K P <suzuki@in.ibm.com>                          */
-/* Copyright (c) 2011 Cyril Hrubis <chrubis@suse.cz>                          */
-/*									      */
-/* This program is free software;  you can redistribute it and/or modify      */
-/* it under the terms of the GNU General Public License as published by       */
-/* the Free Software Foundation; either version 2 of the License, or          */
-/* (at your option) any later version.					      */
-/*									      */
-/* This program is distributed in the hope that it will be useful,	      */
-/* but WITHOUT ANY WARRANTY;  without even the implied warranty of	      */
-/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See	              */
-/* the GNU General Public License for more details.			      */
-/*									      */
-/* You should have received a copy of the GNU General Public License	      */
-/* along with this program;  if not, write to the Free Software		      */
-/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA    */
-/*									      */
-/******************************************************************************/
-/******************************************************************************/
-/* Description:	Test the LINUX memory manager. The program is aimed at        */
-/*		stressing the memory manager by simultanious map/unmap/read   */
-/*		by light weight processes, the test is scheduled to run for   */
-/*		a mininum of 24 hours.					      */
-/*									      */
-/*		Create two light weight processes X and Y.                    */
-/*		X - maps, writes  and unmap a file in a loop.	              */
-/*		Y - read from this mapped region in a loop.		      */
-/*	        read must be a success between map and unmap of the region.   */
-/*									      */
-/******************************************************************************/
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sched.h>
-#include <unistd.h>
-#include <errno.h>
-#include <sys/mman.h>
-#include <sched.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <sys/time.h>
-#include <sys/wait.h>
-#include <setjmp.h>
-#include <pthread.h>
-#include <signal.h>
-#include <string.h>
-#include "test.h"
-#include "safe_macros.h"
-
-#define DISTANT_MMAP_SIZE (64*1024*1024)
-#define OPT_MISSING(prog, opt) do { \
-	fprintf(stderr, "%s: option -%c ", prog, opt); \
-        fprintf(stderr, "requires an argument\n"); \
-	usage(prog); \
-} while (0)
-
-#define TEST_FILENAME "ashfile"
-
-static int verbose_print = 0;
-static char *volatile map_address;
-static jmp_buf jmpbuf;
-static volatile char read_lock = 0;
-static void *distant_area;
-
-char *TCID = "mmap1";
-int TST_TOTAL = 1;
-
-static void sig_handler(int signal, siginfo_t * info, void *ut)
-{
-	switch (signal) {
-	case SIGALRM:
-		tst_resm(TPASS, "Test ended, success");
-		_exit(TPASS);
-	case SIGSEGV:
-		longjmp(jmpbuf, 1);
-		break;
-	default:
-		fprintf(stderr, "Unexpected signal - %d --- exiting\n", signal);
-		_exit(TBROK);
-	}
-}
-
-/*
- * Signal handler that is active, when file is mapped, eg. we do not expect
- * SIGSEGV to be delivered.
- */
-static void sig_handler_mapped(int signal, siginfo_t * info, void *ut)
-{
-	switch (signal) {
-	case SIGALRM:
-		tst_resm(TPASS, "Test ended, success");
-		_exit(TPASS);
-	case SIGSEGV:
-		tst_resm(TINFO, "[%lu] Unexpected page fault at %p",
-			 pthread_self(), info->si_addr);
-		_exit(TFAIL);
-		break;
-	default:
-		fprintf(stderr, "Unexpected signal - %d --- exiting\n", signal);
-		_exit(TBROK);
-	}
-}
-
-int mkfile(int size)
-{
-	int fd, i;
-
-	fd = open(TEST_FILENAME,  O_RDWR | O_CREAT, 0600);
-	if (fd < 0)
-		tst_brkm(TBROK | TERRNO, NULL, "open for %s failed",
-			 TEST_FILENAME);
-
-	unlink(TEST_FILENAME);
-
-	for (i = 0; i < size; i++)
-		if (write(fd, "a", 1) == -1)
-			tst_brkm(TBROK | TERRNO, NULL, "write() failed");
-
-	if (write(fd, "\0", 1) == -1)
-		tst_brkm(TBROK | TERRNO, NULL, "write() failed");
-
-	if (fsync(fd) == -1)
-		tst_brkm(TBROK | TERRNO, NULL, "fsync() failed");
-
-	return fd;
-}
-
-void *map_write_unmap(void *ptr)
-{
-	struct sigaction sa;
-	long *args = ptr;
-	long i;
-	int j;
-
-	tst_resm(TINFO, "[%lu] - map, change contents, unmap files %ld times",
-		 pthread_self(), args[2]);
-
-	if (verbose_print)
-		tst_resm(TINFO, "map_write_unmap() arguments are: "
-			 "fd - arg[0]: %ld; "
-			 "size of file - arg[1]: %ld; "
-			 "num of map/write/unmap - arg[2]: %ld",
-			 args[0], args[1], args[2]);
-
-	for (i = 0; i < args[2]; i++) {
-		map_address = mmap(distant_area, (size_t) args[1],
-			PROT_WRITE | PROT_READ, MAP_SHARED, (int)args[0], 0);
-
-		if (map_address == (void *)-1) {
-			perror("map_write_unmap(): mmap()");
-			pthread_exit((void *)1);
-		}
-
-		while (read_lock)
-			sched_yield();
-
-		sigfillset(&sa.sa_mask);
-		sigdelset(&sa.sa_mask, SIGSEGV);
-		sa.sa_flags = SA_SIGINFO | SA_NODEFER;
-		sa.sa_sigaction = sig_handler_mapped;
-
-		if (sigaction(SIGSEGV, &sa, NULL)) {
-			perror("map_write_unmap(): sigaction()");
-			pthread_exit((void *)1);
-		}
-
-		if (verbose_print)
-			tst_resm(TINFO, "map address = %p", map_address);
-
-		for (j = 0; j < args[1]; j++) {
-			map_address[j] = 'a';
-			if (random() % 2)
-				sched_yield();
-		}
-
-		if (verbose_print)
-			tst_resm(TINFO,
-				 "[%ld] times done: of total [%ld] iterations, "
-				 "map_write_unmap():memset() content of memory = %s",
-				 i, args[2], (char *)map_address);
-
-		sigfillset(&sa.sa_mask);
-		sigdelset(&sa.sa_mask, SIGSEGV);
-		sa.sa_flags = SA_SIGINFO | SA_NODEFER;
-		sa.sa_sigaction = sig_handler;
-
-		if (sigaction(SIGSEGV, &sa, NULL)) {
-			perror("map_write_unmap(): sigaction()");
-			pthread_exit((void *)1);
-		}
-
-		if (munmap(map_address, (size_t) args[1]) == -1) {
-			perror("map_write_unmap(): mmap()");
-			pthread_exit((void *)1);
-		}
-	}
-
-	pthread_exit(NULL);
-}
-
-void *read_mem(void *ptr)
-{
-	long i;
-	long *args = ptr;
-	int j;
-
-	tst_resm(TINFO, "[%lu] - read contents of memory %p %ld times",
-		 pthread_self(), map_address, args[2]);
-
-	if (verbose_print)
-		tst_resm(TINFO, "read_mem() arguments are: "
-			 "number of reads to be performed - arg[2]: %ld; "
-			 "read from address %p", args[2], map_address);
-
-	for (i = 0; i < args[2]; i++) {
-
-		if (verbose_print)
-			tst_resm(TINFO, "read_mem() in while loop %ld times "
-				 "to go %ld times", i, args[2]);
-
-		if (setjmp(jmpbuf) == 1) {
-			read_lock = 0;
-			if (verbose_print)
-				tst_resm(TINFO, "page fault occurred due to "
-					 "a read after an unmap");
-		} else {
-			if (verbose_print) {
-				read_lock = 1;
-				tst_resm(TINFO,
-					 "read_mem(): content of memory: %s",
-					 (char *)map_address);
-				read_lock = 0;
-			}
-			for (j = 0; j < args[1]; j++) {
-				read_lock = 1;
-				if (map_address[j] != 'a')
-					pthread_exit((void *)-1);
-				read_lock = 0;
-				if (random() % 2)
-					sched_yield();
-			}
-		}
-	}
-
-	pthread_exit(NULL);
-}
-
-static void usage(char *progname)
-{
-	fprintf(stderr, "Usage: %s -d -l -s -v -x\n"
-		"\t -h help, usage message.\n"
-		"\t -l number of mmap/write/unmap     default: 1000\n"
-		"\t -s size of the file to be mmapped default: 1024 bytes\n"
-		"\t -v print more info.               default: quiet\n"
-		"\t -x test execution time            default: 24 Hrs\n",
-		progname);
-
-	exit(-1);
-}
-
-struct signal_info {
-	int signum;
-	char *signame;
-};
-
-static struct signal_info sig_info[] = {
-	{SIGHUP, "SIGHUP"},
-	{SIGINT, "SIGINT"},
-	{SIGQUIT, "SIGQUIT"},
-	{SIGABRT, "SIGABRT"},
-	{SIGBUS, "SIGBUS"},
-	{SIGSEGV, "SIGSEGV"},
-	{SIGALRM, "SIGALRM"},
-	{SIGUSR1, "SIGUSR1"},
-	{SIGUSR2, "SIGUSR2"},
-	{-1, "ENDSIG"}
-};
-
-int main(int argc, char **argv)
-{
-	int c, i;
-	int file_size;
-	int num_iter;
-	double exec_time;
-	int fd;
-	void *status;
-	pthread_t thid[2];
-	long chld_args[3];
-	extern char *optarg;
-	struct sigaction sigptr;
-	int ret;
-
-	/* set up the default values */
-	file_size = 1024;
-	num_iter = 1000;
-	exec_time = 24;
-
-	while ((c = getopt(argc, argv, "hvl:s:x:")) != -1) {
-		switch (c) {
-		case 'h':
-			usage(argv[0]);
-			break;
-		case 'l':
-			if ((num_iter = atoi(optarg)) == 0)
-				OPT_MISSING(argv[0], optopt);
-			else if (num_iter < 0)
-				printf
-				    ("WARNING: bad argument. Using default %d\n",
-				     (num_iter = 1000));
-			break;
-		case 's':
-			if ((file_size = atoi(optarg)) == 0)
-				OPT_MISSING(argv[0], optopt);
-			else if (file_size < 0)
-				printf
-				    ("WARNING: bad argument. Using default %d\n",
-				     (file_size = 1024));
-			break;
-		case 'v':
-			verbose_print = 1;
-			break;
-		case 'x':
-			exec_time = atof(optarg);
-			if (exec_time == 0)
-				OPT_MISSING(argv[0], optopt);
-			else if (exec_time < 0)
-				printf
-				    ("WARNING: bad argument. Using default %.0f\n",
-				     (exec_time = 24));
-			break;
-		default:
-			usage(argv[0]);
-			break;
-		}
-	}
-
-	/* We don't want other mmap calls to map into same area as is
-	 * used for test (mmap_address). The test expects read to return
-	 * test pattern or read must fail with SIGSEGV. Find an area
-	 * that we can use, which is unlikely to be chosen for other
-	 * mmap calls. */
-	distant_area = mmap(0, DISTANT_MMAP_SIZE, PROT_WRITE | PROT_READ,
-		MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
-	if (distant_area == (void *)-1)
-		tst_brkm(TBROK | TERRNO, NULL, "distant_area: mmap()");
-	SAFE_MUNMAP(NULL, distant_area, (size_t)DISTANT_MMAP_SIZE);
-	distant_area += DISTANT_MMAP_SIZE / 2;
-
-	if (verbose_print)
-		tst_resm(TINFO, "Input parameters are: File size:  %d; "
-			 "Scheduled to run:  %lf hours; "
-			 "Number of mmap/write/read:  %d",
-			 file_size, exec_time, num_iter);
-
-	alarm(exec_time * 3600);
-
-	/* Do not mask SIGSEGV, as we are interested in handling it. */
-	sigptr.sa_sigaction = sig_handler;
-	sigfillset(&sigptr.sa_mask);
-	sigdelset(&sigptr.sa_mask, SIGSEGV);
-	sigptr.sa_flags = SA_SIGINFO | SA_NODEFER;
-
-	for (i = 0; sig_info[i].signum != -1; i++) {
-		if (sigaction(sig_info[i].signum, &sigptr, NULL) == -1) {
-			perror("man(): sigaction()");
-			fprintf(stderr,
-				"could not set handler for %s, errno = %d\n",
-				sig_info[i].signame, errno);
-			exit(-1);
-		}
-	}
-
-	tst_tmpdir();
-
-	for (;;) {
-		if ((fd = mkfile(file_size)) == -1)
-			tst_brkm(TBROK, NULL,
-				 "main(): mkfile(): Failed to create temp file");
-
-		if (verbose_print)
-			tst_resm(TINFO, "Tmp file created");
-
-		chld_args[0] = fd;
-		chld_args[1] = file_size;
-		chld_args[2] = num_iter;
-
-		if ((ret =
-		     pthread_create(&thid[0], NULL, map_write_unmap,
-				    chld_args)))
-			tst_brkm(TBROK, NULL, "main(): pthread_create(): %s",
-				 strerror(ret));
-
-		tst_resm(TINFO, "created writing thread[%lu]", thid[0]);
-
-		if ((ret = pthread_create(&thid[1], NULL, read_mem, chld_args)))
-			tst_brkm(TBROK, NULL, "main(): pthread_create(): %s",
-				 strerror(ret));
-
-		tst_resm(TINFO, "created reading thread[%lu]", thid[1]);
-
-		for (i = 0; i < 2; i++) {
-			if ((ret = pthread_join(thid[i], &status)))
-				tst_brkm(TBROK, NULL,
-					 "main(): pthread_join(): %s",
-					 strerror(ret));
-
-			if (status)
-				tst_brkm(TFAIL, NULL,
-					 "thread [%lu] - process exited "
-					 "with %ld", thid[i], (long)status);
-		}
-
-		close(fd);
-	}
-
-	tst_rmdir();
-
-	exit(0);
-}
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2018 Jan Stancek. All rights reserved.
+ */
+/*
+ * Test: Spawn 2 threads. First thread maps, writes and unmaps
+ * an area. Second thread tries to read from it. Second thread
+ * races against first thread. There is no synchronization
+ * between threads, but each mmap/munmap increases a counter
+ * that is checked to determine when has read occurred. If a read
+ * hit SIGSEGV in between mmap/munmap it is a failure. If a read
+ * between mmap/munmap worked, then its value must match expected
+ * value.
+ */
+#include <errno.h>
+#include <float.h>
+#include <pthread.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "tst_test.h"
+#include "tst_safe_pthread.h"
+
+#define DISTANT_MMAP_SIZE (64*1024*1024)
+#define TEST_FILENAME "ashfile"
+
+/* seconds remaining before reaching timeout */
+#define STOP_THRESHOLD 10
+
+#define PROGRESS_SEC 3
+
+static int file_size = 1024;
+static int num_iter = 5000;
+static float exec_time = 0.05; /* default is 3 min */
+
+static void *distant_area;
+static char *str_exec_time;
+static jmp_buf jmpbuf;
+static volatile unsigned char *map_address;
+static unsigned long page_sz;
+
+static unsigned long mapped_sigsegv_count;
+static unsigned long map_count;
+static unsigned long threads_spawned;
+static unsigned long data_matched;
+static unsigned long repeated_reads;
+
+/* sequence id for each map/unmap performed */
+static int mapcnt, unmapcnt;
+/* stored sequence id before making read attempt */
+static int br_map, br_unmap;
+
+static struct tst_option options[] = {
+	{"x:", &str_exec_time, "Exec time (hours)"},
+	{NULL, NULL, NULL}
+};
+
+/* compare "before read" counters  with "after read" counters */
+static inline int was_area_mapped(int br_m, int br_u, int ar_m, int ar_u)
+{
+	return (br_m == ar_m && br_u == ar_u && br_m > br_u);
+}
+
+static void sig_handler(int signal, siginfo_t *info,
+	LTP_ATTRIBUTE_UNUSED void *ut)
+{
+	int ar_m, ar_u;
+
+	switch (signal) {
+	case SIGSEGV:
+		/* if we hit SIGSEGV between map/unmap, something is wrong */
+		ar_u = tst_atomic_load(&unmapcnt);
+		ar_m = tst_atomic_load(&mapcnt);
+		if (was_area_mapped(br_map, br_unmap, ar_m, ar_u)) {
+			tst_res(TFAIL, "got sigsegv while mapped");
+			_exit(TFAIL);
+		}
+
+		mapped_sigsegv_count++;
+		longjmp(jmpbuf, 1);
+		break;
+	default:
+		tst_res(TFAIL, "Unexpected signal - %d, addr: %p, exiting\n",
+			signal, info->si_addr);
+		_exit(TBROK);
+	}
+}
+
+void *map_write_unmap(void *ptr)
+{
+	long *args = ptr;
+	void *tmp;
+	int i, j;
+
+	for (i = 0; i < num_iter; i++) {
+		map_address = SAFE_MMAP(distant_area,
+			(size_t) file_size, PROT_WRITE | PROT_READ,
+			MAP_SHARED, (int)args[0], 0);
+		tst_atomic_inc(&mapcnt);
+
+		for (j = 0; j < file_size; j++)
+			map_address[j] = 'b';
+
+		tmp = (void *)map_address;
+		tst_atomic_inc(&unmapcnt);
+		SAFE_MUNMAP(tmp, file_size);
+
+		map_count++;
+	}
+
+	return NULL;
+}
+
+void *read_mem(LTP_ATTRIBUTE_UNUSED void *ptr)
+{
+	int i, j, ar_map, ar_unmap;
+	unsigned char c;
+
+	for (i = 0; i < num_iter; i++) {
+		if (setjmp(jmpbuf) == 1)
+			continue;
+
+		for (j = 0; j < file_size; j++) {
+read_again:
+			br_map = tst_atomic_load(&mapcnt);
+			br_unmap = tst_atomic_load(&unmapcnt);
+
+			c = map_address[j];
+
+			ar_unmap = tst_atomic_load(&unmapcnt);
+			ar_map = tst_atomic_load(&mapcnt);
+
+			/*
+			 * Read above is racing against munmap and mmap
+			 * in other thread. While the address might be valid
+			 * the mapping could be in various stages of being
+			 * 'ready'. We only check the value, if we can be sure
+			 * read hapenned in between single mmap and munmap as
+			 * observed by first thread.
+			 */
+			if (was_area_mapped(br_map, br_unmap, ar_map,
+				ar_unmap)) {
+				switch (c) {
+				case 'a':
+					repeated_reads++;
+					goto read_again;
+				case 'b':
+					data_matched++;
+					break;
+				default:
+					tst_res(TFAIL, "value[%d] is %c", j, c);
+					break;
+				}
+			}
+		}
+	}
+
+	return NULL;
+}
+
+int mkfile(int size)
+{
+	int fd, i;
+
+	fd = SAFE_OPEN(TEST_FILENAME, O_RDWR | O_CREAT, 0600);
+	SAFE_UNLINK(TEST_FILENAME);
+
+	for (i = 0; i < size; i++)
+		SAFE_WRITE(1, fd, "a", 1);
+	SAFE_WRITE(1, fd, "\0", 1);
+
+	if (fsync(fd) == -1)
+		tst_brk(TBROK | TERRNO, "fsync()");
+
+	return fd;
+}
+
+static void setup(void)
+{
+	struct sigaction sigptr;
+
+	page_sz = getpagesize();
+
+	/*
+	 * Used as hint for mmap thread, so it doesn't interfere
+	 * with other potential (temporary) mappings from libc
+	 */
+	distant_area = SAFE_MMAP(0, DISTANT_MMAP_SIZE, PROT_WRITE | PROT_READ,
+			MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+	SAFE_MUNMAP(distant_area, (size_t)DISTANT_MMAP_SIZE);
+	distant_area += DISTANT_MMAP_SIZE / 2;
+
+	if (tst_parse_float(str_exec_time, &exec_time, 0, FLT_MAX)) {
+		tst_brk(TBROK, "Invalid number for exec_time '%s'",
+			str_exec_time);
+	}
+
+	sigptr.sa_sigaction = sig_handler;
+	sigemptyset(&sigptr.sa_mask);
+	sigptr.sa_flags = SA_SIGINFO | SA_NODEFER;
+	SAFE_SIGACTION(SIGSEGV, &sigptr, NULL);
+
+	tst_set_timeout((int)(exec_time * 3600));
+}
+
+static void run(void)
+{
+	pthread_t thid[2];
+	long chld_args[1];
+	int remaining = tst_timeout_remaining();
+	int elapsed = 0;
+
+	while (tst_timeout_remaining() > STOP_THRESHOLD) {
+		int fd = mkfile(file_size);
+
+		tst_atomic_store(0, &mapcnt);
+		tst_atomic_store(0, &unmapcnt);
+
+		chld_args[0] = fd;
+		SAFE_PTHREAD_CREATE(&thid[0], NULL, map_write_unmap, chld_args);
+		SAFE_PTHREAD_CREATE(&thid[1], NULL, read_mem, chld_args);
+		threads_spawned += 2;
+
+		SAFE_PTHREAD_JOIN(thid[0], NULL);
+		SAFE_PTHREAD_JOIN(thid[1], NULL);
+
+		close(fd);
+
+		if (remaining - tst_timeout_remaining() > PROGRESS_SEC) {
+			remaining = tst_timeout_remaining();
+			elapsed += PROGRESS_SEC;
+			tst_res(TINFO, "[%d] mapped: %lu, sigsegv hit: %lu, "
+				"threads spawned: %lu",	elapsed, map_count,
+				mapped_sigsegv_count, threads_spawned);
+			tst_res(TINFO, "[%d] repeated_reads: %ld, "
+				"data_matched: %lu", elapsed, repeated_reads,
+				data_matched);
+		}
+	}
+	tst_res(TPASS, "System survived.");
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.setup = setup,
+	.options = options,
+	.needs_tmpdir = 1,
+};