• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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