[LTP] [PATCH v4] syscalls/mmap01: Rewrite the test using new LTP API
Cyril Hrubis
chrubis@suse.cz
Wed Mar 6 15:55:53 CET 2024
On Tue, Jan 30, 2024 at 01:23:57PM +0100, Avinesh Kumar wrote:
> - use SAFE_MSYNC() macro
> - fixed the test for iterations > 1
> - enable test for all filesystems
>
> Signed-off-by: Avinesh Kumar <akumar@suse.de>
> ---
>
> Changes v3->v4:
> * Changed the logic to verify that mapped file has not been changed.
> * Enabled all filesystems.
>
>
> testcases/kernel/syscalls/mmap/mmap01.c | 223 +++++++-----------------
> 1 file changed, 61 insertions(+), 162 deletions(-)
>
> diff --git a/testcases/kernel/syscalls/mmap/mmap01.c b/testcases/kernel/syscalls/mmap/mmap01.c
> index 99266b57f..e0b36915c 100644
> --- a/testcases/kernel/syscalls/mmap/mmap01.c
> +++ b/testcases/kernel/syscalls/mmap/mmap01.c
> @@ -1,194 +1,93 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> /*
> * Copyright (c) International Business Machines Corp., 2001
> - *
> - * 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
> + * 07/2001 Ported by Wayne Boyer
> + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com>
> */
>
> -/*
> - * Test Description:
> - * Verify that, mmap() succeeds when used to map a file where size of the
> - * file is not a multiple of the page size, the memory area beyond the end
> - * of the file to the end of the page is accessible. Also, verify that
> - * this area is all zeroed and the modifications done to this area are
> - * not written to the file.
> - *
> - * Expected Result:
> - * mmap() should succeed returning the address of the mapped region.
> - * The memory area beyond the end of file to the end of page should be
> - * filled with zero.
> - * The changes beyond the end of file should not get written to the file.
> +/*\
> + * [Description]
> *
> - * HISTORY
> - * 07/2001 Ported by Wayne Boyer
> + * Verify that, mmap() succeeds when used to map a file where size of the
> + * file is not a multiple of the page size, the memory area beyond the end
> + * of the file to the end of the page is accessible. Also, verify that
> + * this area is all zeroed and the modifications done to this area are
> + * not written to the file.
> */
> -#include <stdio.h>
> -#include <stdlib.h>
> -#include <sys/types.h>
> -#include <errno.h>
> -#include <unistd.h>
> -#include <fcntl.h>
> -#include <string.h>
> -#include <signal.h>
> -#include <stdint.h>
> -#include <sys/stat.h>
> -#include <sys/mman.h>
> -#include <sys/shm.h>
>
> -#include "test.h"
> -
> -#define TEMPFILE "mmapfile"
> +#include <stdlib.h>
> +#include "tst_test.h"
>
> -char *TCID = "mmap01";
> -int TST_TOTAL = 1;
> +#define MNT_POINT "mntpoint"
> +#define TEMPFILE MNT_POINT"/mmapfile"
>
> -static char *addr;
> -static char *dummy;
> +static int fd;
> static size_t page_sz;
> static size_t file_sz;
> -static int fildes;
> -static char cmd_buffer[BUFSIZ];
> -
> -static void setup(void);
> -static void cleanup(void);
> +static char *addr;
> +static char *dummy;
> +static struct stat stat_buf;
> +static const char write_buf[] = "HelloWorld!";
>
> -int main(int ac, char **av)
> +static void setup(void)
> {
> - int lc;
> -
> - tst_parse_opts(ac, av, NULL, NULL);
> -
> - setup();
> -
> - for (lc = 0; TEST_LOOPING(lc); lc++) {
> -
> - tst_count = 0;
> -
> - /*
> - * Call mmap to map the temporary file beyond EOF
> - * with write access.
> - */
> - errno = 0;
> - addr = mmap(NULL, page_sz, PROT_READ | PROT_WRITE,
> - MAP_FILE | MAP_SHARED, fildes, 0);
> -
> - /* Check for the return value of mmap() */
> - if (addr == MAP_FAILED) {
> - tst_resm(TFAIL | TERRNO, "mmap of %s failed", TEMPFILE);
> - continue;
> - }
> -
> - /*
> - * Check if mapped memory area beyond EOF are
> - * zeros and changes beyond EOF are not written
> - * to file.
> - */
> - if (memcmp(&addr[file_sz], dummy, page_sz - file_sz)) {
> - tst_brkm(TFAIL, cleanup,
> - "mapped memory area contains invalid "
> - "data");
> - }
> -
> - /*
> - * Initialize memory beyond file size
> - */
> - addr[file_sz] = 'X';
> - addr[file_sz + 1] = 'Y';
> - addr[file_sz + 2] = 'Z';
> -
> - /*
> - * Synchronize the mapped memory region
> - * with the file.
> - */
> - if (msync(addr, page_sz, MS_SYNC) != 0) {
> - tst_brkm(TFAIL | TERRNO, cleanup,
> - "failed to synchronize mapped file");
> - }
> -
> - /*
> - * Now, Search for the pattern 'XYZ' in the
> - * temporary file. The pattern should not be
> - * found and the return value should be 1.
> - */
> - if (system(cmd_buffer) != 0) {
> - tst_resm(TPASS,
> - "Functionality of mmap() successful");
> - } else {
> - tst_resm(TFAIL,
> - "Specified pattern found in file");
> - }
> -
> - /* Clean up things in case we are looping */
> - /* Unmap the mapped memory */
> - if (munmap(addr, page_sz) != 0) {
> - tst_brkm(TFAIL | TERRNO, NULL, "munmap failed");
> - }
> - }
> + fd = SAFE_OPEN(TEMPFILE, O_RDWR | O_CREAT, 0666);
>
> - cleanup();
> - tst_exit();
> -}
> + SAFE_WRITE(SAFE_WRITE_ALL, fd, write_buf, strlen(write_buf));
> + SAFE_LSEEK(fd, 0, SEEK_SET);
> + SAFE_STAT(TEMPFILE, &stat_buf);
>
> -static void setup(void)
> -{
> - struct stat stat_buf;
> - char Path_name[PATH_MAX];
> - char write_buf[] = "hello world\n";
> + file_sz = stat_buf.st_size;
> + page_sz = getpagesize();
>
> - tst_sig(FORK, DEF_HANDLER, cleanup);
> + dummy = SAFE_MALLOC(page_sz);
> + memset(dummy, 0, page_sz);
> +}
>
> - TEST_PAUSE;
> +static void run(void)
> +{
> + char buf[20];
>
> - tst_tmpdir();
> + addr = SAFE_MMAP(NULL, page_sz, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 0);
>
> - /* Get the path of temporary file to be created */
> - if (getcwd(Path_name, sizeof(Path_name)) == NULL) {
> - tst_brkm(TFAIL | TERRNO, cleanup,
> - "getcwd failed to get current working directory");
> + if (memcmp(&addr[file_sz], dummy, page_sz - file_sz) != 0) {
> + tst_res(TFAIL, "mapped memory area contains invalid data");
> + goto unmap;
> }
>
> - /* Creat a temporary file used for mapping */
> - if ((fildes = open(TEMPFILE, O_RDWR | O_CREAT, 0666)) < 0) {
> - tst_brkm(TFAIL, cleanup, "opening %s failed", TEMPFILE);
> - }
> + addr[file_sz] = 'X';
> + addr[file_sz + 1] = 'Y';
> + addr[file_sz + 2] = 'Z';
>
> - /* Write some data into temporary file */
> - if (write(fildes, write_buf, strlen(write_buf)) != (long)strlen(write_buf)) {
> - tst_brkm(TFAIL, cleanup, "writing to %s", TEMPFILE);
> - }
> + SAFE_MSYNC(addr, page_sz, MS_SYNC);
>
> - /* Get the size of temporary file */
> - if (stat(TEMPFILE, &stat_buf) < 0) {
> - tst_brkm(TFAIL | TERRNO, cleanup, "stat of %s failed",
> - TEMPFILE);
> - }
> - file_sz = stat_buf.st_size;
> + SAFE_FILE_SCANF(TEMPFILE, "%s", buf);
Hmm, why do we SAFE_LSEEK() the fd if we are not using it for reading?
This could be just simple SAFE_READ() instead.
> - page_sz = getpagesize();
> + if (strcmp(write_buf, buf))
> + tst_res(TFAIL, "File data has changed");
> + else
> + tst_res(TPASS, "mmap() functionality successful");
^
"Data after file end were not written out"
It's kind of pointless to print message that just means "success".
> - /* Allocate and initialize dummy string of system page size bytes */
> - if ((dummy = calloc(page_sz, sizeof(char))) == NULL) {
> - tst_brkm(TFAIL, cleanup, "calloc failed (dummy)");
> - }
> + SAFE_LSEEK(fd, 0, SEEK_SET);
> + memset(&addr[file_sz], 0, 3);
I was wondering why this is needed, seems like for tmpfs we will read
back the data after the end of the file on a subsequent runs of the
test, i.e. with -i 2.
I wonder if that is expected or not, it's a bit strange that we can
expand the file size that way.
And it seems to happen for FUSE as well, that actually does sound like a
bug.
> - /* Create the command which will be executed in the test */
> - sprintf(cmd_buffer, "grep XYZ %s/%s > /dev/null", Path_name, TEMPFILE);
> +unmap:
> + SAFE_MUNMAP(addr, page_sz);
> }
>
> static void cleanup(void)
> {
> - close(fildes);
> + if (fd > 0)
> + SAFE_CLOSE(fd);
> +
> free(dummy);
> - tst_rmdir();
> }
> +
> +static struct tst_test test = {
> + .setup = setup,
> + .test_all = run,
> + .cleanup = cleanup,
> + .mntpoint = MNT_POINT,
> + .mount_device = 1,
> + .all_filesystems = 1
> +};
> --
> 2.43.0
>
>
> --
> Mailing list info: https://lists.linux.it/listinfo/ltp
--
Cyril Hrubis
chrubis@suse.cz
More information about the ltp
mailing list