// SPDX-License-Identifier: LGPL-2.1-or-later /* * Copyright (C) 2005-2006 IBM Corporation. * Author: David Gibson & Adam Litke */ /*\ * [Description] * * Tests copy-on-write semantics of large pages where a number of threads * map the same file with the MAP_PRIVATE flag. The threads then write * into their copy of the mapping and recheck the contents to ensure they * were not corrupted by the other threads. */ #include "hugetlb.h" #define THREADS 5 #define NR_HUGEPAGES 6 #define MNTPOINT "hugetlbfs/" static int fd = -1; static long hpage_size; static void do_work(int thread, size_t size, int fd) { char *addr; size_t i; char pattern = thread+65; addr = SAFE_MMAP(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); tst_res(TINFO, "Thread %d (pid %d): Mapped at address %p", thread, getpid(), addr); for (i = 0; i < size; i++) memcpy((char *)addr+i, &pattern, 1); SAFE_MSYNC(addr, size, MS_SYNC); for (i = 0; i < size; i++) { if (addr[i] != pattern) { tst_res(TFAIL, "thread %d (pid: %d): Corruption at %p; " "Got %c, Expected %c", thread, getpid(), &addr[i], addr[i], pattern); goto cleanup; } } tst_res(TINFO, "Thread %d (pid %d): Pattern verified", thread, getpid()); cleanup: SAFE_MUNMAP(addr, size); exit(0); } static void run_test(void) { int i, pid; char *addr; size_t size, itr; pid_t *wait_list; wait_list = SAFE_MALLOC(THREADS * sizeof(pid_t)); size = (NR_HUGEPAGES / (THREADS+1)) * hpage_size; /* * First, mmap the file with MAP_SHARED and fill with data * If this is not done, then the fault handler will not be * called in the kernel since private mappings will be * created for the children at prefault time. */ addr = SAFE_MMAP(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); for (itr = 0; itr < size; itr += 8) memcpy(addr+itr, "deadbeef", 8); for (i = 0; i < THREADS; i++) { pid = SAFE_FORK(); if (pid == 0) do_work(i, size, fd); wait_list[i] = pid; } tst_reap_children(); SAFE_MUNMAP(addr, size); free(wait_list); tst_res(TPASS, "mmap COW working as expected."); } static void setup(void) { hpage_size = tst_get_hugepage_size(); fd = tst_creat_unlinked(MNTPOINT, 0); } static void cleanup(void) { if (fd >= 1) SAFE_CLOSE(fd); } static struct tst_test test = { .needs_root = 1, .mntpoint = MNTPOINT, .needs_hugetlbfs = 1, .needs_tmpdir = 1, .forks_child = 1, .setup = setup, .cleanup = cleanup, .test_all = run_test, .hugepages = {NR_HUGEPAGES, TST_NEEDS}, };