162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2018 Dmitry Safonov, Arista Networks 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * MAP_POPULATE | MAP_PRIVATE should COW VMA pages. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#define _GNU_SOURCE 962306a36Sopenharmony_ci#include <errno.h> 1062306a36Sopenharmony_ci#include <fcntl.h> 1162306a36Sopenharmony_ci#include <sys/mman.h> 1262306a36Sopenharmony_ci#include <sys/socket.h> 1362306a36Sopenharmony_ci#include <sys/types.h> 1462306a36Sopenharmony_ci#include <sys/wait.h> 1562306a36Sopenharmony_ci#include <stdio.h> 1662306a36Sopenharmony_ci#include <stdlib.h> 1762306a36Sopenharmony_ci#include <string.h> 1862306a36Sopenharmony_ci#include <unistd.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define MMAP_SZ 4096 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define BUG_ON(condition, description) \ 2362306a36Sopenharmony_ci do { \ 2462306a36Sopenharmony_ci if (condition) { \ 2562306a36Sopenharmony_ci fprintf(stderr, "[FAIL]\t%s:%d\t%s:%s\n", __func__, \ 2662306a36Sopenharmony_ci __LINE__, (description), strerror(errno)); \ 2762306a36Sopenharmony_ci exit(1); \ 2862306a36Sopenharmony_ci } \ 2962306a36Sopenharmony_ci } while (0) 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic int parent_f(int sock, unsigned long *smap, int child) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci int status, ret; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci ret = read(sock, &status, sizeof(int)); 3662306a36Sopenharmony_ci BUG_ON(ret <= 0, "read(sock)"); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci *smap = 0x22222BAD; 3962306a36Sopenharmony_ci ret = msync(smap, MMAP_SZ, MS_SYNC); 4062306a36Sopenharmony_ci BUG_ON(ret, "msync()"); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci ret = write(sock, &status, sizeof(int)); 4362306a36Sopenharmony_ci BUG_ON(ret <= 0, "write(sock)"); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci waitpid(child, &status, 0); 4662306a36Sopenharmony_ci BUG_ON(!WIFEXITED(status), "child in unexpected state"); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci return WEXITSTATUS(status); 4962306a36Sopenharmony_ci} 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic int child_f(int sock, unsigned long *smap, int fd) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci int ret, buf = 0; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci smap = mmap(0, MMAP_SZ, PROT_READ | PROT_WRITE, 5662306a36Sopenharmony_ci MAP_PRIVATE | MAP_POPULATE, fd, 0); 5762306a36Sopenharmony_ci BUG_ON(smap == MAP_FAILED, "mmap()"); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci BUG_ON(*smap != 0xdeadbabe, "MAP_PRIVATE | MAP_POPULATE changed file"); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci ret = write(sock, &buf, sizeof(int)); 6262306a36Sopenharmony_ci BUG_ON(ret <= 0, "write(sock)"); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci ret = read(sock, &buf, sizeof(int)); 6562306a36Sopenharmony_ci BUG_ON(ret <= 0, "read(sock)"); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci BUG_ON(*smap == 0x22222BAD, "MAP_POPULATE didn't COW private page"); 6862306a36Sopenharmony_ci BUG_ON(*smap != 0xdeadbabe, "mapping was corrupted"); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci return 0; 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ciint main(int argc, char **argv) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci int sock[2], child, ret; 7662306a36Sopenharmony_ci FILE *ftmp; 7762306a36Sopenharmony_ci unsigned long *smap; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci ftmp = tmpfile(); 8062306a36Sopenharmony_ci BUG_ON(!ftmp, "tmpfile()"); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci ret = ftruncate(fileno(ftmp), MMAP_SZ); 8362306a36Sopenharmony_ci BUG_ON(ret, "ftruncate()"); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci smap = mmap(0, MMAP_SZ, PROT_READ | PROT_WRITE, 8662306a36Sopenharmony_ci MAP_SHARED, fileno(ftmp), 0); 8762306a36Sopenharmony_ci BUG_ON(smap == MAP_FAILED, "mmap()"); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci *smap = 0xdeadbabe; 9062306a36Sopenharmony_ci /* Probably unnecessary, but let it be. */ 9162306a36Sopenharmony_ci ret = msync(smap, MMAP_SZ, MS_SYNC); 9262306a36Sopenharmony_ci BUG_ON(ret, "msync()"); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci ret = socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sock); 9562306a36Sopenharmony_ci BUG_ON(ret, "socketpair()"); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci child = fork(); 9862306a36Sopenharmony_ci BUG_ON(child == -1, "fork()"); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci if (child) { 10162306a36Sopenharmony_ci ret = close(sock[0]); 10262306a36Sopenharmony_ci BUG_ON(ret, "close()"); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci return parent_f(sock[1], smap, child); 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci ret = close(sock[1]); 10862306a36Sopenharmony_ci BUG_ON(ret, "close()"); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci return child_f(sock[0], smap, fileno(ftmp)); 11162306a36Sopenharmony_ci} 112