selftests: vm: bring common functions to a new file
Bring common functions to a new file while keeping code as much same as possible. These functions can be used in the new tests. This helps in avoiding code duplication. Link: https://lkml.kernel.org/r/20220420084036.4101604-1-usama.anjum@collabora.com Signed-off-by: Muhammad Usama Anjum <usama.anjum@collabora.com> Acked-by: David Hildenbrand <david@redhat.com> Cc: Gabriel Krisman Bertazi <krisman@collabora.com> Cc: Shuah Khan <shuah@kernel.org> Cc: Will Deacon <will@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
parent
62e80f2b50
commit
642bc52aed
5 changed files with 124 additions and 113 deletions
|
@ -36,7 +36,7 @@ TEST_GEN_FILES += hugepage-mremap
|
||||||
TEST_GEN_FILES += hugepage-shm
|
TEST_GEN_FILES += hugepage-shm
|
||||||
TEST_GEN_FILES += hugepage-vmemmap
|
TEST_GEN_FILES += hugepage-vmemmap
|
||||||
TEST_GEN_FILES += khugepaged
|
TEST_GEN_FILES += khugepaged
|
||||||
TEST_GEN_FILES += madv_populate
|
TEST_GEN_PROGS = madv_populate
|
||||||
TEST_GEN_FILES += map_fixed_noreplace
|
TEST_GEN_FILES += map_fixed_noreplace
|
||||||
TEST_GEN_FILES += map_hugetlb
|
TEST_GEN_FILES += map_hugetlb
|
||||||
TEST_GEN_FILES += map_populate
|
TEST_GEN_FILES += map_populate
|
||||||
|
@ -50,7 +50,7 @@ TEST_GEN_FILES += on-fault-limit
|
||||||
TEST_GEN_FILES += thuge-gen
|
TEST_GEN_FILES += thuge-gen
|
||||||
TEST_GEN_FILES += transhuge-stress
|
TEST_GEN_FILES += transhuge-stress
|
||||||
TEST_GEN_FILES += userfaultfd
|
TEST_GEN_FILES += userfaultfd
|
||||||
TEST_GEN_FILES += split_huge_page_test
|
TEST_GEN_PROGS += split_huge_page_test
|
||||||
TEST_GEN_FILES += ksm_tests
|
TEST_GEN_FILES += ksm_tests
|
||||||
|
|
||||||
ifeq ($(MACHINE),x86_64)
|
ifeq ($(MACHINE),x86_64)
|
||||||
|
@ -94,6 +94,9 @@ TEST_FILES := test_vmalloc.sh
|
||||||
KSFT_KHDR_INSTALL := 1
|
KSFT_KHDR_INSTALL := 1
|
||||||
include ../lib.mk
|
include ../lib.mk
|
||||||
|
|
||||||
|
$(OUTPUT)/madv_populate: vm_util.c
|
||||||
|
$(OUTPUT)/split_huge_page_test: vm_util.c
|
||||||
|
|
||||||
ifeq ($(MACHINE),x86_64)
|
ifeq ($(MACHINE),x86_64)
|
||||||
BINARIES_32 := $(patsubst %,$(OUTPUT)/%,$(BINARIES_32))
|
BINARIES_32 := $(patsubst %,$(OUTPUT)/%,$(BINARIES_32))
|
||||||
BINARIES_64 := $(patsubst %,$(OUTPUT)/%,$(BINARIES_64))
|
BINARIES_64 := $(patsubst %,$(OUTPUT)/%,$(BINARIES_64))
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
|
||||||
#include "../kselftest.h"
|
#include "../kselftest.h"
|
||||||
|
#include "vm_util.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For now, we're using 2 MiB of private anonymous memory for all tests.
|
* For now, we're using 2 MiB of private anonymous memory for all tests.
|
||||||
|
@ -26,18 +27,6 @@
|
||||||
|
|
||||||
static size_t pagesize;
|
static size_t pagesize;
|
||||||
|
|
||||||
static uint64_t pagemap_get_entry(int fd, char *start)
|
|
||||||
{
|
|
||||||
const unsigned long pfn = (unsigned long)start / pagesize;
|
|
||||||
uint64_t entry;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = pread(fd, &entry, sizeof(entry), pfn * sizeof(entry));
|
|
||||||
if (ret != sizeof(entry))
|
|
||||||
ksft_exit_fail_msg("reading pagemap failed\n");
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool pagemap_is_populated(int fd, char *start)
|
static bool pagemap_is_populated(int fd, char *start)
|
||||||
{
|
{
|
||||||
uint64_t entry = pagemap_get_entry(fd, start);
|
uint64_t entry = pagemap_get_entry(fd, start);
|
||||||
|
@ -46,13 +35,6 @@ static bool pagemap_is_populated(int fd, char *start)
|
||||||
return entry & 0xc000000000000000ull;
|
return entry & 0xc000000000000000ull;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool pagemap_is_softdirty(int fd, char *start)
|
|
||||||
{
|
|
||||||
uint64_t entry = pagemap_get_entry(fd, start);
|
|
||||||
|
|
||||||
return entry & 0x0080000000000000ull;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sense_support(void)
|
static void sense_support(void)
|
||||||
{
|
{
|
||||||
char *addr;
|
char *addr;
|
||||||
|
@ -258,20 +240,6 @@ static bool range_is_not_softdirty(char *start, ssize_t size)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clear_softdirty(void)
|
|
||||||
{
|
|
||||||
int fd = open("/proc/self/clear_refs", O_WRONLY);
|
|
||||||
const char *ctrl = "4";
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (fd < 0)
|
|
||||||
ksft_exit_fail_msg("opening clear_refs failed\n");
|
|
||||||
ret = write(fd, ctrl, strlen(ctrl));
|
|
||||||
if (ret != strlen(ctrl))
|
|
||||||
ksft_exit_fail_msg("writing clear_refs failed\n");
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_softdirty(void)
|
static void test_softdirty(void)
|
||||||
{
|
{
|
||||||
char *addr;
|
char *addr;
|
||||||
|
|
|
@ -16,14 +16,13 @@
|
||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include "vm_util.h"
|
||||||
|
|
||||||
uint64_t pagesize;
|
uint64_t pagesize;
|
||||||
unsigned int pageshift;
|
unsigned int pageshift;
|
||||||
uint64_t pmd_pagesize;
|
uint64_t pmd_pagesize;
|
||||||
|
|
||||||
#define PMD_SIZE_PATH "/sys/kernel/mm/transparent_hugepage/hpage_pmd_size"
|
|
||||||
#define SPLIT_DEBUGFS "/sys/kernel/debug/split_huge_pages"
|
#define SPLIT_DEBUGFS "/sys/kernel/debug/split_huge_pages"
|
||||||
#define SMAP_PATH "/proc/self/smaps"
|
|
||||||
#define INPUT_MAX 80
|
#define INPUT_MAX 80
|
||||||
|
|
||||||
#define PID_FMT "%d,0x%lx,0x%lx"
|
#define PID_FMT "%d,0x%lx,0x%lx"
|
||||||
|
@ -51,30 +50,6 @@ int is_backed_by_thp(char *vaddr, int pagemap_file, int kpageflags_file)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static uint64_t read_pmd_pagesize(void)
|
|
||||||
{
|
|
||||||
int fd;
|
|
||||||
char buf[20];
|
|
||||||
ssize_t num_read;
|
|
||||||
|
|
||||||
fd = open(PMD_SIZE_PATH, O_RDONLY);
|
|
||||||
if (fd == -1) {
|
|
||||||
perror("Open hpage_pmd_size failed");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
num_read = read(fd, buf, 19);
|
|
||||||
if (num_read < 1) {
|
|
||||||
close(fd);
|
|
||||||
perror("Read hpage_pmd_size failed");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
buf[num_read] = '\0';
|
|
||||||
close(fd);
|
|
||||||
|
|
||||||
return strtoul(buf, NULL, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int write_file(const char *path, const char *buf, size_t buflen)
|
static int write_file(const char *path, const char *buf, size_t buflen)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
|
@ -113,58 +88,6 @@ static void write_debugfs(const char *fmt, ...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MAX_LINE_LENGTH 500
|
|
||||||
|
|
||||||
static bool check_for_pattern(FILE *fp, const char *pattern, char *buf)
|
|
||||||
{
|
|
||||||
while (fgets(buf, MAX_LINE_LENGTH, fp) != NULL) {
|
|
||||||
if (!strncmp(buf, pattern, strlen(pattern)))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint64_t check_huge(void *addr)
|
|
||||||
{
|
|
||||||
uint64_t thp = 0;
|
|
||||||
int ret;
|
|
||||||
FILE *fp;
|
|
||||||
char buffer[MAX_LINE_LENGTH];
|
|
||||||
char addr_pattern[MAX_LINE_LENGTH];
|
|
||||||
|
|
||||||
ret = snprintf(addr_pattern, MAX_LINE_LENGTH, "%08lx-",
|
|
||||||
(unsigned long) addr);
|
|
||||||
if (ret >= MAX_LINE_LENGTH) {
|
|
||||||
printf("%s: Pattern is too long\n", __func__);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fp = fopen(SMAP_PATH, "r");
|
|
||||||
if (!fp) {
|
|
||||||
printf("%s: Failed to open file %s\n", __func__, SMAP_PATH);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
if (!check_for_pattern(fp, addr_pattern, buffer))
|
|
||||||
goto err_out;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Fetch the AnonHugePages: in the same block and check the number of
|
|
||||||
* hugepages.
|
|
||||||
*/
|
|
||||||
if (!check_for_pattern(fp, "AnonHugePages:", buffer))
|
|
||||||
goto err_out;
|
|
||||||
|
|
||||||
if (sscanf(buffer, "AnonHugePages:%10ld kB", &thp) != 1) {
|
|
||||||
printf("Reading smap error\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
err_out:
|
|
||||||
fclose(fp);
|
|
||||||
return thp;
|
|
||||||
}
|
|
||||||
|
|
||||||
void split_pmd_thp(void)
|
void split_pmd_thp(void)
|
||||||
{
|
{
|
||||||
char *one_page;
|
char *one_page;
|
||||||
|
|
108
tools/testing/selftests/vm/vm_util.c
Normal file
108
tools/testing/selftests/vm/vm_util.c
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
#include <string.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include "../kselftest.h"
|
||||||
|
#include "vm_util.h"
|
||||||
|
|
||||||
|
#define PMD_SIZE_FILE_PATH "/sys/kernel/mm/transparent_hugepage/hpage_pmd_size"
|
||||||
|
#define SMAP_FILE_PATH "/proc/self/smaps"
|
||||||
|
#define MAX_LINE_LENGTH 500
|
||||||
|
|
||||||
|
uint64_t pagemap_get_entry(int fd, char *start)
|
||||||
|
{
|
||||||
|
const unsigned long pfn = (unsigned long)start / getpagesize();
|
||||||
|
uint64_t entry;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = pread(fd, &entry, sizeof(entry), pfn * sizeof(entry));
|
||||||
|
if (ret != sizeof(entry))
|
||||||
|
ksft_exit_fail_msg("reading pagemap failed\n");
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pagemap_is_softdirty(int fd, char *start)
|
||||||
|
{
|
||||||
|
uint64_t entry = pagemap_get_entry(fd, start);
|
||||||
|
|
||||||
|
// Check if dirty bit (55th bit) is set
|
||||||
|
return entry & 0x0080000000000000ull;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_softdirty(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
const char *ctrl = "4";
|
||||||
|
int fd = open("/proc/self/clear_refs", O_WRONLY);
|
||||||
|
|
||||||
|
if (fd < 0)
|
||||||
|
ksft_exit_fail_msg("opening clear_refs failed\n");
|
||||||
|
ret = write(fd, ctrl, strlen(ctrl));
|
||||||
|
close(fd);
|
||||||
|
if (ret != strlen(ctrl))
|
||||||
|
ksft_exit_fail_msg("writing clear_refs failed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool check_for_pattern(FILE *fp, const char *pattern, char *buf)
|
||||||
|
{
|
||||||
|
while (fgets(buf, MAX_LINE_LENGTH, fp) != NULL) {
|
||||||
|
if (!strncmp(buf, pattern, strlen(pattern)))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t read_pmd_pagesize(void)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
char buf[20];
|
||||||
|
ssize_t num_read;
|
||||||
|
|
||||||
|
fd = open(PMD_SIZE_FILE_PATH, O_RDONLY);
|
||||||
|
if (fd == -1)
|
||||||
|
ksft_exit_fail_msg("Open hpage_pmd_size failed\n");
|
||||||
|
|
||||||
|
num_read = read(fd, buf, 19);
|
||||||
|
if (num_read < 1) {
|
||||||
|
close(fd);
|
||||||
|
ksft_exit_fail_msg("Read hpage_pmd_size failed\n");
|
||||||
|
}
|
||||||
|
buf[num_read] = '\0';
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
return strtoul(buf, NULL, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t check_huge(void *addr)
|
||||||
|
{
|
||||||
|
uint64_t thp = 0;
|
||||||
|
int ret;
|
||||||
|
FILE *fp;
|
||||||
|
char buffer[MAX_LINE_LENGTH];
|
||||||
|
char addr_pattern[MAX_LINE_LENGTH];
|
||||||
|
|
||||||
|
ret = snprintf(addr_pattern, MAX_LINE_LENGTH, "%08lx-",
|
||||||
|
(unsigned long) addr);
|
||||||
|
if (ret >= MAX_LINE_LENGTH)
|
||||||
|
ksft_exit_fail_msg("%s: Pattern is too long\n", __func__);
|
||||||
|
|
||||||
|
fp = fopen(SMAP_FILE_PATH, "r");
|
||||||
|
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))
|
||||||
|
goto err_out;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fetch the AnonHugePages: in the same block and check the number of
|
||||||
|
* hugepages.
|
||||||
|
*/
|
||||||
|
if (!check_for_pattern(fp, "AnonHugePages:", buffer))
|
||||||
|
goto err_out;
|
||||||
|
|
||||||
|
if (sscanf(buffer, "AnonHugePages:%10ld kB", &thp) != 1)
|
||||||
|
ksft_exit_fail_msg("Reading smap error\n");
|
||||||
|
|
||||||
|
err_out:
|
||||||
|
fclose(fp);
|
||||||
|
return thp;
|
||||||
|
}
|
9
tools/testing/selftests/vm/vm_util.h
Normal file
9
tools/testing/selftests/vm/vm_util.h
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
uint64_t pagemap_get_entry(int fd, char *start);
|
||||||
|
bool pagemap_is_softdirty(int fd, char *start);
|
||||||
|
void clear_softdirty(void);
|
||||||
|
uint64_t read_pmd_pagesize(void);
|
||||||
|
uint64_t check_huge(void *addr);
|
Loading…
Add table
Reference in a new issue