1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 /*
3 * Copyright (C) 2013 LG Electronics.
4 * Author: Joonsoo Kim
5 */
6
7 /*\
8 * [Description]
9 *
10 * Test to preserve a reserved page against no-reserved mapping. If all
11 * hugepages are reserved, access to no-reserved shared mapping cause a
12 * process die, instead of stealing a hugepage which is reserved for other
13 * process.
14 */
15
16 #include <setjmp.h>
17 #include "hugetlb.h"
18
19 #define MNTPOINT "hugetlbfs/"
20 static long hpage_size;
21 static int fd1 = -1, fd2 = -1;
22 static sigjmp_buf sig_escape;
23 static void *sig_expected = MAP_FAILED;
24
sig_handler(int signum,siginfo_t * si,void * uc)25 static void sig_handler(int signum, siginfo_t *si, void *uc)
26 {
27 (void)uc;
28
29 if (signum == SIGBUS) {
30 if (si->si_addr == sig_expected)
31 siglongjmp(sig_escape, 1);
32 tst_res(TFAIL, "SIGBUS somewhere unexpected: %p (expected: %p)",
33 si->si_addr, sig_expected);
34 } else {
35 tst_res(TFAIL, "Unexpected signal %s", strsignal(signum));
36 }
37 }
38
test_write(void * p)39 static int test_write(void *p)
40 {
41 volatile char *pl = p;
42
43 if (sigsetjmp(sig_escape, 1)) {
44 /* We got a SIGBUS */
45 return 1;
46 }
47
48 sig_expected = p;
49 barrier();
50 *pl = 's';
51 return 0;
52 }
53
run_test(void)54 static void run_test(void)
55 {
56 int nr_hugepages;
57 int surp_hugepages;
58 int ret;
59 char *p, *q;
60 struct sigaction sa = {
61 .sa_sigaction = sig_handler,
62 .sa_flags = SA_SIGINFO,
63 };
64
65 nr_hugepages = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE);
66
67 SAFE_SIGACTION(SIGBUS, &sa, NULL);
68
69 p = SAFE_MMAP(NULL, hpage_size * nr_hugepages,
70 PROT_READ | PROT_WRITE, MAP_SHARED, fd1, 0);
71
72 tst_res(TINFO, "Reserve all hugepages %d", nr_hugepages);
73
74 q = SAFE_MMAP(NULL, hpage_size,
75 PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NORESERVE, fd2, 0);
76
77 tst_res(TINFO, "Write to %p to steal reserved page", q);
78
79 surp_hugepages = SAFE_READ_MEMINFO(MEMINFO_HPAGE_SURP);
80 ret = test_write(q);
81 if (ret == 1) {
82 tst_res(TPASS, "Successful with SIGSEGV received");
83 goto cleanup;
84 }
85
86 /* Provisioning succeeded because of overcommit */
87 if (SAFE_READ_MEMINFO(MEMINFO_HPAGE_SURP) ==
88 surp_hugepages + 1) {
89 tst_res(TPASS, "Successful because of surplus pages");
90 goto cleanup;
91 }
92
93 tst_res(TFAIL, "Steal reserved page");
94 cleanup:
95 SAFE_MUNMAP(p, hpage_size * nr_hugepages);
96 SAFE_MUNMAP(q, hpage_size);
97 }
98
setup(void)99 static void setup(void)
100 {
101 hpage_size = tst_get_hugepage_size();
102 fd1 = tst_creat_unlinked(MNTPOINT, 0);
103 fd2 = tst_creat_unlinked(MNTPOINT, 0);
104 }
105
cleanup(void)106 static void cleanup(void)
107 {
108 if (fd1 >= 0)
109 SAFE_CLOSE(fd1);
110 if (fd2 >= 0)
111 SAFE_CLOSE(fd2);
112 }
113
114 static struct tst_test test = {
115 .needs_root = 1,
116 .mntpoint = MNTPOINT,
117 .needs_hugetlbfs = 1,
118 .needs_tmpdir = 1,
119 .setup = setup,
120 .cleanup = cleanup,
121 .test_all = run_test,
122 .hugepages = {2, TST_NEEDS},
123 };
124