src/idmapped-mounts: use renameat instead of renameat2
[xfstests-dev.git] / src / t_mmap_cow_race.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2017 Intel Corporation. */
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <libgen.h>
6 #include <pthread.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <sys/mman.h>
11 #include <sys/stat.h>
12 #include <sys/types.h>
13 #include <unistd.h>
14
15 #define MiB(a) ((a)*1024*1024)
16 #define NUM_THREADS 2
17
18 void err_exit(char *op)
19 {
20         fprintf(stderr, "%s: %s\n", op, strerror(errno));
21         exit(1);
22 }
23
24 void worker_fn(void *ptr)
25 {
26         char *data = (char *)ptr;
27         volatile int a;
28         int i, err;
29
30         for (i = 0; i < 10; i++) {
31                 a = data[0];
32                 data[0] = a;
33
34                 err = madvise(data, MiB(2), MADV_DONTNEED);
35                 if (err < 0)
36                         err_exit("madvise");
37
38                 /* Mix up the thread timings to encourage the race. */
39                 err = usleep(rand() % 100);
40                 if (err < 0)
41                         err_exit("usleep");
42         }
43 }
44
45 int main(int argc, char *argv[])
46 {
47         pthread_t thread[NUM_THREADS];
48         int i, j, fd, err;
49         char *data;
50
51         if (argc < 2) {
52                 printf("Usage: %s <file>\n", basename(argv[0]));
53                 exit(0);
54         }
55
56         fd = open(argv[1], O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
57         if (fd < 0)
58                 err_exit("fd");
59
60         /* This allows us to map a huge page. */
61         ftruncate(fd, 0);
62         ftruncate(fd, MiB(2));
63
64         /*
65          * First we set up a shared mapping.  Our write will (hopefully) get
66          * the filesystem to give us a 2MiB huge page DAX mapping.  We will
67          * then use this 2MiB page for our private mapping race.
68          */
69         data = mmap(NULL, MiB(2), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
70         if (data == MAP_FAILED)
71                 err_exit("shared mmap");
72
73         data[0] = 1;
74
75         err = munmap(data, MiB(2));
76         if (err < 0)
77                 err_exit("shared munmap");
78
79         for (i = 0; i < 500; i++) {
80                 data = mmap(NULL, MiB(2), PROT_READ|PROT_WRITE, MAP_PRIVATE,
81                                 fd, 0);
82                 if (data == MAP_FAILED)
83                         err_exit("private mmap");
84
85                 for (j = 0; j < NUM_THREADS; j++) {
86                         err = pthread_create(&thread[j], NULL,
87                                         (void*)&worker_fn, data);
88                         if (err)
89                                 err_exit("pthread_create");
90                 }
91
92                 for (j = 0; j < NUM_THREADS; j++) {
93                         err = pthread_join(thread[j], NULL);
94                         if (err)
95                                 err_exit("pthread_join");
96                 }
97
98                 err = munmap(data, MiB(2));
99                 if (err < 0)
100                         err_exit("private munmap");
101         }
102
103         err = close(fd);
104         if (err < 0)
105                 err_exit("close");
106
107         return 0;
108 }