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: ``` 3bd6137220bb selftests/mm: virtual_address_range: avoid reading from VM_IO mappings 3c479b5dc60b selftests/mm: vm_util: split up /proc/self/smaps parsing 391e86971161 mm: selftest to verify zero-filled pages are mapped to zeropage b2a79f62133a selftests/mm: virtual_address_range: unmap chunks after validation a005145b9c96 selftests/mm: virtual_address_range: mmap() without PROT_WRITE e847f8cd96ae selftest/mm: fix typo in virtual_address_range 86483f8b4e8d 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 (3c479b5dc60b, 391e86971161, 86483f8b4e8d) to resolve the compiling error on RHEL9. Conflicts: - 86483f8b4e8d: Minor merge conflict of ksft_exit_fail_perror(), no functional changes. - 3bd6137220bb: Minor merge conflict of check_vmflag_io(), no functional changes. - 391e86971161: Dropped updates to split_huge_page_test.c (split_pmd_zero_pages() not needed). Omitted-fix: 136c5b40e0ad ("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>
This commit is contained in:
commit
f1570787e4
|
@ -38,6 +38,7 @@
|
|||
* the program is aborting before finishing all tests):
|
||||
*
|
||||
* ksft_exit_fail_msg(fmt, ...);
|
||||
* ksft_exit_fail_perror(msg);
|
||||
*
|
||||
*/
|
||||
#ifndef __KSELFTEST_H
|
||||
|
@ -302,6 +303,19 @@ static inline __printf(1, 2) int ksft_exit_fail_msg(const char *msg, ...)
|
|||
exit(KSFT_FAIL);
|
||||
}
|
||||
|
||||
static inline void ksft_exit_fail_perror(const char *msg)
|
||||
{
|
||||
#ifndef NOLIBC
|
||||
ksft_exit_fail_msg("%s: %s (%d)\n", msg, strerror(errno), errno);
|
||||
#else
|
||||
/*
|
||||
* nolibc doesn't provide strerror() and it seems
|
||||
* inappropriate to add one, just print the errno.
|
||||
*/
|
||||
ksft_exit_fail_msg("%s: %d)\n", msg, errno);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int ksft_exit_xfail(void)
|
||||
{
|
||||
ksft_print_cnts();
|
||||
|
|
|
@ -6,3 +6,4 @@ CONFIG_TEST_HMM=m
|
|||
CONFIG_GUP_TEST=y
|
||||
CONFIG_TRANSPARENT_HUGEPAGE=y
|
||||
CONFIG_MEM_SOFT_DIRTY=y
|
||||
CONFIG_ANON_VMA_NAME=y
|
||||
|
|
|
@ -10,10 +10,12 @@
|
|||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/time.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "vm_util.h"
|
||||
#include "../kselftest.h"
|
||||
|
||||
/*
|
||||
|
@ -64,7 +66,7 @@
|
|||
#define NR_CHUNKS_HIGH NR_CHUNKS_384TB
|
||||
#endif
|
||||
|
||||
static char *hind_addr(void)
|
||||
static char *hint_addr(void)
|
||||
{
|
||||
int bits = HIGH_ADDR_SHIFT + rand() % (63 - HIGH_ADDR_SHIFT);
|
||||
|
||||
|
@ -82,6 +84,24 @@ static void validate_addr(char *ptr, int high_addr)
|
|||
ksft_exit_fail_msg("Bad address %lx\n", addr);
|
||||
}
|
||||
|
||||
static void mark_range(char *ptr, size_t size)
|
||||
{
|
||||
if (prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, size, "virtual_address_range") == -1) {
|
||||
if (errno == EINVAL) {
|
||||
/* Depends on CONFIG_ANON_VMA_NAME */
|
||||
ksft_test_result_skip("prctl(PR_SET_VMA_ANON_NAME) not supported\n");
|
||||
ksft_finished();
|
||||
} else {
|
||||
ksft_exit_fail_perror("prctl(PR_SET_VMA_ANON_NAME) failed\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int is_marked_vma(const char *vma_name)
|
||||
{
|
||||
return vma_name && !strcmp(vma_name, "[anon:virtual_address_range]\n");
|
||||
}
|
||||
|
||||
static int validate_lower_address_hint(void)
|
||||
{
|
||||
char *ptr;
|
||||
|
@ -116,12 +136,17 @@ static int validate_complete_va_space(void)
|
|||
|
||||
prev_end_addr = 0;
|
||||
while (fgets(line, sizeof(line), file)) {
|
||||
const char *vma_name = NULL;
|
||||
int vma_name_start = 0;
|
||||
unsigned long hop;
|
||||
|
||||
if (sscanf(line, "%lx-%lx %s[rwxp-]",
|
||||
&start_addr, &end_addr, prot) != 3)
|
||||
if (sscanf(line, "%lx-%lx %4s %*s %*s %*s %n",
|
||||
&start_addr, &end_addr, prot, &vma_name_start) != 3)
|
||||
ksft_exit_fail_msg("cannot parse /proc/self/maps\n");
|
||||
|
||||
if (vma_name_start)
|
||||
vma_name = line + vma_name_start;
|
||||
|
||||
/* end of userspace mappings; ignore vsyscall mapping */
|
||||
if (start_addr & (1UL << 63))
|
||||
return 0;
|
||||
|
@ -135,6 +160,9 @@ static int validate_complete_va_space(void)
|
|||
if (prot[0] != 'r')
|
||||
continue;
|
||||
|
||||
if (check_vmflag_io((void *)start_addr))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Confirm whether MAP_CHUNK_SIZE chunk can be found or not.
|
||||
* If write succeeds, no need to check MAP_CHUNK_SIZE - 1
|
||||
|
@ -149,6 +177,9 @@ static int validate_complete_va_space(void)
|
|||
return 1;
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
|
||||
if (is_marked_vma(vma_name))
|
||||
munmap((char *)(start_addr + hop), MAP_CHUNK_SIZE);
|
||||
|
||||
hop += MAP_CHUNK_SIZE;
|
||||
}
|
||||
}
|
||||
|
@ -166,7 +197,7 @@ int main(int argc, char *argv[])
|
|||
ksft_set_plan(1);
|
||||
|
||||
for (i = 0; i < NR_CHUNKS_LOW; i++) {
|
||||
ptr[i] = mmap(NULL, MAP_CHUNK_SIZE, PROT_READ | PROT_WRITE,
|
||||
ptr[i] = mmap(NULL, MAP_CHUNK_SIZE, PROT_READ,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
|
||||
if (ptr[i] == MAP_FAILED) {
|
||||
|
@ -175,6 +206,7 @@ int main(int argc, char *argv[])
|
|||
break;
|
||||
}
|
||||
|
||||
mark_range(ptr[i], MAP_CHUNK_SIZE);
|
||||
validate_addr(ptr[i], 0);
|
||||
}
|
||||
lchunks = i;
|
||||
|
@ -185,13 +217,14 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
for (i = 0; i < NR_CHUNKS_HIGH; i++) {
|
||||
hint = hind_addr();
|
||||
hptr[i] = mmap(hint, MAP_CHUNK_SIZE, PROT_READ | PROT_WRITE,
|
||||
hint = hint_addr();
|
||||
hptr[i] = mmap(hint, MAP_CHUNK_SIZE, PROT_READ,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
|
||||
if (hptr[i] == MAP_FAILED)
|
||||
break;
|
||||
|
||||
mark_range(ptr[i], MAP_CHUNK_SIZE);
|
||||
validate_addr(hptr[i], 1);
|
||||
}
|
||||
hchunks = i;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/userfaultfd.h>
|
||||
#include <sys/syscall.h>
|
||||
|
@ -11,6 +12,7 @@
|
|||
|
||||
#define PMD_SIZE_FILE_PATH "/sys/kernel/mm/transparent_hugepage/hpage_pmd_size"
|
||||
#define SMAP_FILE_PATH "/proc/self/smaps"
|
||||
#define STATUS_FILE_PATH "/proc/self/status"
|
||||
#define MAX_LINE_LENGTH 500
|
||||
|
||||
unsigned int __page_size;
|
||||
|
@ -97,13 +99,32 @@ uint64_t read_pmd_pagesize(void)
|
|||
return strtoul(buf, NULL, 10);
|
||||
}
|
||||
|
||||
bool __check_huge(void *addr, char *pattern, int nr_hpages,
|
||||
uint64_t hpage_size)
|
||||
unsigned long rss_anon(void)
|
||||
{
|
||||
uint64_t thp = -1;
|
||||
int ret;
|
||||
unsigned long rss_anon = 0;
|
||||
FILE *fp;
|
||||
char buffer[MAX_LINE_LENGTH];
|
||||
|
||||
fp = fopen(STATUS_FILE_PATH, "r");
|
||||
if (!fp)
|
||||
ksft_exit_fail_msg("%s: Failed to open file %s\n", __func__, STATUS_FILE_PATH);
|
||||
|
||||
if (!check_for_pattern(fp, "RssAnon:", buffer, sizeof(buffer)))
|
||||
goto err_out;
|
||||
|
||||
if (sscanf(buffer, "RssAnon:%10lu kB", &rss_anon) != 1)
|
||||
ksft_exit_fail_msg("Reading status error\n");
|
||||
|
||||
err_out:
|
||||
fclose(fp);
|
||||
return rss_anon;
|
||||
}
|
||||
|
||||
char *__get_smap_entry(void *addr, const char *pattern, char *buf, size_t len)
|
||||
{
|
||||
int ret;
|
||||
FILE *fp;
|
||||
char *entry = NULL;
|
||||
char addr_pattern[MAX_LINE_LENGTH];
|
||||
|
||||
ret = snprintf(addr_pattern, MAX_LINE_LENGTH, "%08lx-",
|
||||
|
@ -115,23 +136,40 @@ bool __check_huge(void *addr, char *pattern, int nr_hpages,
|
|||
if (!fp)
|
||||
ksft_exit_fail_msg("%s: Failed to open file %s\n", __func__, SMAP_FILE_PATH);
|
||||
|
||||
if (!check_for_pattern(fp, addr_pattern, buffer, sizeof(buffer)))
|
||||
if (!check_for_pattern(fp, addr_pattern, buf, len))
|
||||
goto err_out;
|
||||
|
||||
/*
|
||||
* Fetch the pattern in the same block and check the number of
|
||||
* hugepages.
|
||||
*/
|
||||
if (!check_for_pattern(fp, pattern, buffer, sizeof(buffer)))
|
||||
/* Fetch the pattern in the same block */
|
||||
if (!check_for_pattern(fp, pattern, buf, len))
|
||||
goto err_out;
|
||||
|
||||
snprintf(addr_pattern, MAX_LINE_LENGTH, "%s%%9ld kB", pattern);
|
||||
/* Trim trailing newline */
|
||||
entry = strchr(buf, '\n');
|
||||
if (entry)
|
||||
*entry = '\0';
|
||||
|
||||
if (sscanf(buffer, addr_pattern, &thp) != 1)
|
||||
ksft_exit_fail_msg("Reading smap error\n");
|
||||
entry = buf + strlen(pattern);
|
||||
|
||||
err_out:
|
||||
fclose(fp);
|
||||
return entry;
|
||||
}
|
||||
|
||||
bool __check_huge(void *addr, char *pattern, int nr_hpages,
|
||||
uint64_t hpage_size)
|
||||
{
|
||||
char buffer[MAX_LINE_LENGTH];
|
||||
uint64_t thp = -1;
|
||||
char *entry;
|
||||
|
||||
entry = __get_smap_entry(addr, pattern, buffer, sizeof(buffer));
|
||||
if (!entry)
|
||||
goto err_out;
|
||||
|
||||
if (sscanf(entry, "%9" SCNu64 " kB", &thp) != 1)
|
||||
ksft_exit_fail_msg("Reading smap error\n");
|
||||
|
||||
err_out:
|
||||
return thp == (nr_hpages * (hpage_size >> 10));
|
||||
}
|
||||
|
||||
|
@ -218,6 +256,30 @@ unsigned long get_free_hugepages(void)
|
|||
return fhp;
|
||||
}
|
||||
|
||||
bool check_vmflag_io(void *addr)
|
||||
{
|
||||
char buffer[MAX_LINE_LENGTH];
|
||||
const char *flags;
|
||||
size_t flaglen;
|
||||
|
||||
flags = __get_smap_entry(addr, "VmFlags:", buffer, sizeof(buffer));
|
||||
if (!flags)
|
||||
ksft_exit_fail_msg("%s: No VmFlags for %p\n", __func__, addr);
|
||||
|
||||
while (true) {
|
||||
flags += strspn(flags, " ");
|
||||
|
||||
flaglen = strcspn(flags, " ");
|
||||
if (!flaglen)
|
||||
return false;
|
||||
|
||||
if (flaglen == strlen("io") && !memcmp(flags, "io", flaglen))
|
||||
return true;
|
||||
|
||||
flags += flaglen;
|
||||
}
|
||||
}
|
||||
|
||||
int detect_hugetlb_page_sizes(size_t sizes[], int max)
|
||||
{
|
||||
DIR *dir = opendir("/sys/kernel/mm/hugepages/");
|
||||
|
|
|
@ -39,6 +39,7 @@ unsigned long pagemap_get_pfn(int fd, char *start);
|
|||
void clear_softdirty(void);
|
||||
bool check_for_pattern(FILE *fp, const char *pattern, char *buf, size_t len);
|
||||
uint64_t read_pmd_pagesize(void);
|
||||
unsigned long rss_anon(void);
|
||||
bool check_huge_anon(void *addr, int nr_hpages, uint64_t hpage_size);
|
||||
bool check_huge_file(void *addr, int nr_hpages, uint64_t hpage_size);
|
||||
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,
|
|||
int uffd_unregister(int uffd, void *addr, uint64_t len);
|
||||
int uffd_register_with_ioctls(int uffd, void *addr, uint64_t len,
|
||||
bool miss, bool wp, bool minor, uint64_t *ioctls);
|
||||
bool check_vmflag_io(void *addr);
|
||||
|
||||
/*
|
||||
* On ppc64 this will only work with radix 2M hugepage size
|
||||
|
|
Loading…
Reference in New Issue