forked from Minki/linux
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
@ -36,7 +36,7 @@ TEST_GEN_FILES += hugepage-mremap
|
||||
TEST_GEN_FILES += hugepage-shm
|
||||
TEST_GEN_FILES += hugepage-vmemmap
|
||||
TEST_GEN_FILES += khugepaged
|
||||
TEST_GEN_FILES += madv_populate
|
||||
TEST_GEN_PROGS = madv_populate
|
||||
TEST_GEN_FILES += map_fixed_noreplace
|
||||
TEST_GEN_FILES += map_hugetlb
|
||||
TEST_GEN_FILES += map_populate
|
||||
@ -50,7 +50,7 @@ TEST_GEN_FILES += on-fault-limit
|
||||
TEST_GEN_FILES += thuge-gen
|
||||
TEST_GEN_FILES += transhuge-stress
|
||||
TEST_GEN_FILES += userfaultfd
|
||||
TEST_GEN_FILES += split_huge_page_test
|
||||
TEST_GEN_PROGS += split_huge_page_test
|
||||
TEST_GEN_FILES += ksm_tests
|
||||
|
||||
ifeq ($(MACHINE),x86_64)
|
||||
@ -94,6 +94,9 @@ TEST_FILES := test_vmalloc.sh
|
||||
KSFT_KHDR_INSTALL := 1
|
||||
include ../lib.mk
|
||||
|
||||
$(OUTPUT)/madv_populate: vm_util.c
|
||||
$(OUTPUT)/split_huge_page_test: vm_util.c
|
||||
|
||||
ifeq ($(MACHINE),x86_64)
|
||||
BINARIES_32 := $(patsubst %,$(OUTPUT)/%,$(BINARIES_32))
|
||||
BINARIES_64 := $(patsubst %,$(OUTPUT)/%,$(BINARIES_64))
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "../kselftest.h"
|
||||
#include "vm_util.h"
|
||||
|
||||
/*
|
||||
* For now, we're using 2 MiB of private anonymous memory for all tests.
|
||||
@ -26,18 +27,6 @@
|
||||
|
||||
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)
|
||||
{
|
||||
uint64_t entry = pagemap_get_entry(fd, start);
|
||||
@ -46,13 +35,6 @@ static bool pagemap_is_populated(int fd, char *start)
|
||||
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)
|
||||
{
|
||||
char *addr;
|
||||
@ -258,20 +240,6 @@ static bool range_is_not_softdirty(char *start, ssize_t size)
|
||||
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)
|
||||
{
|
||||
char *addr;
|
||||
|
@ -16,14 +16,13 @@
|
||||
#include <sys/mount.h>
|
||||
#include <malloc.h>
|
||||
#include <stdbool.h>
|
||||
#include "vm_util.h"
|
||||
|
||||
uint64_t pagesize;
|
||||
unsigned int pageshift;
|
||||
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 SMAP_PATH "/proc/self/smaps"
|
||||
#define INPUT_MAX 80
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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…
Reference in New Issue
Block a user