mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
113 lines
2.4 KiB
113 lines
2.4 KiB
// SPDX-License-Identifier: GPL-2.0 |
|
/* |
|
* Copyright (c) 2018 Dmitry Safonov, Arista Networks |
|
* |
|
* MAP_POPULATE | MAP_PRIVATE should COW VMA pages. |
|
*/ |
|
|
|
#define _GNU_SOURCE |
|
#include <errno.h> |
|
#include <fcntl.h> |
|
#include <sys/mman.h> |
|
#include <sys/socket.h> |
|
#include <sys/types.h> |
|
#include <sys/wait.h> |
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
#include <unistd.h> |
|
|
|
#ifndef MMAP_SZ |
|
#define MMAP_SZ 4096 |
|
#endif |
|
|
|
#define BUG_ON(condition, description) \ |
|
do { \ |
|
if (condition) { \ |
|
fprintf(stderr, "[FAIL]\t%s:%d\t%s:%s\n", __func__, \ |
|
__LINE__, (description), strerror(errno)); \ |
|
exit(1); \ |
|
} \ |
|
} while (0) |
|
|
|
static int parent_f(int sock, unsigned long *smap, int child) |
|
{ |
|
int status, ret; |
|
|
|
ret = read(sock, &status, sizeof(int)); |
|
BUG_ON(ret <= 0, "read(sock)"); |
|
|
|
*smap = 0x22222BAD; |
|
ret = msync(smap, MMAP_SZ, MS_SYNC); |
|
BUG_ON(ret, "msync()"); |
|
|
|
ret = write(sock, &status, sizeof(int)); |
|
BUG_ON(ret <= 0, "write(sock)"); |
|
|
|
waitpid(child, &status, 0); |
|
BUG_ON(!WIFEXITED(status), "child in unexpected state"); |
|
|
|
return WEXITSTATUS(status); |
|
} |
|
|
|
static int child_f(int sock, unsigned long *smap, int fd) |
|
{ |
|
int ret, buf = 0; |
|
|
|
smap = mmap(0, MMAP_SZ, PROT_READ | PROT_WRITE, |
|
MAP_PRIVATE | MAP_POPULATE, fd, 0); |
|
BUG_ON(smap == MAP_FAILED, "mmap()"); |
|
|
|
BUG_ON(*smap != 0xdeadbabe, "MAP_PRIVATE | MAP_POPULATE changed file"); |
|
|
|
ret = write(sock, &buf, sizeof(int)); |
|
BUG_ON(ret <= 0, "write(sock)"); |
|
|
|
ret = read(sock, &buf, sizeof(int)); |
|
BUG_ON(ret <= 0, "read(sock)"); |
|
|
|
BUG_ON(*smap == 0x22222BAD, "MAP_POPULATE didn't COW private page"); |
|
BUG_ON(*smap != 0xdeadbabe, "mapping was corrupted"); |
|
|
|
return 0; |
|
} |
|
|
|
int main(int argc, char **argv) |
|
{ |
|
int sock[2], child, ret; |
|
FILE *ftmp; |
|
unsigned long *smap; |
|
|
|
ftmp = tmpfile(); |
|
BUG_ON(ftmp == 0, "tmpfile()"); |
|
|
|
ret = ftruncate(fileno(ftmp), MMAP_SZ); |
|
BUG_ON(ret, "ftruncate()"); |
|
|
|
smap = mmap(0, MMAP_SZ, PROT_READ | PROT_WRITE, |
|
MAP_SHARED, fileno(ftmp), 0); |
|
BUG_ON(smap == MAP_FAILED, "mmap()"); |
|
|
|
*smap = 0xdeadbabe; |
|
/* Probably unnecessary, but let it be. */ |
|
ret = msync(smap, MMAP_SZ, MS_SYNC); |
|
BUG_ON(ret, "msync()"); |
|
|
|
ret = socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sock); |
|
BUG_ON(ret, "socketpair()"); |
|
|
|
child = fork(); |
|
BUG_ON(child == -1, "fork()"); |
|
|
|
if (child) { |
|
ret = close(sock[0]); |
|
BUG_ON(ret, "close()"); |
|
|
|
return parent_f(sock[1], smap, child); |
|
} |
|
|
|
ret = close(sock[1]); |
|
BUG_ON(ret, "close()"); |
|
|
|
return child_f(sock[0], smap, fileno(ftmp)); |
|
}
|
|
|