* Copyright (C) 2000 Juan Quintela <quintela@fi.udc.es>
* Aaron Laffin <alaffin@sgi.com>
* Copyright (C) 2025 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
*/
* Verify that we can use mmap() to map a large file, write to it via memory
* access, and read back the data from the file.
*/
#include "tst_test.h"
#define FILE_NAME "testfile"
static char *str_pages;
static long long pages = 1000;
static long long memory_size;
static char *memory_data;
static char *buff;
static void run(void)
{
int fd;
pid_t pid;
tst_res(TINFO, "mmap()ing file of %llu bytes", memory_size);
fd = SAFE_OPEN(FILE_NAME, O_RDWR | O_CREAT, 0666);
SAFE_LSEEK(fd, memory_size, SEEK_SET);
SAFE_WRITE(SAFE_WRITE_ALL, fd, "\0", 1);
memory_data = SAFE_MMAP(0, memory_size, PROT_WRITE, MAP_SHARED, fd, 0);
pid = SAFE_FORK();
if (!pid) {
tst_res(TINFO, "Touching mapped memory");
for (int i = 0; i < memory_size; i++)
memory_data[i] = (char)i;
exit(0);
}
tst_reap_children();
SAFE_MSYNC(memory_data, memory_size, MS_SYNC);
memset(buff, 0, memory_size);
SAFE_LSEEK(fd, 0, SEEK_SET);
SAFE_READ(0, fd, buff, memory_size);
SAFE_CLOSE(fd);
for (int i = 0; i < memory_size; i++) {
if (buff[i] != (char)i) {
tst_res(TFAIL, "Mapped file has not been updated at byte %d", i);
goto exit;
}
}
tst_res(TPASS, "Mapped file has been updated");
exit:
SAFE_MUNMAP(memory_data, memory_size);
memory_data = NULL;
SAFE_UNLINK(FILE_NAME);
}
static void setup(void)
{
if (tst_parse_filesize(str_pages, &pages, 1, LLONG_MAX))
tst_brk(TBROK, "Invalid number of pages: %s", str_pages);
memory_size = pages * getpagesize();
buff = SAFE_MALLOC(memory_size);
}
static void cleanup(void)
{
if (buff)
free(buff);
if (memory_data)
SAFE_MUNMAP(memory_data, memory_size);
}
static struct tst_test test = {
.test_all = run,
.setup = setup,
.cleanup = cleanup,
.needs_tmpdir = 1,
.forks_child = 1,
.options = (struct tst_option[]) {
{"m:", &str_pages, "Number of pages (default 1000)"},
{}
},
};