1 /*
2  * Copyright (C) 2013-2021 Canonical, Ltd.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * This code is a complete clean re-write of the stress tool by
19  * Colin Ian King <colin.king@canonical.com> and attempts to be
20  * backwardly compatible with the stress tool by Amos Waterland
21  * <apw@rossby.metr.ou.edu> but has more stress tests and more
22  * functionality.
23  *
24  */
25 #include "stress-ng.h"
26 
27 #if defined(HAVE_MADVISE)
28 static const int madvise_options[] = {
29 #if defined(MADV_NORMAL)
30 	MADV_NORMAL,
31 #endif
32 #if defined(MADV_RANDOM)
33 	MADV_RANDOM,
34 #endif
35 #if defined(MADV_SEQUENTIAL)
36 	MADV_SEQUENTIAL,
37 #endif
38 #if defined(MADV_WILLNEED)
39 	MADV_WILLNEED,
40 #endif
41 /*
42  *  Don't use DONTNEED as this can zero fill
43  *  pages that don't have backing store which
44  *  trips checksum errors when we check that
45  *  the pages are sane.
46  *
47 #if defined(MADV_DONTNEED)
48 	MADV_DONTNEED,
49 #endif
50 */
51 #if defined(MADV_DONTFORK)
52 	MADV_DONTFORK,
53 #endif
54 #if defined(MADV_DOFORK)
55 	MADV_DOFORK,
56 #endif
57 #if defined(MADV_MERGEABLE)
58 	MADV_MERGEABLE,
59 #endif
60 #if defined(MADV_UNMERGEABLE)
61 	MADV_UNMERGEABLE,
62 #endif
63 #if defined(MADV_HUGEPAGE)
64 	MADV_HUGEPAGE,
65 #endif
66 #if defined(MADV_NOHUGEPAGE)
67 	MADV_NOHUGEPAGE,
68 #endif
69 #if defined(MADV_DONTDUMP)
70 	MADV_DONTDUMP,
71 #endif
72 #if defined(MADV_DODUMP)
73 	MADV_DODUMP,
74 #endif
75 #if defined(MADV_COLD)
76 	MADV_COLD,
77 #endif
78 #if defined(MADV_PAGEOUT)
79 	MADV_PAGEOUT,
80 #endif
81 /*
82  *  Don't use MADV_FREE as this can zero fill
83  *  pages that don't have backing store which
84  *  trips checksum errors when we check that
85  *  the pages are sane.
86  *
87 #if defined(MADV_FREE)
88 	MADV_FREE
89 #endif
90 */
91 /* Linux 5.14 */
92 #if defined(MADV_POPULATE_READ)
93 	MADV_POPULATE_READ,
94 #endif
95 /* Linux 5.14 */
96 #if defined(MADV_POPULATE_WRITE)
97 	MADV_POPULATE_WRITE,
98 #endif
99 };
100 #endif
101 
102 /*
103  *  stress_madvise_random()
104  *	apply random madvise setting to a memory region
105  */
stress_madvise_random(void * addr,const size_t length)106 int stress_madvise_random(void *addr, const size_t length)
107 {
108 #if defined(HAVE_MADVISE)
109 	if (g_opt_flags & OPT_FLAGS_MMAP_MADVISE) {
110 		const int i = (stress_mwc32() >> 7) % SIZEOF_ARRAY(madvise_options);
111 
112 		return madvise(addr, length, madvise_options[i]);
113 	}
114 #else
115 	(void)addr;
116 	(void)length;
117 #endif
118 	return 0;
119 }
120 
121 /*
122  *  stress_madvise_pid_all_pages()
123  *	apply madvise advise to all pages in a progress
124  */
stress_madvise_pid_all_pages(const pid_t pid,const int advise)125 void stress_madvise_pid_all_pages(const pid_t pid, const int advise)
126 {
127 #if defined(HAVE_MADVISE) &&	\
128     defined(__linux__)
129 	FILE *fp;
130 	char path[PATH_MAX];
131 	char buf[4096];
132 
133 	(void)snprintf(path, sizeof(path), "/proc/%" PRIdMAX "/maps", (intmax_t)pid);
134 
135 	fp = fopen(path, "r");
136 	if (!fp)
137 		return;
138 	while (fgets(buf, sizeof(buf), fp)) {
139 		void *start, *end, *offset;
140 		int major, minor, n, ret;
141 		uint64_t inode;
142 		char prot[5];
143 
144 		n = sscanf(buf, "%p-%p %4s %p %x:%x %" PRIu64 " %s\n",
145 			&start, &end, prot, &offset, &major, &minor,
146 			&inode, path);
147 		if (n < 7)
148 			continue;	/* bad sscanf data */
149 		if (start >= end)
150 			continue;	/* invalid addresse range */
151 
152 		ret = madvise(start, (size_t)(end - start), advise);
153 		(void)ret;
154 
155 		/*
156 		 *  Readable protection? read pages
157 		 */
158 		if ((prot[0] == 'r') && (path[0] != '[')) {
159 			const size_t page_size = stress_get_pagesize();
160 
161 			volatile uint8_t *ptr = (volatile uint8_t *)start;
162 
163 			while (ptr < (uint8_t *)end) {
164 				(*ptr);
165 				ptr += page_size;
166 			}
167 		}
168 	}
169 
170 	(void)fclose(fp);
171 #else
172 	(void)pid;
173 	(void)advise;
174 #endif
175 }
176