1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | // |
3 | // Copyright 2019, Michael Ellerman, IBM Corp. |
4 | // |
5 | // Test that allocating memory beyond the memory limit and then forking is |
6 | // handled correctly, ie. the child is able to access the mappings beyond the |
7 | // memory limit and the child's writes are not visible to the parent. |
8 | |
9 | #include <stdio.h> |
10 | #include <stdlib.h> |
11 | #include <sys/mman.h> |
12 | #include <sys/types.h> |
13 | #include <sys/wait.h> |
14 | #include <unistd.h> |
15 | |
16 | #include "utils.h" |
17 | |
18 | |
19 | #ifndef MAP_FIXED_NOREPLACE |
20 | #define MAP_FIXED_NOREPLACE MAP_FIXED // "Should be safe" above 512TB |
21 | #endif |
22 | |
23 | |
24 | static int test(void) |
25 | { |
26 | int p2c[2], c2p[2], rc, status, c, *p; |
27 | unsigned long page_size; |
28 | pid_t pid; |
29 | |
30 | page_size = sysconf(_SC_PAGESIZE); |
31 | SKIP_IF(page_size != 65536); |
32 | |
33 | // Create a mapping at 512TB to allocate an extended_id |
34 | p = mmap((void *)(512ul << 40), page_size, PROT_READ | PROT_WRITE, |
35 | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED_NOREPLACE, -1, 0); |
36 | if (p == MAP_FAILED) { |
37 | perror("mmap" ); |
38 | printf("Error: couldn't mmap(), confirm kernel has 4TB support?\n" ); |
39 | return 1; |
40 | } |
41 | |
42 | printf("parent writing %p = 1\n" , p); |
43 | *p = 1; |
44 | |
45 | FAIL_IF(pipe(p2c) == -1 || pipe(c2p) == -1); |
46 | |
47 | pid = fork(); |
48 | if (pid == 0) { |
49 | FAIL_IF(read(p2c[0], &c, 1) != 1); |
50 | |
51 | pid = getpid(); |
52 | printf("child writing %p = %d\n" , p, pid); |
53 | *p = pid; |
54 | |
55 | FAIL_IF(write(c2p[1], &c, 1) != 1); |
56 | FAIL_IF(read(p2c[0], &c, 1) != 1); |
57 | exit(0); |
58 | } |
59 | |
60 | c = 0; |
61 | FAIL_IF(write(p2c[1], &c, 1) != 1); |
62 | FAIL_IF(read(c2p[0], &c, 1) != 1); |
63 | |
64 | // Prevent compiler optimisation |
65 | barrier(); |
66 | |
67 | rc = 0; |
68 | printf("parent reading %p = %d\n" , p, *p); |
69 | if (*p != 1) { |
70 | printf("Error: BUG! parent saw child's write! *p = %d\n" , *p); |
71 | rc = 1; |
72 | } |
73 | |
74 | FAIL_IF(write(p2c[1], &c, 1) != 1); |
75 | FAIL_IF(waitpid(pid, &status, 0) == -1); |
76 | FAIL_IF(!WIFEXITED(status) || WEXITSTATUS(status)); |
77 | |
78 | if (rc == 0) |
79 | printf("success: test completed OK\n" ); |
80 | |
81 | return rc; |
82 | } |
83 | |
84 | int main(void) |
85 | { |
86 | return test_harness(test, "large_vm_fork_separation" ); |
87 | } |
88 | |