[LTP] [PATCH v7 1/1] mmapstress01: refactor to tst_test framework
Richard Palethorpe
rpalethorpe@suse.de
Tue Nov 8 12:19:38 CET 2022
Hello,
Richard Palethorpe <rpalethorpe@suse.de> writes:
> Hello,
>
> Edward Liaw via ltp <ltp@lists.linux.it> writes:
>
>> Use ltp framework and apply make check corrections. Reorder functions
>> and variables. Use safe macros.
>> Drop leavefile option.
>> Build tests with FILE_OFFSET_BITS=64 instead of doing LARGE_FILE checks
>> to switch between 32 and 64 bit types and syscalls.
>> Define fsize bounds by file offset bits.
>> Move sighandler to setup and remove sig blocks.
>> Add option to specify pattern.
>> Set default nprocs to ncpus with min of 1 and max of 20.
>>
>> Signed-off-by: Edward Liaw <edliaw@google.com>
>
> Reviewed-by: Richard Palethorpe <rpalethorpe@suse.com>
>
> Will merge this today if the CI is happy and nobody comments.
Merged, thanks!
>
>> ---
>> testcases/kernel/mem/mmapstress/Makefile | 2 +
>> .../kernel/mem/mmapstress/mmapstress01.c | 886 +++++-------------
>> 2 files changed, 261 insertions(+), 627 deletions(-)
>>
>> diff --git a/testcases/kernel/mem/mmapstress/Makefile b/testcases/kernel/mem/mmapstress/Makefile
>> index 744f099d8..b30bd34b8 100644
>> --- a/testcases/kernel/mem/mmapstress/Makefile
>> +++ b/testcases/kernel/mem/mmapstress/Makefile
>> @@ -5,3 +5,5 @@ top_srcdir ?= ../../../..
>>
>> include $(top_srcdir)/include/mk/testcases.mk
>> include $(top_srcdir)/include/mk/generic_leaf_target.mk
>> +
>> +mmapstress01: CFLAGS += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
>> diff --git a/testcases/kernel/mem/mmapstress/mmapstress01.c b/testcases/kernel/mem/mmapstress/mmapstress01.c
>> index f425c223d..ac1b77387 100644
>> --- a/testcases/kernel/mem/mmapstress/mmapstress01.c
>> +++ b/testcases/kernel/mem/mmapstress/mmapstress01.c
>> @@ -1,23 +1,24 @@
>> -/* IBM Corporation */
>> -/* 01/02/2003 Port to LTP avenkat@us.ibm.com */
>> -/* 06/30/2001 Port to Linux nsharoff@us.ibm.com */
>> +// SPDX-License-Identifier: GPL-2.0-or-later
>> /*
>> - * Copyright (c) International Business Machines Corp., 2003
>> - *
>> - *
>> - * 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.
>> + * Copyright (c) International Business Machines Corp., 2003
>> + * 01/02/2003 Port to LTP avenkat@us.ibm.com
>> + * 06/30/2001 Port to Linux nsharoff@us.ibm.com
>> + * 10/03/2022 Refactor to LTP framework edliaw@google.com
>> + */
>> +/*\
>> + * [Description]
>> + * This test stresses mmaps, without dealing with fragments or anything!
>> + * It forks a specified number of children,
>> + * all of whom mmap the same file, make a given number of accesses
>> + * to random pages in the map (reading & writing and comparing data).
>> + * Then the child exits and the parent forks another to take its place.
>> + * Each time a child is forked, it stats the file and maps the full
>> + * length of the file.
>> *
>> - * 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
>> + * This program continues to run until it either receives a SIGINT,
>> + * or times out (if a timeout value is specified). When either of
>> + * these things happens, it cleans up its kids, then checks the
>> + * file to make sure it has the correct data.
>> */
>>
>> #define _GNU_SOURCE 1
>> @@ -32,517 +33,159 @@
>> #include <errno.h>
>> #include <sys/types.h>
>> #include <limits.h>
>> -/***** LTP Port *****/
>> -#include "test.h"
>> -#define FAILED 0
>> -#define PASSED 1
>> -
>> -int local_flag = PASSED;
>> -char *TCID = "mmapstress01"; //tmnoextend
>> -FILE *temp;
>> -int TST_TOTAL = 1;
>> -
>> -int anyfail();
>> -void ok_exit();
>> -/***** ** ** *****/
>> -
>> -/*
>> - * This test stresses mmaps, without dealing with fragments or anything!
>> - * It forks a specified number of children,
>> - * all of whom mmap the same file, make a given number of accesses
>> - * to random pages in the map (reading & writing and comparing data).
>> - * Then the child exits and the parent forks another to take its place.
>> - * Each time a child is forked, it stats the file and maps the full
>> - * length of the file.
>> - *
>> - * This program continues to run until it either receives a SIGINT,
>> - * or times out (if a timeout value is specified). When either of
>> - * these things happens, it cleans up its kids, then checks the
>> - * file to make sure it has the correct data.
>> - *
>> - * usage:
>> - * tmnoextend -p nprocs [-t minutes -f filesize -S sparseoffset
>> - * -r -o -m -l -d]
>> - * where:
>> - * -p nprocs - specifies the number of mapping children
>> - * to create. (nprocs + 1 children actually
>> - * get created, since one is the writer child)
>> - * -t minutes - specifies minutes to run. If not specified,
>> - * default is to run forever until a SIGINT
>> - * is received.
>> - * -f filesize - initial filesize (defaults to FILESIZE)
>> - * -S sparseoffset - when non-zero, causes a sparse area to
>> - * be left before the data, meaning that the
>> - * actual initial file size is sparseoffset +
>> - * filesize. Useful for testing large files.
>> - * (default is 0).
>> - * -r - randomize number of pages map children check.
>> - * (random % MAXLOOPS). If not specified, each
>> - * child checks MAXLOOPS pages.
>> - * -o - randomize offset of file to map. (default is 0)
>> - * -m - do random msync/fsyncs as well
>> - * -l - if set, the output file is not removed on
>> - * program exit.
>> - * -d - enable debug output
>> - *
>> - * Compile with -DLARGE_FILE to enable file sizes > 2 GB.
>> - */
>> -
>> +#include <float.h>
>> +#include "tst_test.h"
>> +
>> +#if _FILE_OFFSET_BITS == 64
>> +# define FSIZE_MIN LONG_MIN
>> +# define FSIZE_MAX LONG_MAX
>> +#else
>> +# define FSIZE_MIN INT_MIN
>> +# define FSIZE_MAX INT_MAX
>> +#endif
>> #define MAXLOOPS 500 /* max pages for map children to write */
>> -#define FILESIZE 4096 /* initial filesize set up by parent */
>> +#define TEST_FILE "mmapstress01.out"
>>
>> #ifdef roundup
>> #undef roundup
>> #endif
>> #define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
>>
>> -extern time_t time(time_t *);
>> -extern char *ctime(const time_t *);
>> -extern void *malloc(size_t);
>> -extern long lrand48(void);
>> -extern void srand(unsigned);
>> -extern void srand48(long);
>> -extern int rand(void);
>> -extern int atoi(const char *);
>> -
>> -char *usage =
>> - "-p nprocs [-t minutes -f filesize -S sparseoffset -r -o -m -l -d]";
>> -
>> -typedef unsigned char uchar_t;
>> -#define SIZE_MAX UINT_MAX
>> -
>> -unsigned int initrand(void);
>> -void finish(int sig);
>> -void child_mapper(char *file, unsigned procno, unsigned nprocs);
>> -int fileokay(char *file, uchar_t * expbuf);
>> -int finished = 0;
>> -int leavefile = 0;
>> -
>> -int debug = 0;
>> -#ifdef LARGE_FILE
>> -off64_t filesize = FILESIZE;
>> -off64_t sparseoffset = 0;
>> -#else /* LARGE_FILE */
>> -off_t filesize = FILESIZE;
>> -off_t sparseoffset = 0;
>> -#endif /* LARGE_FILE */
>> -unsigned randloops = 0;
>> -unsigned dosync = 0;
>> -unsigned do_offset = 0;
>> -unsigned pattern = 0;
>> -
>> -int main(int argc, char *argv[])
>> +static unsigned int initrand(void);
>> +static void sighandler(int);
>> +
>> +static char *debug;
>> +static char *do_sync;
>> +static char *do_offset;
>> +static char *opt_filesize;
>> +static char *opt_nprocs;
>> +static char *opt_pattern;
>> +static char *opt_sparseoffset;
>> +static char *randloops;
>> +
>> +static int fd;
>> +static volatile int finished;
>> +static int nprocs;
>> +static long long filesize = 4096;
>> +static long long sparseoffset;
>> +static size_t pagesize;
>> +static int pattern;
>> +
>> +static struct tst_option options[] = {
>> + {"d", &debug, "Enable debug output"},
>> + {"f:", &opt_filesize, "Initial filesize (default 4096)"},
>> + {"m", &do_sync, "Do random msync/fsyncs as well"},
>> + {"o", &do_offset, "Randomize the offset of file to map"},
>> + {"p:", &opt_nprocs,
>> + "Number of mapping children to create (default 1 < ncpus < 20)"},
>> + {"P:", &opt_pattern,
>> + "Use a fixed pattern (default random)"},
>> + {"r", &randloops,
>> + "Randomize number of pages map children check (random % 500), "
>> + "otherwise each child checks 500 pages"},
>> + {"S:", &opt_sparseoffset,
>> + "When non-zero, causes the sparse area to be left before the data, "
>> + "so that the actual initial filesize is sparseoffset + filesize "
>> + "(default 0)"},
>> + {},
>> +};
>> +
>> +static void setup(void)
>> {
>> - char *progname;
>> - int fd;
>> - int c;
>> - extern char *optarg;
>> - unsigned nprocs = 0;
>> - unsigned procno;
>> - pid_t *pidarray = NULL;
>> - pid_t pid;
>> - uchar_t *buf = NULL;
>> - unsigned int seed;
>> - int pagesize = sysconf(_SC_PAGE_SIZE);
>> - float alarmtime = 0;
>> struct sigaction sa;
>> - unsigned i;
>> - int write_cnt;
>> - uchar_t data;
>> - int no_prob = 0;
>> - int wait_stat;
>> - time_t t;
>> -#ifdef LARGE_FILE
>> - off64_t bytes_left;
>> -#else /* LARGE_FILE */
>> - off_t bytes_left;
>> -#endif /* LARGE_FILE */
>> - const char *filename = "mmapstress01.out";
>> -
>> - progname = *argv;
>> - tst_tmpdir();
>> - if (argc < 2) {
>> - tst_brkm(TBROK, NULL, "usage: %s %s", progname, usage);
>> - }
>> -
>> - while ((c = getopt(argc, argv, "S:omdlrf:p:t:")) != -1) {
>> - switch (c) {
>> - case 'd':
>> - debug = 1;
>> - break;
>> - case 't':
>> - alarmtime = atof(optarg) * 60;
>> - break;
>> - case 'p':
>> - nprocs = atoi(optarg);
>> - break;
>> - case 'l':
>> - leavefile = 1;
>> - break;
>> - case 'f':
>> -#ifdef LARGE_FILE
>> - filesize = atoll(optarg);
>> -#else /* LARGE_FILE */
>> - filesize = atoi(optarg);
>> -#endif /* LARGE_FILE */
>> - if (filesize < 0) {
>> - (void)fprintf(stderr, "error: negative "
>> - "filesize\n");
>> - anyfail();
>> - }
>> - break;
>> - case 'r':
>> - randloops = 1;
>> - break;
>> - case 'm':
>> - dosync = 1;
>> - break;
>> - case 'o':
>> - do_offset = 1;
>> - break;
>> - case 'S':
>> -#ifdef LARGE_FILE
>> - sparseoffset = atoll(optarg);
>> -#else /* LARGE_FILE */
>> - sparseoffset = atoi(optarg);
>> -#endif /* LARGE_FILE */
>> - if (sparseoffset % pagesize != 0) {
>> - fprintf(stderr,
>> - "sparseoffset must be pagesize multiple\n");
>> - anyfail();
>> - }
>> - break;
>> - default:
>> - (void)fprintf(stderr, "usage: %s %s\n", progname,
>> - usage);
>> - tst_exit();
>> - }
>> - }
>> -
>> - /* nprocs is >= 0 since it's unsigned */
>> - if (nprocs > 255) {
>> - (void)fprintf(stderr, "invalid nprocs %d - (range 0-255)\n",
>> - nprocs);
>> - anyfail();
>> - }
>> -
>> - (void)time(&t);
>> -
>> - seed = initrand();
>> - pattern = seed & 0xff;
>> -
>> - if (debug) {
>> -#ifdef LARGE_FILE
>> - (void)printf("creating file <%s> with %Ld bytes, pattern %d\n",
>> - filename, filesize, pattern);
>> -#else /* LARGE_FILE */
>> - (void)printf("creating file <%s> with %ld bytes, pattern %d\n",
>> - filename, filesize, pattern);
>> -#endif /* LARGE_FILE */
>> - if (alarmtime)
>> - (void)printf("running for %f minutes\n",
>> - alarmtime / 60);
>> - else
>> - (void)printf("running with no time limit\n");
>> - }
>>
>> - /*
>> - * Plan for death by signal. User may have specified
>> - * a time limit, in which set an alarm and catch SIGALRM.
>> - * Also catch and cleanup with SIGINT.
>> - */
>> - sa.sa_handler = finish;
>> + sa.sa_handler = sighandler;
>> sa.sa_flags = 0;
>> - if (sigemptyset(&sa.sa_mask)) {
>> - perror("sigemptyset error");
>> - goto cleanup;
>> - }
>> -
>> - if (sigaction(SIGINT, &sa, 0) == -1) {
>> - perror("sigaction error SIGINT");
>> - goto cleanup;
>> - }
>> - if (sigaction(SIGQUIT, &sa, 0) == -1) {
>> - perror("sigaction error SIGQUIT");
>> - goto cleanup;
>> - }
>> - if (sigaction(SIGTERM, &sa, 0) == -1) {
>> - perror("sigaction error SIGTERM");
>> - goto cleanup;
>> - }
>> -
>> - if (alarmtime) {
>> - if (sigaction(SIGALRM, &sa, 0) == -1) {
>> - perror("sigaction error");
>> - goto cleanup;
>> - }
>> - (void)alarm(alarmtime);
>> - }
>> -#ifdef LARGE_FILE
>> - if ((fd = open64(filename, O_CREAT | O_TRUNC | O_RDWR, 0664)) == -1) {
>> -#else /* LARGE_FILE */
>> - if ((fd = open(filename, O_CREAT | O_TRUNC | O_RDWR, 0664)) == -1) {
>> -#endif /* LARGE_FILE */
>> - perror("open error");
>> - anyfail();
>> - }
>> -
>> - if ((buf = malloc(pagesize)) == NULL
>> - || (pidarray = malloc(nprocs * sizeof(pid_t))) == NULL) {
>> - perror("malloc error");
>> - anyfail();
>> - }
>> -
>> - for (i = 0; i < nprocs; i++)
>> - *(pidarray + i) = 0;
>> -
>> - for (i = 0, data = 0; i < pagesize; i++) {
>> - *(buf + i) = (data + pattern) & 0xff;
>> - if (++data == nprocs)
>> - data = 0;
>> - }
>> -#ifdef LARGE_FILE
>> - if (lseek64(fd, sparseoffset, SEEK_SET) < 0) {
>> -#else /* LARGE_FILE */
>> - if (lseek(fd, sparseoffset, SEEK_SET) < 0) {
>> -#endif /* LARGE_FILE */
>> - perror("lseek");
>> - anyfail();
>> - }
>> - for (bytes_left = filesize; bytes_left; bytes_left -= c) {
>> - write_cnt = MIN(pagesize, (int)bytes_left);
>> - if ((c = write(fd, buf, write_cnt)) != write_cnt) {
>> - if (c == -1) {
>> - perror("write error");
>> - } else {
>> - (void)fprintf(stderr, "write: wrote %d of %d "
>> - "bytes\n", c, write_cnt);
>> - }
>> - (void)close(fd);
>> - (void)unlink(filename);
>> - anyfail();
>> - }
>> - }
>> -
>> - (void)close(fd);
>> -
>> - /*
>> - * Fork off mmap children.
>> - */
>> - for (procno = 0; procno < nprocs; procno++) {
>> - switch (pid = fork()) {
>> -
>> - case -1:
>> - perror("fork error");
>> - goto cleanup;
>> -
>> - case 0:
>> - child_mapper(filename, procno, nprocs);
>> - exit(0);
>> -
>> - default:
>> - pidarray[procno] = pid;
>> - }
>> - }
>> -
>> - /*
>> - * Now wait for children and refork them as needed.
>> - */
>> -
>> - while (!finished) {
>> - pid = wait(&wait_stat);
>> - /*
>> - * Block signals while processing child exit.
>> - */
>> -
>> - if (sighold(SIGALRM) || sighold(SIGINT)) {
>> - perror("sighold error");
>> - goto cleanup;
>> - }
>> -
>> - if (pid != -1) {
>> - /*
>> - * Check exit status, then refork with the
>> - * appropriate procno.
>> - */
>> - if (!WIFEXITED(wait_stat)
>> - || WEXITSTATUS(wait_stat) != 0) {
>> - (void)fprintf(stderr, "child exit with err "
>> - "<x%x>\n", wait_stat);
>> - goto cleanup;
>> - }
>> - for (i = 0; i < nprocs; i++)
>> - if (pid == pidarray[i])
>> - break;
>> - if (i == nprocs) {
>> - (void)fprintf(stderr, "unknown child pid %d, "
>> - "<x%x>\n", pid, wait_stat);
>> - goto cleanup;
>> - }
>> -
>> - if ((pid = fork()) == -1) {
>> - perror("fork error");
>> - pidarray[i] = 0;
>> - goto cleanup;
>> - } else if (pid == 0) { /* child */
>> - child_mapper(filename, i, nprocs);
>> - exit(0);
>> - } else
>> - pidarray[i] = pid;
>> - } else {
>> - /*
>> - * wait returned an error. If EINTR, then
>> - * normal finish, else it's an unexpected
>> - * error...
>> - */
>> - if (errno != EINTR || !finished) {
>> - perror("unexpected wait error");
>> - goto cleanup;
>> - }
>> - }
>> - if (sigrelse(SIGALRM) || sigrelse(SIGINT)) {
>> - perror("sigrelse error");
>> - goto cleanup;
>> - }
>> - }
>> -
>> - /*
>> - * Finished! Check the file for sanity, then kill all
>> - * the children and done!.
>> - */
>> -
>> - if (sighold(SIGALRM)) {
>> - perror("sighold error");
>> - goto cleanup;
>> - }
>> - (void)alarm(0);
>> - no_prob = 1;
>> -
>> -cleanup:
>> - for (i = 0; i < nprocs; i++)
>> - (void)kill(pidarray[i], SIGKILL);
>> -
>> - while (wait(&wait_stat) != -1 || errno != ECHILD)
>> - continue;
>> -
>> - if (no_prob) { /* only check file if no errors */
>> - if (!fileokay(filename, buf)) {
>> - (void)fprintf(stderr, "file data incorrect!\n");
>> - (void)printf(" leaving file <%s>\n", filename);
>> - /***** LTP Port *****/
>> - local_flag = FAILED;
>> - anyfail();
>> - /***** ** *****/
>> - } else {
>> - (void)printf("file data okay\n");
>> - if (!leavefile)
>> - (void)unlink(filename);
>> - }
>> - } else
>> - (void)printf(" leaving file <%s>\n", filename);
>> + SAFE_SIGEMPTYSET(&sa.sa_mask);
>> + SAFE_SIGACTION(SIGINT, &sa, 0);
>> + SAFE_SIGACTION(SIGQUIT, &sa, 0);
>> + SAFE_SIGACTION(SIGTERM, &sa, 0);
>> + SAFE_SIGACTION(SIGALRM, &sa, 0);
>> +
>> + pagesize = sysconf(_SC_PAGE_SIZE);
>> +
>> + if (tst_parse_filesize(opt_filesize, &filesize, 0, FSIZE_MAX))
>> + tst_brk(TBROK, "invalid initial filesize '%s'", opt_filesize);
>> +
>> + if (tst_parse_filesize(opt_sparseoffset, &sparseoffset, FSIZE_MIN, FSIZE_MAX))
>> + tst_brk(TBROK, "invalid sparse offset '%s'", opt_sparseoffset);
>> + if (sparseoffset % pagesize != 0)
>> + tst_brk(TBROK, "sparseoffset must be pagesize multiple");
>> +
>> + if (tst_parse_int(opt_nprocs, &nprocs, 0, 255))
>> + tst_brk(TBROK, "invalid number of mapping children '%s'",
>> + opt_nprocs);
>> + if (!opt_nprocs)
>> + nprocs = MAX(MIN(tst_ncpus() - 1L, 20L), 1L);
>> +
>> + if (tst_parse_int(opt_pattern, &pattern, 0, 255))
>> + tst_brk(TBROK, "invalid pattern '%s'", opt_pattern);
>> + if (!opt_pattern)
>> + pattern = initrand() & 0xff;
>> +
>> + tst_res(TINFO, "creating file <%s> with %lld bytes, pattern %d",
>> + TEST_FILE, filesize, pattern);
>> +}
>>
>> - (void)time(&t);
>> - //(void)printf("%s: Finished %s", argv[0], ctime(&t)); LTP Port
>> - ok_exit();
>> - tst_exit();
>> +static void cleanup(void)
>> +{
>> + if (fd > 0)
>> + SAFE_CLOSE(fd);
>> }
>>
>> /*
>> - * Child process that reads/writes map. The child stats the file
>> - * to determine the size, maps the size of the file, then reads/writes
>> - * its own locations on random pages of the map (its locations being
>> - * determined based on nprocs & procno). After a specific number of
>> - * iterations, it exits.
>> + * Child process that reads/writes map. The child stats the file
>> + * to determine the size, maps the size of the file, then reads/writes
>> + * its own locations on random pages of the map (its locations being
>> + * determined based on nprocs & procno). After a specific number of
>> + * iterations, it exits.
>> */
>> -void child_mapper(char *file, unsigned procno, unsigned nprocs)
>> +static void child_mapper(char *file, unsigned int procno, unsigned int nprocs)
>> {
>> -#ifdef LARGE_FILE
>> - struct stat64 statbuf;
>> - off64_t filesize;
>> - off64_t offset;
>> -#else /* LARGE_FILE */
>> struct stat statbuf;
>> off_t filesize;
>> off_t offset;
>> -#endif /* LARGE_FILE */
>> size_t validsize;
>> size_t mapsize;
>> char *maddr = NULL, *paddr;
>> - int fd;
>> - size_t pagesize = sysconf(_SC_PAGE_SIZE);
>> - unsigned randpage;
>> + unsigned int randpage;
>> unsigned int seed;
>> - unsigned loopcnt;
>> - unsigned nloops;
>> - unsigned mappages;
>> - unsigned i;
>> -
>> - seed = initrand(); /* initialize random seed */
>> -
>> -#ifdef LARGE_FILE
>> - if (stat64(file, &statbuf) == -1) {
>> -#else /* LARGE_FILE */
>> - if (stat(file, &statbuf) == -1) {
>> -#endif /* LARGE_FILE */
>> - perror("stat error");
>> - anyfail();
>> - }
>> + unsigned int loopcnt;
>> + unsigned int nloops;
>> + unsigned int mappages;
>> + unsigned int i;
>> +
>> + seed = initrand();
>> +
>> + SAFE_STAT(file, &statbuf);
>> filesize = statbuf.st_size;
>>
>> -#ifdef LARGE_FILE
>> - if ((fd = open64(file, O_RDWR)) == -1) {
>> -#else /* LARGE_FILE */
>> - if ((fd = open(file, O_RDWR)) == -1) {
>> -#endif /* LARGE_FILE */
>> - perror("open error");
>> - anyfail();
>> - }
>> + fd = SAFE_OPEN(file, O_RDWR);
>>
>> - if (statbuf.st_size - sparseoffset > SIZE_MAX) {
>> - fprintf(stderr, "size_t overflow when setting up map\n");
>> - anyfail();
>> - }
>> + if (statbuf.st_size - sparseoffset > UINT_MAX)
>> + tst_brk(TBROK, "size_t overflow when setting up map");
>> mapsize = (size_t) (statbuf.st_size - sparseoffset);
>> mappages = roundup(mapsize, pagesize) / pagesize;
>> offset = sparseoffset;
>> if (do_offset) {
>> int pageoffset = lrand48() % mappages;
>> int byteoffset = pageoffset * pagesize;
>> +
>> offset += byteoffset;
>> mapsize -= byteoffset;
>> mappages -= pageoffset;
>> }
>> nloops = (randloops) ? (lrand48() % MAXLOOPS) : MAXLOOPS;
>>
>> - if (debug) {
>> -#ifdef LARGE_FILE
>> - (void)printf("child %d (pid %ld): seed %d, fsize %Ld, "
>> - "mapsize %d, off %Ld, loop %d\n",
>> - procno, getpid(), seed, filesize, mapsize,
>> - offset / pagesize, nloops);
>> -#else /* LARGE_FILE */
>> - (void)printf("child %d (pid %d): seed %d, fsize %ld, "
>> - "mapsize %ld, off %ld, loop %d\n",
>> - procno, getpid(), seed, filesize, (long)mapsize,
>> - offset / pagesize, nloops);
>> -#endif /* LARGE_FILE */
>> - }
>> -#ifdef LARGE_FILE
>> - if ((maddr = mmap64(0, mapsize, PROT_READ | PROT_WRITE, MAP_SHARED,
>> - fd, offset)) == (caddr_t) - 1) {
>> -#else /* LARGE_FILE */
>> - if ((maddr = mmap(0, mapsize, PROT_READ | PROT_WRITE, MAP_SHARED,
>> - fd, offset)) == (caddr_t) - 1) {
>> -#endif /* LARGE_FILE */
>> - perror("mmap error");
>> - anyfail();
>> - }
>> + if (debug)
>> + tst_res(TINFO, "child %d (pid %d): seed %d, fsize %lld, mapsize %ld, off %lld, loop %d",
>> + procno, getpid(), seed, (long long)filesize,
>> + (long)mapsize, (long long)offset / pagesize, nloops);
>>
>> - (void)close(fd);
>> + maddr = SAFE_MMAP(0, mapsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
>> + offset);
>> + SAFE_CLOSE(fd);
>>
>> - /*
>> - * Now loop read/writing random pages.
>> - */
>> for (loopcnt = 0; loopcnt < nloops; loopcnt++) {
>> randpage = lrand48() % mappages;
>> paddr = maddr + (randpage * pagesize); /* page address */
>> @@ -554,185 +197,174 @@ void child_mapper(char *file, unsigned procno, unsigned nprocs)
>>
>> for (i = procno; i < validsize; i += nprocs) {
>> if (*((unsigned char *)(paddr + i))
>> - != ((procno + pattern) & 0xff)) {
>> - (void)fprintf(stderr, "child %d: invalid data "
>> - "<x%x>", procno,
>> - *((unsigned char *)(paddr + i)));
>> - (void)fprintf(stderr, " at pg %d off %d, exp "
>> - "<x%x>\n", randpage, i,
>> - (procno + pattern) & 0xff);
>> - anyfail();
>> - }
>> + != ((procno + pattern) & 0xff))
>> + tst_brk(TFAIL, "child %d: invalid data <x%x>\n"
>> + " at pg %d off %d, exp <x%x>", procno,
>> + *((unsigned char *)(paddr + i)),
>> + randpage, i, (procno + pattern) & 0xff);
>>
>> - /*
>> - * Now write it.
>> - */
>> *(paddr + i) = (procno + pattern) & 0xff;
>> }
>> }
>> - if (dosync) {
>> - /*
>> - * Exercise msync() as well!
>> - */
>> + if (do_sync) {
>> randpage = lrand48() % mappages;
>> paddr = maddr + (randpage * pagesize); /* page address */
>> if (msync(paddr, (mappages - randpage) * pagesize,
>> - MS_SYNC) == -1) {
>> - anyfail();
>> - }
>> - }
>> - if (munmap(maddr, mapsize) == -1) {
>> - perror("munmap failed");
>> - local_flag = FAILED;
>> - anyfail();
>> + MS_SYNC) == -1)
>> + tst_brk(TBROK | TERRNO, "msync failed");
>> }
>> + SAFE_MUNMAP(maddr, mapsize);
>> exit(0);
>> }
>>
>> -/*
>> - * Make sure file has all the correct data.
>> - */
>> -int fileokay(char *file, uchar_t * expbuf)
>> +/* Make sure file has all the correct data. */
>> +static void fileokay(char *file, unsigned char *expbuf)
>> {
>> -#ifdef LARGE_FILE
>> - struct stat64 statbuf;
>> -#else /* LARGE_FILE */
>> - struct stat statbuf;
>> -#endif /* LARGE_FILE */
>> - size_t mapsize;
>> - unsigned mappages;
>> - unsigned pagesize = sysconf(_SC_PAGE_SIZE);
>> - uchar_t readbuf[pagesize];
>> - int fd;
>> int cnt;
>> - unsigned i, j;
>> -
>> -#ifdef LARGE_FILE
>> - if ((fd = open64(file, O_RDONLY)) == -1) {
>> -#else /* LARGE_FILE */
>> - if ((fd = open(file, O_RDONLY)) == -1) {
>> -#endif /* LARGE_FILE */
>> - perror("open error");
>> - /***** LTP Port *****/
>> - local_flag = FAILED;
>> - anyfail();
>> - /***** ** *****/
>> - return 0;
>> - }
>> -#ifdef LARGE_FILE
>> - if (fstat64(fd, &statbuf) == -1) {
>> -#else /* LARGE_FILE */
>> - if (fstat(fd, &statbuf) == -1) {
>> -#endif /* LARGE_FILE */
>> - perror("stat error");
>> - /***** LTP Port *****/
>> - local_flag = FAILED;
>> - anyfail();
>> - /***** ** *****/
>> - return 0;
>> - }
>> -#ifdef LARGE_FILE
>> - if (lseek64(fd, sparseoffset, SEEK_SET) < 0) {
>> -#else /* LARGE_FILE */
>> - if (lseek(fd, sparseoffset, SEEK_SET) < 0) {
>> -#endif /* LARGE_FILE */
>> - perror("lseek");
>> - anyfail();
>> - }
>> + size_t mapsize;
>> + struct stat statbuf;
>> + unsigned char readbuf[pagesize];
>> + unsigned int i, j;
>> + unsigned int mappages;
>>
>> - if (statbuf.st_size - sparseoffset > SIZE_MAX) {
>> - fprintf(stderr, "size_t overflow when setting up map\n");
>> - anyfail();
>> - }
>> + fd = SAFE_OPEN(file, O_RDONLY);
>> +
>> + SAFE_FSTAT(fd, &statbuf);
>> + SAFE_LSEEK(fd, sparseoffset, SEEK_SET);
>> +
>> + if (statbuf.st_size - sparseoffset > UINT_MAX)
>> + tst_brk(TBROK, "size_t overflow when setting up map");
>> mapsize = (size_t) (statbuf.st_size - sparseoffset);
>>
>> mappages = roundup(mapsize, pagesize) / pagesize;
>>
>> for (i = 0; i < mappages; i++) {
>> - cnt = read(fd, readbuf, pagesize);
>> - if (cnt == -1) {
>> - perror("read error");
>> - /***** LTP Port *****/
>> - local_flag = FAILED;
>> - anyfail();
>> - /***** ** *****/
>> - return 0;
>> - } else if (cnt != pagesize) {
>> - /*
>> - * Okay if at last page in file...
>> - */
>> - if ((i * pagesize) + cnt != mapsize) {
>> - (void)fprintf(stderr, "read %d of %ld bytes\n",
>> - (i * pagesize) + cnt,
>> - (long)mapsize);
>> - close(fd);
>> - return 0;
>> - }
>> + cnt = SAFE_READ(0, fd, readbuf, pagesize);
>> + if ((unsigned int)cnt != pagesize) {
>> + /* Okay if at last page in file... */
>> + if ((i * pagesize) + cnt != mapsize)
>> + tst_brk(TFAIL, "missing data: read %lu of %ld bytes",
>> + (i * pagesize) + cnt, (long)mapsize);
>> }
>> - /*
>> - * Compare read bytes of data.
>> - */
>> - for (j = 0; j < cnt; j++) {
>> - if (expbuf[j] != readbuf[j]) {
>> - (void)fprintf(stderr,
>> - "read bad data: exp %c got %c)",
>> - expbuf[j], readbuf[j]);
>> -#ifdef LARGE_FILE
>> - (void)fprintf(stderr, ", pg %d off %d, "
>> - "(fsize %Ld)\n", i, j,
>> - statbuf.st_size);
>> -#else /* LARGE_FILE */
>> - (void)fprintf(stderr, ", pg %d off %d, "
>> - "(fsize %ld)\n", i, j,
>> - statbuf.st_size);
>> -#endif /* LARGE_FILE */
>> - close(fd);
>> - return 0;
>> - }
>> + /* Compare read bytes of data. */
>> + for (j = 0; j < (unsigned int)cnt; j++) {
>> + if (expbuf[j] != readbuf[j])
>> + tst_brk(TFAIL,
>> + "read bad data: exp %c got %c, pg %d off %d, (fsize %lld)",
>> + expbuf[j], readbuf[j], i, j,
>> + (long long)statbuf.st_size);
>> }
>> }
>> - close(fd);
>> -
>> - return 1;
>> + SAFE_CLOSE(fd);
>> }
>>
>> - /*ARGSUSED*/ void finish(int sig)
>> +static void sighandler(int sig LTP_ATTRIBUTE_UNUSED)
>> {
>> finished++;
>> - return;
>> }
>>
>> -unsigned int initrand(void)
>> +static unsigned int initrand(void)
>> {
>> unsigned int seed;
>>
>> /*
>> - * Initialize random seed... Got this from a test written
>> - * by scooter:
>> - * Use srand/rand to diffuse the information from the
>> - * time and pid. If you start several processes, then
>> - * the time and pid information don't provide much
>> - * variation.
>> + * Use srand/rand to diffuse the information from the
>> + * time and pid. If you start several processes, then
>> + * the time and pid information don't provide much
>> + * variation.
>> */
>> srand((unsigned int)getpid());
>> seed = rand();
>> srand((unsigned int)time(NULL));
>> seed = (seed ^ rand()) % 100000;
>> - srand48((long int)seed);
>> - return (seed);
>> + srand48((long)seed);
>> + return seed;
>> }
>>
>> -/***** LTP Port *****/
>> -void ok_exit(void)
>> +static void run(void)
>> {
>> - tst_resm(TPASS, "Test passed");
>> - tst_rmdir();
>> - tst_exit();
>> -}
>> + int c;
>> + int i;
>> + int wait_stat;
>> + off_t bytes_left;
>> + pid_t pid;
>> + pid_t *pidarray;
>> + size_t write_cnt;
>> + unsigned char data;
>> + unsigned char *buf;
>>
>> -int anyfail(void)
>> -{
>> - tst_brkm(TFAIL, tst_rmdir, "Test failed");
>> + alarm(tst_remaining_runtime());
>> +
>> + finished = 0;
>> + fd = SAFE_OPEN(TEST_FILE, O_CREAT | O_TRUNC | O_RDWR, 0664);
>> + buf = SAFE_MALLOC(pagesize);
>> + pidarray = SAFE_MALLOC(nprocs * sizeof(pid_t));
>> +
>> + for (i = 0; i < nprocs; i++)
>> + *(pidarray + i) = 0;
>> +
>> + for (i = 0, data = 0; i < (int)pagesize; i++) {
>> + *(buf + i) = (data + pattern) & 0xff;
>> + if (++data == nprocs)
>> + data = 0;
>> + }
>> + SAFE_LSEEK(fd, (off_t)sparseoffset, SEEK_SET);
>> + for (bytes_left = filesize; bytes_left; bytes_left -= c) {
>> + write_cnt = MIN((long long)pagesize, (long long)bytes_left);
>> + c = SAFE_WRITE(1, fd, buf, write_cnt);
>> + }
>> + SAFE_CLOSE(fd);
>> +
>> + for (i = 0; i < nprocs; i++) {
>> + pid = SAFE_FORK();
>> +
>> + if (pid == 0) {
>> + child_mapper(TEST_FILE, (unsigned int)i, (unsigned int)nprocs);
>> + exit(0);
>> + } else {
>> + pidarray[i] = pid;
>> + }
>> + }
>> +
>> + while (!finished) {
>> + pid = wait(&wait_stat);
>> + if (pid != -1) {
>> + if (!WIFEXITED(wait_stat)
>> + || WEXITSTATUS(wait_stat) != 0)
>> + tst_brk(TBROK, "child exit with err <x%x>",
>> + wait_stat);
>> + for (i = 0; i < nprocs; i++)
>> + if (pid == pidarray[i])
>> + break;
>> + if (i == nprocs)
>> + tst_brk(TBROK, "unknown child pid %d, <x%x>",
>> + pid, wait_stat);
>> +
>> + pid = SAFE_FORK();
>> + if (pid == 0) {
>> + child_mapper(TEST_FILE, (unsigned int)i, (unsigned int)nprocs);
>> + exit(0);
>> + } else {
>> + pidarray[i] = pid;
>> + }
>> + } else {
>> + if (errno != EINTR || !finished)
>> + tst_brk(TBROK | TERRNO,
>> + "unexpected wait error");
>> + }
>> + }
>> + alarm(0);
>> +
>> + fileokay(TEST_FILE, buf);
>> + tst_res(TPASS, "file has expected data");
>> }
>>
>> -/***** ** ** *****/
>> +static struct tst_test test = {
>> + .test_all = run,
>> + .setup = setup,
>> + .options = options,
>> + .cleanup = cleanup,
>> + .max_runtime = 12,
>> + .needs_tmpdir = 1,
>> + .forks_child = 1,
>> +};
>> --
>> 2.38.1.273.g43a17bfeac-goog
--
Thank you,
Richard.
More information about the ltp
mailing list