Skip to content

Commit f157078

Browse files
committed
Merge: selftests/mm: resolve virtual_address_range test fail on rhel-9.6
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/6781 JIRA: https://issues.redhat.com/browse/RHEL-88165 Tested: by me, using RHEL-9.6 s390x and aarch64 arches. This is a bunch of backports to resolve virtual_address_range test fail on rhel9: ``` 3bd6137 selftests/mm: virtual_address_range: avoid reading from VM_IO mappings 3c479b5 selftests/mm: vm_util: split up /proc/self/smaps parsing 391e869 mm: selftest to verify zero-filled pages are mapped to zeropage b2a79f6 selftests/mm: virtual_address_range: unmap chunks after validation a005145 selftests/mm: virtual_address_range: mmap() without PROT_WRITE e847f8c selftest/mm: fix typo in virtual_address_range 86483f8 selftests: add ksft_exit_fail_perror() ``` Considering the __get_smap_entry is called by check_vmflag_io() and new ksft_exit_fail_perror() is needed by mark_range(), we have to additionally backport a few more commits (3c479b5, 391e869, 86483f8) to resolve the compiling error on RHEL9. Conflicts: - 86483f8: Minor merge conflict of ksft_exit_fail_perror(), no functional changes. - 3bd6137: Minor merge conflict of check_vmflag_io(), no functional changes. - 391e869: Dropped updates to split_huge_page_test.c (split_pmd_zero_pages() not needed). Omitted-fix: 136c5b4 ("selftests/mm: use selftests framework to print test result") Signed-off-by: Li Wang <liwang@redhat.com> Approved-by: Rafael Aquini <raquini@redhat.com> Approved-by: Waiman Long <longman@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Merged-by: Augusto Caringi <acaringi@redhat.com>
2 parents 16f402e + 7155f1b commit f157078

File tree

5 files changed

+131
-19
lines changed

5 files changed

+131
-19
lines changed

tools/testing/selftests/kselftest.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
* the program is aborting before finishing all tests):
3939
*
4040
* ksft_exit_fail_msg(fmt, ...);
41+
* ksft_exit_fail_perror(msg);
4142
*
4243
*/
4344
#ifndef __KSELFTEST_H
@@ -302,6 +303,19 @@ static inline __printf(1, 2) int ksft_exit_fail_msg(const char *msg, ...)
302303
exit(KSFT_FAIL);
303304
}
304305

