at v6.2-rc1 151 lines 3.6 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 31bool pagemap_is_swapped(int fd, char *start) 32{ 33 uint64_t entry = pagemap_get_entry(fd, start); 34 35 return entry & 0x4000000000000000ull; 36} 37 38bool pagemap_is_populated(int fd, char *start) 39{ 40 uint64_t entry = pagemap_get_entry(fd, start); 41 42 /* Present or swapped. */ 43 return entry & 0xc000000000000000ull; 44} 45 46unsigned long pagemap_get_pfn(int fd, char *start) 47{ 48 uint64_t entry = pagemap_get_entry(fd, start); 49 50 /* If present (63th bit), PFN is at bit 0 -- 54. */ 51 if (entry & 0x8000000000000000ull) 52 return entry & 0x007fffffffffffffull; 53 return -1ul; 54} 55 56void clear_softdirty(void) 57{ 58 int ret; 59 const char *ctrl = "4"; 60 int fd = open("/proc/self/clear_refs", O_WRONLY); 61 62 if (fd < 0) 63 ksft_exit_fail_msg("opening clear_refs failed\n"); 64 ret = write(fd, ctrl, strlen(ctrl)); 65 close(fd); 66 if (ret != strlen(ctrl)) 67 ksft_exit_fail_msg("writing clear_refs failed\n"); 68} 69 70bool check_for_pattern(FILE *fp, const char *pattern, char *buf, size_t len) 71{ 72 while (fgets(buf, len, fp)) { 73 if (!strncmp(buf, pattern, strlen(pattern))) 74 return true; 75 } 76 return false; 77} 78 79uint64_t read_pmd_pagesize(void) 80{ 81 int fd; 82 char buf[20]; 83 ssize_t num_read; 84 85 fd = open(PMD_SIZE_FILE_PATH, O_RDONLY); 86 if (fd == -1) 87 ksft_exit_fail_msg("Open hpage_pmd_size failed\n"); 88 89 num_read = read(fd, buf, 19); 90 if (num_read < 1) { 91 close(fd); 92 ksft_exit_fail_msg("Read hpage_pmd_size failed\n"); 93 } 94 buf[num_read] = '\0'; 95 close(fd); 96 97 return strtoul(buf, NULL, 10); 98} 99 100bool __check_huge(void *addr, char *pattern, int nr_hpages, 101 uint64_t hpage_size) 102{ 103 uint64_t thp = -1; 104 int ret; 105 FILE *fp; 106 char buffer[MAX_LINE_LENGTH]; 107 char addr_pattern[MAX_LINE_LENGTH]; 108 109 ret = snprintf(addr_pattern, MAX_LINE_LENGTH, "%08lx-", 110 (unsigned long) addr); 111 if (ret >= MAX_LINE_LENGTH) 112 ksft_exit_fail_msg("%s: Pattern is too long\n", __func__); 113 114 fp = fopen(SMAP_FILE_PATH, "r"); 115 if (!fp) 116 ksft_exit_fail_msg("%s: Failed to open file %s\n", __func__, SMAP_FILE_PATH); 117 118 if (!check_for_pattern(fp, addr_pattern, buffer, sizeof(buffer))) 119 goto err_out; 120 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))) 126 goto err_out; 127 128 snprintf(addr_pattern, MAX_LINE_LENGTH, "%s%%9ld kB", pattern); 129 130 if (sscanf(buffer, addr_pattern, &thp) != 1) 131 ksft_exit_fail_msg("Reading smap error\n"); 132 133err_out: 134 fclose(fp); 135 return thp == (nr_hpages * (hpage_size >> 10)); 136} 137 138bool check_huge_anon(void *addr, int nr_hpages, uint64_t hpage_size) 139{ 140 return __check_huge(addr, "AnonHugePages: ", nr_hpages, hpage_size); 141} 142 143bool check_huge_file(void *addr, int nr_hpages, uint64_t hpage_size) 144{ 145 return __check_huge(addr, "FilePmdMapped:", nr_hpages, hpage_size); 146} 147 148bool check_huge_shmem(void *addr, int nr_hpages, uint64_t hpage_size) 149{ 150 return __check_huge(addr, "ShmemPmdMapped:", nr_hpages, hpage_size); 151}