Message ID | 0e62adebbb4e5c8e3aa28440f860234b937d3e56.1543219161.git.jstancek@redhat.com |
---|---|
State | Accepted |
Headers | show |
Series | [v2] mtest06/mmap1: rewrite to newlib | expand |
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
----- 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 >
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
----- 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
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
----- 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
----- 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 --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, +};
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%)