306+
static inline void ksft_exit_fail_perror(const char *msg)
307+
{
308+
#ifndef NOLIBC
309+
ksft_exit_fail_msg("%s: %s (%d)\n", msg, strerror(errno), errno);
310+
#else
311+
/*
312+
* nolibc doesn't provide strerror() and it seems
313+
* inappropriate to add one, just print the errno.
314+
*/
315+
ksft_exit_fail_msg("%s: %d)\n", msg, errno);
316+
#endif
317+
}
318+
305319
static inline int ksft_exit_xfail(void)
306320
{
307321
ksft_print_cnts();

tools/testing/selftests/mm/config

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ CONFIG_TEST_HMM=m
66
CONFIG_GUP_TEST=y
77
CONFIG_TRANSPARENT_HUGEPAGE=y
88
CONFIG_MEM_SOFT_DIRTY=y
9+
CONFIG_ANON_VMA_NAME=y

tools/testing/selftests/mm/virtual_address_range.c

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@
1010
#include <string.h>
1111
#include <unistd.h>
1212
#include <errno.h>
13+
#include <sys/prctl.h>
1314
#include <sys/mman.h>
1415
#include <sys/time.h>
1516
#include <fcntl.h>
1617

18+
#include "vm_util.h"
1719
#include "../kselftest.h"
1820

1921
/*
@@ -64,7 +66,7 @@
6466
#define NR_CHUNKS_HIGH NR_CHUNKS_384TB
6567
#endif
6668

67-
static char *hind_addr(void)
69+
static char *hint_addr(void)
6870
{
6971
int bits = HIGH_ADDR_SHIFT + rand() % (63 - HIGH_ADDR_SHIFT);
7072

@@ -82,6 +84,24 @@ static void validate_addr(char *ptr, int high_addr)
8284
ksft_exit_fail_msg("Bad address %lx\n", addr);
8385
}
8486

87+
static void mark_range(char *ptr, size_t size)
88+
{
89+
if (prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, size, "virtual_address_range") == -1) {
90+
if (errno == EINVAL) {
91+
/* Depends on CONFIG_ANON_VMA_NAME */
92+
ksft_test_result_skip("prctl(PR_SET_VMA_ANON_NAME) not supported\n");
93+
ksft_finished();
94+
} else {
95+
ksft_exit_fail_perror("prctl(PR_SET_VMA_ANON_NAME) failed\n");
96+
}
97+
}
98+
}
99+
100+
static int is_marked_vma(const char *vma_name)
101+
{
102+
return vma_name && !strcmp(vma_name, "[anon:virtual_address_range]\n");
103+
}
104+
85105
static int validate_lower_address_hint(void)
86106
{
87107
char *ptr;
@@ -116,12 +136,17 @@ static int validate_complete_va_space(void)
116136

117137
prev_end_addr = 0;
118138
while (fgets(line, sizeof(line), file)) {
139+
const char *vma_name = NULL;
140+
int vma_name_start = 0;
119141
unsigned long hop;
120142

121-
if (sscanf(line, "%lx-%lx %s[rwxp-]",
122-
&start_addr, &end_addr, prot) != 3)
143+
if (sscanf(line, "%lx-%lx %4s %*s %*s %*s %n",
144+
&start_addr, &end_addr, prot, &vma_name_start) != 3)
123145
ksft_exit_fail_msg("cannot parse /proc/self/maps\n");
124146

147+
if (vma_name_start)
148+
vma_name = line + vma_name_start;
149+
125150
/* end of userspace mappings; ignore vsyscall mapping */
126151
if (start_addr & (1UL << 63))
127152
return 0;
@@ -135,6 +160,9 @@ static int validate_complete_va_space(void)
135160
if (prot[0] != 'r')
136161
continue;
137162

163+
if (check_vmflag_io((void *)start_addr))
164+
continue;
165+
138166
/*
139167
* Confirm whether MAP_CHUNK_SIZE chunk can be found or not.
140168
* If write succeeds, no need to check MAP_CHUNK_SIZE - 1
@@ -149,6 +177,9 @@ static int validate_complete_va_space(void)
149177
return 1;
150178
lseek(fd, 0, SEEK_SET);
151179

180+
if (is_marked_vma(vma_name))
181+
munmap((char *)(start_addr + hop), MAP_CHUNK_SIZE);
182+
152183
hop += MAP_CHUNK_SIZE;
153184
}
154185
}
@@ -166,7 +197,7 @@ int main(int argc, char *argv[])
166197
ksft_set_plan(1);
167198

168199
for (i = 0; i < NR_CHUNKS_LOW; i++) {
169-
ptr[i] = mmap(NULL, MAP_CHUNK_SIZE, PROT_READ | PROT_WRITE,
200+
ptr[i] = mmap(NULL, MAP_CHUNK_SIZE, PROT_READ,
170201
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
171202

172203
if (ptr[i] == MAP_FAILED) {
@@ -175,6 +206,7 @@ int main(int argc, char *argv[])
175206
break;
176207
}
177208

209+
mark_range(ptr[i], MAP_CHUNK_SIZE);
178210
validate_addr(ptr[i], 0);
179211
}
180212
lchunks = i;
@@ -185,13 +217,14 @@ int main(int argc, char *argv[])
185217
}
186218

187219
for (i = 0; i < NR_CHUNKS_HIGH; i++) {
188-
hint = hind_addr();
189-
hptr[i] = mmap(hint, MAP_CHUNK_SIZE, PROT_READ | PROT_WRITE,
220+
hint = hint_addr();
221+
hptr[i] = mmap(hint, MAP_CHUNK_SIZE, PROT_READ,
190222
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
191223

192224
if (hptr[i] == MAP_FAILED)
193225
break;
194226

227+
mark_range(ptr[i], MAP_CHUNK_SIZE);
195228
validate_addr(hptr[i], 1);
196229
}
197230
hchunks = i;

tools/testing/selftests/mm/vm_util.c

Lines changed: 75 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include <string.h>
33
#include <fcntl.h>
44
#include <dirent.h>
5+
#include <inttypes.h>
56
#include <sys/ioctl.h>
67
#include <linux/userfaultfd.h>
78
#include <sys/syscall.h>
@@ -11,6 +12,7 @@
1112

1213
#define PMD_SIZE_FILE_PATH "/sys/kernel/mm/transparent_hugepage/hpage_pmd_size"
1314
#define SMAP_FILE_PATH "/proc/self/smaps"
15+
#define STATUS_FILE_PATH "/proc/self/status"
1416
#define MAX_LINE_LENGTH 500
1517

1618
unsigned int __page_size;
@@ -97,13 +99,32 @@ uint64_t read_pmd_pagesize(void)
9799
return strtoul(buf, NULL, 10);
98100
}
99101

100-
bool __check_huge(void *addr, char *pattern, int nr_hpages,
101-
uint64_t hpage_size)
102+
unsigned long rss_anon(void)
102103
{
103-
uint64_t thp = -1;
104-
int ret;
104+
unsigned long rss_anon = 0;
105105
FILE *fp;
106106
char buffer[MAX_LINE_LENGTH];
107+
108+
fp = fopen(STATUS_FILE_PATH, "r");
109+
if (!fp)
110+
ksft_exit_fail_msg("%s: Failed to open file %s\n", __func__, STATUS_FILE_PATH);
111+
112+
if (!check_for_pattern(fp, "RssAnon:", buffer, sizeof(buffer)))
113+
goto err_out;
114+
115+
if (sscanf(buffer, "RssAnon:%10lu kB", &rss_anon) != 1)
116+
ksft_exit_fail_msg("Reading status error\n");
117+
118+
err_out:
119+
fclose(fp);
120+
return rss_anon;
121+
}
122+
123+
char *__get_smap_entry(void *addr, const char *pattern, char *buf, size_t len)
124+
{
125+
int ret;
126+
FILE *fp;
127+
char *entry = NULL;
107128
char addr_pattern[MAX_LINE_LENGTH];
108129

109130
ret = snprintf(addr_pattern, MAX_LINE_LENGTH, "%08lx-",
@@ -115,23 +136,40 @@ bool __check_huge(void *addr, char *pattern, int nr_hpages,
115136
if (!fp)
116137
ksft_exit_fail_msg("%s: Failed to open file %s\n", __func__, SMAP_FILE_PATH);
117138

118-
if (!check_for_pattern(fp, addr_pattern, buffer, sizeof(buffer)))
139+
if (!check_for_pattern(fp, addr_pattern, buf, len))
119140
goto err_out;
120141

121-
/*
122-
* Fetch the pattern in the same block and check the number of
123-
* hugepages.
124-
*/
125-
if (!check_for_pattern(fp, pattern, buffer, sizeof(buffer)))
142+
/* Fetch the pattern in the same block */
143+
if (!check_for_pattern(fp, pattern, buf, len))
126144
goto err_out;
127145

128-
snprintf(addr_pattern, MAX_LINE_LENGTH, "%s%%9ld kB", pattern);
146+
/* Trim trailing newline */
147+
entry = strchr(buf, '\n');
148+
if (entry)
149+
*entry = '\0';
129150

130-
if (sscanf(buffer, addr_pattern, &thp) != 1)
131-
ksft_exit_fail_msg("Reading smap error\n");
151+
entry = buf + strlen(pattern);
132152

133153
err_out:
134154
fclose(fp);
155+
return entry;
156+
}
157+
158+
bool __check_huge(void *addr, char *pattern, int nr_hpages,
159+
uint64_t hpage_size)
160+
{
161+
char buffer[MAX_LINE_LENGTH];
162+
uint64_t thp = -1;
163+
char *entry;
164+
165+
entry = __get_smap_entry(addr, pattern, buffer, sizeof(buffer));
166+
if (!entry)
167+
goto err_out;
168+
169+
if (sscanf(entry, "%9" SCNu64 " kB", &thp) != 1)
170+
ksft_exit_fail_msg("Reading smap error\n");
171+
172+
err_out:
135173
return thp == (nr_hpages * (hpage_size >> 10));
136174
}
137175

@@ -218,6 +256,30 @@ unsigned long get_free_hugepages(void)
218256
return fhp;
219257
}
220258

