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