at v6.1-rc4 126 lines 3.1 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2#include <string.h> 3#include <fcntl.h> 4#include "../kselftest.h" 5#include "vm_util.h" 6 7#define PMD_SIZE_FILE_PATH "/sys/kernel/mm/transparent_hugepage/hpage_pmd_size" 8#define SMAP_FILE_PATH "/proc/self/smaps" 9#define MAX_LINE_LENGTH 500 10 11uint64_t pagemap_get_entry(int fd, char *start) 12{ 13 const unsigned long pfn = (unsigned long)start / getpagesize(); 14 uint64_t entry; 15 int ret; 16 17 ret = pread(fd, &entry, sizeof(entry), pfn * sizeof(entry)); 18 if (ret != sizeof(entry)) 19 ksft_exit_fail_msg("reading pagemap failed\n"); 20 return entry; 21} 22 23bool pagemap_is_softdirty(int fd, char *start) 24{ 25 uint64_t entry = pagemap_get_entry(fd, start); 26 27 // Check if dirty bit (55th bit) is set 28 return entry & 0x0080000000000000ull; 29} 30 31void clear_softdirty(void) 32{ 33 int ret; 34 const char *ctrl = "4"; 35 int fd = open("/proc/self/clear_refs", O_WRONLY); 36 37 if (fd < 0) 38 ksft_exit_fail_msg("opening clear_refs failed\n"); 39 ret = write(fd, ctrl, strlen(ctrl)); 40 close(fd); 41 if (ret != strlen(ctrl)) 42 ksft_exit_fail_msg("writing clear_refs failed\n"); 43} 44 45bool check_for_pattern(FILE *fp, const char *pattern, char *buf, size_t len) 46{ 47 while (fgets(buf, len, fp)) { 48 if (!strncmp(buf, pattern, strlen(pattern))) 49 return true; 50 } 51 return false; 52} 53 54uint64_t read_pmd_pagesize(void) 55{ 56 int fd; 57 char buf[20]; 58 ssize_t num_read; 59 60 fd = open(PMD_SIZE_FILE_PATH, O_RDONLY); 61 if (fd == -1) 62 ksft_exit_fail_msg("Open hpage_pmd_size failed\n"); 63 64 num_read = read(fd, buf, 19); 65 if (num_read < 1) { 66 close(fd); 67 ksft_exit_fail_msg("Read hpage_pmd_size failed\n"); 68 } 69 buf[num_read] = '\0'; 70 close(fd); 71 72 return strtoul(buf, NULL, 10); 73} 74 75bool __check_huge(void *addr, char *pattern, int nr_hpages, 76 uint64_t hpage_size) 77{ 78 uint64_t thp = -1; 79 int ret; 80 FILE *fp; 81 char buffer[MAX_LINE_LENGTH]; 82 char addr_pattern[MAX_LINE_LENGTH]; 83 84 ret = snprintf(addr_pattern, MAX_LINE_LENGTH, "%08lx-", 85 (unsigned long) addr); 86 if (ret >= MAX_LINE_LENGTH) 87 ksft_exit_fail_msg("%s: Pattern is too long\n", __func__); 88 89 fp = fopen(SMAP_FILE_PATH, "r"); 90 if (!fp) 91 ksft_exit_fail_msg("%s: Failed to open file %s\n", __func__, SMAP_FILE_PATH); 92 93 if (!check_for_pattern(fp, addr_pattern, buffer, sizeof(buffer))) 94 goto err_out; 95 96 /* 97 * Fetch the pattern in the same block and check the number of 98 * hugepages. 99 */ 100 if (!check_for_pattern(fp, pattern, buffer, sizeof(buffer))) 101 goto err_out; 102 103 snprintf(addr_pattern, MAX_LINE_LENGTH, "%s%%9ld kB", pattern); 104 105 if (sscanf(buffer, addr_pattern, &thp) != 1) 106 ksft_exit_fail_msg("Reading smap error\n"); 107 108err_out: 109 fclose(fp); 110 return thp == (nr_hpages * (hpage_size >> 10)); 111} 112 113bool check_huge_anon(void *addr, int nr_hpages, uint64_t hpage_size) 114{ 115 return __check_huge(addr, "AnonHugePages: ", nr_hpages, hpage_size); 116} 117 118bool check_huge_file(void *addr, int nr_hpages, uint64_t hpage_size) 119{ 120 return __check_huge(addr, "FilePmdMapped:", nr_hpages, hpage_size); 121} 122 123bool check_huge_shmem(void *addr, int nr_hpages, uint64_t hpage_size) 124{ 125 return __check_huge(addr, "ShmemPmdMapped:", nr_hpages, hpage_size); 126}