259+
bool check_vmflag_io(void *addr)
260+
{
261+
char buffer[MAX_LINE_LENGTH];
262+
const char *flags;
263+
size_t flaglen;
264+
265+
flags = __get_smap_entry(addr, "VmFlags:", buffer, sizeof(buffer));
266+
if (!flags)
267+
ksft_exit_fail_msg("%s: No VmFlags for %p\n", __func__, addr);
268+
269+
while (true) {
270+
flags += strspn(flags, " ");
271+
272+
flaglen = strcspn(flags, " ");
273+
if (!flaglen)
274+
return false;
275+
276+
if (flaglen == strlen("io") && !memcmp(flags, "io", flaglen))
277+
return true;
278+
279+
flags += flaglen;
280+
}
281+
}
282+
221283
int detect_hugetlb_page_sizes(size_t sizes[], int max)
222284
{
223285
DIR *dir = opendir("/sys/kernel/mm/hugepages/");

tools/testing/selftests/mm/vm_util.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ unsigned long pagemap_get_pfn(int fd, char *start);
3939
void clear_softdirty(void);
4040
bool check_for_pattern(FILE *fp, const char *pattern, char *buf, size_t len);
4141
uint64_t read_pmd_pagesize(void);
42+
unsigned long rss_anon(void);
4243
bool check_huge_anon(void *addr, int nr_hpages, uint64_t hpage_size);
4344
bool check_huge_file(void *addr, int nr_hpages, uint64_t hpage_size);
4445
bool check_huge_shmem(void *addr, int nr_hpages, uint64_t hpage_size);
@@ -52,6 +53,7 @@ int uffd_register(int uffd, void *addr, uint64_t len,
5253
int uffd_unregister(int uffd, void *addr, uint64_t len);
5354
int uffd_register_with_ioctls(int uffd, void *addr, uint64_t len,
5455
bool miss, bool wp, bool minor, uint64_t *ioctls);
56+
bool check_vmflag_io(void *addr);
5557

5658
/*
5759
* On ppc64 this will only work with radix 2M hugepage size

0 commit comments

Comments
 (0)