Home | History | Annotate | Download | only in vm
      1 // SPDX-License-Identifier: GPL-2.0
      2 /*
      3  * Copyright (c) 2018 Dmitry Safonov, Arista Networks
      4  *
      5  * MAP_POPULATE | MAP_PRIVATE should COW VMA pages.
      6  */
      7 
      8 #define _GNU_SOURCE
      9 #include <errno.h>
     10 #include <fcntl.h>
     11 #include <sys/mman.h>
     12 #include <sys/socket.h>
     13 #include <sys/types.h>
     14 #include <sys/wait.h>
     15 #include <stdio.h>
     16 #include <stdlib.h>
     17 #include <string.h>
     18 #include <unistd.h>
     19 
     20 #ifndef MMAP_SZ
     21 #define MMAP_SZ		4096
     22 #endif
     23 
     24 #define BUG_ON(condition, description)					\
     25 	do {								\
     26 		if (condition) {					\
     27 			fprintf(stderr, "[FAIL]\t%s:%d\t%s:%s\n", __func__, \
     28 				__LINE__, (description), strerror(errno)); \
     29 			exit(1);					\
     30 		}							\
     31 	} while (0)
     32 
     33 static int parent_f(int sock, unsigned long *smap, int child)
     34 {
     35 	int status, ret;
     36 
     37 	ret = read(sock, &status, sizeof(int));
     38 	BUG_ON(ret <= 0, "read(sock)");
     39 
     40 	*smap = 0x22222BAD;
     41 	ret = msync(smap, MMAP_SZ, MS_SYNC);
     42 	BUG_ON(ret, "msync()");
     43 
     44 	ret = write(sock, &status, sizeof(int));
     45 	BUG_ON(ret <= 0, "write(sock)");
     46 
     47 	waitpid(child, &status, 0);
     48 	BUG_ON(!WIFEXITED(status), "child in unexpected state");
     49 
     50 	return WEXITSTATUS(status);
     51 }
     52 
     53 static int child_f(int sock, unsigned long *smap, int fd)
     54 {
     55 	int ret, buf = 0;
     56 
     57 	smap = mmap(0, MMAP_SZ, PROT_READ | PROT_WRITE,
     58 			MAP_PRIVATE | MAP_POPULATE, fd, 0);
     59 	BUG_ON(smap == MAP_FAILED, "mmap()");
     60 
     61 	BUG_ON(*smap != 0xdeadbabe, "MAP_PRIVATE | MAP_POPULATE changed file");
     62 
     63 	ret = write(sock, &buf, sizeof(int));
     64 	BUG_ON(ret <= 0, "write(sock)");
     65 
     66 	ret = read(sock, &buf, sizeof(int));
     67 	BUG_ON(ret <= 0, "read(sock)");
     68 
     69 	BUG_ON(*smap == 0x22222BAD, "MAP_POPULATE didn't COW private page");
     70 	BUG_ON(*smap != 0xdeadbabe, "mapping was corrupted");
     71 
     72 	return 0;
     73 }
     74 
     75 int main(int argc, char **argv)
     76 {
     77 	int sock[2], child, ret;
     78 	FILE *ftmp;
     79 	unsigned long *smap;
     80 
     81 	ftmp = tmpfile();
     82 	BUG_ON(ftmp == 0, "tmpfile()");
     83 
     84 	ret = ftruncate(fileno(ftmp), MMAP_SZ);
     85 	BUG_ON(ret, "ftruncate()");
     86 
     87 	smap = mmap(0, MMAP_SZ, PROT_READ | PROT_WRITE,
     88 			MAP_SHARED, fileno(ftmp), 0);
     89 	BUG_ON(smap == MAP_FAILED, "mmap()");
     90 
     91 	*smap = 0xdeadbabe;
     92 	/* Probably unnecessary, but let it be. */
     93 	ret = msync(smap, MMAP_SZ, MS_SYNC);
     94 	BUG_ON(ret, "msync()");
     95 
     96 	ret = socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sock);
     97 	BUG_ON(ret, "socketpair()");
     98 
     99 	child = fork();
    100 	BUG_ON(child == -1, "fork()");
    101 
    102 	if (child) {
    103 		ret = close(sock[0]);
    104 		BUG_ON(ret, "close()");
    105 
    106 		return parent_f(sock[1], smap, child);
    107 	}
    108 
    109 	ret = close(sock[1]);
    110 	BUG_ON(ret, "close()");
    111 
    112 	return child_f(sock[0], smap, fileno(ftmp));
    113 }
    114